summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAlessandro Desantis <desa.alessandro@gmail.com>2020-10-10 10:16:37 +0200
committerGitHub <noreply@github.com>2020-10-10 10:16:37 +0200
commit6b5c54f6998ed9ebe99e9c047e077cffdd7827b6 (patch)
tree018fd3c502ee833e625fd659170fe3d1e0aa35d4 /lib
parentceb0b5a3c7d21213afdf75e496db98ae51640098 (diff)
parent5b1795151eb52ec8c5097f3ad58db055d9acb1bb (diff)
Merge pull request #152 from solidusio-contrib/aldesantis/churn-buster
Integrate Churn Buster
Diffstat (limited to 'lib')
-rw-r--r--lib/generators/solidus_subscriptions/install/templates/initializer.rb14
-rw-r--r--lib/solidus_subscriptions.rb16
-rw-r--r--lib/solidus_subscriptions/churn_buster/client.rb48
-rw-r--r--lib/solidus_subscriptions/churn_buster/order_serializer.rb19
-rw-r--r--lib/solidus_subscriptions/churn_buster/serializer.rb23
-rw-r--r--lib/solidus_subscriptions/churn_buster/subscription_customer_serializer.rb19
-rw-r--r--lib/solidus_subscriptions/churn_buster/subscription_payment_method_serializer.rb37
-rw-r--r--lib/solidus_subscriptions/churn_buster/subscription_serializer.rb17
-rw-r--r--lib/solidus_subscriptions/configuration.rb8
9 files changed, 200 insertions, 1 deletions
diff --git a/lib/generators/solidus_subscriptions/install/templates/initializer.rb b/lib/generators/solidus_subscriptions/install/templates/initializer.rb
index 17a6f51..e1e9731 100644
--- a/lib/generators/solidus_subscriptions/install/templates/initializer.rb
+++ b/lib/generators/solidus_subscriptions/install/templates/initializer.rb
@@ -64,4 +64,18 @@ SolidusSubscriptions.configure do |config|
# :interval_units,
# :end_date,
# ]
+
+ # ========================================= Churn Buster =========================================
+ #
+ # This extension can integrate with Churn Buster for churn mitigation and failed payment recovery.
+ # If you want to integrate with Churn Buster, simply configure your credentials below.
+ #
+ # NOTE: If you integrate with Churn Buster and override any of the handlers, make sure to call
+ # `super` or copy-paste the original integration code or things won't work!
+
+ # Your Churn Buster account ID.
+ # config.churn_buster_account_id = 'YOUR_CHURN_BUSTER_ACCOUNT_ID'
+
+ # Your Churn Buster API key.
+ # config.churn_buster_api_key = 'YOUR_CHURN_BUSTER_API_KEY'
end
diff --git a/lib/solidus_subscriptions.rb b/lib/solidus_subscriptions.rb
index 039b172..e9dae93 100644
--- a/lib/solidus_subscriptions.rb
+++ b/lib/solidus_subscriptions.rb
@@ -4,6 +4,7 @@ require 'solidus_core'
require 'solidus_support'
require 'deface'
+require 'httparty'
require 'state_machines'
require 'solidus_subscriptions/configuration'
@@ -11,6 +12,12 @@ require 'solidus_subscriptions/permission_sets/default_customer'
require 'solidus_subscriptions/permission_sets/subscription_management'
require 'solidus_subscriptions/version'
require 'solidus_subscriptions/engine'
+require 'solidus_subscriptions/churn_buster/client'
+require 'solidus_subscriptions/churn_buster/serializer'
+require 'solidus_subscriptions/churn_buster/subscription_customer_serializer'
+require 'solidus_subscriptions/churn_buster/subscription_payment_method_serializer'
+require 'solidus_subscriptions/churn_buster/subscription_serializer'
+require 'solidus_subscriptions/churn_buster/order_serializer'
module SolidusSubscriptions
class << self
@@ -21,5 +28,14 @@ module SolidusSubscriptions
def configuration
@configuration ||= Configuration.new
end
+
+ def churn_buster
+ return unless configuration.churn_buster?
+
+ @churn_buster ||= ChurnBuster::Client.new(
+ account_id: SolidusSubscriptions.configuration.churn_buster_account_id,
+ api_key: SolidusSubscriptions.configuration.churn_buster_api_key,
+ )
+ end
end
end
diff --git a/lib/solidus_subscriptions/churn_buster/client.rb b/lib/solidus_subscriptions/churn_buster/client.rb
new file mode 100644
index 0000000..915bb40
--- /dev/null
+++ b/lib/solidus_subscriptions/churn_buster/client.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+module SolidusSubscriptions
+ module ChurnBuster
+ class Client
+ BASE_API_URL = 'https://api.churnbuster.io/v1'
+
+ attr_reader :account_id, :api_key
+
+ def initialize(account_id:, api_key:)
+ @account_id = account_id
+ @api_key = api_key
+ end
+
+ def report_failed_payment(order)
+ post('/failed_payments', OrderSerializer.serialize(order))
+ end
+
+ def report_successful_payment(order)
+ post('/successful_payments', OrderSerializer.serialize(order))
+ end
+
+ def report_subscription_cancellation(subscription)
+ post('/cancellations', SubscriptionSerializer.serialize(subscription))
+ end
+
+ def report_payment_method_change(subscription)
+ post('/payment_methods', SubscriptionPaymentMethodSerializer.serialize(subscription))
+ end
+
+ private
+
+ def post(path, body)
+ HTTParty.post(
+ "#{BASE_API_URL}#{path}",
+ body: body.to_json,
+ headers: {
+ 'Content-Type' => 'application/json',
+ },
+ basic_auth: {
+ username: account_id,
+ password: api_key,
+ },
+ )
+ end
+ end
+ end
+end
diff --git a/lib/solidus_subscriptions/churn_buster/order_serializer.rb b/lib/solidus_subscriptions/churn_buster/order_serializer.rb
new file mode 100644
index 0000000..5bc5dee
--- /dev/null
+++ b/lib/solidus_subscriptions/churn_buster/order_serializer.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module SolidusSubscriptions
+ module ChurnBuster
+ class OrderSerializer < Serializer
+ def to_h
+ {
+ payment: {
+ source: 'in_house',
+ source_id: object.number,
+ amount_in_cents: object.display_total.cents,
+ currency: object.currency,
+ },
+ customer: SubscriptionCustomerSerializer.serialize(object.subscription),
+ }
+ end
+ end
+ end
+end
diff --git a/lib/solidus_subscriptions/churn_buster/serializer.rb b/lib/solidus_subscriptions/churn_buster/serializer.rb
new file mode 100644
index 0000000..d8b83bb
--- /dev/null
+++ b/lib/solidus_subscriptions/churn_buster/serializer.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+module SolidusSubscriptions
+ module ChurnBuster
+ class Serializer
+ attr_reader :object
+
+ class << self
+ def serialize(object)
+ new(object).to_h
+ end
+ end
+
+ def initialize(object)
+ @object = object
+ end
+
+ def to_h
+ raise NotImplementedError
+ end
+ end
+ end
+end
diff --git a/lib/solidus_subscriptions/churn_buster/subscription_customer_serializer.rb b/lib/solidus_subscriptions/churn_buster/subscription_customer_serializer.rb
new file mode 100644
index 0000000..700c1c6
--- /dev/null
+++ b/lib/solidus_subscriptions/churn_buster/subscription_customer_serializer.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module SolidusSubscriptions
+ module ChurnBuster
+ class SubscriptionCustomerSerializer < Serializer
+ def to_h
+ {
+ source: 'in_house',
+ source_id: object.id,
+ email: object.user.email,
+ properties: {
+ first_name: object.shipping_address_to_use.firstname,
+ last_name: object.shipping_address_to_use.lastname,
+ },
+ }
+ end
+ end
+ end
+end
diff --git a/lib/solidus_subscriptions/churn_buster/subscription_payment_method_serializer.rb b/lib/solidus_subscriptions/churn_buster/subscription_payment_method_serializer.rb
new file mode 100644
index 0000000..984059d
--- /dev/null
+++ b/lib/solidus_subscriptions/churn_buster/subscription_payment_method_serializer.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module SolidusSubscriptions
+ module ChurnBuster
+ class SubscriptionPaymentMethodSerializer < Serializer
+ def to_h
+ {
+ payment_method: {
+ source: 'in_house',
+ source_id: [
+ object.payment_method_to_use&.id,
+ object.payment_source_to_use&.id
+ ].compact.join('-'),
+ type: 'card',
+ properties: payment_source_properties,
+ },
+ customer: SubscriptionCustomerSerializer.serialize(object),
+ }
+ end
+
+ private
+
+ def payment_source_properties
+ if object.payment_source.is_a?(::Spree::CreditCard)
+ {
+ brand: object.payment_source.cc_type,
+ last4: object.payment_source.last_digits,
+ exp_month: object.payment_source.month,
+ exp_year: object.payment_source.year,
+ }
+ else
+ {}
+ end
+ end
+ end
+ end
+end
diff --git a/lib/solidus_subscriptions/churn_buster/subscription_serializer.rb b/lib/solidus_subscriptions/churn_buster/subscription_serializer.rb
new file mode 100644
index 0000000..06c08d1
--- /dev/null
+++ b/lib/solidus_subscriptions/churn_buster/subscription_serializer.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module SolidusSubscriptions
+ module ChurnBuster
+ class SubscriptionSerializer < Serializer
+ def to_h
+ {
+ subscription: {
+ source: 'in_house',
+ source_id: object.id
+ },
+ customer: SubscriptionCustomerSerializer.serialize(object),
+ }
+ end
+ end
+ end
+end
diff --git a/lib/solidus_subscriptions/configuration.rb b/lib/solidus_subscriptions/configuration.rb
index d5dc80f..22b7d84 100644
--- a/lib/solidus_subscriptions/configuration.rb
+++ b/lib/solidus_subscriptions/configuration.rb
@@ -2,7 +2,9 @@
module SolidusSubscriptions
class Configuration
- attr_accessor :maximum_total_skips
+ attr_accessor(
+ :maximum_total_skips, :churn_buster_account_id, :churn_buster_api_key,
+ )
attr_writer(
:success_dispatcher_class, :failure_dispatcher_class, :payment_failed_dispatcher_class,
@@ -73,5 +75,9 @@ module SolidusSubscriptions
@subscribable_class ||= 'Spree::Variant'
@subscribable_class.constantize
end
+
+ def churn_buster?
+ churn_buster_account_id.present? && churn_buster_api_key.present?
+ end
end
end