caboose-cms 0.8.64 → 0.8.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/assets/javascripts/caboose/my_account_edit_invoice.js +80 -16
- data/app/assets/javascripts/caboose/my_account_payment_method_controller.js +175 -0
- data/app/assets/stylesheets/caboose/my_account_edit_invoice.css.scss +1 -1
- data/app/controllers/caboose/#checkout_controller.rb# +464 -0
- data/app/controllers/caboose/invoices_controller.rb +2 -1
- data/app/controllers/caboose/my_account_invoices_controller.rb +81 -1
- data/app/mailers/caboose/invoices_mailer.rb +2 -2
- data/app/models/caboose/invoice.rb +3 -1
- data/app/views/caboose/my_account_invoices/edit.html.erb +19 -0
- data/lib/caboose/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e6a4ba5943295734cab32b17d7fdbfa8dd72711d
|
|
4
|
+
data.tar.gz: 88ff9aec8169a808c90b0b9ed97e63816638be5e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ec41548d7130692a7754d55d62703cf5d17266222a4b2215da0c4bdc5179f8f5722868ad7878d7340a3248de76cfb1c2839e9eed03e21fd12927fc85695d56d8
|
|
7
|
+
data.tar.gz: b50b104307b57b2839efbfc1460be7922d6967150c91e00daf2d455f4d1b27b0afcbf435ed17746094ec3362166f623931c915ed3ced32c5b38303dff4f64b57
|
|
@@ -14,6 +14,7 @@ MyAccountInvoiceController.prototype = {
|
|
|
14
14
|
|
|
15
15
|
var that = this;
|
|
16
16
|
$('#payment_form').hide();
|
|
17
|
+
|
|
17
18
|
$(document).ready(function() { that.refresh(); });
|
|
18
19
|
},
|
|
19
20
|
|
|
@@ -21,9 +22,13 @@ MyAccountInvoiceController.prototype = {
|
|
|
21
22
|
{
|
|
22
23
|
var that = this;
|
|
23
24
|
that.refresh_invoice(function() {
|
|
25
|
+
if (that.invoice.financial_status == 'pending')
|
|
26
|
+
that.payment_method_controller = new MyAccountPaymentMethodController({ ic: that });
|
|
27
|
+
|
|
24
28
|
$('#invoice_table').html("<p class='loading'>Getting invoice...</p>");
|
|
25
29
|
that.print();
|
|
26
|
-
|
|
30
|
+
|
|
31
|
+
if (after) after();
|
|
27
32
|
});
|
|
28
33
|
},
|
|
29
34
|
|
|
@@ -79,6 +84,9 @@ MyAccountInvoiceController.prototype = {
|
|
|
79
84
|
if (count_downloadable > 0) that.downloadable_line_items_table(table);
|
|
80
85
|
that.summary_table(table);
|
|
81
86
|
$('#invoice_table').empty().append(table);
|
|
87
|
+
|
|
88
|
+
if (that.invoice.financial_status == 'pending')
|
|
89
|
+
that.payment_method_controller.print();
|
|
82
90
|
}
|
|
83
91
|
else
|
|
84
92
|
{
|
|
@@ -96,7 +104,8 @@ MyAccountInvoiceController.prototype = {
|
|
|
96
104
|
var fstatus = $('<div/>').append($('<p/>').html(capitalize_first_letter(that.invoice.financial_status)));
|
|
97
105
|
if (that.invoice.financial_status == 'pending')
|
|
98
106
|
{
|
|
99
|
-
fstatus.append($('<
|
|
107
|
+
fstatus.append($('<div/>').attr('id', 'payment_method_container'));
|
|
108
|
+
//fstatus.append($('<p/>').append($('<input/>').attr('type', 'button').addClass('btn').val('Pay now').click(function(e) { e.preventDefault(); that.payment_form(); })));
|
|
100
109
|
}
|
|
101
110
|
|
|
102
111
|
var table = $('<table/>').addClass('invoice');
|
|
@@ -424,32 +433,87 @@ MyAccountInvoiceController.prototype = {
|
|
|
424
433
|
},
|
|
425
434
|
|
|
426
435
|
/****************************************************************************/
|
|
436
|
+
|
|
437
|
+
confirm_invoice: function()
|
|
438
|
+
{
|
|
439
|
+
var that = this;
|
|
440
|
+
var cust = that.invoice.customer;
|
|
441
|
+
var form = $('#payment_form');
|
|
442
|
+
var message = $('#payment_message');
|
|
443
|
+
|
|
444
|
+
if (form.is(':visible'))
|
|
445
|
+
{
|
|
446
|
+
form.slideUp(function() { form.empty(); });
|
|
447
|
+
message.empty();
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
form.append($('<h4/>').append("Confirm payment"));
|
|
452
|
+
form.append($('<p/>').html("A payment of $" + curr(that.invoice.total) + " will be charged to your " + cust.card_brand + ' ending in ' + cust.card_last4 + "."));
|
|
453
|
+
|
|
454
|
+
form.append($('<input/>').attr('type', 'button').addClass('btn').val('Pay Now').click(function(e)
|
|
455
|
+
{
|
|
456
|
+
e.preventDefault();
|
|
457
|
+
message.empty().html("<p class='loading'>Processing payment...</p>");
|
|
458
|
+
|
|
459
|
+
$.ajax({
|
|
460
|
+
url: '/my-account/confirm',
|
|
461
|
+
type: 'post',
|
|
462
|
+
data: { id: that.invoice.id},
|
|
463
|
+
success: function(resp) {
|
|
464
|
+
if (resp.success == true)
|
|
465
|
+
{
|
|
466
|
+
form.slideUp(function() { form.empty(); });
|
|
467
|
+
message.empty().html("<p class='note success'>" + resp.message + "</p>");
|
|
468
|
+
setTimeout(function() { message.empty() }, 5000);
|
|
469
|
+
that.refresh();
|
|
470
|
+
}
|
|
471
|
+
else {
|
|
472
|
+
message.empty().html("<p class='note error'>" + resp.error + "</p>");
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
));
|
|
478
|
+
|
|
479
|
+
form.slideDown();
|
|
480
|
+
},
|
|
427
481
|
|
|
428
482
|
payment_form: function()
|
|
429
483
|
{
|
|
430
|
-
var that
|
|
431
|
-
var form
|
|
484
|
+
var that = this;
|
|
485
|
+
var form = $('#payment_form');
|
|
486
|
+
var message = $('#payment_message')
|
|
432
487
|
if (form.is(':visible'))
|
|
433
488
|
{
|
|
434
489
|
form.slideUp(function() { form.empty(); });
|
|
435
|
-
|
|
490
|
+
message.empty();
|
|
436
491
|
return;
|
|
437
492
|
}
|
|
438
493
|
|
|
439
|
-
|
|
494
|
+
message.empty().html("<p class='loading'>Processing payment...</p>");
|
|
440
495
|
$.ajax({
|
|
441
496
|
url: '/my-account/invoices/' + that.invoice.id + '/payment-form',
|
|
442
497
|
type: 'get',
|
|
443
|
-
success: function(
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
498
|
+
success: function(resp) {
|
|
499
|
+
if (resp.success == true)
|
|
500
|
+
{
|
|
501
|
+
message.empty().html("<p class='note success'>" + resp.message + "</p>");
|
|
502
|
+
setTimeout(function() { message.empty() }, 5000);
|
|
503
|
+
that.refresh();
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
message.empty().html("<p class='note error'>" + resp.error + "</p>");
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// form.empty().append(html);
|
|
510
|
+
// form.slideDown();
|
|
511
|
+
// $('#payment_confirm').click(function(e) {
|
|
512
|
+
// $('#expiration').val($('#month').val() + $('#year').val());
|
|
513
|
+
// $('#payment_message').empty().html("<p class='loading'>Processing payment...</p>");
|
|
514
|
+
// $('#payment_form').slideUp();
|
|
515
|
+
// $('#payment').submit();
|
|
516
|
+
// });
|
|
453
517
|
}
|
|
454
518
|
});
|
|
455
519
|
},
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
|
|
2
|
+
var MyAccountPaymentMethodController = function(params) { this.init(params); };
|
|
3
|
+
|
|
4
|
+
MyAccountPaymentMethodController.prototype = {
|
|
5
|
+
|
|
6
|
+
container: 'payment_method_container',
|
|
7
|
+
stripe_key: false,
|
|
8
|
+
customer_id: false,
|
|
9
|
+
card_brand: false,
|
|
10
|
+
card_last4: false,
|
|
11
|
+
card_name: false,
|
|
12
|
+
card_zip: false,
|
|
13
|
+
ic: false,
|
|
14
|
+
|
|
15
|
+
init: function(params)
|
|
16
|
+
{
|
|
17
|
+
var that = this;
|
|
18
|
+
for (var i in params)
|
|
19
|
+
that[i] = params[i];
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
refresh: function(after)
|
|
23
|
+
{
|
|
24
|
+
var that = this;
|
|
25
|
+
$.ajax({
|
|
26
|
+
url: '/checkout/stripe/json',
|
|
27
|
+
type: 'get',
|
|
28
|
+
success: function(resp) {
|
|
29
|
+
that.stripe_key = resp.stripe_key;
|
|
30
|
+
that.customer_id = resp.customer_id;
|
|
31
|
+
that.card_brand = resp.card_brand;
|
|
32
|
+
that.card_last4 = resp.card_last4;
|
|
33
|
+
//that.cc.print_ready_message();
|
|
34
|
+
if (after) after();
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
print: function()
|
|
40
|
+
{
|
|
41
|
+
var that = this;
|
|
42
|
+
if (!that.stripe_key)
|
|
43
|
+
{
|
|
44
|
+
that.refresh(function() { that.print(); });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
var msg = that.card_brand && that.card_last4 ? that.card_brand + ' ending in ' + that.card_last4 : 'You have no card on file.';
|
|
48
|
+
var div = $('<div/>');
|
|
49
|
+
|
|
50
|
+
if (that.ic.invoice.financial_status == 'pending') {
|
|
51
|
+
if (that.card_brand && that.card_last4) {
|
|
52
|
+
div.append($('<p/>').append($('<input/>').attr('type', 'button').addClass('btn').val('Confirm').click(function(e) { e.preventDefault(); that.ic.refresh_invoice( function() { that.ic.confirm_invoice(); }); })));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (that.ic.invoice.total > 0.00)
|
|
57
|
+
{
|
|
58
|
+
var msg = that.card_brand && that.card_last4 ? that.card_brand + ' ending in ' + that.card_last4 : 'You have no card on file.';
|
|
59
|
+
div.append($('<p/>')
|
|
60
|
+
.append(msg).append(' ')
|
|
61
|
+
.append($('<a/>').attr('href', '#').html('Edit').click(function(e) { e.preventDefault(); that.edit(); })
|
|
62
|
+
));
|
|
63
|
+
}
|
|
64
|
+
else
|
|
65
|
+
{
|
|
66
|
+
div.append($('<p/>')
|
|
67
|
+
.append("No payment is required at this time. ")
|
|
68
|
+
.append($('<a/>').attr('href', '#').html('Edit').click(function(e) { e.preventDefault(); that.edit(); })
|
|
69
|
+
));
|
|
70
|
+
}
|
|
71
|
+
$('#'+that.container).empty().append(div);
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
edit: function()
|
|
75
|
+
{
|
|
76
|
+
var that = this;
|
|
77
|
+
|
|
78
|
+
if (that.ic.invoice.total <= 0.00)
|
|
79
|
+
{
|
|
80
|
+
that.print();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var form = $('<form/>')
|
|
85
|
+
.attr('action', '')
|
|
86
|
+
.attr('method', 'post')
|
|
87
|
+
.attr('id', 'stripe_form')
|
|
88
|
+
.addClass('stripe_form')
|
|
89
|
+
.submit(function(e) { e.preventDefault(); that.update(); return false; });
|
|
90
|
+
|
|
91
|
+
form.append($('<div/>').addClass('card_number_container')
|
|
92
|
+
.append($('<input/>').attr('id', 'card_number').attr('type', 'tel').attr('autocomplete', 'off').attr('autocorrect', 'off').attr('spellcheck', 'off').attr('autocapitalize', 'off').attr('placeholder', 'Card number'))
|
|
93
|
+
.append($('<div/>').addClass('svg icon').css('width', '30px').css('height', '30px').html('<svg version="1.1" viewBox="0 0 30 30" width="30" height="30" focusable="false"><g fill-rule="evenodd"><path d="M2.00585866,0 C0.898053512,0 0,0.900176167 0,1.99201702 L0,9.00798298 C0,10.1081436 0.897060126,11 2.00585866,11 L11.9941413,11 C13.1019465,11 14,10.0998238 14,9.00798298 L14,1.99201702 C14,0.891856397 13.1029399,0 11.9941413,0 L2.00585866,0 Z M2.00247329,1 C1.44882258,1 1,1.4463114 1,1.99754465 L1,9.00245535 C1,9.55338405 1.45576096,10 2.00247329,10 L11.9975267,10 C12.5511774,10 13,9.5536886 13,9.00245535 L13,1.99754465 C13,1.44661595 12.544239,1 11.9975267,1 L2.00247329,1 Z M1,3 L1,5 L13,5 L13,3 L1,3 Z M11,8 L11,9 L12,9 L12,8 L11,8 Z M9,8 L9,9 L10,9 L10,8 L9,8 Z M9,8" style="fill:#3b6faa" transform="translate(8,10)"></g></svg>')));
|
|
94
|
+
form.append($('<div/>').addClass('card_exp_container')
|
|
95
|
+
.append($('<input/>').attr('id', 'card_exp').attr('type', 'tel').attr('autocomplete', 'off').attr('autocorrect', 'off').attr('spellcheck', 'off').attr('autocapitalize', 'off').attr('placeholder', 'MM / YY').attr('x-autocompletetype', 'off').attr('autocompletetype', 'off'))
|
|
96
|
+
.append($('<div/>').addClass('svg icon').css('width', '30px').css('height', '30px').html('<svg version="1.1" viewBox="0 0 30 30" width="30" height="30" focusable="false"><g fill-rule="evenodd"><path d="M2.0085302,1 C0.899249601,1 0,1.90017617 0,2.99201702 L0,10.007983 C0,11.1081436 0.901950359,12 2.0085302,12 L9.9914698,12 C11.1007504,12 12,11.0998238 12,10.007983 L12,2.99201702 C12,1.8918564 11.0980496,1 9.9914698,1 L2.0085302,1 Z M1.99539757,4 C1.44565467,4 1,4.43788135 1,5.00292933 L1,9.99707067 C1,10.5509732 1.4556644,11 1.99539757,11 L10.0046024,11 C10.5543453,11 11,10.5621186 11,9.99707067 L11,5.00292933 C11,4.44902676 10.5443356,4 10.0046024,4 L1.99539757,4 Z M3,1 L3,2 L4,2 L4,1 L3,1 Z M8,1 L8,2 L9,2 L9,1 L8,1 Z M3,0 L3,1 L4,1 L4,0 L3,0 Z M8,0 L8,1 L9,1 L9,0 L8,0 Z M8,0" style="fill:#3b6faa" transform="translate(8,9)"></g></svg>')));
|
|
97
|
+
form.append($('<div/>').addClass('card_cvc_container')
|
|
98
|
+
.append($('<input>').attr('id', 'card_cvc').attr('type', 'tel').attr('autocomplete', 'off').attr('autocorrect', 'off').attr('spellcheck', 'off').attr('autocapitalize', 'off').attr('placeholder', 'CVC').attr('maxlength', '4'))
|
|
99
|
+
.append($('<div>').addClass('svg icon').css('width', '30px').css('height', '30px').html('<svg version="1.1" viewBox="0 0 30 30" width="30" height="30" focusable="false"><g fill-rule="evenodd"><path d="M8.8,4 C8.8,1.79086089 7.76640339,4.18628304e-07 5.5,0 C3.23359661,-4.1480896e-07 2.2,1.79086089 2.2,4 L3.2,4 C3.2,2.34314567 3.81102123,0.999999681 5.5,1 C7.18897877,1.00000032 7.80000001,2.34314567 7.80000001,4 L8.8,4 Z M1.99201702,4 C0.891856397,4 0,4.88670635 0,5.99810135 L0,10.0018986 C0,11.1054196 0.900176167,12 1.99201702,12 L9.00798298,12 C10.1081436,12 11,11.1132936 11,10.0018986 L11,5.99810135 C11,4.89458045 10.0998238,4 9.00798298,4 L1.99201702,4 Z M1.99754465,5 C1.44661595,5 1,5.45097518 1,5.99077797 L1,10.009222 C1,10.5564136 1.4463114,11 1.99754465,11 L9.00245535,11 C9.55338405,11 10,10.5490248 10,10.009222 L10,5.99077797 C10,5.44358641 9.5536886,5 9.00245535,5 L1.99754465,5 Z M1.99754465,5" style="fill:#3b6faa" transform="translate(9,9)"></g></svg>')));
|
|
100
|
+
form.append($('<div/>').addClass('card_name_container')
|
|
101
|
+
.append($('<input/>').attr('id', 'card_name').attr('type', 'text').attr('autocomplete', 'off').attr('autocorrect', 'off').attr('spellcheck', 'off').attr('autocapitalize', 'on').attr('placeholder', 'Name on card')));
|
|
102
|
+
form.append($('<div/>').addClass('card_zip_container')
|
|
103
|
+
.append($('<input/>').attr('id', 'card_zip').attr('type', 'tel').attr('autocomplete', 'off').attr('autocorrect', 'off').attr('spellcheck', 'off').attr('autocapitalize', 'on').attr('placeholder', 'Zip code')));
|
|
104
|
+
form.append($('<div/>').attr('id', 'payment_message'))
|
|
105
|
+
form.append($('<p/>').addClass('payment_controls')
|
|
106
|
+
.append($('<input/>').attr('type', 'button').attr('id', 'cancel_payment_btn').val('Cancel' ).click(function(e) { that.print(); })).append(' ')
|
|
107
|
+
.append($('<input/>').attr('type', 'submit').attr('id', 'save_payment_btn').val('Save' ))
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
$('#payment_method_container').empty().append(form);
|
|
111
|
+
|
|
112
|
+
$('#stripe_form .card_number_container input').payment('formatCardNumber');
|
|
113
|
+
$('#stripe_form .card_exp_container input').payment('formatCardExpiry');
|
|
114
|
+
$('#stripe_form .card_cvc_container input').payment('formatCardCVC');
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
update: function()
|
|
118
|
+
{
|
|
119
|
+
var that = this;
|
|
120
|
+
var info = {
|
|
121
|
+
number: $('#card_number').val(),
|
|
122
|
+
exp: $('#card_exp').val(),
|
|
123
|
+
cvc: $('#card_cvc').val(),
|
|
124
|
+
name: $('card_name').val(),
|
|
125
|
+
address_zip: $('card_zip').val()
|
|
126
|
+
};
|
|
127
|
+
var exp = info.exp.split('/');
|
|
128
|
+
var m = exp.length > 0 ? exp[0] : '';
|
|
129
|
+
var y = exp.length > 1 ? exp[1] : '';
|
|
130
|
+
var error = false;
|
|
131
|
+
if (!$.payment.validateCardNumber(info.number)) error = "Invalid card number.";
|
|
132
|
+
if (!$.payment.validateCardExpiry(m, y)) error = "Invalid expiration date.";
|
|
133
|
+
if (!$.payment.validateCardCVC(info.cvc)) error = "Invalid CVC.";
|
|
134
|
+
if (error) { $('#payment_message').html("<p class='note error'>" + error + "</p>"); return; }
|
|
135
|
+
|
|
136
|
+
$('#save_payment_btn').attr('disabled', 'true').val('Saving card...');
|
|
137
|
+
Stripe.setPublishableKey(that.stripe_key);
|
|
138
|
+
Stripe.card.createToken(info, function(status, resp) {
|
|
139
|
+
if (resp.error)
|
|
140
|
+
{
|
|
141
|
+
$('#save_payment_btn').attr('disabled', 'false').val('Save Payment Method');
|
|
142
|
+
$('#payment_message').html("<p class='note error'>" + resp.error.message + "</p>");
|
|
143
|
+
}
|
|
144
|
+
else
|
|
145
|
+
{
|
|
146
|
+
that.card_brand = resp.card.brand;
|
|
147
|
+
that.card_last4 = resp.card.last4;
|
|
148
|
+
$.ajax({
|
|
149
|
+
url: '/checkout/stripe-details',
|
|
150
|
+
type: 'put',
|
|
151
|
+
data: { token: resp.id, card: resp.card },
|
|
152
|
+
success: function(resp2) {
|
|
153
|
+
if (resp2.success)
|
|
154
|
+
{
|
|
155
|
+
that.customer_id = resp2.customer_id;
|
|
156
|
+
that.print();
|
|
157
|
+
//that.cc.print_ready_message();
|
|
158
|
+
}
|
|
159
|
+
if (resp2.error) $('#payment_message').html("<p class='note error'>" + resp2.error + "</p>");
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
ready: function()
|
|
167
|
+
{
|
|
168
|
+
var that = this;
|
|
169
|
+
if (that.ic.invoice.total <= 0.00) return true;
|
|
170
|
+
if (!that.customer_id ) return false;
|
|
171
|
+
if (!that.card_brand ) return false;
|
|
172
|
+
if (!that.card_last4 ) return false;
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
};
|
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
require 'authorize_net'
|
|
2
|
+
|
|
3
|
+
module Caboose
|
|
4
|
+
class CheckoutController < Caboose::ApplicationController
|
|
5
|
+
|
|
6
|
+
before_filter :ensure_line_items, :only => [:step_one, :step_two]
|
|
7
|
+
protect_from_forgery
|
|
8
|
+
|
|
9
|
+
def ensure_line_items
|
|
10
|
+
redirect_to '/checkout/empty' if @invoice.line_items.empty?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @route GET /checkout/json
|
|
14
|
+
def invoice_json
|
|
15
|
+
render :json => @invoice.as_json(
|
|
16
|
+
:include => [
|
|
17
|
+
:customer,
|
|
18
|
+
:shipping_address,
|
|
19
|
+
:billing_address,
|
|
20
|
+
:invoice_transactions,
|
|
21
|
+
{
|
|
22
|
+
:line_items => {
|
|
23
|
+
:include => {
|
|
24
|
+
:variant => {
|
|
25
|
+
:include => [
|
|
26
|
+
{ :product_images => { :methods => :urls }},
|
|
27
|
+
{ :product => { :include => { :product_images => { :methods => :urls }}}}
|
|
28
|
+
],
|
|
29
|
+
:methods => :title
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{ :invoice_packages => { :include => [:shipping_package, :shipping_method] }},
|
|
35
|
+
{ :discounts => { :include => :gift_card }}
|
|
36
|
+
]
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @route GET /checkout/stripe/json
|
|
41
|
+
def stripe_json
|
|
42
|
+
sc = @site.store_config
|
|
43
|
+
u = logged_in_user
|
|
44
|
+
render :json => {
|
|
45
|
+
:stripe_key => sc.stripe_publishable_key.strip,
|
|
46
|
+
:customer_id => u.stripe_customer_id,
|
|
47
|
+
:card_last4 => u.card_last4,
|
|
48
|
+
:card_brand => u.card_brand,
|
|
49
|
+
:card_exp_month => u.card_exp_month,
|
|
50
|
+
:card_exp_year => u.card_exp_year
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
#===========================================================================
|
|
55
|
+
|
|
56
|
+
# Step 1 - Login or register
|
|
57
|
+
# @route GET /checkout
|
|
58
|
+
def index
|
|
59
|
+
if logged_in?
|
|
60
|
+
if @invoice.customer_id.nil?
|
|
61
|
+
@invoice.customer_id = logged_in_user.id
|
|
62
|
+
@invoice.save
|
|
63
|
+
end
|
|
64
|
+
#redirect_to '/checkout/addresses'
|
|
65
|
+
#return
|
|
66
|
+
|
|
67
|
+
@invoice.verify_invoice_packages
|
|
68
|
+
|
|
69
|
+
# See if any there are any empty invoice packages
|
|
70
|
+
#@invoice.invoice_packages.each do |op|
|
|
71
|
+
# count = 0
|
|
72
|
+
# @invoice.line_items.each do |li|
|
|
73
|
+
# count = count + 1 if li.invoice_package_id == op.id
|
|
74
|
+
# end
|
|
75
|
+
# op.destroy if count == 0
|
|
76
|
+
#end
|
|
77
|
+
#
|
|
78
|
+
## See if any line items aren't associated with an invoice package
|
|
79
|
+
#line_items_attached = true
|
|
80
|
+
#@invoice.line_items.each do |li|
|
|
81
|
+
# line_items_attached = false if li.invoice_package_id.nil?
|
|
82
|
+
#end
|
|
83
|
+
#
|
|
84
|
+
#ops = @invoice.invoice_packages
|
|
85
|
+
#if ops.count == 0 || !line_items_attached
|
|
86
|
+
# @invoice.calculate
|
|
87
|
+
# LineItem.where(:invoice_id => @invoice.id).update_all(:invoice_package_id => nil)
|
|
88
|
+
# InvoicePackage.where(:invoice_id => @invoice.id).destroy_all
|
|
89
|
+
# InvoicePackage.create_for_invoice(@invoice)
|
|
90
|
+
#end
|
|
91
|
+
|
|
92
|
+
#render :file => "caboose/checkout/checkout_#{@site.store_config.pp_name}"
|
|
93
|
+
render :file => "caboose/checkout/checkout"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Step 3 - Shipping method
|
|
98
|
+
# @route GET /checkout/shipping/json
|
|
99
|
+
def shipping_json
|
|
100
|
+
render :json => { :error => 'Not logged in.' } and return if !logged_in?
|
|
101
|
+
render :json => { :error => 'No shippable items.' } and return if !@invoice.has_shippable_items?
|
|
102
|
+
render :json => { :error => 'Empty shipping address.' } and return if @invoice.shipping_address.nil?
|
|
103
|
+
|
|
104
|
+
@invoice.calculate
|
|
105
|
+
|
|
106
|
+
#ops = @invoice.invoice_packages
|
|
107
|
+
#if params[:recalculate_invoice_packages] || ops.count == 0
|
|
108
|
+
# # Remove any invoice packages
|
|
109
|
+
# LineItem.where(:invoice_id => @invoice.id).update_all(:invoice_package_id => nil)
|
|
110
|
+
# InvoicePackage.where(:invoice_id => @invoice.id).destroy_all
|
|
111
|
+
#
|
|
112
|
+
# # Calculate what shipping packages we'll need
|
|
113
|
+
# InvoicePackage.create_for_invoice(@invoice)
|
|
114
|
+
#end
|
|
115
|
+
|
|
116
|
+
# Now get the rates for those packages
|
|
117
|
+
rates = ShippingCalculator.rates(@invoice)
|
|
118
|
+
render :json => rates
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Step 5 - Update Stripe Details
|
|
122
|
+
# @route PUT /checkout/stripe-details
|
|
123
|
+
def update_stripe_details
|
|
124
|
+
render :json => false and return if !logged_in?
|
|
125
|
+
|
|
126
|
+
sc = @site.store_config
|
|
127
|
+
Stripe.api_key = sc.stripe_secret_key.strip
|
|
128
|
+
|
|
129
|
+
u = logged_in_user
|
|
130
|
+
|
|
131
|
+
c = nil
|
|
132
|
+
if u.stripe_customer_id
|
|
133
|
+
c = Stripe::Customer.retrieve(u.stripe_customer_id)
|
|
134
|
+
begin
|
|
135
|
+
c.source = params[:token]
|
|
136
|
+
c.save
|
|
137
|
+
rescue
|
|
138
|
+
c = nil
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
if c.nil?
|
|
143
|
+
c = Stripe::Customer.create(
|
|
144
|
+
:source => params[:token],
|
|
145
|
+
:email => u.email,
|
|
146
|
+
:metadata => { :user_id => u.id }
|
|
147
|
+
)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
u.stripe_customer_id = c.id
|
|
151
|
+
u.card_last4 = params[:card][:last4]
|
|
152
|
+
u.card_brand = params[:card][:brand]
|
|
153
|
+
u.card_exp_month = params[:card][:exp_month]
|
|
154
|
+
u.card_exp_year = params[:card][:exp_year]
|
|
155
|
+
u.save
|
|
156
|
+
|
|
157
|
+
render :json => {
|
|
158
|
+
:success => true,
|
|
159
|
+
:customer_id => u.stripe_customer_id
|
|
160
|
+
}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# @route POST /checkout/confirm
|
|
164
|
+
def confirm
|
|
165
|
+
render :json => { :error => 'Not logged in.' } and return if !logged_in?
|
|
166
|
+
#render :json => { :error => 'Invalid billing address.' } and return if @invoice.billing_address.nil?
|
|
167
|
+
render :json => { :error => 'Invalid shipping address.' } and return if @invoice.has_shippable_items? && @invoice.shipping_address.nil?
|
|
168
|
+
render :json => { :error => 'Invalid shipping methods.' } and return if @invoice.has_shippable_items? && @invoice.has_empty_shipping_methods?
|
|
169
|
+
|
|
170
|
+
resp = Caboose::StdClass.new
|
|
171
|
+
sc = @site.store_config
|
|
172
|
+
|
|
173
|
+
# Make sure all the variants still exist
|
|
174
|
+
@invoice.line_items.each do |li|
|
|
175
|
+
v = Variant.where(:id => li.variant_id).first
|
|
176
|
+
if v.nil? || v.status == 'Deleted'
|
|
177
|
+
render :json => { :error => 'One or more of the products you are purchasing are no longer available.' }
|
|
178
|
+
return
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
error = false
|
|
183
|
+
requires_payment = @invoice.line_items.count > 0 && @invoice.total > 0 && @invoice.payment_terms == Invoice::PAYMENT_TERMS_PIA
|
|
184
|
+
if requires_payment
|
|
185
|
+
|
|
186
|
+
ot = nil
|
|
187
|
+
case sc.pp_name
|
|
188
|
+
when StoreConfig::PAYMENT_PROCESSOR_AUTHNET
|
|
189
|
+
|
|
190
|
+
when StoreConfig::PAYMENT_PROCESSOR_STRIPE
|
|
191
|
+
Stripe.api_key = sc.stripe_secret_key.strip
|
|
192
|
+
begin
|
|
193
|
+
c = Stripe::Charge.create(
|
|
194
|
+
:amount => (@invoice.total * 100).to_i,
|
|
195
|
+
:currency => 'usd',
|
|
196
|
+
:customer => logged_in_user.stripe_customer_id,
|
|
197
|
+
:capture => false,
|
|
198
|
+
:metadata => { :invoice_id => @invoice.id },
|
|
199
|
+
:statement_descriptor => "Invoice ##{@invoice.id}"
|
|
200
|
+
)
|
|
201
|
+
rescue Exception => ex
|
|
202
|
+
render :json => { :error => ex.message }
|
|
203
|
+
return
|
|
204
|
+
end
|
|
205
|
+
ot = Caboose::InvoiceTransaction.create(
|
|
206
|
+
:invoice_id => @invoice.id,
|
|
207
|
+
:transaction_id => c.id,
|
|
208
|
+
:transaction_type => c.captured ? Caboose::InvoiceTransaction::TYPE_AUTHCAP : Caboose::InvoiceTransaction::TYPE_AUTHORIZE,
|
|
209
|
+
:payment_processor => sc.pp_name,
|
|
210
|
+
:amount => c.amount/100.0,
|
|
211
|
+
:date_processed => DateTime.now.utc,
|
|
212
|
+
:success => c.status == 'succeeded'
|
|
213
|
+
)
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
if !ot.success
|
|
217
|
+
render :json => { :error => error }
|
|
218
|
+
return
|
|
219
|
+
else
|
|
220
|
+
@invoice.financial_status = Invoice::FINANCIAL_STATUS_AUTHORIZED
|
|
221
|
+
@invoice.take_gift_card_funds
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
@invoice.status = Invoice::STATUS_PENDING
|
|
226
|
+
@invoice.invoice_number = @site.store_config.next_invoice_number
|
|
227
|
+
|
|
228
|
+
# Send out emails
|
|
229
|
+
begin
|
|
230
|
+
InvoicesMailer.configure_for_site(@site.id).customer_new_invoice(@invoice).deliver
|
|
231
|
+
InvoicesMailer.configure_for_site(@site.id).fulfillment_new_invoice(@invoice).deliver
|
|
232
|
+
rescue
|
|
233
|
+
puts "=================================================================="
|
|
234
|
+
puts "Error sending out invoice confirmation emails for invoice ID #{@invoice.id}"
|
|
235
|
+
puts "=================================================================="
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Emit invoice event
|
|
239
|
+
Caboose.plugin_hook('invoice_authorized', @invoice) if @invoice.total > 0
|
|
240
|
+
|
|
241
|
+
# Save the invoice
|
|
242
|
+
@invoice.save
|
|
243
|
+
|
|
244
|
+
# Decrement quantities of variants
|
|
245
|
+
@invoice.decrement_quantities
|
|
246
|
+
|
|
247
|
+
# Clear the cart and re-initialize
|
|
248
|
+
session[:cart_id] = nil
|
|
249
|
+
init_cart
|
|
250
|
+
|
|
251
|
+
resp.success = true
|
|
252
|
+
resp.redirect = '/checkout/thanks'
|
|
253
|
+
render :json => resp
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# @route GET /checkout/thanks
|
|
257
|
+
def thanks
|
|
258
|
+
@logged_in_user = logged_in_user
|
|
259
|
+
|
|
260
|
+
# Find the last invoice for the user
|
|
261
|
+
@last_invoice = Invoice.where(:customer_id => @logged_in_user.id).reorder("id desc").limit(1).first
|
|
262
|
+
add_ga_event('Ecommerce', 'Checkout', 'Payment', (@last_invoice.total*100).to_i)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
#===========================================================================
|
|
266
|
+
|
|
267
|
+
# @route GET /checkout/state-options
|
|
268
|
+
def state_options
|
|
269
|
+
options = Caboose::States.all.collect { |abbr, state| { 'value' => abbr, 'text' => abbr }}
|
|
270
|
+
render :json => options
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# @route GET /checkout/total
|
|
274
|
+
def verify_total
|
|
275
|
+
total = 0.00
|
|
276
|
+
if logged_in?
|
|
277
|
+
@invoice.calculate
|
|
278
|
+
total = @invoice.total
|
|
279
|
+
end
|
|
280
|
+
render :json => total.to_f
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# @route GET /checkout/address
|
|
284
|
+
def address
|
|
285
|
+
render :json => {
|
|
286
|
+
:shipping_address => @invoice.shipping_address,
|
|
287
|
+
:billing_address => @invoice.billing_address
|
|
288
|
+
}
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# @route PUT /checkout/addresses
|
|
292
|
+
def update_addresses
|
|
293
|
+
|
|
294
|
+
# Grab or create addresses
|
|
295
|
+
shipping_address = if @invoice.shipping_address then @invoice.shipping_address else Address.new end
|
|
296
|
+
billing_address = if @invoice.billing_address then @invoice.billing_address else Address.new end
|
|
297
|
+
|
|
298
|
+
has_shippable_items = @invoice.has_shippable_items?
|
|
299
|
+
|
|
300
|
+
# Shipping address
|
|
301
|
+
if has_shippable_items
|
|
302
|
+
shipping_address.first_name = params[:shipping][:first_name]
|
|
303
|
+
shipping_address.last_name = params[:shipping][:last_name]
|
|
304
|
+
shipping_address.company = params[:shipping][:company]
|
|
305
|
+
shipping_address.address1 = params[:shipping][:address1]
|
|
306
|
+
shipping_address.address2 = params[:shipping][:address2]
|
|
307
|
+
shipping_address.city = params[:shipping][:city]
|
|
308
|
+
shipping_address.state = params[:shipping][:state]
|
|
309
|
+
shipping_address.zip = params[:shipping][:zip]
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Billing address
|
|
313
|
+
if has_shippable_items && params[:use_as_billing]
|
|
314
|
+
billing_address.update_attributes(shipping_address.attributes)
|
|
315
|
+
else
|
|
316
|
+
billing_address.first_name = params[:billing][:first_name]
|
|
317
|
+
billing_address.last_name = params[:billing][:last_name]
|
|
318
|
+
billing_address.company = params[:billing][:company]
|
|
319
|
+
billing_address.address1 = params[:billing][:address1]
|
|
320
|
+
billing_address.address2 = params[:billing][:address2]
|
|
321
|
+
billing_address.city = params[:billing][:city]
|
|
322
|
+
billing_address.state = params[:billing][:state]
|
|
323
|
+
billing_address.zip = params[:billing][:zip]
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Save address info; generate ids
|
|
327
|
+
render :json => { :success => false, :errors => shipping_address.errors.full_messages, :address => 'shipping' } and return if has_shippable_items && !shipping_address.save
|
|
328
|
+
render :json => { :success => false, :errors => billing_address.errors.full_messages, :address => 'billing' } and return if !billing_address.save
|
|
329
|
+
|
|
330
|
+
# Associate address info with invoice
|
|
331
|
+
@invoice.shipping_address_id = shipping_address.id
|
|
332
|
+
@invoice.billing_address_id = billing_address.id
|
|
333
|
+
|
|
334
|
+
#render :json => { :redirect => 'checkout/shipping' }
|
|
335
|
+
render :json => { :success => @invoice.save, :errors => @invoice.errors.full_messages }
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
# @route PUT /checkout/shipping-address
|
|
339
|
+
def update_shipping_address
|
|
340
|
+
resp = Caboose::StdClass.new
|
|
341
|
+
|
|
342
|
+
# Grab or create addresses
|
|
343
|
+
sa = @invoice.shipping_address
|
|
344
|
+
if sa.nil?
|
|
345
|
+
sa = Address.create
|
|
346
|
+
@invoice.shipping_address_id = sa.id
|
|
347
|
+
@invoice.save
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
save = true
|
|
351
|
+
recalc_shipping = false
|
|
352
|
+
params.each do |name, value|
|
|
353
|
+
case name
|
|
354
|
+
when 'address1' then recalc_shipping = true if sa.address1 != value
|
|
355
|
+
when 'address2' then recalc_shipping = true if sa.address2 != value
|
|
356
|
+
when 'city' then recalc_shipping = true if sa.city != value
|
|
357
|
+
when 'state' then recalc_shipping = true if sa.state != value
|
|
358
|
+
when 'zip' then recalc_shipping = true if sa.zip != value
|
|
359
|
+
end
|
|
360
|
+
case name
|
|
361
|
+
when 'name' then sa.name = value
|
|
362
|
+
when 'first_name' then sa.first_name = value
|
|
363
|
+
when 'last_name' then sa.last_name = value
|
|
364
|
+
when 'street' then sa.street = value
|
|
365
|
+
when 'address1' then sa.address1 = value
|
|
366
|
+
when 'address2' then sa.address2 = value
|
|
367
|
+
when 'company' then sa.company = value
|
|
368
|
+
when 'city' then sa.city = value
|
|
369
|
+
when 'state' then sa.state = value
|
|
370
|
+
when 'province' then sa.province = value
|
|
371
|
+
when 'province_code' then sa.province_code = value
|
|
372
|
+
when 'zip' then sa.zip = value
|
|
373
|
+
when 'country' then sa.country = value
|
|
374
|
+
when 'country_code' then sa.country_code = value
|
|
375
|
+
when 'phone' then sa.phone = value
|
|
376
|
+
end
|
|
377
|
+
end
|
|
378
|
+
if recalc_shipping
|
|
379
|
+
@invoice.invoice_packages.each do |op|
|
|
380
|
+
op.shipping_method_id = nil
|
|
381
|
+
op.total = nil
|
|
382
|
+
op.save
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
resp.success = save && sa.save
|
|
387
|
+
render :json => resp
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# @route PUT /checkout/billing-address
|
|
391
|
+
def update_billing_address
|
|
392
|
+
|
|
393
|
+
# Grab or create addresses
|
|
394
|
+
ba = @invoice.billing_address
|
|
395
|
+
if ba.nil?
|
|
396
|
+
ba = Address.create
|
|
397
|
+
@invoice.billing_address_id = ba.id
|
|
398
|
+
@invoice.save
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
ba.first_name = params[:first_name]
|
|
402
|
+
ba.last_name = params[:last_name]
|
|
403
|
+
ba.company = params[:company]
|
|
404
|
+
ba.address1 = params[:address1]
|
|
405
|
+
ba.address2 = params[:address2]
|
|
406
|
+
ba.city = params[:city]
|
|
407
|
+
ba.state = params[:state]
|
|
408
|
+
ba.zip = params[:zip]
|
|
409
|
+
ba.save
|
|
410
|
+
|
|
411
|
+
render :json => { :success => true }
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
# @route POST /checkout/attach-user
|
|
415
|
+
def attach_user
|
|
416
|
+
render :json => { :success => false, :errors => ['User is not logged in'] } and return if !logged_in?
|
|
417
|
+
@invoice.customer_id = logged_in_user.id
|
|
418
|
+
#Caboose.log("Attaching user to invoice: customer_id = #{@invoice.customer_id}")
|
|
419
|
+
render :json => { :success => @invoice.save, :errors => @invoice.errors.full_messages, :logged_in => logged_in? }
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
# @route POST /checkout/guest
|
|
423
|
+
def attach_guest
|
|
424
|
+
resp = Caboose::StdClass.new
|
|
425
|
+
email = params[:email]
|
|
426
|
+
|
|
427
|
+
if email != params[:confirm_email]
|
|
428
|
+
resp.error = "Emails do not match."
|
|
429
|
+
elsif Caboose::User.where(:email => email, :is_guest => false).exists?
|
|
430
|
+
resp.error = "A user with that email address already exists."
|
|
431
|
+
else
|
|
432
|
+
user = Caboose::User.where(:email => email, :is_guest => true).first
|
|
433
|
+
if user.nil?
|
|
434
|
+
user = Caboose::User.create(:email => email)
|
|
435
|
+
user.is_guest = true
|
|
436
|
+
user.save
|
|
437
|
+
user = Caboose::User.where(:email => email).first
|
|
438
|
+
end
|
|
439
|
+
@invoice.customer_id = user.id
|
|
440
|
+
login_user(user)
|
|
441
|
+
|
|
442
|
+
if !@invoice.valid?
|
|
443
|
+
resp.errors = @invoice.errors.full_messages
|
|
444
|
+
else
|
|
445
|
+
@invoice.save
|
|
446
|
+
resp.redirect = '/checkout/addresses'
|
|
447
|
+
end
|
|
448
|
+
end
|
|
449
|
+
render :json => resp
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
# @route PUT /checkout/shipping
|
|
453
|
+
def update_shipping
|
|
454
|
+
op = InvoicePackage.find(params[:invoice_package_id])
|
|
455
|
+
op.shipping_method_id = params[:shipping_method_id]
|
|
456
|
+
op.total = params[:total]
|
|
457
|
+
op.save
|
|
458
|
+
op.invoice.calculate
|
|
459
|
+
|
|
460
|
+
render :json => { :success => true }
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
end
|
|
464
|
+
end
|
|
@@ -279,7 +279,8 @@ module Caboose
|
|
|
279
279
|
Invoice::STATUS_CART,
|
|
280
280
|
Invoice::STATUS_PENDING,
|
|
281
281
|
Invoice::STATUS_READY_TO_SHIP,
|
|
282
|
-
Invoice::STATUS_SHIPPED,
|
|
282
|
+
Invoice::STATUS_SHIPPED,
|
|
283
|
+
Invoice::STATUS_PAID,
|
|
283
284
|
Invoice::STATUS_CANCELED
|
|
284
285
|
]
|
|
285
286
|
options = statuses.collect{ |s| { 'text' => s.capitalize, 'value' => s }}
|
|
@@ -56,10 +56,90 @@ module Caboose
|
|
|
56
56
|
|
|
57
57
|
when 'stripe'
|
|
58
58
|
# TODO: Implement manual invoice payment for stripe
|
|
59
|
-
|
|
60
59
|
end
|
|
61
60
|
render :layout => false
|
|
62
61
|
end
|
|
62
|
+
|
|
63
|
+
# @route POST /my-account/confirm
|
|
64
|
+
def confirm
|
|
65
|
+
Caboose::log(params)
|
|
66
|
+
sc = @site.store_config
|
|
67
|
+
@invoice = Invoice.find(params[:id])
|
|
68
|
+
|
|
69
|
+
# Make sure all the variants still exist
|
|
70
|
+
@invoice.line_items.each do |li|
|
|
71
|
+
v = Variant.where(:id => li.variant_id).first
|
|
72
|
+
if v.nil? || v.status == 'Deleted'
|
|
73
|
+
render :json => { :error => 'One or more of the products you are purchasing are no longer available.' }
|
|
74
|
+
return
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
error = false
|
|
79
|
+
requires_payment = @invoice.line_items.count > 0 && @invoice.total > 0
|
|
80
|
+
if requires_payment
|
|
81
|
+
ot = nil
|
|
82
|
+
|
|
83
|
+
Stripe.api_key = sc.stripe_secret_key.strip
|
|
84
|
+
begin
|
|
85
|
+
c = Stripe::Charge.create(
|
|
86
|
+
:amount => (@invoice.total * 100).to_i,
|
|
87
|
+
:currency => 'usd',
|
|
88
|
+
:customer => logged_in_user.stripe_customer_id,
|
|
89
|
+
:capture => false,
|
|
90
|
+
:metadata => { :invoice_id => @invoice.id },
|
|
91
|
+
:statement_descriptor => "Invoice ##{@invoice.id}"
|
|
92
|
+
)
|
|
93
|
+
rescue Exception => ex
|
|
94
|
+
render :json => { :error => ex.message }
|
|
95
|
+
return
|
|
96
|
+
end
|
|
97
|
+
ot = Caboose::InvoiceTransaction.create(
|
|
98
|
+
:invoice_id => @invoice.id,
|
|
99
|
+
:transaction_id => c.id,
|
|
100
|
+
:transaction_type => c.captured ? Caboose::InvoiceTransaction::TYPE_AUTHCAP : Caboose::InvoiceTransaction::TYPE_AUTHORIZE,
|
|
101
|
+
:payment_processor => sc.pp_name,
|
|
102
|
+
:amount => c.amount/100.0,
|
|
103
|
+
:date_processed => DateTime.now.utc,
|
|
104
|
+
:success => c.status == 'succeeded'
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
if !ot.success
|
|
108
|
+
render :json => { :error => error }
|
|
109
|
+
return
|
|
110
|
+
else
|
|
111
|
+
capture_resp = @invoice.capture_funds
|
|
112
|
+
if capture_resp.success == true
|
|
113
|
+
@invoice.take_gift_card_funds
|
|
114
|
+
@invoice.status = Caboose::Invoice::STATUS_PAID
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
@invoice.invoice_number = @site.store_config.next_invoice_number
|
|
120
|
+
|
|
121
|
+
# Send out emails
|
|
122
|
+
begin
|
|
123
|
+
InvoicesMailer.configure_for_site(@site.id).customer_new_invoice(@invoice).deliver
|
|
124
|
+
InvoicesMailer.configure_for_site(@site.id).fulfillment_new_invoice(@invoice).deliver
|
|
125
|
+
rescue
|
|
126
|
+
puts "=================================================================="
|
|
127
|
+
puts "Error sending out invoice confirmation emails for invoice ID #{@invoice.id}"
|
|
128
|
+
puts "=================================================================="
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Save the invoice
|
|
132
|
+
@invoice.save
|
|
133
|
+
|
|
134
|
+
# Decrement quantities of variants
|
|
135
|
+
@invoice.decrement_quantities
|
|
136
|
+
|
|
137
|
+
render :json => {
|
|
138
|
+
:success => true,
|
|
139
|
+
:message => "Thank you for your payment!"
|
|
140
|
+
}
|
|
141
|
+
return
|
|
142
|
+
end
|
|
63
143
|
|
|
64
144
|
# @route GET /my-account/invoices/:id/json
|
|
65
145
|
def invoice_json
|
|
@@ -19,9 +19,9 @@ module Caboose
|
|
|
19
19
|
#end
|
|
20
20
|
|
|
21
21
|
# Sends a confirmation email to the customer about a new invoice
|
|
22
|
-
def customer_new_invoice(invoice)
|
|
22
|
+
def customer_new_invoice(invoice)
|
|
23
23
|
@invoice = invoice
|
|
24
|
-
mail(:to => invoice.customer.email, :subject => 'Thank you for your
|
|
24
|
+
mail(:to => invoice.customer.email, :subject => 'Thank you for your order!')
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# Sends a notification email to the fulfillment dept about a new invoice
|
|
@@ -55,6 +55,7 @@ module Caboose
|
|
|
55
55
|
STATUS_CANCELED = 'canceled'
|
|
56
56
|
STATUS_READY_TO_SHIP = 'ready to ship'
|
|
57
57
|
STATUS_SHIPPED = 'shipped'
|
|
58
|
+
STATUS_PAID = 'paid'
|
|
58
59
|
STATUS_TESTING = 'testing'
|
|
59
60
|
|
|
60
61
|
# New
|
|
@@ -89,6 +90,7 @@ module Caboose
|
|
|
89
90
|
scope :pending , where('status = ?', 'pending')
|
|
90
91
|
scope :canceled , where('status = ?', 'canceled')
|
|
91
92
|
scope :shipped , where('status = ?', 'shipped')
|
|
93
|
+
scope :paid , where('status = ?', 'paid')
|
|
92
94
|
scope :test , where('status = ?', 'testing')
|
|
93
95
|
|
|
94
96
|
scope :authorized , where('financial_status = ?', 'authorized')
|
|
@@ -101,7 +103,7 @@ module Caboose
|
|
|
101
103
|
#
|
|
102
104
|
|
|
103
105
|
validates :status, :inclusion => {
|
|
104
|
-
:in => ['cart', 'pending', 'canceled', 'ready to ship', 'shipped', 'testing'],
|
|
106
|
+
:in => ['cart', 'pending', 'canceled', 'ready to ship', 'shipped', 'paid', 'testing'],
|
|
105
107
|
:message => "%{value} is not a valid status. Must be either 'pending' or 'shipped'"
|
|
106
108
|
}
|
|
107
109
|
|
|
@@ -15,8 +15,11 @@ store_config = @invoice.site.store_config
|
|
|
15
15
|
<p><input type='button' value='< Back' class='btn' onclick="window.location='/my-account/invoices';" /></p>
|
|
16
16
|
|
|
17
17
|
<% content_for :caboose_js do %>
|
|
18
|
+
<%= javascript_include_tag 'https://js.stripe.com/v2/' %>
|
|
19
|
+
<%= javascript_include_tag 'caboose/jquery.payment' %>
|
|
18
20
|
<%= javascript_include_tag 'caboose/model/all' %>
|
|
19
21
|
<%= javascript_include_tag 'caboose/my_account_edit_invoice' %>
|
|
22
|
+
<%= javascript_include_tag 'caboose/my_account_payment_method_controller' %>
|
|
20
23
|
<script type='text/javascript'>
|
|
21
24
|
|
|
22
25
|
var controller = false;
|
|
@@ -32,4 +35,20 @@ $(document).ready(function() {
|
|
|
32
35
|
|
|
33
36
|
<% content_for :caboose_css do %>
|
|
34
37
|
<%= stylesheet_link_tag 'caboose/my_account_edit_invoice' %>
|
|
38
|
+
<style type='text/css'>
|
|
39
|
+
.stripe_form { width: 100%; }
|
|
40
|
+
.stripe_form .card_number_container { position: relative; width: 100%; } .stripe_form .card_number_container input { padding-left: 30px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 0px 1px; }
|
|
41
|
+
.stripe_form .card_exp_container { position: relative; width: 50% !important; float: left; } .stripe_form .card_exp_container input { padding-left: 30px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 0px 1px; }
|
|
42
|
+
.stripe_form .card_cvc_container { position: relative; width: 50%; float: left; } .stripe_form .card_cvc_container input { padding-left: 30px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 0px 0px; }
|
|
43
|
+
.stripe_form .card_name_container { position: relative; width: 50%; float: left; } .stripe_form .card_name_container input { padding-left: 10px; height: 37px !important; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 0px 1px 1px; }
|
|
44
|
+
.stripe_form .card_zip_container { position: relative; width: 50%; float: left; margin-bottom: 4px; } .stripe_form .card_zip_container input { padding-left: 10px; height: 37px; font-size: 15px; width: 100%; border-color: #b9b9b9; border-style: solid; border-width: 1px 1px 1px 0px; }
|
|
45
|
+
|
|
46
|
+
.stripe_form .card_number_container .icon { position: absolute; top: 3px; left: 1px; transform-origin: 50% 50% 0; pointer-events: none; }
|
|
47
|
+
.stripe_form .card_exp_container .icon { position: absolute; top: 3px; left: 1px; transform-origin: 50% 50% 0; pointer-events: none; }
|
|
48
|
+
.stripe_form .card_cvc_container .icon { position: absolute; top: 3px; left: 1px; transform-origin: 50% 50% 0; pointer-events: none; }
|
|
49
|
+
|
|
50
|
+
.stripe_form .note { width: 100%; margin-bottom: 10px !important; text-align: center; }
|
|
51
|
+
.stripe_form .payment_controls { clear: left; margin-top: 4px !important; }
|
|
52
|
+
|
|
53
|
+
</style>
|
|
35
54
|
<% end %>
|
data/lib/caboose/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.8.65
|
|
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-09-
|
|
11
|
+
date: 2016-09-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pg
|
|
@@ -600,6 +600,7 @@ files:
|
|
|
600
600
|
- app/assets/javascripts/caboose/model/pager.js
|
|
601
601
|
- app/assets/javascripts/caboose/model/s3.js
|
|
602
602
|
- app/assets/javascripts/caboose/my_account_edit_invoice.js
|
|
603
|
+
- app/assets/javascripts/caboose/my_account_payment_method_controller.js
|
|
603
604
|
- app/assets/javascripts/caboose/product.js
|
|
604
605
|
- app/assets/javascripts/caboose/product_new.js
|
|
605
606
|
- app/assets/javascripts/caboose/product_old.js
|
|
@@ -743,6 +744,7 @@ files:
|
|
|
743
744
|
- app/assets/templates/caboose/product/images.jst.ejs
|
|
744
745
|
- app/assets/templates/caboose/product/images_old.jst.ejs
|
|
745
746
|
- app/assets/templates/caboose/product/options.jst.ejs
|
|
747
|
+
- app/controllers/caboose/#checkout_controller.rb#
|
|
746
748
|
- app/controllers/caboose/ab_options_controller.rb
|
|
747
749
|
- app/controllers/caboose/ab_variants_controller.rb
|
|
748
750
|
- app/controllers/caboose/admin_controller.rb
|