Files

111 lines
3.4 KiB
Go
Raw Permalink Normal View History

package marketing
import (
"fmt"
"time"
)
// PresetID identifies a seasonal content-calendar preset.
type PresetID string
const (
PresetBlackFriday PresetID = "black_friday"
PresetChristmas PresetID = "christmas"
)
// CampaignStructureKey is stored on export_feeds.template JSON (no migration).
const CampaignStructureKey = "_campaign"
// Preset is a dated seasonal window for preparing an export feed.
type Preset struct {
ID PresetID `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
Year int `json:"year"`
}
// StructureMeta is persisted under template._campaign.
type StructureMeta struct {
PresetID PresetID `json:"presetId"`
Name string `json:"name"`
StartDate string `json:"startDate"`
EndDate string `json:"endDate"`
Year int `json:"year"`
PreparedAt string `json:"preparedAt"`
}
func pad2(n int) string {
return fmt.Sprintf("%02d", n)
}
func toISODate(t time.Time) string {
return fmt.Sprintf("%s-%s-%s", pad2(t.Year()), pad2(int(t.Month())), pad2(t.Day()))
}
// BlackFridayDate returns Black Friday (day after US Thanksgiving) in UTC date parts.
func BlackFridayDate(year int) time.Time {
nov1 := time.Date(year, time.November, 1, 0, 0, 0, 0, time.UTC)
dow := int(nov1.Weekday()) // Sunday=0
firstThursday := 1 + ((4 - dow + 7) % 7)
fourthThursday := firstThursday + 21
return time.Date(year, time.November, fourthThursday+1, 0, 0, 0, 0, time.UTC)
}
// ResolvePreset returns date window for a preset id and year.
func ResolvePreset(id PresetID, year int) (Preset, error) {
if year < 2000 || year > 2100 {
return Preset{}, ClientMsg("invalid year")
}
switch id {
case PresetBlackFriday:
bf := BlackFridayDate(year)
start := bf.AddDate(0, 0, -7)
end := bf.AddDate(0, 0, 3)
return Preset{
ID: id,
Name: "Black Friday",
Description: "Promo window around Black Friday — prepare a Google Shopping-style export feed.",
StartDate: toISODate(start),
EndDate: toISODate(end),
Year: year,
}, nil
case PresetChristmas:
return Preset{
ID: PresetChristmas,
Name: "Christmas",
Description: "Holiday catalog push from Dec 1 through Boxing Day.",
StartDate: toISODate(time.Date(year, time.December, 1, 0, 0, 0, 0, time.UTC)),
EndDate: toISODate(time.Date(year, time.December, 26, 0, 0, 0, 0, time.UTC)),
Year: year,
}, nil
default:
return Preset{}, ClientMsg("preset_id must be black_friday or christmas")
}
}
// ListPresets returns Black Friday + Christmas for the year.
func ListPresets(year int) []Preset {
bf, _ := ResolvePreset(PresetBlackFriday, year)
xmas, _ := ResolvePreset(PresetChristmas, year)
return []Preset{bf, xmas}
}
// DefaultCampaignMappings are Google Shopping-ish CSV column → product field sources.
func DefaultCampaignMappings() map[string]string {
return map[string]string{
"id": "product_id",
"title": "processed_name",
"description": "processed_description",
"link": "attr.url",
"image_link": "attr.image",
"availability": "attr.availability",
"price": "attr.price",
"brand": "attr.brand",
"gtin": "gtin",
"google_product_category": "category",
"condition": "attr.condition",
}
}