caboose-cms 0.8.34 → 0.8.35

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 10b912cc8b30e8569dcb1f1d2e9b9282fbc8c4cb
4
- data.tar.gz: 4c7b76303acd61dfa695d381ccac0330520ebe25
3
+ metadata.gz: e580ca759518da7762c5cc5160d5de30136cad5d
4
+ data.tar.gz: 11c47056fb135a003a5b437760dfe0e859565231
5
5
  SHA512:
6
- metadata.gz: 5aa8fe51db11317e5a6570caba27576ee6855c633e0d9204c19dbbe885118edb2ba2342c4ef0df80fb0b640b180c6bf56b491987eed5423517ed7163a7703ca6
7
- data.tar.gz: 020d7efb4def9817166f65d9cc15f5b13bd0d5fcaa12d9acb5818d388eb2230840080ba649cf907ef9f3ce7f1444502f6e905796c1f2ad189d5c03e3c828504e
6
+ metadata.gz: 1b159c76555d47fb10f9bd58b89c806a8095bbce445a8704e7ee46841c6b057ea2ef5a75f68a1cd165d87e112823a02fbb1375890b883fc047dd9c340cd18d3e
7
+ data.tar.gz: f79ba2f659c609466058f6f49a341bcc615b447fd59d8d3758639b9079916b596e987ee49c9dfac6f7f334a76525d518d2593abef2b316d4a860a24b9a0da823
@@ -79,7 +79,7 @@ InvoiceController.prototype = {
79
79
  update_url: '/admin/invoices/' + op.invoice_id + '/packages/' + op.id,
80
80
  authenticity_token: that.authenticity_token,
81
81
  attributes: [
82
- { name: 'status' , nice_name: 'Status' , type: 'select' , value: op.status , width: 300, fixed_placeholder: true , options_url: '/admin/invoices/line-items/status-options' },
82
+ { name: 'status' , nice_name: 'Status' , type: 'select' , value: op.status , width: 300, fixed_placeholder: true , options_url: '/admin/invoices/line-items/status-options' },
83
83
  { name: 'package_method' , nice_name: 'Package/Method' , type: 'select' , value: op.shipping_package_id + '_' + op.shipping_method_id , width: 300, fixed_placeholder: false, options_url: '/admin/shipping-packages/package-method-options' },
84
84
  { name: 'tracking_number' , nice_name: 'Tracking Number' , type: 'text' , value: op.tracking_number , width: 300, fixed_placeholder: true, align: 'right' },
85
85
  { name: 'total' , nice_name: 'Shipping Total' , type: 'text' , value: curr(op.total) , width: 300, fixed_placeholder: true, align: 'right' , after_update: function() { that.refresh_invoice(); }}
@@ -93,9 +93,10 @@ InvoiceController.prototype = {
93
93
  update_url: '/admin/invoices/' + li.invoice_id + '/line-items/' + li.id,
94
94
  authenticity_token: that.authenticity_token,
95
95
  attributes: [
96
- { name: 'status' , nice_name: 'Status' , type: 'select' , align: 'left' , value: li.status , text: li.status, width: 150, fixed_placeholder: false, options_url: '/admin/invoices/line-items/status-options' },
97
- { name: 'tracking_number' , nice_name: 'Tracking Number' , type: 'text' , align: 'left' , value: li.tracking_number , width: 200, fixed_placeholder: false },
98
- { name: 'quantity' , nice_name: 'Quantity' , type: 'text' , align: 'right', value: li.quantity , width: 75, fixed_placeholder: false, after_update: function() { that.refresh_invoice(); } }
96
+ { name: 'status' , nice_name: 'Status' , type: 'select' , align: 'left' , value: li.status , text: li.status, width: 150, fixed_placeholder: false, options_url: '/admin/invoices/line-items/status-options' },
97
+ { name: 'tracking_number' , nice_name: 'Tracking Number' , type: 'text' , align: 'left' , value: li.tracking_number , width: 200, fixed_placeholder: false },
98
+ { name: 'unit_price' , nice_name: 'Unit Price' , type: 'text' , align: 'right', value: curr(li.unit_price) , width: 75, fixed_placeholder: false, after_update: function() { that.refresh_invoice(); } },
99
+ { name: 'quantity' , nice_name: 'Quantity' , type: 'text' , align: 'right', value: li.quantity , width: 75, fixed_placeholder: false, after_update: function() { that.refresh_invoice(); } }
99
100
  ]
100
101
  });
101
102
  });
