116 lines
4.7 KiB
Go
116 lines
4.7 KiB
Go
package processor
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"apskel-pos-be/internal/models"
|
|
)
|
|
|
|
// wib is a moment in the customer's time zone.
|
|
func wib(year int, month time.Month, day, hour, minute int) time.Time {
|
|
return time.Date(year, month, day, hour, minute, 0, 0, walletDisplayLocation)
|
|
}
|
|
|
|
// expiryDay is the day a lot expires on, as the apps show it.
|
|
func expiryDay(t *testing.T, at *time.Time) string {
|
|
t.Helper()
|
|
require.NotNil(t, at)
|
|
local := at.In(walletDisplayLocation)
|
|
assert.Equal(t, "23:59:59", local.Format("15:04:05"), "a lot lasts to the end of its day")
|
|
return local.Format("2006-01-02")
|
|
}
|
|
|
|
func fixedDate(dates ...string) models.LoyaltyExpirySettings {
|
|
return models.LoyaltyExpirySettings{Enabled: true, Mode: "FIXED_DATE", FixedDates: dates, GraceMonths: 3}
|
|
}
|
|
|
|
func rolling(period int64, unit string, endOfMonth bool) models.LoyaltyExpirySettings {
|
|
return models.LoyaltyExpirySettings{Enabled: true, Mode: "ROLLING", Period: period, Unit: unit, EndOfMonth: endOfMonth}
|
|
}
|
|
|
|
func TestComputeExpiry_OffNeverExpires(t *testing.T) {
|
|
s := fixedDate("12-31")
|
|
s.Enabled = false
|
|
assert.Nil(t, ComputeExpiry(s, wib(2026, 5, 1, 10, 0)))
|
|
}
|
|
|
|
func TestComputeExpiry_FixedDateWithGrace(t *testing.T) {
|
|
yearly := fixedDate("12-31")
|
|
for received, want := range map[time.Time]string{
|
|
wib(2026, 1, 15, 9, 0): "2026-12-31",
|
|
wib(2026, 9, 30, 23, 0): "2026-12-31", // 30 Dec + nothing: still this year
|
|
wib(2026, 10, 1, 0, 30): "2027-12-31", // within 3 months of 31 Dec: next year
|
|
wib(2026, 12, 31, 8, 0): "2027-12-31",
|
|
} {
|
|
assert.Equal(t, want, expiryDay(t, ComputeExpiry(yearly, received)), received.String())
|
|
}
|
|
|
|
twice := fixedDate("12-31", "06-30")
|
|
assert.Equal(t, "2026-06-30", expiryDay(t, ComputeExpiry(twice, wib(2026, 3, 1, 12, 0))))
|
|
assert.Equal(t, "2026-12-31", expiryDay(t, ComputeExpiry(twice, wib(2026, 4, 1, 12, 0))))
|
|
assert.Equal(t, "2027-06-30", expiryDay(t, ComputeExpiry(twice, wib(2026, 10, 1, 12, 0))))
|
|
|
|
noGrace := fixedDate("12-31")
|
|
noGrace.GraceMonths = 0
|
|
assert.Equal(t, "2026-12-31", expiryDay(t, ComputeExpiry(noGrace, wib(2026, 12, 31, 22, 0))))
|
|
}
|
|
|
|
// The day received is the customer's day: 20:00 UTC on 31 Mar is already 1 Apr in WIB.
|
|
func TestComputeExpiry_UsesTheCustomersDay(t *testing.T) {
|
|
received := time.Date(2026, 3, 31, 20, 0, 0, 0, time.UTC)
|
|
assert.Equal(t, "2026-04-11", expiryDay(t, ComputeExpiry(rolling(10, "DAY", false), received)))
|
|
}
|
|
|
|
func TestComputeExpiry_Rolling(t *testing.T) {
|
|
assert.Equal(t, "2027-03-14", expiryDay(t, ComputeExpiry(rolling(12, "MONTH", false), wib(2026, 3, 14, 10, 0))))
|
|
assert.Equal(t, "2027-03-31", expiryDay(t, ComputeExpiry(rolling(12, "MONTH", true), wib(2026, 3, 14, 10, 0))))
|
|
assert.Equal(t, "2026-03-24", expiryDay(t, ComputeExpiry(rolling(10, "DAY", false), wib(2026, 3, 14, 10, 0))))
|
|
// A month that is shorter keeps to its last day.
|
|
assert.Equal(t, "2026-02-28", expiryDay(t, ComputeExpiry(rolling(1, "MONTH", false), wib(2026, 1, 31, 10, 0))))
|
|
}
|
|
|
|
func TestActivationExpiry(t *testing.T) {
|
|
// FIXED_DATE: the second fixed date after activation, so nobody loses a balance
|
|
// weeks after the rule is announced.
|
|
assert.Equal(t, "2027-12-31", expiryDay(t, ActivationExpiry(fixedDate("12-31"), wib(2026, 11, 20, 10, 0))))
|
|
assert.Equal(t, "2027-12-31", expiryDay(t, ActivationExpiry(fixedDate("12-31"), wib(2026, 12, 31, 10, 0))))
|
|
assert.Equal(t, "2027-06-30", expiryDay(t, ActivationExpiry(fixedDate("06-30", "12-31"), wib(2026, 11, 20, 10, 0))))
|
|
// ROLLING: a full period from activation.
|
|
assert.Equal(t, "2027-11-20", expiryDay(t, ActivationExpiry(rolling(12, "MONTH", false), wib(2026, 11, 20, 10, 0))))
|
|
}
|
|
|
|
func TestRefundExpiry(t *testing.T) {
|
|
now := wib(2026, 6, 1, 10, 0)
|
|
later := wib(2026, 12, 31, 23, 59)
|
|
soon := wib(2026, 6, 3, 23, 59)
|
|
past := wib(2026, 5, 1, 23, 59)
|
|
|
|
assert.Nil(t, RefundExpiry(nil, now))
|
|
assert.Equal(t, &later, RefundExpiry(&later, now))
|
|
assert.Equal(t, "2026-06-08", expiryDay(t, RefundExpiry(&soon, now)))
|
|
assert.Equal(t, "2026-06-08", expiryDay(t, RefundExpiry(&past, now)))
|
|
}
|
|
|
|
func TestEarlierExpiry(t *testing.T) {
|
|
a, b := wib(2026, 1, 1, 0, 0), wib(2026, 2, 1, 0, 0)
|
|
assert.Equal(t, &a, EarlierExpiry(&a, &b))
|
|
assert.Equal(t, &a, EarlierExpiry(&b, &a))
|
|
assert.Equal(t, &a, EarlierExpiry(nil, &a))
|
|
assert.Equal(t, &a, EarlierExpiry(&a, nil))
|
|
assert.Nil(t, EarlierExpiry(nil, nil))
|
|
}
|
|
|
|
func TestNormalizeDaysOfYear(t *testing.T) {
|
|
days, err := normalizeDaysOfYear([]string{" 12-31", "06-30", "12-31", ""})
|
|
require.NoError(t, err)
|
|
assert.Equal(t, []string{"06-30", "12-31"}, days)
|
|
for _, bad := range [][]string{{}, {"13-01"}, {"12-32"}, {"1-31"}, {"02-29"}, {"31-12"}} {
|
|
_, err := normalizeDaysOfYear(bad)
|
|
assert.Error(t, err, bad)
|
|
}
|
|
}
|