feat: add percentage loyalti setting mode

This commit is contained in:
efrilm
2026-10-02 14:19:12 +07:00
parent d3e3ea6b08
commit b372821b23
13 changed files with 193 additions and 36 deletions
@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert"
"apskel-pos-be/internal/constants"
"apskel-pos-be/internal/entities"
"apskel-pos-be/internal/models"
)
@@ -113,6 +114,44 @@ func TestCalculateEarning_EdgeCases(t *testing.T) {
assert.Equal(t, int64(0), CalculateEarning(&entities.Order{Subtotal: 87500}, 0, s).Point.Amount)
}
func TestCalculateEarning_Percentage(t *testing.T) {
s := prdEarningSettings()
s.Point.EarnMode = constants.LoyaltyEarnModePercentage
s.Point.EarnPercent = 1
// 1% of the basis; the per-amount settings are ignored, and coin keeps its own mode.
got := CalculateEarning(&entities.Order{Subtotal: 97500, DiscountAmount: 10000}, 0, s)
assert.Equal(t, int64(875), got.Point.Amount)
assert.Equal(t, int64(3), got.Coin.Amount)
// The part paid with EnakPoint earns nothing in this mode either.
assert.Equal(t, int64(675), CalculateEarning(&entities.Order{Subtotal: 97500, DiscountAmount: 10000}, 20000, s).Point.Amount)
// Decimals, and floor, not round: 2.5% of 87.500 is 2187.5.
s.Point.EarnPercent = 2.5
assert.Equal(t, int64(2187), CalculateEarning(&entities.Order{Subtotal: 87500}, 0, s).Point.Amount)
s.Point.EarnPercent = 0.01
assert.Equal(t, int64(8), CalculateEarning(&entities.Order{Subtotal: 87599.99}, 0, s).Point.Amount)
// The minimum and the cap apply as in the other mode.
s.Point.EarnPercent = 10
s.Point.MinOrderAmount = 50000
max := int64(6000)
s.Point.MaxPerOrder = &max
assert.Equal(t, int64(0), CalculateEarning(&entities.Order{Subtotal: 49999}, 0, s).Point.Amount)
assert.Equal(t, int64(5000), CalculateEarning(&entities.Order{Subtotal: 50000}, 0, s).Point.Amount)
got = CalculateEarning(&entities.Order{Subtotal: 87500}, 0, s)
assert.Equal(t, int64(6000), got.Point.Amount)
assert.True(t, got.Point.Capped)
// The mode and percent are frozen on the ledger row.
assert.Equal(t, constants.LoyaltyEarnModePercentage, got.Metadata(got.Point)["earn_mode"])
assert.Equal(t, 10.0, got.Metadata(got.Point)["earn_percent"])
// A zero percent earns nothing even when enabled.
s.Point.EarnPercent = 0
assert.Equal(t, int64(0), CalculateEarning(&entities.Order{Subtotal: 87500}, 0, s).Point.Amount)
}
func TestCalculateEarning_MetadataSnapshot(t *testing.T) {
got := CalculateEarning(&entities.Order{Subtotal: 87500}, 0, prdEarningSettings())
assert.Equal(t, entities.Metadata{