artfully_ose 1.2.0.pre.16 → 1.2.0.pre.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/app/assets/javascripts/angular-resource.js +546 -0
- data/app/assets/javascripts/angular.js +20311 -0
- data/app/assets/javascripts/application.js +13 -2
- data/app/assets/javascripts/change-membership.js +98 -0
- data/app/assets/stylesheets/application.sass +3 -0
- data/app/controllers/artfully_ose_controller.rb +12 -0
- data/app/controllers/membership_awards_controller.rb +2 -0
- data/app/controllers/membership_changes_controller.rb +39 -0
- data/app/controllers/membership_types_controller.rb +2 -0
- data/app/controllers/sales_controller.rb +1 -1
- data/app/controllers/store/checkouts_controller.rb +4 -4
- data/app/controllers/store/orders_controller.rb +1 -1
- data/app/helpers/artfully_ose_helper.rb +10 -0
- data/app/helpers/membership_types_helper.rb +17 -0
- data/app/models/actions/change_action.rb +13 -0
- data/app/models/carts/cart.rb +6 -3
- data/app/models/donation.rb +4 -0
- data/app/models/ext/integrations.rb +1 -3
- data/app/models/item.rb +1 -1
- data/app/models/kits/membership_kit.rb +1 -1
- data/app/models/member.rb +6 -0
- data/app/models/membership.rb +10 -2
- data/app/models/membership_change.rb +176 -0
- data/app/models/membership_type.rb +10 -1
- data/app/models/order_handler.rb +2 -2
- data/app/models/orders/order.rb +9 -1
- data/app/models/section.rb +1 -1
- data/app/models/show.rb +2 -2
- data/app/models/ticket.rb +4 -0
- data/app/models/ticket_type.rb +2 -2
- data/app/views/events/_ticket_type_fields.html.haml +18 -17
- data/app/views/kits/_list.html.haml +8 -0
- data/app/views/layouts/storefront.html.haml +3 -3
- data/app/views/members/mailer/invitation_instructions.html.haml +3 -2
- data/app/views/membership_kits/edit.html.haml +2 -18
- data/app/views/membership_types/_form.html.haml +71 -5
- data/app/views/memberships/index.html.haml +45 -45
- data/app/views/orders/_item_table.haml +2 -0
- data/app/views/organizations/show.html.haml +22 -16
- data/app/views/sales/new.html.haml +1 -1
- data/app/views/store/checkouts/_membership_info.html.haml +2 -2
- data/app/views/store/checkouts/thanks.html.haml +1 -1
- data/app/views/store/memberships/index.html.haml +2 -2
- data/app/views/store/orders/show.html.haml +3 -3
- data/app/views/store/shows/_show.html.haml +1 -1
- data/app/views/user_memberships/_list.html.haml +27 -26
- data/config/routes.rb +2 -0
- data/db/migrate/20131206153323_add_membership_kit.rb +5 -0
- data/db/migrate/20131206175325_add_marketing_to_membership_type.rb +6 -0
- data/db/migrate/20131210212342_add_show_fee_to_memberhsip_type.rb +5 -0
- data/db/migrate/20131210222814_add_renewal_price_to_membership_type.rb +6 -0
- data/lib/artfully_ose/version.rb +1 -1
- metadata +13 -4
- data/app/assets/javascripts/angular-resource.min.js +0 -11
- data/app/assets/javascripts/angular.min.js +0 -178
@@ -2,14 +2,15 @@
|
|
2
2
|
//= require jquery_ujs
|
3
3
|
//= require jquery-lib
|
4
4
|
//= require jquery-migrate-1.2.1
|
5
|
-
//= require angular
|
6
|
-
//= require angular-resource
|
5
|
+
//= require angular
|
6
|
+
//= require angular-resource
|
7
7
|
//= require locationselector
|
8
8
|
//= require_directory ./custom
|
9
9
|
//= require bootstrap
|
10
10
|
//= require wysihtml5-0.3.0.min.js
|
11
11
|
//= require bootstrap-wysihtml5.js
|
12
12
|
//= require_self
|
13
|
+
//= require change-membership
|
13
14
|
|
14
15
|
var artfully = angular.module("artfully", ['ngResource']);
|
15
16
|
|
@@ -205,6 +206,16 @@ $(document).ready(function() {
|
|
205
206
|
$('.no-fa').on('keyup', checkForFA);
|
206
207
|
$('.no-fa').on('change', clearFA);
|
207
208
|
|
209
|
+
$('#membership_type_offer_renewal').click(function () {
|
210
|
+
$("#renewal-price-group").toggle();
|
211
|
+
});
|
212
|
+
|
213
|
+
if($("#membership_type_offer_renewal").is(':checked')) {
|
214
|
+
$("#renewal-price-group").show();
|
215
|
+
} else {
|
216
|
+
$("#renewal-price-group").hide();
|
217
|
+
}
|
218
|
+
|
208
219
|
bindMemberTickets()
|
209
220
|
|
210
221
|
/*********** EXISTING ARTFUL.LY JS ******/
|
@@ -0,0 +1,98 @@
|
|
1
|
+
//
|
2
|
+
// Service for keeping track of which memberships are selected
|
3
|
+
//
|
4
|
+
angular.module('artfully').factory('membershipSelections', function() {
|
5
|
+
// Map of selected membership ids
|
6
|
+
var map = {};
|
7
|
+
|
8
|
+
// Initial values
|
9
|
+
$('input[name=membership_ids\\[\\]]:checked').each(function(i,input) { map[input.value] = true });
|
10
|
+
|
11
|
+
// Watch for changes
|
12
|
+
$('body').on('change', 'input[name=membership_ids\\[\\]]', function(change) {
|
13
|
+
var e = $(change.target);
|
14
|
+
var row = e.closest('tr');
|
15
|
+
var type = $(row.find('.item-description')[0]);
|
16
|
+
var price = $(row.find('.price')[0]);
|
17
|
+
var membership_id = e.val();
|
18
|
+
|
19
|
+
if ($(e).prop( "checked" )) {
|
20
|
+
// Add the membership id if it's not already in the list
|
21
|
+
if (map[membership_id] === undefined) {
|
22
|
+
map[membership_id] = {
|
23
|
+
id: membership_id,
|
24
|
+
type: type.text(),
|
25
|
+
price: price.text()
|
26
|
+
};
|
27
|
+
}
|
28
|
+
|
29
|
+
} else {
|
30
|
+
// Remove the membership id
|
31
|
+
delete map[membership_id];
|
32
|
+
}
|
33
|
+
});
|
34
|
+
|
35
|
+
return map;
|
36
|
+
});
|
37
|
+
|
38
|
+
//
|
39
|
+
// Controller
|
40
|
+
//
|
41
|
+
angular.module('artfully').controller('ChangeMembershipController', ['$scope', 'membershipSelections', function($scope, membershipSelections) {
|
42
|
+
|
43
|
+
// Template variables
|
44
|
+
$scope.payment_method = 'cash';
|
45
|
+
$scope.price = 0;
|
46
|
+
$scope.total = 0;
|
47
|
+
$scope.selected = {};
|
48
|
+
|
49
|
+
// Helpers
|
50
|
+
$scope.anySelected = function() {
|
51
|
+
if (Object.keys(membershipSelections).length == 0 ) {
|
52
|
+
return false;
|
53
|
+
}
|
54
|
+
return true;
|
55
|
+
}
|
56
|
+
|
57
|
+
$scope.changeSelected = function(click) {
|
58
|
+
click.preventDefault();
|
59
|
+
|
60
|
+
if (!$scope.anySelected()) {
|
61
|
+
alert("Select one or more memberships to change.");
|
62
|
+
return false;
|
63
|
+
}
|
64
|
+
|
65
|
+
// Open the modal
|
66
|
+
$('#change').modal('show');
|
67
|
+
return false;
|
68
|
+
}
|
69
|
+
|
70
|
+
$scope.updateTotal = function() {
|
71
|
+
var price = parseFloat($scope.price.substr(1).replace(/,/, ""));
|
72
|
+
var total = (Object.keys($scope.selected).length * price);
|
73
|
+
|
74
|
+
|
75
|
+
$scope.total = '$'+total.toFixed(2);
|
76
|
+
}
|
77
|
+
|
78
|
+
// Update the list of selected ids when the modal is shown
|
79
|
+
$("#change").on('shown', function(shown) {
|
80
|
+
$scope.selected = membershipSelections;
|
81
|
+
|
82
|
+
// Mask the price field
|
83
|
+
touchCurrency();
|
84
|
+
});
|
85
|
+
|
86
|
+
// Clear the list of selected ids when the modal is hidden
|
87
|
+
$("#change").on('hidden', function(hidden) {
|
88
|
+
$scope.payment_method = 'cash';
|
89
|
+
$scope.price = 0;
|
90
|
+
$scope.total = 0;
|
91
|
+
$scope.selected = {};
|
92
|
+
|
93
|
+
// Reset the form
|
94
|
+
var form = $(this).find('form')[0];
|
95
|
+
if (form) { form.reset(); }
|
96
|
+
});
|
97
|
+
}]);
|
98
|
+
|
@@ -17,6 +17,18 @@ class ArtfullyOseController < ActionController::Base
|
|
17
17
|
|
18
18
|
protected
|
19
19
|
|
20
|
+
#
|
21
|
+
# don't appent "kit" to the name.
|
22
|
+
# Example requires_kit :membership
|
23
|
+
#
|
24
|
+
def self.requires_kit(kit)
|
25
|
+
before_filter do
|
26
|
+
unless current_user.current_organization.has_kit? (kit)
|
27
|
+
raise CanCan::AccessDenied
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
20
32
|
def to_plural(variable, word)
|
21
33
|
self.class.helpers.pluralize(variable, word)
|
22
34
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class MembershipChangesController < ApplicationController
|
2
|
+
before_filter :set_person, :only => [:create]
|
3
|
+
|
4
|
+
def create
|
5
|
+
change = MembershipChange.new(membership_change_params)
|
6
|
+
if change.save
|
7
|
+
# Success!
|
8
|
+
flash[:success] = 'Memberships have been successfully changed.'
|
9
|
+
else
|
10
|
+
# Error!
|
11
|
+
flash[:error] = error_message
|
12
|
+
end
|
13
|
+
rescue Exception => e
|
14
|
+
Rails.logger.info(e.message)
|
15
|
+
Rails.logger.info(e.backtrace.join("\n"))
|
16
|
+
|
17
|
+
flash[:error] = error_message
|
18
|
+
ensure
|
19
|
+
redirect_to person_memberships_path(@person)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def error_message
|
24
|
+
"We're sorry but we could not process the change. Please make sure all fields are filled out accurately."
|
25
|
+
end
|
26
|
+
|
27
|
+
def membership_change_params
|
28
|
+
permitted = [:membership_ids, :membership_type_id, :price, :payment_method, :credit_card_info, :person_id]
|
29
|
+
permitted.reduce({}) do |all,key|
|
30
|
+
all[key] = params[key] if params[key].present?
|
31
|
+
all
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def set_person
|
36
|
+
@person = Person.find(params[:person_id])
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
@@ -63,7 +63,7 @@ class SalesController < ArtfullyOseController
|
|
63
63
|
def tickets_remaining
|
64
64
|
remaining = {}
|
65
65
|
@sale.ticket_types.each do |ticket_type|
|
66
|
-
remaining[ticket_type.id] = ticket_type.available
|
66
|
+
remaining[ticket_type.id] = ticket_type.available("box_office")
|
67
67
|
end
|
68
68
|
remaining
|
69
69
|
end
|
@@ -29,10 +29,10 @@ class Store::CheckoutsController < Store::StoreController
|
|
29
29
|
redirect_to store_order_path
|
30
30
|
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def dook
|
33
|
+
@order = Order.find(157)
|
34
|
+
render :thanks
|
35
|
+
end
|
36
36
|
|
37
37
|
def filter(params)
|
38
38
|
filters = Rails.application.config.filter_parameters
|
@@ -6,7 +6,7 @@ class Store::OrdersController < Store::StoreController
|
|
6
6
|
handler = OrderHandler.new(current_cart, current_member)
|
7
7
|
handler.handle_tickets(params)
|
8
8
|
handler.handle_donation(params, @store_organization)
|
9
|
-
handler.handle_memberships(params)
|
9
|
+
handler.handle_memberships(params, current_member)
|
10
10
|
handler.handle_discount(params)
|
11
11
|
|
12
12
|
flash[:alert] = handler.error unless handler.error.blank?
|
@@ -13,6 +13,16 @@ module ArtfullyOseHelper
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
#
|
17
|
+
# Pass kit name with Kit or _kit. Like this "with_kit(:membership)"
|
18
|
+
#
|
19
|
+
def with_kit(kit)
|
20
|
+
organization = current_user.try(:current_organization) || @store_organization
|
21
|
+
if organization.has_kit? kit
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
16
26
|
def thanks_message(person)
|
17
27
|
message = "Thanks"
|
18
28
|
message += ", #{person.first_name}" unless person.first_name.blank?
|
@@ -2,4 +2,21 @@ module MembershipTypesHelper
|
|
2
2
|
def membership_type_storefront_path(membership_type)
|
3
3
|
url_for(organization_slug: membership_type.organization.cached_slug, controller: 'store/memberships', action: 'show', id: membership_type.id)
|
4
4
|
end
|
5
|
+
|
6
|
+
def options_for_membership_types(types, opts={})
|
7
|
+
default_options = {
|
8
|
+
:include_price => false
|
9
|
+
}
|
10
|
+
options = default_options
|
11
|
+
options = options.merge(opts) unless opts.blank?
|
12
|
+
|
13
|
+
items = types.map do |type|
|
14
|
+
name = type.name
|
15
|
+
name << (' - $%.2f' % number_to_dollars(type.price)) if options[:include_price]
|
16
|
+
|
17
|
+
[name, type.id]
|
18
|
+
end
|
19
|
+
|
20
|
+
options_for_select items
|
21
|
+
end
|
5
22
|
end
|
data/app/models/carts/cart.rb
CHANGED
@@ -2,8 +2,8 @@ class Cart < ActiveRecord::Base
|
|
2
2
|
include ActiveRecord::Transitions
|
3
3
|
|
4
4
|
has_many :donations, :dependent => :destroy
|
5
|
-
has_many :tickets
|
6
|
-
has_many :memberships
|
5
|
+
has_many :tickets, :after_add => :calculate_fees
|
6
|
+
has_many :memberships, :after_add => :calculate_fees
|
7
7
|
after_destroy :clear!
|
8
8
|
before_validation :set_token
|
9
9
|
attr_accessor :special_instructions
|
@@ -74,6 +74,10 @@ class Cart < ActiveRecord::Base
|
|
74
74
|
items.sum(&:service_fee)
|
75
75
|
end
|
76
76
|
|
77
|
+
def calculate_fees(obj)
|
78
|
+
FeeCalculator.apply(FeeStrategy.new).to(self)
|
79
|
+
end
|
80
|
+
|
77
81
|
def <<(tkts)
|
78
82
|
tkts = Array.wrap(tkts)
|
79
83
|
tkts.each do |t|
|
@@ -81,7 +85,6 @@ class Cart < ActiveRecord::Base
|
|
81
85
|
t.cart_price = t.ticket_type.price
|
82
86
|
end
|
83
87
|
self.tickets << tkts.flatten
|
84
|
-
FeeCalculator.apply(FeeStrategy.new).to(self)
|
85
88
|
end
|
86
89
|
|
87
90
|
def subtotal
|
data/app/models/donation.rb
CHANGED
@@ -24,15 +24,13 @@ module Ext
|
|
24
24
|
#
|
25
25
|
# Used for rendering widget and api charts. Storefront uses section.ticket_types_for instead
|
26
26
|
#
|
27
|
-
def chart_for(channel,
|
27
|
+
def chart_for(channel, organization_id = nil)
|
28
28
|
chart = Chart.joins(:show)
|
29
29
|
.joins(:sections => :ticket_types)
|
30
30
|
.includes(:sections => :ticket_types)
|
31
31
|
.where('shows.id = ?', self.id)
|
32
32
|
.where("ticket_types.#{channel} = ?", true)
|
33
33
|
|
34
|
-
chart = chart.where(:ticket_types=>{:membership_type_id=>member.try(:current_membership_types)})
|
35
|
-
|
36
34
|
chart.first
|
37
35
|
end
|
38
36
|
end
|
data/app/models/item.rb
CHANGED
@@ -263,7 +263,7 @@ class Item < ActiveRecord::Base
|
|
263
263
|
def set_prices_from(prod)
|
264
264
|
self.original_price = prod.price
|
265
265
|
self.price = (prod.sold_price || prod.cart_price || prod.price)
|
266
|
-
self.realized_price = self.price - prod.
|
266
|
+
self.realized_price = self.price - prod.realized_fee
|
267
267
|
self.net = (self.realized_price - (per_item_processing_charge || lambda { |item| 0 }).call(self)).floor
|
268
268
|
self.service_fee = prod.service_fee || 0
|
269
269
|
end
|
@@ -17,7 +17,7 @@ class MembershipKit < Kit
|
|
17
17
|
|
18
18
|
before_save :sanitize_accessors
|
19
19
|
|
20
|
-
ACCESSORS = [ :marketing_copy_heading, :marketing_copy_sidebar
|
20
|
+
ACCESSORS = [ :marketing_copy_heading, :marketing_copy_sidebar ]
|
21
21
|
|
22
22
|
ACCESSORS.each do |accessor|
|
23
23
|
attr_accessible accessor
|
data/app/models/member.rb
CHANGED
data/app/models/membership.rb
CHANGED
@@ -19,11 +19,11 @@ class Membership < ActiveRecord::Base
|
|
19
19
|
scope :lapsed, lambda { |time = Time.now, since = (time - 1.year)| where("ends_at < ?", time).where("ends_at > ?", since.midnight) }
|
20
20
|
scope :past, lambda { |time = Time.now| where("ends_at < ?", time - 1.year) }
|
21
21
|
|
22
|
-
def self.for(membership_type)
|
22
|
+
def self.for(membership_type, member = nil)
|
23
23
|
new.tap do |membership|
|
24
24
|
membership.membership_type = membership_type
|
25
25
|
membership.organization = membership_type.organization
|
26
|
-
membership.price = membership_type.
|
26
|
+
membership.price = membership_type.price_for(member)
|
27
27
|
membership.starts_at = membership_type.starts_at
|
28
28
|
membership.ends_at = membership_type.ends_at
|
29
29
|
end
|
@@ -62,6 +62,14 @@ class Membership < ActiveRecord::Base
|
|
62
62
|
0
|
63
63
|
end
|
64
64
|
|
65
|
+
def realized_fee
|
66
|
+
self.membership_type.hide_fee? ? self.price * MembershipType::SERVICE_FEE : 0
|
67
|
+
end
|
68
|
+
|
69
|
+
def expired?
|
70
|
+
ends_at < Time.now
|
71
|
+
end
|
72
|
+
|
65
73
|
def refundable?
|
66
74
|
false
|
67
75
|
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
class MembershipChange
|
2
|
+
include ActiveModel::Validations
|
3
|
+
|
4
|
+
attr_reader :cart
|
5
|
+
attr_reader :checkout
|
6
|
+
attr_reader :changing_memberships
|
7
|
+
attr_reader :new_memberships
|
8
|
+
attr_reader :payment
|
9
|
+
|
10
|
+
attr_accessor :credit_card_info
|
11
|
+
attr_accessor :membership_ids
|
12
|
+
attr_accessor :membership_type_id
|
13
|
+
attr_accessor :payment_method
|
14
|
+
attr_accessor :person_id
|
15
|
+
attr_accessor :price
|
16
|
+
|
17
|
+
validates :person_id, :presence => true
|
18
|
+
validates :membership_ids, :presence => true
|
19
|
+
validates :membership_type_id, :presence => true
|
20
|
+
validates :payment_method, :presence => true
|
21
|
+
validates :price, :presence => true
|
22
|
+
validates :credit_card_info, :presence => {:if => :credit?}
|
23
|
+
|
24
|
+
# This is purely to assuage shoulda and it's validation matchers
|
25
|
+
def self.reflect_on_association(a)
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(params = nil)
|
30
|
+
@price = 0
|
31
|
+
assign_params(params) if params
|
32
|
+
end
|
33
|
+
|
34
|
+
def assign_params(new_params)
|
35
|
+
return if new_params.blank?
|
36
|
+
|
37
|
+
params = new_params.stringify_keys
|
38
|
+
params.each do |k,v|
|
39
|
+
if respond_to?("#{k}=")
|
40
|
+
send("#{k}=", v)
|
41
|
+
else
|
42
|
+
raise(ArgumentError, "unknown parameter: #{k}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def cart
|
48
|
+
unless @cart
|
49
|
+
@cart = Cart.create
|
50
|
+
|
51
|
+
# Add the new memberships
|
52
|
+
new_memberships.each do |membership|
|
53
|
+
cart.memberships << membership
|
54
|
+
end
|
55
|
+
end
|
56
|
+
@cart
|
57
|
+
end
|
58
|
+
|
59
|
+
def changing_memberships
|
60
|
+
@changing_memberships ||= Membership.where(id: membership_ids)
|
61
|
+
end
|
62
|
+
|
63
|
+
def checkout
|
64
|
+
@checkout ||= MembershipChange::Checkout.new(cart, payment)
|
65
|
+
end
|
66
|
+
|
67
|
+
def comp?
|
68
|
+
'comp' == payment_method
|
69
|
+
end
|
70
|
+
|
71
|
+
def credit?
|
72
|
+
!!(payment_method =~ /credit|cc/)
|
73
|
+
end
|
74
|
+
|
75
|
+
def membership_type
|
76
|
+
@membership_type ||= MembershipType.find(membership_type_id)
|
77
|
+
end
|
78
|
+
|
79
|
+
def new_memberships
|
80
|
+
if @new_memberships.blank?
|
81
|
+
@new_memberships = []
|
82
|
+
|
83
|
+
unless membership_ids.blank?
|
84
|
+
# Grab the old memberships and hash on id
|
85
|
+
old_memberships = changing_memberships.reduce({}) do |all, o|
|
86
|
+
all[o.id.to_s] = o
|
87
|
+
all
|
88
|
+
end
|
89
|
+
|
90
|
+
# Make new memberships
|
91
|
+
@new_memberships = membership_ids.map do |old_membership_id|
|
92
|
+
old = old_memberships[old_membership_id]
|
93
|
+
|
94
|
+
# Create the new membership, setting sold price, and the start/end dates from the old one
|
95
|
+
membership = Membership.for(membership_type)
|
96
|
+
membership.starts_at = old.starts_at
|
97
|
+
membership.ends_at = old.ends_at
|
98
|
+
membership.price = price
|
99
|
+
membership.member = person.member
|
100
|
+
|
101
|
+
membership
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
@new_memberships
|
106
|
+
end
|
107
|
+
|
108
|
+
def payment
|
109
|
+
unless @payment
|
110
|
+
@payment = Payment.create(payment_method, {credit_card: credit_card_info})
|
111
|
+
@payment.customer = person
|
112
|
+
end
|
113
|
+
@payment
|
114
|
+
end
|
115
|
+
|
116
|
+
def person
|
117
|
+
@person ||= Person.find(person_id)
|
118
|
+
end
|
119
|
+
|
120
|
+
def price
|
121
|
+
return nil unless @price
|
122
|
+
return 0 if comp?
|
123
|
+
@price
|
124
|
+
end
|
125
|
+
|
126
|
+
def price=(new_price)
|
127
|
+
new_price = new_price.to_i unless new_price.blank?
|
128
|
+
@price = new_price
|
129
|
+
end
|
130
|
+
|
131
|
+
def save
|
132
|
+
return false unless valid?
|
133
|
+
|
134
|
+
Order.transaction do
|
135
|
+
expiration = 1.second.ago
|
136
|
+
|
137
|
+
# Complete checkout
|
138
|
+
success = checkout.finish
|
139
|
+
|
140
|
+
# Failure?
|
141
|
+
raise MembershipChange::Error unless success
|
142
|
+
|
143
|
+
# Expire old memberships
|
144
|
+
changing_memberships.each do |old|
|
145
|
+
old.adjust_expiration_to(expiration)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
true
|
149
|
+
rescue MembershipChange::Error => e
|
150
|
+
payment.errors[:base].each do |msg|
|
151
|
+
errors.add(:base, msg)
|
152
|
+
end
|
153
|
+
false
|
154
|
+
end
|
155
|
+
|
156
|
+
def valid?
|
157
|
+
super && checkout.valid?
|
158
|
+
end
|
159
|
+
|
160
|
+
class Error < StandardError; end
|
161
|
+
|
162
|
+
class Cart < ::Cart
|
163
|
+
end
|
164
|
+
|
165
|
+
class Checkout < ::Checkout
|
166
|
+
def order_class
|
167
|
+
MembershipChange::Order
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class Order < ::Order
|
172
|
+
def membership_action_class
|
173
|
+
ChangeAction
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|