Detailed changes
@@ -4,10 +4,19 @@ require_relative "trust_level_repo"
require_relative "credit_card_sale"
class BuyAccountCreditForm
+ # Returns a TrustLevelRepo instance, allowing for dependency injection.
+ # Either creates a new instance given kwargs or returns the existing instance.
+ # @param kwargs [Hash] keyword arguments.
+ # @option kwargs [TrustLevelRepo] :trust_level_repo An existing TrustLevelRepo instance.
+ # @return [TrustLevelRepo] An instance of TrustLevelRepo.
def self.trust_level_repo(**kwargs)
kwargs[:trust_level_repo] || TrustLevelRepo.new(**kwargs)
end
+ # Factory method to create a BuyAccountCreditForm for a given customer.
+ # It fetches the customer's trust level to determine the maximum top-up amount.
+ # @param customer [Customer] The customer for whom the form is being created.
+ # @return [EMPromise<BuyAccountCreditForm>] A promise that resolves with the new form instance.
def self.for(customer)
trust_level_repo.find(customer).then do |trust_level|
customer.payment_methods.then do |payment_methods|
@@ -16,12 +25,20 @@ class BuyAccountCreditForm
end
end
+ # Initializes a new BuyAccountCreditForm.
+ # @param balance [BigDecimal] The current balance of the customer.
+ # @param payment_methods [PaymentMethods] The available payment methods for the customer.
+ # @param max_top_up_amount [Numeric] The maximum amount the customer is allowed to top up, based on their trust level.
def initialize(balance, payment_methods, max_top_up_amount)
@balance = balance
@payment_methods = payment_methods
@max_top_up_amount = max_top_up_amount
end
+ # Generates the form template for topping up account credit.
+ # The form will include a range for the amount field, constrained by a minimum of $15
+ # and the customer's specific maximum top-up amount.
+ # @return [FormTemplate::OneRender] The rendered form template.
def form
FormTemplate.render(
:top_up,
@@ -8,9 +8,16 @@ require_relative "trust_level_repo"
class TransactionDeclinedError < StandardError; end
+# Error raised when a transaction amount exceeds the maximum allowed limit.
class AmountTooHighError < TransactionDeclinedError
- attr_reader :amount, :max_amount
-
+ # @return [Numeric] The transaction amount that was too high.
+ attr_reader :amount
+ # @return [Numeric] The maximum amount allowed for the transaction.
+ attr_reader :max_amount
+
+ # Initializes a new AmountTooHighError.
+ # @param amount [Numeric] The transaction amount.
+ # @param max_amount [Numeric] The maximum allowed amount.
def initialize(amount, max_amount)
@amount = amount
@max_amount = max_amount
@@ -18,9 +25,16 @@ class AmountTooHighError < TransactionDeclinedError
end
end
+# Error raised when a transaction amount is below the minimum required limit.
class AmountTooLowError < TransactionDeclinedError
- attr_reader :amount, :min_amount
-
+ # @return [Numeric] The transaction amount that was too low.
+ attr_reader :amount
+ # @return [Numeric] The minimum amount required for the transaction.
+ attr_reader :min_amount
+
+ # Initializes a new AmountTooLowError.
+ # @param amount [Numeric] The transaction amount.
+ # @param min_amount [Numeric] The minimum required amount.
def initialize(amount, min_amount)
@amount = amount
@min_amount = min_amount
@@ -28,9 +42,16 @@ class AmountTooLowError < TransactionDeclinedError
end
end
+# Error raised when a transaction is declined, potentially due to exceeding decline limits.
class DeclinedError < TransactionDeclinedError
- attr_reader :declines, :max_declines
-
+ # @return [Integer, nil] The number of declines the customer has.
+ attr_reader :declines
+ # @return [Integer, nil] The maximum number of declines allowed.
+ attr_reader :max_declines
+
+ # Initializes a new DeclinedError.
+ # @param declines [Integer, nil] The current number of declines.
+ # @param max_declines [Integer, nil] The maximum allowed declines.
def initialize(declines, max_declines)
@declines = declines
@max_declines = max_declines
@@ -89,6 +110,12 @@ class CreditCardSale
protected
+ # Validates the transaction against customer locks, trust level, and decline history.
+ # @raise [TransactionDeclinedError] if the customer has made too many payments recently.
+ # @raise [AmountTooHighError] if the amount exceeds the trust level's maximum top-up amount.
+ # @raise [AmountTooLowError] if the amount is below any applicable minimum.
+ # @raise [DeclinedError] if the transaction is declined due to too many previous declines or other trust level restrictions.
+ # @return [EMPromise<void>] A promise that resolves if validation passes, or rejects with an error.
def validate!
EMPromise.all([
REDIS.exists("jmp_customer_credit_card_lock-#{@customer.customer_id}"),
@@ -32,6 +32,8 @@ module TrustLevel
new if manual == "Tomb"
end
+ # The maximum amount a user at Tomb trust level can top up.
+ # @return [Integer] Always 0 for Tomb level.
def max_top_up_amount
0
end
@@ -48,6 +50,11 @@ module TrustLevel
false
end
+ # Validates a credit card transaction for a Tomb trust level user.
+ # Users at this level cannot make credit card transactions.
+ # @param _amount [BigDecimal] The amount of the transaction (ignored).
+ # @param _declines [Integer] The number of recent declines (ignored).
+ # @raise [DeclinedError] Always raised to prevent transactions.
def validate_credit_card_transaction!(_amount, _declines)
# Give a more ambiguous error so they don't know they're tombed.
raise DeclinedError
@@ -67,10 +74,15 @@ module TrustLevel
new if manual == "Basement" || (!manual && settled_amount < 10)
end
+ # The maximum amount a user at Basement trust level can top up.
+ # @return [Integer]
def max_top_up_amount
35
end
+ # The maximum number of credit card declines allowed for a Basement user
+ # before further transactions are blocked.
+ # @return [Integer]
def max_declines
2
end
@@ -87,6 +99,11 @@ module TrustLevel
messages_today < 40
end
+ # Validates a credit card transaction for a Basement trust level user.
+ # @param amount [BigDecimal] The amount of the transaction.
+ # @param declines [Integer] The number of recent declines for the customer.
+ # @raise [DeclinedError] if the number of declines exceeds `max_declines`.
+ # @raise [AmountTooHighError] if the transaction amount exceeds `max_top_up_amount`.
def validate_credit_card_transaction!(amount, declines)
raise DeclinedError.new(declines, max_declines) if declines > max_declines
return unless amount > max_top_up_amount
@@ -108,10 +125,15 @@ module TrustLevel
new if manual == "Paragon" || (!manual && settled_amount > 60)
end
+ # The maximum amount a user at Paragon trust level can top up.
+ # @return [Integer]
def max_top_up_amount
500
end
+ # The maximum number of credit card declines allowed for a Paragon user
+ # before further transactions are blocked.
+ # @return [Integer]
def max_declines
3
end
@@ -128,6 +150,11 @@ module TrustLevel
messages_today < 700
end
+ # Validates a credit card transaction for a Paragon trust level user.
+ # @param amount [BigDecimal] The amount of the transaction.
+ # @param declines [Integer] The number of recent declines for the customer.
+ # @raise [DeclinedError] if the number of declines exceeds `max_declines`.
+ # @raise [AmountTooHighError] if the transaction amount exceeds `max_top_up_amount`.
def validate_credit_card_transaction!(amount, declines)
raise DeclinedError.new(declines, max_declines) if declines > max_declines
return unless amount > max_top_up_amount
@@ -161,6 +188,11 @@ module TrustLevel
true
end
+ # Validates a credit card transaction for an Olympias trust level user.
+ # Users at this level have no restrictions on credit card transactions through this method.
+ # @param _amount [BigDecimal] The amount of the transaction (ignored).
+ # @param _declines [Integer] The number of recent declines (ignored).
+ # @return [void]
def validate_credit_card_transaction!(*) end
def create_subaccount?(*)
@@ -192,10 +224,15 @@ module TrustLevel
@max_rate = EXPENSIVE_ROUTE.fetch(plan_name, 0.1)
end
+ # The maximum amount a user at Customer trust level can top up.
+ # @return [Integer]
def max_top_up_amount
130
end
+ # The maximum number of credit card declines allowed for a Customer user
+ # before further transactions are blocked.
+ # @return [Integer]
def max_declines
2
end
@@ -212,6 +249,11 @@ module TrustLevel
messages_today < 500
end
+ # Validates a credit card transaction for a Customer trust level user.
+ # @param amount [BigDecimal] The amount of the transaction.
+ # @param declines [Integer] The number of recent declines for the customer.
+ # @raise [DeclinedError] if the number of declines exceeds `max_declines`.
+ # @raise [AmountTooHighError] if the transaction amount exceeds `max_top_up_amount`.
def validate_credit_card_transaction!(amount, declines)
raise DeclinedError.new(declines, max_declines) if declines > max_declines
return unless amount > max_top_up_amount