@@ -105,11 +106,12 @@ InvoiceController.prototype = {
105
106
  update_url: '/admin/invoices/' + that.invoice.id,
106
107
  authenticity_token: that.authenticity_token,
107
108
  attributes: [
108
- { name: 'status' , nice_name: 'Status' , type: 'select', value: that.invoice.status , width: 100, fixed_placeholder: false, options_url: '/admin/invoices/status-options' },
109
- { name: 'payment_terms' , nice_name: 'Terms' , type: 'select', value: that.invoice.payment_terms , width: 200, fixed_placeholder: true , options_url: '/admin/invoices/payment-terms-options' },
110
- { name: 'tax' , nice_name: 'Tax' , type: 'text' , value: curr(that.invoice.tax) , width: 100, fixed_placeholder: false, align: 'right' , after_update: function() { that.refresh_invoice(); }},
111
- { name: 'handling' , nice_name: 'Handling' , type: 'text' , value: curr(that.invoice.handling) , width: 100, fixed_placeholder: false, align: 'right' , after_update: function() { that.refresh_invoice(); }},
112
- { name: 'custom_discount', nice_name: 'Discount' , type: 'text' , value: curr(that.invoice.custom_discount) , width: 100, fixed_placeholder: false, align: 'right' , after_update: function() { that.refresh_invoice(); }}
109
+ { name: 'status' , nice_name: 'Status' , type: 'select', value: that.invoice.status , width: 100, fixed_placeholder: false, options_url: '/admin/invoices/status-options' },
110
+ { name: 'financial_status' , nice_name: 'Status' , type: 'select', value: that.invoice.financial_status , width: 100, fixed_placeholder: true , width: 200, options_url: '/admin/invoices/financial-status-options' },
111
+ { name: 'payment_terms' , nice_name: 'Terms' , type: 'select', value: that.invoice.payment_terms , width: 200, fixed_placeholder: true , width: 200, options_url: '/admin/invoices/payment-terms-options' },
112
+ { name: 'tax' , nice_name: 'Tax' , type: 'text' , value: curr(that.invoice.tax) , width: 100, fixed_placeholder: false, align: 'right' , after_update: function() { that.refresh_invoice(); }},
113
+ { name: 'handling' , nice_name: 'Handling' , type: 'text' , value: curr(that.invoice.handling) , width: 100, fixed_placeholder: false, align: 'right' , after_update: function() { that.refresh_invoice(); }},
114
+ { name: 'custom_discount' , nice_name: 'Discount' , type: 'text' , value: curr(that.invoice.custom_discount) , width: 100, fixed_placeholder: false, align: 'right' , after_update: function() { that.refresh_invoice(); }}
113
115
  ]
114
116
  });
115
117
  },
@@ -227,7 +229,13 @@ InvoiceController.prototype = {
227
229
  {
228
230
  var that = this;
229
231
  window.open('/admin/invoices/' + that.invoice.id + '/print');
230
- },
232
+ },
233
+
234
+ print_invoice: function()
235
+ {
236
+ var that = this;
237
+ window.open('/admin/invoices/' + that.invoice.id + '/print');
238
+ },
231
239
 
232
240
  line_items_for_invoice_package: function(invoice_package_id)
