Reapply "feat(loyalty): EnakPoint & EnakCoin" (#32)
This reverts commit 4e24f9bbb0.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"apskel-pos-be/internal/constants"
|
||||
"apskel-pos-be/internal/contract"
|
||||
)
|
||||
|
||||
// walletAdjustmentReasonLimit is the size of wallet_transactions.reason.
|
||||
const walletAdjustmentReasonLimit = 255
|
||||
|
||||
// walletCashOutWords are reasons that describe turning balance into money. EnakPoint
|
||||
// and EnakCoin can never be cashed out, and an adjustment must not be used to record
|
||||
// that it happened (docs/prd-point-coin.md K7). Words like "tunai" are left out on
|
||||
// purpose: "paid in cash but the points never arrived" is a legitimate reason.
|
||||
var walletCashOutWords = []string{"pencairan", "cairkan", "cash out", "cashout", "withdraw"}
|
||||
|
||||
type WalletValidator interface {
|
||||
ValidateAdjustRequest(req *contract.AdjustCustomerWalletRequest) (error, string)
|
||||
}
|
||||
|
||||
type WalletValidatorImpl struct{}
|
||||
|
||||
func NewWalletValidator() *WalletValidatorImpl {
|
||||
return &WalletValidatorImpl{}
|
||||
}
|
||||
|
||||
func (v *WalletValidatorImpl) ValidateAdjustRequest(req *contract.AdjustCustomerWalletRequest) (error, string) {
|
||||
if req == nil {
|
||||
return errors.New("request body is required"), constants.MissingFieldErrorCode
|
||||
}
|
||||
|
||||
req.Currency = strings.ToUpper(strings.TrimSpace(req.Currency))
|
||||
if req.Currency == "" {
|
||||
return errors.New("currency is required"), constants.MissingFieldErrorCode
|
||||
}
|
||||
if !constants.IsValidWalletCurrency(req.Currency) {
|
||||
return errors.New("currency must be POINT or COIN"), constants.MalformedFieldErrorCode
|
||||
}
|
||||
|
||||
if req.Amount == 0 {
|
||||
return errors.New("amount must not be zero: use a positive amount to add and a negative one to take away"), constants.ValidationErrorCode
|
||||
}
|
||||
|
||||
req.Reason = strings.TrimSpace(req.Reason)
|
||||
if req.Reason == "" {
|
||||
return errors.New("reason is required"), constants.MissingFieldErrorCode
|
||||
}
|
||||
if utf8.RuneCountInString(req.Reason) > walletAdjustmentReasonLimit {
|
||||
return errors.New("reason must be at most 255 characters"), constants.MalformedFieldErrorCode
|
||||
}
|
||||
lower := strings.ToLower(req.Reason)
|
||||
for _, word := range walletCashOutWords {
|
||||
if strings.Contains(lower, word) {
|
||||
return errors.New("EnakPoint and EnakCoin cannot be cashed out, so an adjustment cannot be for a cash-out"), constants.ValidationErrorCode
|
||||
}
|
||||
}
|
||||
|
||||
if len(req.IdempotencyKey) > 50 {
|
||||
return errors.New("idempotency_key must be at most 50 characters"), constants.MalformedFieldErrorCode
|
||||
}
|
||||
return nil, ""
|
||||
}
|
||||
Reference in New Issue
Block a user