107 lines
3.5 KiB
Go
107 lines
3.5 KiB
Go
package gateway
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/shopspring/decimal"
|
|
"github.com/tech/sendico/pkg/merrors"
|
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
|
mntxv1 "github.com/tech/sendico/pkg/proto/gateway/mntx/v1"
|
|
)
|
|
|
|
func validateAmount(amount *moneyv1.Money) error {
|
|
if amount == nil {
|
|
return newPayoutError("missing_amount", merrors.InvalidArgument("amount is required", "amount"))
|
|
}
|
|
|
|
if strings.TrimSpace(amount.Currency) == "" {
|
|
return newPayoutError("missing_currency", merrors.InvalidArgument("amount currency is required", "amount.currency"))
|
|
}
|
|
|
|
val := strings.TrimSpace(amount.Amount)
|
|
if val == "" {
|
|
return newPayoutError("missing_amount_value", merrors.InvalidArgument("amount value is required", "amount.amount"))
|
|
}
|
|
dec, err := decimal.NewFromString(val)
|
|
if err != nil {
|
|
return newPayoutError("invalid_amount", merrors.InvalidArgument("amount must be a decimal value", "amount.amount"))
|
|
}
|
|
if dec.Sign() <= 0 {
|
|
return newPayoutError("non_positive_amount", merrors.InvalidArgument("amount must be positive", "amount.amount"))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateDestination(dest *mntxv1.PayoutDestination) error {
|
|
if dest == nil {
|
|
return newPayoutError("missing_destination", merrors.InvalidArgument("destination is required", "destination"))
|
|
}
|
|
|
|
if bank := dest.GetBankAccount(); bank != nil {
|
|
return validateBankAccount(bank)
|
|
}
|
|
|
|
if card := dest.GetCard(); card != nil {
|
|
return validateCardDestination(card)
|
|
}
|
|
|
|
return newPayoutError("invalid_destination", merrors.InvalidArgument("destination must include bank_account or card", "destination"))
|
|
}
|
|
|
|
func validateBankAccount(dest *mntxv1.BankAccount) error {
|
|
if dest == nil {
|
|
return newPayoutError("missing_destination", merrors.InvalidArgument("destination is required", "destination"))
|
|
}
|
|
iban := strings.TrimSpace(dest.Iban)
|
|
holder := strings.TrimSpace(dest.AccountHolder)
|
|
|
|
if iban == "" && holder == "" {
|
|
return newPayoutError("invalid_destination", merrors.InvalidArgument("destination must include iban or account_holder", "destination"))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateCardDestination(card *mntxv1.CardDestination) error {
|
|
if card == nil {
|
|
return newPayoutError("missing_destination", merrors.InvalidArgument("destination.card is required", "destination.card"))
|
|
}
|
|
|
|
pan := strings.TrimSpace(card.GetPan())
|
|
token := strings.TrimSpace(card.GetToken())
|
|
if pan == "" && token == "" {
|
|
return newPayoutError("invalid_card_destination", merrors.InvalidArgument("card destination must include pan or token", "destination.card"))
|
|
}
|
|
|
|
if strings.TrimSpace(card.GetCardholderName()) == "" {
|
|
return newPayoutError("missing_cardholder_name", merrors.InvalidArgument("cardholder_name is required", "destination.card.cardholder_name"))
|
|
}
|
|
|
|
month := strings.TrimSpace(card.GetExpMonth())
|
|
year := strings.TrimSpace(card.GetExpYear())
|
|
if pan != "" {
|
|
if err := validateExpiry(month, year); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateExpiry(month, year string) error {
|
|
if month == "" || year == "" {
|
|
return newPayoutError("missing_expiry", merrors.InvalidArgument("exp_month and exp_year are required for card payouts", "destination.card.expiry"))
|
|
}
|
|
|
|
m, err := strconv.Atoi(month)
|
|
if err != nil || m < 1 || m > 12 {
|
|
return newPayoutError("invalid_expiry_month", merrors.InvalidArgument("exp_month must be between 01 and 12", "destination.card.exp_month"))
|
|
}
|
|
|
|
if _, err := strconv.Atoi(year); err != nil || len(year) < 2 {
|
|
return newPayoutError("invalid_expiry_year", merrors.InvalidArgument("exp_year must be numeric", "destination.card.exp_year"))
|
|
}
|
|
|
|
return nil
|
|
}
|