feat: add tags
This commit is contained in:
parent
6f790d65b3
commit
cb7e9fb5bb
|
@ -1,6 +1,9 @@
|
|||
package entity
|
||||
|
||||
import "go.mongodb.org/mongo-driver/bson/primitive"
|
||||
import (
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/kyc"
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type KYC struct {
|
||||
ID primitive.ObjectID `bson:"_id,omitempty"`
|
||||
|
@ -20,7 +23,7 @@ type KYC struct {
|
|||
BranchCode string `bson:"branch_code"` // 分行代碼
|
||||
BranchName string `bson:"branch_name"` // 分行名稱(顯示用)
|
||||
BankAccount string `bson:"bank_account"` // 銀行帳號
|
||||
Status string `bson:"status"` // 審核狀態:PENDING, APPROVED, REJECTED
|
||||
Status kyc.Status `bson:"status"` // 審核狀態:PENDING, APPROVED, REJECTED
|
||||
RejectReason string `bson:"reject_reason"` // 若被駁回,原因描述
|
||||
UpdatedAt int64 `bson:"updated_at,omitempty"`
|
||||
CreatedAt int64 `bson:"created_at,omitempty"`
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package kyc
|
||||
|
||||
type Status string
|
||||
|
||||
const (
|
||||
StatusPending Status = "PENDING"
|
||||
StatusAPPROVED Status = "APPROVED"
|
||||
StatusREJECTED Status = "REJECTED"
|
||||
)
|
|
@ -1,4 +1,48 @@
|
|||
package usecase
|
||||
|
||||
type KYCUseCase struct {
|
||||
import (
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
|
||||
"context"
|
||||
)
|
||||
|
||||
type KYCUseCase interface {
|
||||
// Create 建立 KYC 資料
|
||||
Create(ctx context.Context, kyc *entity.KYC) error
|
||||
// FindLatestByUID 根據使用者 UID 取得最新 KYC 紀錄
|
||||
FindLatestByUID(ctx context.Context, uid string) (*entity.KYC, error)
|
||||
// FindByID 根據 KYC ID 查詢
|
||||
FindByID(ctx context.Context, id string) (*entity.KYC, error)
|
||||
// List 分頁查詢(後台審核列表用)
|
||||
List(ctx context.Context, params KYCQueryParams) ([]*entity.KYC, int64, error)
|
||||
// UpdateStatus 更新 KYC 狀態與審核原因(審核用)
|
||||
UpdateStatus(ctx context.Context, id string, status string, reason string) error
|
||||
// UpdateKYCInfo 更新使用者的 KYC(限於尚未審核的)
|
||||
UpdateKYCInfo(ctx context.Context, id string, update *KYCUpdateParams) error
|
||||
}
|
||||
|
||||
type KYCQueryParams struct {
|
||||
UID *string
|
||||
Country *string
|
||||
Status *string // PENDING, APPROVED, REJECTED
|
||||
PageSize int64
|
||||
PageIndex int64
|
||||
SortByDate bool // 是否依申請時間倒序
|
||||
}
|
||||
|
||||
type KYCUpdateParams struct {
|
||||
Name *string
|
||||
Identification *string
|
||||
IdentificationType *string
|
||||
Address *string
|
||||
PostalCode *string
|
||||
DateOfBirth *string
|
||||
Gender *string
|
||||
IDFrontImage *string
|
||||
IDBackImage *string
|
||||
BankStatementImg *string
|
||||
BankCode *string
|
||||
BankName *string
|
||||
BranchCode *string
|
||||
BranchName *string
|
||||
BankAccount *string
|
||||
}
|
||||
|
|
|
@ -1 +1,40 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/product"
|
||||
"context"
|
||||
)
|
||||
|
||||
type ProductBaseTags interface {
|
||||
// Create 新增一筆 Tag 資料
|
||||
Create(ctx context.Context, tag *entity.Tags) error
|
||||
// GetByID 根據 tag 的內部 ID 取得資料
|
||||
GetByID(ctx context.Context, id string) (*entity.Tags, error)
|
||||
// Update 更新現有的 Tag 資料
|
||||
Update(ctx context.Context, id string, tag TagModifyParams) error
|
||||
// Delete 刪除指定 ID 的 Tag 資料
|
||||
Delete(ctx context.Context, id string) error
|
||||
// List 根據查詢條件取得 Tag 資料列表
|
||||
// 回傳值分別為資料列表與符合條件的總筆數
|
||||
List(ctx context.Context, params TagQueryParams) ([]*entity.Tags, int64, error)
|
||||
// GetByIDs 根據查詢條件取得 Tag 資料列表
|
||||
GetByIDs(ctx context.Context, ids []string) ([]*entity.Tags, error)
|
||||
}
|
||||
|
||||
// TagQueryParams 為查詢 Tags 時的參數結構
|
||||
type TagQueryParams struct {
|
||||
Types *product.ItemType // 過濾 Tag 類型
|
||||
Name *string // 過濾名稱(部分比對)
|
||||
ShowType *product.ShowType // 過濾顯示筐
|
||||
// 可根據需求增加其他查詢條件,如分頁、排序等
|
||||
PageSize int64
|
||||
PageIndex int64
|
||||
}
|
||||
|
||||
type TagModifyParams struct {
|
||||
Types *product.ItemType // 過濾 Tag 類型
|
||||
Name *string // 過濾名稱(部分比對)
|
||||
ShowType *product.ShowType // 過濾顯示筐
|
||||
Cover *string `bson:"cover,omitempty"` // 封面圖片
|
||||
}
|
||||
|
|
|
@ -5,10 +5,12 @@ import (
|
|||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
|
||||
mgo "code.30cm.net/digimon/library-go/mongo"
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/zeromicro/go-zero/core/stores/cache"
|
||||
"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"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"time"
|
||||
)
|
||||
|
@ -62,6 +64,9 @@ func (repo *KYCRepository) FindLatestByUID(ctx context.Context, uid string) (*en
|
|||
|
||||
err := repo.DB.GetClient().FindOne(ctx, &result, filter, opts)
|
||||
if err != nil {
|
||||
if errors.Is(err, mongo.ErrNoDocuments) {
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
|
|
|
@ -1 +1,168 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/kyc"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase"
|
||||
repo "code.30cm.net/digimon/app-cloudep-product-service/pkg/repository"
|
||||
"code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type KYCUseCaseParam struct {
|
||||
KYCRepo repository.KYCRepository
|
||||
}
|
||||
|
||||
type KYCUseCase struct {
|
||||
KYCUseCaseParam
|
||||
}
|
||||
|
||||
func MustKYCUseCase(param KYCUseCaseParam) usecase.KYCUseCase {
|
||||
return &KYCUseCase{
|
||||
param,
|
||||
}
|
||||
}
|
||||
|
||||
func (use *KYCUseCase) Create(ctx context.Context, data *entity.KYC) error {
|
||||
latest, err := use.KYCRepo.FindLatestByUID(ctx, data.UID)
|
||||
|
||||
// 發生真正的錯誤(非找不到)
|
||||
if err != nil && !errors.Is(err, repo.ErrNotFound) {
|
||||
return errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "param", Value: data},
|
||||
{Key: "func", Value: "KYCRepo.FindLatestByUID"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to get latest kyc")
|
||||
}
|
||||
|
||||
// 若查到資料,且不是被駁回的,表示已存在審核中/已通過資料 → 禁止再次建立
|
||||
if err == nil && latest.Status != kyc.StatusREJECTED {
|
||||
return errs.ForbiddenL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "param", Value: data},
|
||||
{Key: "func", Value: "KYCRepo.FindLatestByUID"},
|
||||
{Key: "reason", Value: "KYC already in progress or approved"},
|
||||
}, "不能重複送出 KYC 資料")
|
||||
}
|
||||
|
||||
// ✅ 若查不到資料(ErrNotFound),或前一筆是 REJECTED,允許建立
|
||||
data.Status = kyc.StatusPending
|
||||
err = use.KYCRepo.Create(ctx, data)
|
||||
if err != nil {
|
||||
return errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "param", Value: data},
|
||||
{Key: "func", Value: "KYCRepo.Create"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to create kyc review")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (use *KYCUseCase) FindLatestByUID(ctx context.Context, uid string) (*entity.KYC, error) {
|
||||
latest, err := use.KYCRepo.FindLatestByUID(ctx, uid)
|
||||
if err != nil {
|
||||
return nil, errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "uid", Value: uid},
|
||||
{Key: "func", Value: "KYCRepo.FindLatestByUID"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to get latest kyc")
|
||||
}
|
||||
|
||||
return latest, nil
|
||||
}
|
||||
|
||||
func (use *KYCUseCase) FindByID(ctx context.Context, id string) (*entity.KYC, error) {
|
||||
byID, err := use.KYCRepo.FindByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "id", Value: id},
|
||||
{Key: "func", Value: "KYCRepo.FindByID"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to get kyc")
|
||||
}
|
||||
|
||||
return byID, nil
|
||||
}
|
||||
|
||||
func (use *KYCUseCase) List(ctx context.Context, params usecase.KYCQueryParams) ([]*entity.KYC, int64, error) {
|
||||
q := repository.KYCQueryParams{
|
||||
PageIndex: params.PageIndex,
|
||||
PageSize: params.PageSize,
|
||||
SortByDate: true,
|
||||
}
|
||||
if params.UID != nil {
|
||||
q.UID = params.UID
|
||||
}
|
||||
if params.Country != nil {
|
||||
q.Country = params.Country
|
||||
}
|
||||
if params.Status != nil {
|
||||
q.Status = params.Status
|
||||
}
|
||||
|
||||
list, i, err := use.KYCRepo.List(ctx, q)
|
||||
if err != nil {
|
||||
return nil, 0, errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "params", Value: params},
|
||||
{Key: "func", Value: "KYCRepo.List"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to list kyc")
|
||||
}
|
||||
|
||||
return list, i, nil
|
||||
}
|
||||
|
||||
func (use *KYCUseCase) UpdateStatus(ctx context.Context, id string, status string, reason string) error {
|
||||
err := use.KYCRepo.UpdateStatus(ctx, id, status, reason)
|
||||
if err != nil {
|
||||
return errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "params", Value: fmt.Sprintf("id:%s, status:%s, reason: %s", id, status, reason)},
|
||||
{Key: "func", Value: "KYCRepo.UpdateStatus"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to update kyc status")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (use *KYCUseCase) UpdateKYCInfo(ctx context.Context, id string, update *usecase.KYCUpdateParams) error {
|
||||
err := use.KYCRepo.UpdateKYCInfo(ctx, id, &repository.KYCUpdateParams{
|
||||
Name: update.Name,
|
||||
Identification: update.Identification,
|
||||
IdentificationType: update.IdentificationType,
|
||||
Address: update.Address,
|
||||
PostalCode: update.PostalCode,
|
||||
DateOfBirth: update.DateOfBirth,
|
||||
Gender: update.Gender,
|
||||
IDFrontImage: update.IDFrontImage,
|
||||
IDBackImage: update.IDBackImage,
|
||||
BankStatementImg: update.BankStatementImg,
|
||||
BankCode: update.BankCode,
|
||||
BankName: update.BankName,
|
||||
BranchCode: update.BranchCode,
|
||||
BranchName: update.BranchName,
|
||||
BankAccount: update.BankAccount,
|
||||
})
|
||||
if err != nil {
|
||||
return errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "id", Value: id},
|
||||
{Key: "params", Value: update},
|
||||
{Key: "func", Value: "KYCRepo.UpdateKYCInfo"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to update kyc")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
package usecase
|
||||
|
||||
import (
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
|
||||
repo "code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase"
|
||||
"code.30cm.net/digimon/app-cloudep-product-service/pkg/repository"
|
||||
"code.30cm.net/digimon/library-go/errs"
|
||||
"context"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type TagsUseCaseParam struct {
|
||||
TagsRepo repository.TagsRepository
|
||||
}
|
||||
|
||||
type TagsUseCase struct {
|
||||
TagsUseCaseParam
|
||||
}
|
||||
|
||||
func MustTagsUseCase(param TagsUseCaseParam) usecase.ProductBaseTags {
|
||||
return &TagsUseCase{
|
||||
param,
|
||||
}
|
||||
}
|
||||
|
||||
func (use *TagsUseCase) Create(ctx context.Context, data *entity.Tags) error {
|
||||
err := use.TagsRepo.Create(ctx, data)
|
||||
if err != nil {
|
||||
return errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "param", Value: data},
|
||||
{Key: "func", Value: "TagsRepo.Create"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to create tags")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (use *TagsUseCase) GetByID(ctx context.Context, id string) (*entity.Tags, error) {
|
||||
tag, err := use.TagsRepo.GetByID(ctx, id)
|
||||
if err != nil {
|
||||
return nil, errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "id", Value: id},
|
||||
{Key: "func", Value: "TagsRepo.GetByID"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to get tags")
|
||||
}
|
||||
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func (use *TagsUseCase) GetByIDs(ctx context.Context, ids []string) ([]*entity.Tags, error) {
|
||||
tags, err := use.TagsRepo.GetByIDs(ctx, ids)
|
||||
if err != nil {
|
||||
return nil, errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "ids", Value: ids},
|
||||
{Key: "func", Value: "TagsRepo.GetByIDs"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to get tags")
|
||||
}
|
||||
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func (use *TagsUseCase) Delete(ctx context.Context, id string) error {
|
||||
// TODO 是否要刪除已綁定的Tag 還是在查詢的時候做
|
||||
|
||||
err := use.TagsRepo.Delete(ctx, id)
|
||||
if err != nil {
|
||||
return errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "id", Value: id},
|
||||
{Key: "func", Value: "TagsRepo.Delete"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to delete tags")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (use *TagsUseCase) List(ctx context.Context, params usecase.TagQueryParams) ([]*entity.Tags, int64, error) {
|
||||
q := repo.TagQueryParams{
|
||||
PageSize: params.PageSize,
|
||||
PageIndex: params.PageIndex,
|
||||
}
|
||||
if params.Types != nil {
|
||||
q.Types = params.Types
|
||||
}
|
||||
|
||||
if params.Name != nil {
|
||||
q.Name = params.Name
|
||||
}
|
||||
if params.ShowType != nil {
|
||||
q.ShowType = params.ShowType
|
||||
}
|
||||
|
||||
list, total, err := use.TagsRepo.List(ctx, q)
|
||||
if err != nil {
|
||||
return nil, 0, errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "params", Value: params},
|
||||
{Key: "func", Value: "TagsRepo.List"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to list tags")
|
||||
}
|
||||
|
||||
return list, total, nil
|
||||
}
|
||||
|
||||
func (use *TagsUseCase) Update(ctx context.Context, id string, tag usecase.TagModifyParams) error {
|
||||
update := repo.TagModifyParams{}
|
||||
if tag.Name != nil {
|
||||
update.Name = tag.Name
|
||||
}
|
||||
if tag.Types != nil {
|
||||
update.Types = tag.Types
|
||||
}
|
||||
if tag.ShowType != nil {
|
||||
update.ShowType = tag.ShowType
|
||||
}
|
||||
if tag.Cover != nil {
|
||||
update.Cover = tag.Cover
|
||||
}
|
||||
|
||||
err := use.TagsRepo.Update(ctx, id, update)
|
||||
if err != nil {
|
||||
return errs.DBErrorL(logx.WithContext(ctx),
|
||||
[]logx.LogField{
|
||||
{Key: "id", Value: id},
|
||||
{Key: "params", Value: tag},
|
||||
{Key: "func", Value: "TagsRepo.Update"},
|
||||
{Key: "err", Value: err.Error()},
|
||||
}, "failed to update tags")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue