Merge pull request #683 from Attendize/stripe-sca-payment

Added Stripe SCA payment gateway as an option.
This commit is contained in:
Jeremy Quinton 2019-09-16 12:01:22 +02:00 committed by GitHub
commit 7ca897ff72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 2270 additions and 1111 deletions

View File

@ -16,6 +16,7 @@ use App\Models\QuestionAnswer;
use App\Models\ReservedTickets;
use App\Models\Ticket;
use App\Services\Order as OrderService;
use App\Services\PaymentGateway\Factory as PaymentGatewayFactory;
use Carbon\Carbon;
use Cookie;
use DB;
@ -180,22 +181,17 @@ class EventCheckoutController extends Controller
]);
}
if (config('attendize.enable_dummy_payment_gateway') == TRUE) {
$activeAccountPaymentGateway = new AccountPaymentGateway();
$activeAccountPaymentGateway->fill(['payment_gateway_id' => config('attendize.payment_gateway_dummy')]);
$paymentGateway = $activeAccountPaymentGateway;
} else {
$activeAccountPaymentGateway = $event->account->getGateway($event->account->payment_gateway_id);
//if no payment gateway configured and no offline pay, don't go to the next step and show user error
if (empty($activeAccountPaymentGateway) && !$event->enable_offline_payments) {
return response()->json([
'status' => 'error',
'message' => 'No payment gateway configured',
]);
}
$paymentGateway = $activeAccountPaymentGateway ? $activeAccountPaymentGateway->payment_gateway : false;
$activeAccountPaymentGateway = $event->account->getGateway($event->account->payment_gateway_id);
//if no payment gateway configured and no offline pay, don't go to the next step and show user error
if (empty($activeAccountPaymentGateway) && !$event->enable_offline_payments) {
return response()->json([
'status' => 'error',
'message' => 'No payment gateway configured',
]);
}
$paymentGateway = $activeAccountPaymentGateway ? $activeAccountPaymentGateway->payment_gateway : false;
/*
* The 'ticket_order_{event_id}' session stores everything we need to complete the transaction.
*/
@ -274,16 +270,10 @@ 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)
{
//If there's no session kill the request and redirect back to the event homepage.
if (!session()->get('ticket_order_' . $event_id)) {
@ -296,6 +286,13 @@ class EventCheckoutController extends Controller
]);
}
$request_data = session()->get('ticket_order_' . $event_id . ".request_data");
$request_data = (!empty($request_data[0])) ? array_merge($request_data[0], $request->all())
: $request->all();
session()->remove('ticket_order_' . $event_id . '.request_data');
session()->push('ticket_order_' . $event_id . '.request_data', $request_data);
$event = Event::findOrFail($event_id);
$order = new Order();
$ticket_order = session()->get('ticket_order_' . $event_id);
@ -335,92 +332,96 @@ class EventCheckoutController extends Controller
]);
}
//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']));
return response()->json([
'status' => 'success',
'redirectUrl' => route('showEventPayment', [
'event_id' => $event_id,
'is_embedded' => $this->is_embedded
])
]);
$orderRequiresPayment = $ticket_order['order_requires_payment'];
}
if ($orderRequiresPayment && $request->get('pay_offline') && $event->enable_offline_payments) {
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();
$payment_failed = $request->get('is_payment_failed') ? 1 : 0;
$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,
'payment_failed' => $payment_failed
];
return view('Public.ViewEvent.EventPagePayment', $viewData);
}
/**
* Create the order and start the payment for the order via Omnipay
*
*
* @param Request $request
* @param $event_id
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
* @throws \Exception
*/
public function postCreateOrder(Request $request, $event_id)
{
$request_data = $ticket_order = session()->get('ticket_order_' . $event_id . ".request_data");
$request_data = array_merge($request_data[0], $request->except(['cardnumber', 'cvc']));
session()->remove('ticket_order_' . $event_id . '.request_data');
session()->push('ticket_order_' . $event_id . '.request_data', $request_data);
$ticket_order = session()->get('ticket_order_' . $event_id);
$event = Event::findOrFail($event_id);
$order_requires_payment = $ticket_order['order_requires_payment'];
if ($order_requires_payment && $request->get('pay_offline') && $event->enable_offline_payments) {
return $this->completeOrder($event_id);
}
if (!$orderRequiresPayment) {
if (!$order_requires_payment) {
return $this->completeOrder($event_id);
}
try {
//more transation data being put in here.
$transaction_data = [];
if (config('attendize.enable_dummy_payment_gateway') == TRUE) {
$formData = config('attendize.fake_card_data');
$transaction_data = [
'card' => $formData
];
$gateway = Omnipay::create('Dummy');
$gateway->initialize();
$order_service = new OrderService($ticket_order['order_total'], $ticket_order['total_booking_fee'], $event);
$order_service->calculateFinalCosts();
} else {
$gateway = Omnipay::create($ticket_order['payment_gateway']->name);
$gateway->initialize($ticket_order['account_payment_gateway']->config + [
'testMode' => config('attendize.enable_test_payments'),
]);
}
$payment_gateway_config = $ticket_order['account_payment_gateway']->config + [
'testMode' => config('attendize.enable_test_payments')];
$orderService = new OrderService($ticket_order['order_total'], $ticket_order['total_booking_fee'], $event);
$orderService->calculateFinalCosts();
$payment_gateway_factory = new PaymentGatewayFactory();
$gateway = $payment_gateway_factory->create($ticket_order['payment_gateway']->name, $payment_gateway_config);
//certain payment gateways require an extra parameter here and there so this method takes care of that
//and sets certain options for the gateway that can be used when the transaction is started
$gateway->extractRequestParameters($request);
$transaction_data += [
'amount' => $orderService->getGrandTotal(),
'currency' => $event->currency->code,
'description' => 'Order for customer: ' . $request->get('order_email'),
];
//generic data that is needed for most orders
$order_total = $order_service->getGrandTotal();
$order_email = $ticket_order['request_data'][0]['order_email'];
//TODO: class with an interface that builds the transaction data.
switch ($ticket_order['payment_gateway']->id) {
case config('attendize.payment_gateway_dummy'):
$token = uniqid();
$transaction_data += [
'token' => $token,
'receipt_email' => $request->get('order_email'),
'card' => $formData
];
break;
case config('attendize.payment_gateway_paypal'):
$transaction_data += [
'cancelUrl' => route('showEventCheckoutPaymentReturn', [
'event_id' => $event_id,
'is_payment_cancelled' => 1
]),
'returnUrl' => route('showEventCheckoutPaymentReturn', [
'event_id' => $event_id,
'is_payment_successful' => 1
]),
'brandName' => isset($ticket_order['account_payment_gateway']->config['brandingName'])
? $ticket_order['account_payment_gateway']->config['brandingName']
: $event->organiser->name
];
break;
case config('attendize.payment_gateway_stripe'):
$token = $request->get('stripeToken');
$transaction_data += [
'token' => $token,
'receipt_email' => $request->get('order_email'),
];
break;
default:
Log::error('No payment gateway configured.');
return response()->json([
'status' => 'error',
'message' => 'No payment gateway configured.'
]);
break;
}
$transaction = $gateway->purchase($transaction_data);
$response = $transaction->send();
$response = $gateway->startTransaction($order_total, $order_email, $event);
if ($response->isSuccessful()) {
@ -431,11 +432,12 @@ class EventCheckoutController extends Controller
} elseif ($response->isRedirect()) {
/*
* As we're going off-site for payment we need to store some data in a session so it's available
* when we return
*/
session()->push('ticket_order_' . $event_id . '.transaction_data', $transaction_data);
$additionalData = ($gateway->storeAdditionalData()) ? $gateway->getAdditionalData($response) : array();
session()->push('ticket_order_' . $event_id . '.transaction_data',
$gateway->getTransactionData() + $additionalData);
Log::info("Redirect url: " . $response->getRedirectUrl());
$return = [
@ -472,43 +474,34 @@ class EventCheckoutController extends Controller
}
/**
* Attempt to complete a user's payment when they return from
* an off-site gateway
* Handles the return when a payment is off site
*
* @param Request $request
* @param $event_id
* @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse
* @throws \Exception
*/
public function showEventCheckoutPaymentReturn(Request $request, $event_id)
{
if ($request->get('is_payment_cancelled') == '1') {
session()->flash('message', trans('Event.payment_cancelled'));
return response()->redirectToRoute('showEventCheckout', [
'event_id' => $event_id,
'is_payment_cancelled' => 1,
]);
}
$ticket_order = session()->get('ticket_order_' . $event_id);
$gateway = Omnipay::create($ticket_order['payment_gateway']->name);
$gateway->initialize($ticket_order['account_payment_gateway']->config + [
'testMode' => config('attendize.enable_test_payments'),
]);
$payment_gateway_config = $ticket_order['account_payment_gateway']->config + [
'testMode' => config('attendize.enable_test_payments')];
$transaction = $gateway->completePurchase($ticket_order['transaction_data'][0]);
$payment_gateway_factory = new PaymentGatewayFactory();
$gateway = $payment_gateway_factory->create($ticket_order['payment_gateway']->name, $payment_gateway_config);
$gateway->extractRequestParameters($request);
$response = $gateway->completeTransaction($ticket_order['transaction_data'][0]);
$response = $transaction->send();
if ($response->isSuccessful()) {
session()->push('ticket_order_' . $event_id . '.transaction_id', $response->getTransactionReference());
return $this->completeOrder($event_id, false);
} else {
session()->flash('message', $response->getMessage());
return response()->redirectToRoute('showEventCheckout', [
return response()->redirectToRoute('showEventPayment', [
'event_id' => $event_id,
'is_payment_failed' => 1,
]);
@ -532,6 +525,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;
@ -543,6 +537,11 @@ class EventCheckoutController extends Controller
if (isset($ticket_order['transaction_id'])) {
$order->transaction_id = $ticket_order['transaction_id'][0];
}
if (isset($ticket_order['transaction_data'][0]['payment_intent'])) {
$order->payment_intent = $ticket_order['transaction_data'][0]['payment_intent'];
}
if ($ticket_order['order_requires_payment'] && !isset($request_data['pay_offline'])) {
$order->payment_gateway_id = $ticket_order['payment_gateway']->id;
}
@ -805,4 +804,3 @@ class EventCheckoutController extends Controller
}
}

View File

@ -8,7 +8,9 @@ use App\Models\Attendee;
use App\Models\Event;
use App\Models\EventStats;
use App\Models\Order;
use App\Models\PaymentGateway;
use App\Services\Order as OrderService;
use App\Services\PaymentGateway\Factory as PaymentGatewayFactory;
use DB;
use Excel;
use Illuminate\Http\Request;
@ -196,11 +198,10 @@ class EventOrdersController extends MyBaseController
/**
* Cancels an order
*
* @param Request $request
* @param $order_id
* @return mixed
* @return \Illuminate\Http\JsonResponse
* @throws \Exception
*/
public function postCancelOrder(Request $request, $order_id)
{
@ -244,24 +245,23 @@ class EventOrdersController extends MyBaseController
$order->event->currency))]);
}
if (!$error_message) {
try {
$gateway = Omnipay::create($order->payment_gateway->name);
$gateway->initialize($order->account->getGateway($order->payment_gateway->id)->config);
try {
$payment_gateway_config = $order->account->getGateway($order->payment_gateway->id)->config + [
'testMode' => config('attendize.enable_test_payments')];
$payment_gateway_factory = new PaymentGatewayFactory();
$gateway = $payment_gateway_factory->create($order->payment_gateway->name, $payment_gateway_config);
if ($refund_type === 'full') { /* Full refund */
$refund_amount = $order->organiser_amount - $order->amount_refunded;
}
$request = $gateway->refund([
'transactionReference' => $order->transaction_id,
'amount' => $refund_amount,
'refundApplicationFee' => floatval($order->booking_fee) > 0 ? true : false,
]);
$refund_application_fee = floatval($order->booking_fee) > 0 ? true : false;
$response = $gateway->refundTransaction($order, $refund_amount, $refund_application_fee);
$response = $request->send();
if ($response->isSuccessful()) {
if ($response['successful']) {
/* Update the event sales volume*/
$order->event->decrement('sales_volume', $refund_amount);
$order->amount_refunded = round(($order->amount_refunded + $refund_amount), 2);
@ -274,10 +274,11 @@ class EventOrdersController extends MyBaseController
$order->order_status_id = config('attendize.order_partially_refunded');
}
} else {
$error_message = $response->getMessage();
$error_message = $response['error_message'];
}
$order->save();
} catch (\Exeption $e) {
Log::error($e);
$error_message = trans("Controllers.refund_exception");

View File

@ -14,6 +14,9 @@ use HttpClient;
use Illuminate\Http\Request;
use Input;
use Mail;
use Services\PaymentGateway\Dummy;
use Services\PaymentGateway\Stripe;
use Services\PaymentGateway\StripeSCA;
use Validator;
use GuzzleHttp\Client;
@ -31,7 +34,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,17 +128,29 @@ 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
$payment_gateway = PaymentGateway::where('id', '=', $gateway_id)->first();
$config = [];
switch ($payment_gateway->name) {
case Stripe::GATEWAY_NAME :
$config = $request->get('stripe');
break;
case config('attendize.payment_gateway_paypal') : //PayPal
$config = $request->get('paypal');
case StripeSCA::GATEWAY_NAME :
$config = $request->get('stripe_sca');
break;
case Dummy::GATEWAY_NAME :
break;
}
PaymentGateway::query()->update(['default' => 0]);
$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

@ -0,0 +1,79 @@
<?php
namespace Services\PaymentGateway;
class Dummy
{
CONST GATEWAY_NAME = 'Dummy';
private $transaction_data;
private $gateway;
public function __construct($gateway)
{
$this->gateway = $gateway;
$this->options = [];
}
private function createTransactionData($order_total, $order_email, $event)
{
$token = uniqid();
$this->transaction_data = [
'amount' => $order_total,
'currency' => $event->currency->code,
'description' => 'Order for customer: ' . $order_email,
'card' => config('attendize.fake_card_data'),
'token' => $token,
'receipt_email' => $order_email
];
return $this->transaction_data;
}
public function startTransaction($order_total, $order_email, $event)
{
$this->createTransactionData($order_total, $order_email, $event);
$transaction = $this->gateway->purchase($this->transaction_data);
$response = $transaction->send();
return $response;
}
public function getTransactionData() {
return $this->transaction_data;
}
public function extractRequestParameters($request) {}
public function completeTransaction($transactionId) {}
public function getAdditionalData() {}
public function storeAdditionalData() {
return false;
}
public function refundTransaction($order, $refund_amount, $refund_application_fee) {
$request = $this->gateway->refund([
'transactionReference' => $order->transaction_id,
'amount' => $refund_amount,
'refundApplicationFee' => $refund_application_fee
]);
$response = $request->send();
if ($response->isSuccessful()) {
$refundResponse['successful'] = true;
} else {
$refundResponse['successful'] = false;
$refundResponse['error_message'] = $response->getMessage();
}
return $refundResponse;
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace App\Services\PaymentGateway;
use Illuminate\Support\Facades\Log;
use Omnipay\Omnipay;
use Services\PaymentGateway\Dummy;
use Services\PaymentGateway\Stripe;
use Services\PaymentGateway\StripeSCA;
/**
* The intention of this factory is to create a service that is a wrapper around the relative Omnipay implementation
* Each Gateway is a facade around the Omnipay implementation. Each Class can then handle the nuances. Additionally
* having a factory should make it easier to implement any Omnipay Gateway
*
* Class GatewayFactory
* @package App\Services\PaymentGateway
*/
class Factory
{
/**
* @param $name
* @param $paymentGatewayConfig
* @return Dummy|Stripe|StripeSCA
* @throws \Exception
*/
public function create($name, $paymentGatewayConfig)
{
switch ($name) {
case Dummy::GATEWAY_NAME :
{
$gateway = Omnipay::create($name);
$gateway->initialize();
return new Dummy($gateway, $paymentGatewayConfig);
}
case Stripe::GATEWAY_NAME :
{
$gateway = Omnipay::create($name);
$gateway->initialize($paymentGatewayConfig);
return new Stripe($gateway, $paymentGatewayConfig);
}
case StripeSCA::GATEWAY_NAME :
{
$gateway = Omnipay::create($name);
$gateway->initialize($paymentGatewayConfig);
return new StripeSCA($gateway, $paymentGatewayConfig);
}
default :
{
throw New \Exception('Invalid gateway specified');
}
}
}
}

View File

@ -0,0 +1,92 @@
<?php
namespace Services\PaymentGateway;
class Stripe
{
CONST GATEWAY_NAME = 'Stripe';
private $transaction_data;
private $gateway;
private $extra_params = ['stripeToken'];
public function __construct($gateway)
{
$this->gateway = $gateway;
$this->options = [];
}
private function createTransactionData($order_total, $order_email, $event)
{
$this->transaction_data = [
'amount' => $order_total,
'currency' => $event->currency->code,
'description' => 'Order for customer: ' . $order_email,
'token' => $this->options['stripeToken'],
'receipt_email' => $order_email
];
return $this->transaction_data;
}
public function startTransaction($order_total, $order_email, $event)
{
$this->createTransactionData($order_total, $order_email, $event);
$transaction = $this->gateway->purchase($this->transaction_data);
$response = $transaction->send();
return $response;
}
public function getTransactionData()
{
return $this->transaction_data;
}
public function extractRequestParameters($request)
{
foreach ($this->extra_params as $param) {
if (!empty($request->get($param))) {
$this->options[$param] = $request->get($param);
}
}
}
public function completeTransaction($transactionId)
{
}
public function getAdditionalData()
{
}
public function storeAdditionalData()
{
return false;
}
public function refundTransaction($order, $refund_amount, $refund_application_fee)
{
$request = $this->gateway->refund([
'transactionReference' => $order->transaction_id,
'amount' => $refund_amount,
'refundApplicationFee' => $refund_application_fee
]);
$response = $request->send();
if ($response->isSuccessful()) {
$refundResponse['successful'] = true;
} else {
$refundResponse['successful'] = false;
$refundResponse['error_message'] = $response->getMessage();
}
return $refundResponse;
}
}

View File

@ -0,0 +1,117 @@
<?php
namespace Services\PaymentGateway;
use Illuminate\Support\Facades\Log;
class StripeSCA
{
CONST GATEWAY_NAME = 'Stripe\PaymentIntents';
private $transaction_data;
private $gateway;
private $extra_params = ['paymentMethod', 'payment_intent'];
public function __construct($gateway)
{
$this->gateway = $gateway;
$this->options = [];
}
private function createTransactionData($order_total, $order_email, $event)
{
$returnUrl = route('showEventCheckoutPaymentReturn', [
'event_id' => $event->id,
'is_payment_successful' => 1,
]);
$this->transaction_data = [
'amount' => $order_total,
'currency' => $event->currency->code,
'description' => 'Order for customer: ' . $order_email,
'paymentMethod' => $this->options['paymentMethod'],
'receipt_email' => $order_email,
'returnUrl' => $returnUrl,
'confirm' => true
];
return $this->transaction_data;
}
public function startTransaction($order_total, $order_email, $event)
{
$this->createTransactionData($order_total, $order_email, $event);
$response = $this->gateway->authorize($this->transaction_data)->send();
return $response;
}
public function getTransactionData()
{
return $this->transaction_data;
}
public function extractRequestParameters($request)
{
foreach ($this->extra_params as $param) {
if (!empty($request->get($param))) {
$this->options[$param] = $request->get($param);
}
}
}
public function completeTransaction($transactionId = '')
{
$intentData = [
'paymentIntentReference' => $this->options['payment_intent'],
];
$paymentIntent = $this->gateway->fetchPaymentIntent($intentData);
$response = $paymentIntent->send();
if ($response->requiresConfirmation()) {
$response = $this->gateway->confirm($intentData)->send();
}
return $response;
}
public function getAdditionalData($response)
{
$additionalData['payment_intent'] = $response->getPaymentIntentReference();
return $additionalData;
}
public function storeAdditionalData()
{
return true;
}
public function refundTransaction($order, $refund_amount, $refund_application_fee)
{
$request = $this->gateway->cancel([
'transactionReference' => $order->transaction_id,
'amount' => $refund_amount,
'refundApplicationFee' => $refund_application_fee,
'paymentIntentReference' => $order->payment_intent
]);
$response = $request->send();
if ($response->isCancelled()) {
$refundResponse['successful'] = true;
} else {
$refundResponse['successful'] = false;
$refundResponse['error_message'] = $response->getMessage();
}
return $refundResponse;
}
}

View File

@ -33,12 +33,13 @@
"omnipay/common": "~3",
"omnipay/dummy": "~3",
"omnipay/paypal": "~3",
"omnipay/stripe": "~3",
"omnipay/stripe": "3.1",
"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.*",
@ -52,7 +53,8 @@
"database",
"app/Http/Controllers",
"app/Models",
"app/Attendize"
"app/Attendize",
"app/Services"
],
"psr-4": {
"App\\": "app/",

1410
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,78 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
use App\Models\PaymentGateway;
class AddDefaultGateways extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
PaymentGateway::where('name', 'PayPal_Express')->delete();
Schema::table('payment_gateways', function($table) {
$table->boolean('default')->default(0);
$table->string('admin_blade_template', 150)->default('');
$table->string('checkout_blade_template', 150)->default('');
});
Schema::table('orders', function($table) {
$table->string('payment_intent', 150)->default('');
});
DB::table('payment_gateways')
->where('provider_name', 'Stripe')
->update(['admin_blade_template' => 'ManageAccount.Partials.Stripe',
'checkout_blade_template' => 'Public.ViewEvent.Partials.PaymentStripe']);
$dummyGateway = DB::table('payment_gateways')->where('name', '=', 'Dummy')->first();
if ($dummyGateway === null) {
// user doesn't exist
DB::table('payment_gateways')->insert(
array(
'provider_name' => 'Dummy/Test Gateway',
'provider_url' => 'none',
'is_on_site' => 1,
'can_refund' => 1,
'name' => 'Dummy',
'default' => 0,
'admin_blade_template' => '',
'checkout_blade_template' => 'Public.ViewEvent.Partials.Dummy'
)
);
}
$stripePaymentIntents = DB::table('payment_gateways')->where('name', '=', 'Stripe\PaymentIntents')->first();
if ($stripePaymentIntents === null) {
DB::table('payment_gateways')->insert(
[
'provider_name' => 'Stripe SCA',
'provider_url' => 'https://www.stripe.com',
'is_on_site' => 0,
'can_refund' => 1,
'name' => 'Stripe\PaymentIntents',
'default' => 0,
'admin_blade_template' => 'ManageAccount.Partials.StripeSCA',
'checkout_blade_template' => 'Public.ViewEvent.Partials.PaymentStripeSCA'
]
);
}
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}

View File

@ -11,27 +11,56 @@ class PaymentGatewaySeeder extends Seeder
*/
public function run()
{
$payment_gateways = [
[
'id' => 1,
'name' => 'Stripe',
'provider_name' => 'Stripe',
'provider_url' => 'https://www.stripe.com',
'is_on_site' => 1,
'can_refund' => 1,
],
[
'id' => 2,
'name' => 'PayPal_Express',
'provider_name' => 'PayPal Express',
'provider_url' => 'https://www.paypal.com',
'is_on_site' => 0,
'can_refund' => 0
]
];
$dummyGateway = DB::table('payment_gateways')->where('name', '=', 'Dummy')->first();
DB::table('payment_gateways')->insert($payment_gateways);
if ($dummyGateway === null) {
// user doesn't exist
DB::table('payment_gateways')->insert(
[
'provider_name' => 'Dummy/Test Gateway',
'provider_url' => 'none',
'is_on_site' => 1,
'can_refund' => 1,
'name' => 'Dummy',
'default' => 0,
'admin_blade_template' => '',
'checkout_blade_template' => 'Public.ViewEvent.Partials.Dummy'
]
);
}
$stripe = DB::table('payment_gateways')->where('name', '=', 'Stripe')->first();
if ($stripe === null) {
DB::table('payment_gateways')->insert(
[
'name' => 'Stripe',
'provider_name' => 'Stripe',
'provider_url' => 'https://www.stripe.com',
'is_on_site' => 1,
'can_refund' => 1,
'default' => 0,
'admin_blade_template' => 'ManageAccount.Partials.Stripe',
'checkout_blade_template' => 'Public.ViewEvent.Partials.PaymentStripe'
]
);
}
$stripePaymentIntents = DB::table('payment_gateways')->where('name', '=', 'Stripe\PaymentIntents')->first();
if ($stripePaymentIntents === null) {
DB::table('payment_gateways')->insert(
[
'provider_name' => 'Stripe SCA',
'provider_url' => 'https://www.stripe.com',
'is_on_site' => 0,
'can_refund' => 1,
'name' => 'Stripe\PaymentIntents',
'default' => 0,
'admin_blade_template' => 'ManageAccount.Partials.StripeSCA',
'checkout_blade_template' => 'Public.ViewEvent.Partials.PaymentStripeSCA'
]
);
}
}
}
}

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

@ -31,6 +31,8 @@ return array (
'order_ref' => 'Reference',
'organiser_booking_fees' => 'Organiser Booking Fees',
'payment_gateway' => 'Payment Gateway',
'payment_intent' => 'Payment Intent',
'payment_failed' => 'Payment failed please try enter your payment details again.',
'price' => 'Price',
'purchase_date' => 'Purchase Date',
'quantity' => 'Quantity',

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();
$(function () {
$('.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,76 +12,37 @@
});
</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--}}
<section class="payment_gateway_options" id="gateway_{{config('attendize.payment_gateway_stripe')}}">
<h4>@lang("ManageAccount.stripe_settings")</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
{!! Form::label('stripe[apiKey]', trans("ManageAccount.stripe_secret_key"), array('class'=>'control-label ')) !!}
{!! Form::text('stripe[apiKey]', $account->getGatewayConfigVal(config('attendize.payment_gateway_stripe'), '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[publishableKey]', $account->getGatewayConfigVal(config('attendize.payment_gateway_stripe'), 'publishableKey'),[ 'class'=>'form-control']) !!}
</div>
</div>
</div>
</section>
@foreach ($payment_gateways as $id => $payment_gateway)
{{--Paypal--}}
<section class="payment_gateway_options" id="gateway_{{config('attendize.payment_gateway_paypal')}}">
<h4>@lang("ManageAccount.paypal_settings")</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
{!! Form::label('paypal[username]', trans("ManageAccount.paypal_username"), array('class'=>'control-label ')) !!}
{!! Form::text('paypal[username]', $account->getGatewayConfigVal(config('attendize.payment_gateway_paypal'), 'username'),[ 'class'=>'form-control']) !!}
</div>
</div>
<div class="col-md-6">
<div class="form-group">
{!! Form::label('paypal[password]', trans("ManageAccount.paypal_password"), ['class'=>'control-label ']) !!}
{!! Form::text('paypal[password]', $account->getGatewayConfigVal(config('attendize.payment_gateway_paypal'), 'password'),[ 'class'=>'form-control']) !!}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
{!! Form::label('paypal[signature]', trans("ManageAccount.paypal_signature"), array('class'=>'control-label ')) !!}
{!! Form::text('paypal[signature]', $account->getGatewayConfigVal(config('attendize.payment_gateway_paypal'), 'signature'),[ 'class'=>'form-control']) !!}
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
{!! Form::label('paypal[brandName]', trans("ManageAccount.branding_name"), array('class'=>'control-label ')) !!}
{!! Form::text('paypal[brandName]', $account->getGatewayConfigVal(config('attendize.payment_gateway_paypal'), 'brandName'),[ 'class'=>'form-control']) !!}
<div class="help-block">
@lang("ManageAccount.branding_name_help")
</div>
</div>
</div>
</div>
@if(View::exists($payment_gateway['admin_blade_template']))
@include($payment_gateway['admin_blade_template'])
@endif
</section>
@endforeach
<div class="row">
<div class="col-md-12">
<div class="panel-footer">
{!! Form::submit(trans("ManageAccount.save_payment_details_submit"), ['class' => 'btn btn-success pull-right']) !!}
{!! Form::submit(trans("ManageAccount.save_payment_details_submit"), ['class' => 'btn btn-success
pull-right']) !!}
</div>
</div>
</div>

View File

@ -0,0 +1,17 @@
<section class="payment_gateway_options" id="gateway_{{$payment_gateway['id']}}">
<h4>@lang("ManageAccount.stripe_settings")</h4>
<div class="row">
<div class="col-md-6">
<div class="form-group">
{!! Form::label('stripe[apiKey]', trans("ManageAccount.stripe_secret_key"), array('class'=>'control-label ')) !!}
{!! Form::text('stripe[apiKey]', $account->getGatewayConfigVal($payment_gateway['id'], '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[publishableKey]', $account->getGatewayConfigVal($payment_gateway['id'], 'publishableKey'),[ 'class'=>'form-control']) !!}
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,17 @@
<section class="payment_gateway_options" id="gateway_{{$payment_gateway['id']}}">
<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($payment_gateway['id'], '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($payment_gateway['id'], 'publishableKey'),[ 'class'=>'form-control']) !!}
</div>
</div>
</div>
</section>

View File

@ -70,6 +70,12 @@
</div>
@endif
@if($order->payment_intent)
<div class="col-sm-6 col-xs-6">
<b>@lang("Order.payment_intent")</b><br> {{$order->payment_intent}}
</div>
@endif
@if ($order->is_business)
<div class="col-sm-6 col-xs-6">
<b>@lang("Public_ViewEvent.business_name")</b><br />

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

@ -0,0 +1,46 @@
<form class="online_payment ajax" action="<?php echo route('postCreateOrder', ['event_id' => $event->id]); ?>" method="post">
<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="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' => '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' => '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="cvc">
</div>
</div>
</div>
{!! Form::token() !!}
<input class="btn btn-lg btn-success card-submit" style="width:100%;" type="submit" value="Complete Payment">
</div>
</form>

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 ]), 'class' => 'ajax payment-form']) !!}
{!! 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,85 @@
<section id='order_form' class="container">
<div class="row">
<h1 class="section_head">
@lang("Public_ViewEvent.payment_information")
</h1>
</div>
@if($payment_failed)
<div class="row">
<div class="col-md-8 alert-danger" style="text-align: left; padding: 10px">
@lang("Order.payment_failed")
</div>
</div>
@endif
<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">
@if($order_requires_payment)
@include('Public.ViewEvent.Partials.OfflinePayments')
@endif
@if(View::exists($payment_gateway['checkout_blade_template']))
@include($payment_gateway['checkout_blade_template'])
@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,85 @@
<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', {hidePostalCode: true, 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 #e0e0e0 !important;
border-radius: 4px;
background-color: white;
box-shadow: 0 1px 3px 0 #e6ebf1;
-webkit-transition: box-shadow 150ms ease;
transition: box-shadow 150ms ease;
margin-bottom: 20px;
}
.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,83 @@
<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() !!}
<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 cardElement = elements.create('card', {hidePostalCode: true, 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 #e0e0e0 !important;
border-radius: 4px;
background-color: white;
box-shadow: 0 1px 3px 0 #e6ebf1;
-webkit-transition: box-shadow 150ms ease;
transition: box-shadow 150ms ease;
margin-bottom: 20px;
}
.StripeElement--focus {
box-shadow: 0 1px 3px 0 #cfd7df;
}
.StripeElement--invalid {
border-color: #fa755a;
}
.StripeElement--webkit-autofill {
background-color: #fefde5 !important;
}
</style>