175 lines
5.4 KiB
Go
175 lines
5.4 KiB
Go
package usecase
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"haixun-backend/internal/library/clock"
|
|
app "haixun-backend/internal/library/errors"
|
|
"haixun-backend/internal/library/errors/code"
|
|
"haixun-backend/internal/model/publish_inventory/domain/entity"
|
|
domrepo "haixun-backend/internal/model/publish_inventory/domain/repository"
|
|
domusecase "haixun-backend/internal/model/publish_inventory/domain/usecase"
|
|
threadsaccountdomain "haixun-backend/internal/model/threads_account/domain/usecase"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type inventoryUseCase struct {
|
|
repo domrepo.Repository
|
|
threadsAccount threadsaccountdomain.UseCase
|
|
}
|
|
|
|
func NewUseCase(repo domrepo.Repository, threadsAccount threadsaccountdomain.UseCase) domusecase.UseCase {
|
|
return &inventoryUseCase{repo: repo, threadsAccount: threadsAccount}
|
|
}
|
|
|
|
func (u *inventoryUseCase) Get(ctx context.Context, tenantID, ownerUID, accountID string) (*domusecase.PolicySummary, error) {
|
|
if err := u.require(ctx, tenantID, ownerUID, accountID); err != nil {
|
|
return nil, err
|
|
}
|
|
item, err := u.repo.Get(ctx, tenantID, ownerUID, accountID)
|
|
if err != nil {
|
|
if strings.Contains(err.Error(), "not found") {
|
|
item = defaultPolicy(tenantID, ownerUID, accountID)
|
|
} else {
|
|
return nil, err
|
|
}
|
|
}
|
|
out := toSummary(item)
|
|
return &out, nil
|
|
}
|
|
|
|
func (u *inventoryUseCase) Upsert(ctx context.Context, req domusecase.UpsertRequest) (*domusecase.PolicySummary, error) {
|
|
if err := u.require(ctx, req.TenantID, req.OwnerUID, req.AccountID); err != nil {
|
|
return nil, err
|
|
}
|
|
item := defaultPolicy(req.TenantID, req.OwnerUID, req.AccountID)
|
|
item.Enabled = req.Enabled
|
|
if req.TargetDailyCount > 0 {
|
|
item.TargetDailyCount = req.TargetDailyCount
|
|
}
|
|
if req.LowStockThreshold > 0 {
|
|
item.LowStockThreshold = req.LowStockThreshold
|
|
}
|
|
if req.LookaheadDays > 0 {
|
|
item.LookaheadDays = req.LookaheadDays
|
|
}
|
|
if strings.TrimSpace(req.Timezone) != "" {
|
|
item.Timezone = strings.TrimSpace(req.Timezone)
|
|
}
|
|
item.Slots = slotsToEntity(req.Slots)
|
|
item.SourceRefs = sourceRefsToEntity(req.SourceRefs)
|
|
now := clock.NowUnixNano()
|
|
item.UpdateAt = now
|
|
saved, err := u.repo.Upsert(ctx, item)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := toSummary(saved)
|
|
return &out, nil
|
|
}
|
|
|
|
func (u *inventoryUseCase) ListEnabled(ctx context.Context, limit int) ([]domusecase.PolicySummary, error) {
|
|
items, err := u.repo.ListEnabled(ctx, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := make([]domusecase.PolicySummary, 0, len(items))
|
|
for _, item := range items {
|
|
summary := toSummary(&item)
|
|
out = append(out, summary)
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func (u *inventoryUseCase) require(ctx context.Context, tenantID, ownerUID, accountID string) error {
|
|
if strings.TrimSpace(tenantID) == "" || strings.TrimSpace(ownerUID) == "" {
|
|
return app.For(code.Auth).AuthUnauthorized("missing actor")
|
|
}
|
|
if strings.TrimSpace(accountID) == "" {
|
|
return app.For(code.ThreadsAccount).InputMissingRequired("account_id is required")
|
|
}
|
|
if u.threadsAccount != nil {
|
|
_, err := u.threadsAccount.Get(ctx, tenantID, ownerUID, accountID)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func defaultPolicy(tenantID, ownerUID, accountID string) *entity.Policy {
|
|
now := clock.NowUnixNano()
|
|
return &entity.Policy{
|
|
ID: uuid.NewString(),
|
|
TenantID: strings.TrimSpace(tenantID),
|
|
OwnerUID: strings.TrimSpace(ownerUID),
|
|
AccountID: strings.TrimSpace(accountID),
|
|
Enabled: false,
|
|
TargetDailyCount: 2,
|
|
LowStockThreshold: 3,
|
|
LookaheadDays: 7,
|
|
Timezone: "Asia/Taipei",
|
|
Slots: []entity.Slot{
|
|
{Weekday: 1, Time: "09:30"},
|
|
{Weekday: 3, Time: "12:30"},
|
|
{Weekday: 5, Time: "18:30"},
|
|
},
|
|
CreateAt: now,
|
|
UpdateAt: now,
|
|
}
|
|
}
|
|
|
|
func toSummary(item *entity.Policy) domusecase.PolicySummary {
|
|
if item == nil {
|
|
return domusecase.PolicySummary{}
|
|
}
|
|
return domusecase.PolicySummary{
|
|
AccountID: item.AccountID, Enabled: item.Enabled, TargetDailyCount: item.TargetDailyCount,
|
|
LowStockThreshold: item.LowStockThreshold, LookaheadDays: item.LookaheadDays,
|
|
Timezone: item.Timezone, Slots: slotsFromEntity(item.Slots), SourceRefs: sourceRefsFromEntity(item.SourceRefs), UpdateAt: item.UpdateAt,
|
|
}
|
|
}
|
|
|
|
func slotsToEntity(items []domusecase.Slot) []entity.Slot {
|
|
out := make([]entity.Slot, 0, len(items))
|
|
for _, item := range items {
|
|
if strings.TrimSpace(item.Time) == "" {
|
|
continue
|
|
}
|
|
out = append(out, entity.Slot{Weekday: item.Weekday, Time: strings.TrimSpace(item.Time)})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func slotsFromEntity(items []entity.Slot) []domusecase.Slot {
|
|
out := make([]domusecase.Slot, 0, len(items))
|
|
for _, item := range items {
|
|
out = append(out, domusecase.Slot{Weekday: item.Weekday, Time: item.Time})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func sourceRefsToEntity(items []domusecase.SourceRef) []entity.SourceRef {
|
|
out := make([]entity.SourceRef, 0, len(items))
|
|
for _, item := range items {
|
|
if strings.TrimSpace(item.Type) == "" {
|
|
continue
|
|
}
|
|
out = append(out, entity.SourceRef{
|
|
Type: strings.TrimSpace(item.Type), PersonaID: strings.TrimSpace(item.PersonaID),
|
|
CopyMissionID: strings.TrimSpace(item.CopyMissionID), ScanPostID: strings.TrimSpace(item.ScanPostID), ManualSeed: strings.TrimSpace(item.ManualSeed),
|
|
})
|
|
}
|
|
return out
|
|
}
|
|
|
|
func sourceRefsFromEntity(items []entity.SourceRef) []domusecase.SourceRef {
|
|
out := make([]domusecase.SourceRef, 0, len(items))
|
|
for _, item := range items {
|
|
out = append(out, domusecase.SourceRef{
|
|
Type: item.Type, PersonaID: item.PersonaID, CopyMissionID: item.CopyMissionID, ScanPostID: item.ScanPostID, ManualSeed: item.ManualSeed,
|
|
})
|
|
}
|
|
return out
|
|
}
|