Compare commits
3 Commits
Author | SHA1 | Date |
---|---|---|
|
a1f3a439ab | |
|
0c1009dddb | |
|
039677b15b |
|
@ -0,0 +1,6 @@
|
||||||
|
Name: order.rpc
|
||||||
|
ListenOn: 0.0.0.0:8080
|
||||||
|
Etcd:
|
||||||
|
Hosts:
|
||||||
|
- 127.0.0.1:2379
|
||||||
|
Key: order.rpc
|
66
go.mod
66
go.mod
|
@ -1,18 +1,14 @@
|
||||||
module app-cloudep-order-server
|
module code.30cm.net/digimon/app-cloudep-order-service
|
||||||
|
|
||||||
go 1.22.3
|
go 1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
code.30cm.net/digimon/library-go/errs v1.2.5
|
code.30cm.net/digimon/library-go/errs v1.2.14
|
||||||
code.30cm.net/digimon/library-go/validator v1.0.0
|
|
||||||
github.com/go-playground/validator/v10 v10.22.0
|
|
||||||
github.com/shopspring/decimal v1.4.0
|
github.com/shopspring/decimal v1.4.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/zeromicro/go-zero v1.8.1
|
||||||
github.com/zeromicro/go-zero v1.7.2
|
go.mongodb.org/mongo-driver v1.17.3
|
||||||
go.mongodb.org/mongo-driver v1.16.1
|
google.golang.org/grpc v1.71.0
|
||||||
go.uber.org/mock v0.4.0
|
google.golang.org/protobuf v1.36.6
|
||||||
google.golang.org/grpc v1.67.1
|
|
||||||
google.golang.org/protobuf v1.34.2
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -24,15 +20,12 @@ require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
|
||||||
github.com/fatih/color v1.17.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
|
||||||
github.com/go-logr/logr v1.4.2 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
github.com/go-openapi/swag v0.22.4 // 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/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.4 // indirect
|
||||||
|
@ -44,8 +37,7 @@ require (
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.17.9 // indirect
|
github.com/klauspost/compress v1.17.11 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
@ -55,45 +47,45 @@ require (
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
github.com/openzipkin/zipkin-go v0.4.3 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/prometheus/client_golang v1.21.0 // indirect
|
||||||
github.com/prometheus/client_golang v1.20.2 // indirect
|
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.55.0 // indirect
|
github.com/prometheus/common v0.62.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.6.1 // indirect
|
github.com/redis/go-redis/v9 v9.7.1 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.1.2 // indirect
|
github.com/xdg-go/scram v1.1.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.etcd.io/etcd/api/v3 v3.5.15 // 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/pkg/v3 v3.5.15 // indirect
|
||||||
go.etcd.io/etcd/client/v3 v3.5.15 // indirect
|
go.etcd.io/etcd/client/v3 v3.5.15 // indirect
|
||||||
go.opentelemetry.io/otel v1.24.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.34.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect
|
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect
|
go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
go.opentelemetry.io/otel/metric v1.34.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.34.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
go.opentelemetry.io/otel/trace v1.34.0 // indirect
|
||||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||||
go.uber.org/atomic v1.10.0 // indirect
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
go.uber.org/zap v1.24.0 // indirect
|
go.uber.org/zap v1.24.0 // indirect
|
||||||
golang.org/x/crypto v0.26.0 // indirect
|
golang.org/x/crypto v0.33.0 // indirect
|
||||||
golang.org/x/net v0.28.0 // indirect
|
golang.org/x/net v0.35.0 // indirect
|
||||||
golang.org/x/oauth2 v0.22.0 // indirect
|
golang.org/x/oauth2 v0.25.0 // indirect
|
||||||
golang.org/x/sync v0.8.0 // indirect
|
golang.org/x/sync v0.11.0 // indirect
|
||||||
golang.org/x/sys v0.24.0 // indirect
|
golang.org/x/sys v0.30.0 // indirect
|
||||||
golang.org/x/term v0.23.0 // indirect
|
golang.org/x/term v0.29.0 // indirect
|
||||||
golang.org/x/text v0.17.0 // indirect
|
golang.org/x/text v0.22.0 // indirect
|
||||||
golang.org/x/time v0.6.0 // indirect
|
golang.org/x/time v0.10.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
|
@ -4,13 +4,4 @@ import "github.com/zeromicro/go-zero/zrpc"
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
zrpc.RpcServerConf
|
zrpc.RpcServerConf
|
||||||
|
|
||||||
Mongo struct {
|
|
||||||
Schema string
|
|
||||||
User string
|
|
||||||
Password string
|
|
||||||
Host string
|
|
||||||
Port string
|
|
||||||
Database string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
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, " "))
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
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 // 交易超時
|
|
||||||
)
|
|
|
@ -1,14 +1,10 @@
|
||||||
package orderservicelogic
|
package orderservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
"app-cloudep-order-server/internal/domain"
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
ers "code.30cm.net/digimon/library-go/errs"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -27,42 +23,9 @@ 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 取消訂單
|
// CancelOrder 取消訂單
|
||||||
func (l *CancelOrderLogic) CancelOrder(in *order.CancelOrderReq) (*order.OKResp, error) {
|
func (l *CancelOrderLogic) CancelOrder(in *order.CancelOrderReq) (*order.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 &order.OKResp{}, nil
|
return &order.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,110 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
mocksvc "app-cloudep-order-server/internal/mock/lib"
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
|
|
||||||
mockmodel "app-cloudep-order-server/internal/mock/model"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCancelOrder(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
// 初始化 mock 依賴
|
|
||||||
mockOrderModel := mockmodel.NewMockOrderModel(ctrl)
|
|
||||||
mockValidate := mocksvc.NewMockValidate(ctrl)
|
|
||||||
|
|
||||||
// 初始化服務上下文
|
|
||||||
svcCtx := &svc.ServiceContext{
|
|
||||||
OrderModel: mockOrderModel,
|
|
||||||
Validate: mockValidate,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試數據
|
|
||||||
cancelReq := &order.CancelOrderReq{
|
|
||||||
BusinessId: "12345",
|
|
||||||
Status: 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試數據集
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input *order.CancelOrderReq
|
|
||||||
prepare func()
|
|
||||||
expectErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "成功取消訂單",
|
|
||||||
input: cancelReq,
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證通過
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬更新狀態成功
|
|
||||||
mockOrderModel.EXPECT().UpdateStatus(gomock.Any(), model.UpdateStatusReq{
|
|
||||||
BusinessID: "12345",
|
|
||||||
Status: 1,
|
|
||||||
}).Return(&mongo.UpdateResult{MatchedCount: 1}, nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "訂單更新狀態失敗",
|
|
||||||
input: cancelReq,
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證通過
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬更新狀態失敗
|
|
||||||
mockOrderModel.EXPECT().UpdateStatus(gomock.Any(), model.UpdateStatusReq{
|
|
||||||
BusinessID: "12345",
|
|
||||||
Status: 1,
|
|
||||||
}).Return(nil, errors.New("update failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "驗證失敗",
|
|
||||||
input: cancelReq,
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證失敗
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("invalid input")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// 執行測試
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// 設置測試環境
|
|
||||||
tt.prepare()
|
|
||||||
|
|
||||||
// 初始化 CancelOrderLogic
|
|
||||||
logic := CancelOrderLogic{
|
|
||||||
svcCtx: svcCtx,
|
|
||||||
ctx: context.TODO(),
|
|
||||||
}
|
|
||||||
|
|
||||||
// 執行 CancelOrder
|
|
||||||
resp, err := logic.CancelOrder(tt.input)
|
|
||||||
|
|
||||||
// 驗證結果
|
|
||||||
if tt.expectErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, resp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +1,10 @@
|
||||||
package orderservicelogic
|
package orderservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
"app-cloudep-order-server/internal/domain"
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
ers "code.30cm.net/digimon/library-go/errs"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
"github.com/shopspring/decimal"
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -29,226 +23,9 @@ func NewCreateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Creat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type createOrderReq struct { // 訂單ID
|
|
||||||
BusinessID string `json:"business_id" validate:"required"` // 訂單業務流水號
|
|
||||||
OrderType int8 `json:"order_type" validate:"required"` // 訂單類型
|
|
||||||
OrderStatus int8 `json:"order_status" validate:"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,decimalGt=0"` // 訂單數量
|
|
||||||
OrderFee decimal.Decimal `json:"order_fee" validate:"required,decimalGte=0"` // 訂單手續費
|
|
||||||
Amount decimal.Decimal `json:"amount" validate:"required,decimalGte=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,decimalGte=0"` // 第三方手續費
|
|
||||||
CryptoToUSDTRate *decimal.Decimal `json:"crypto_to_usdt_rate,omitempty" validate:"omitempty,decimalGte=0"` // 交易幣種對 USDT 匯率
|
|
||||||
FiatToUSDRate *decimal.Decimal `json:"fiat_to_usd_rate,omitempty" validate:"omitempty,decimalGte=0"` // 法幣對 USD 匯率
|
|
||||||
FeeCryptoToUSDTRate *decimal.Decimal `json:"fee_crypto_to_usdt_rate,omitempty" validate:"omitempty,decimalGte=0"` // 手續費幣種對 USDT 匯率
|
|
||||||
USDTToCryptoTypeRate *decimal.Decimal `json:"usdt_to_crypto_type_rate,omitempty" validate:"omitempty,decimalGte=0"` // USDT 對交易幣種匯率
|
|
||||||
PaymentFiat *string `json:"payment_fiat,omitempty" validate:"omitempty"` // 支付法幣
|
|
||||||
PaymentUnitPrice *decimal.Decimal `json:"payment_unit_price,omitempty" validate:"omitempty,decimalGte=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,decimalGte=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,decimalGte=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 建立訂單
|
// CreateOrder 建立訂單
|
||||||
func (l *CreateOrderLogic) CreateOrder(in *order.CreateOrderReq) (*order.OKResp, error) {
|
func (l *CreateOrderLogic) CreateOrder(in *order.CreateOrderReq) (*order.OKResp, error) {
|
||||||
req, err := buildCreateOrderReq(in)
|
// todo: add your logic here and delete this line
|
||||||
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: convertDecimalToDecimal128(req.Count),
|
|
||||||
OrderFee: convertDecimalToDecimal128(req.OrderFee),
|
|
||||||
Amount: convertDecimalToDecimal128(req.Amount),
|
|
||||||
// 下面的是未來擴充用,加密貨幣用,或者幣別轉換用,普通訂單用不到
|
|
||||||
ReferenceBrand: req.ReferenceBrand,
|
|
||||||
ReferenceUID: req.ReferenceUID,
|
|
||||||
WalletStatus: req.WalletStatus,
|
|
||||||
ThreePartyStatus: req.ThreePartyStatus,
|
|
||||||
DirectionType: req.DirectionType,
|
|
||||||
CryptoType: req.CryptoType,
|
|
||||||
ThirdPartyFee: convertDecimalPtrToDecimal128(req.ThirdPartyFee),
|
|
||||||
CryptoToUSDTRate: convertDecimalPtrToDecimal128(req.CryptoToUSDTRate),
|
|
||||||
FiatToUSDRate: convertDecimalPtrToDecimal128(req.FiatToUSDRate),
|
|
||||||
FeeCryptoToUSDTRate: convertDecimalPtrToDecimal128(req.FeeCryptoToUSDTRate),
|
|
||||||
USDTToCryptoTypeRate: convertDecimalPtrToDecimal128(req.USDTToCryptoTypeRate),
|
|
||||||
PaymentFiat: req.PaymentFiat,
|
|
||||||
PaymentUnitPrice: convertDecimalPtrToDecimal128(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: convertDecimalPtrToDecimal128(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 &order.OKResp{}, nil
|
return &order.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocyclo,gocognit
|
|
||||||
func buildCreateOrderReq(in *order.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
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,371 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
mocksvc "app-cloudep-order-server/internal/mock/lib"
|
|
||||||
mockmodel "app-cloudep-order-server/internal/mock/model"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestBuildCreateOrderReq(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input *order.CreateOrderReq
|
|
||||||
expectErr bool
|
|
||||||
expected *createOrderReq
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "所有必填字段存在,可選字段為空",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
expected: &createOrderReq{
|
|
||||||
BusinessID: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUID: "UID123",
|
|
||||||
ReferenceID: "REF123",
|
|
||||||
Count: decimal.RequireFromString("10.5"),
|
|
||||||
OrderFee: decimal.RequireFromString("0.5"),
|
|
||||||
Amount: decimal.RequireFromString("100"),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "包含可選字段",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
ReferenceBrand: ptr("OtherBrand"),
|
|
||||||
WalletStatus: ptrInt64(1),
|
|
||||||
ThreePartyStatus: ptrInt64(2),
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
expected: &createOrderReq{
|
|
||||||
BusinessID: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUID: "UID123",
|
|
||||||
ReferenceID: "REF123",
|
|
||||||
Count: decimal.RequireFromString("10.5"),
|
|
||||||
OrderFee: decimal.RequireFromString("0.5"),
|
|
||||||
Amount: decimal.RequireFromString("100"),
|
|
||||||
ReferenceBrand: ptr("OtherBrand"),
|
|
||||||
WalletStatus: ptrInt64(1),
|
|
||||||
ThreePartyStatus: ptrInt64(2),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "無效的十進制字段",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "invalid-decimal", // 無效的數值
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "空字符串的可選欄位應返回 nil",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
ThirdPartyFee: ptr(""), // 空字符串
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
expected: &createOrderReq{
|
|
||||||
BusinessID: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUID: "UID123",
|
|
||||||
ReferenceID: "REF123",
|
|
||||||
Count: decimal.RequireFromString("10.5"),
|
|
||||||
OrderFee: decimal.RequireFromString("0.5"),
|
|
||||||
Amount: decimal.RequireFromString("100"),
|
|
||||||
ThirdPartyFee: nil, // 空字符串應返回 nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
result, err := buildCreateOrderReq(tt.input)
|
|
||||||
if tt.expectErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expected, result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCreateOrder(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
// 初始化 mock 依賴
|
|
||||||
mockOrderModel := mockmodel.NewMockOrderModel(ctrl)
|
|
||||||
mockValidate := mocksvc.NewMockValidate(ctrl)
|
|
||||||
|
|
||||||
// 初始化服務上下文
|
|
||||||
svcCtx := &svc.ServiceContext{
|
|
||||||
OrderModel: mockOrderModel,
|
|
||||||
Validate: mockValidate,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試數據集
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input *order.CreateOrderReq
|
|
||||||
prepare func()
|
|
||||||
expectErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "成功建立訂單",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬資料庫插入成功
|
|
||||||
mockOrderModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "建立訂單時驗證失敗",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證失敗
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "插入資料庫失敗",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬插入資料庫失敗
|
|
||||||
mockOrderModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(errors.New("insert failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "成功建立訂單,必填字段",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬資料庫插入成功
|
|
||||||
mockOrderModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "成功建立訂單,可選字段有值",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
ReferenceBrand: ptr("OtherBrand"),
|
|
||||||
WalletStatus: ptrInt64(1),
|
|
||||||
CryptoType: ptr("BTC"),
|
|
||||||
PaymentFiat: ptr("USD"),
|
|
||||||
OrderArrivalTime: ptrInt64(time.Now().UTC().Unix()),
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬資料庫插入成功
|
|
||||||
mockOrderModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "部分可選字段有值,其他為空",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
ReferenceBrand: ptr("OtherBrand"),
|
|
||||||
WalletStatus: ptrInt64(1),
|
|
||||||
CryptoType: nil, // 空
|
|
||||||
PaymentFiat: nil, // 空
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬資料庫插入成功
|
|
||||||
mockOrderModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "無效的十進制數字",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "invalid", // 無效的數值
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 無需調用資料庫操作,因為會在驗證或轉換時失敗
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "可選欄位為空字符串",
|
|
||||||
input: &order.CreateOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
ThirdPartyFee: ptr(""), // 空字符串
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬資料庫插入成功
|
|
||||||
mockOrderModel.EXPECT().Insert(gomock.Any(), gomock.Any()).Return(nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// 設置測試環境
|
|
||||||
tt.prepare()
|
|
||||||
|
|
||||||
// 初始化 CreateOrderLogic
|
|
||||||
logic := NewCreateOrderLogic(context.TODO(), svcCtx)
|
|
||||||
|
|
||||||
// 執行 CreateOrder
|
|
||||||
resp, err := logic.CreateOrder(tt.input)
|
|
||||||
|
|
||||||
// 驗證結果
|
|
||||||
if tt.expectErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, resp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ================================ 輔助函數 ================================
|
|
||||||
func ptr(s string) *string {
|
|
||||||
return &s
|
|
||||||
}
|
|
||||||
|
|
||||||
func ptrInt64(i int64) *int64 {
|
|
||||||
return &i
|
|
||||||
}
|
|
||||||
|
|
||||||
// decimalPtr 是一個輔助函數,用來將字串轉換為 *decimal.Decimal 指針
|
|
||||||
func decimalPtr(val string) *decimal.Decimal {
|
|
||||||
d, _ := decimal.NewFromString(val)
|
|
||||||
return &d
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Helper function for decimal conversion with nil support and logging
|
|
||||||
func decimalPtrFromString(val string) *decimal.Decimal {
|
|
||||||
if val == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
dec, err := decimal.NewFromString(val)
|
|
||||||
if err != nil {
|
|
||||||
logx.Errorf("Failed to convert string to decimal: %v", err)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &dec
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert decimal.Decimal to primitive.Decimal128 and handle nil values
|
|
||||||
func convertDecimalPtrToDecimal128(d *decimal.Decimal) *primitive.Decimal128 {
|
|
||||||
if d == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result, err := primitive.ParseDecimal128(d.String())
|
|
||||||
if err != nil {
|
|
||||||
logx.Errorf("Failed to convert decimal to Decimal128: %v", err)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert decimal.Decimal (non-pointer) to primitive.Decimal128 and log errors
|
|
||||||
func convertDecimalToDecimal128(d decimal.Decimal) primitive.Decimal128 {
|
|
||||||
result, err := primitive.ParseDecimal128(d.String())
|
|
||||||
if err != nil {
|
|
||||||
logx.Errorf("Failed to convert decimal to Decimal128: %v", err)
|
|
||||||
|
|
||||||
return primitive.NewDecimal128(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
// 將 primitive.Decimal128 轉換為字符串
|
|
||||||
func convertDecimal128ToString(d128 *primitive.Decimal128) *string {
|
|
||||||
if d128 == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
result := d128.String()
|
|
||||||
|
|
||||||
return &result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions for optional fields
|
|
||||||
func optionalString(s *string) *string {
|
|
||||||
if s != nil {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func optionalInt64(i *int64) *int64 {
|
|
||||||
if i != nil {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func nilString(s *string) *string {
|
|
||||||
if s == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
||||||
func nilInt64(i *int64) *int64 {
|
|
||||||
if i == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return i
|
|
||||||
}
|
|
|
@ -1,12 +1,10 @@
|
||||||
package orderservicelogic
|
package orderservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
ers "code.30cm.net/digimon/library-go/errs"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -25,25 +23,9 @@ func NewDeleteOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Delet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteOrderQuery 刪除訂單(軟刪除)
|
|
||||||
type DeleteOrderQuery struct {
|
|
||||||
BusinessID string `json:"business_id" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteOrder 刪除訂單(軟刪除)
|
// DeleteOrder 刪除訂單(軟刪除)
|
||||||
func (l *DeleteOrderLogic) DeleteOrder(in *order.DeleteOrderReq) (*order.OKResp, error) {
|
func (l *DeleteOrderLogic) DeleteOrder(in *order.DeleteOrderReq) (*order.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 &order.OKResp{}, nil
|
return &order.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,97 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
mocksvc "app-cloudep-order-server/internal/mock/lib"
|
|
||||||
mockmodel "app-cloudep-order-server/internal/mock/model"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestDeleteOrder(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
// 初始化 mock 依賴
|
|
||||||
mockOrderModel := mockmodel.NewMockOrderModel(ctrl)
|
|
||||||
mockValidate := mocksvc.NewMockValidate(ctrl)
|
|
||||||
|
|
||||||
// 初始化服務上下文
|
|
||||||
svcCtx := &svc.ServiceContext{
|
|
||||||
OrderModel: mockOrderModel,
|
|
||||||
Validate: mockValidate,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試數據集
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input *order.DeleteOrderReq
|
|
||||||
prepare func()
|
|
||||||
expectErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "成功刪除訂單",
|
|
||||||
input: &order.DeleteOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬資料庫刪除成功
|
|
||||||
mockOrderModel.EXPECT().DeleteByBusinessID(gomock.Any(), "B123").Return(nil, nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "驗證失敗",
|
|
||||||
input: &order.DeleteOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證失敗
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "刪除資料庫失敗",
|
|
||||||
input: &order.DeleteOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬資料庫刪除失敗
|
|
||||||
mockOrderModel.EXPECT().DeleteByBusinessID(gomock.Any(), "B123").Return(nil, errors.New("delete failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// 設置測試環境
|
|
||||||
tt.prepare()
|
|
||||||
|
|
||||||
// 初始化 DeleteOrderLogic
|
|
||||||
logic := NewDeleteOrderLogic(context.TODO(), svcCtx)
|
|
||||||
|
|
||||||
// 執行 DeleteOrder
|
|
||||||
resp, err := logic.DeleteOrder(tt.input)
|
|
||||||
|
|
||||||
// 驗證結果
|
|
||||||
if tt.expectErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, resp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,14 +1,10 @@
|
||||||
package orderservicelogic
|
package orderservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
"app-cloudep-order-server/internal/domain"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
|
|
||||||
ers "code.30cm.net/digimon/library-go/errs"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
"github.com/zeromicro/go-zero/core/stores/mon"
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -27,67 +23,9 @@ func NewGetOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOrderQuery 取得訂單
|
|
||||||
type GetOrderQuery struct {
|
|
||||||
BusinessID string `json:"business_id" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOrder 取得訂單詳情
|
// GetOrder 取得訂單詳情
|
||||||
func (l *GetOrderLogic) GetOrder(in *order.GetOrderReq) (*order.GetOrderResp, error) {
|
func (l *GetOrderLogic) GetOrder(in *order.GetOrderReq) (*order.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())
|
|
||||||
}
|
|
||||||
|
|
||||||
o, err := l.svcCtx.OrderModel.FindOneBusinessID(l.ctx, in.GetBusinessId())
|
return &order.GetOrderResp{}, nil
|
||||||
if err != nil {
|
|
||||||
if errors.Is(mon.ErrNotFound, err) {
|
|
||||||
return nil, domain.NotFoundError(domain.DataNotFoundErrorCode, "failed to get this order id:", in.GetBusinessId())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &order.GetOrderResp{
|
|
||||||
UpdateTime: o.UpdateTime,
|
|
||||||
CreateTime: o.CreateTime,
|
|
||||||
BusinessId: o.BusinessID,
|
|
||||||
OrderType: int32(o.OrderType),
|
|
||||||
OrderStatus: int32(o.OrderStatus),
|
|
||||||
Brand: o.Brand,
|
|
||||||
OrderUid: o.OrderUID,
|
|
||||||
ReferenceId: o.ReferenceID,
|
|
||||||
Count: o.Count.String(),
|
|
||||||
OrderFee: o.OrderFee.String(),
|
|
||||||
Amount: o.Amount.String(),
|
|
||||||
// 下面的為未來擴充用的欄位
|
|
||||||
ReferenceBrand: nilString(o.ReferenceBrand),
|
|
||||||
ReferenceUid: nilString(o.ReferenceUID),
|
|
||||||
WalletStatus: nilInt64(o.WalletStatus),
|
|
||||||
ThreePartyStatus: nilInt64(o.ThreePartyStatus),
|
|
||||||
DirectionType: nilInt64(o.DirectionType),
|
|
||||||
CryptoType: nilString(o.CryptoType),
|
|
||||||
ThirdPartyFee: convertDecimal128ToString(o.ThirdPartyFee),
|
|
||||||
CryptoToUsdtRate: convertDecimal128ToString(o.CryptoToUSDTRate),
|
|
||||||
FiatToUsdRate: convertDecimal128ToString(o.FiatToUSDRate),
|
|
||||||
FeeCryptoToUsdtRate: convertDecimal128ToString(o.FeeCryptoToUSDTRate),
|
|
||||||
UsdtToCryptoTypeRate: convertDecimal128ToString(o.USDTToCryptoTypeRate),
|
|
||||||
PaymentFiat: nilString(o.PaymentFiat),
|
|
||||||
PaymentUnitPrice: convertDecimal128ToString(o.PaymentUnitPrice),
|
|
||||||
PaymentTemplateId: nilString(o.PaymentTemplateID),
|
|
||||||
OrderArrivalTime: nilInt64(o.OrderArrivalTime),
|
|
||||||
OrderPaymentTime: nilInt64(o.OrderPaymentTime),
|
|
||||||
UnpaidTimeoutSecond: nilInt64(o.UnpaidTimeoutSecond),
|
|
||||||
ChainType: nilString(o.ChainType),
|
|
||||||
TxHash: nilString(o.TxHash),
|
|
||||||
FromAddress: nilString(o.FromAddress),
|
|
||||||
ToAddress: nilString(o.ToAddress),
|
|
||||||
ChainFee: convertDecimal128ToString(o.ChainFee),
|
|
||||||
ChainFeeCrypto: nilString(o.ChainFeeCrypto),
|
|
||||||
Memo: nilString(o.Memo),
|
|
||||||
OrderNote: nilString(o.OrderNote),
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,132 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
mocksvc "app-cloudep-order-server/internal/mock/lib"
|
|
||||||
mockmodel "app-cloudep-order-server/internal/mock/model"
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGetOrder(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
// 初始化 mock 依賴
|
|
||||||
mockOrderModel := mockmodel.NewMockOrderModel(ctrl)
|
|
||||||
mockValidate := mocksvc.NewMockValidate(ctrl)
|
|
||||||
|
|
||||||
// 初始化服務上下文
|
|
||||||
svcCtx := &svc.ServiceContext{
|
|
||||||
OrderModel: mockOrderModel,
|
|
||||||
Validate: mockValidate,
|
|
||||||
}
|
|
||||||
Count, _ := primitive.ParseDecimal128("10.5")
|
|
||||||
OrderFee, _ := primitive.ParseDecimal128("0.5")
|
|
||||||
Amount, _ := primitive.ParseDecimal128("100")
|
|
||||||
|
|
||||||
// 模擬返回的訂單數據
|
|
||||||
mockOrder := &model.Order{
|
|
||||||
UpdateTime: 1630000000,
|
|
||||||
CreateTime: 1620000000,
|
|
||||||
BusinessID: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUID: "UID123",
|
|
||||||
ReferenceID: "REF123",
|
|
||||||
Count: Count,
|
|
||||||
OrderFee: OrderFee,
|
|
||||||
Amount: Amount,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試數據集
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input *order.GetOrderReq
|
|
||||||
prepare func()
|
|
||||||
expectErr bool
|
|
||||||
expected *order.GetOrderResp
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "成功取得訂單",
|
|
||||||
input: &order.GetOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬查詢訂單成功
|
|
||||||
mockOrderModel.EXPECT().FindOneBusinessID(gomock.Any(), "B123").Return(mockOrder, nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
expected: &order.GetOrderResp{
|
|
||||||
UpdateTime: 1630000000,
|
|
||||||
CreateTime: 1620000000,
|
|
||||||
BusinessId: "B123",
|
|
||||||
OrderType: 1,
|
|
||||||
OrderStatus: 2,
|
|
||||||
Brand: "TestBrand",
|
|
||||||
OrderUid: "UID123",
|
|
||||||
ReferenceId: "REF123",
|
|
||||||
Count: "10.5",
|
|
||||||
OrderFee: "0.5",
|
|
||||||
Amount: "100",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "驗證失敗",
|
|
||||||
input: &order.GetOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證失敗
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("validation failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "查詢訂單失敗",
|
|
||||||
input: &order.GetOrderReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬查詢訂單失敗
|
|
||||||
mockOrderModel.EXPECT().FindOneBusinessID(gomock.Any(), "B123").Return(nil, errors.New("order not found")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// 設置測試環境
|
|
||||||
tt.prepare()
|
|
||||||
|
|
||||||
// 初始化 GetOrderLogic
|
|
||||||
logic := NewGetOrderLogic(context.TODO(), svcCtx)
|
|
||||||
|
|
||||||
// 執行 GetOrder
|
|
||||||
resp, err := logic.GetOrder(tt.input)
|
|
||||||
|
|
||||||
// 驗證結果
|
|
||||||
if tt.expectErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expected, resp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,10 @@
|
||||||
package orderservicelogic
|
package orderservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
ers "code.30cm.net/digimon/library-go/errs"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -26,125 +23,9 @@ 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 取得訂單列表
|
// ListOrder 取得訂單列表
|
||||||
func (l *ListOrderLogic) ListOrder(in *order.ListOrderReq) (*order.ListOrderResp, error) {
|
func (l *ListOrderLogic) ListOrder(in *order.ListOrderReq) (*order.ListOrderResp, error) {
|
||||||
// 驗證資料
|
// todo: add your logic here and delete this line
|
||||||
if err := l.svcCtx.Validate.ValidateAll(&GetOrderListReq{
|
|
||||||
PageIndex: in.GetPageIndex(),
|
|
||||||
PageSize: in.GetPageSize(),
|
|
||||||
}); err != nil {
|
|
||||||
// 錯誤代碼 06-011-00
|
|
||||||
return nil, ers.InvalidFormat(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
// 構建查詢條件
|
return &order.ListOrderResp{}, nil
|
||||||
req := model.GetOrderListReq{
|
|
||||||
PageIndex: in.GetPageIndex(),
|
|
||||||
PageSize: in.GetPageSize(),
|
|
||||||
ReferenceID: in.ReferenceId,
|
|
||||||
ReferenceUID: in.ReferenceUid,
|
|
||||||
BusinessID: in.BusinessId,
|
|
||||||
UID: in.Uid,
|
|
||||||
OrderType: int(in.OrderType),
|
|
||||||
DirectionType: in.DirectionType,
|
|
||||||
OrderStatus: in.OrderStatus,
|
|
||||||
StartCreateTime: in.StartCreateTime,
|
|
||||||
EndCreateTime: in.EndCreateTime,
|
|
||||||
StartUpdateTime: in.StartUpdateTime,
|
|
||||||
EndUpdateTime: in.EndUpdateTime,
|
|
||||||
StartOrderArrivalTime: in.StartOrderArrivalTime,
|
|
||||||
EndOrderArrivalTime: in.EndOrderArrivalTime,
|
|
||||||
StartOrderPaymentTime: in.StartOrderPaymentTime,
|
|
||||||
EndOrderPaymentTime: in.EndOrderPaymentTime,
|
|
||||||
CryptoType: in.CryptoType,
|
|
||||||
TxHash: in.TxHash,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查詢訂單
|
|
||||||
orders, total, err := l.svcCtx.OrderModel.ListOrder(l.ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 構建返回結果
|
|
||||||
res := make([]*order.GetOrderResp, 0, len(orders))
|
|
||||||
for _, item := range orders {
|
|
||||||
res = append(res, convertOrderToGetOrderResp(item))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &order.ListOrderResp{
|
|
||||||
Data: res,
|
|
||||||
Page: &order.Pager{
|
|
||||||
Total: total,
|
|
||||||
Index: in.GetPageIndex(),
|
|
||||||
Size: in.GetPageSize(),
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConvertOrderToGetOrderResp 將 Order 結構轉換為 GetOrderResp
|
|
||||||
func convertOrderToGetOrderResp(o model.Order) *order.GetOrderResp {
|
|
||||||
return &order.GetOrderResp{
|
|
||||||
BusinessId: o.BusinessID,
|
|
||||||
OrderType: int32(o.OrderType),
|
|
||||||
OrderStatus: int32(o.OrderStatus),
|
|
||||||
Brand: o.Brand,
|
|
||||||
OrderUid: o.OrderUID,
|
|
||||||
ReferenceId: o.ReferenceID,
|
|
||||||
Count: o.Count.String(),
|
|
||||||
OrderFee: o.OrderFee.String(),
|
|
||||||
Amount: o.Amount.String(),
|
|
||||||
ReferenceBrand: optionalString(o.ReferenceBrand),
|
|
||||||
ReferenceUid: optionalString(o.ReferenceUID),
|
|
||||||
WalletStatus: optionalInt64(o.WalletStatus),
|
|
||||||
ThreePartyStatus: optionalInt64(o.ThreePartyStatus),
|
|
||||||
DirectionType: optionalInt64(o.DirectionType),
|
|
||||||
CryptoType: optionalString(o.CryptoType),
|
|
||||||
ThirdPartyFee: convertDecimal128ToString(o.ThirdPartyFee),
|
|
||||||
CryptoToUsdtRate: convertDecimal128ToString(o.CryptoToUSDTRate),
|
|
||||||
FiatToUsdRate: convertDecimal128ToString(o.FiatToUSDRate),
|
|
||||||
FeeCryptoToUsdtRate: convertDecimal128ToString(o.FeeCryptoToUSDTRate),
|
|
||||||
UsdtToCryptoTypeRate: convertDecimal128ToString(o.USDTToCryptoTypeRate),
|
|
||||||
PaymentFiat: optionalString(o.PaymentFiat),
|
|
||||||
PaymentUnitPrice: convertDecimal128ToString(o.PaymentUnitPrice),
|
|
||||||
PaymentTemplateId: optionalString(o.PaymentTemplateID),
|
|
||||||
OrderArrivalTime: optionalInt64(o.OrderArrivalTime),
|
|
||||||
OrderPaymentTime: optionalInt64(o.OrderPaymentTime),
|
|
||||||
UnpaidTimeoutSecond: optionalInt64(o.UnpaidTimeoutSecond),
|
|
||||||
ChainType: optionalString(o.ChainType),
|
|
||||||
TxHash: optionalString(o.TxHash),
|
|
||||||
FromAddress: optionalString(o.FromAddress),
|
|
||||||
ToAddress: optionalString(o.ToAddress),
|
|
||||||
ChainFee: convertDecimal128ToString(o.ChainFee),
|
|
||||||
ChainFeeCrypto: optionalString(o.ChainFeeCrypto),
|
|
||||||
Memo: optionalString(o.Memo),
|
|
||||||
OrderNote: optionalString(o.OrderNote),
|
|
||||||
CreateTime: o.CreateTime,
|
|
||||||
UpdateTime: o.UpdateTime,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,444 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
// func TestConvertOrdersToGetOrderResp(t *testing.T) {
|
|
||||||
// tests := []struct {
|
|
||||||
// name string
|
|
||||||
// input []model.Order
|
|
||||||
// expected []*order.GetOrderResp
|
|
||||||
// }{
|
|
||||||
// {
|
|
||||||
// name: "空訂單列表",
|
|
||||||
// input: []model.Order{},
|
|
||||||
// expected: []*order.GetOrderResp{},
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "單筆訂單",
|
|
||||||
// input: []model.Order{
|
|
||||||
// {
|
|
||||||
// BusinessID: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUID: "UID123",
|
|
||||||
// ReferenceID: "REF123",
|
|
||||||
// Count: decimal.RequireFromString("10.5"),
|
|
||||||
// OrderFee: decimal.RequireFromString("0.5"),
|
|
||||||
// Amount: decimal.RequireFromString("100"),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// expected: []*order.GetOrderResp{
|
|
||||||
// {
|
|
||||||
// BusinessId: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUid: "UID123",
|
|
||||||
// ReferenceId: "REF123",
|
|
||||||
// Count: "10.5",
|
|
||||||
// OrderFee: "0.5",
|
|
||||||
// Amount: "100",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "多筆訂單",
|
|
||||||
// input: []model.Order{
|
|
||||||
// {
|
|
||||||
// BusinessID: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUID: "UID123",
|
|
||||||
// ReferenceID: "REF123",
|
|
||||||
// Count: decimal.RequireFromString("10.5"),
|
|
||||||
// OrderFee: decimal.RequireFromString("0.5"),
|
|
||||||
// Amount: decimal.RequireFromString("100"),
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// BusinessID: "B456",
|
|
||||||
// OrderType: 2,
|
|
||||||
// OrderStatus: 3,
|
|
||||||
// Brand: "OtherBrand",
|
|
||||||
// OrderUID: "UID456",
|
|
||||||
// ReferenceID: "REF456",
|
|
||||||
// Count: decimal.RequireFromString("20"),
|
|
||||||
// OrderFee: decimal.RequireFromString("1"),
|
|
||||||
// Amount: decimal.RequireFromString("200"),
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// expected: []*order.GetOrderResp{
|
|
||||||
// {
|
|
||||||
// BusinessId: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUid: "UID123",
|
|
||||||
// ReferenceId: "REF123",
|
|
||||||
// Count: "10.5",
|
|
||||||
// OrderFee: "0.5",
|
|
||||||
// Amount: "100",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// BusinessId: "B456",
|
|
||||||
// OrderType: 2,
|
|
||||||
// OrderStatus: 3,
|
|
||||||
// Brand: "OtherBrand",
|
|
||||||
// OrderUid: "UID456",
|
|
||||||
// ReferenceId: "REF456",
|
|
||||||
// Count: "20",
|
|
||||||
// OrderFee: "1",
|
|
||||||
// Amount: "200",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for _, tt := range tests {
|
|
||||||
// t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// // 執行 ConvertOrdersToGetOrderResp 函數
|
|
||||||
// result := ConvertOrdersToGetOrderResp(tt.input)
|
|
||||||
//
|
|
||||||
// // 驗證結果
|
|
||||||
// assert.Equal(t, tt.expected, result)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func TestOptionalString(t *testing.T) {
|
|
||||||
// t.Run("非 nil 字串", func(t *testing.T) {
|
|
||||||
// str := "hello"
|
|
||||||
// result := optionalString(&str)
|
|
||||||
// assert.NotNil(t, result)
|
|
||||||
// assert.Equal(t, &str, result)
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// t.Run("nil 字串", func(t *testing.T) {
|
|
||||||
// result := optionalString(nil)
|
|
||||||
// assert.Nil(t, result)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func TestOptionalInt64(t *testing.T) {
|
|
||||||
// t.Run("非 nil int64", func(t *testing.T) {
|
|
||||||
// num := int64(123)
|
|
||||||
// result := optionalInt64(&num)
|
|
||||||
// assert.NotNil(t, result)
|
|
||||||
// assert.Equal(t, &num, result)
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// t.Run("nil int64", func(t *testing.T) {
|
|
||||||
// result := optionalInt64(nil)
|
|
||||||
// assert.Nil(t, result)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func TestOptionalDecimalToString(t *testing.T) {
|
|
||||||
// t.Run("非 nil decimal", func(t *testing.T) {
|
|
||||||
// dec := decimal.NewFromInt(123)
|
|
||||||
// expected := "123"
|
|
||||||
// result := optionalDecimalToString(&dec)
|
|
||||||
// assert.NotNil(t, result)
|
|
||||||
// assert.Equal(t, &expected, result)
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// t.Run("nil decimal", func(t *testing.T) {
|
|
||||||
// result := optionalDecimalToString(nil)
|
|
||||||
// assert.Nil(t, result)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func TestConvertOrderToGetOrderResp(t *testing.T) {
|
|
||||||
// tests := []struct {
|
|
||||||
// name string
|
|
||||||
// input model.Order
|
|
||||||
// expected *order.GetOrderResp
|
|
||||||
// }{
|
|
||||||
// {
|
|
||||||
// name: "所有欄位都有值",
|
|
||||||
// input: model.Order{
|
|
||||||
// BusinessID: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUID: "UID123",
|
|
||||||
// ReferenceID: "REF123",
|
|
||||||
// Count: decimal.RequireFromString("10.5"),
|
|
||||||
// OrderFee: decimal.RequireFromString("0.5"),
|
|
||||||
// Amount: decimal.RequireFromString("100"),
|
|
||||||
// ReferenceBrand: ptrString("OtherBrand"),
|
|
||||||
// ReferenceUID: ptrString("REFUID"),
|
|
||||||
// WalletStatus: ptrInt64(1),
|
|
||||||
// ThreePartyStatus: ptrInt64(2),
|
|
||||||
// DirectionType: ptrInt64(1),
|
|
||||||
// CryptoType: ptrString("BTC"),
|
|
||||||
// ThirdPartyFee: decimalPtrFromString("0.01"),
|
|
||||||
// CryptoToUSDTRate: decimalPtrFromString("50000"),
|
|
||||||
// FiatToUSDRate: decimalPtrFromString("1"),
|
|
||||||
// FeeCryptoToUSDTRate: decimalPtrFromString("0.02"),
|
|
||||||
// USDTToCryptoTypeRate: decimalPtrFromString("0.00002"),
|
|
||||||
// PaymentFiat: ptrString("USD"),
|
|
||||||
// PaymentUnitPrice: decimalPtrFromString("50000"),
|
|
||||||
// PaymentTemplateID: ptrString("TEMPLATE123"),
|
|
||||||
// OrderArrivalTime: ptrInt64(1630000000),
|
|
||||||
// OrderPaymentTime: ptrInt64(1620000000),
|
|
||||||
// UnpaidTimeoutSecond: ptrInt64(3600),
|
|
||||||
// ChainType: ptrString("ETH"),
|
|
||||||
// TxHash: ptrString("0xABC123"),
|
|
||||||
// FromAddress: ptrString("0xFROM123"),
|
|
||||||
// ToAddress: ptrString("0xTO123"),
|
|
||||||
// ChainFee: decimalPtrFromString("0.001"),
|
|
||||||
// ChainFeeCrypto: ptrString("ETH"),
|
|
||||||
// Memo: ptrString("Test Memo"),
|
|
||||||
// OrderNote: ptrString("Test Note"),
|
|
||||||
// CreateTime: 1620000000,
|
|
||||||
// UpdateTime: 1630000000,
|
|
||||||
// },
|
|
||||||
// expected: &order.GetOrderResp{
|
|
||||||
// BusinessId: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUid: "UID123",
|
|
||||||
// ReferenceId: "REF123",
|
|
||||||
// Count: "10.5",
|
|
||||||
// OrderFee: "0.5",
|
|
||||||
// Amount: "100",
|
|
||||||
// ReferenceBrand: ptrString("OtherBrand"),
|
|
||||||
// ReferenceUid: ptrString("REFUID"),
|
|
||||||
// WalletStatus: ptrInt64(1),
|
|
||||||
// ThreePartyStatus: ptrInt64(2),
|
|
||||||
// DirectionType: ptrInt64(1),
|
|
||||||
// CryptoType: ptrString("BTC"),
|
|
||||||
// ThirdPartyFee: ptrString("0.01"),
|
|
||||||
// CryptoToUsdtRate: ptrString("50000"),
|
|
||||||
// FiatToUsdRate: ptrString("1"),
|
|
||||||
// FeeCryptoToUsdtRate: ptrString("0.02"),
|
|
||||||
// UsdtToCryptoTypeRate: ptrString("0.00002"),
|
|
||||||
// PaymentFiat: ptrString("USD"),
|
|
||||||
// PaymentUnitPrice: ptrString("50000"),
|
|
||||||
// PaymentTemplateId: ptrString("TEMPLATE123"),
|
|
||||||
// OrderArrivalTime: ptrInt64(1630000000),
|
|
||||||
// OrderPaymentTime: ptrInt64(1620000000),
|
|
||||||
// UnpaidTimeoutSecond: ptrInt64(3600),
|
|
||||||
// ChainType: ptrString("ETH"),
|
|
||||||
// TxHash: ptrString("0xABC123"),
|
|
||||||
// FromAddress: ptrString("0xFROM123"),
|
|
||||||
// ToAddress: ptrString("0xTO123"),
|
|
||||||
// ChainFee: ptrString("0.001"),
|
|
||||||
// ChainFeeCrypto: ptrString("ETH"),
|
|
||||||
// Memo: ptrString("Test Memo"),
|
|
||||||
// OrderNote: ptrString("Test Note"),
|
|
||||||
// CreateTime: 1620000000,
|
|
||||||
// UpdateTime: 1630000000,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "部分欄位為 nil",
|
|
||||||
// input: model.Order{
|
|
||||||
// BusinessID: "B456",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUID: "UID456",
|
|
||||||
// ReferenceID: "REF456",
|
|
||||||
// Count: decimal.RequireFromString("10"),
|
|
||||||
// OrderFee: decimal.RequireFromString("1"),
|
|
||||||
// Amount: decimal.RequireFromString("100"),
|
|
||||||
// ReferenceBrand: nil,
|
|
||||||
// ReferenceUID: nil,
|
|
||||||
// WalletStatus: nil,
|
|
||||||
// ThreePartyStatus: nil,
|
|
||||||
// DirectionType: nil,
|
|
||||||
// CryptoType: nil,
|
|
||||||
// ThirdPartyFee: nil,
|
|
||||||
// CryptoToUSDTRate: nil,
|
|
||||||
// FiatToUSDRate: nil,
|
|
||||||
// FeeCryptoToUSDTRate: nil,
|
|
||||||
// USDTToCryptoTypeRate: nil,
|
|
||||||
// PaymentFiat: nil,
|
|
||||||
// PaymentUnitPrice: nil,
|
|
||||||
// PaymentTemplateID: nil,
|
|
||||||
// OrderArrivalTime: nil,
|
|
||||||
// OrderPaymentTime: nil,
|
|
||||||
// UnpaidTimeoutSecond: nil,
|
|
||||||
// ChainType: nil,
|
|
||||||
// TxHash: nil,
|
|
||||||
// FromAddress: nil,
|
|
||||||
// ToAddress: nil,
|
|
||||||
// ChainFee: nil,
|
|
||||||
// ChainFeeCrypto: nil,
|
|
||||||
// Memo: nil,
|
|
||||||
// OrderNote: nil,
|
|
||||||
// CreateTime: 1620000000,
|
|
||||||
// UpdateTime: 1630000000,
|
|
||||||
// },
|
|
||||||
// expected: &order.GetOrderResp{
|
|
||||||
// BusinessId: "B456",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUid: "UID456",
|
|
||||||
// ReferenceId: "REF456",
|
|
||||||
// Count: "10",
|
|
||||||
// OrderFee: "1",
|
|
||||||
// Amount: "100",
|
|
||||||
// ReferenceBrand: nil,
|
|
||||||
// ReferenceUid: nil,
|
|
||||||
// WalletStatus: nil,
|
|
||||||
// ThreePartyStatus: nil,
|
|
||||||
// DirectionType: nil,
|
|
||||||
// CryptoType: nil,
|
|
||||||
// ThirdPartyFee: nil,
|
|
||||||
// CryptoToUsdtRate: nil,
|
|
||||||
// FiatToUsdRate: nil,
|
|
||||||
// FeeCryptoToUsdtRate: nil,
|
|
||||||
// UsdtToCryptoTypeRate: nil,
|
|
||||||
// PaymentFiat: nil,
|
|
||||||
// PaymentUnitPrice: nil,
|
|
||||||
// PaymentTemplateId: nil,
|
|
||||||
// OrderArrivalTime: nil,
|
|
||||||
// OrderPaymentTime: nil,
|
|
||||||
// UnpaidTimeoutSecond: nil,
|
|
||||||
// ChainType: nil,
|
|
||||||
// TxHash: nil,
|
|
||||||
// FromAddress: nil,
|
|
||||||
// ToAddress: nil,
|
|
||||||
// ChainFee: nil,
|
|
||||||
// ChainFeeCrypto: nil,
|
|
||||||
// Memo: nil,
|
|
||||||
// OrderNote: nil,
|
|
||||||
// CreateTime: 1620000000,
|
|
||||||
// UpdateTime: 1630000000,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for _, tt := range tests {
|
|
||||||
// t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// // 執行 ConvertOrderToGetOrderResp 函數
|
|
||||||
// result := ConvertOrderToGetOrderResp(tt.input)
|
|
||||||
//
|
|
||||||
// // 驗證結果
|
|
||||||
// assert.Equal(t, tt.expected, result)
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// func TestListOrder(t *testing.T) {
|
|
||||||
// ctrl := gomock.NewController(t)
|
|
||||||
// defer ctrl.Finish()
|
|
||||||
//
|
|
||||||
// // 初始化 mock 依賴
|
|
||||||
// mockOrderModel := mockmodel.NewMockOrderModel(ctrl)
|
|
||||||
// mockValidate := mocksvc.NewMockValidate(ctrl)
|
|
||||||
//
|
|
||||||
// // 初始化服務上下文
|
|
||||||
// svcCtx := &svc.ServiceContext{
|
|
||||||
// OrderModel: mockOrderModel,
|
|
||||||
// Validate: mockValidate,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // 測試數據集
|
|
||||||
// tests := []struct {
|
|
||||||
// name string
|
|
||||||
// input *order.ListOrderReq
|
|
||||||
// prepare func()
|
|
||||||
// expectErr bool
|
|
||||||
// expectedRes *order.ListOrderResp
|
|
||||||
// }{
|
|
||||||
// {
|
|
||||||
// name: "成功取得訂單列表",
|
|
||||||
// input: &order.ListOrderReq{
|
|
||||||
// PageIndex: 1,
|
|
||||||
// PageSize: 10,
|
|
||||||
// },
|
|
||||||
// prepare: func() {
|
|
||||||
// // 模擬驗證成功
|
|
||||||
// mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// // 模擬返回訂單列表
|
|
||||||
// mockOrderModel.EXPECT().ListOrder(gomock.Any(), gomock.Any()).Return([]model.Order{
|
|
||||||
// {
|
|
||||||
// BusinessID: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUID: "UID123",
|
|
||||||
// ReferenceID: "REF123",
|
|
||||||
// Count: decimal.RequireFromString("10.5"),
|
|
||||||
// OrderFee: decimal.RequireFromString("0.5"),
|
|
||||||
// Amount: decimal.RequireFromString("100"),
|
|
||||||
// },
|
|
||||||
// }, int64(1), nil).Times(1)
|
|
||||||
// },
|
|
||||||
// expectErr: false,
|
|
||||||
// expectedRes: &order.ListOrderResp{
|
|
||||||
// Data: []*order.GetOrderResp{
|
|
||||||
// {
|
|
||||||
// BusinessId: "B123",
|
|
||||||
// OrderType: 1,
|
|
||||||
// OrderStatus: 2,
|
|
||||||
// Brand: "TestBrand",
|
|
||||||
// OrderUid: "UID123",
|
|
||||||
// ReferenceId: "REF123",
|
|
||||||
// Count: "10.5",
|
|
||||||
// OrderFee: "0.5",
|
|
||||||
// Amount: "100",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// Page: &order.Pager{
|
|
||||||
// Total: 1,
|
|
||||||
// Index: 1,
|
|
||||||
// Size: 10,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "訂單查詢失敗",
|
|
||||||
// input: &order.ListOrderReq{
|
|
||||||
// PageIndex: 1,
|
|
||||||
// PageSize: 10,
|
|
||||||
// },
|
|
||||||
// prepare: func() {
|
|
||||||
// // 模擬驗證成功
|
|
||||||
// mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// // 模擬返回查詢錯誤
|
|
||||||
// mockOrderModel.EXPECT().ListOrder(gomock.Any(), gomock.Any()).Return(nil, int64(0), errors.New("query failed")).Times(1)
|
|
||||||
// },
|
|
||||||
// expectErr: true,
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: "分頁錯誤",
|
|
||||||
// input: &order.ListOrderReq{
|
|
||||||
// PageIndex: 0,
|
|
||||||
// PageSize: 10,
|
|
||||||
// },
|
|
||||||
// prepare: func() {
|
|
||||||
// // 模擬驗證失敗,因為 PageIndex 為 0
|
|
||||||
// mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("invalid pagination")).Times(1)
|
|
||||||
// },
|
|
||||||
// expectErr: true,
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for _, tt := range tests {
|
|
||||||
// t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// // 準備測試環境
|
|
||||||
// tt.prepare()
|
|
||||||
//
|
|
||||||
// // 初始化 ListOrderLogic
|
|
||||||
// logic := NewListOrderLogic(context.TODO(), svcCtx)
|
|
||||||
//
|
|
||||||
// // 執行 ListOrder
|
|
||||||
// resp, err := logic.ListOrder(tt.input)
|
|
||||||
//
|
|
||||||
// // 驗證結果
|
|
||||||
// if tt.expectErr {
|
|
||||||
// assert.Error(t, err)
|
|
||||||
// assert.Nil(t, resp)
|
|
||||||
// } else {
|
|
||||||
// assert.NoError(t, err)
|
|
||||||
// assert.Equal(t, tt.expectedRes, resp)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
|
@ -1,14 +1,10 @@
|
||||||
package orderservicelogic
|
package orderservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
"app-cloudep-order-server/internal/domain"
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
ers "code.30cm.net/digimon/library-go/errs"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -27,46 +23,9 @@ 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 修改訂單狀態
|
// ModifyOrderStatus 修改訂單狀態
|
||||||
func (l *ModifyOrderStatusLogic) ModifyOrderStatus(in *order.ModifyOrderStatusReq) (*order.OKResp, error) {
|
func (l *ModifyOrderStatusLogic) ModifyOrderStatus(in *order.ModifyOrderStatusReq) (*order.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 &order.OKResp{}, nil
|
return &order.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
mocksvc "app-cloudep-order-server/internal/mock/lib"
|
|
||||||
mockmodel "app-cloudep-order-server/internal/mock/model"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestModifyOrderStatus(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
// 初始化 mock 依賴
|
|
||||||
mockOrderModel := mockmodel.NewMockOrderModel(ctrl)
|
|
||||||
mockValidate := mocksvc.NewMockValidate(ctrl)
|
|
||||||
|
|
||||||
// 初始化服務上下文
|
|
||||||
svcCtx := &svc.ServiceContext{
|
|
||||||
OrderModel: mockOrderModel,
|
|
||||||
Validate: mockValidate,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試數據集
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
input *order.ModifyOrderStatusReq
|
|
||||||
prepare func()
|
|
||||||
expectErr bool
|
|
||||||
expectedRes *order.OKResp
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "成功修改訂單狀態",
|
|
||||||
input: &order.ModifyOrderStatusReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
Status: 3,
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬狀態更新成功
|
|
||||||
mockOrderModel.EXPECT().UpdateStatus(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
expectedRes: &order.OKResp{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "驗證失敗",
|
|
||||||
input: &order.ModifyOrderStatusReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
Status: 12, // 錯誤的狀態值
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證失敗
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(errors.New("invalid status")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "修改訂單狀態失敗",
|
|
||||||
input: &order.ModifyOrderStatusReq{
|
|
||||||
BusinessId: "B123",
|
|
||||||
Status: 3,
|
|
||||||
},
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬驗證成功
|
|
||||||
mockValidate.EXPECT().ValidateAll(gomock.Any()).Return(nil).Times(1)
|
|
||||||
// 模擬狀態更新失敗
|
|
||||||
mockOrderModel.EXPECT().UpdateStatus(gomock.Any(), gomock.Any()).Return(nil, errors.New("update failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// 準備測試環境
|
|
||||||
tt.prepare()
|
|
||||||
|
|
||||||
// 初始化 ModifyOrderStatusLogic
|
|
||||||
logic := NewModifyOrderStatusLogic(context.TODO(), svcCtx)
|
|
||||||
|
|
||||||
// 執行 ModifyOrderStatus
|
|
||||||
resp, err := logic.ModifyOrderStatus(tt.input)
|
|
||||||
|
|
||||||
// 驗證結果
|
|
||||||
if tt.expectErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expectedRes, resp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,10 @@
|
||||||
package orderservicelogic
|
package orderservicelogic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
"app-cloudep-order-server/internal/domain"
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
"context"
|
"context"
|
||||||
"time"
|
|
||||||
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/logx"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
)
|
)
|
||||||
|
@ -27,25 +24,8 @@ func NewOrderStatusTimeoutLogic(ctx context.Context, svcCtx *svc.ServiceContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrderStatusTimeout 訂單超時任務/cron/order-status/timeout
|
// OrderStatusTimeout 訂單超時任務/cron/order-status/timeout
|
||||||
func (l *OrderStatusTimeoutLogic) OrderStatusTimeout(_ *order.OrderStatusTimeoutReq) (*order.OKResp, error) {
|
func (l *OrderStatusTimeoutLogic) OrderStatusTimeout(in *order.OrderStatusTimeoutReq) (*order.OKResp, error) {
|
||||||
now := time.Now().UTC().UnixNano()
|
// todo: add your logic here and delete this line
|
||||||
_, 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 &order.OKResp{}, nil
|
return &order.OKResp{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
package orderservicelogic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
mockmodel "app-cloudep-order-server/internal/mock/model"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestOrderStatusTimeout(t *testing.T) {
|
|
||||||
ctrl := gomock.NewController(t)
|
|
||||||
defer ctrl.Finish()
|
|
||||||
|
|
||||||
// 初始化 mock 依賴
|
|
||||||
mockOrderModel := mockmodel.NewMockOrderModel(ctrl)
|
|
||||||
|
|
||||||
// 初始化服務上下文
|
|
||||||
svcCtx := &svc.ServiceContext{
|
|
||||||
OrderModel: mockOrderModel,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 測試數據集
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
prepare func()
|
|
||||||
expectErr bool
|
|
||||||
expectedRes *order.OKResp
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "成功更新訂單狀態",
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬訂單狀態超時更新成功
|
|
||||||
mockOrderModel.EXPECT().UpdateTimeoutOrder(gomock.Any(), gomock.Any()).Return(nil, nil).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: false,
|
|
||||||
expectedRes: &order.OKResp{},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "更新訂單狀態失敗",
|
|
||||||
prepare: func() {
|
|
||||||
// 模擬訂單狀態超時更新失敗
|
|
||||||
mockOrderModel.EXPECT().UpdateTimeoutOrder(gomock.Any(), gomock.Any()).Return(nil, errors.New("update failed")).Times(1)
|
|
||||||
},
|
|
||||||
expectErr: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
// 準備測試環境
|
|
||||||
tt.prepare()
|
|
||||||
|
|
||||||
// 初始化 OrderStatusTimeoutLogic
|
|
||||||
logic := NewOrderStatusTimeoutLogic(context.TODO(), svcCtx)
|
|
||||||
|
|
||||||
// 執行 OrderStatusTimeout
|
|
||||||
resp, err := logic.OrderStatusTimeout(&order.OrderStatusTimeoutReq{})
|
|
||||||
|
|
||||||
// 驗證結果
|
|
||||||
if tt.expectErr {
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Nil(t, resp)
|
|
||||||
} else {
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.Equal(t, tt.expectedRes, resp)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
// Code generated by MockGen. DO NOT EDIT.
|
|
||||||
// Source: ./validate.go
|
|
||||||
//
|
|
||||||
// Generated by this command:
|
|
||||||
//
|
|
||||||
// mockgen -source=./validate.go -destination=../../mock/lib/validate.go -package=lib
|
|
||||||
//
|
|
||||||
|
|
||||||
// Package lib is a generated GoMock package.
|
|
||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
reflect "reflect"
|
|
||||||
|
|
||||||
required "code.30cm.net/digimon/library-go/validator"
|
|
||||||
|
|
||||||
gomock "go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockValidate is a mock of Validate interface.
|
|
||||||
type MockValidate struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockValidateMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockValidateMockRecorder is the mock recorder for MockValidate.
|
|
||||||
type MockValidateMockRecorder struct {
|
|
||||||
mock *MockValidate
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockValidate creates a new mock instance.
|
|
||||||
func NewMockValidate(ctrl *gomock.Controller) *MockValidate {
|
|
||||||
mock := &MockValidate{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockValidateMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockValidate) EXPECT() *MockValidateMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindToValidator mocks base method.
|
|
||||||
func (m *MockValidate) BindToValidator(opts ...required.Option) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
varargs := []any{}
|
|
||||||
for _, a := range opts {
|
|
||||||
varargs = append(varargs, a)
|
|
||||||
}
|
|
||||||
ret := m.ctrl.Call(m, "BindToValidator", varargs...)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// BindToValidator indicates an expected call of BindToValidator.
|
|
||||||
func (mr *MockValidateMockRecorder) BindToValidator(opts ...any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BindToValidator", reflect.TypeOf((*MockValidate)(nil).BindToValidator), opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateAll mocks base method.
|
|
||||||
func (m *MockValidate) ValidateAll(obj any) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "ValidateAll", obj)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateAll indicates an expected call of ValidateAll.
|
|
||||||
func (mr *MockValidateMockRecorder) ValidateAll(obj any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAll", reflect.TypeOf((*MockValidate)(nil).ValidateAll), obj)
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
// Code generated by MockGen. DO NOT EDIT.
|
|
||||||
// Source: ./internal/model/mongo/order_model.go
|
|
||||||
//
|
|
||||||
// Generated by this command:
|
|
||||||
//
|
|
||||||
// mockgen -source=./internal/model/mongo/order_model.go -destination=./internal/mock/model/order_model.go -package=mock
|
|
||||||
//
|
|
||||||
|
|
||||||
// Package mock is a generated GoMock package.
|
|
||||||
package mock
|
|
||||||
|
|
||||||
import (
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
context "context"
|
|
||||||
reflect "reflect"
|
|
||||||
|
|
||||||
mongo "go.mongodb.org/mongo-driver/mongo"
|
|
||||||
gomock "go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockOrderModel is a mock of OrderModel interface.
|
|
||||||
type MockOrderModel struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockOrderModelMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockOrderModelMockRecorder is the mock recorder for MockOrderModel.
|
|
||||||
type MockOrderModelMockRecorder struct {
|
|
||||||
mock *MockOrderModel
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockOrderModel creates a new mock instance.
|
|
||||||
func NewMockOrderModel(ctrl *gomock.Controller) *MockOrderModel {
|
|
||||||
mock := &MockOrderModel{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockOrderModelMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockOrderModel) EXPECT() *MockOrderModelMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete mocks base method.
|
|
||||||
func (m *MockOrderModel) Delete(ctx context.Context, id string) (int64, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Delete", ctx, id)
|
|
||||||
ret0, _ := ret[0].(int64)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete indicates an expected call of Delete.
|
|
||||||
func (mr *MockOrderModelMockRecorder) Delete(ctx, id any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockOrderModel)(nil).Delete), ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteByBusinessID mocks base method.
|
|
||||||
func (m *MockOrderModel) DeleteByBusinessID(ctx context.Context, id string) (*mongo.UpdateResult, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "DeleteByBusinessID", ctx, id)
|
|
||||||
ret0, _ := ret[0].(*mongo.UpdateResult)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteByBusinessID indicates an expected call of DeleteByBusinessID.
|
|
||||||
func (mr *MockOrderModelMockRecorder) DeleteByBusinessID(ctx, id any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByBusinessID", reflect.TypeOf((*MockOrderModel)(nil).DeleteByBusinessID), ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindOne mocks base method.
|
|
||||||
func (m *MockOrderModel) FindOne(ctx context.Context, id string) (*model.Order, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "FindOne", ctx, id)
|
|
||||||
ret0, _ := ret[0].(*model.Order)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindOne indicates an expected call of FindOne.
|
|
||||||
func (mr *MockOrderModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockOrderModel)(nil).FindOne), ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindOneBusinessID mocks base method.
|
|
||||||
func (m *MockOrderModel) FindOneBusinessID(ctx context.Context, id string) (*model.Order, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "FindOneBusinessID", ctx, id)
|
|
||||||
ret0, _ := ret[0].(*model.Order)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindOneBusinessID indicates an expected call of FindOneBusinessID.
|
|
||||||
func (mr *MockOrderModelMockRecorder) FindOneBusinessID(ctx, id any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneBusinessID", reflect.TypeOf((*MockOrderModel)(nil).FindOneBusinessID), ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert mocks base method.
|
|
||||||
func (m *MockOrderModel) Insert(ctx context.Context, data *model.Order) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Insert", ctx, data)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert indicates an expected call of Insert.
|
|
||||||
func (mr *MockOrderModelMockRecorder) Insert(ctx, data any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockOrderModel)(nil).Insert), ctx, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListOrder mocks base method.
|
|
||||||
func (m *MockOrderModel) ListOrder(ctx context.Context, req model.GetOrderListReq) ([]model.Order, int64, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "ListOrder", ctx, req)
|
|
||||||
ret0, _ := ret[0].([]model.Order)
|
|
||||||
ret1, _ := ret[1].(int64)
|
|
||||||
ret2, _ := ret[2].(error)
|
|
||||||
return ret0, ret1, ret2
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListOrder indicates an expected call of ListOrder.
|
|
||||||
func (mr *MockOrderModelMockRecorder) ListOrder(ctx, req any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListOrder", reflect.TypeOf((*MockOrderModel)(nil).ListOrder), ctx, req)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update mocks base method.
|
|
||||||
func (m *MockOrderModel) Update(ctx context.Context, data *model.Order) (*mongo.UpdateResult, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Update", ctx, data)
|
|
||||||
ret0, _ := ret[0].(*mongo.UpdateResult)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update indicates an expected call of Update.
|
|
||||||
func (mr *MockOrderModelMockRecorder) Update(ctx, data any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockOrderModel)(nil).Update), ctx, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus mocks base method.
|
|
||||||
func (m *MockOrderModel) UpdateStatus(ctx context.Context, data model.UpdateStatusReq) (*mongo.UpdateResult, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "UpdateStatus", ctx, data)
|
|
||||||
ret0, _ := ret[0].(*mongo.UpdateResult)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateStatus indicates an expected call of UpdateStatus.
|
|
||||||
func (mr *MockOrderModelMockRecorder) UpdateStatus(ctx, data any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStatus", reflect.TypeOf((*MockOrderModel)(nil).UpdateStatus), ctx, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateTimeoutOrder mocks base method.
|
|
||||||
func (m *MockOrderModel) UpdateTimeoutOrder(ctx context.Context, req model.UpdateTimeoutReq) (*mongo.UpdateResult, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "UpdateTimeoutOrder", ctx, req)
|
|
||||||
ret0, _ := ret[0].(*mongo.UpdateResult)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateTimeoutOrder indicates an expected call of UpdateTimeoutOrder.
|
|
||||||
func (mr *MockOrderModelMockRecorder) UpdateTimeoutOrder(ctx, req any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTimeoutOrder", reflect.TypeOf((*MockOrderModel)(nil).UpdateTimeoutOrder), ctx, req)
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
// Code generated by MockGen. DO NOT EDIT.
|
|
||||||
// Source: ./internal/model/mongo/order_model_gen.go
|
|
||||||
//
|
|
||||||
// Generated by this command:
|
|
||||||
//
|
|
||||||
// mockgen -source=./internal/model/mongo/order_model_gen.go -destination=./internal/mock/model/order_model_gen.go -package=mock
|
|
||||||
//
|
|
||||||
|
|
||||||
// Package mock is a generated GoMock package.
|
|
||||||
package mock
|
|
||||||
|
|
||||||
import (
|
|
||||||
model "app-cloudep-order-server/internal/model/mongo"
|
|
||||||
context "context"
|
|
||||||
reflect "reflect"
|
|
||||||
|
|
||||||
mongo "go.mongodb.org/mongo-driver/mongo"
|
|
||||||
gomock "go.uber.org/mock/gomock"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockorderModel is a mock of orderModel interface.
|
|
||||||
type MockorderModel struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockorderModelMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockorderModelMockRecorder is the mock recorder for MockorderModel.
|
|
||||||
type MockorderModelMockRecorder struct {
|
|
||||||
mock *MockorderModel
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockorderModel creates a new mock instance.
|
|
||||||
func NewMockorderModel(ctrl *gomock.Controller) *MockorderModel {
|
|
||||||
mock := &MockorderModel{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockorderModelMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
|
||||||
func (m *MockorderModel) EXPECT() *MockorderModelMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete mocks base method.
|
|
||||||
func (m *MockorderModel) Delete(ctx context.Context, id string) (int64, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Delete", ctx, id)
|
|
||||||
ret0, _ := ret[0].(int64)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete indicates an expected call of Delete.
|
|
||||||
func (mr *MockorderModelMockRecorder) Delete(ctx, id any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockorderModel)(nil).Delete), ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindOne mocks base method.
|
|
||||||
func (m *MockorderModel) FindOne(ctx context.Context, id string) (*model.Order, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "FindOne", ctx, id)
|
|
||||||
ret0, _ := ret[0].(*model.Order)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindOne indicates an expected call of FindOne.
|
|
||||||
func (mr *MockorderModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockorderModel)(nil).FindOne), ctx, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert mocks base method.
|
|
||||||
func (m *MockorderModel) Insert(ctx context.Context, data *model.Order) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Insert", ctx, data)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert indicates an expected call of Insert.
|
|
||||||
func (mr *MockorderModelMockRecorder) Insert(ctx, data any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockorderModel)(nil).Insert), ctx, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update mocks base method.
|
|
||||||
func (m *MockorderModel) Update(ctx context.Context, data *model.Order) (*mongo.UpdateResult, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "Update", ctx, data)
|
|
||||||
ret0, _ := ret[0].(*mongo.UpdateResult)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update indicates an expected call of Update.
|
|
||||||
func (mr *MockorderModelMockRecorder) Update(ctx, data any) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockorderModel)(nil).Update), ctx, data)
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/stores/mon"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
ErrNotFound = mon.ErrNotFound
|
|
||||||
ErrInvalidObjectId = errors.New("invalid objectId")
|
|
||||||
)
|
|
|
@ -1,240 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"app-cloudep-order-server/internal/domain"
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/stores/mon"
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ OrderModel = (*customOrderModel)(nil)
|
|
||||||
|
|
||||||
type (
|
|
||||||
// OrderModel is an interface to be customized, add more methods here,
|
|
||||||
// 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.
|
|
||||||
func NewOrderModel(url, db, collection string) OrderModel {
|
|
||||||
conn := mon.MustNewModel(url, db, collection)
|
|
||||||
return &customOrderModel{
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
// Code generated by goctl. DO NOT EDIT.
|
|
||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/stores/mon"
|
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
|
||||||
)
|
|
||||||
|
|
||||||
type orderModel interface {
|
|
||||||
Insert(ctx context.Context, data *Order) error
|
|
||||||
FindOne(ctx context.Context, id string) (*Order, error)
|
|
||||||
Update(ctx context.Context, data *Order) (*mongo.UpdateResult, error)
|
|
||||||
Delete(ctx context.Context, id string) (int64, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type defaultOrderModel struct {
|
|
||||||
conn *mon.Model
|
|
||||||
}
|
|
||||||
|
|
||||||
func newDefaultOrderModel(conn *mon.Model) *defaultOrderModel {
|
|
||||||
return &defaultOrderModel{conn: conn}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultOrderModel) Insert(ctx context.Context, data *Order) error {
|
|
||||||
if data.ID.IsZero() {
|
|
||||||
data.ID = primitive.NewObjectID()
|
|
||||||
data.CreateTime = time.Now().UTC().UnixNano()
|
|
||||||
data.UpdateTime = time.Now().UTC().UnixNano()
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := m.conn.InsertOne(ctx, data)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultOrderModel) FindOne(ctx context.Context, id string) (*Order, error) {
|
|
||||||
oid, err := primitive.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, ErrInvalidObjectId
|
|
||||||
}
|
|
||||||
|
|
||||||
var data Order
|
|
||||||
|
|
||||||
err = m.conn.FindOne(ctx, &data, bson.M{"_id": oid})
|
|
||||||
switch err {
|
|
||||||
case nil:
|
|
||||||
return &data, nil
|
|
||||||
case mon.ErrNotFound:
|
|
||||||
return nil, ErrNotFound
|
|
||||||
default:
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultOrderModel) Update(ctx context.Context, data *Order) (*mongo.UpdateResult, error) {
|
|
||||||
data.UpdateTime = time.Now().UTC().UnixNano()
|
|
||||||
|
|
||||||
res, err := m.conn.UpdateOne(ctx, bson.M{"_id": data.ID}, bson.M{"$set": data})
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultOrderModel) Delete(ctx context.Context, id string) (int64, error) {
|
|
||||||
oid, err := primitive.ObjectIDFromHex(id)
|
|
||||||
if err != nil {
|
|
||||||
return 0, ErrInvalidObjectId
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := m.conn.DeleteOne(ctx, bson.M{"_id": oid})
|
|
||||||
return res, err
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package model
|
|
||||||
|
|
||||||
import (
|
|
||||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Order struct {
|
|
||||||
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"` // 訂單狀態
|
|
||||||
Brand string `bson:"brand"` // 下單平台
|
|
||||||
OrderUID string `bson:"order_uid"` // 下單用戶 UID
|
|
||||||
ReferenceID string `bson:"reference_id"` // 訂單來源
|
|
||||||
Count primitive.Decimal128 `bson:"count"` // 訂單數量
|
|
||||||
OrderFee primitive.Decimal128 `bson:"order_fee"` // 訂單手續費
|
|
||||||
Amount primitive.Decimal128 `bson:"amount"` // 單價
|
|
||||||
ReferenceBrand *string `bson:"reference_brand,omitempty"` // 訂單來源平台
|
|
||||||
ReferenceUID *string `bson:"reference_uid,omitempty"` // 訂單來源用戶 UID
|
|
||||||
WalletStatus *int64 `bson:"wallet_status,omitempty"` // 交易金額狀態
|
|
||||||
ThreePartyStatus *int64 `bson:"three_party_status,omitempty"` // 三方請求狀態
|
|
||||||
DirectionType *int64 `bson:"direction_type,omitempty"` // 交易方向
|
|
||||||
CryptoType *string `bson:"crypto_type,omitempty"` // 交易幣種
|
|
||||||
ThirdPartyFee *primitive.Decimal128 `bson:"third_party_fee,omitempty"` // 第三方手續費
|
|
||||||
CryptoToUSDTRate *primitive.Decimal128 `bson:"crypto_to_usdt_rate,omitempty"` // 加密貨幣對 USDT 匯率
|
|
||||||
FiatToUSDRate *primitive.Decimal128 `bson:"fiat_to_usd_rate,omitempty"` // 法幣對 USD 匯率
|
|
||||||
FeeCryptoToUSDTRate *primitive.Decimal128 `bson:"fee_crypto_to_usdt_rate,omitempty"` // 手續費加密貨幣對 USDT 匯率
|
|
||||||
USDTToCryptoTypeRate *primitive.Decimal128 `bson:"usdt_to_crypto_type_rate,omitempty"` // USDT 對加密貨幣匯率
|
|
||||||
PaymentFiat *string `bson:"payment_fiat,omitempty"` // 支付法幣
|
|
||||||
PaymentUnitPrice *primitive.Decimal128 `bson:"payment_unit_price,omitempty"` // 加密貨幣單價
|
|
||||||
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 *primitive.Decimal128 `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"
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Code generated by goctl. DO NOT EDIT.
|
// Code generated by goctl. DO NOT EDIT.
|
||||||
|
// goctl 1.8.1
|
||||||
// Source: order.proto
|
// Source: order.proto
|
||||||
|
|
||||||
package server
|
package server
|
||||||
|
@ -6,9 +7,9 @@ package server
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
orderservicelogic "app-cloudep-order-server/internal/logic/orderservice"
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/logic/orderservice"
|
||||||
"app-cloudep-order-server/internal/svc"
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OrderServiceServer struct {
|
type OrderServiceServer struct {
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
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())
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package svc
|
|
||||||
|
|
||||||
import (
|
|
||||||
vi "code.30cm.net/digimon/library-go/validator"
|
|
||||||
"github.com/go-playground/validator/v10"
|
|
||||||
"github.com/shopspring/decimal"
|
|
||||||
)
|
|
||||||
|
|
||||||
// WithDecimalGt 是否大於等於
|
|
||||||
func WithDecimalGt() vi.Option {
|
|
||||||
return vi.Option{
|
|
||||||
ValidatorName: "decimalGt",
|
|
||||||
ValidatorFunc: func(fl validator.FieldLevel) bool {
|
|
||||||
if val, ok := fl.Field().Interface().(string); ok {
|
|
||||||
value, err := decimal.NewFromString(val)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
conditionValue, err := decimal.NewFromString(fl.Param())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.GreaterThan(conditionValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithDecimalGte 是否大於等於
|
|
||||||
func WithDecimalGte() vi.Option {
|
|
||||||
return vi.Option{
|
|
||||||
ValidatorName: "decimalGte",
|
|
||||||
ValidatorFunc: func(fl validator.FieldLevel) bool {
|
|
||||||
if val, ok := fl.Field().Interface().(string); ok {
|
|
||||||
value, err := decimal.NewFromString(val)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
conditionValue, err := decimal.NewFromString(fl.Param())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return value.GreaterThanOrEqual(conditionValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +1,13 @@
|
||||||
package svc
|
package svc
|
||||||
|
|
||||||
import (
|
import "code.30cm.net/digimon/app-cloudep-order-service/internal/config"
|
||||||
"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 {
|
type ServiceContext struct {
|
||||||
Config config.Config
|
Config config.Config
|
||||||
Validate vi.Validate
|
|
||||||
|
|
||||||
OrderModel model.OrderModel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceContext(c config.Config) *ServiceContext {
|
func NewServiceContext(c config.Config) *ServiceContext {
|
||||||
ers.Scope = code.CloudEPOrder
|
|
||||||
|
|
||||||
return &ServiceContext{
|
return &ServiceContext{
|
||||||
Config: c,
|
Config: c,
|
||||||
Validate: vi.MustValidator(WithDecimalGt(), WithDecimalGte()),
|
|
||||||
OrderModel: MustOrderModel(c),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
order.go
14
order.go
|
@ -1,13 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"app-cloudep-order-server/gen_result/pb/order"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"app-cloudep-order-server/internal/config"
|
"github.com/zeromicro/go-zero/core/logx"
|
||||||
orderserviceServer "app-cloudep-order-server/internal/server/orderservice"
|
|
||||||
"app-cloudep-order-server/internal/svc"
|
"code.30cm.net/digimon/app-cloudep-order-service/gen_result/pb/order"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/config"
|
||||||
|
orderserviceServer "code.30cm.net/digimon/app-cloudep-order-service/internal/server/orderservice"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/internal/svc"
|
||||||
|
|
||||||
"github.com/zeromicro/go-zero/core/conf"
|
"github.com/zeromicro/go-zero/core/conf"
|
||||||
"github.com/zeromicro/go-zero/core/service"
|
"github.com/zeromicro/go-zero/core/service"
|
||||||
|
@ -34,7 +35,6 @@ func main() {
|
||||||
})
|
})
|
||||||
defer s.Stop()
|
defer s.Stop()
|
||||||
|
|
||||||
//nolint:forbidigo
|
logx.Infof("Starting rpc server at %s...\n", c.ListenOn)
|
||||||
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
|
||||||
s.Start()
|
s.Start()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/pkg/domain/order"
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Order struct {
|
||||||
|
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 order.Type `bson:"order_type"` // 訂單類型
|
||||||
|
OrderStatus order.Status `bson:"order_status"` // 訂單狀態
|
||||||
|
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"` // 單價
|
||||||
|
WalletStatus int64 `bson:"wallet_status,omitempty"` // 交易金額狀態
|
||||||
|
DirectionType int64 `bson:"direction_type,omitempty"` // 交易方向
|
||||||
|
BookingInfo *BookingInfo `bson:"booking_info,omitempty"` // 寄送資訊
|
||||||
|
InvoiceInfo *InvoiceInfo `bson:"invoice_info,omitempty"` // 寄送資訊
|
||||||
|
OrderItem []OrderItem `bson:"order_item,omitempty"` // 這筆訂單所訂購的 ProductItem List
|
||||||
|
// 以上為必要欄位,下面是區塊鏈時才需要
|
||||||
|
ReferenceBrand *string `bson:"reference_brand,omitempty"` // 訂單來源平台
|
||||||
|
ReferenceUID *string `bson:"reference_uid,omitempty"` // 訂單來源用戶 UID
|
||||||
|
ThreePartyStatus *int64 `bson:"three_party_status,omitempty"` // 三方請求狀態
|
||||||
|
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"` // 加密貨幣單價
|
||||||
|
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"` // 訂單交易備註
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookingInfo struct {
|
||||||
|
SenderName string `bson:"sender_name"` // 寄件者姓名
|
||||||
|
SenderPhone string `bson:"sender_phone"` // 寄件者手機
|
||||||
|
SenderEmail string `bson:"sender_email"` // 寄件者信箱
|
||||||
|
SenderNational string `bson:"sender_national"` // 寄件者國家
|
||||||
|
SenderAddress string `bson:"sender_address"` // 寄件者地址
|
||||||
|
SenderCode string `bson:"sender_code"` // 寄件者郵遞區號
|
||||||
|
ReceiverName string `bson:"receiver_name"` // 收件者姓名
|
||||||
|
ReceiverPhone string `bson:"receiver_phone"` // 收件者手機
|
||||||
|
ReceiverEmail string `bson:"receiver_email"` // 收件者信箱
|
||||||
|
ReceiverAddress string `bson:"receiver_address"` // 收件者地址
|
||||||
|
ReceiverNational string `bson:"receiver_national"` // 收件者國家
|
||||||
|
ReceiverCode string `bson:"receiver_code"` // 收件者郵遞區號
|
||||||
|
Memo string `bson:"memo"` // 備註
|
||||||
|
}
|
||||||
|
type InvoiceInfo struct {
|
||||||
|
Type string `bson:"type"` // 發票類型
|
||||||
|
Code string `bson:"code"` // 載具條碼
|
||||||
|
Name string `bson:"name"` // 捐款人姓名 / 公司抬頭
|
||||||
|
ID string `bson:"id"` // 身分證字號,通依編號
|
||||||
|
National string `bson:"national"` // 國家
|
||||||
|
City string `bson:"city" ` // 縣市
|
||||||
|
Area string `bson:"area"` // 地區
|
||||||
|
Address string `bson:"address"` // 收件者地址
|
||||||
|
Memo string `bson:"memo"` // 備註
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderItem struct {
|
||||||
|
ItemID string
|
||||||
|
Count int64
|
||||||
|
Additional uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Order) CollectionName() string {
|
||||||
|
return "order"
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
import "go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
|
|
||||||
|
type RememberMe struct {
|
||||||
|
ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
|
||||||
|
UID string `bson:"uid"`
|
||||||
|
BookingInfo *BookingInfo `bson:"booking_info,omitempty"` // 寄送資訊
|
||||||
|
InvoiceInfo *InvoiceInfo `bson:"invoice_info,omitempty"` // 寄送資訊
|
||||||
|
UpdateTime int64 `bson:"update_time"`
|
||||||
|
CreateTime int64 `bson:"create_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *RememberMe) CollectionName() string {
|
||||||
|
return "remember_me"
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import "code.30cm.net/digimon/library-go/errs"
|
||||||
|
|
||||||
|
// Error Code 統一這邊改
|
||||||
|
const (
|
||||||
|
_ = iota
|
||||||
|
CreateOrderErrorCode errs.ErrorCode = iota
|
||||||
|
CancelOrderErrorCode
|
||||||
|
DeleteOrderErrorCode
|
||||||
|
DataNotFoundErrorCode
|
||||||
|
ListOrderErrorCode
|
||||||
|
ModifyOrderErrorCode
|
||||||
|
TimeoutOrderErrorCode
|
||||||
|
ModifyBookingInfoErrorCode
|
||||||
|
GetReadmeErrorCode
|
||||||
|
)
|
|
@ -0,0 +1,20 @@
|
||||||
|
package order
|
||||||
|
|
||||||
|
// DirectType 表示訂單方向
|
||||||
|
type DirectType int64
|
||||||
|
|
||||||
|
// ToInt 將訂單類型轉為 int
|
||||||
|
func (t DirectType) ToInt() int {
|
||||||
|
return int(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToInt64 將訂單類型轉為 int64
|
||||||
|
func (t DirectType) ToInt64() int64 {
|
||||||
|
return int64(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 訂單類型常量
|
||||||
|
const (
|
||||||
|
Buy DirectType = iota + 1 // 測試訂單
|
||||||
|
Sell
|
||||||
|
)
|
|
@ -0,0 +1,84 @@
|
||||||
|
package order
|
||||||
|
|
||||||
|
// Status 表示訂單狀態
|
||||||
|
type Status int64
|
||||||
|
|
||||||
|
// ToInt64 將訂單狀態轉為 int64
|
||||||
|
func (s Status) ToInt64() int64 {
|
||||||
|
return int64(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
var statusMap = map[Status]string{
|
||||||
|
Created: CreatedString,
|
||||||
|
Failed: FailedString,
|
||||||
|
UnderReview: UnderReviewString,
|
||||||
|
Processing: ProcessingString,
|
||||||
|
Paid: PaidString,
|
||||||
|
AwaitingTransfer: AwaitingTransferString,
|
||||||
|
InDispute: InDisputeString,
|
||||||
|
Completed: CompletedString,
|
||||||
|
FailedTrade: FailedTradeString,
|
||||||
|
Cancelled: CancelledString,
|
||||||
|
Abnormal: AbnormalString,
|
||||||
|
TimedOut: TimedOutString,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString 將訂單類型轉為 String
|
||||||
|
func (s Status) ToString() string {
|
||||||
|
r := statusMap[s]
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
// 訂單狀態常量
|
||||||
|
const (
|
||||||
|
Created Status = iota // 訂單已建立
|
||||||
|
Failed // 建單失敗
|
||||||
|
UnderReview // 審核中
|
||||||
|
Processing // 付款中
|
||||||
|
Paid // 已付款
|
||||||
|
AwaitingTransfer // 待轉帳
|
||||||
|
InDispute // 申訴中
|
||||||
|
Completed // 交易完成
|
||||||
|
FailedTrade // 交易失敗
|
||||||
|
Cancelled // 交易取消
|
||||||
|
Abnormal // 交易異常
|
||||||
|
TimedOut // 交易超時
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
CreatedString = "create" // 訂單已建立
|
||||||
|
FailedString = "failed" // 建單失敗
|
||||||
|
UnderReviewString = "under_review" // 審核中
|
||||||
|
ProcessingString = "processing" // 付款中
|
||||||
|
PaidString = "paid" // 已付款
|
||||||
|
AwaitingTransferString = "awaiting_transfer" // 待轉帳
|
||||||
|
InDisputeString = "in_dispute" // 申訴中
|
||||||
|
CompletedString = "completed" // 交易完成
|
||||||
|
FailedTradeString = "failed_trade" // 交易失敗
|
||||||
|
CancelledString = "cancelled" // 交易取消
|
||||||
|
AbnormalString = "abnormal" // 交易異常
|
||||||
|
TimedOutString = "timed_out" // 交易超時
|
||||||
|
)
|
||||||
|
|
||||||
|
var statusStringMap = map[string]Status{
|
||||||
|
CreatedString: Created,
|
||||||
|
FailedString: Failed,
|
||||||
|
UnderReviewString: UnderReview,
|
||||||
|
ProcessingString: Processing,
|
||||||
|
PaidString: Paid,
|
||||||
|
AwaitingTransferString: AwaitingTransfer,
|
||||||
|
InDisputeString: InDispute,
|
||||||
|
CompletedString: Completed,
|
||||||
|
FailedTradeString: FailedTrade,
|
||||||
|
CancelledString: Cancelled,
|
||||||
|
AbnormalString: Abnormal,
|
||||||
|
TimedOutString: TimedOut,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConvertStringToStatus 將訂單類型轉為 Status
|
||||||
|
func ConvertStringToStatus(t string) Status {
|
||||||
|
s := statusStringMap[t]
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package order
|
||||||
|
|
||||||
|
// Type 表示訂單類型
|
||||||
|
type Type int64
|
||||||
|
|
||||||
|
const (
|
||||||
|
UnDefine Type = iota
|
||||||
|
ProductType // 商品訂單
|
||||||
|
)
|
||||||
|
|
||||||
|
// typeToStr 是 Type 對應的文字敘述
|
||||||
|
var typeToStr = map[Type]string{
|
||||||
|
UnDefine: "un_define",
|
||||||
|
ProductType: "product",
|
||||||
|
}
|
||||||
|
|
||||||
|
// strToType 是文字轉回 Type 的對應
|
||||||
|
var strToType = map[string]Type{
|
||||||
|
"un_define": UnDefine,
|
||||||
|
"product": ProductType,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToInt 將 Type 轉為 int
|
||||||
|
func (t Type) ToInt() int {
|
||||||
|
return int(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToString 將 Type 轉為 string
|
||||||
|
func (t Type) ToString() string {
|
||||||
|
if s, ok := typeToStr[t]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseType 從字串解析 Type,預設回傳 UnDefine
|
||||||
|
func ParseType(s string) Type {
|
||||||
|
if t, ok := strToType[s]; ok {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
return UnDefine
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package domain
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type RedisKey string
|
||||||
|
|
||||||
|
const (
|
||||||
|
OrderRedisKey RedisKey = "id"
|
||||||
|
RememberME RedisKey = "remember_me"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (key RedisKey) ToString() string {
|
||||||
|
return "order:" + string(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (key RedisKey) With(s ...string) RedisKey {
|
||||||
|
parts := append([]string{string(key)}, s...)
|
||||||
|
|
||||||
|
return RedisKey(strings.Join(parts, ":"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetOrderRedisKey(id string) string {
|
||||||
|
return OrderRedisKey.With(id).ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetRememberMeRedisKey(uid string) string {
|
||||||
|
return RememberME.With(uid).ToString()
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/pkg/domain/entity"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderRepository interface {
|
||||||
|
Insert(ctx context.Context, data *entity.Order) error
|
||||||
|
FindOne(ctx context.Context, id string) (*entity.Order, error)
|
||||||
|
Update(ctx context.Context, data *entity.Order) (*mongo.UpdateResult, error)
|
||||||
|
Delete(ctx context.Context, id string) (int64, error)
|
||||||
|
UpdateStatus(ctx context.Context, data UpdateStatusReq) (*mongo.UpdateResult, error)
|
||||||
|
UpdateTimeoutOrder(ctx context.Context, req UpdateTimeoutReq) ([]string, error)
|
||||||
|
DeleteByBusinessID(ctx context.Context, id string) (*mongo.UpdateResult, error)
|
||||||
|
FindOneBusinessID(ctx context.Context, id string) (*entity.Order, error)
|
||||||
|
ListOrder(ctx context.Context, req GetOrderListReq) ([]entity.Order, int64, error)
|
||||||
|
ModifyBookingInfoByBusinessID(ctx context.Context, orderID string, param *BookingInfo) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
|
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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
BookingInfo struct {
|
||||||
|
SenderName string // 寄件者姓名
|
||||||
|
SenderPhone string // 寄件者手機
|
||||||
|
SenderEmail string // 寄件者信箱
|
||||||
|
SenderNational string // 寄件者國家
|
||||||
|
SenderAddress string // 寄件者地址
|
||||||
|
SenderCode string // 寄件者郵遞區號
|
||||||
|
ReceiverName string // 收件者姓名
|
||||||
|
ReceiverPhone string // 收件者手機
|
||||||
|
ReceiverEmail string // 收件者信箱
|
||||||
|
ReceiverAddress string // 收件者地址
|
||||||
|
ReceiverNational string // 收件者國家
|
||||||
|
ReceiverCode string // 收件者郵遞區號
|
||||||
|
Memo string // 備註
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderItem struct {
|
||||||
|
ItemID string
|
||||||
|
Count int64
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package repository
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/pkg/domain/entity"
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RememberMeRepository interface {
|
||||||
|
Insert(ctx context.Context, data *entity.RememberMe) error
|
||||||
|
FindOne(ctx context.Context, uid string) (*entity.RememberMe, error)
|
||||||
|
Delete(ctx context.Context, uid string) error
|
||||||
|
}
|
|
@ -0,0 +1,220 @@
|
||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/pkg/domain/entity"
|
||||||
|
"code.30cm.net/digimon/app-cloudep-order-service/pkg/domain/order"
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/shopspring/decimal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrderUseCase interface {
|
||||||
|
// CreateOrder 建立訂單,不另外做 struct 直接用 model.Order
|
||||||
|
// 考量底層已經寫完,如有額外需求需要在這邊用轉的
|
||||||
|
CreateOrder(ctx context.Context, param CreateOrderReq) error
|
||||||
|
// CancelOrder 取消訂單
|
||||||
|
CancelOrder(ctx context.Context, param CancelOrderQuery) error
|
||||||
|
// DeleteOrder 刪除訂單(軟刪除)
|
||||||
|
DeleteOrder(ctx context.Context, param DeleteOrderQuery) error
|
||||||
|
// GetOrder 取得訂單資料
|
||||||
|
GetOrder(ctx context.Context, param GetOrderQuery) (*GetOrderResp, error)
|
||||||
|
// ListOrder 取得資料列表
|
||||||
|
ListOrder(ctx context.Context, param GetOrderListReq) (*ListOrderResp, error)
|
||||||
|
// ModifyOrderStatus 更新資料
|
||||||
|
ModifyOrderStatus(ctx context.Context, param *ModifyOrderQuery) error
|
||||||
|
// OrderStatusTimeout 訂單超時任務/cron/order-status/timeout
|
||||||
|
OrderStatusTimeout(ctx context.Context) ([]string, error)
|
||||||
|
// ModifyBookingInfo 編輯訂單送達的資訊
|
||||||
|
ModifyBookingInfo(ctx context.Context, orderID string, param *BookingInfo) error
|
||||||
|
// GenerateProductBusinessID 產生 product business id
|
||||||
|
GenerateProductBusinessID() string
|
||||||
|
// UpdateRememberMe 記住我的常用資訊
|
||||||
|
UpdateRememberMe(ctx context.Context, data *entity.RememberMe) error
|
||||||
|
// GetRememberMe 取得我的常用資訊
|
||||||
|
GetRememberMe(ctx context.Context, uid string) (RememberMe, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CancelOrderQuery 1.建單失敗 9.交易取消 10.交易異常
|
||||||
|
type CancelOrderQuery struct {
|
||||||
|
BusinessID string
|
||||||
|
Status order.Status
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteOrderQuery 刪除訂單(軟刪除)
|
||||||
|
type DeleteOrderQuery struct {
|
||||||
|
BusinessID string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOrderQuery 取得訂單
|
||||||
|
type GetOrderQuery struct {
|
||||||
|
BusinessID string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetOrderResp struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
BusinessID string // 訂單業務流水號
|
||||||
|
OrderType order.Type `json:"order_type"` // 訂單類型
|
||||||
|
OrderStatus order.Status `json:"order_status"` // 訂單狀態
|
||||||
|
Brand string `json:"brand"` // 下單平台
|
||||||
|
OrderUID string `json:"order_uid"` // 下單用戶 UID
|
||||||
|
ReferenceID string `json:"reference_id"` // 訂單來源
|
||||||
|
Count string `json:"count"` // 訂單數量 (decimal to string)
|
||||||
|
OrderFee string `json:"order_fee"` // 訂單手續費 (decimal to string)
|
||||||
|
Amount string `json:"amount"` // 單價 (decimal to string)
|
||||||
|
ReferenceBrand *string `json:"reference_brand,omitempty"` // 訂單來源平台
|
||||||
|
ReferenceUID *string `json:"reference_uid,omitempty"` // 訂單來源用戶 UID
|
||||||
|
WalletStatus *int64 `json:"wallet_status,omitempty"` // 交易金額狀態
|
||||||
|
ThreePartyStatus *int64 `json:"three_party_status,omitempty"` // 三方請求狀態
|
||||||
|
DirectionType *int64 `json:"direction_type,omitempty"` // 交易方向
|
||||||
|
CryptoType *string `json:"crypto_type,omitempty"` // 交易幣種
|
||||||
|
ThirdPartyFee *string `json:"third_party_fee,omitempty"` // 第三方手續費 (decimal to string)
|
||||||
|
CryptoToUsdtRate *string `json:"crypto_to_usdt_rate,omitempty"` // 交易幣種對 USDT 匯率 (decimal to string)
|
||||||
|
FiatToUsdRate *string `json:"fiat_to_usd_rate,omitempty"` // 法幣對 USD 匯率 (decimal to string)
|
||||||
|
FeeCryptoToUsdtRate *string `json:"fee_crypto_to_usdt_rate,omitempty"` // 手續費幣種對 USDT 匯率 (decimal to string)
|
||||||
|
UsdtToCryptoTypeRate *string `json:"usdt_to_crypto_type_rate,omitempty"` // USDT 對交易幣種匯率 (decimal to string)
|
||||||
|
PaymentFiat *string `json:"payment_fiat,omitempty"` // 支付法幣
|
||||||
|
PaymentUnitPrice *string `json:"payment_unit_price,omitempty"` // crypto 單價 (decimal to string)
|
||||||
|
PaymentTemplateID *string `json:"payment_template_id,omitempty"` // 支付方式配置 ID
|
||||||
|
OrderArrivalTime *int64 `json:"order_arrival_time,omitempty"` // 訂單到帳時間
|
||||||
|
OrderPaymentTime *int64 `json:"order_payment_time,omitempty"` // 訂單付款時間
|
||||||
|
UnpaidTimeoutSecond *int64 `json:"unpaid_timeout_second,omitempty"` // 支付期限秒數
|
||||||
|
ChainType *string `json:"chain_type,omitempty"` // 主網類型
|
||||||
|
TxHash *string `json:"tx_hash,omitempty,omitempty"` // 交易哈希
|
||||||
|
FromAddress *string `json:"from_address,omitempty,omitempty"` // 來源地址
|
||||||
|
ToAddress *string `json:"to_address,omitempty,omitempty"` // 目標地址
|
||||||
|
ChainFee *string `json:"chain_fee,omitempty"` // 鏈上交易手續費 (decimal to string)
|
||||||
|
ChainFeeCrypto *string `json:"chain_fee_crypto,omitempty"` // 鏈上手續費使用幣別
|
||||||
|
Memo *string `json:"memo,omitempty"` // 鏈上備註
|
||||||
|
OrderNote *string `json:"order_note,omitempty"` // 訂單交易備註
|
||||||
|
CreateTime int64 `json:"create_time,omitempty"` // 建立時間
|
||||||
|
UpdateTime int64 `json:"update_time,omitempty"` // 更新時間
|
||||||
|
BookingInfo *BookingInfo `json:"booking_info,omitempty"` // 實體訂單資訊
|
||||||
|
OrderItemInfo []OrderItem `json:"order_item_info,omitempty"` // 這張單的品項資訊
|
||||||
|
InvoiceInfo *InvoiceInfo `json:"invoice_info,omitempty"` // 這張單的品項資訊
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetOrderListReq struct {
|
||||||
|
PageIndex int64
|
||||||
|
PageSize int64
|
||||||
|
|
||||||
|
ReferenceID string
|
||||||
|
ReferenceUID string
|
||||||
|
BusinessID string
|
||||||
|
UID string
|
||||||
|
OrderType order.Type
|
||||||
|
DirectionType []int64
|
||||||
|
OrderStatus []int64
|
||||||
|
|
||||||
|
StartCreateTime int64
|
||||||
|
EndCreateTime int64
|
||||||
|
StartUpdateTime int64
|
||||||
|
EndUpdateTime int64
|
||||||
|
StartOrderArrivalTime int64
|
||||||
|
EndOrderArrivalTime int64
|
||||||
|
StartOrderPaymentTime int64
|
||||||
|
EndOrderPaymentTime int64
|
||||||
|
|
||||||
|
CryptoType string
|
||||||
|
TxHash string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Pager struct {
|
||||||
|
Index int64
|
||||||
|
Size int64
|
||||||
|
Total int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListOrderResp struct {
|
||||||
|
Data []*GetOrderResp `json:"data"` // 訂單列表
|
||||||
|
Page *Pager `json:"page"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateOrderReq struct {
|
||||||
|
BusinessID string
|
||||||
|
OrderType order.Type // 訂單類型
|
||||||
|
OrderStatus order.Status // 訂單狀態
|
||||||
|
Brand string // 下單平台
|
||||||
|
OrderUID string // 下單用戶 UID
|
||||||
|
ReferenceID string // 訂單來源
|
||||||
|
Count decimal.Decimal // 訂單數量
|
||||||
|
OrderFee decimal.Decimal // 訂單手續費
|
||||||
|
Amount decimal.Decimal // 單價
|
||||||
|
WalletStatus int64 // 交易金額狀態
|
||||||
|
DirectionType int64 // 交易方向
|
||||||
|
// 以上為必要欄位,下面是區塊鏈時才需要
|
||||||
|
ReferenceBrand *string // 訂單來源平台
|
||||||
|
ReferenceUID *string // 訂單來源用戶 UID
|
||||||
|
ThreePartyStatus *int64 // 三方請求狀態
|
||||||
|
CryptoType *string // 交易幣種
|
||||||
|
ThirdPartyFee *decimal.Decimal // 第三方手續費
|
||||||
|
CryptoToUSDTRate *decimal.Decimal // 加密貨幣對 USDT 匯率
|
||||||
|
FiatToUSDRate *decimal.Decimal // 法幣對 USD 匯率
|
||||||
|
FeeCryptoToUSDTRate *decimal.Decimal // 手續費加密貨幣對 USDT 匯率
|
||||||
|
USDTToCryptoTypeRate *decimal.Decimal // USDT 對加密貨幣匯率
|
||||||
|
PaymentFiat *string // 支付法幣
|
||||||
|
PaymentUnitPrice *decimal.Decimal // 加密貨幣單價
|
||||||
|
PaymentTemplateID *string // 支付方式配置 ID
|
||||||
|
OrderArrivalTime *int64 // 訂單到帳時間
|
||||||
|
OrderPaymentTime *int64 // 訂單付款時間
|
||||||
|
UnpaidTimeoutSecond *int64 // 支付期限秒數
|
||||||
|
ChainType *string // 主網類型
|
||||||
|
TxHash *string // 交易哈希
|
||||||
|
FromAddress *string // 來源地址
|
||||||
|
ToAddress *string // 目標地址
|
||||||
|
ChainFee *decimal.Decimal // 鏈上交易手續費
|
||||||
|
ChainFeeCrypto *string // 鏈上手續費使用幣別
|
||||||
|
Memo *string // 鏈上備註
|
||||||
|
OrderNote *string // 訂單交易備註
|
||||||
|
BookingInfo *BookingInfo // 實體訂單資訊
|
||||||
|
OrderItemInfo []OrderItem // 這張單的品項資訊
|
||||||
|
InvoiceInfo *InvoiceInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
type BookingInfo struct {
|
||||||
|
SenderName string // 寄件者姓名
|
||||||
|
SenderPhone string // 寄件者手機
|
||||||
|
SenderEmail string // 寄件者信箱
|
||||||
|
SenderNational string // 寄件者國家
|
||||||
|
SenderAddress string // 寄件者地址
|
||||||
|
SenderCode string // 寄件者郵遞區號
|
||||||
|
ReceiverName string // 收件者姓名
|
||||||
|
ReceiverPhone string // 收件者手機
|
||||||
|
ReceiverEmail string // 收件者信箱
|
||||||
|
ReceiverNational string // 收件者國家
|
||||||
|
ReceiverAddress string // 收件者地址
|
||||||
|
ReceiverCode string // 收件者郵遞區號
|
||||||
|
Memo string // 備註
|
||||||
|
}
|
||||||
|
|
||||||
|
type InvoiceInfo struct {
|
||||||
|
Type string `json:"type" validate:"required"` // 發票類型
|
||||||
|
Code string `json:"code" validate:"required"` // 載具條碼
|
||||||
|
Name string `json:"name" validate:"required"` // 捐款人姓名 / 公司抬頭
|
||||||
|
ID string `json:"id" validate:"required"` // 身分證字號,通依編號
|
||||||
|
City string `json:"city" validate:"required"` // 縣市
|
||||||
|
Area string `json:"area" validate:"required"` // 地區
|
||||||
|
National string `json:"national" validate:"required"` // 國家
|
||||||
|
Address string `json:"address" validate:"required"` // 收件者地址
|
||||||
|
Memo string `json:"memo,optional"` // 備註
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderItem struct {
|
||||||
|
ItemID string
|
||||||
|
Count int64
|
||||||
|
Additional uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type RememberMe struct {
|
||||||
|
BookingInfo BookingInfo `json:"booking_info"` // 寄送資訊
|
||||||
|
InvoiceInfo InvoiceInfo `json:"invoice_info"` // 寄送資訊
|
||||||
|
}
|
Loading…
Reference in New Issue