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
+29 -10
View File
@@ -5,6 +5,8 @@ import (
"time"
"github.com/google/uuid"
"apskel-pos-be/internal/constants"
)
// OutletLoyaltySettings are an outlet's loyalty settings (docs/prd-point-coin.md F1).
@@ -15,15 +17,23 @@ type OutletLoyaltySettings struct {
PointPayment LoyaltyPointPaymentSettings `json:"point_payment"`
}
// LoyaltyEarnSettings is how much of one currency an order earns:
// floor(basis / EarnPerAmount) × EarnValue, nothing below MinOrderAmount, and at most
// MaxPerOrder when set.
// LoyaltyEarnSettings is how much of one currency an order earns, nothing below
// MinOrderAmount, and at most MaxPerOrder when set:
//
// - PER_AMOUNT: floor(basis / EarnPerAmount) × EarnValue;
// - PERCENTAGE: floor(basis × EarnPercent / 100).
//
// The settings of the mode not in use are kept, so switching back restores them.
type LoyaltyEarnSettings struct {
Enabled bool `json:"enabled"`
EarnPerAmount int64 `json:"earn_per_amount"`
EarnValue int64 `json:"earn_value"`
MinOrderAmount int64 `json:"min_order_amount"`
MaxPerOrder *int64 `json:"max_per_order"`
Enabled bool `json:"enabled"`
// PER_AMOUNT or PERCENTAGE.
EarnMode string `json:"earn_mode"`
EarnPerAmount int64 `json:"earn_per_amount"`
EarnValue int64 `json:"earn_value"`
// PERCENTAGE: percent of the basis earned, 0–100 with at most two decimals.
EarnPercent float64 `json:"earn_percent"`
MinOrderAmount int64 `json:"min_order_amount"`
MaxPerOrder *int64 `json:"max_per_order"`
}
type LoyaltyPointPaymentSettings struct {
@@ -102,8 +112,8 @@ type OutletLoyaltySettingsView struct {
// The organization's rupiah value of one EnakPoint, which the cashback depends on.
PointValue int64 `json:"point_value"`
// Effective EnakPoint cashback in percent: earn_value × point_value /
// earn_per_amount × 100. Shown next to the setting so an owner cannot misread the
// scale (F1).
// earn_per_amount × 100, or earn_percent × point_value in PERCENTAGE mode. Shown
// next to the setting so an owner cannot misread the scale (F1).
PointCashbackPercent float64 `json:"point_cashback_percent"`
// Set on PUT: the keys that changed.
Changes []LoyaltySettingChange `json:"changes,omitempty"`
@@ -168,6 +178,15 @@ type LoyaltySettingsImpact struct {
CoinRupiahAfter int64 `json:"coin_rupiah_after"`
}
// CashbackPercent is the rupiah value of what an order earns as a percentage of its
// basis, in the mode the settings are in, rounded to two decimals.
func (s LoyaltyEarnSettings) CashbackPercent(pointValue int64) float64 {
if s.EarnMode == constants.LoyaltyEarnModePercentage {
return math.Round(s.EarnPercent*float64(pointValue)*100) / 100
}
return LoyaltyCashbackPercent(s.EarnValue, pointValue, s.EarnPerAmount)
}
// NewLoyaltySettingsImpact computes the impact of moving from one organization setting
// to another on the balances in circulation.
func NewLoyaltySettingsImpact(points, coins int64, before, after OrganizationLoyaltySettings) LoyaltySettingsImpact {