feat(loyalty): outlet loyalty settings API

Adds GET and PUT /outlets/:id/loyalty-settings (docs/prd-point-coin.md F1,
PC-201) on top of the typed settings processor.

The response shows every setting with its default when unset, the
organization's point value, and the effective EnakPoint cashback
(earn_value × point_value / earn_per_amount), so an owner cannot misread
the scale. PUT applies the body on top of the current settings: fields left
out keep their value, null clears an optional limit, and unknown fields are
refused so a typo cannot be ignored silently. The read-only fields of the
GET response are accepted and ignored, so a client can send back what it
received. It returns the keys that changed. Values outside the F1 bounds
answer 400, and an outlet of another organization 404.

RequireAdminOrManager also lets the purchasing role through, so loyalty
settings and the manual wallet adjustment from PC-107 now use a stricter
RequireLoyaltyManager (superadmin, admin, manager, owner).

Adds a test that registers every route, since gin panics at startup when
two routes name the same path parameter differently.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
efrilm
2026-09-30 10:28:40 +07:00
co-authored by Claude Opus 5.5
parent 39e47ff0e6
commit 2bd53ee4a4
10 changed files with 452 additions and 2 deletions
+3
View File
@@ -152,6 +152,7 @@ func (a *App) Initialize(cfg *config.Config) error {
validators.cashAdvanceValidator,
services.walletAdminService,
validators.walletValidator,
services.loyaltySettingsService,
a.redisClient,
)
@@ -474,6 +475,7 @@ type services struct {
expenseService *service.ExpenseServiceImpl
cashAdvanceService *service.CashAdvanceServiceImpl
walletAdminService *service.WalletAdminServiceImpl
loyaltySettingsService *service.LoyaltySettingsServiceImpl
}
func (a *App) initServices(processors *processors, repos *repositories, cfg *config.Config) *services {
@@ -556,6 +558,7 @@ func (a *App) initServices(processors *processors, repos *repositories, cfg *con
expenseService: service.NewExpenseService(processors.expenseProcessor),
cashAdvanceService: service.NewCashAdvanceService(processors.cashAdvanceProcessor),
walletAdminService: service.NewWalletAdminService(processors.walletAdminProcessor),
loyaltySettingsService: service.NewLoyaltySettingsService(processors.loyaltySettingsProcessor),
}
}