payola-payments 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/payola/checkout_button.js +9 -9
- data/app/assets/javascripts/payola/form.js +6 -6
- data/app/assets/javascripts/payola/subscription_form.js +6 -6
- data/app/controllers/concerns/payola/affiliate_behavior.rb +17 -0
- data/app/controllers/concerns/payola/async_behavior.rb +36 -0
- data/app/controllers/payola/subscriptions_controller.rb +31 -46
- data/app/controllers/payola/transactions_controller.rb +16 -32
- data/app/mailers/payola/admin_mailer.rb +7 -15
- data/app/mailers/payola/receipt_mailer.rb +2 -0
- data/app/models/concerns/payola/guid_behavior.rb +20 -0
- data/app/models/concerns/payola/plan.rb +0 -1
- data/app/models/payola/sale.rb +6 -12
- data/app/models/payola/subscription.rb +9 -12
- data/app/services/payola/charge_card.rb +42 -33
- data/app/services/payola/create_plan.rb +2 -2
- data/app/services/payola/invoice_behavior.rb +55 -0
- data/app/services/payola/invoice_failed.rb +4 -29
- data/app/services/payola/invoice_paid.rb +4 -31
- data/lib/payola.rb +13 -11
- data/lib/payola/version.rb +1 -1
- data/spec/concerns/plan_spec.rb +0 -5
- data/spec/controllers/payola/subscriptions_controller_spec.rb +10 -1
- data/spec/controllers/payola/transactions_controller_spec.rb +10 -1
- data/spec/dummy/app/models/subscription_plan_without_interval_count.rb +3 -0
- data/spec/dummy/config/environments/test.rb +2 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20141120170744_create_subscription_plan_without_interval_counts.rb +12 -0
- data/spec/dummy/db/schema.rb +10 -1
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +222 -0
- data/spec/dummy/log/test.log +15830 -141203
- data/spec/factories/subscription_plan.rb +7 -0
- data/spec/mailers/payola/admin_mailer_spec.rb +35 -0
- data/spec/mailers/payola/receipt_mailer_spec.rb +52 -0
- data/spec/models/payola/subscription_spec.rb +21 -0
- data/spec/payola_spec.rb +6 -2
- data/spec/services/payola/create_plan_spec.rb +9 -0
- data/spec/services/payola/process_sale_spec.rb +15 -0
- data/spec/services/payola/process_subscription_spec.rb +15 -0
- data/spec/services/payola/send_mail_spec.rb +25 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/worker_spec.rb +55 -0
- metadata +40 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c4d4f9f5bd8ecf269a31f484690a7fdd910e39d
|
4
|
+
data.tar.gz: 4caf45459de1c9d0913cd6c025d86cf96ea805aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14920d40f2f7d4ebaeadfc6e34c75dea86a277eecf3d2f0e44f6e85e2106a0ef16e63f90b32fb2adec4099137572950f2a64e2882259e01d3ac0898b49e61118
|
7
|
+
data.tar.gz: 598088dfc2c1a12c955e801522ff2ec8c21c04846971df7f399635b5eee9f1e14ac9b32f5d5d570993975269fe8accfe57977555763ea39608aa517d780e6a23
|
@@ -7,13 +7,13 @@ var PayolaCheckout = {
|
|
7
7
|
},
|
8
8
|
|
9
9
|
handleCheckoutButtonClick: function(button) {
|
10
|
-
form = button.parent('form');
|
11
|
-
options = form.data();
|
10
|
+
var form = button.parent('form');
|
11
|
+
var options = form.data();
|
12
12
|
|
13
13
|
var handler = StripeCheckout.configure({
|
14
14
|
key: options.publishable_key,
|
15
15
|
image: options.product_image_path,
|
16
|
-
token: function(token) { PayolaCheckout.tokenHandler(token, options) },
|
16
|
+
token: function(token) { PayolaCheckout.tokenHandler(token, options); },
|
17
17
|
name: options.name,
|
18
18
|
description: options.description,
|
19
19
|
amount: options.price,
|
@@ -45,8 +45,8 @@ var PayolaCheckout = {
|
|
45
45
|
type: "POST",
|
46
46
|
url: options.base_path + "/buy/" + options.product_class + "/" + options.product_permalink,
|
47
47
|
data: form.serialize(),
|
48
|
-
success: function(data) { PayolaCheckout.poll(data.guid, 60, options) },
|
49
|
-
error: function(data) { PayolaCheckout.showError(data.responseJSON.error, options) }
|
48
|
+
success: function(data) { PayolaCheckout.poll(data.guid, 60, options); },
|
49
|
+
error: function(data) { PayolaCheckout.showError(data.responseJSON.error, options); }
|
50
50
|
});
|
51
51
|
},
|
52
52
|
|
@@ -60,7 +60,7 @@ var PayolaCheckout = {
|
|
60
60
|
},
|
61
61
|
|
62
62
|
poll: function(guid, num_retries_left, options) {
|
63
|
-
if (num_retries_left
|
63
|
+
if (num_retries_left === 0) {
|
64
64
|
PayolaCheckout.showError("This seems to be taking too long. Please contact support and give them transaction ID: " + guid, options);
|
65
65
|
return;
|
66
66
|
}
|
@@ -71,9 +71,9 @@ var PayolaCheckout = {
|
|
71
71
|
} else if (data.status === "errored") {
|
72
72
|
PayolaCheckout.showError(data.error, options);
|
73
73
|
} else {
|
74
|
-
setTimeout(function() { PayolaCheckout.poll(guid, num_retries_left - 1, options) }, 500);
|
74
|
+
setTimeout(function() { PayolaCheckout.poll(guid, num_retries_left - 1, options); }, 500);
|
75
75
|
}
|
76
76
|
});
|
77
77
|
}
|
78
|
-
}
|
79
|
-
PayolaCheckout.initialize();
|
78
|
+
};
|
79
|
+
$(function() { PayolaCheckout.initialize(); });
|
@@ -34,15 +34,15 @@ var PayolaPaymentForm = {
|
|
34
34
|
type: "POST",
|
35
35
|
url: base_path + "/buy/" + product + "/" + permalink,
|
36
36
|
data: data_form.serialize(),
|
37
|
-
success: function(data) { PayolaPaymentForm.poll(form, 60, data.guid, base_path) },
|
38
|
-
error: function(data) { PayolaPaymentForm.showError(form, data.responseJSON.error) }
|
37
|
+
success: function(data) { PayolaPaymentForm.poll(form, 60, data.guid, base_path); },
|
38
|
+
error: function(data) { PayolaPaymentForm.showError(form, data.responseJSON.error); }
|
39
39
|
});
|
40
40
|
}
|
41
41
|
},
|
42
42
|
|
43
43
|
poll: function(form, num_retries_left, guid, base_path) {
|
44
|
-
if (num_retries_left
|
45
|
-
PayolaPaymentForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid)
|
44
|
+
if (num_retries_left === 0) {
|
45
|
+
PayolaPaymentForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid);
|
46
46
|
}
|
47
47
|
$.get(base_path + '/status/' + guid, function(data) {
|
48
48
|
if (data.status === "finished") {
|
@@ -52,7 +52,7 @@ var PayolaPaymentForm = {
|
|
52
52
|
} else if (data.status === "errored") {
|
53
53
|
PayolaPaymentForm.showError(form, data.error);
|
54
54
|
} else {
|
55
|
-
setTimeout(function() { PayolaPaymentForm.poll(form, num_retries_left - 1, guid, base_path) }, 500);
|
55
|
+
setTimeout(function() { PayolaPaymentForm.poll(form, num_retries_left - 1, guid, base_path); }, 500);
|
56
56
|
}
|
57
57
|
});
|
58
58
|
},
|
@@ -68,4 +68,4 @@ var PayolaPaymentForm = {
|
|
68
68
|
}
|
69
69
|
};
|
70
70
|
|
71
|
-
$(function() { PayolaPaymentForm.initialize() } );
|
71
|
+
$(function() { PayolaPaymentForm.initialize(); } );
|
@@ -35,15 +35,15 @@ var PayolaSubscriptionForm = {
|
|
35
35
|
type: "POST",
|
36
36
|
url: base_path + "/subscribe/" + plan_type + "/" + plan_id,
|
37
37
|
data: data_form.serialize(),
|
38
|
-
success: function(data) { PayolaSubscriptionForm.poll(form, 60, data.guid, base_path) },
|
39
|
-
error: function(data) { PayolaSubscriptionForm.showError(form, data.responseJSON.error) }
|
38
|
+
success: function(data) { PayolaSubscriptionForm.poll(form, 60, data.guid, base_path); },
|
39
|
+
error: function(data) { PayolaSubscriptionForm.showError(form, data.responseJSON.error); }
|
40
40
|
});
|
41
41
|
}
|
42
42
|
},
|
43
43
|
|
44
44
|
poll: function(form, num_retries_left, guid, base_path) {
|
45
|
-
if (num_retries_left
|
46
|
-
PayolaSubscriptionForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid)
|
45
|
+
if (num_retries_left === 0) {
|
46
|
+
PayolaSubscriptionForm.showError(form, "This seems to be taking too long. Please contact support and give them transaction ID: " + guid);
|
47
47
|
}
|
48
48
|
$.get(base_path + '/subscription_status/' + guid, function(data) {
|
49
49
|
if (data.status === "active") {
|
@@ -53,7 +53,7 @@ var PayolaSubscriptionForm = {
|
|
53
53
|
} else if (data.status === "errored") {
|
54
54
|
PayolaSubscriptionForm.showError(form, data.error);
|
55
55
|
} else {
|
56
|
-
setTimeout(function() { PayolaSubscriptionForm.poll(form, num_retries_left - 1, guid, base_path) }, 500);
|
56
|
+
setTimeout(function() { PayolaSubscriptionForm.poll(form, num_retries_left - 1, guid, base_path); }, 500);
|
57
57
|
}
|
58
58
|
});
|
59
59
|
},
|
@@ -71,4 +71,4 @@ var PayolaSubscriptionForm = {
|
|
71
71
|
}
|
72
72
|
};
|
73
73
|
|
74
|
-
$(function() { PayolaSubscriptionForm.initialize() } );
|
74
|
+
$(function() { PayolaSubscriptionForm.initialize(); } );
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Payola
|
2
|
+
module AffiliateBehavior
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_filter :find_affiliate
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_affiliate
|
10
|
+
affiliate_code = cookies[:aff] || params[:aff]
|
11
|
+
@affiliate = Affiliate.where('lower(code) = lower(?)', affiliate_code).first
|
12
|
+
if @affiliate
|
13
|
+
cookies[:aff] = affiliate_code
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Payola
|
2
|
+
module AsyncBehavior
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def show_object(object_class)
|
6
|
+
object = object_class.find_by!(guid: params[:guid])
|
7
|
+
redirector = object.redirector
|
8
|
+
|
9
|
+
new_path = redirector.respond_to?(:redirect_path) ? redirector.redirect_path(object) : '/'
|
10
|
+
redirect_to new_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def object_status(object_class)
|
14
|
+
object = object_class.find_by(guid: params[:guid])
|
15
|
+
render nothing: true, status: 404 and return unless object
|
16
|
+
render json: {guid: object.guid, status: object.state, error: object.error}
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_object(object_class, object_creator_class, object_processor_class, product_key, product)
|
20
|
+
create_params = params.permit!.merge(
|
21
|
+
product_key => product,
|
22
|
+
coupon: @coupon,
|
23
|
+
affiliate: @affiliate
|
24
|
+
)
|
25
|
+
|
26
|
+
object = object_creator_class.call(create_params)
|
27
|
+
|
28
|
+
if object.save
|
29
|
+
Payola.queue!(object_processor_class, object.guid)
|
30
|
+
render json: { guid: object.guid }
|
31
|
+
else
|
32
|
+
render json: { error: object.errors.full_messages.join(". ") }, status: 400
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,37 +1,21 @@
|
|
1
1
|
module Payola
|
2
2
|
class SubscriptionsController < ApplicationController
|
3
|
-
|
3
|
+
include Payola::AffiliateBehavior
|
4
|
+
include Payola::AsyncBehavior
|
5
|
+
|
6
|
+
before_filter :find_plan_and_coupon, only: [:create, :change_plan]
|
4
7
|
before_filter :check_modify_permissions, only: [:destroy, :change_plan, :update_card]
|
5
8
|
|
6
9
|
def show
|
7
|
-
|
8
|
-
plan = subscription.plan
|
9
|
-
|
10
|
-
new_path = plan.respond_to?(:redirect_path) ? plan.redirect_path(subscription) : '/'
|
11
|
-
redirect_to new_path
|
10
|
+
show_object(Subscription)
|
12
11
|
end
|
13
12
|
|
14
13
|
def status
|
15
|
-
|
16
|
-
render nothing: true, status: 404 and return unless @subscription
|
17
|
-
render json: {guid: @subscription.guid, status: @subscription.state, error: @subscription.error}
|
14
|
+
object_status(Subscription)
|
18
15
|
end
|
19
16
|
|
20
17
|
def create
|
21
|
-
|
22
|
-
plan: @plan,
|
23
|
-
coupon: @coupon,
|
24
|
-
affiliate: @affiliate
|
25
|
-
)
|
26
|
-
|
27
|
-
@subscription = CreateSubscription.call(create_params)
|
28
|
-
|
29
|
-
if @subscription.save
|
30
|
-
Payola.queue!(Payola::ProcessSubscription, @subscription.guid)
|
31
|
-
render json: { guid: @subscription.guid }
|
32
|
-
else
|
33
|
-
render json: { error: @subscription.errors.full_messages.join(". ") }, status: 400
|
34
|
-
end
|
18
|
+
create_object(Subscription, CreateSubscription, ProcessSubscription, :plan, @plan)
|
35
19
|
end
|
36
20
|
|
37
21
|
def destroy
|
@@ -41,44 +25,36 @@ module Payola
|
|
41
25
|
end
|
42
26
|
|
43
27
|
def change_plan
|
44
|
-
subscription = Subscription.find_by!(guid: params[:guid])
|
45
|
-
Payola::ChangeSubscriptionPlan.call(subscription, @plan)
|
28
|
+
@subscription = Subscription.find_by!(guid: params[:guid])
|
29
|
+
Payola::ChangeSubscriptionPlan.call(@subscription, @plan)
|
46
30
|
|
47
|
-
|
48
|
-
redirect_to confirm_subscription_path(subscription), notice: "Subscription plan updated"
|
49
|
-
else
|
50
|
-
redirect_to confirm_subscription_path(subscription), alert: subscription.errors.full_messages.to_sentence
|
51
|
-
end
|
31
|
+
confirm_with_message("Subscription plan updated")
|
52
32
|
end
|
53
33
|
|
54
34
|
def update_card
|
55
|
-
subscription = Subscription.find_by!(guid: params[:guid])
|
56
|
-
Payola::UpdateCard.call(subscription, params[:stripeToken])
|
35
|
+
@subscription = Subscription.find_by!(guid: params[:guid])
|
36
|
+
Payola::UpdateCard.call(@subscription, params[:stripeToken])
|
57
37
|
|
58
|
-
|
59
|
-
redirect_to confirm_subscription_path(subscription), notice: "Card updated"
|
60
|
-
else
|
61
|
-
redirect_to confirm_subscription_path(subscription), alert: subscription.errors.full_messages.to_sentence
|
62
|
-
end
|
38
|
+
confirm_with_message("Card updated")
|
63
39
|
end
|
64
40
|
|
65
41
|
private
|
66
42
|
|
67
|
-
def
|
43
|
+
def find_plan_and_coupon
|
44
|
+
find_plan
|
45
|
+
find_coupon
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_plan
|
68
49
|
@plan_class = Payola.subscribables[params[:plan_class]]
|
69
50
|
|
70
51
|
raise ActionController::RoutingError.new('Not Found') unless @plan_class && @plan_class.subscribable?
|
71
52
|
|
72
53
|
@plan = @plan_class.find_by!(id: params[:plan_id])
|
73
|
-
|
74
|
-
@coupon = cookies[:cc] || params[:cc] || params[:coupon_code] || params[:coupon]
|
75
|
-
|
76
|
-
affiliate_code = cookies[:aff] || params[:aff]
|
77
|
-
@affiliate = Affiliate.where('lower(code) = lower(?)', affiliate_code).first
|
78
|
-
if @affiliate
|
79
|
-
cookies[:aff] = affiliate_code
|
80
|
-
end
|
54
|
+
end
|
81
55
|
|
56
|
+
def find_coupon
|
57
|
+
@coupon = cookies[:cc] || params[:cc] || params[:coupon_code] || params[:coupon]
|
82
58
|
end
|
83
59
|
|
84
60
|
def check_modify_permissions
|
@@ -90,5 +66,14 @@ module Payola
|
|
90
66
|
) and return unless self.payola_can_modify_subscription?(subscription)
|
91
67
|
end
|
92
68
|
end
|
69
|
+
|
70
|
+
def confirm_with_message(message)
|
71
|
+
if @subscription.valid?
|
72
|
+
redirect_to confirm_subscription_path(@subscription), notice: message
|
73
|
+
else
|
74
|
+
redirect_to confirm_subscription_path(@subscription), alert: @subscription.errors.full_messages.to_sentence
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
93
78
|
end
|
94
79
|
end
|
@@ -1,47 +1,38 @@
|
|
1
1
|
module Payola
|
2
2
|
class TransactionsController < ApplicationController
|
3
|
-
|
3
|
+
include Payola::AffiliateBehavior
|
4
|
+
include Payola::AsyncBehavior
|
4
5
|
|
5
|
-
|
6
|
-
sale = Sale.find_by!(guid: params[:guid])
|
7
|
-
product = sale.product
|
6
|
+
before_filter :find_product_and_coupon, only: [:create]
|
8
7
|
|
9
|
-
|
10
|
-
|
8
|
+
def show
|
9
|
+
show_object(Sale)
|
11
10
|
end
|
12
11
|
|
13
12
|
def status
|
14
|
-
|
15
|
-
render nothing: true, status: 404 and return unless @sale
|
16
|
-
render json: {guid: @sale.guid, status: @sale.state, error: @sale.error}
|
13
|
+
object_status(Sale)
|
17
14
|
end
|
18
15
|
|
19
16
|
def create
|
20
|
-
|
21
|
-
product: @product,
|
22
|
-
coupon: @coupon,
|
23
|
-
affiliate: @affiliate
|
24
|
-
)
|
25
|
-
|
26
|
-
@sale = CreateSale.call(create_params)
|
27
|
-
|
28
|
-
if @sale.save
|
29
|
-
Payola.queue!(Payola::ProcessSale, @sale.guid)
|
30
|
-
render json: { guid: @sale.guid }
|
31
|
-
else
|
32
|
-
render json: { error: @sale.errors.full_messages.join(". ") }, status: 400
|
33
|
-
end
|
17
|
+
create_object(Sale, CreateSale, ProcessSale, :product, @product)
|
34
18
|
end
|
35
19
|
|
36
20
|
private
|
37
|
-
def
|
21
|
+
def find_product_and_coupon
|
22
|
+
find_product
|
23
|
+
find_coupon
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_product
|
38
27
|
@product_class = Payola.sellables[params[:product_class]]
|
39
28
|
|
40
29
|
raise ActionController::RoutingError.new('Not Found') unless @product_class && @product_class.sellable?
|
41
30
|
|
42
31
|
@product = @product_class.find_by!(permalink: params[:permalink])
|
43
|
-
|
32
|
+
end
|
44
33
|
|
34
|
+
def find_coupon
|
35
|
+
coupon_code = cookies[:cc] || params[:cc] || params[:coupon_code]
|
45
36
|
@coupon = Coupon.where('lower(code) = lower(?)', coupon_code).first
|
46
37
|
if @coupon
|
47
38
|
cookies[:cc] = coupon_code
|
@@ -49,13 +40,6 @@ module Payola
|
|
49
40
|
else
|
50
41
|
@price = @product.price
|
51
42
|
end
|
52
|
-
|
53
|
-
affiliate_code = cookies[:aff] || params[:aff]
|
54
|
-
@affiliate = Affiliate.where('lower(code) = lower(?)', affiliate_code).first
|
55
|
-
if @affiliate
|
56
|
-
cookies[:aff] = affiliate_code
|
57
|
-
end
|
58
|
-
|
59
43
|
end
|
60
44
|
|
61
45
|
end
|
@@ -3,30 +3,22 @@ module Payola
|
|
3
3
|
helper Payola::PriceHelper
|
4
4
|
|
5
5
|
def receipt(sale_guid)
|
6
|
-
|
7
|
-
@sale = Payola::Sale.find_by(guid: sale_guid)
|
8
|
-
@product = @sale.product
|
9
|
-
mail(from: Payola.support_email, to: Payola.support_email)
|
10
|
-
end
|
6
|
+
send_admin_mail(sale_guid)
|
11
7
|
end
|
12
8
|
|
13
9
|
def refund(sale_guid)
|
14
|
-
|
15
|
-
@sale = Payola::Sale.find_by(guid: sale_guid)
|
16
|
-
@product = @sale.product
|
17
|
-
mail(from: Payola.support_email, to: Payola.support_email)
|
18
|
-
end
|
10
|
+
send_admin_mail(sale_guid)
|
19
11
|
end
|
20
12
|
|
21
13
|
def dispute(sale_guid)
|
22
|
-
|
23
|
-
@sale = Payola::Sale.find_by(guid: sale_guid)
|
24
|
-
@product = @sale.product
|
25
|
-
mail(from: Payola.support_email, to: Payola.support_email)
|
26
|
-
end
|
14
|
+
send_admin_mail(sale_guid)
|
27
15
|
end
|
28
16
|
|
29
17
|
def failure(sale_guid)
|
18
|
+
send_admin_mail(sale_guid)
|
19
|
+
end
|
20
|
+
|
21
|
+
def send_admin_mail(sale_guid)
|
30
22
|
ActiveRecord::Base.connection_pool.with_connection do
|
31
23
|
@sale = Payola::Sale.find_by(guid: sale_guid)
|
32
24
|
@product = @sale.product
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module Payola
|
4
|
+
module GuidBehavior
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
before_save :populate_guid
|
9
|
+
validates_uniqueness_of :guid
|
10
|
+
end
|
11
|
+
|
12
|
+
def populate_guid
|
13
|
+
if new_record?
|
14
|
+
while !valid? || self.guid.nil?
|
15
|
+
self.guid = Payola.guid_generator.call
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|