1/*
2 * WHMCS Stripe Javascript
3 *
4 * @copyright Copyright (c) WHMCS Limited 2005-2019
5 * @license http://www.whmcs.com/license/ WHMCS Eula
6 */
7var elementsDiv = null,
8 modalInput = false;
9function initStripe() {
10 var paymentMethod = jQuery('input[name="paymentmethod"]'),
11 frm = jQuery('#frmCheckout'),
12 newCcForm = jQuery('.frm-credit-card-input'),
13 paymentForm = jQuery('#frmPayment'),
14 adminCreditCard = jQuery('#frmCreditCardDetails');
15 if (paymentMethod.length && !newCcForm.length) {
16 var newCcInputs = jQuery('#newCardInfo');
17
18 insertAndMountElementsDivAfterInput(newCcInputs);
19 elementsDiv = jQuery('#stripeElements');
20
21 var newOrExisting = jQuery('input[name="ccinfo"]'),
22 selectedCard = jQuery('input[name="ccinfo"]:checked'),
23 selectedPaymentMethod = jQuery('input[name="paymentmethod"]:checked').val(),
24 existingCvv = jQuery('#existingCardInfo');
25
26 if (typeof selectedPaymentMethod == 'undefined') {
27 selectedPaymentMethod = jQuery('input[name="paymentmethod"]').val();
28 }
29
30 enablePaymentRequestButton();
31
32 if (selectedPaymentMethod === 'stripe') {
33 hide_cc_fields();
34 enable_stripe();
35 if (selectedCard.val() !== 'new') {
36 get_existing_token(selectedCard.val());
37 elementsDiv.slideUp();
38 frm.off('submit.stripe');
39 existingCvv.slideUp();
40 if (amount !== '000') {
41 frm.on('submit.stripe', processExisting);
42 }
43 }
44 }
45
46 paymentMethod.on('ifChecked', function(){
47 selectedPaymentMethod = jQuery(this).val();
48 if (selectedPaymentMethod === 'stripe') {
49 var newOrExistingValue = jQuery('input[name="ccinfo"]:checked').val();
50 hide_cc_fields();
51 enable_stripe();
52 if (newOrExistingValue !== 'new') {
53 get_existing_token(newOrExistingValue);
54 elementsDiv.slideUp();
55 frm.off('submit.stripe');
56 if (amount !== '000') {
57 frm.on('submit.stripe', processExisting);
58 }
59 }
60 } else {
61 disable_stripe();
62 }
63 });
64 jQuery(document).on('ifChecked', 'input[name="ccinfo"]', function() {
65 frm.off('submit.stripe');
66 selectedPaymentMethod = jQuery('input[name="paymentmethod"]:checked').val();
67 if (selectedPaymentMethod !== 'stripe') {
68 return;
69 }
70 hide_cc_fields();
71 if (jQuery(this).val() === 'new') {
72 enable_stripe();
73 } else {
74 get_existing_token(jQuery(this).val());
75 elementsDiv.slideUp();
76 frm.off('submit.stripe');
77 if (amount !== '000') {
78 frm.on('submit.stripe', processExisting);
79 }
80 }
81 });
82 } else if (newCcForm.length) {
83 if (jQuery('input[name="type"]:checked').data('gateway') === 'stripe') {
84 insertAndMountElementsDivBeforeInput(
85 newCcForm.find('div.cc-details')
86 );
87 elementsDiv = jQuery('#stripeElements');
88 hide_cc_fields();
89 elementsDiv.slideDown();
90
91 card.addEventListener('change', cardListener);
92 cardExpiryElements.addEventListener('change', cardListener);
93 cardCvcElements.addEventListener('change', cardListener);
94 newCcForm.on('submit.stripe', addNewCardClientSide);
95 }
96 jQuery('input[name="type"]').on('ifChecked', function(){
97 if (jQuery(this).data('gateway') === 'stripe') {
98 insertAndMountElementsDivBeforeInput(
99 newCcForm.find('div.cc-details')
100 );
101 elementsDiv = jQuery('#stripeElements');
102 hide_cc_fields();
103 elementsDiv.slideDown();
104
105 newCcForm.off('submit.stripe');
106 newCcForm.on('submit.stripe', addNewCardClientSide);
107 card.addEventListener('change', cardListener);
108 cardExpiryElements.addEventListener('change', cardListener);
109 cardCvcElements.addEventListener('change', cardListener);
110 } else {
111 disable_stripe();
112 newCcForm.find('.cc-details').slideDown();
113 }
114 });
115 } else if (paymentForm.length) {
116 insertAndMountElementsDivBeforeInput(paymentForm.find('#billingAddressChoice'));
117 paymentForm.find('#inputCardCvv').closest('div.form-group').remove();
118 paymentForm.off('submit', validateCreditCardInput);
119 if (jQuery('input[name="ccinfo"]:checked').val() === 'new') {
120 enable_payment_stripe();
121 } else {
122 get_existing_token(jQuery('input[name="ccinfo"]:checked').val());
123 paymentForm.on('submit.stripe', processExisting);
124 }
125 jQuery('input[name="ccinfo"]').on('ifChecked', function(){
126 if (jQuery(this).val() === 'new') {
127 enable_payment_stripe();
128 } else {
129 get_existing_token(jQuery(this).val());
130 jQuery('#stripeElements').slideUp();
131 paymentForm.off('submit.stripe');
132 paymentForm.on('submit.stripe', processExisting);
133 if (card.hasRegisteredListener('change')) {
134 card.removeEventListener('change', cardListener);
135 }
136 }
137 });
138 enablePaymentRequestButton();
139 } else if (adminCreditCard.length) {
140 adminCreditCard.find('#cctype').closest('tr').slideUp().remove();
141 adminCreditCard.find('#inputCardNumber')
142 .closest('div')
143 .html('<div id="elementCardNumber" class="form-control"></div>');
144 adminCreditCard.find('#inputCardExpiry')
145 .closest('div')
146 .html('<div id="elementCardExpiry" class="form-control"></div>');
147 adminCreditCard.find('#cardcvv')
148 .closest('div')
149 .html('<div id="elementCardCvc" class="form-control"></div>');
150 card.mount('#elementCardNumber');
151 cardExpiryElements.mount('#elementCardExpiry');
152 cardCvcElements.mount('#elementCardCvc');
153 card.addEventListener('change', cardListener);
154 cardExpiryElements.addEventListener('change', cardListener);
155 cardCvcElements.addEventListener('change', cardListener);
156
157 // same as above - Firefox issues
158 elementsDiv = jQuery('#elementCardNumber');
159 if (jQuery('#containerStorageInputControl')) {
160 var modalFooter = jQuery('#modalAjaxFooter'),
161 btnSubmit = modalFooter.find('#btnSave');
162 btnSubmit.removeAttr('name');
163 btnSubmit.off();
164 btnSubmit.on('click', validateChangeCard);
165 modalInput = true;
166 } else {
167 adminCreditCard.find('#btnSaveChanges').removeAttr('name');
168 adminCreditCard.on('submit.stripe', validateChangeCard);
169 }
170 }
171}
172
173function validateStripe(event) {
174 if (
175 typeof recaptchaValidationComplete !== 'undefined'
176 && typeof recaptchaType !== 'undefined'
177 && recaptchaType === 'invisible'
178 && recaptchaValidationComplete === false
179 ) {
180 event.preventDefault();
181 return;
182 }
183 var paymentMethod = jQuery('input[name="paymentmethod"]:checked'),
184 frm = elementsDiv.closest('form'),
185 displayError = jQuery('.gateway-errors,.assisted-cc-input-feedback').first();
186
187 if (paymentMethod.length && paymentMethod.val() !== 'stripe') {
188 return true;
189 }
190 event.preventDefault();
191 // Disable the submit button to prevent repeated clicks:
192 frm.find('button[type="submit"],input[type="submit"]')
193 .prop('disabled', true)
194 .addClass('disabled')
195 .find('span').toggle();
196
197 stripe.createPaymentMethod(
198 'card',
199 card
200 ).then(function(result) {
201 if (result.error) {
202 var error = result.error.message;
203 if (error) {
204 displayError.html(error);
205 if (displayError.not(':visible')) {
206 displayError.slideDown();
207 }
208 scrollToGatewayInputError();
209 }
210 } else {
211 WHMCS.http.jqClient.jsonPost({
212 url: WHMCS.utils.getRouteUrl('/stripe/payment/intent'),
213 data: frm.serialize() + '&payment_method_id=' + result.paymentMethod.id,
214 success: function(response) {
215 if (response.success) {
216 //payment has been successful already at this point
217 stripeResponseHandler(response.token);
218 } else if (response.two_factor) {
219 stripeResponseHandler('');
220 } else if (response.validation_feedback) {
221 // An error has been received.
222 displayError.html(response.validation_feedback);
223 if (displayError.not(':visible')) {
224 displayError.slideDown();
225 }
226 scrollToGatewayInputError();
227 WHMCS.form.reloadCaptcha();
228 } else {
229 stripe.handleCardPayment(
230 response.token
231 ).then(function(result) {
232 if (result.error) {
233 var error = result.error.message;
234 if (error) {
235 displayError.html(error);
236 if (displayError.not(':visible')) {
237 displayError.slideDown();
238 }
239 scrollToGatewayInputError();
240 WHMCS.form.reloadCaptcha();
241 }
242 } else {
243 stripeResponseHandler(result.paymentIntent.id);
244 }
245 });
246
247 }
248 },
249 warning: function(error) {
250 WHMCS.form.reloadCaptcha();
251 displayError.html(defaultErrorMessage);
252 if (displayError.not(':visible')) {
253 displayError.slideDown();
254 }
255 scrollToGatewayInputError();
256 },
257 fail: function(error) {
258 displayError.html(defaultErrorMessage);
259 if (displayError.not(':visible')) {
260 displayError.slideDown();
261 }
262 scrollToGatewayInputError();
263 }
264 });
265 }
266 });
267 // Prevent the form from being submitted:
268 return false;
269}
270
271function processExisting(event)
272{
273 if (
274 typeof recaptchaValidationComplete !== 'undefined'
275 && typeof recaptchaType !== 'undefined'
276 && recaptchaType === 'invisible'
277 && recaptchaValidationComplete === false
278 ) {
279 event.preventDefault();
280 return;
281 }
282 var frm = elementsDiv.closest('form'),
283 displayError = jQuery('.gateway-errors,.assisted-cc-input-feedback').first();
284
285 frm.find('.gateway-errors').html('').slideUp();
286 event.preventDefault();
287
288 // Disable the submit button to prevent repeated clicks:
289 frm.find('button[type="submit"],input[type="submit"]')
290 .prop('disabled', true)
291 .addClass('disabled')
292 .find('span').toggle();
293
294 WHMCS.http.jqClient.jsonPost({
295 url: WHMCS.utils.getRouteUrl('/stripe/payment/intent'),
296 data: frm.serialize() + '&payment_method_id=' + existingToken,
297 success: function(response) {
298 if (response.success) {
299 //payment has been successful already at this point
300 stripeResponseHandler(response.token);
301 } else if (response.validation_feedback) {
302 // An error has been received.
303 displayError.html(response.validation_feedback);
304 if (displayError.not(':visible')) {
305 displayError.slideDown();
306 }
307 scrollToGatewayInputError();
308 WHMCS.form.reloadCaptcha();
309 } else {
310 stripe.handleCardPayment(
311 response.token
312 ).then(function(result) {
313 if (result.error) {
314 var error = result.error.message;
315 if (error) {
316 displayError.html(error);
317 if (displayError.not(':visible')) {
318 displayError.slideDown();
319 }
320 scrollToGatewayInputError();
321 WHMCS.form.reloadCaptcha();
322 }
323 } else {
324 stripeResponseHandler(result.paymentIntent.id);
325 }
326 });
327 }
328 },
329 warning: function(error) {
330 WHMCS.form.reloadCaptcha();
331 displayError.html(defaultErrorMessage);
332 if (displayError.not(':visible')) {
333 displayError.slideDown();
334 }
335 scrollToGatewayInputError();
336 },
337 fail: function(error) {
338 displayError.html(defaultErrorMessage);
339 if (displayError.not(':visible')) {
340 displayError.slideDown();
341 }
342 scrollToGatewayInputError();
343 }
344 });
345}
346
347function stripeResponseHandler(token) {
348 var frm = elementsDiv.closest('form');
349 frm.find('.gateway-errors,.assisted-cc-input-feedback').html('').slideUp();
350 // Insert the token ID into the form so it gets submitted to the server:
351 frm.append(jQuery('<input type="hidden" name="remoteStorageToken">').val(token));
352 frm.find('button[type="submit"],input[type="submit"]')
353 .find('i.fas,i.far,i.fal,i.fab')
354 .removeAttr('class')
355 .addClass('fas fa-spinner fa-spin');
356
357 if (!modalInput) {
358 elementsDiv.slideUp();
359 }
360
361 // Submit the form:
362 frm.off('submit.stripe');
363
364 frm.append('<input type="submit" id="hiddenSubmit" name="submit" value="Save Changes" style="display:none;">');
365 var hiddenButton = jQuery('#hiddenSubmit');
366 if (modalInput) {
367
368 var modalFooter = jQuery('#modalAjaxFooter'),
369 hiddenButton = modalFooter.find('#btnSave');
370 hiddenButton.removeClass('disabled');
371 jQuery('#modalAjax .loader').fadeOut();
372 hiddenButton.off('click', validateChangeCard);
373 hiddenButton.on('click', submitIdAjaxModalClickEvent);
374 }
375 hiddenButton.click();
376}
377
378function hide_cc_fields() {
379 var frm = elementsDiv.closest('form'),
380 cardInputs = jQuery('#newCardInfo,.cc-details,#existingCardInfo');
381 if (cardInputs.is(':visible')) {
382 cardInputs.slideUp('fast', function() {
383 frm.find('#cctype').removeAttr('name');
384 frm.find('#inputCardCvvExisting').removeAttr('name');
385 frm.find('#inputCardNumber').removeAttr('name');
386 frm.find('#inputCardExpiry').removeAttr('name');
387 frm.find('#inputCardCVV').removeAttr('name');
388 frm.find('#inputCardCvvExisting').removeAttr('name');
389 });
390 }
391}
392
393function enable_stripe() {
394 var frm = elementsDiv.closest('form'),
395 inputDescriptionContainer = jQuery('#inputDescriptionContainer');
396 hide_cc_fields();
397
398 elementsDiv.slideDown();
399 card.addEventListener('change', cardListener);
400 cardExpiryElements.addEventListener('change', cardListener);
401 cardCvcElements.addEventListener('change', cardListener);
402 frm.off('submit.stripe');
403 if (amount === '000') {
404 frm.on('submit.stripe', addNewCardClientSide);
405 } else {
406 frm.on('submit.stripe', validateStripe);
407 }
408 inputDescriptionContainer.addClass('col-md-offset-3 offset-md-3');
409}
410
411function disable_stripe() {
412 var frm = elementsDiv.closest('form'),
413 cardInputs = jQuery('#newCardInfo,.cc-details'),
414 showLocal = true,
415 inputDescriptionContainer = jQuery('#inputDescriptionContainer');
416
417 frm.find('#inputCardCvvExisting').attr('name', 'cccvvexisting');
418 frm.find('#inputCardNumber').attr('name', 'ccnumber');
419 frm.find('#inputCardExpiry').attr('name', 'ccexpirydate');
420 frm.find('#inputCardCVV').attr('name', 'cccvv');
421 frm.find('#inputCardCvvExisting').attr('name', 'cccvvexisting');
422 frm.find('#cctype').attr('name', 'cctype');
423
424 if (jQuery('input[name="paymentmethod"]:checked').data('remote-inputs') === 1) {
425 showLocal = false;
426 }
427
428 elementsDiv.hide('fast', function() {
429 var firstVisible = jQuery('input[name="ccinfo"]:visible').first();
430 if (firstVisible.val() === 'new') {
431 if (showLocal) {
432 cardInputs.slideDown();
433 }
434 } else {
435 firstVisible.click();
436 }
437 });
438
439 frm.off('submit.stripe');
440 if (card.hasRegisteredListener('change')) {
441 card.removeEventListener('change', cardListener);
442 }
443 if (cardExpiryElements.hasRegisteredListener('change')) {
444 cardExpiryElements.removeEventListener('change', cardListener);
445 }
446 if (cardCvcElements.hasRegisteredListener('change')) {
447 cardCvcElements.removeEventListener('change', cardListener);
448 }
449 inputDescriptionContainer.removeClass('col-md-offset-3 offset-md-3');
450}
451
452function enable_payment_stripe() {
453 var paymentForm = elementsDiv.closest('form');
454
455 paymentForm.find('#inputCardNumber').closest('div.form-group').remove();
456 paymentForm.find('#inputCardExpiry').closest('div.form-group').remove();
457 elementsDiv.slideDown();
458 card.addEventListener('change', cardListener);
459 cardExpiryElements.addEventListener('change', cardListener);
460 cardCvcElements.addEventListener('change', cardListener);
461 paymentForm.off('submit.stripe');
462 paymentForm.on('submit.stripe', validateStripe);
463}
464
465function enablePaymentRequestButton() {
466 if (paymentRequestButtonEnabled) {
467 var frm = elementsDiv.closest('form'),
468 paymentRequest = stripe.paymentRequest({
469 country: 'US',
470 currency: paymentRequestCurrency.toLowerCase(),
471 total: {
472 label: paymentRequestDescription,
473 amount: paymentRequestAmountDue
474 },
475 requestPayerName: true,
476 requestPayerEmail: true,
477 }),
478 displayError = jQuery('.gateway-errors,.assisted-cc-input-feedback').first();
479 var prButton = elements.create('paymentRequestButton', {
480 paymentRequest: paymentRequest,
481 });
482
483 paymentRequest.canMakePayment().then(function(result) {
484 if (result) {
485 if (result.applePay) {
486 //we know it's applepay
487 } else {
488 //we know it's a browser based card option
489 }
490 if (jQuery('#paymentRequestButton').length === 0) {
491 elementsDiv.prepend(
492 '<div class="row"><div class="col-md-4 col-md-offset-4 offset-md-4">' +
493 '<div id="paymentRequestButton"></div>' +
494 '</div></div>'
495 );
496 }
497 prButton.mount('#paymentRequestButton');
498 }
499 });
500
501 paymentRequest.on('paymentmethod', function(ev) {
502 var paymentMethodId = ev.paymentMethod.id,
503 paymentIntentId = null,
504 event = ev,
505 frm = elementsDiv.closest('form');
506 frm.find('.gateway-errors,.assisted-cc-input-feedback').html('').slideUp();
507 frm.find('button[type="submit"],input[type="submit"]')
508 .addClass('disabled')
509 .prop('disabled', true)
510 .find('i.fas,i.far,i.fal,i.fab')
511 .removeAttr('class')
512 .addClass('fas fa-spinner fa-spin');
513 WHMCS.http.jqClient.jsonPost({
514 url: WHMCS.utils.getRouteUrl('/stripe/payment/intent'),
515 data: frm.serialize() + '&payment_method_id=' + paymentMethodId,
516 success: function(response) {
517 paymentIntentId = response.token;
518 if (response.success) {
519 event.complete('success');
520 stripeResponseHandler(response.token);
521 } else if (response.validation_feedback) {
522 // An error has been received.
523 displayError.html(response.validation_feedback);
524 if (displayError.not(':visible')) {
525 displayError.slideDown();
526 }
527 scrollToGatewayInputError();
528 WHMCS.form.reloadCaptcha();
529 } else {
530 // Let Stripe.js handle the rest of the payment flow.
531 stripe.handleCardPayment(paymentIntentId).then(function(result) {
532 if (result.error) {
533 var error = result.error.message;
534 if (error) {
535 displayError.html(error);
536 if (displayError.not(':visible')) {
537 displayError.slideDown();
538 }
539 scrollToGatewayInputError();
540 WHMCS.form.reloadCaptcha();
541 }
542 } else {
543 stripeResponseHandler(result.paymentIntent.id);
544 }
545 });
546 }
547 WHMCS.form.reloadCaptcha();
548 },
549 warning: function(error) {
550 WHMCS.form.reloadCaptcha();
551 displayError.html(defaultErrorMessage);
552 if (displayError.not(':visible')) {
553 displayError.slideDown();
554 }
555 scrollToGatewayInputError();
556 },
557 fail: function(error) {
558 displayError.html(defaultErrorMessage);
559 if (displayError.not(':visible')) {
560 displayError.slideDown();
561 }
562 scrollToGatewayInputError();
563 }
564 });
565 });
566 }
567}
568
569function insertAndMountElementsDivAfterInput(input) {
570 elementsDiv = jQuery('#stripeElements');
571 if (!elementsDiv.length) {
572 input.after(stripe_cc_html(input));
573 var stripeCvvWhere = jQuery('#stripeCvcWhere');
574 if (stripeCvvWhere.length) {
575 jQuery('#cvvWhereLink').clone().appendTo(stripeCvvWhere);
576 // Default catch for all other popovers
577 jQuery('[data-toggle="popover"]').popover({
578 html: true
579 });
580 }
581 elementsDiv = jQuery('#stripeElements');
582 card.mount('#stripeCreditCard');
583 cardExpiryElements.mount('#stripeExpiryDate');
584 cardCvcElements.mount('#stripeCvc');
585 }
586}
587
588function insertAndMountElementsDivBeforeInput(input) {
589 elementsDiv = jQuery('#stripeElements');
590 if (!elementsDiv.length) {
591 input.before(stripe_cc_html(input));
592 var stripeCvvWhere = jQuery('#stripeCvcWhere');
593 if (stripeCvvWhere.length) {
594 jQuery('#cvvWhereLink').clone().appendTo(stripeCvvWhere);
595 // Default catch for all other popovers
596 jQuery('[data-toggle="popover"]').popover({
597 html: true
598 });
599 }
600 elementsDiv = jQuery('#stripeElements');
601 card.mount('#stripeCreditCard');
602 cardExpiryElements.mount('#stripeExpiryDate');
603 cardCvcElements.mount('#stripeCvc');
604 }
605
606}
607
608function stripe_cc_html(input)
609{
610 var frm = input.closest('form')[0],
611 html = '';
612
613 if (frm.id === 'frmCheckout') {
614 html = '<div id="stripeElements" class="form-group" style="display: none;">' +
615 '<div class="stripe-cards-inputs col-md-8 col-md-offset-2 offset-md-2">' +
616 '<div class="row">' +
617 '<div class="col-md-6">' +
618 '<label for="stripeCreditCard">' + lang.creditCardInput + '</label>' +
619 '<div id="stripeCreditCard" class="form-control"></div>' +
620 '<div id="stripeCardType"></div>' +
621 '</div><div class="col-md-3">' +
622 '<label for="stripeExpiryDate">' + lang.creditCardExpiry + '</label>' +
623 '<div id="stripeExpiryDate" class="form-control"></div>' +
624 '</div><div class="col-md-3">' +
625 '<label for="stripeCvc">' + lang.creditCardCvc + '</label>' +
626 '<div id="stripeCvc" class="form-control"></div>' +
627 '</div>' +
628 '</div>' + //row
629 '</div>' + //stripe-card-inputs
630 '</div>' + //#stripeElements
631 '<div class="clearfix"></div>';
632 } else {
633 elementsClass = '';
634
635 html = '<div id="stripeElements" style="display: none;">' +
636 '<div class="form-group row cc-billing-address">' +
637 '<label for="stripeCreditCard" class="col-sm-4 control-label">' +
638 lang.creditCardInput + '</label>' +
639 '<div class="col-sm-7">' +
640 '<div id="stripeCreditCard" class="form-control" aria-describedby="cc-type"></div>' +
641 '<div id="stripeCardType"></div>' +
642 '</div>' + //col-sm-6
643 '<div class="col-sm-4"></div>' +
644 '</div>' + //form-group
645 '<div class="form-group row cc-billing-address">' +
646 '<label for="stripeExpiryDate" class="col-sm-4 control-label">' +
647 lang.creditCardExpiry + '</label>' +
648 '<div class="col-sm-2">' +
649 '<div id="stripeExpiryDate" class="form-control"></div>' +
650 '</div>' + //col-sm-6
651 '<div class="col-sm-6"></div>' +
652 '</div>' + //form-group
653 '<div class="form-group row cc-billing-address">' +
654 '<label for="stripeCvc" class="col-sm-4 control-label">' +
655 lang.creditCardCvc + '</label>' +
656 '<div class="col-sm-2">' +
657 '<div id="stripeCvc" class="form-control"></div>' +
658 '</div>' + //col-sm-2
659 '<div class="col-sm-4">' +
660 '<div id="stripeCvcWhere"></div>' +
661 '</div>' + //col-sm-4
662 '</div>' + //form-group
663 '</div>' + //row
664 '</div>' + //#stripeElements
665 '<div class="clearfix"></div>';
666 }
667 return html;
668}
669
670function cardListener(event) {
671 var displayError = jQuery('.gateway-errors,.assisted-cc-input-feedback').first(),
672 error = '';
673 if (typeof event.error !== "undefined") {
674 error = event.error.message;
675
676 if (error) {
677 displayError.html(error);
678 if (displayError.not(':visible')) {
679 displayError.slideDown();
680 }
681 scrollToGatewayInputError();
682 }
683 } else {
684 displayError.slideUp().html('');
685 }
686 if (typeof event.brand !== 'undefined') {
687 // var cardType = jQuery('#stripeCardType');
688 // if (cardType.length && event.brand === 'unknown') {
689 // cardType.html('');
690 // } else if (cardType.length && event.brand !== 'unknown') {
691 // cardType.html(event.brand.toUpperCase());
692 // }
693 }
694}
695
696function addNewCardClientSide(event)
697{
698 var frm = elementsDiv.closest('form'),
699 displayError = jQuery('.gateway-errors,.assisted-cc-input-feedback').first();
700 event.preventDefault();
701 // Disable the submit button to prevent repeated clicks:
702 frm.find('button[type="submit"],input[type="submit"]')
703 .prop('disabled', true)
704 .addClass('disabled')
705 .find('span').toggle();
706
707
708 // We need to submit first to our endpoint to start a SetupIntent
709 WHMCS.http.jqClient.jsonPost({
710 url: WHMCS.utils.getRouteUrl('/stripe/setup/intent'),
711 data: frm.serialize(),
712 success: function(response) {
713 if (response.success) {
714 stripe.handleCardSetup(
715 response.setup_intent,
716 card
717 ).then(function(result) {
718 if (result.error) {
719 displayError.html(result.error.message);
720 if (displayError.not(':visible')) {
721 displayError.slideDown();
722 }
723 scrollToGatewayInputError();
724 WHMCS.form.reloadCaptcha();
725 } else {
726 stripeResponseHandler(result.setupIntent.id);
727 }
728 });
729 }
730 },
731 warning: function(error) {
732 displayError.html(error);
733 if (displayError.not(':visible')) {
734 displayError.slideDown();
735 }
736 scrollToGatewayInputError();
737 },
738 fail: function(error) {
739 displayError.html(error);
740 if (displayError.not(':visible')) {
741 displayError.slideDown();
742 }
743 scrollToGatewayInputError();
744 }
745 });
746}
747
748function validateChangeCard(event)
749{
750 var frm = elementsDiv.closest('form'),
751 displayError = jQuery('.gateway-errors,.assisted-cc-input-feedback').first();
752 event.preventDefault();
753 // Disable the submit button to prevent repeated clicks:
754 frm.find('button[type="submit"],input[type="submit"]')
755 .prop('disabled', true)
756 .addClass('disabled')
757 .find('span').toggle();
758
759 stripe.createPaymentMethod(
760 'card',
761 card
762 ).then(function(result) {
763 if (result.error) {
764 var error = result.error.message;
765 if (error) {
766 displayError.html(error);
767 if (displayError.not(':visible')) {
768 displayError.slideDown();
769 }
770 scrollToGatewayInputError();
771 }
772 } else {
773 if (modalInput) {
774 var btnSubmit = jQuery('#btnSave');
775 btnSubmit.addClass('disabled');
776 jQuery('#modalAjax .loader').slideDown();
777 }
778 if (typeof WHMCS.utils !== 'undefined') {
779 var url = WHMCS.utils.getRouteUrl('/stripe/payment/add');
780 } else {
781 var url = WHMCS.adminUtils.getAdminRouteUrl('/stripe/payment/admin/add');
782 }
783 WHMCS.http.jqClient.jsonPost({
784 url: url,
785 data: frm.serialize()
786 + '&payment_method_id=' + result.paymentMethod.id,
787 success: function(response) {
788 if (response.success) {
789 //payment has been successful already at this point
790 stripeResponseHandler(response.token);
791 }
792 if (response.validation_feedback) {
793 displayError.text(response.validation_feedback);
794 if (displayError.not(':visible')) {
795 displayError.slideDown();
796 }
797 }
798 },
799 warning: function(error) {
800 displayError.html(error);
801 if (displayError.not(':visible')) {
802 displayError.slideDown();
803 }
804 scrollToGatewayInputError();
805 },
806 fail: function(error) {
807 displayError.html(error);
808 if (displayError.not(':visible')) {
809 displayError.slideDown();
810 }
811 scrollToGatewayInputError();
812 },
813 always: function() {
814 if (modalInput) {
815 btnSubmit.removeClass('disabled');
816 jQuery('#modalAjax .loader').fadeOut();
817 }
818 }
819 });
820 }
821 });
822 // Prevent the form from being submitted:
823 return false;
824}
825
826function get_existing_token(tokenId)
827{
828 if (typeof tokenId === 'undefined') {
829 var input = jQuery('input[name="ccinfo"]:visible:first');
830 input.iCheck('check');
831 tokenId = input.val();
832 if (tokenId === 'new') {
833 return;
834 }
835 }
836 var displayError = jQuery('.gateway-errors,.assisted-cc-input-feedback').first(),
837 frm = displayError.closest('form');
838
839 frm.find('button[type="submit"],input[type="submit"]')
840 .prop('disabled', true)
841 .addClass('disabled')
842 .find('span').toggle();
843 WHMCS.http.jqClient.jsonPost({
844 url: WHMCS.utils.getRouteUrl('/payment/stripe/token/get'),
845 data: 'paymethod_id=' + tokenId + '&token=' + csrfToken,
846 success: function(response) {
847 existingToken = response.token;
848 frm.find('button[type="submit"],input[type="submit"]')
849 .prop('disabled', false)
850 .removeClass('disabled')
851 .find('span').toggle();
852 },
853 warning: function(error) {
854 displayError.html(error);
855 if (displayError.not(':visible')) {
856 displayError.slideDown();
857 }
858 scrollToGatewayInputError();
859 reset_input_to_new();
860 },
861 fail: function(error) {
862 displayError.html(error);
863 if (displayError.not(':visible')) {
864 displayError.slideDown();
865 }
866 scrollToGatewayInputError();
867 reset_input_to_new();
868 }
869 });
870}
871
872function reset_input_to_new()
873{
874 jQuery('input[name="ccinfo"][value="new"]').iCheck('check');
875 if (jQuery('#existingCardInfo').is(':visible')) {
876 jQuery('#existingCardInfo').slideUp();
877 }
878
879 setTimeout(function() {
880 jQuery('.gateway-errors,.assisted-cc-input-feedback').slideUp();
881 }, 4000);
882}
883