Enables Stripe SCA payments

This commit is contained in:
Jeremy Quinton 2019-08-29 21:23:05 +02:00
parent f5c23aaddc
commit 19c2ca8a8c
17 changed files with 1588 additions and 830 deletions

View File

@ -274,17 +274,13 @@ class EventCheckoutController extends Controller
}
return view('Public.ViewEvent.EventPageCheckout', $data);
}
/**
* Create the order, handle payment, update stats, fire off email jobs then redirect user
*
* @param Request $request
* @param $event_id
* @return \Illuminate\Http\JsonResponse
*/
public function postCreateOrder(Request $request, $event_id)
public function postValidateOrder(Request $request, $event_id)
{
session()->push('ticket_order_' . $event_id . '.request_data', $request->all());
//If there's no session kill the request and redirect back to the event homepage.
if (!session()->get('ticket_order_' . $event_id)) {
return response()->json([
@ -335,8 +331,72 @@ class EventCheckoutController extends Controller
]);
}
return response()->json([
'status' => 'success',
'redirectUrl' => route('showEventPayment', [
'event_id' => $event_id,
'is_embedded' => $this->is_embedded
])
]);
}
public function showEventPayment(Request $request, $event_id)
{
$order_session = session()->get('ticket_order_' . $event_id);
$event = Event::findOrFail($event_id);
$payment_gateway = $order_session['payment_gateway'];
$order_total = $order_session['order_total'];
$account_payment_gateway = $order_session['account_payment_gateway'];
$orderService = new OrderService($order_session['order_total'], $order_session['total_booking_fee'], $event);
$orderService->calculateFinalCosts();
switch ($payment_gateway->id) {
case config('attendize.payment_gateway_stripe_sca'):
\Stripe\Stripe::setApiKey($account_payment_gateway->config['apiKey']);
$intent = \Stripe\PaymentIntent::create([
'amount' => $order_total,
'currency' => $event->currency->code,
]);
break;
}
$secondsToExpire = Carbon::now()->diffInSeconds($order_session['expires']);
$viewData = ['event' => $event,
'tickets' => $order_session['tickets'],
'order_total' => $order_total,
'orderService' => $orderService,
'order_requires_payment' => (ceil($order_session['order_total']) == 0) ? false : true,
'account_payment_gateway' => $account_payment_gateway,
'payment_gateway' => $payment_gateway,
'secondsToExpire' => $secondsToExpire
];
if (!empty($intent)) {
$viewData['client_secret'] = $intent->client_secret;
}
return view('Public.ViewEvent.EventPagePayment', $viewData);
}
/**
* Create the order, update stats, fire off email jobs then redirect user
*
* @param Request $request
* @param $event_id
* @return \Illuminate\Http\JsonResponse
*/
public function postCreateOrder(Request $request, $event_id)
{
//Add the request data to a session in case payment is required off-site
session()->push('ticket_order_' . $event_id . '.request_data', $request->except(['card-number', 'card-cvc']));
session()->push('ticket_order_' . $event_id . '.request_data', $request->except(['cardnumber', 'cvc']));
$ticket_order = session()->get('ticket_order_' . $event_id);
$event = Event::findOrFail($event_id);
$orderRequiresPayment = $ticket_order['order_requires_payment'];
@ -361,6 +421,7 @@ class EventCheckoutController extends Controller
$gateway->initialize();
} else {
$gateway = Omnipay::create($ticket_order['payment_gateway']->name);
$gateway->initialize($ticket_order['account_payment_gateway']->config + [
'testMode' => config('attendize.enable_test_payments'),
@ -401,14 +462,51 @@ class EventCheckoutController extends Controller
? $ticket_order['account_payment_gateway']->config['brandingName']
: $event->organiser->name
];
$transaction = $gateway->purchase($transaction_data);
$response = $transaction->send();
break;
case config('attendize.payment_gateway_stripe'):
$token = $request->get('stripeToken');
$transaction_data += [
'token' => $token,
'token' => $token,
'receipt_email' => $request->get('order_email'),
'returnUrl' => route('showEventCheckoutPaymentReturn', [
'event_id' => $event_id,
'is_payment_successful' => 1
]),
];
$transaction = $gateway->purchase($transaction_data);
$response = $transaction->send();
break;
case config('attendize.payment_gateway_stripe_sca'):
Log::error($ticket_order['payment_gateway']->name);
$paymentMethod = $request->get('paymentMethod');
$returnUrl = route('showEventCheckoutPaymentReturn', [
'event_id' => $event_id,
'is_payment_successful' => 1,
]);
$transaction_data += [
'paymentMethod' => $paymentMethod,
'receipt_email' => 'jeremyquinton@gmail.com', //$request->get('order_email'),
'returnUrl' => $returnUrl,
'confirm' => true,
];
Log::error(print_r($transaction_data, true));
$response = $gateway->authorize($transaction_data)->send();
break;
default:
Log::error('No payment gateway configured.');
return response()->json([
@ -416,12 +514,9 @@ class EventCheckoutController extends Controller
'message' => 'No payment gateway configured.'
]);
break;
}
$transaction = $gateway->purchase($transaction_data);
$response = $transaction->send();
if ($response->isSuccessful()) {
session()->push('ticket_order_' . $event_id . '.transaction_id',
@ -472,7 +567,6 @@ class EventCheckoutController extends Controller
}
/**
* Attempt to complete a user's payment when they return from
* an off-site gateway
@ -513,7 +607,6 @@ class EventCheckoutController extends Controller
'is_payment_failed' => 1,
]);
}
}
/**
@ -532,6 +625,7 @@ class EventCheckoutController extends Controller
$order = new Order();
$ticket_order = session()->get('ticket_order_' . $event_id);
$request_data = $ticket_order['request_data'][0];
$event = Event::findOrFail($ticket_order['event_id']);
$attendee_increment = 1;

View File

@ -31,7 +31,8 @@ class ManageAccountController extends MyBaseController
'account' => Account::find(Auth::user()->account_id),
'timezones' => Timezone::pluck('location', 'id'),
'currencies' => Currency::pluck('title', 'id'),
'payment_gateways' => PaymentGateway::pluck('provider_name', 'id'),
'payment_gateways' => PaymentGateway::getAllWithDefaultSet(),
'default_payment_gateway_id' => PaymentGateway::getDefaultPaymentGatewayId(),
'account_payment_gateways' => AccountPaymentGateway::scope()->get(),
'version_info' => $this->getVersionInfo(),
];
@ -124,7 +125,7 @@ class ManageAccountController extends MyBaseController
public function postEditAccountPayment(Request $request)
{
$account = Account::find(Auth::user()->account_id);
$gateway_id = $request->get('payment_gateway_id');
$gateway_id = $request->get('payment_gateway');
switch ($gateway_id) {
case config('attendize.payment_gateway_stripe') : //Stripe
@ -133,8 +134,16 @@ class ManageAccountController extends MyBaseController
case config('attendize.payment_gateway_paypal') : //PayPal
$config = $request->get('paypal');
break;
case config('attendize.payment_gateway_stripe_sca') : //Stripe SCA
$config = $request->get('stripe_sca');
break;
}
PaymentGateway::query()->update(['default' => 0]);
$payment_gateway = PaymentGateway::where('id', '=', $gateway_id)->first();
$payment_gateway->default = 1;
$payment_gateway->save();
$account_payment_gateway = AccountPaymentGateway::firstOrNew(
[
'payment_gateway_id' => $gateway_id,

View File

@ -153,6 +153,16 @@ Route::group(
'uses' => 'EventCheckoutController@postValidateTickets',
]);
Route::post('{event_id}/checkout/validate', [
'as' => 'postValidateOrder',
'uses' => 'EventCheckoutController@postValidateOrder',
]);
Route::get('{event_id}/checkout/payment', [
'as' => 'showEventPayment',
'uses' => 'EventCheckoutController@showEventPayment',
]);
Route::get('{event_id}/checkout/create', [
'as' => 'showEventCheckout',
'uses' => 'EventCheckoutController@showEventCheckout',
@ -163,7 +173,6 @@ Route::group(
'uses' => 'EventCheckoutController@showEventCheckoutPaymentReturn',
]);
Route::post('{event_id}/checkout/create', [
'as' => 'postCreateOrder',
'uses' => 'EventCheckoutController@postCreateOrder',

View File

@ -9,5 +9,38 @@ namespace App\Models;
class PaymentGateway extends MyBaseModel
{
public $timestamps = false;
/**
* @return array
*/
static public function getAllWithDefaultSet()
{
$payment_gateways = PaymentGateway::all()->toArray();
$payment_gateway = PaymentGateway::select('id')->where('default', 1)->get()->first();
if (empty($payment_gateway)) {
$default_payment_gateway_id = config('attendize.default_payment_gateway');
foreach ($payment_gateways as &$payment_gateway) {
if ($payment_gateway['id'] == $default_payment_gateway_id) {
$payment_gateway['default'] = 1;
}
}
}
return $payment_gateways;
}
/**
* @return \Illuminate\Config\Repository|mixed
*/
static public function getDefaultPaymentGatewayId()
{
$payment_gateway = PaymentGateway::select('id')->where('default', 1)->get()->first();
if (empty($payment_gateway)) {
$default_payment_gateway_id = config('attendize.default_payment_gateway');
return $default_payment_gateway_id;
}
return $payment_gateway['id'];
}
}

View File

@ -33,12 +33,13 @@
"omnipay/common": "~3",
"omnipay/dummy": "~3",
"omnipay/paypal": "~3",
"omnipay/stripe": "~3",
"omnipay/stripe": "3.1.x-dev",
"php-http/curl-client": "^1.7",
"php-http/message": "^1.6",
"predis/predis": "~1.1",
"vinelab/http": "~1.5",
"laravel/tinker": "^1.0"
"laravel/tinker": "^1.0",
"stripe/stripe-php": "^6.43"
},
"require-dev": {
"phpunit/phpunit": "7.3.*",

1244
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,144 +1,160 @@
function getAjaxFormConfig(form) {
var $form = form;
var $submitButton = $form.find('input[type=submit]');
toggleSubmitDisabled($submitButton);
var ajaxFormConf = {
delegation: true,
beforeSerialize: function (jqForm, options) {
window.doSubmit = true;
clearFormErrors(jqForm[0]);
toggleSubmitDisabled($submitButton);
},
beforeSubmit: function () {
$submitButton = $form.find('input[type=submit]');
toggleSubmitDisabled($submitButton);
return window.doSubmit;
},
error: function (data, statusText, xhr, $form) {
$submitButton = $form.find('input[type=submit]');
// Form validation error.
if (422 == data.status) {
processFormErrors($form, $.parseJSON(data.responseText));
return;
}
toggleSubmitDisabled($submitButton);
showMessage(lang("whoops"));
},
success: function (data, statusText, xhr, $form) {
var $submitButton = $form.find('input[type=submit]');
if (data.message) {
showMessage(data.message);
}
switch (data.status) {
case 'success':
if (data.redirectUrl) {
if (data.redirectData) {
$.redirectPost(data.redirectUrl, data.redirectData);
} else {
document.location.href = data.redirectUrl;
}
}
break;
case 'error':
if (data.messages) {
processFormErrors($form, data.messages);
return;
}
break;
default:
break;
}
toggleSubmitDisabled($submitButton);
},
dataType: 'json'
};
return ajaxFormConf;
}
$(function() {
$('form.ajax').on('submit', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
var $form =
$(this),
$submitButton = $form.find('input[type=submit]'),
ajaxFormConf = {
delegation: true,
beforeSerialize: function(jqForm, options) {
window.doSubmit = true;
clearFormErrors(jqForm[0]);
toggleSubmitDisabled($submitButton);
},
beforeSubmit: function() {
$submitButton = $form.find('input[type=submit]');
toggleSubmitDisabled($submitButton);
return window.doSubmit;
},
error: function(data, statusText, xhr, $form) {
$submitButton = $form.find('input[type=submit]');
var ajaxFormConf = getAjaxFormConfig($(this));
// Form validation error.
if (422 == data.status) {
processFormErrors($form, $.parseJSON(data.responseText));
return;
}
$(this).ajaxSubmit(ajaxFormConf);
toggleSubmitDisabled($submitButton);
showMessage(lang("whoops"));
},
success: function(data, statusText, xhr, $form) {
var $submitButton = $form.find('input[type=submit]');
if (data.message) {
showMessage(data.message);
}
switch (data.status) {
case 'success':
if (data.redirectUrl) {
if(data.redirectData) {
$.redirectPost(data.redirectUrl, data.redirectData);
} else {
document.location.href = data.redirectUrl;
}
}
break;
case 'error':
if (data.messages) {
processFormErrors($form, data.messages);
return;
}
break;
default:
break;
}
toggleSubmitDisabled($submitButton);
},
dataType: 'json'
};
toggleSubmitDisabled($submitButton);
if ($form.hasClass('payment-form') && !$('#pay_offline').is(":checked")) {
clearFormErrors($('.payment-form'));
Stripe.setPublishableKey($form.data('stripe-pub-key'));
var
noErrors = true,
$cardNumber = $('.card-number'),
$cardName = $('.card-name'),
$cvcNumber = $('.card-cvc'),
$expiryMonth = $('.card-expiry-month'),
$expiryYear = $('.card-expiry-year');
if (!Stripe.validateCardNumber($cardNumber.val())) {
showFormError($cardNumber, lang("credit_card_error"));
noErrors = false;
}
if (!Stripe.validateCVC($cvcNumber.val())) {
showFormError($cardNumber, lang("cvc_error"));
noErrors = false;
}
if (!Stripe.validateExpiry($expiryMonth.val(), $expiryYear.val())) {
showFormError($cardNumber, lang("expiry_error"));
showFormError($expiryYear, '');
noErrors = false;
}
if (noErrors) {
Stripe.card.createToken({
name: $cardName.val(),
number: $cardNumber.val(),
cvc: $cvcNumber.val(),
exp_month: $expiryMonth.val(),
exp_year: $expiryYear.val()
},
function(status, response) {
if (response.error) {
clearFormErrors($('.payment-form'));
if(response.error.param.length>0)
showFormError($('*[data-stripe=' + response.error.param + ']', $('.payment-form')), response.error.message);
else
showMessage(response.error.message);
toggleSubmitDisabled($submitButton);
} else {
var token = response.id;
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
$form.ajaxSubmit(ajaxFormConf);
}
});
} else {
showMessage(lang("card_validation_error"));
toggleSubmitDisabled($submitButton);
}
} else {
$form.ajaxSubmit(ajaxFormConf);
}
});
//handles stripe payment form submit
$('#stripe-payment-form').on('submit', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
stripe.createToken(card).then(function (result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
var form = document.getElementById('stripe-payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
var $ajaxFormConf = getAjaxFormConfig($('#stripe-payment-form'));
$('#stripe-payment-form').ajaxSubmit($ajaxFormConf);
}
$('#stripe-sca-payment-form').on('submit', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
stripe.createPaymentMethod(
'card',
cardElement
).then(function (result) {
if (result.error) {
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
stripePaymentMethodHandler(result.paymentMethod);
}
});
});
function stripePaymentMethodHandler(paymentMethod) {
var form = document.getElementById('stripe-sca-payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'paymentMethod');
hiddenInput.setAttribute('value', paymentMethod.id);
form.appendChild(hiddenInput);
var $ajaxFormConf = getAjaxFormConfig($('#stripe-sca-payment-form'));
$('#stripe-sca-payment-form').ajaxSubmit($ajaxFormConf);
}
$('#pay_offline').change(function () {
$('.online_payment').toggle(!this.checked);
$('.offline_payment').toggle(this.checked);
}).change();
$('a').smoothScroll({
offset: -60
});
/* Scroll to top */
$(window).scroll(function() {
if ($(this).scrollTop() > 100) {
@ -167,15 +183,6 @@ $(function() {
$('.card-number').payment('formatCardNumber');
$('.card-cvc').payment('formatCardCVC');
$('#pay_offline').change(function () {
$('.online_payment').toggle(!this.checked);
$('.offline_payment').toggle(this.checked);
// Disable CC form inputs to prevent Chrome trying to validate hidden fields
$('.online_payment input, .online_payment select').attr('disabled', this.checked);
}).change();
// Apply access code here to unlock hidden tickets
$('#apply_access_code').click(function(e) {
var $clicked = $(this);

View File

@ -4566,147 +4566,163 @@ function log() {
};
}).call(this);
;$(function() {
;function getAjaxFormConfig(form) {
var $form = form;
var $submitButton = $form.find('input[type=submit]');
toggleSubmitDisabled($submitButton);
var ajaxFormConf = {
delegation: true,
beforeSerialize: function (jqForm, options) {
window.doSubmit = true;
clearFormErrors(jqForm[0]);
toggleSubmitDisabled($submitButton);
},
beforeSubmit: function () {
$submitButton = $form.find('input[type=submit]');
toggleSubmitDisabled($submitButton);
return window.doSubmit;
},
error: function (data, statusText, xhr, $form) {
$submitButton = $form.find('input[type=submit]');
// Form validation error.
if (422 == data.status) {
processFormErrors($form, $.parseJSON(data.responseText));
return;
}
toggleSubmitDisabled($submitButton);
showMessage(lang("whoops"));
},
success: function (data, statusText, xhr, $form) {
var $submitButton = $form.find('input[type=submit]');
if (data.message) {
showMessage(data.message);
}
switch (data.status) {
case 'success':
if (data.redirectUrl) {
if (data.redirectData) {
$.redirectPost(data.redirectUrl, data.redirectData);
} else {
document.location.href = data.redirectUrl;
}
}
break;
case 'error':
if (data.messages) {
processFormErrors($form, data.messages);
return;
}
break;
default:
break;
}
toggleSubmitDisabled($submitButton);
},
dataType: 'json'
};
return ajaxFormConf;
}
$(function() {
$('form.ajax').on('submit', function(e) {
e.preventDefault();
e.stopImmediatePropagation();
var $form =
$(this),
$submitButton = $form.find('input[type=submit]'),
ajaxFormConf = {
delegation: true,
beforeSerialize: function(jqForm, options) {
window.doSubmit = true;
clearFormErrors(jqForm[0]);
toggleSubmitDisabled($submitButton);
},
beforeSubmit: function() {
$submitButton = $form.find('input[type=submit]');
toggleSubmitDisabled($submitButton);
return window.doSubmit;
},
error: function(data, statusText, xhr, $form) {
$submitButton = $form.find('input[type=submit]');
var ajaxFormConf = getAjaxFormConfig($(this));
// Form validation error.
if (422 == data.status) {
processFormErrors($form, $.parseJSON(data.responseText));
return;
}
$(this).ajaxSubmit(ajaxFormConf);
toggleSubmitDisabled($submitButton);
showMessage(lang("whoops"));
},
success: function(data, statusText, xhr, $form) {
var $submitButton = $form.find('input[type=submit]');
if (data.message) {
showMessage(data.message);
}
switch (data.status) {
case 'success':
if (data.redirectUrl) {
if(data.redirectData) {
$.redirectPost(data.redirectUrl, data.redirectData);
} else {
document.location.href = data.redirectUrl;
}
}
break;
case 'error':
if (data.messages) {
processFormErrors($form, data.messages);
return;
}
break;
default:
break;
}
toggleSubmitDisabled($submitButton);
},
dataType: 'json'
};
toggleSubmitDisabled($submitButton);
if ($form.hasClass('payment-form') && !$('#pay_offline').is(":checked")) {
clearFormErrors($('.payment-form'));
Stripe.setPublishableKey($form.data('stripe-pub-key'));
var
noErrors = true,
$cardNumber = $('.card-number'),
$cardName = $('.card-name'),
$cvcNumber = $('.card-cvc'),
$expiryMonth = $('.card-expiry-month'),
$expiryYear = $('.card-expiry-year');
if (!Stripe.validateCardNumber($cardNumber.val())) {
showFormError($cardNumber, lang("credit_card_error"));
noErrors = false;
}
if (!Stripe.validateCVC($cvcNumber.val())) {
showFormError($cardNumber, lang("cvc_error"));
noErrors = false;
}
if (!Stripe.validateExpiry($expiryMonth.val(), $expiryYear.val())) {
showFormError($cardNumber, lang("expiry_error"));
showFormError($expiryYear, '');
noErrors = false;
}
if (noErrors) {
Stripe.card.createToken({
name: $cardName.val(),
number: $cardNumber.val(),
cvc: $cvcNumber.val(),
exp_month: $expiryMonth.val(),
exp_year: $expiryYear.val()
},
function(status, response) {
if (response.error) {
clearFormErrors($('.payment-form'));
if(response.error.param.length>0)
showFormError($('*[data-stripe=' + response.error.param + ']', $('.payment-form')), response.error.message);
else
showMessage(response.error.message);
toggleSubmitDisabled($submitButton);
} else {
var token = response.id;
$form.append($('<input type="hidden" name="stripeToken" />').val(token));
$form.ajaxSubmit(ajaxFormConf);
}
});
} else {
showMessage(lang("card_validation_error"));
toggleSubmitDisabled($submitButton);
}
} else {
$form.ajaxSubmit(ajaxFormConf);
}
});
//handles stripe payment form submit
$('#stripe-payment-form').on('submit', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
stripe.createToken(card).then(function (result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
function stripeTokenHandler(token) {
var form = document.getElementById('stripe-payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
var $ajaxFormConf = getAjaxFormConfig($('#stripe-payment-form'));
$('#stripe-payment-form').ajaxSubmit($ajaxFormConf);
}
$('#stripe-sca-payment-form').on('submit', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
stripe.createPaymentMethod(
'card',
cardElement
).then(function (result) {
if (result.error) {
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
stripePaymentMethodHandler(result.paymentMethod);
}
});
});
function stripePaymentMethodHandler(paymentMethod) {
var form = document.getElementById('stripe-sca-payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'paymentMethod');
hiddenInput.setAttribute('value', paymentMethod.id);
form.appendChild(hiddenInput);
var $ajaxFormConf = getAjaxFormConfig($('#stripe-sca-payment-form'));
$('#stripe-sca-payment-form').ajaxSubmit($ajaxFormConf);
}
$('#pay_offline').change(function () {
$('.online_payment').toggle(!this.checked);
$('.offline_payment').toggle(this.checked);
}).change();
$('a').smoothScroll({
offset: -60
});
/* Scroll to top */
$(window).scroll(function() {
if ($(this).scrollTop() > 100) {
@ -4735,15 +4751,6 @@ function log() {
$('.card-number').payment('formatCardNumber');
$('.card-cvc').payment('formatCardCVC');
$('#pay_offline').change(function () {
$('.online_payment').toggle(!this.checked);
$('.offline_payment').toggle(this.checked);
// Disable CC form inputs to prevent Chrome trying to validate hidden fields
$('.online_payment input, .online_payment select').attr('disabled', this.checked);
}).change();
// Apply access code here to unlock hidden tickets
$('#apply_access_code').click(function(e) {
var $clicked = $(this);

View File

@ -27,6 +27,7 @@ return [
'business_address_code' => 'Code',
'card_number' => 'Card number',
'checkout_submit' => 'Checkout',
'checkout_order' => 'Contine to Payment',
'confirmation_email' => 'and a confirmation email have been sent to you.',
'copy_buyer' => 'Copy buyer details to all ticket holders',
'currently_not_on_sale' => 'Currently Not On Sale',

View File

@ -1,9 +1,10 @@
<script>
$(function() {
$('.payment_gateway_options').hide();
$('#gateway_{{$account->payment_gateway_id}}').show();
$('.gateway_selector').on('change', function(e) {
$('.payment_gateway_options').hide();
$('#gateway_{{ $default_payment_gateway_id }}').show();
$('input[type=radio][name=payment_gateway]').on('change', function(e) {
$('.payment_gateway_options').hide();
$('#gateway_' + $(this).val()).fadeIn();
});
@ -11,10 +12,17 @@
});
</script>
{!! Form::model($account, array('url' => route('postEditAccountPayment'), 'class' => 'ajax ')) !!}
<div class="form-group">
{!! Form::label('payment_gateway_id', trans("ManageAccount.default_payment_gateway"), array('class'=>'control-label ')) !!}
{!! Form::select('payment_gateway_id', $payment_gateways, $account->payment_gateway_id, ['class' => 'form-control gateway_selector']) !!}
{!! Form::label('payment_gateway_id', trans("ManageAccount.default_payment_gateway"), array('class'=>'control-label ')) !!}<br />
@foreach ($payment_gateways as $id => $payment_gateway)
{!! Form::radio('payment_gateway', $payment_gateway['id'], $payment_gateway['default'], array('id'=>'payment_gateway_' . $payment_gateway['id'])) !!}
{!! Form::label($payment_gateway['provider_name'],$payment_gateway['provider_name'] , array('class'=>'control-label gateway_selector')) !!}<br />
@endforeach
</div>
{{--Stripe--}}
@ -36,6 +44,25 @@
</div>
</section>
{{--Stripe SCA--}}
<section class="payment_gateway_options" id="gateway_{{config('attendize.payment_gateway_stripe_sca')}}">
<h4>@lang("ManageAccount.stripe_settings")</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
{!! Form::label('stripe_sca[apiKey]', trans("ManageAccount.stripe_secret_key"), array('class'=>'control-label ')) !!}
{!! Form::text('stripe_sca[apiKey]', $account->getGatewayConfigVal(config('attendize.payment_gateway_stripe_sca'), 'apiKey'),[ 'class'=>'form-control']) !!}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
{!! Form::label('publishableKey', trans("ManageAccount.stripe_publishable_key"), array('class'=>'control-label ')) !!}
{!! Form::text('stripe_sca[publishableKey]', $account->getGatewayConfigVal(config('attendize.payment_gateway_stripe_sca'), 'publishableKey'),[ 'class'=>'form-control']) !!}
</div>
</div>
</div>
</section>
{{--Paypal--}}
<section class="payment_gateway_options" id="gateway_{{config('attendize.payment_gateway_paypal')}}">
<h4>@lang("ManageAccount.paypal_settings")</h4>
@ -73,8 +100,6 @@
</div>
</div>
</div>
</section>
<div class="row">

View File

@ -1,7 +1,7 @@
@extends('Public.ViewEvent.Layouts.EventPage')
@section('head')
<script type="text/javascript" src="https://js.stripe.com/v2/"></script>
@stop
@section('content')

View File

@ -0,0 +1,12 @@
@extends('Public.ViewEvent.Layouts.EventPage')
@section('head')
@stop
@section('content')
@include('Public.ViewEvent.Partials.EventHeaderSection')
@include('Public.ViewEvent.Partials.EventPaymentSection')
@include('Public.ViewEvent.Partials.EventFooterSection')
@stop

View File

@ -58,7 +58,7 @@
</div>
<div class="col-md-8 col-md-pull-4">
<div class="event_order_form">
{!! Form::open(['url' => route('postCreateOrder', ['event_id' => $event->id]), 'class' => ($order_requires_payment && @$payment_gateway->is_on_site) ? 'ajax payment-form' : 'ajax', 'data-stripe-pub-key' => isset($account_payment_gateway->config['publishableKey']) ? $account_payment_gateway->config['publishableKey'] : '']) !!}
{!! Form::open(['url' => route('postValidateOrder', ['event_id' => $event->id ]) ]) !!}
{!! Form::hidden('event_id', $event->id) !!}
@ -201,10 +201,7 @@
@include('Public.ViewEvent.Partials.AttendeeQuestions', ['ticket' => $ticket['ticket'],'attendee_number' => $total_attendee_increment++])
</div>
</div>
</div>
@endfor
@endforeach
@ -212,82 +209,6 @@
</div>
</div>
<style>
.offline_payment_toggle {
padding: 20px 0;
}
</style>
@if($order_requires_payment)
<h3>@lang("Public_ViewEvent.payment_information")</h3>
@lang("Public_ViewEvent.below_payment_information_header")
@if($event->enable_offline_payments)
<div class="offline_payment_toggle">
<div class="custom-checkbox">
@if($payment_gateway === false)
{{-- Force offline payment if no gateway --}}
<input type="hidden" name="pay_offline" value="1">
<input id="pay_offline" type="checkbox" value="1" checked disabled>
@else
<input data-toggle="toggle" id="pay_offline" name="pay_offline" type="checkbox" value="1">
@endif
<label for="pay_offline">@lang("Public_ViewEvent.pay_using_offline_methods")</label>
</div>
</div>
<div class="offline_payment" style="display: none;">
<h5>@lang("Public_ViewEvent.offline_payment_instructions")</h5>
<div class="well">
{!! Markdown::parse($event->offline_payment_instructions) !!}
</div>
</div>
@endif
@if(@$payment_gateway->is_on_site)
<div class="online_payment">
<div class="row">
<div class="col-md-12">
<div class="form-group">
{!! Form::label('card-number', trans("Public_ViewEvent.card_number")) !!}
<input required="required" type="text" autocomplete="off" placeholder="**** **** **** ****" class="form-control card-number" size="20" data-stripe="number">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<div class="form-group">
{!! Form::label('card-expiry-month', trans("Public_ViewEvent.expiry_month")) !!}
{!! Form::selectRange('card-expiry-month',1,12,null, [
'class' => 'form-control card-expiry-month',
'data-stripe' => 'exp_month'
] ) !!}
</div>
</div>
<div class="col-xs-6">
<div class="form-group">
{!! Form::label('card-expiry-year', trans("Public_ViewEvent.expiry_year")) !!}
{!! Form::selectRange('card-expiry-year',date('Y'),date('Y')+10,null, [
'class' => 'form-control card-expiry-year',
'data-stripe' => 'exp_year'
] ) !!}</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
{!! Form::label('card-expiry-year', trans("Public_ViewEvent.cvc_number")) !!}
<input required="required" placeholder="***" class="form-control card-cvc" data-stripe="cvc">
</div>
</div>
</div>
</div>
@endif
@endif
@if($event->pre_order_display_message)
<div class="well well-small">
{!! nl2br(e($event->pre_order_display_message)) !!}
@ -295,7 +216,8 @@
@endif
{!! Form::hidden('is_embedded', $is_embedded) !!}
{!! Form::submit(trans("Public_ViewEvent.checkout_submit"), ['class' => 'btn btn-lg btn-success card-submit', 'style' => 'width:100%;']) !!}
{!! Form::submit(trans("Public_ViewEvent.checkout_order"), ['class' => 'btn btn-lg btn-success card-submit', 'style' => 'width:100%;']) !!}
{!! Form::close() !!}
</div>
</div>

View File

@ -0,0 +1,84 @@
<section id='order_form' class="container">
<div class="row">
<h1 class="section_head">
@lang("Public_ViewEvent.payment_information")
</h1>
</div>
<div class="row">
<div class="col-md-12" style="text-align: center">
@lang("Public_ViewEvent.below_order_details_header")
</div>
<div class="col-md-4 col-md-push-8">
<div class="panel">
<div class="panel-heading">
<h3 class="panel-title">
<i class="ico-cart mr5"></i>
@lang("Public_ViewEvent.order_summary")
</h3>
</div>
<div class="panel-body pt0">
<table class="table mb0 table-condensed">
@foreach($tickets as $ticket)
<tr>
<td class="pl0">{{{$ticket['ticket']['title']}}} X <b>{{$ticket['qty']}}</b></td>
<td style="text-align: right;">
@if((int)ceil($ticket['full_price']) === 0)
@lang("Public_ViewEvent.free")
@else
{{ money($ticket['full_price'], $event->currency) }}
@endif
</td>
</tr>
@endforeach
</table>
</div>
@if($order_total > 0)
<div class="panel-footer">
<h5>
@lang("Public_ViewEvent.total"): <span style="float: right;"><b>{{ $orderService->getOrderTotalWithBookingFee(true) }}</b></span>
</h5>
@if($event->organiser->charge_tax)
<h5>
{{ $event->organiser->tax_name }} ({{ $event->organiser->tax_value }}%):
<span style="float: right;"><b>{{ $orderService->getTaxAmount(true) }}</b></span>
</h5>
<h5>
<strong>@lang("Public_ViewEvent.grand_total")</strong>
<span style="float: right;"><b>{{ $orderService->getGrandTotal(true) }}</b></span>
</h5>
@endif
</div>
@endif
</div>
<div class="help-block">
{!! @trans("Public_ViewEvent.time", ["time"=>"<span id='countdown'></span>"]) !!}
</div>
</div>
<div class="col-md-8 col-md-pull-4">
<div class="row">
{{ $payment_gateway->name }}
@if($order_requires_payment)
@include('Public.ViewEvent.Partials.OfflinePayments')
@endif
@if($payment_gateway->name == 'Stripe')
@include('Public.ViewEvent.Partials.PaymentStripe')
@endif
@if($payment_gateway->name == 'Stripe\PaymentIntents')
@include('Public.ViewEvent.Partials.PaymentStripeSCA')
@endif
</div>
</div>
</div>
<img src="https://cdn.attendize.com/lg.png" />
</section>
@if(session()->get('message'))
<script>showMessage('{{session()->get('message')}}');</script>
@endif

View File

@ -0,0 +1,30 @@
<h3>@lang("Public_ViewEvent.payment_information")</h3>
@lang("Public_ViewEvent.below_payment_information_header")
@if($event->enable_offline_payments)
{!! Form::open(['url' => route('postCreateOrder', ['event_id' => $event->id]), 'class' => 'ajax']) !!}
<div class="offline_payment_toggle">
<div class="custom-checkbox">
@if($payment_gateway === false)
{{-- Force offline payment if no gateway --}}
<input type="hidden" name="pay_offline" value="1">
<input id="pay_offline" type="checkbox" value="1" checked disabled>
@else
<input data-toggle="toggle" id="pay_offline" name="pay_offline" type="checkbox" value="1">
@endif
<label for="pay_offline">@lang("Public_ViewEvent.pay_using_offline_methods")</label>
</div>
</div>
<div class="offline_payment" style="display: none;">
<h5>@lang("Public_ViewEvent.offline_payment_instructions")</h5>
<div class="well">
{!! Markdown::parse($event->offline_payment_instructions) !!}
</div>
<input class="btn btn-lg btn-success card-submit" style="width:100%;" type="submit" value="Complete Order">
</div>
{!! Form::close() !!}
<style>
.offline_payment_toggle {
padding: 20px 0;
}
</style>
@endif

View File

@ -0,0 +1,83 @@
<form class="online_payment" action="<?php echo route('postCreateOrder', ['event_id' => $event->id]); ?>" method="post" id="stripe-payment-form">
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element">
</div>
<div id="card-errors" role="alert"></div>
</div>
{!! Form::token() !!}
<input class="btn btn-lg btn-success card-submit" style="width:100%;" type="submit" value="Complete Payment">
</form>
<script type="text/javascript" src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
var stripe = Stripe('<?php echo $account_payment_gateway->config['publishableKey']; ?>');
var elements = stripe.elements();
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
var card = elements.create('card', {style: style});
card.mount('#card-element');
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
</script>
<style type="text/css">
.StripeElement {
box-sizing: border-box;
height: 40px;
padding: 10px 12px;
border: 1px solid transparent;
border-radius: 4px;
background-color: white;
box-shadow: 0 1px 3px 0 #e6ebf1;
-webkit-transition: box-shadow 150ms ease;
transition: box-shadow 150ms ease;
}
.StripeElement--focus {
box-shadow: 0 1px 3px 0 #cfd7df;
}
.StripeElement--invalid {
border-color: #fa755a;
}
.StripeElement--webkit-autofill {
background-color: #fefde5 !important;
}
</style>

View File

@ -0,0 +1,85 @@
<form class="online_payment" action="<?php echo route('postCreateOrder', ['event_id' => $event->id]); ?>" method="post" id="stripe-sca-payment-form">
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element">
</div>
<div id="card-errors" role="alert"></div>
</div>
{!! Form::token() !!}
<button id="card-button" data-secret="<?php echo $client_secret; ?>">
Submit Payment
</button>
</form>
<script type="text/javascript" src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
var stripe = Stripe('<?php echo $account_payment_gateway->config['publishableKey']; ?>');
var elements = stripe.elements();
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
var cardElement = elements.create('card', {style: style});
cardElement.mount('#card-element');
cardElement.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
</script>
<style type="text/css">
.StripeElement {
box-sizing: border-box;
height: 40px;
padding: 10px 12px;
border: 1px solid transparent;
border-radius: 4px;
background-color: white;
box-shadow: 0 1px 3px 0 #e6ebf1;
-webkit-transition: box-shadow 150ms ease;
transition: box-shadow 150ms ease;
}
.StripeElement--focus {
box-shadow: 0 1px 3px 0 #cfd7df;
}
.StripeElement--invalid {
border-color: #fa755a;
}
.StripeElement--webkit-autofill {
background-color: #fefde5 !important;
}
</style>