Class: UsageCredits::Transaction

Inherits:
ApplicationRecord show all
Defined in:
lib/usage_credits/models/transaction.rb

Overview

Records all credit changes in a wallet (additions, deductions, expirations).

Each transaction represents a single credit operation and includes:

- amount: How many credits (positive for additions, negative for deductions)
- category: What kind of operation (subscription fulfillment, pack purchase, etc)
- metadata: Additional details about the operation
- expires_at: When these credits expire (optional)

Constant Summary collapse

CATEGORIES =

All possible transaction types, grouped by purpose:

[
  # Bonus credits
  "signup_bonus",                   # Initial signup bonus
  "referral_bonus",                 # Referral reward bonus
  "bonus",                          # Generic bonus

  # Subscription-related
  "subscription_credits",           # Generic subscription credits
  "subscription_trial",             # Trial period credits
  "subscription_signup_bonus",      # Bonus for subscribing

  # One-time purchases
  "credit_pack",                    # Generic credit pack
  "credit_pack_purchase",           # Credit pack bought
  "credit_pack_refund",             # Credit pack refunded

  # Credit usage & management
  "operation_charge",               # Credits spent on operation
  "manual_adjustment",              # Manual admin adjustment
  "credit_added",                   # Generic addition
  "credit_deducted"                 # Generic deduction
].freeze

Instance Method Summary collapse

Instance Method Details

#allocated_amountObject

How many credits from this transaction have already been allocated (spent)? Only applies if this transaction is positive.



107
108
109
# File 'lib/usage_credits/models/transaction.rb', line 107

def allocated_amount
  incoming_allocations.sum(:amount)
end

#credit?Boolean

Is this transaction a positive credit or a negative (spend)?

Returns:

  • (Boolean)


97
98
99
# File 'lib/usage_credits/models/transaction.rb', line 97

def credit?
  amount > 0
end

#debit?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'lib/usage_credits/models/transaction.rb', line 101

def debit?
  amount < 0
end

#descriptionObject

Get a human-readable description of what this transaction represents



129
130
131
132
133
134
135
136
137
138
# File 'lib/usage_credits/models/transaction.rb', line 129

def description
  # Custom description takes precedence
  return self[:description] if self[:description].present?

  # Operation charges have dynamic descriptions
  return operation_description if category == "operation_charge"

  # Use predefined description or fallback to titleized category
  category.titleize
end

#expired?Boolean

Have these credits expired?

Returns:

  • (Boolean)


92
93
94
# File 'lib/usage_credits/models/transaction.rb', line 92

def expired?
  expires_at.present? && expires_at < Time.current
end

#formatted_amountObject

Format the amount for display (e.g., “+100 credits” or “-10 credits”)



123
124
125
126
# File 'lib/usage_credits/models/transaction.rb', line 123

def formatted_amount
  prefix = amount.positive? ? "+" : ""
  "#{prefix}#{UsageCredits.configuration.credit_formatter.call(amount)}"
end

#metadataObject

Get metadata with indifferent access (string/symbol keys)



145
146
147
# File 'lib/usage_credits/models/transaction.rb', line 145

def 
   ||= ActiveSupport::HashWithIndifferentAccess.new(super || {})
end

#metadata=(hash) ⇒ Object

Set metadata, ensuring consistent storage format



150
151
152
153
# File 'lib/usage_credits/models/transaction.rb', line 150

def metadata=(hash)
   = nil  # Clear cache
  super(hash.is_a?(Hash) ? hash.to_h : {})
end

#ownerObject

Get the owner of the wallet these credits belong to



87
88
89
# File 'lib/usage_credits/models/transaction.rb', line 87

def owner
  wallet.owner
end

#remaining_amountObject

How many credits remain unused in this positive transaction? If negative, this will effectively be 0.



113
114
115
116
# File 'lib/usage_credits/models/transaction.rb', line 113

def remaining_amount
  return 0 unless credit?
  amount - allocated_amount
end