233
241
  {
@@ -267,7 +275,7 @@ InvoiceController.prototype = {
267
275
  .append($('<th/>').html('Shipping Address'))
268
276
  .append($('<th/>').html('Billing Address'))
269
277
  .append($('<th/>').html('Invoice Status'))
270
- .append($('<th/>').html('Payment Status'))
278
+ .append($('<th/>').html('Payment'))
271
279
  );
272
280
  table.append($('<tr/>')
273
281
  .append($('<td/>').attr('valign', 'top')
@@ -285,6 +293,8 @@ InvoiceController.prototype = {
285
293
  .append($('<td/>').attr('valign', 'top').append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_status')))
286
294
  .append($('<td/>').attr('valign', 'top')
287
295
  .append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_payment_terms'))
296
+ .append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_payment_terms'))
297
+ .append($('<div/>').attr('id', 'invoice_' + that.invoice.id + '_financial_status'))
288
298
  .append($('<div/>').attr('id', 'transactions').attr('align', 'center').append(transactions))
289
299
  )
290
300
  );
@@ -494,7 +504,8 @@ InvoiceController.prototype = {
494
504
  .append($('<div/>').attr('id', 'line_item_' + li.id + '_message'))
495
505
  );
496
506
  tr.append($('<td/>').append($('<div/>').attr('id', 'lineitem_' + li.id + '_status')))
497
- tr.append($('<td/>').attr('align', 'right').html(curr(li.unit_price)));
507
+ //tr.append($('<td/>').attr('align', 'right').html(curr(li.unit_price)));
508
+ tr.append($('<td/>').attr('align', 'right').append($('<div/>').attr('id', 'lineitem_' + li.id + '_unit_price')));
498
509
  tr.append($('<td/>').attr('align', 'right').append($('<div/>').attr('id', 'lineitem_' + li.id + '_quantity')));
499
510
  tr.append($('<td/>').attr('align', 'right').attr('id', 'li_' + li.id + '_subtotal').html(curr(li.subtotal)));
500
511
  table.append(tr);
@@ -680,7 +691,8 @@ InvoiceController.prototype = {
680
691
  .append($('<div/>').attr('id', 'line_item_' + li.id + '_message'))
681
692
  );
682
693
  tr.append($('<td/>').append($('<div/>').attr('id', 'lineitem_' + li.id + '_status')))
683
- tr.append($('<td/>').attr('align', 'right').html(curr(li.unit_price)));
694
+ //tr.append($('<td/>').attr('align', 'right').html(curr(li.unit_price)));
695
+ tr.append($('<td/>').attr('align', 'right').append($('<div/>').attr('id', 'lineitem_' + li.id + '_unit_price')));
684
696
  tr.append($('<td/>').attr('align', 'right').append($('<div/>').attr('id', 'lineitem_' + li.id + '_quantity')));
685
697
  tr.append($('<td/>').attr('align', 'right').attr('id', 'li_' + li.id + '_subtotal').html(curr(li.subtotal)));
686
698
  table.append(tr);
@@ -737,10 +749,11 @@ InvoiceController.prototype = {
737
749
  var p = $('<p/>');
738
750
  p.append($('<input/>').attr('type', 'button').val('< Back').click(function() { window.location = '/admin/invoices'; })).append(' ');
739
751
  if (that.invoice.total > 0 && that.invoice.financial_status == 'pending')
740
- p.append($('<input/>').attr('type', 'button').val('Send for Authorization').click(function() { that.send_for_authorization(); })).append(' ');
741
- //p.append($('<input/>').attr('type', 'button').val('Resend Confirmation' ).click(function() { that.resend_confirmation(); })).append(' ');
742
- p.append($('<input/>').attr('type', 'button').val('Add Item' ).click(function() { that.add_variant(); })).append(' ');
743
- p.append($('<input/>').attr('type', 'button').val('Print Invoice' ).click(function() { that.print_invoice(); })).append(' ');
752
+ p.append($('<input/>').attr('type', 'button').val('Send for Payment').click(function() { that.send_for_authorization(); })).append(' ');
753
+ if (that.invoice.total > 0 && (that.invoice.financial_status == 'captured' || that.invoice.financial_status == 'paid by check' || that.invoice.financial_status == 'paid by other means'))
754
+ p.append($('<input/>').attr('type', 'button').val('Send Receipt to Customer' ).click(function() { that.send_receipt(); })).append(' ');
755
+ p.append($('<input/>').attr('type', 'button').val('Add Item' ).click(function() { that.add_variant(); })).append(' ');
756
+ p.append($('<input/>').attr('type', 'button').val('Print Invoice' ).click(function() { that.print_invoice(); })).append(' ');
744
757
  $('#controls').empty().append(p);
745
758
  },
746
759
 
@@ -842,8 +855,8 @@ InvoiceController.prototype = {
842
855
  {
843
856
  var that = this;
844
857
  var div = $('<div/>')
845
- .append($('<span/>').attr('id', 'financial_status').append(that.invoice.financial_status)).append(' ')
846
- .append($('<a/>').attr('href', '#').html('refresh').click(function(e) { e.preventDefault(); that.refresh_transactions(); }))
858
+ //.append($('<span/>').attr('id', 'financial_status').append(that.invoice.financial_status)).append(' ')
859
+ .append($('<a/>').attr('href', '#').html('refresh transactions').click(function(e) { e.preventDefault(); that.refresh_transactions(); }))
847
860
  .append($('<div/>').attr('id', 'transactions_message'));
848
861
  if (that.invoice.invoice_transactions.length > 0)
849
862
  {
@@ -1000,6 +1013,29 @@ InvoiceController.prototype = {
1000
1013
  }
1001
1014
  });
1002
1015
  },
1016
+
1017
+ send_receipt: function(confirm)
1018
+ {
1019
+ var that = this;
1020
+ if (!confirm)
1021
+ {
1022
+ var p = $('<p/>').addClass('note confirm')
1023
+ .append("Are you sure you want to send a receipt to the customer? ")
1024
+ .append($('<input/>').attr('type','button').val('Yes').click(function() { that.send_receipt(true); }))
1025
+ .append(' ')
1026
+ .append($('<input/>').attr('type','button').val('No').click(function() { $('#message').empty(); }));
1027
+ $('#message').empty().append(p);
1028
+ return;
1029
+ }
1030
+ $('#message').html("<p class='loading'>Sending receipt...</p>");
1031
+ $.ajax({
1032
+ url: '/admin/invoices/' + that.invoice.id + '/send-receipt',
1033
+ success: function(resp) {
1034
+ if (resp.error) { that.flash_error(resp.error); }
1035
+ if (resp.success) { that.refresh(function() { that.flash_success("A receipt email has been sent successfully to the customer."); }); }
1036
+ }
1037
+ });
1038
+ },
1003
1039
 
1004
1040
  calculate_tax: function()
1005
1041
  {
@@ -67,44 +67,44 @@ module Caboose
67
67
  render :json => resp
68
68
  end
69
69
 
70
- # @route PUT /admin/invoices/:invoice_id/line-items/:id
71
- def admin_update_line_item
72
- return if !user_is_allowed('invoices', 'edit')
73
-
74
- resp = Caboose::StdClass.new({'attributes' => {}})
75
- li = LineItem.find(params[:id])
76
-
77
- save = true
78
- send_status_email = false
79
- params.each do |name,value|
80
- case name
81
- when 'quantity'
82
- li.quantity = value
83
- li.save
84
-
85
- # Recalculate everything
86
- r = ShippingCalculator.rate(li.invoice, li.invoice.shipping_method_code)
87
- li.invoice.shipping = r['negotiated_rate'] / 100
88
- li.invoice.handling = (r['negotiated_rate'] / 100) * 0.05
89
- li.invoice.tax = TaxCalculator.tax(li.invoice)
90
- li.invoice.calculate_total
91
- li.invoice.save
92
-
93
- when 'tracking_number'
94
- li.tracking_number = value
95
- send_status_email = true
96
- when 'status'
97
- li.status = value
98
- resp.attributes['status'] = {'text' => value}
99
- send_status_email = true
100
- end
101
- end
102
- if send_status_email
103
- InvoicesMailer.configure_for_site(@site.id).customer_status_updated(li.invoice).deliver
104
- end
105
- resp.success = save && li.save
106
- render :json => resp
107
- end
70
+ # @ route PUT /admin/invoices/:invoice_id/line-items/:id
71
+ #def admin_update_line_item
72
+ # return if !user_is_allowed('invoices', 'edit')
73
+ #
74
+ # resp = Caboose::StdClass.new({'attributes' => {}})
75
+ # li = LineItem.find(params[:id])
76
+ #
77
+ # save = true
78
+ # send_status_email = false
79
+ # params.each do |name,value|
80
+ # case name
81
+ # when 'quantity'
82
+ # li.quantity = value
83
+ # li.save
84
+ #
85
+ # # Recalculate everything
86
+ # r = ShippingCalculator.rate(li.invoice, li.invoice.shipping_method_code)
87
+ # li.invoice.shipping = r['negotiated_rate'] / 100
88
+ # li.invoice.handling = (r['negotiated_rate'] / 100) * 0.05
89
+ # li.invoice.tax = TaxCalculator.tax(li.invoice)
90
+ # li.invoice.calculate_total
91
+ # li.invoice.save
92
+ #
93
+ # when 'tracking_number'
94
+ # li.tracking_number = value
95
+ # send_status_email = true
96
+ # when 'status'
97
+ # li.status = value
98
+ # resp.attributes['status'] = {'text' => value}
99
+ # send_status_email = true
100
+ # end
101
+ # end
102
+ # if send_status_email
103
+ # InvoicesMailer.configure_for_site(@site.id).customer_status_updated(li.invoice).deliver
104
+ # end
105
+ # resp.success = save && li.save
106
+ # render :json => resp
107
+ #end
108
108
 
109
109
  # @route DELETE /admin/invoices/:invoice_id/packages/:id
110
110
  def admin_delete
@@ -189,26 +189,27 @@ module Caboose
189
189
 
190
190
  resp = Caboose::StdClass.new({'attributes' => {}})
191
191
  invoice = Invoice.find(params[:id])
192
-
192
+
193
193
  save = true
194
- params.each do |name,value|
194
+ params.each do |name,value|
195
195
  case name
196
- when 'tax' then
196
+ when 'tax'
197
197
  invoice.tax = value
198
198
  invoice.total = invoice.calculate_total
199
- when 'handling' then
199
+ when 'handling'
200
200
  invoice.handling = value
201
201
  invoice.total = invoice.calculate_total
202
- when 'custom_discount' then
202
+ when 'custom_discount'
203
203
  invoice.custom_discount = value
204
204
  invoice.discount = invoice.calculate_discount
205
205
  invoice.total = invoice.calculate_total
206
- when 'status' then
206
+ when 'status'
207
207
  invoice.status = value
208
- if value == 'Shipped'
209
- invoice.date_shipped = DateTime.now.utc
210
- end
211
- when 'customer_id' then invoice.customer_id = value
208
+ invoice.date_shipped = DateTime.now.utc if value == 'Shipped'
209
+ when 'financial_status'
210
+ invoice.financial_status = value
211
+ when 'customer_id'
212
+ invoice.customer_id = value
212
213
  end
213
214
  end
214
215
 
@@ -216,7 +217,7 @@ module Caboose
216
217
  #invoice.calculate_total
217
218
  #resp.attributes['total'] = { 'value' => invoice.total }
218
219
 
219
- resp.success = save && invoice.save
220
+ resp.success = save && invoice.save
220
221
  render :json => resp
221
222
  end
222
223
 
@@ -237,6 +238,14 @@ module Caboose
237
238
  render :json => { :success => true }
238
239
  end
239
240
 
241
+ # @route GET /admin/invoices/:id/send-receipt
242
+ def admin_send_for_authorization
243
+ return if !user_is_allowed('invoices', 'edit')
244
+ invoice = Invoice.find(params[:id])
245
+ invoice.delay(:queue => 'caboose_store').send_receipt_email
246
+ render :json => { :success => true }
247
+ end
248
+
240
249
  # @route GET /admin/invoices/city-report
241
250
  def admin_city_report
242
251
  return if !user_is_allowed('invoices', 'view')
@@ -273,7 +282,18 @@ module Caboose
273
282
  Invoice::STATUS_SHIPPED,
274
283
  Invoice::STATUS_CANCELED
275
284
  ]
276
- options = statuses.collect{ |s| { 'text' => s.capitalize, 'value' => s }}
285
+ options = statuses.collect{ |s| { 'text' => s.capitalize, 'value' => s }}
286
+ when 'financial-status'
287
+ statuses = [
288
+ Invoice::FINANCIAL_STATUS_PENDING ,
289
+ Invoice::FINANCIAL_STATUS_AUTHORIZED ,
290
+ Invoice::FINANCIAL_STATUS_CAPTURED ,
291
+ Invoice::FINANCIAL_STATUS_REFUNDED ,
292
+ Invoice::FINANCIAL_STATUS_VOIDED ,
293
+ Invoice::FINANCIAL_STATUS_PAID_BY_CHECK ,
294
+ Invoice::FINANCIAL_STATUS_PAID_BY_OTHER_MEANS
295
+ ]
296
+ options = statuses.collect{ |s| { 'text' => s.capitalize, 'value' => s }}
277
297
  when 'payment-terms'
278
298
  options = [
279
299
  { 'value' => Invoice::PAYMENT_TERMS_PIA , 'text' => 'Pay In Advance' },
@@ -46,21 +46,26 @@ module Caboose
46
46
  case name
47
47
  when 'invoice_id' then li.invoice_id = value
48
48
  when 'invoice_package_id' then li.invoice_package_id = value
49
- when 'variant_id' then li.variant_id = value
50
- when 'parent_id' then li.parent_id = value
51
- #when 'unit_price' then li.unit_price = value
52
- #when 'subtotal' then li.subtotal = value
53
- when 'notes' then li.notes = value
54
- when 'custom1' then li.custom1 = value
55
- when 'custom2' then li.custom2 = value
56
- when 'custom3' then li.custom3 = value
57
- when 'quantity'
58
- li.quantity = value
49
+ when 'variant_id' then li.variant_id = value
50
+ when 'parent_id' then li.parent_id = value
51
+ #when 'subtotal' then li.subtotal = value
52
+ when 'notes' then li.notes = value
53
+ when 'custom1' then li.custom1 = value
54
+ when 'custom2' then li.custom2 = value
55
+ when 'custom3' then li.custom3 = value
56
+ when 'unit_price'
57
+ Caboose.log("li.unit_price = #{li.unit_price}")
58
+ li.unit_price = value
59
+ li.save
60
+ Caboose.log("li.unit_price = #{li.unit_price}")
59
61
  li.subtotal = li.unit_price * li.quantity
60
-
61
62
  li.save
62
-
63
-
63
+ li.invoice.subtotal = li.invoice.calculate_subtotal
64
+ li.invoice.total = li.invoice.calculate_total
65
+ when 'quantity'
66
+ li.quantity = value
67
+ li.subtotal = li.unit_price * li.quantity
68
+ li.save
64
69
  li.invoice.subtotal = li.invoice.calculate_subtotal
65
70
  li.invoice.total = li.invoice.calculate_total
66
71
 
@@ -269,19 +269,24 @@ module Caboose
269
269
  return if !user_is_allowed('users', 'sudo')
270
270
  user = User.find(params[:id])
271
271
 
272
- # See if we're on the default domain
273
- d = Caboose::Domain.where(:domain => request.host_with_port).first
274
-
275
- if d.primary == true
276
- logout_user
277
- login_user(user, false) # Login the new user
278
- redirect_to "/"
279
- end
280
-
281
- # Set a random token for the user
282
- user.token = (0...20).map { ('a'..'z').to_a[rand(26)] }.join
283
- user.save
284
- redirect_to "http://#{d.site.primary_domain.domain}/admin/users/#{params[:id]}/su/#{user.token}"
272
+ ## See if we're on the default domain
273
+ #d = Caboose::Domain.where(:domain => request.host_with_port).first
274
+ #
275
+ #if d.primary == true
276
+ # logout_user
277
+ # login_user(user, false) # Login the new user
278
+ # redirect_to "/"
279
+ #end
280
+ #
281
+ ## Set a random token for the user
282
+ #user.token = (0...20).map { ('a'..'z').to_a[rand(26)] }.join
283
+ #user.save
284
+ #
285
+ #redirect_to "http://#{d.site.primary_domain.domain}/admin/users/#{params[:id]}/su/#{user.token}"
286
+
287
+ logout_user
288
+ login_user(user, false) # Login the new user
289
+ redirect_to "/"
285
290
  end
286
291
 
287
292
  # @route GET /admin/users/:id/su/:token
@@ -47,7 +47,13 @@ module Caboose
47
47
  # Sends an email to the customer telling them they need to authorize payment on an invoice
48
48
  def customer_payment_authorization(invoice)
49
49
  @invoice = invoice
50
- mail(:to => invoice.customer.email, :subject => "Order #{@invoice.invoice_number} ready for payment")
50
+ mail(:to => invoice.customer.email, :subject => "Invoice #{@invoice.invoice_number} ready for payment")
51
+ end
52
+
53
+ # Sends an email to the customer telling them they need to authorize payment on an invoice
54
+ def customer_receipt(invoice)
55
+ @invoice = invoice
56
+ mail(:to => invoice.customer.email, :subject => "Invoice #{@invoice.invoice_number} receipt")
51
57
  end
52
58
  end
53
59
  end
@@ -66,12 +66,14 @@ module Caboose
66
66
  #STATUS_CANCELED = 'Canceled'
67
67
  #STATUS_WAIVED = 'Waived'
68
68
 
69
- FINANCIAL_STATUS_PENDING = 'pending'
70
- FINANCIAL_STATUS_AUTHORIZED = 'authorized'
71
- FINANCIAL_STATUS_CAPTURED = 'captured'
72
- FINANCIAL_STATUS_REFUNDED = 'refunded'
73
- FINANCIAL_STATUS_VOIDED = 'voided'
74
-
69
+ FINANCIAL_STATUS_PENDING = 'pending'
70
+ FINANCIAL_STATUS_AUTHORIZED = 'authorized'
71
+ FINANCIAL_STATUS_CAPTURED = 'captured'
72
+ FINANCIAL_STATUS_REFUNDED = 'refunded'
73
+ FINANCIAL_STATUS_VOIDED = 'voided'
74
+ FINANCIAL_STATUS_PAID_BY_CHECK = 'paid by check'
75
+ FINANCIAL_STATUS_PAID_BY_OTHER_MEANS = 'paid by other means'
76
+
75
77
  PAYMENT_TERMS_PIA = 'pia'
76
78
  PAYMENT_TERMS_NET7 = 'net7'
77
79
  PAYMENT_TERMS_NET10 = 'net10'
@@ -104,7 +106,7 @@ module Caboose
104
106
  }
105
107
 
106
108
  validates :financial_status, :inclusion => {
107
- :in => ['pending', 'authorized', 'captured', 'refunded', 'voided'],
109
+ :in => ['pending', 'authorized', 'captured', 'refunded', 'voided', 'paid by check', 'paid by other means'],
108
110
  :message => "%{value} is not a valid financial status. Must be 'authorized', 'captured', 'refunded' or 'voided'"
109
111
  }
110
112
 
@@ -489,6 +491,10 @@ module Caboose
489
491
  InvoicesMailer.configure_for_site(self.site_id).customer_payment_authorization(self).deliver
490
492
  end
491
493
 
494
+ def send_receipt_email
495
+ InvoicesMailer.configure_for_site(self.site_id).customer_receipt(self).deliver
496
+ end
497
+
492
498
  def determine_statuses
493
499
 
494
500
  auth = false
@@ -647,67 +653,69 @@ module Caboose
647
653
  case sc.pp_name
648
654
  when StoreConfig::PAYMENT_PROCESSOR_STRIPE
649
655
 
650
- Stripe.api_key = sc.stripe_secret_key.strip
651
- charges = Stripe::Charge.list(:limit => 100, :customer => self.customer.stripe_customer_id)
652
-
653
- self.financial_status = Invoice::FINANCIAL_STATUS_PENDING
654
- charges.each do |c|
655
- invoice_id = c.metadata && c.metadata['invoice_id'] ? c.metadata['invoice_id'].to_i : nil
656
- next if invoice_id.nil? || invoice_id != self.id
656
+ if sc.stripe_secret_key && sc.stripe_secret_key.strip.length > 0
657
+ Stripe.api_key = sc.stripe_secret_key.strip
658
+ charges = Stripe::Charge.list(:limit => 100, :customer => self.customer.stripe_customer_id)
657
659
 
658
- if c.refunded then self.financial_status = Invoice::FINANCIAL_STATUS_REFUNDED
659
- elsif c.status == 'succeeded' && c.captured then self.financial_status = Invoice::FINANCIAL_STATUS_CAPTURED
660
- elsif c.status == 'succeeded' then self.financial_status = Invoice::FINANCIAL_STATUS_AUTHORIZED
661
- end
662
-
663
- auth_trans = InvoiceTransaction.create(
664
- :invoice_id => self.id,
665
- :transaction_id => c.id,
666
- :transaction_type => c.captured ? InvoiceTransaction::TYPE_AUTHCAP : InvoiceTransaction::TYPE_AUTHORIZE,
667
- :payment_processor => sc.pp_name,
668
- :amount => c.amount / 100.0,
669
- :amount_refunded => c.amount_refunded,
670
- :date_processed => DateTime.strptime(c.created.to_s, '%s'),
671
- :success => c.status == 'succeeded',
672
- :captured => c.captured,
673
- :refunded => c.refunded
674
- )
675
- if c.balance_transaction
676
- bt = Stripe::BalanceTransaction.retrieve(c.balance_transaction)
677
- capture_trans = InvoiceTransaction.create(
660
+ self.financial_status = Invoice::FINANCIAL_STATUS_PENDING
661
+ charges.each do |c|
662
+ invoice_id = c.metadata && c.metadata['invoice_id'] ? c.metadata['invoice_id'].to_i : nil
663
+ next if invoice_id.nil? || invoice_id != self.id
664
+
665
+ if c.refunded then self.financial_status = Invoice::FINANCIAL_STATUS_REFUNDED
666
+ elsif c.status == 'succeeded' && c.captured then self.financial_status = Invoice::FINANCIAL_STATUS_CAPTURED
667
+ elsif c.status == 'succeeded' then self.financial_status = Invoice::FINANCIAL_STATUS_AUTHORIZED
668
+ end
669
+
670
+ auth_trans = InvoiceTransaction.create(
678
671
  :invoice_id => self.id,
679
- :parent_id => auth_trans.id,
680
- :transaction_id => bt.id,
681
- :transaction_type => InvoiceTransaction::TYPE_CAPTURE,
672
+ :transaction_id => c.id,
673
+ :transaction_type => c.captured ? InvoiceTransaction::TYPE_AUTHCAP : InvoiceTransaction::TYPE_AUTHORIZE,
682
674
  :payment_processor => sc.pp_name,
683
- :amount => bt.amount / 100.0,
684
- :date_processed => DateTime.strptime(bt.created.to_s, '%s'),
685
- :success => bt.status == 'succeeded' || bt.status == 'pending'
686
- )
687
- end
688
- if c.refunds && c.refunds['total_count'] > 0
689
- total = 0
690
- c.refunds['data'].each do |r|
691
- total = total + r.amount
692
- InvoiceTransaction.create(
675
+ :amount => c.amount / 100.0,
676
+ :amount_refunded => c.amount_refunded,
677
+ :date_processed => DateTime.strptime(c.created.to_s, '%s'),
678
+ :success => c.status == 'succeeded',
679
+ :captured => c.captured,
680
+ :refunded => c.refunded
681
+ )
682
+ if c.balance_transaction
683
+ bt = Stripe::BalanceTransaction.retrieve(c.balance_transaction)
684
+ capture_trans = InvoiceTransaction.create(
693
685
  :invoice_id => self.id,
694
- :parent_id => auth_trans.id,
695
- :transaction_id => r.id,
696
- :transaction_type => InvoiceTransaction::TYPE_REFUND,
686
+ :parent_id => auth_trans.id,
687
+ :transaction_id => bt.id,
688
+ :transaction_type => InvoiceTransaction::TYPE_CAPTURE,
697
689
  :payment_processor => sc.pp_name,
698
- :amount => r.amount / 100.0,
699
- :date_processed => DateTime.strptime(r.created.to_s, '%s'),
700
- :success => r.status == 'succeeded' || r.status == 'pending'
701
- )
690
+ :amount => bt.amount / 100.0,
691
+ :date_processed => DateTime.strptime(bt.created.to_s, '%s'),
692
+ :success => bt.status == 'succeeded' || bt.status == 'pending'
693
+ )
702
694
  end
703
- total = total.to_f / 100
704
- if total >= auth_trans.amount
705
- auth_trans.refunded = true
706
- auth_trans.save
695
+ if c.refunds && c.refunds['total_count'] > 0
696
+ total = 0
697
+ c.refunds['data'].each do |r|
698
+ total = total + r.amount
699
+ InvoiceTransaction.create(
700
+ :invoice_id => self.id,
701
+ :parent_id => auth_trans.id,
702
+ :transaction_id => r.id,
703
+ :transaction_type => InvoiceTransaction::TYPE_REFUND,
704
+ :payment_processor => sc.pp_name,
705
+ :amount => r.amount / 100.0,
706
+ :date_processed => DateTime.strptime(r.created.to_s, '%s'),
707
+ :success => r.status == 'succeeded' || r.status == 'pending'
708
+ )
709
+ end
710
+ total = total.to_f / 100
711
+ if total >= auth_trans.amount
712
+ auth_trans.refunded = true
713
+ auth_trans.save
714
+ end
707
715
  end
708
716
  end
717
+ self.save
709
718
  end
710
- self.save
711
719
  end
712
720
  end
713
721
 
@@ -4,7 +4,7 @@ module Caboose
4
4
  class TaxCalculator
5
5
 
6
6
  def self.custom_tax(store_config, invoice)
7
- return eval(store_config.custom_tax_function)
7
+ return store_config.custom_tax_function && store_config.custom_tax_function.strip.length > 0 ? eval(store_config.custom_tax_function) : 0.00
8
8
  end
9
9
 
10
10
  def self.tax(invoice)
@@ -0,0 +1,75 @@
1
+ <p><img src='<%= @invoice.site.logo.url(:thumb) %>' /></p>
2
+
3
+ <h1>Receipt</h1>
4
+
5
+ <p>
6
+ Invoice #<%= @invoice.id %><br />
7
+ Status: <% @invoice.status %><br />
8
+ Financial status: <% @invoice.financial_status %>
9
+ </p>
10
+
11
+ <table border='1' style='border-collapse: collapse;'>
12
+ <tr>
13
+ <th>Line Item</th>
14
+ <th>Unit Price</th>
15
+ <th>Quantity</th>
16
+ <th>Subtotal</th>
17
+ </tr>
18
+ <% @invoice.line_items.each do |li| %>
19
+ <% v = li.variant %>
20
+ <% p = v.product %>
21
+ <tr>
22
+ <td>
23
+ <p><%= p.title %></td></p>
24
+ <% if li.is_gift %>
25
+ <p>This item is a gift.</p>
26
+ <ul>
27
+ <li><% if li.gift_wrap %>Gift wrap (<%= number_to_currency(p.gift_wrap_price) %>)<% else %>Do not gift wrap<% end %></li>
28
+ <li><% if li.include_gift_message %>Gift message: <%= li.gift_message %><% else %>No gift message<% end %></li>
29
+ <li><% if li.hide_prices %>Hide all prices<% else %>Show all prices<% end %></li>
30
+ </ul>
31
+ <% end %>
32
+ </td>
33
+ <td align='right'><%= number_to_currency(li.unit_price) %></td>
34
+ <td align='right'><%= li.quantity %></td>
35
+ <td align='right'><%= number_to_currency(li.subtotal) %></td>
36
+ </tr>
37
+ <% end %>
38
+ <tr><td colspan="4" align='right'>Subtotal: </td><td align='right'><%= number_to_currency(@invoice.subtotal) %></td></tr>
39
+ <tr><td colspan="4" align='right'>Tax: </td><td align='right'><%= number_to_currency(@invoice.tax) %></td></tr>
40
+ <tr><td colspan="4" align='right'>Shipping and Handling: </td><td align='right'><%= number_to_currency(@invoice.shipping + @invoice.handling) %></td></tr>
41
+ <% if @invoice.gift_wrap && @invoice.gift_wrap > 0 %>
42
+ <tr><td colspan="4" align='right'>Gift wrap: </td><td align='right'><%= number_to_currency(@invoice.gift_wrap) %></td></tr>
43
+ <% end %>
44
+ <% if @invoice.discounts %>
45
+ <% @invoice.discounts.each do |d| %>
46
+ <tr><td colspan="4" align='right'>"<%= d.gift_card.code %>" gift card: </td><td align='right'><%= number_to_currency(d.amount) %></td></tr>
47
+ <% end %>
48
+ <% end %>
49
+ <% if @invoice.custom_discount %>
50
+ <tr><td colspan="4" align='right'>Discount: </td><td align='right'><%= number_to_currency(@invoice.custom_discount) %></td></tr>
51
+ <% end %>
52
+ <tr><td colspan="4" align='right'>Total: </td><td align='right'><%= number_to_currency(@invoice.total) %></td></tr>
53
+ </table>
54
+
55
+ <% if @invoice.shipping_address %>
56
+ <% sa = @invoice.shipping_address %>
57
+ <h2>Shipping Address</h2>
58
+ <p>
59
+ <%= sa.first_name %> <%= sa.last_name %><br />
60
+ <%= sa.address1 %><br />
61
+ <% if sa.address2 && sa.address2.strip.length > 0 %><%= sa.address2 %><br /><% end %>
62
+ <%= sa.city %>, <%= sa.state %> <%= sa.zip %>
63
+ </p>
64
+ <% end %>
65
+
66
+ <% if @invoice.billing_address %>
67
+ <% ba = @invoice.billing_address %>
68
+ <h2>Billing Address</h2>
69
+ <p>
70
+ <%= ba.first_name %> <%= ba.last_name %><br />
71
+ <%= ba.address1 %><br />
72
+ <% if ba.address2 && ba.address2.strip.length > 0 %><%= ba.address2 %><br /><% end %>
73
+ <%= ba.city %>, <%= ba.state %> <%= ba.zip %>
74
+ </p>
75
+ <% end %>
@@ -1,3 +1,3 @@
1
1
  module Caboose
2
- VERSION = '0.8.34'
2
+ VERSION = '0.8.35'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: caboose-cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.34
4
+ version: 0.8.35
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Barry
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-03 00:00:00.000000000 Z
11
+ date: 2016-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pg
@@ -1057,6 +1057,7 @@ files:
1057
1057
  - app/views/caboose/invoices/admin_summary_report.html.erb
1058
1058
  - app/views/caboose/invoices_mailer/customer_new_invoice.html.erb
1059
1059
  - app/views/caboose/invoices_mailer/customer_payment_authorization.html.erb
1060
+ - app/views/caboose/invoices_mailer/customer_receipt.html.erb
1060
1061
  - app/views/caboose/invoices_mailer/customer_status_updated.html.erb
1061
1062
  - app/views/caboose/invoices_mailer/fulfillment_new_invoice.html.erb
1062
1063
  - app/views/caboose/invoices_mailer/shipping_invoice_ready.html.erb