payola-payments 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|