153 lines
5.3 KiB
Go
153 lines
5.3 KiB
Go
package processor
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"apskel-pos-be/internal/entities"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func jakarta(t *testing.T) *time.Location {
|
|
t.Helper()
|
|
loc, err := time.LoadLocation("Asia/Jakarta")
|
|
require.NoError(t, err)
|
|
return loc
|
|
}
|
|
|
|
func TestStartOfWeekLandsOnMonday(t *testing.T) {
|
|
loc := jakarta(t)
|
|
|
|
// 3 Aug 2026 is a Monday, so the whole week must collapse onto it
|
|
monday := time.Date(2026, 8, 3, 0, 0, 0, 0, loc)
|
|
|
|
for offset := 0; offset < 7; offset++ {
|
|
day := monday.AddDate(0, 0, offset).Add(13 * time.Hour)
|
|
|
|
got := startOfWeek(day)
|
|
require.Equal(t, monday, got, "day %s should map to %s", day, monday)
|
|
require.Equal(t, time.Monday, got.Weekday())
|
|
}
|
|
}
|
|
|
|
func TestEndOfWeekLandsOnSunday(t *testing.T) {
|
|
loc := jakarta(t)
|
|
|
|
// Sunday 9 Aug 2026 closes the week that starts Monday 3 Aug
|
|
got := endOfWeek(time.Date(2026, 8, 5, 9, 30, 0, 0, loc))
|
|
|
|
require.Equal(t, time.Sunday, got.Weekday())
|
|
require.Equal(t, 2026, got.Year())
|
|
require.Equal(t, time.August, got.Month())
|
|
require.Equal(t, 9, got.Day())
|
|
require.Equal(t, 23, got.Hour())
|
|
require.Equal(t, 59, got.Minute())
|
|
}
|
|
|
|
func TestBuildBudgetCutOffWidensToWholeWeeks(t *testing.T) {
|
|
loc := jakarta(t)
|
|
processor := &AnalyticsProcessorImpl{analyticsRepo: &analyticsRepositoryStub{}}
|
|
|
|
// Saturday 1 Aug to Monday 31 Aug 2026: both ends fall mid-week
|
|
from := time.Date(2026, 8, 1, 0, 0, 0, 0, loc)
|
|
to := time.Date(2026, 8, 31, 23, 59, 59, 0, loc)
|
|
|
|
budget, err := processor.buildBudgetCutOff(context.Background(), uuid.New(), nil, nil, from, to)
|
|
require.NoError(t, err)
|
|
|
|
// Reaches back into July and forward into September to keep weeks whole
|
|
require.Equal(t, time.Monday, budget.CutOffFrom.Weekday())
|
|
require.Equal(t, time.July, budget.CutOffFrom.Month())
|
|
require.Equal(t, 27, budget.CutOffFrom.Day())
|
|
require.Equal(t, time.Sunday, budget.CutOffTo.Weekday())
|
|
require.Equal(t, time.September, budget.CutOffTo.Month())
|
|
require.Equal(t, 6, budget.CutOffTo.Day())
|
|
|
|
require.Len(t, budget.Weekly, 6)
|
|
for _, week := range budget.Weekly {
|
|
require.Equal(t, time.Monday, week.PeriodStart.Weekday())
|
|
require.Equal(t, time.Sunday, week.PeriodEnd.Weekday())
|
|
}
|
|
|
|
// A week is filed under the month of its Monday, so the 27 Jul week counts as July
|
|
require.Len(t, budget.Monthly, 2)
|
|
require.Equal(t, "2026-07", budget.Monthly[0].Month)
|
|
require.Equal(t, 1, budget.Monthly[0].WeekCount)
|
|
require.Equal(t, "2026-08", budget.Monthly[1].Month)
|
|
require.Equal(t, 5, budget.Monthly[1].WeekCount)
|
|
}
|
|
|
|
func TestBuildBudgetCutOffAppliesLimits(t *testing.T) {
|
|
loc := jakarta(t)
|
|
weekStart := time.Date(2026, 8, 3, 0, 0, 0, 0, loc)
|
|
|
|
stub := &analyticsRepositoryStub{budgetCutOffWeeks: []*entities.BudgetCutOffWeek{
|
|
{WeekStart: weekStart, Revenue: 10_000_000, OrderCount: 120},
|
|
}}
|
|
processor := &AnalyticsProcessorImpl{analyticsRepo: stub}
|
|
|
|
budget, err := processor.buildBudgetCutOff(context.Background(), uuid.New(), nil, nil, weekStart, weekStart.AddDate(0, 0, 6))
|
|
require.NoError(t, err)
|
|
require.Len(t, budget.Weekly, 1)
|
|
|
|
// 60 / 20 / 20 of the week's revenue
|
|
week := budget.Weekly[0]
|
|
require.Equal(t, float64(6_000_000), week.LimitPurchase)
|
|
require.Equal(t, float64(2_000_000), week.LimitOwner)
|
|
require.Equal(t, float64(2_000_000), week.LimitTeam)
|
|
require.Equal(t, int64(120), week.OrderCount)
|
|
|
|
// Totals mirror the single week
|
|
require.Equal(t, week.Revenue, budget.Total.Revenue)
|
|
require.Equal(t, week.LimitPurchase, budget.Total.LimitPurchase)
|
|
}
|
|
|
|
func TestBuildBudgetCutOffAccumulatesMonthlyFromWeeks(t *testing.T) {
|
|
loc := jakarta(t)
|
|
first := time.Date(2026, 8, 3, 0, 0, 0, 0, loc)
|
|
|
|
stub := &analyticsRepositoryStub{budgetCutOffWeeks: []*entities.BudgetCutOffWeek{
|
|
{WeekStart: first, Revenue: 10_000_000, OrderCount: 100},
|
|
{WeekStart: first.AddDate(0, 0, 7), Revenue: 5_000_000, OrderCount: 60},
|
|
}}
|
|
processor := &AnalyticsProcessorImpl{analyticsRepo: stub}
|
|
|
|
budget, err := processor.buildBudgetCutOff(context.Background(), uuid.New(), nil, nil, first, first.AddDate(0, 0, 9))
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, budget.Monthly, 1)
|
|
month := budget.Monthly[0]
|
|
require.Equal(t, "2026-08", month.Month)
|
|
require.Equal(t, 2, month.WeekCount)
|
|
require.Equal(t, float64(15_000_000), month.Revenue)
|
|
require.Equal(t, int64(160), month.OrderCount)
|
|
|
|
// The month limit is the accumulation of its weeks
|
|
require.Equal(t, float64(9_000_000), month.LimitPurchase)
|
|
require.Equal(t, budget.Weekly[0].LimitPurchase+budget.Weekly[1].LimitPurchase, month.LimitPurchase)
|
|
}
|
|
|
|
func TestBuildBudgetCutOffEmitsWeeksWithoutSales(t *testing.T) {
|
|
loc := jakarta(t)
|
|
first := time.Date(2026, 8, 3, 0, 0, 0, 0, loc)
|
|
|
|
// Only the third week has sales; the two quiet weeks must still be reported
|
|
stub := &analyticsRepositoryStub{budgetCutOffWeeks: []*entities.BudgetCutOffWeek{
|
|
{WeekStart: first.AddDate(0, 0, 14), Revenue: 4_000_000, OrderCount: 40},
|
|
}}
|
|
processor := &AnalyticsProcessorImpl{analyticsRepo: stub}
|
|
|
|
budget, err := processor.buildBudgetCutOff(context.Background(), uuid.New(), nil, nil, first, first.AddDate(0, 0, 16))
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, budget.Weekly, 3)
|
|
require.Zero(t, budget.Weekly[0].Revenue)
|
|
require.Zero(t, budget.Weekly[0].LimitPurchase)
|
|
require.Zero(t, budget.Weekly[1].Revenue)
|
|
require.Equal(t, float64(4_000_000), budget.Weekly[2].Revenue)
|
|
require.Equal(t, float64(4_000_000), budget.Total.Revenue)
|
|
}
|