dm_event 4.2.3.2 → 4.2.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/dm_event/admin/workshops_controller.rb +3 -1
- data/app/models/registration.rb +41 -17
- data/app/models/workshop.rb +1 -1
- data/app/models/workshop_price.rb +46 -12
- data/app/views/dm_event/admin/registrations/_form.html.erb +73 -29
- data/app/views/dm_event/admin/workshops/financials.html.erb +13 -6
- data/spec/dummy/log/development.log +16989 -0
- data/spec/dummy/log/test.log +53876 -0
- data/spec/models/registration_spec.rb +120 -15
- data/spec/models/workshop_price_spec.rb +137 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 166674962a59997e15cc1dd82e97776ea718d6e7
|
4
|
+
data.tar.gz: 14dfe6801c934c2d49f64ee532760138d48e2aac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d4c563433c1131e20a8cad5bc2768e033d9dbf3bc94f7f1457d517511a144e2d878c5b8c6e96d1660ee5d223e4e5b022af140adbea611e66041be3e50ed7ba3
|
7
|
+
data.tar.gz: e9f9c5a5fbfac90c1fe75e4363dfedb2acf728f83f080780c9341c27fccec84174fcd84e37f60096871884c7d336788e0bfdde5c13c170cca030ce1a526a4baf
|
@@ -93,7 +93,9 @@ class DmEvent::Admin::WorkshopsController < DmEvent::Admin::AdminController
|
|
93
93
|
def financials
|
94
94
|
authorize! :manage_event_finances, @workshop
|
95
95
|
@financials = @workshop.financial_details
|
96
|
-
@payments
|
96
|
+
@payments = PaymentHistory.where(owner_type: 'Registration', owner_id: @workshop.registrations.pluck(:id)).includes(:user_profile, owner: [:user_profile])
|
97
|
+
@unpaid = @workshop.registrations.unpaid.includes(:user_profile, :workshop_price)
|
98
|
+
@unpaid = @unpaid.to_a.delete_if {|i| i.payment_owed.zero?}.sort_by {|i| i.full_name.downcase}
|
97
99
|
end
|
98
100
|
|
99
101
|
# Generate a list of all outstanding balances across all workshops
|
data/app/models/registration.rb
CHANGED
@@ -36,6 +36,7 @@ class Registration < ActiveRecord::Base
|
|
36
36
|
after_initialize :create_uuid
|
37
37
|
before_create :set_currency
|
38
38
|
after_create :set_receipt_code
|
39
|
+
before_save :clear_reminder_sent_on, if: :amount_paid_cents_changed?
|
39
40
|
|
40
41
|
validates_uniqueness_of :uuid
|
41
42
|
validates_presence_of :workshop_price_id, if: Proc.new { |reg| reg.workshop.workshop_prices.size > 0}
|
@@ -48,6 +49,12 @@ class Registration < ActiveRecord::Base
|
|
48
49
|
|
49
50
|
private
|
50
51
|
|
52
|
+
# when a payment is made, we want reset whether a payment reminder has been sent
|
53
|
+
#------------------------------------------------------------------------------
|
54
|
+
def clear_reminder_sent_on
|
55
|
+
self.payment_reminder_sent_on = nil
|
56
|
+
end
|
57
|
+
|
51
58
|
# the uuid is used to provide a private url to a customer so that they can access
|
52
59
|
# their registration if not logged in. This is particularly important when
|
53
60
|
# a customer registers without having a user account.
|
@@ -110,12 +117,13 @@ public
|
|
110
117
|
end
|
111
118
|
|
112
119
|
# suggested amount of next payment.
|
113
|
-
#
|
120
|
+
# when it's recurring, they payment should be whatever is needed to bring their
|
121
|
+
# payment plan up to date
|
114
122
|
#------------------------------------------------------------------------------
|
115
123
|
def payment_owed
|
116
|
-
if workshop_price
|
117
|
-
|
118
|
-
|
124
|
+
if workshop_price && workshop_price.recurring_payments?
|
125
|
+
to_pay = recurring_what_should_be_paid_by_now(0) - amount_paid
|
126
|
+
to_pay.negative? ? Money.new(0, workshop_price.price.currency) : to_pay
|
119
127
|
else
|
120
128
|
balance_owed
|
121
129
|
end
|
@@ -167,25 +175,43 @@ public
|
|
167
175
|
def unpaid?
|
168
176
|
self.accepted? && self.archived_on == nil
|
169
177
|
end
|
170
|
-
|
178
|
+
|
171
179
|
# Is it time to send a payment reminder?
|
172
|
-
# Due first 7 days after inital registration. Then every 14 days after that
|
180
|
+
# Due first 7 days after inital registration (or a payment period). Then every 14 days after that
|
173
181
|
#------------------------------------------------------------------------------
|
174
182
|
def payment_reminder_due?
|
175
183
|
if preferred_payment_reminder_hold_until.nil? || preferred_payment_reminder_hold_until < Time.now
|
176
184
|
time_period = self.payment_reminder_sent_on.nil? ? (self.created_at + 7.days) : (self.payment_reminder_sent_on + 14.days)
|
177
|
-
|
185
|
+
past_due?(7) ? time_period < Time.now : false
|
186
|
+
else
|
187
|
+
false
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# past due means they haven't paid what they should have paid by now
|
192
|
+
#------------------------------------------------------------------------------
|
193
|
+
def past_due?(grace_period_in_days = 7)
|
194
|
+
return false if !balance_owed.positive?
|
195
|
+
if workshop_price.recurring_payments?
|
196
|
+
return amount_paid < recurring_what_should_be_paid_by_now(grace_period_in_days)
|
197
|
+
else
|
198
|
+
return Date.today > (self.created_at + grace_period_in_days.days)
|
178
199
|
end
|
200
|
+
end
|
179
201
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
# last_payment = payment_histories.order('created_on').last
|
185
|
-
# if workshop_price.recurring?
|
186
|
-
# if
|
202
|
+
#------------------------------------------------------------------------------
|
203
|
+
def recurring_what_should_be_paid_by_now(grace_period_in_days = 7)
|
204
|
+
entry = workshop_price.specific_payment_schedule(self.created_at + grace_period_in_days.days, Date.today)
|
205
|
+
entry ? entry[:total_due] : 0
|
187
206
|
end
|
188
|
-
|
207
|
+
|
208
|
+
# date when the most recent payment was due
|
209
|
+
#------------------------------------------------------------------------------
|
210
|
+
def last_payment_due_on
|
211
|
+
entry = workshop_price.specific_payment_schedule(self.created_at, Date.today)
|
212
|
+
entry ? entry[:due_on] : self.created_at.to_date
|
213
|
+
end
|
214
|
+
|
189
215
|
# Setup the columns for exporting data as csv.
|
190
216
|
#------------------------------------------------------------------------------
|
191
217
|
def self.csv_columns(workshop)
|
@@ -202,9 +228,7 @@ public
|
|
202
228
|
column_definitions << ["State", "item.state.capitalize"]
|
203
229
|
column_definitions << ["Zipcode", "item.zipcode"]
|
204
230
|
column_definitions << ["Country", "item.country.code"]
|
205
|
-
|
206
231
|
column_definitions << ['Registered on', 'item.created_at.to_date', 75, {type: 'DateTime', numberformat: 'd mmm, yyyy'}]
|
207
|
-
|
208
232
|
column_definitions << ["Price", "item.workshop_price.price.to_f", nil, {type: 'Number', numberformat: '#,##0.00'}]
|
209
233
|
column_definitions << ["Price Description", "item.workshop_price.price_description"]
|
210
234
|
column_definitions << ["Price Sub Descr", "item.workshop_price.sub_description"]
|
data/app/models/workshop.rb
CHANGED
@@ -180,7 +180,7 @@ class Workshop < ActiveRecord::Base
|
|
180
180
|
success = failed = 0
|
181
181
|
unpaid_list = ( registration_id == 'all' ? registrations.unpaid : registrations.unpaid.where(id: registration_id) )
|
182
182
|
unpaid_list.each do |registration|
|
183
|
-
if registration.payment_reminder_due? || registration_id != 'all'
|
183
|
+
if (registration.payment_reminder_due? && registration.payment_owed.positive?) || registration_id != 'all'
|
184
184
|
email = PaymentReminderMailer.payment_reminder(registration).deliver_now
|
185
185
|
if email
|
186
186
|
registration.update_attribute(:payment_reminder_sent_on, Time.now)
|
@@ -45,7 +45,7 @@ class WorkshopPrice < ActiveRecord::Base
|
|
45
45
|
# Call this method on the attributes before passing into new() or update_attributes()
|
46
46
|
#------------------------------------------------------------------------------
|
47
47
|
def self.prepare_prices(attributes = {})
|
48
|
-
attributes['price'] = attributes['price'].to_money(attributes['price_currency'])
|
48
|
+
attributes['price'] = attributes['price'].to_money(attributes['price_currency']) if attributes['price'].present? && attributes['price_currency'].present?
|
49
49
|
attributes['alt1_price'] = attributes['alt1_price'].to_money(attributes['alt1_price_currency']) if attributes['alt1_price'].present? && attributes['alt1_price_currency'].present?
|
50
50
|
attributes['alt2_price'] = attributes['alt2_price'].to_money(attributes['alt2_price_currency']) if attributes['alt2_price'].present? && attributes['alt2_price_currency'].present?
|
51
51
|
return attributes
|
@@ -53,14 +53,14 @@ class WorkshopPrice < ActiveRecord::Base
|
|
53
53
|
|
54
54
|
#------------------------------------------------------------------------------
|
55
55
|
def visible?
|
56
|
-
!(disabled? || (!valid_starting_on.nil? && valid_starting_on >
|
56
|
+
!(disabled? || (!valid_starting_on.nil? && valid_starting_on > Date.today) || (!valid_until.nil? && valid_until < Date.today))
|
57
57
|
end
|
58
58
|
|
59
59
|
# If the total_available is nil, then there are unlimited tickets to be sold.
|
60
60
|
# Otherwise, check if we have sold out
|
61
61
|
#------------------------------------------------------------------------------
|
62
62
|
def sold_out?(num_sold)
|
63
|
-
|
63
|
+
total_available.nil? ? false : (num_sold >= total_available)
|
64
64
|
end
|
65
65
|
|
66
66
|
#------------------------------------------------------------------------------
|
@@ -78,12 +78,41 @@ class WorkshopPrice < ActiveRecord::Base
|
|
78
78
|
def recurring_payments?
|
79
79
|
recurring_number.to_i > 1
|
80
80
|
end
|
81
|
-
|
81
|
+
|
82
|
+
# return array of when payments should be made. if `from_date` is specified,
|
83
|
+
# then actual dates are returned. Otherwise number of days
|
84
|
+
#------------------------------------------------------------------------------
|
85
|
+
def payment_schedule(from_date = nil)
|
86
|
+
schedule = []
|
87
|
+
if recurring_payments?
|
88
|
+
(0...recurring_number).each do |period|
|
89
|
+
xdays = period * recurring_period
|
90
|
+
schedule << {due_on: (from_date ? from_date.to_date + xdays.days : xdays),
|
91
|
+
period_payment: payment_price,
|
92
|
+
total_due: (period + 1) * payment_price}
|
93
|
+
end
|
94
|
+
# adjust the last entry
|
95
|
+
schedule.last[:total_due] = price
|
96
|
+
schedule.last[:period_payment] = price - (recurring_number - 1) * payment_price
|
97
|
+
else
|
98
|
+
schedule << {due_on: (from_date ? from_date.to_date : 0), period_payment: payment_price, total_due: payment_price}
|
99
|
+
end
|
100
|
+
schedule
|
101
|
+
end
|
102
|
+
|
103
|
+
# return the payment schedule entry that is before the specified date
|
104
|
+
#------------------------------------------------------------------------------
|
105
|
+
def specific_payment_schedule(from_date, on_date = Date.today)
|
106
|
+
payment_schedule(from_date).reverse.detect {|item| item[:due_on] <= on_date}
|
107
|
+
end
|
108
|
+
|
109
|
+
# return list of currencies used, in a format for a dropdown list
|
110
|
+
# ex: [['USD', 'USD'], ['EUR', 'EUR']]
|
82
111
|
#------------------------------------------------------------------------------
|
83
112
|
def currency_list
|
84
113
|
list = [[price_currency, price_currency]]
|
85
114
|
list << [alt1_price_currency, alt1_price_currency] unless alt1_price_currency.blank?
|
86
|
-
list << [alt2_price_currency,
|
115
|
+
list << [alt2_price_currency, alt2_price_currency] unless alt2_price_currency.blank?
|
87
116
|
return list
|
88
117
|
end
|
89
118
|
|
@@ -95,21 +124,26 @@ class WorkshopPrice < ActiveRecord::Base
|
|
95
124
|
|
96
125
|
# return a bank object filled with the exchange rates, based on the prices.
|
97
126
|
# then you can do: bank.exchange_with(price, 'USD')
|
127
|
+
# note: since JPY doesn't have cents (the price doesn't get multiplied by 100)
|
128
|
+
# then we need to do that in order to calculate the proper exchange rate
|
98
129
|
#------------------------------------------------------------------------------
|
99
130
|
def bank
|
100
131
|
unless @bank
|
101
132
|
@bank = Money::Bank::VariableExchange.new
|
133
|
+
base_cents = price_currency == 'JPY' ? (price_cents.to_f * 100) : price_cents.to_f
|
102
134
|
unless alt1_price_currency.blank?
|
103
|
-
|
104
|
-
@bank.add_rate(
|
135
|
+
alt1_cents = alt1_price_currency == 'JPY' ? (alt1_price_cents.to_f * 100) : alt1_price_cents.to_f
|
136
|
+
@bank.add_rate(price_currency, alt1_price_currency, alt1_cents / base_cents)
|
137
|
+
@bank.add_rate(alt1_price_currency, price_currency, base_cents / alt1_cents)
|
105
138
|
end
|
106
139
|
unless alt2_price_currency.blank?
|
107
|
-
|
108
|
-
@bank.add_rate(
|
140
|
+
alt2_cents = alt2_price_currency == 'JPY' ? (alt2_price_cents.to_f * 100) : alt2_price_cents.to_f
|
141
|
+
@bank.add_rate(price_currency, alt2_price_currency, alt2_cents / base_cents)
|
142
|
+
@bank.add_rate(alt2_price_currency, price_currency, base_cents / alt2_cents)
|
109
143
|
end
|
110
|
-
|
111
|
-
@bank.add_rate(alt1_price_currency, alt2_price_currency,
|
112
|
-
@bank.add_rate(alt2_price_currency, alt1_price_currency,
|
144
|
+
if !alt1_price_currency.blank? && !alt2_price_currency.blank?
|
145
|
+
@bank.add_rate(alt1_price_currency, alt2_price_currency, alt2_cents / alt1_cents)
|
146
|
+
@bank.add_rate(alt2_price_currency, alt1_price_currency, alt1_cents / alt2_cents)
|
113
147
|
end
|
114
148
|
end
|
115
149
|
return @bank
|
@@ -38,6 +38,8 @@
|
|
38
38
|
<div class="col-md-6 col-sm-6">
|
39
39
|
<% if @registration.workshop_price %>
|
40
40
|
<dl class="block">
|
41
|
+
<dt class="text-info">Registered On</dt>
|
42
|
+
<dd><%= format_date(@registration.created_at) %></dd>
|
41
43
|
<dt class="text-info">Price</dt>
|
42
44
|
<dd><%= price_details(@registration.workshop_price) %></dd>
|
43
45
|
<% if @registration.payment_comment %>
|
@@ -106,13 +108,17 @@
|
|
106
108
|
</tr>
|
107
109
|
<% if @registration.payment_owed.positive? %>
|
108
110
|
<tr class="section">
|
109
|
-
<th>
|
111
|
+
<th>Payment Owed
|
110
112
|
<% if @registration.workshop_price.recurring_payments? %>
|
111
113
|
<span style="font-weight: normal"></br>On a payment plan</span>
|
112
114
|
<% end %>
|
113
115
|
</th>
|
114
116
|
<td class="text-info"><%= @registration.payment_owed.format %></td>
|
115
117
|
</tr>
|
118
|
+
<tr>
|
119
|
+
<th>Payment Due On</th>
|
120
|
+
<td class="text-info"><%= format_date(@registration.last_payment_due_on) %></td>
|
121
|
+
</tr>
|
116
122
|
<% end %>
|
117
123
|
</table>
|
118
124
|
</div>
|
@@ -171,39 +177,77 @@
|
|
171
177
|
|
172
178
|
<%#--- Payments Tab %>
|
173
179
|
<div class="tab-pane fade" id="payment_tab">
|
174
|
-
|
175
|
-
<
|
176
|
-
|
180
|
+
<div class="row">
|
181
|
+
<div class="col-md-9 col-sm-9">
|
182
|
+
<%= subsection title: 'Recorded Payments' do %>
|
183
|
+
<table class="table table-condensed table-gradient table-hover" style="margin-bottom: 20px;">
|
184
|
+
<thead>
|
185
|
+
<tr>
|
186
|
+
<th width="100">Date</th>
|
187
|
+
<th>Description</th>
|
188
|
+
<th width="75">Paid</th>
|
189
|
+
<th width="100">Method</th>
|
190
|
+
<th width="18"><%= icons(:edit) %></th>
|
191
|
+
</tr>
|
192
|
+
</thead>
|
193
|
+
<tbody>
|
194
|
+
<% @registration.payment_histories.order('created_on ASC').each do |payment| %>
|
195
|
+
<tr>
|
196
|
+
<td><%= format_date(payment.payment_date) %></td>
|
197
|
+
<td><%= payment.item_ref %></td>
|
198
|
+
<td><%= payment.total.format(no_cents_if_whole: true, symbol: true) %></td>
|
199
|
+
<td><%= payment.payment_method %></td>
|
200
|
+
<td>
|
201
|
+
<% if payment.user_profile #--- only allow editing of manual payments %>
|
202
|
+
<%= link_to(icons('icon-pencil3'), '#', data: { toggle: "modal", target: "#edit_payment_#{payment.id}"}, title: 'Edit Payment') %>
|
203
|
+
<% end %>
|
204
|
+
</td>
|
205
|
+
</tr>
|
206
|
+
<% end %>
|
207
|
+
</tbody>
|
208
|
+
</table>
|
209
|
+
<%= link_to 'Add Payment', '#', data: { toggle: "modal", target: "#enter_new_payment"}, title: 'Add Payment', class: "btn btn-xs btn-primary" %>
|
210
|
+
<%= link_to 'Customer Payment Page', @registration.payment_url, target: '_blank', class: 'btn btn-xs btn-default' %>
|
211
|
+
<% if @registration.payment_owed.positive? %>
|
212
|
+
Next payment should be: <span class="text-info"><%= @registration.payment_owed.format %></span>
|
213
|
+
<% end %>
|
214
|
+
<% end %>
|
215
|
+
</div>
|
216
|
+
<div class="col-md-3 col-sm-3">
|
217
|
+
<table class="accounting" style="width: 100%">
|
177
218
|
<tr>
|
178
|
-
<th
|
179
|
-
<
|
180
|
-
<th width="75">Paid</th>
|
181
|
-
<th width="100">Method</th>
|
182
|
-
<th width="18"><%= icons(:edit) %></th>
|
219
|
+
<th>Price</th>
|
220
|
+
<td><%= @registration.price.format %></td>
|
183
221
|
</tr>
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
222
|
+
<tr>
|
223
|
+
<th>Discount</th>
|
224
|
+
<td class="text-danger"> - <%= @registration.discount.format %></td>
|
225
|
+
</tr>
|
226
|
+
<tr class="section">
|
227
|
+
<th>Total</th>
|
228
|
+
<td><strong><%= @registration.discounted_price.format %></strong></td>
|
229
|
+
</tr>
|
230
|
+
<tr>
|
231
|
+
<th>Paid</th>
|
232
|
+
<td class="text-success"><%= @registration.amount_paid.format %></td>
|
233
|
+
</tr>
|
234
|
+
<% if @registration.payment_owed.positive? %>
|
235
|
+
<tr class="section">
|
236
|
+
<th>Payment Owed
|
237
|
+
<% if @registration.workshop_price.recurring_payments? %>
|
238
|
+
<span style="font-weight: normal"></br>On a payment plan</span>
|
195
239
|
<% end %>
|
196
|
-
</
|
240
|
+
</th>
|
241
|
+
<td class="text-info"><%= @registration.payment_owed.format %></td>
|
242
|
+
</tr>
|
243
|
+
<tr>
|
244
|
+
<th>Payment Due On</th>
|
245
|
+
<td class="text-info"><%= format_date(@registration.last_payment_due_on) %></td>
|
197
246
|
</tr>
|
198
247
|
<% end %>
|
199
|
-
</
|
200
|
-
</
|
201
|
-
|
202
|
-
<%= link_to 'Customer Payment Page', @registration.payment_url, target: '_blank', class: 'btn btn-xs btn-default' %>
|
203
|
-
<% if @registration.payment_owed.positive? %>
|
204
|
-
Next payment should be: <span class="text-info"><%= @registration.payment_owed.format %></span>
|
205
|
-
<% end %>
|
206
|
-
<% end %>
|
248
|
+
</table>
|
249
|
+
</div>
|
250
|
+
</div>
|
207
251
|
|
208
252
|
<%= subsection title: 'Payment Reminders' do %>
|
209
253
|
<%= simple_form_for @registration, url: admin_registration_path,
|
@@ -85,27 +85,34 @@
|
|
85
85
|
</div>
|
86
86
|
</div>
|
87
87
|
|
88
|
-
<% unpaid = @workshop.registrations.unpaid.order('payment_reminder_sent_on ASC') %>
|
89
88
|
<% toolbar = toolbar_btn('Send Payment Reminders', send_payment_reminder_emails_admin_workshop_path(@workshop, registration_id: :all), class: 'btn btn-xs btn-info', method: :patch, data: {confirm: "Are you sure you wish to send a reminder email to those eligible?"}) %>
|
90
|
-
<%= panel body: false, title: "#{unpaid.count} Unpaid Participants", toolbar: toolbar do %>
|
89
|
+
<%= panel body: false, title: "#{@unpaid.count} Unpaid Participants", toolbar: toolbar do %>
|
90
|
+
<div class="panel-body">
|
91
|
+
<p>Shows those that have missed their payment (either a full payment, or a recurring payment). If they have made all the payments
|
92
|
+
up to this point in time, they are not listed.</p>
|
93
|
+
<p>You can send them a payment reminder email at any time using the <em>Send</em> button. A line is marked in blue if we have detected that
|
94
|
+
they should be sent a payment reminder. <em>Send Payment Reminders</em> will send the email to all persons marked in blue.</p>
|
95
|
+
</div>
|
91
96
|
<table class="table table-bordered table-condensed table-striped">
|
92
97
|
<thead>
|
93
98
|
<tr>
|
94
99
|
<th class="receipt_code">Receipt</th>
|
95
100
|
<th class="name">Name</th>
|
96
|
-
<th class="cost">Balance</th>
|
97
|
-
<th class="
|
101
|
+
<th class="cost">Balance Owed</th>
|
102
|
+
<th class="cost">Payment Due</th>
|
103
|
+
<th class="date">Payment Was Due On</th>
|
98
104
|
<th class="date">Reminded</th>
|
99
105
|
<th></th>
|
100
106
|
</tr>
|
101
107
|
</thead>
|
102
108
|
<tbody>
|
103
|
-
<% unpaid.each do |registration| -%>
|
109
|
+
<% @unpaid.each do |registration| -%>
|
104
110
|
<tr>
|
105
111
|
<td class="receipt_code" style="white-space:nowrap"><%= registration.receipt_code %></td>
|
106
112
|
<td class="name"><%= link_to registration.full_name, dm_event.edit_admin_registration_path(registration) %> </td>
|
107
113
|
<td class="cost"><%= registration.balance_owed.format %><%= content_tag(:span, icons('icon-bubble2 inside-content', size: 12), class: 'pull-right') if registration.private_comments.count > 0 %></td>
|
108
|
-
<td class="
|
114
|
+
<td class="cost"><%= registration.payment_owed.format %><%= " <sup>R</sup>".html_safe if registration.try(:workshop_price).try(:recurring_payments?) %></td>
|
115
|
+
<td class="date" style="white-space:nowrap"><%= format_date(registration.last_payment_due_on) %></td>
|
109
116
|
<td class="date" <%= "style='background-color: #B3D4FD;'".html_safe if registration.payment_reminder_due? %>>
|
110
117
|
<% if registration.payment_reminder_sent_on.nil? %>
|
111
118
|
not yet
|