135 lines
4.6 KiB
Go
135 lines
4.6 KiB
Go
package job
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"haixun-backend/internal/library/publishschedule"
|
|
copydraftdomain "haixun-backend/internal/model/copy_draft/domain/usecase"
|
|
missiondomain "haixun-backend/internal/model/copy_mission/domain/usecase"
|
|
jobdom "haixun-backend/internal/model/job/domain/usecase"
|
|
inventorydomain "haixun-backend/internal/model/publish_inventory/domain/usecase"
|
|
pqdomain "haixun-backend/internal/model/publish_queue/domain/usecase"
|
|
)
|
|
|
|
type RefillPublishInventoryDeps struct {
|
|
Jobs jobdom.UseCase
|
|
PublishInventory inventorydomain.UseCase
|
|
PublishQueue pqdomain.UseCase
|
|
CopyMission missiondomain.UseCase
|
|
CopyDraft copydraftdomain.UseCase
|
|
}
|
|
|
|
func RegisterRefillPublishInventoryHandler(runner *Runner, deps RefillPublishInventoryDeps) {
|
|
if runner == nil {
|
|
return
|
|
}
|
|
runner.RegisterStepHandler("refill_publish_inventory", func(ctx context.Context, step StepContext) error {
|
|
return runRefillPublishInventory(ctx, step, deps)
|
|
})
|
|
}
|
|
|
|
func runRefillPublishInventory(ctx context.Context, step StepContext, deps RefillPublishInventoryDeps) error {
|
|
payload := step.Run.Payload
|
|
tenantID, ownerUID := runActorFromPayload(payload, step.Run)
|
|
accountID := stringField(payload, "account_id")
|
|
if tenantID == "" || ownerUID == "" || accountID == "" {
|
|
return fmt.Errorf("refill publish inventory payload missing tenant_id, owner_uid, or account_id")
|
|
}
|
|
if deps.PublishInventory == nil || deps.PublishQueue == nil {
|
|
return fmt.Errorf("publish inventory dependencies are not configured")
|
|
}
|
|
policy, err := deps.PublishInventory.Get(ctx, tenantID, ownerUID, accountID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !policy.Enabled {
|
|
return nil
|
|
}
|
|
health, err := deps.PublishQueue.ListPublishHealth(ctx, tenantID, ownerUID, accountID, 1, 1)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
need := policy.LowStockThreshold - int(health.Summary.PendingScheduled)
|
|
if requested := intField(payload, "count"); requested > 0 {
|
|
need = requested
|
|
}
|
|
if need <= 0 {
|
|
return nil
|
|
}
|
|
if need > 12 {
|
|
need = 12
|
|
}
|
|
slots := make([]publishschedule.Slot, 0, len(policy.Slots))
|
|
for _, slot := range policy.Slots {
|
|
slots = append(slots, publishschedule.Slot{Weekday: slot.Weekday, Time: slot.Time})
|
|
}
|
|
times := publishschedule.BuildSchedule(0, policy.Timezone, slots, need)
|
|
for i := 0; i < need; i++ {
|
|
if err := step.Heartbeat(ctx); err != nil {
|
|
return err
|
|
}
|
|
ref := pickSourceRef(policy.SourceRefs, i)
|
|
text, personaID, missionID := refillText(ctx, deps, tenantID, ownerUID, ref, i)
|
|
createReq := pqdomain.CreateRequest{
|
|
TenantID: tenantID, OwnerUID: ownerUID, AccountID: accountID,
|
|
PersonaID: personaID, CopyMissionID: missionID, Text: text,
|
|
}
|
|
if i < len(times) {
|
|
createReq.ScheduledAt = times[i]
|
|
}
|
|
if deps.CopyDraft != nil && personaID != "" {
|
|
draft, err := deps.CopyDraft.Create(ctx, copydraftdomain.CreateRequest{
|
|
TenantID: tenantID, OwnerUID: ownerUID, PersonaID: personaID,
|
|
CopyMissionID: missionID, DraftType: "inventory-refill", SortOrder: i + 1,
|
|
Text: text, Rationale: "自動補庫存產生",
|
|
})
|
|
if err == nil && draft != nil {
|
|
createReq.CopyDraftID = draft.ID
|
|
}
|
|
}
|
|
item, err := deps.PublishQueue.Create(ctx, createReq)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if deps.CopyDraft != nil && createReq.CopyDraftID != "" {
|
|
_, _ = deps.CopyDraft.MarkScheduled(ctx, copydraftdomain.MarkScheduledRequest{
|
|
TenantID: tenantID, OwnerUID: ownerUID, PersonaID: personaID, DraftID: createReq.CopyDraftID, QueueID: item.ID,
|
|
})
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func pickSourceRef(items []inventorydomain.SourceRef, idx int) inventorydomain.SourceRef {
|
|
if len(items) == 0 {
|
|
return inventorydomain.SourceRef{Type: "manual_seed", ManualSeed: "分享一個今天巡樓觀察到的重點"}
|
|
}
|
|
return items[idx%len(items)]
|
|
}
|
|
|
|
func refillText(ctx context.Context, deps RefillPublishInventoryDeps, tenantID, ownerUID string, ref inventorydomain.SourceRef, idx int) (string, string, string) {
|
|
personaID := strings.TrimSpace(ref.PersonaID)
|
|
missionID := strings.TrimSpace(ref.CopyMissionID)
|
|
seed := strings.TrimSpace(ref.ManualSeed)
|
|
if missionID != "" && personaID != "" && deps.CopyMission != nil {
|
|
if mission, err := deps.CopyMission.Get(ctx, tenantID, ownerUID, personaID, missionID); err == nil {
|
|
seed = strings.TrimSpace(firstNonEmpty(mission.Brief, mission.Label, mission.SeedQuery))
|
|
}
|
|
}
|
|
if seed == "" {
|
|
seed = "分享一個今天巡樓觀察到的重點"
|
|
}
|
|
return fmt.Sprintf("%s\n\n巡樓筆記 #%d", seed, idx+1), personaID, missionID
|
|
}
|
|
|
|
func firstNonEmpty(values ...string) string {
|
|
for _, value := range values {
|
|
if strings.TrimSpace(value) != "" {
|
|
return strings.TrimSpace(value)
|
|
}
|
|
}
|
|
return ""
|
|
}
|