app/services/action_queue.rb
# frozen_string_literal: true
require 'active_support/concern'
module ActionQueue
module Enqueable
extend ActiveSupport::Concern
def initialize(action, mailing_id)
@action = action
@mailing_id = mailing_id
end
def push
ChampaignQueue.push(payload.merge(meta), group_id: "action:#{@action.id}")
end
def page
@page ||= @action.page
end
def data
@data ||= @action.form_data.symbolize_keys
end
def country(iso_code)
(ISO3166::Country.search(iso_code).try(:translations) || {})['en']
end
def member
@member ||= @action.member
end
def meta
{
meta: {
title: page.title,
uri: "/a/#{page.slug}",
slug: page.slug,
first_name: member.first_name,
last_name: member.last_name,
member_id: member.id,
created_at: @action.created_at,
country: country(member.country),
action_id: @action.id,
subscribed_member: @action.subscribed_member
}
}
end
def currency
data[:currency].try(:upcase)
end
class_methods do
def push(action, mailing_id)
new(action, mailing_id).push
end
end
end
module Donatable
def user_data
data.select { |k, v| v.present? && ActionKitFields.is_predefined_by_ak(k) }.merge(
first_name: member.first_name,
last_name: member.last_name,
email: member.email,
country: country(member.country),
akid: data[:akid],
source: data[:source],
user_express_cookie: data[:store_in_vault] ? 1 : 0,
user_express_account: data[:express_account] ? 1 : 0
).merge(UserLanguageISO.for(page.language))
end
def action_fields
@action_fields ||= {}.tap do |fields|
data.keys.select { |k| k =~ /^action_/ }.each do |key|
fields[key] = data[key]
end
fields[:action_bucket] = data[:bucket] if data.key? :bucket
end
end
end
class Pusher
def self.push(event, action, mailing_id)
case event
when :new_action
if action.donation
if action.form_data.fetch('payment_provider', '').inquiry.go_cardless?
NewDirectDebitAction.push(action, mailing_id)
else
NewDonationAction.push(action, mailing_id)
end
else
NewPetitionAction.push(action, mailing_id)
end
when :new_survey_response
NewSurveyResponse.push(action, mailing_id)
end
end
end
class NewPetitionAction
include Donatable
include Enqueable
def get_page_name
if page.status.inquiry.imported?
page.slug
else
"#{page.ak_uid}-petition"
end
end
def payload
{
type: 'action',
params: {
page: get_page_name,
email: @action.member.email,
mailing_id: @mailing_id
}.merge(@action.form_data)
.merge(UserLanguageISO.for(page.language))
.tap do |params|
params[:country] = country(member.country) if member.country.present?
params[:action_bucket] = data[:bucket] if data.key? :bucket
end
}.deep_symbolize_keys
end
end
class NewSurveyResponse < NewPetitionAction
def payload
super.tap do |p|
p[:type] = 'new_survey_response'
end
end
end
class NewDirectDebitAction
include Enqueable
include Donatable
def payload
# TODO: This really needs to be handled in a less hackish solution once we refactor.
@action.form_data[:action_express_donation] = 0
if data[:is_subscription]
subscription_payload
else
transaction_payload
end
end
def subscription_payload
{
type: 'donation',
payment_provider: 'go_cardless',
params: {
donationpage: {
name: "#{@action.page.ak_uid}-donation",
payment_account: get_payment_account
},
order: {
amount: data[:amount],
currency: currency,
recurring_id: data[:subscription_id]
}.merge(fake_card_info),
action: action_data,
user: user_data,
referring_akid: @action.form_data['referring_akid'],
mailing_id: @mailing_id
}
}
end
def transaction_payload
{
type: 'donation',
payment_provider: 'go_cardless',
params: {
donationpage: {
name: "#{@action.page.ak_uid}-donation",
payment_account: get_payment_account
},
order: {
amount: data[:amount],
currency: currency,
trans_id: data[:transaction_id]
}.merge(fake_card_info),
action: action_data,
user: user_data,
referring_akid: @action.form_data['referring_akid'],
mailing_id: @mailing_id
}
}
end
def action_data
{
fields: action_fields.merge(
action_account_number_ending: data[:account_number_ending],
action_mandate_reference: data[:mandate_reference],
action_bank_name: data[:bank_name],
action_express_donation: data[:express_donation] ? 1 : 0,
payment_gateway_status: 'pending'
),
source: data[:source]
}
end
def fake_card_info
{
card_num: 'DDEB',
card_code: '007',
exp_date_month: '01',
exp_date_year: '99'
}
end
def get_payment_account
"GoCardless #{currency}"
end
def user_data
super.except(:user_express_cookie, :user_express_account)
end
end
class NewDonationAction
include Enqueable
include Donatable
def payload
if data[:is_subscription]
subscription_payload
else
transaction_payload
end
end
def subscription_payload
{
type: 'donation',
payment_provider: 'braintree',
params: {
donationpage: {
name: "#{@action.page.ak_uid}-donation",
payment_account: get_payment_account
},
order: {
amount: data[:amount],
card_num: data[:card_num],
card_code: '007',
exp_date_month: expire_month,
exp_date_year: expire_year,
currency: currency,
recurring_id: data[:subscription_id],
trans_id: data[:transaction_id]
},
action: {
source: data[:source],
fields: action_fields
},
user: user_data,
referring_akid: @action.form_data['referring_akid']
}
}
end
def transaction_payload
{
type: 'donation',
payment_provider: 'braintree',
params: {
donationpage: {
name: "#{@action.page.ak_uid}-donation",
payment_account: get_payment_account
},
order: {
amount: data[:amount],
card_num: data[:card_num],
card_code: '007',
exp_date_month: expire_month,
exp_date_year: expire_year,
currency: currency,
trans_id: data[:transaction_id]
},
action: {
source: data[:source],
fields: action_fields
},
user: user_data,
referring_akid: @action.form_data['referring_akid']
}
}
end
# ActionKit can accept one of the following:
#
# PayPal USD
# PayPal GBP
# PayPal CAD
# PayPal EUR
# PayPal AUD
#
# Braintree USD
# Braintree CAD
# Braintree AUD
# Braintree GBP
# Braintree EUR
#
def get_payment_account
provider = is_paypal? ? 'PayPal' : 'Braintree'
"#{provider} #{currency}"
end
def is_paypal?
data[:card_num] == 'PYPL'
end
def expire_month
split_expire_date[0]
end
def expire_year
split_expire_date[1]
end
def split_expire_date
if data[:card_expiration_date] == '/' || data[:card_expiration_date].blank?
# We weren't given an expiration, probably because it's a PayPal transaction, so set a fake expiration five years
# in the future.
[Time.now.month.to_s, (Time.now.year + 5).to_s]
else
@split_date ||= data[:card_expiration_date].split('/')
end
end
end
end