316 lines
9.9 KiB
Go
316 lines
9.9 KiB
Go
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"
|
||
"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/utils"
|
||
"code.30cm.net/digimon/library-go/errs"
|
||
"context"
|
||
"github.com/shopspring/decimal"
|
||
"github.com/zeromicro/go-zero/core/logx"
|
||
)
|
||
|
||
type ProductItemUseCaseParam struct {
|
||
ProductItems repository.ProductItemRepository
|
||
TagRepo repository.TagRepo
|
||
}
|
||
|
||
type ProductItemUseCase struct {
|
||
ProductItemUseCaseParam
|
||
}
|
||
|
||
func MustProductItemUseCase(param ProductItemUseCaseParam) usecase.ProductItemUseCase {
|
||
return &ProductItemUseCase{
|
||
param,
|
||
}
|
||
}
|
||
|
||
// --- 輔助函式 ---
|
||
|
||
// 將 usecase.ProductItems 轉換為 entity.ProductItems(用於 Create)
|
||
func toEntity(u *usecase.ProductItems) (entity.ProductItems, error) {
|
||
// 將價格字串轉換為 decimal.Decimal
|
||
priceDec, err := decimal.NewFromString(u.Price)
|
||
if err != nil {
|
||
return entity.ProductItems{}, err
|
||
}
|
||
return entity.ProductItems{
|
||
// ID 在新增時通常由資料庫自動產生
|
||
ReferenceID: u.ReferenceID,
|
||
Name: u.Name,
|
||
Description: u.Description,
|
||
ShortDescription: u.ShortDescription,
|
||
IsUnLimit: u.IsUnLimit,
|
||
IsFree: u.IsFree,
|
||
Stock: u.Stock,
|
||
Price: priceDec,
|
||
SKU: u.SKU,
|
||
TimeSeries: u.TimeSeries,
|
||
Media: convertMediaToEntity(u.Media),
|
||
Status: u.Status,
|
||
Freight: convertCustomFieldsToEntity(u.Freight),
|
||
CustomFields: convertCustomFieldsToEntity(u.CustomFields),
|
||
}, nil
|
||
}
|
||
|
||
// 將 entity.ProductItems 轉換為 usecase.ProductItems(用於 Get 與 List)
|
||
func fromEntity(e *entity.ProductItems) *usecase.ProductItems {
|
||
return &usecase.ProductItems{
|
||
ID: e.ID.Hex(),
|
||
ReferenceID: e.ReferenceID,
|
||
Name: e.Name,
|
||
Description: e.Description,
|
||
ShortDescription: e.ShortDescription,
|
||
IsUnLimit: e.IsUnLimit,
|
||
IsFree: e.IsFree,
|
||
Stock: e.Stock,
|
||
Price: e.Price.String(),
|
||
SKU: e.SKU,
|
||
TimeSeries: e.TimeSeries,
|
||
Media: convertEntityMedia(e.Media),
|
||
Status: e.Status,
|
||
Freight: convertEntityCustomFields(e.Freight),
|
||
CustomFields: convertEntityCustomFields(e.CustomFields),
|
||
SalesCount: e.SalesCount,
|
||
UpdatedAt: utils.UnixToRfc3339(e.UpdatedAt),
|
||
CreatedAt: utils.UnixToRfc3339(e.CreatedAt),
|
||
}
|
||
}
|
||
|
||
// Media 轉換:usecase.Media -> entity.Media
|
||
func convertMediaToEntity(meds []usecase.Media) []entity.Media {
|
||
res := make([]entity.Media, len(meds))
|
||
for i, m := range meds {
|
||
res[i] = entity.Media{
|
||
Sort: m.Sort,
|
||
Type: m.Type,
|
||
URL: m.URL,
|
||
}
|
||
}
|
||
return res
|
||
}
|
||
|
||
// Media 轉換:entity.Media -> usecase.Media
|
||
func convertEntityMedia(meds []entity.Media) []usecase.Media {
|
||
res := make([]usecase.Media, len(meds))
|
||
for i, m := range meds {
|
||
res[i] = usecase.Media{
|
||
Sort: m.Sort,
|
||
Type: m.Type,
|
||
URL: m.URL,
|
||
}
|
||
}
|
||
return res
|
||
}
|
||
|
||
// CustomFields 轉換:usecase.CustomFields -> entity.CustomFields
|
||
func convertCustomFieldsToEntity(cfs []usecase.CustomFields) []entity.CustomFields {
|
||
res := make([]entity.CustomFields, len(cfs))
|
||
for i, cf := range cfs {
|
||
res[i] = entity.CustomFields{
|
||
Key: cf.Key,
|
||
Value: cf.Value,
|
||
}
|
||
}
|
||
return res
|
||
}
|
||
|
||
// CustomFields 轉換:entity.CustomFields -> usecase.CustomFields
|
||
func convertEntityCustomFields(cfs []entity.CustomFields) []usecase.CustomFields {
|
||
res := make([]usecase.CustomFields, len(cfs))
|
||
for i, cf := range cfs {
|
||
res[i] = usecase.CustomFields{
|
||
Key: cf.Key,
|
||
Value: cf.Value,
|
||
}
|
||
}
|
||
return res
|
||
}
|
||
|
||
// --- 實作 ProductItemUseCase interface ---
|
||
|
||
func (use *ProductItemUseCase) Create(ctx context.Context, productItem *usecase.ProductItems) error {
|
||
// 轉換成 entity 層型別
|
||
ent, err := toEntity(productItem)
|
||
if err != nil {
|
||
return errs.InvalidFormatL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "product_id", Value: productItem},
|
||
{Key: "func", Value: "ProductItemUseCase.Create"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to change use case into entity")
|
||
}
|
||
|
||
err = use.ProductItemUseCaseParam.ProductItems.Insert(ctx, []entity.ProductItems{ent})
|
||
if err != nil {
|
||
return errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "req", Value: productItem},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.Insert"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to insert product item")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (use *ProductItemUseCase) Get(ctx context.Context, id string) (*usecase.ProductItems, error) {
|
||
ent, err := use.ProductItemUseCaseParam.ProductItems.FindByID(ctx, id)
|
||
if err != nil {
|
||
return nil, errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "id", Value: id},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.FindByID"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to create product items")
|
||
}
|
||
return fromEntity(ent), nil
|
||
}
|
||
|
||
func (use *ProductItemUseCase) Update(ctx context.Context, id string, data *usecase.UpdateProductItems) error {
|
||
// 構建更新參數(僅更新部分欄位)
|
||
update := &repository.ProductUpdateItem{}
|
||
if data.Name != nil {
|
||
update.Name = data.Name
|
||
}
|
||
if data.Description != nil {
|
||
update.Description = data.Description
|
||
}
|
||
if data.ShortDescription != nil {
|
||
update.ShortDescription = data.ShortDescription
|
||
}
|
||
if data.IsUnLimit != nil {
|
||
update.IsUnLimit = data.IsUnLimit
|
||
}
|
||
if data.IsFree != nil {
|
||
update.IsFree = data.IsFree
|
||
}
|
||
if data.Stock != nil {
|
||
// data.Stock 為 *uint64,需先解引用再轉換為 int64
|
||
s := int64(*data.Stock)
|
||
update.Stock = &s
|
||
}
|
||
if data.Price != nil {
|
||
// data.Price 為 *string,需先解引用並轉換為 decimal.Decimal
|
||
dec, err := decimal.NewFromString(*data.Price)
|
||
if err != nil {
|
||
return errs.InvalidFormat("failed to convert price to decimal")
|
||
}
|
||
update.Price = &dec
|
||
}
|
||
if data.SKU != nil {
|
||
update.SKU = data.SKU
|
||
}
|
||
// 假設有 TimeSeries 欄位也需要更新(若有定義的話)
|
||
if data.TimeSeries != nil {
|
||
update.TimeSeries = data.TimeSeries
|
||
}
|
||
if len(data.Media) > 0 {
|
||
update.Media = convertMediaToEntity(data.Media)
|
||
}
|
||
if len(data.CustomFields) > 0 {
|
||
update.CustomFields = convertCustomFieldsToEntity(data.CustomFields)
|
||
}
|
||
if len(data.Freight) > 0 {
|
||
update.Freight = convertCustomFieldsToEntity(data.Freight)
|
||
}
|
||
if err := use.ProductItemUseCaseParam.ProductItems.Update(ctx, id, update); err != nil {
|
||
return errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "id", Value: id},
|
||
{Key: "req", Value: data},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.Update"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to update product item")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (use *ProductItemUseCase) UpdateStatus(ctx context.Context, id string, status product.ItemStatus) error {
|
||
err := use.ProductItemUseCaseParam.ProductItems.UpdateStatus(ctx, id, status)
|
||
if err != nil {
|
||
return errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "id", Value: id},
|
||
{Key: "status", Value: status},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.UpdateStatus"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to update product item status")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (use *ProductItemUseCase) IncSalesCount(ctx context.Context, id string, saleCount uint64) error {
|
||
// repository 方法使用 int64,故需轉型
|
||
if err := use.ProductItemUseCaseParam.ProductItems.IncSalesCount(ctx, id, int64(saleCount)); err != nil {
|
||
return errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "id", Value: id},
|
||
{Key: "saleCount", Value: saleCount},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.IncSalesCount"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to insert product item")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (use *ProductItemUseCase) DecSalesCount(ctx context.Context, id string, saleCount uint64) error {
|
||
// repository 方法使用 int64,故需轉型
|
||
if err := use.ProductItemUseCaseParam.ProductItems.DecSalesCount(ctx, id, int64(saleCount)); err != nil {
|
||
return errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "id", Value: id},
|
||
{Key: "saleCount", Value: saleCount},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.DecSalesCount"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to Dec product item")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (use *ProductItemUseCase) Delete(ctx context.Context, id string) error {
|
||
// repository.Delete 接收 slice,因此將 id 放入 slice 中
|
||
if err := use.ProductItemUseCaseParam.ProductItems.Delete(ctx, []string{id}); err != nil {
|
||
return errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "id", Value: id},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.Delete"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to delete product item")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (use *ProductItemUseCase) List(ctx context.Context, filter usecase.QueryProductItemParam) ([]*usecase.ProductItems, int64, error) {
|
||
repoQuery := repository.ProductItemQueryParams{
|
||
PageSize: filter.PageSize,
|
||
PageIndex: filter.PageIndex,
|
||
ReferenceID: filter.ReferenceID,
|
||
IsFree: filter.IsFree,
|
||
Status: filter.Status,
|
||
// 注意:若需要依 IsUnLimit 過濾,需擴充 repository.ProductItemQueryParams 結構
|
||
}
|
||
entities, total, err := use.ProductItemUseCaseParam.ProductItems.ListProductItem(ctx, repoQuery)
|
||
if err != nil {
|
||
return nil, 0, errs.DBErrorL(logx.WithContext(ctx),
|
||
[]logx.LogField{
|
||
{Key: "filter", Value: filter},
|
||
{Key: "func", Value: "ProductItemUseCaseParam.ProductItems.ListProductItem"},
|
||
{Key: "err", Value: err.Error()},
|
||
}, "failed to list product item")
|
||
}
|
||
var result []*usecase.ProductItems
|
||
for i := range entities {
|
||
// 逐筆轉換 entity -> usecase 型別
|
||
result = append(result, fromEntity(&entities[i]))
|
||
}
|
||
return result, total, nil
|
||
}
|