Created
January 16, 2022 09:59
-
-
Save nightcrawler-/97cac5dc0241dcd70ac5266594bef9c3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
# == Schema Information | |
# | |
# Table name: contributions | |
# | |
# id :bigint not null, primary key | |
# aasm_state :string | |
# amount :integer default(0) | |
# error_message :string | |
# message :text | |
# mpesa_fees :decimal(, ) default(0.0) | |
# phone_number :string | |
# platform_fees :decimal(, ) default(0.0) | |
# source :string | |
# created_at :datetime not null | |
# updated_at :datetime not null | |
# campaign_id :bigint | |
# contributor_id :bigint | |
# | |
class Contribution < ApplicationRecord | |
include AASM | |
include PhoneNumberSanitizer | |
scope :completed, -> { where(aasm_state: :completed) } | |
FIXED_PLATFORM_FEES_RATE = 0.05 | |
#################### Enums ############################## | |
#################### Associations ####################### | |
belongs_to :campaign | |
belongs_to :contributor, class_name: :User | |
has_one :payment_online_payment_request, class_name: 'Payment::OnlinePaymentRequest' | |
has_one :payment_paybill_confirmation, class_name: 'Payment::PaybillConfirmation' | |
#################### Validations ######################## | |
validates :amount, :source, presence: true | |
validates :amount, numericality: { greater_than_or_equal_to: 1, only_integer: true } | |
validates :phone_number, telephone_number: { country: proc { |_record| 'KE' }, types: %i[fixed_line mobile] } | |
#################### Callbacks ########################## | |
after_create :process_contribution | |
#################### AASM State Machine ######################### | |
aasm do | |
state :pending, initial: true | |
state :processing | |
state :completed | |
state :failed | |
event :process, after: :send_payment_request do | |
transitions from: :pending, to: :processing | |
end | |
event :complete, after: :send_notifications do # Sending notifications after transition and charges applied, resource saved. | |
transitions from: :processing, to: :completed, after: :apply_charges # Apply charges doesnt need to call save, it will be done after this transition before persisting the state | |
end | |
event :failure do | |
transitions from: :processing, to: :failed, after: proc { |args| apply_failure_reason(args) } | |
end | |
after_all_transitions :log_status_change | |
end | |
#################### Object methods### ################## | |
# AASM Callbacks | |
def apply_charges | |
rate = CalistoDefault.first&.platform_fees_rate | |
rate ||= FIXED_PLATFORM_FEES_RATE | |
self.platform_fees = amount * rate | |
self.mpesa_fees = MpesaCharge.new(amount, campaign.fees_regime).call | |
self | |
end | |
def send_notifications | |
puts 'Sending contribution complete notifications' | |
UserMailer.send_donation_processed(self).deliver_later | |
UserMailer.send_donation_received(self).deliver_later | |
end | |
# dont forget to call comlete on the contribution! | |
def self.from_paybill_confirmation(params) | |
# Only create if corresponding campaign exists | |
# Create user from phone number | |
# Apply campaign and user to contribution | |
# Will include user name | |
campaign = Campaign.find_by(account_number: params['bill_ref_number']) | |
if campaign.present? | |
user = User.from_phone_number({ phone_number: params['msisdn'], name: "#{params['first_name']} #{params['middle_name']} #{params['last_name']}" }) | |
contribution = Contribution.create!( | |
campaign: campaign, | |
contributor: user, | |
phone_number: params['msisdn'], | |
amount: params['trans_amount'].to_i, | |
source: 'mpesa-paybill', | |
aasm_state: 'processing' # Doing this so that on save doesnt trigger a callback to request online payment | |
) | |
contribution.complete! | |
contribution | |
end | |
end | |
private | |
def process_contribution | |
ContributionWorker.perform_async({ phone: phone_number, amount: amount, id: id }) | |
end | |
######################### AASM State change callbacks ################# | |
def apply_failure_reason(message) | |
puts "That failed: #{message}" | |
self.error_message = message | |
save | |
end | |
def send_payment_request | |
# Guess this is where the online payment happens? ama? | |
puts "Sending payment request...#{inspect}" | |
end | |
def log_status_change | |
puts "Changed from #{aasm.from_state} to #{aasm.to_state} (event: #{aasm.current_event})" | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment