diff --git a/.gitignore b/.gitignore index 79e37ce1..e106f359 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/.phpstorm.meta.php /vendor /node_modules .env diff --git a/app/Http/Controllers/EventCheckoutController.php b/app/Http/Controllers/EventCheckoutController.php index 1fc3eb39..be210d50 100644 --- a/app/Http/Controllers/EventCheckoutController.php +++ b/app/Http/Controllers/EventCheckoutController.php @@ -165,21 +165,23 @@ class EventCheckoutController extends Controller * @todo - Store this in something other than a session? */ session()->set('ticket_order_'.$event->id, [ - 'validation_rules' => $validation_rules, - 'validation_messages' => $validation_messages, - 'event_id' => $event->id, - 'tickets' => $tickets, /* probably shouldn't store the whole ticket obj in session */ - 'total_ticket_quantity' => $total_ticket_quantity, - 'order_started' => time(), - 'expires' => $order_expires_time, - 'reserved_tickets_id' => $reservedTickets->id, - 'order_total' => $order_total, - 'booking_fee' => $booking_fee, - 'organiser_booking_fee' => $organiser_booking_fee, - 'total_booking_fee' => $booking_fee + $organiser_booking_fee, - 'order_requires_payment' => (ceil($order_total) == 0) ? false : true, - 'account_id' => $event->account->id, - 'affiliate_referral' => Cookie::get('affiliate_'.$event_id), + 'validation_rules' => $validation_rules, + 'validation_messages' => $validation_messages, + 'event_id' => $event->id, + 'tickets' => $tickets, /* probably shouldn't store the whole ticket obj in session */ + 'total_ticket_quantity' => $total_ticket_quantity, + 'order_started' => time(), + 'expires' => $order_expires_time, + 'reserved_tickets_id' => $reservedTickets->id, + 'order_total' => $order_total, + 'booking_fee' => $booking_fee, + 'organiser_booking_fee' => $organiser_booking_fee, + 'total_booking_fee' => $booking_fee + $organiser_booking_fee, + 'order_requires_payment' => (ceil($order_total) == 0) ? false : true, + 'account_id' => $event->account->id, + 'affiliate_referral' => Cookie::get('affiliate_'.$event_id), + 'account_payment_gateway' => $event->account->active_payment_gateway->exists() ? $event->account->active_payment_gateway : false, + 'payment_gateway' => $event->account->active_payment_gateway->payment_gateway->exists() ? $event->account->active_payment_gateway->payment_gateway : false, ]); if ($request->ajax()) { @@ -192,12 +194,7 @@ class EventCheckoutController extends Controller ]); } - /* - * TODO: We should just show an enable JS message here instead - */ - return redirect()->route('showEventCheckout', [ - 'event_id' => $event_id, - ]); + exit('Please enable Javascript in your browser.'); } /** @@ -211,6 +208,7 @@ class EventCheckoutController extends Controller { $order_session = session()->get('ticket_order_'.$event_id); + if (!$order_session || $order_session['expires'] < Carbon::now()) { return redirect()->route('showEventPage', ['event_id' => $event_id]); } @@ -240,14 +238,10 @@ class EventCheckoutController extends Controller public function postCreateOrder(Request $request, $event_id) { $mirror_buyer_info = ($request->get('mirror_buyer_info') == 'on'); - $event = Event::findOrFail($event_id); - - $order = new Order(); - + $order = new Order; $ticket_order = session()->get('ticket_order_'.$event_id); - $attendee_increment = 1; $validation_rules = $ticket_order['validation_rules']; $validation_messages = $ticket_order['validation_messages']; @@ -264,34 +258,86 @@ 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'])); + /* * Begin payment attempt before creating the attendees etc. * */ if ($ticket_order['order_requires_payment']) { try { - $error = false; - $token = $request->get('stripeToken'); - $gateway = Omnipay::gateway('stripe'); + $gateway = Omnipay::create($ticket_order['payment_gateway']->name); - $gateway->initialize([ - 'apiKey' => $event->account->stripe_api_key, - ]); + $gateway->initialize($ticket_order['account_payment_gateway']->config + [ + 'testMode' => config('attendize.enable_test_payments'), + ]); - $transaction = $gateway->purchase([ - 'amount' => ($ticket_order['order_total'] + $ticket_order['organiser_booking_fee']), - 'currency' => $event->currency->code, - 'description' => $request->get('order_email'), - 'description' => 'Order for customer: '.$request->get('order_email'), - 'token' => $token, - ]); + switch($ticket_order['payment_gateway']->id) { + case config('attendize.payment_gateway_paypal'): + case config('attendize.payment_gateway_bitpay'): + + $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; + break; + case config('attendize.payment_gateway_stripe'): + $token = $request->get('stripeToken'); + $transaction_data = [ + 'token' => $token, + ]; + break; + default: + Log::error('No payment gateway configured.'); + return repsonse()->json([ + 'status' => 'error', + 'message' => 'No payment gateway configured.' + ]); + break; + } + + $transaction_data = [ + 'amount' => ($ticket_order['order_total'] + $ticket_order['organiser_booking_fee']), + 'currency' => $event->currency->code, + 'description' => 'Order for customer: '.$request->get('order_email'), + ] + $transaction_data; + + $transaction = $gateway->purchase($transaction_data); $response = $transaction->send(); if ($response->isSuccessful()) { - $order->transaction_id = $response->getTransactionReference(); + + session()->push('ticket_order_' . $event_id .'.transaction_id', $response->getTransactionReference()); + return $this->completeOrder($event_id); + } elseif ($response->isRedirect()) { - $response->redirect(); + + /* + * As we're going off-site for payment we need to store some into in a session + */ + session()->push('ticket_order_' . $event_id .'.transaction_data', $transaction_data); + + return response()->json([ + 'status' => 'success', + 'redirectUrl' => $response->getRedirectUrl(), + 'redirectData' => $response->getRedirectData(), + 'message' => 'Redirecting to ' . $ticket_order['payment_gateway']->provider_name + ]); + } else { // display error to customer return response()->json([ @@ -312,19 +358,88 @@ class EventCheckoutController extends Controller } } + + /* + * No payment required so go ahead and complete the order + */ + return $this->completeOrder($event_id); + + } + + + public function showEventCheckoutPaymentReturn(Request $request, $event_id) + { + + if($request->get('is_payment_cancelled') == '1') { + session()->flash('message', 'You cancelled your payment. You may try again.'); + 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'), + ]); + + $transaction = $gateway->completePurchase($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', [ + 'event_id' => $event_id, + 'is_payment_failed' => 1, + ]); + } + + } + + + /** + * Complete an order + * + * @param $event_id + * @param bool|true $return_json + * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\RedirectResponse + */ + public function completeOrder($event_id, $return_json=true) + { + + $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; + $mirror_buyer_info = isset($request_data['mirror_buyer_info']) ? ($request_data['mirror_buyer_info'] == 'on') : false; + /* * Create the order */ - $order->first_name = $request->get('order_first_name'); - $order->last_name = $request->get('order_last_name'); - $order->email = $request->get('order_email'); + if(isset($ticket_order['transaction_id'])) + { + $order->transaction_id = $ticket_order['transaction_id'][0]; + } + if($ticket_order['order_requires_payment']) { + $order->payment_gateway_id = $ticket_order['payment_gateway']->id; + } + $order->first_name = $request_data['order_first_name']; + $order->last_name = $request_data['order_last_name']; + $order->email = $request_data['order_email']; $order->order_status_id = config('attendize.order_complete'); $order->amount = $ticket_order['order_total']; $order->booking_fee = $ticket_order['booking_fee']; $order->organiser_booking_fee = $ticket_order['organiser_booking_fee']; $order->discount = 0.00; $order->account_id = $event->account->id; - $order->event_id = $event_id; + $order->event_id = $ticket_order['event_id']; $order->save(); /* @@ -390,9 +505,9 @@ class EventCheckoutController extends Controller */ for ($i = 0; $i < $attendee_details['qty']; $i++) { $attendee = new Attendee(); - $attendee->first_name = $event->ask_for_all_attendees_info ? ($mirror_buyer_info ? $order->first_name : $request->get("ticket_holder_first_name.$i.{$attendee_details['ticket']['id']}")) : $order->first_name; - $attendee->last_name = $event->ask_for_all_attendees_info ? ($mirror_buyer_info ? $order->last_name : $request->get("ticket_holder_last_name.$i.{$attendee_details['ticket']['id']}")) : $order->last_name; - $attendee->email = $event->ask_for_all_attendees_info ? ($mirror_buyer_info ? $order->email : $request->get("ticket_holder_email.$i.{$attendee_details['ticket']['id']}")) : $order->email; + $attendee->first_name = $event->ask_for_all_attendees_info ? ($mirror_buyer_info ? $order->first_name : $request_data["ticket_holder_first_name.$i.{$attendee_details['ticket']['id']}"]) : $order->first_name; + $attendee->last_name = $event->ask_for_all_attendees_info ? ($mirror_buyer_info ? $order->last_name : $request_data["ticket_holder_last_name.$i.{$attendee_details['ticket']['id']}"]) : $order->last_name; + $attendee->email = $event->ask_for_all_attendees_info ? ($mirror_buyer_info ? $order->email : $request_data["ticket_holder_email.$i.{$attendee_details['ticket']['id']}"]) : $order->email; $attendee->event_id = $event_id; $attendee->order_id = $order->id; $attendee->ticket_id = $attendee_details['ticket']['id']; @@ -410,7 +525,7 @@ class EventCheckoutController extends Controller } /* - * Queue up some tasks - Emails to be sents, PDFs etc. + * Queue up some tasks - Emails to be sent, PDFs etc. */ $this->dispatch(new OrderTicketsCommand($order)); @@ -424,19 +539,24 @@ class EventCheckoutController extends Controller */ session()->forget('ticket_order_'.$event->id); - /* - * Queue the PDF creation jobs - */ + if($return_json) { + return response()->json([ + 'status' => 'success', + 'redirectUrl' => route('showOrderDetails', [ + 'is_embedded' => $this->is_embedded, + 'order_reference' => $order->order_reference, + ]), + ]); + } - return response()->json([ - 'status' => 'success', - 'redirectUrl' => route('showOrderDetails', [ + return response()->redirectToRoute('showOrderDetails', [ 'is_embedded' => $this->is_embedded, 'order_reference' => $order->order_reference, - ]), - ]); + ]); + } + /** * Show the order details page * @@ -495,12 +615,4 @@ class EventCheckoutController extends Controller return view('Public.ViewEvent.Partials.PDFTicket', $data); } - - public function handleStripePayment() - { - } - - public function handlePaypalPayment() - { - } } diff --git a/app/Http/Controllers/EventOrdersController.php b/app/Http/Controllers/EventOrdersController.php index 5f0410a4..08e38a9e 100644 --- a/app/Http/Controllers/EventOrdersController.php +++ b/app/Http/Controllers/EventOrdersController.php @@ -115,7 +115,7 @@ class EventOrdersController extends MyBaseController $attendees = Input::get('attendees'); $error_message = false; - if ($refund_order) { + if ($refund_order && $order->payment_gateway->can_refund) { if (!$order->transaction_id) { $error_message = 'Sorry, this order cannot be refunded.'; } diff --git a/app/Http/Controllers/ManageAccountController.php b/app/Http/Controllers/ManageAccountController.php index 26c79e6a..9bbf31b2 100644 --- a/app/Http/Controllers/ManageAccountController.php +++ b/app/Http/Controllers/ManageAccountController.php @@ -3,27 +3,32 @@ namespace App\Http\Controllers; use App\Models\Account; +use App\Models\AccountPaymentGateway; use App\Models\Currency; +use App\Models\PaymentGateway; use App\Models\Timezone; use App\Models\User; use Auth; use HttpClient; +use Illuminate\Http\Request; use Input; use Response; use View; class ManageAccountController extends MyBaseController { - public function showEditAccount() + public function showEditAccount(Request $request) { $data = [ - 'modal_id' => Input::get('modal_id'), - 'account' => Account::find(Auth::user()->account_id), - 'timezones' => Timezone::lists('location', 'id'), + 'modal_id' => $request->get('modal_id'), + 'account' => Account::find(Auth::user()->account_id), + 'timezones' => Timezone::lists('location', 'id'), 'currencies' => Currency::lists('title', 'id'), + 'payment_gateways' => PaymentGateway::lists('provider_name', 'id'), + 'account_payment_gateways' => AccountPaymentGateway::scope()->get() ]; - return View::make('ManageAccount.Modals.EditAccount', $data); + return view('ManageAccount.Modals.EditAccount', $data); } public function showStripeReturn() @@ -31,19 +36,18 @@ class ManageAccountController extends MyBaseController $error_message = 'There was an error connecting your Stripe account. Please try again.'; if (Input::get('error') || !Input::get('code')) { - //BugSnag::notifyError('Error Connecting to Stripe', Input::get('error')); \Session::flash('message', $error_message); return redirect()->route('showEventsDashboard'); } $request = [ - 'url' => 'https://connect.stripe.com/oauth/token', + 'url' => 'https://connect.stripe.com/oauth/token', 'params' => [ 'client_secret' => STRIPE_SECRET_KEY, //sk_test_iXk2Ky0DlhIcTcKMvsDa8iKI', - 'code' => Input::get('code'), - 'grant_type' => 'authorization_code', + 'code' => Input::get('code'), + 'grant_type' => 'authorization_code', ], ]; @@ -52,7 +56,6 @@ class ManageAccountController extends MyBaseController $content = $response->json(); if (isset($content->error) || !isset($content->access_token)) { - //BugSnag::notifyError('Error Connecting to Stripe', Input::get('error')); \Session::flash('message', $error_message); return redirect()->route('showEventsDashboard'); @@ -76,7 +79,7 @@ class ManageAccountController extends MyBaseController if (!$account->validate(Input::all())) { return Response::json([ - 'status' => 'error', + 'status' => 'error', 'messages' => $account->errors(), ]); } @@ -89,24 +92,51 @@ class ManageAccountController extends MyBaseController $account->save(); return Response::json([ - 'status' => 'success', - 'id' => $account->id, + 'status' => 'success', + 'id' => $account->id, 'message' => 'Account Successfully Updated', ]); } - public function postEditAccountPayment() + /** + * Save account payment information + * + * @param Request $request + * @return mixed + */ + public function postEditAccountPayment(Request $request) { $account = Account::find(Auth::user()->account_id); + $gateway_id = $request->get('payment_gateway_id'); - $account->stripe_publishable_key = Input::get('stripe_publishable_key'); - $account->stripe_secret_key = Input::get('stripe_secret_key'); + switch ($gateway_id) { + case config('attendize.payment_gateway_stripe') : //Stripe + $config = $request->get('stripe'); + break; + case config('attendize.payment_gateway_paypal') : //PayPal + $config = $request->get('paypal'); + break; + case config('attendize.payment_gateway_bitpay') : //BitPay + $config = $request->get('bitpay'); + break; + } + $account_payment_gateway = AccountPaymentGateway::firstOrNew( + [ + 'payment_gateway_id' => $gateway_id, + 'account_id' => $account->id, + ]); + $account_payment_gateway->config = $config; + $account_payment_gateway->account_id = $account->id; + $account_payment_gateway->payment_gateway_id = $gateway_id; + $account_payment_gateway->save(); + + $account->payment_gateway_id = $gateway_id; $account->save(); - return Response::json([ - 'status' => 'success', - 'id' => $account->id, + return response()->json([ + 'status' => 'success', + 'id' => $account_payment_gateway->id, 'message' => 'Payment Information Successfully Updated', ]); } @@ -114,22 +144,22 @@ class ManageAccountController extends MyBaseController public function postInviteUser() { $rules = [ - 'email' => ['required', 'email', 'unique:users,email,NULL,id,account_id,'.Auth::user()->account_id], - ]; + 'email' => ['required', 'email', 'unique:users,email,NULL,id,account_id,' . Auth::user()->account_id], + ]; $messages = [ - 'email.email' => 'Please enter a valid E-mail address.', - 'email.required' => 'E-mail address is required.', - 'email.unique' => 'E-mail already in use for this account.', - ]; + 'email.email' => 'Please enter a valid E-mail address.', + 'email.required' => 'E-mail address is required.', + 'email.unique' => 'E-mail already in use for this account.', + ]; $validation = \Validator::make(Input::all(), $rules, $messages); if ($validation->fails()) { return \Response::json([ - 'status' => 'error', - 'messages' => $validation->messages()->toArray(), - ]); + 'status' => 'error', + 'messages' => $validation->messages()->toArray(), + ]); } $temp_password = str_random(8); @@ -141,19 +171,19 @@ class ManageAccountController extends MyBaseController $user->save(); $data = [ - 'user' => $user, - 'temp_password' => $temp_password, - 'inviter' => Auth::user(), + 'user' => $user, + 'temp_password' => $temp_password, + 'inviter' => Auth::user(), ]; \Mail::send('Emails.inviteUser', $data, function ($message) use ($data) { $message->to($data['user']->email) - ->subject($data['inviter']->first_name.' '.$data['inviter']->last_name.' added you to an Attendize Ticketing account.'); + ->subject($data['inviter']->first_name . ' ' . $data['inviter']->last_name . ' added you to an Attendize Ticketing account.'); }); return Response::json([ - 'status' => 'success', - 'message' => 'Success! '.$user->email.' has been sent further instructions.', + 'status' => 'success', + 'message' => 'Success! ' . $user->email . ' has been sent further instructions.', ]); } } diff --git a/app/Http/routes.php b/app/Http/routes.php index 378727f1..750ed1ed 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -147,6 +147,13 @@ Route::group(['prefix' => 'e'], function () { 'uses' => 'EventCheckoutController@showEventCheckout', ]); + Route::get('{event_id}/checkout/success', [ + 'as' => 'showEventCheckoutPaymentReturn', + 'uses' => 'EventCheckoutController@showEventCheckoutPaymentReturn', + ]); + + + Route::post('{event_id}/checkout/create', [ 'as' => 'postCreateOrder', 'uses' => 'EventCheckoutController@postCreateOrder', diff --git a/app/Models/Account.php b/app/Models/Account.php index 6b8d747b..d28860a9 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Attendize\Utils; use Illuminate\Database\Eloquent\SoftDeletes; +use DB; class Account extends MyBaseModel { @@ -97,6 +98,66 @@ class Account extends MyBaseModel return $this->hasOne('\App\Models\Currency'); } + /** + * Payment gateways associated with an account + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function account_payment_gateways() + { + return $this->hasMany('\App\Models\AccountPaymentGateway'); + } + + /** + * Alias for $this->account_payment_gateways() + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function gateways() { + return $this->account_payment_gateways(); + } + + /** + * Get an accounts active payment gateway + * + * @return \Illuminate\Database\Eloquent\Relations\HasOne + */ + public function active_payment_gateway() + { + return $this->hasOne('\App\Models\AccountPaymentGateway', 'payment_gateway_id', 'payment_gateway_id'); + } + + /** + * Get an accounts gateways + * + * @param $gateway_id + * @return mixed + */ + public function getGateway($gateway_id) + { + return $this->gateways->where('payment_gateway_id', $gateway_id)->first(); + } + + /** + * Get a config value for a gateway + * + * @param $gateway_id + * @param $key + * @return mixed + */ + public function getGatewayConfigVal($gateway_id, $key) + { + $gateway = $this->getGateway($gateway_id); + + if($gateway && is_array($gateway->config)) { + return isset($gateway->config[$key]) ? $gateway->config[$key] : false; + } + + return false; + } + + + /** * Get the stripe api key. * diff --git a/app/Models/AccountPaymentGateway.php b/app/Models/AccountPaymentGateway.php new file mode 100644 index 00000000..946c7888 --- /dev/null +++ b/app/Models/AccountPaymentGateway.php @@ -0,0 +1,49 @@ +belongsTo('\App\Models\Account'); + } + + public function payment_gateway() + { + return $this->belongsTo('\App\Models\PaymentGateway', 'payment_gateway_id', 'id'); + } + + + + + + /** + * @param $val + * @return mixed + */ + public function getConfigAttribute($value) { + return json_decode($value, true); + } + + public function setConfigAttribute($value) { + $this->attributes['config'] = json_encode($value); + } + + +} diff --git a/app/Models/Order.php b/app/Models/Order.php index c6621bb9..4508af12 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -82,6 +82,12 @@ class Order extends MyBaseModel return $this->hasMany('\App\Models\Ticket'); } + + public function payment_gateway() + { + return $this->belongsTo('\App\Models\PaymentGateway'); + } + /** * The status associated with the order. * diff --git a/app/Models/PaymentGateway.php b/app/Models/PaymentGateway.php index 851cf0f0..a3143992 100644 --- a/app/Models/PaymentGateway.php +++ b/app/Models/PaymentGateway.php @@ -2,16 +2,12 @@ namespace App\Models; -/* - Attendize.com - Event Management & Ticketing - */ - /** - * Description of PaymentGateway. - * - * @author Dave + * Class PaymentGateway + * @package App\Models */ -class PaymentGateway extends \Illuminate\Database\Eloquent\Model +class PaymentGateway extends MyBaseModel { - //put your code here + + } diff --git a/composer.json b/composer.json index 530877c7..0ccfdca8 100644 --- a/composer.json +++ b/composer.json @@ -20,9 +20,10 @@ "mews/purifier": "~2.0", "league/flysystem-aws-s3-v3" : "~1.0", "maxhoffmann/parsedown-laravel": "dev-master", - "ignited/laravel-omnipay": "2.*", + "omnipay/common": "~2.3", "omnipay/stripe": "*", "omnipay/paypal": "*", + "omnipay/bitpay": "dev-master", "barryvdh/laravel-ide-helper": "^2.1" }, diff --git a/composer.lock b/composer.lock index ca2ac76d..3470e142 100644 --- a/composer.lock +++ b/composer.lock @@ -4,21 +4,21 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "d2df1fb5d7e5abd59ee8001f1bdf9eb0", - "content-hash": "2d529e1152961ba48763e3efe5b10fc7", + "hash": "acfabb6575d92d14c44717c0d3e371c7", + "content-hash": "7874f34b6511337f2d983c8e81cf82db", "packages": [ { "name": "aws/aws-sdk-php", - "version": "3.15.9", + "version": "3.17.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "5f27941e2f1ac1700e667cfcf9d9da44c1d9b612" + "reference": "4853bf1f865f6c6df44db0cd5664319ae806f319" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/5f27941e2f1ac1700e667cfcf9d9da44c1d9b612", - "reference": "5f27941e2f1ac1700e667cfcf9d9da44c1d9b612", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/4853bf1f865f6c6df44db0cd5664319ae806f319", + "reference": "4853bf1f865f6c6df44db0cd5664319ae806f319", "shasum": "" }, "require": { @@ -85,7 +85,7 @@ "s3", "sdk" ], - "time": "2016-03-11 00:44:20" + "time": "2016-03-17 23:57:52" }, { "name": "barryvdh/laravel-ide-helper", @@ -828,52 +828,6 @@ ], "time": "2016-02-18 21:54:00" }, - { - "name": "ignited/laravel-omnipay", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/ignited/laravel-omnipay.git", - "reference": "c64bb5acab93dcf99d4d601ef644eaf33b88433f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ignited/laravel-omnipay/zipball/c64bb5acab93dcf99d4d601ef644eaf33b88433f", - "reference": "c64bb5acab93dcf99d4d601ef644eaf33b88433f", - "shasum": "" - }, - "require": { - "illuminate/support": "~5", - "omnipay/common": "2.3.*", - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-0": { - "Ignited\\LaravelOmnipay": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "authors": [ - { - "name": "Alex Whiteside", - "email": "alexwhiteside@ignitedlabs.com.au" - } - ], - "description": "Integerates Omnipay with Laravel and provides an easy configuration.", - "keywords": [ - "laravel", - "laravel5", - "omnipay", - "payments" - ], - "time": "2015-09-03 01:40:05" - }, { "name": "illuminate/html", "version": "v5.0.0", @@ -1414,16 +1368,16 @@ }, { "name": "league/flysystem", - "version": "1.0.18", + "version": "1.0.20", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "b334d6c5f95364948e06d2f620ab93d084074c6e" + "reference": "e87a786e3ae12a25cf78a71bb07b4b384bfaa83a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/b334d6c5f95364948e06d2f620ab93d084074c6e", - "reference": "b334d6c5f95364948e06d2f620ab93d084074c6e", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e87a786e3ae12a25cf78a71bb07b4b384bfaa83a", + "reference": "e87a786e3ae12a25cf78a71bb07b4b384bfaa83a", "shasum": "" }, "require": { @@ -1493,7 +1447,7 @@ "sftp", "storage" ], - "time": "2016-03-07 21:01:43" + "time": "2016-03-14 21:54:11" }, { "name": "league/flysystem-aws-s3-v3", @@ -1830,16 +1784,16 @@ }, { "name": "monolog/monolog", - "version": "1.18.0", + "version": "1.18.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "e19b764b5c855580e8ffa7e615f72c10fd2f99cc" + "reference": "a5f2734e8c16f3aa21b3da09715d10e15b4d2d45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/e19b764b5c855580e8ffa7e615f72c10fd2f99cc", - "reference": "e19b764b5c855580e8ffa7e615f72c10fd2f99cc", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/a5f2734e8c16f3aa21b3da09715d10e15b4d2d45", + "reference": "a5f2734e8c16f3aa21b3da09715d10e15b4d2d45", "shasum": "" }, "require": { @@ -1904,7 +1858,7 @@ "logging", "psr-3" ], - "time": "2016-03-01 18:00:40" + "time": "2016-03-13 16:08:35" }, { "name": "mtdowling/cron-expression", @@ -2147,16 +2101,16 @@ }, { "name": "omnipay/common", - "version": "v2.3.4", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-common.git", - "reference": "fcd5a606713d11536c89315a5ae02d965a737c21" + "reference": "550138529e850143af7a87eab8cfe16e72a2f768" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-common/zipball/fcd5a606713d11536c89315a5ae02d965a737c21", - "reference": "fcd5a606713d11536c89315a5ae02d965a737c21", + "url": "https://api.github.com/repos/thephpleague/omnipay-common/zipball/550138529e850143af7a87eab8cfe16e72a2f768", + "reference": "550138529e850143af7a87eab8cfe16e72a2f768", "shasum": "" }, "require": { @@ -2175,7 +2129,6 @@ "gateways": [ "AuthorizeNet_AIM", "AuthorizeNet_SIM", - "Buckaroo", "Buckaroo_Ideal", "Buckaroo_PayPal", "CardSave", @@ -2205,26 +2158,7 @@ "TargetPay_Directebanking", "TargetPay_Ideal", "TargetPay_Mrcash", - "TwoCheckout", - "WorldPay", - "Alipay Bank", - "AliPay Dual Func", - "Alipay Express", - "Alipay Mobile Express", - "Alipay Secured", - "Alipay Wap Express", - "Cybersource", - "DataCash", - "Ecopayz", - "Neteller", - "Pacnet", - "PaymentSense", - "Realex Remote", - "SecPay (PayPoint.net)", - "Sisow", - "Skrill", - "YandexMoney", - "YandexMoneyIndividual" + "WorldPay" ] }, "autoload": { @@ -2259,7 +2193,7 @@ "payment", "purchase" ], - "time": "2015-03-30 14:34:46" + "time": "2016-03-10 03:03:17" }, { "name": "omnipay/paypal", @@ -2321,16 +2255,16 @@ }, { "name": "omnipay/stripe", - "version": "v2.3.1", + "version": "v2.3.2", "source": { "type": "git", "url": "https://github.com/thephpleague/omnipay-stripe.git", - "reference": "6c4cef5b5168a58476eef6fa73b7875e15c94b6f" + "reference": "fe05ddd73d9ae38ca026dbc270ca98aaf3f99da4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/omnipay-stripe/zipball/6c4cef5b5168a58476eef6fa73b7875e15c94b6f", - "reference": "6c4cef5b5168a58476eef6fa73b7875e15c94b6f", + "url": "https://api.github.com/repos/thephpleague/omnipay-stripe/zipball/fe05ddd73d9ae38ca026dbc270ca98aaf3f99da4", + "reference": "fe05ddd73d9ae38ca026dbc270ca98aaf3f99da4", "shasum": "" }, "require": { @@ -2374,20 +2308,20 @@ "payment", "stripe" ], - "time": "2016-01-13 04:00:45" + "time": "2016-03-19 08:35:06" }, { "name": "paragonie/random_compat", - "version": "v1.2.1", + "version": "v1.4.1", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "f078eba3bcf140fd69b5fcc3ea5ac809abf729dc" + "reference": "c7e26a21ba357863de030f0b9e701c7d04593774" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/f078eba3bcf140fd69b5fcc3ea5ac809abf729dc", - "reference": "f078eba3bcf140fd69b5fcc3ea5ac809abf729dc", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774", + "reference": "c7e26a21ba357863de030f0b9e701c7d04593774", "shasum": "" }, "require": { @@ -2422,7 +2356,7 @@ "pseudorandom", "random" ], - "time": "2016-02-29 17:25:04" + "time": "2016-03-18 20:34:03" }, { "name": "phenx/php-font-lib", @@ -4304,16 +4238,16 @@ }, { "name": "phpunit/phpunit", - "version": "4.8.23", + "version": "4.8.24", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483" + "reference": "a1066c562c52900a142a0e2bbf0582994671385e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e351261f9cd33daf205a131a1ba61c6d33bd483", - "reference": "6e351261f9cd33daf205a131a1ba61c6d33bd483", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e", + "reference": "a1066c562c52900a142a0e2bbf0582994671385e", "shasum": "" }, "require": { @@ -4372,7 +4306,7 @@ "testing", "xunit" ], - "time": "2016-02-11 14:56:33" + "time": "2016-03-14 06:16:08" }, { "name": "phpunit/phpunit-mock-objects", diff --git a/config/app.php b/config/app.php index f597b469..f8d3b5d2 100644 --- a/config/app.php +++ b/config/app.php @@ -145,7 +145,6 @@ return [ Nitmedia\Wkhtml2pdf\L5Wkhtml2pdfServiceProvider::class, Mews\Purifier\PurifierServiceProvider::class, MaxHoffmann\Parsedown\ParsedownServiceProvider::class, - Ignited\LaravelOmnipay\LaravelOmnipayServiceProvider::class, Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class, ], /* @@ -206,7 +205,8 @@ return [ 'HttpClient' => Vinelab\Http\Facades\Client::class, 'Purifier' => Mews\Purifier\Facades\Purifier::class, 'Markdown' => MaxHoffmann\Parsedown\ParsedownFacade::class, - 'Omnipay' => Ignited\LaravelOmnipay\Facades\OmnipayFacade::class, + 'Omnipay' => Omnipay\Omnipay::class, + // 'Omnipay' => Omnipay\Omnipay::class, ], ]; diff --git a/config/attendize.php b/config/attendize.php index d43610f8..da542179 100644 --- a/config/attendize.php +++ b/config/attendize.php @@ -2,21 +2,11 @@ return [ - 'active_payment_gateway' => 'paypal', - 'payment_gateways' => [ - 'stripe' => [ - 'api_key' => '', - ], - 'paypal' => [ - 'username' => '', - 'password' => '', - ], - 'bitpay' => [ - 'username' => '', - 'password' => '', - ] - ], + 'enable_test_payments' => env('ENABLE_TEST_PAYMENTS', false), + 'payment_gateway_stripe' => 1, + 'payment_gateway_paypal' => 2, + 'payment_gateway_bitpay' => 3, 'outgoing_email_noreply' => env('MAIL_FROM_ADDRESS'), 'outgoing_email' => env('MAIL_FROM_ADDRESS'), @@ -34,8 +24,7 @@ return [ 'fallback_organiser_logo_url' => '/assets/images/logo-100x100-lightBg.png', 'cdn_url' => '', - 'max_tickets_per_person' => 30, #Depreciated - 'checkout_timeout_after' => 8, #mintutes + 'checkout_timeout_after' => app()->environment('local', 'development') ? 30 : 8, #mintutes 'ticket_status_sold_out' => 1, 'ticket_status_after_sale_date' => 2, @@ -58,6 +47,7 @@ return [ 'default_datetime_format' => 'F j, Y, g:i a', 'default_query_cache' => 120, #Minutes 'default_locale' => 'en', + 'default_payment_gateway' => 1, #Stripe=1 Paypal=2 BitPay=3 'cdn_url_user_assets' => '', 'cdn_url_static_assets' => '' diff --git a/database/migrations/2014_03_26_180116_create_users_table.php b/database/migrations/2014_03_26_180116_create_users_table.php index 6bea0384..2c057b3b 100644 --- a/database/migrations/2014_03_26_180116_create_users_table.php +++ b/database/migrations/2014_03_26_180116_create_users_table.php @@ -21,6 +21,7 @@ class CreateUsersTable extends Migration $table->text('name'); }); + Schema::create('reserved_tickets', function ($table) { $table->increments('id'); @@ -68,6 +69,7 @@ class CreateUsersTable extends Migration $table->timestamps(); }); + /* * Accounts table */ @@ -82,6 +84,7 @@ class CreateUsersTable extends Migration $t->unsignedInteger('date_format_id')->nullable(); $t->unsignedInteger('datetime_format_id')->nullable(); $t->unsignedInteger('currency_id')->nullable(); + //$t->unsignedInteger('payment_gateway_id')->default(config('attendize.default_payment_gateway')); $t->timestamps(); $t->softDeletes(); @@ -111,7 +114,7 @@ class CreateUsersTable extends Migration $t->foreign('timezone_id')->references('id')->on('timezones'); $t->foreign('date_format_id')->references('id')->on('date_formats'); $t->foreign('datetime_format_id')->references('id')->on('date_formats'); - //$t->foreign('country_id')->references('id')->on('countries'); + //$t->foreign('payment_gateway_id')->references('id')->on('payment_gateways'); $t->foreign('currency_id')->references('id')->on('currencies'); }); @@ -161,6 +164,8 @@ class CreateUsersTable extends Migration $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); }); + + Schema::create('events', function ($t) { $t->increments('id'); @@ -408,6 +413,7 @@ class CreateUsersTable extends Migration $t->foreign('ticket_id')->references('id')->on('users')->onDelete('cascade'); }); + /* * Tickets / Questions pivot table */ @@ -503,6 +509,31 @@ class CreateUsersTable extends Migration */ public function down() { - Schema::drop('users'); + $tables = [ + 'order_statuses', + 'reserved_tickets', + 'timezones', + 'date_formats', + 'datetime_formats', + 'currencies', + 'accounts', + 'users', + 'organisers', + 'events', + 'orders', + 'tickets', + 'order_items', + 'ticket_order', + 'event_stats', + 'attendees', + 'messages', + 'event_images' + + ]; + + foreach($tables as $table) { + Schema::drop($table); + } + } } diff --git a/database/migrations/2014_04_08_232044_setup_countries_table.php b/database/migrations/2014_04_08_232044_setup_countries_table.php index e11ded41..09ab11c8 100644 --- a/database/migrations/2014_04_08_232044_setup_countries_table.php +++ b/database/migrations/2014_04_08_232044_setup_countries_table.php @@ -12,7 +12,7 @@ class SetupCountriesTable extends Migration public function up() { // Creates the users table - Schema::create('Countries', function ($table) { + Schema::create('countries', function ($table) { $table->integer('id')->index(); $table->string('capital', 255)->nullable(); $table->string('citizenship', 255)->nullable(); @@ -39,6 +39,6 @@ class SetupCountriesTable extends Migration */ public function down() { - Schema::drop('Countries'); + Schema::drop('countries'); } } diff --git a/database/migrations/2014_11_07_132018_add_affiliates_table.php b/database/migrations/2014_11_07_132018_add_affiliates_table.php index 4e83b4bb..b3557643 100644 --- a/database/migrations/2014_11_07_132018_add_affiliates_table.php +++ b/database/migrations/2014_11_07_132018_add_affiliates_table.php @@ -34,6 +34,6 @@ class AddAffiliatesTable extends Migration */ public function down() { - // + Schema::drop('affiliates'); } } diff --git a/database/migrations/2016_03_16_193757_create_gateways_table.php b/database/migrations/2016_03_16_193757_create_gateways_table.php new file mode 100644 index 00000000..7a689987 --- /dev/null +++ b/database/migrations/2016_03_16_193757_create_gateways_table.php @@ -0,0 +1,49 @@ +increments('id'); + $table->string('provider_name', 50); + $table->string('provider_url'); + $table->boolean('is_on_site'); + $table->boolean('can_refund')->default(0); + $table->string('name', 50); + }); + + Schema::create('account_payment_gateways', function (Blueprint $table) { + $table->increments('id'); + $table->unsignedInteger('account_id'); + $table->unsignedInteger('payment_gateway_id'); + $table->text('config'); + $table->softDeletes(); + $table->timestamps(); + + $table->foreign('payment_gateway_id')->references('id')->on('payment_gateways')->onDelete('cascade'); + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + }); + + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('payment_gateways'); + Schema::drop('account_payments_gateways'); + } +} diff --git a/database/migrations/2016_03_16_213041_add_account_payment_id.php b/database/migrations/2016_03_16_213041_add_account_payment_id.php new file mode 100644 index 00000000..6d903d39 --- /dev/null +++ b/database/migrations/2016_03_16_213041_add_account_payment_id.php @@ -0,0 +1,33 @@ +unsignedInteger('payment_gateway_id')->nullable(); + $table->foreign('payment_gateway_id')->references('id')->on('payment_gateways'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('orders', function (Blueprint $table) { + // + }); + } +} diff --git a/database/migrations/2016_03_16_215709_add_gateway_id_accounts_table.php b/database/migrations/2016_03_16_215709_add_gateway_id_accounts_table.php new file mode 100644 index 00000000..d2d363ab --- /dev/null +++ b/database/migrations/2016_03_16_215709_add_gateway_id_accounts_table.php @@ -0,0 +1,32 @@ +unsignedInteger('payment_gateway_id')->default(config('attendize.payment_gateway_stripe')); + $table->foreign('payment_gateway_id')->references('id')->on('payment_gateways'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('accounts', function (Blueprint $table) { + // + }); + } +} diff --git a/database/seeds/ConstantsSeeder.php b/database/seeds/ConstantsSeeder.php index 70575cff..f5d3b213 100644 --- a/database/seeds/ConstantsSeeder.php +++ b/database/seeds/ConstantsSeeder.php @@ -401,13 +401,6 @@ class ConstantsSeeder extends Seeder \App\Models\DateFormat::create(['format' => 'F j, Y', 'picker_format' => 'MM d, yyyy', 'label' => 'March 10, 2013']); \App\Models\DateFormat::create(['format' => 'D M j, Y', 'picker_format' => 'D MM d, yyyy', 'label' => 'Mon March 10, 2013']); - /* - d, dd: Numeric date, no leading zero and leading zero, respectively. Eg, 5, 05. - D, DD: Abbreviated and full weekday names, respectively. Eg, Mon, Monday. - m, mm: Numeric month, no leading zero and leading zero, respectively. Eg, 7, 07. - M, MM: Abbreviated and full month names, respectively. Eg, Jan, January - yy, yyyy: 2- and 4-digit years, respectively. Eg, 12, 2012.) - */ $timezones = [ 'Pacific/Midway' => '(GMT-11:00) Midway Island', @@ -527,5 +520,39 @@ class ConstantsSeeder extends Seeder foreach ($timezones as $name => $location) { \App\Models\Timezone::create(['name' => $name, 'location' => $location]); } + + + $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 + + ], +// [ +// 'id' => 3, +// 'name' => 'BitPay', +// 'provider_name' => 'BitPay', +// 'provider_url' => 'https://bitpay.com', +// 'is_on_site' => 0 +// +// +// ], + ]; + + DB::table('payment_gateways')->insert($payment_gateways); + + } } diff --git a/database/seeds/CountriesSeeder.php b/database/seeds/CountriesSeeder.php index 3b3c75a6..c7ea93d1 100644 --- a/database/seeds/CountriesSeeder.php +++ b/database/seeds/CountriesSeeder.php @@ -12,12 +12,12 @@ class CountriesSeeder extends Seeder public function run() { //Empty the countries table - DB::table('Countries')->delete(); + DB::table('countries')->delete(); //Get all of the countries $countries = json_decode(file_get_contents(database_path().'/seeds/countries.json'), true); foreach ($countries as $countryId => $country) { - DB::table('Countries')->insert([ + DB::table('countries')->insert([ 'id' => $countryId, 'capital' => ((isset($country['capital'])) ? $country['capital'] : null), 'citizenship' => ((isset($country['citizenship'])) ? $country['citizenship'] : null), diff --git a/public/assets/javascript/app-public.js b/public/assets/javascript/app-public.js index fdb01a38..f78482cd 100644 --- a/public/assets/javascript/app-public.js +++ b/public/assets/javascript/app-public.js @@ -33,7 +33,11 @@ $(function() { case 'success': if (data.redirectUrl) { - window.location = data.redirectUrl; + if(data.redirectData) { + $.redirectPost(data.redirectUrl, data.redirectData); + } else { + window.location = data.redirectUrl; + } } var $submitButton = $form.find('input[type=submit]'); @@ -268,6 +272,18 @@ function setCountdown($element, seconds) { updateTimer(); } +$.extend( + { + redirectPost: function(location, args) + { + var form = ''; + $.each( args, function( key, value ) { + value = value.split('"').join('\"') + form += ''; + }); + $('
').appendTo($(document.body)).submit(); + } + }); /*! * Smooth Scroll - v1.4.13 - 2013-11-02 diff --git a/public/assets/javascript/backend.js b/public/assets/javascript/backend.js index 983b4b72..6313a935 100644 --- a/public/assets/javascript/backend.js +++ b/public/assets/javascript/backend.js @@ -8627,7 +8627,7 @@ $(function () { var loadUrl = $(this).data('href'), modalId = $(this).data('modal-id'), - cacheResult = $(this).data('cache') === 'on' ? true : false; + cacheResult = $(this).data('cache') === 'on'; // $('#' + modalId).remove(); $('.modal').remove(); diff --git a/public/assets/javascript/frontend.js b/public/assets/javascript/frontend.js index 1f48d10a..61514882 100644 --- a/public/assets/javascript/frontend.js +++ b/public/assets/javascript/frontend.js @@ -13813,7 +13813,11 @@ function log() { case 'success': if (data.redirectUrl) { - window.location = data.redirectUrl; + if(data.redirectData) { + $.redirectPost(data.redirectUrl, data.redirectData); + } else { + window.location = data.redirectUrl; + } } var $submitButton = $form.find('input[type=submit]'); @@ -14021,13 +14025,11 @@ function setCountdown($element, seconds) { var endTime, mins, msLeft, time, twoMinWarningShown = false; - function twoDigits(n) - { + function twoDigits(n) { return (n <= 9 ? "0" + n : n); } - function updateTimer() - { + function updateTimer() { msLeft = endTime - (+new Date); if (msLeft < 1000) { alert("You have run out of time! You will have to restart the order process."); @@ -14050,6 +14052,18 @@ function setCountdown($element, seconds) { updateTimer(); } +$.extend( + { + redirectPost: function(location, args) + { + var form = ''; + $.each( args, function( key, value ) { + value = value.split('"').join('\"') + form += ''; + }); + $('').appendTo($(document.body)).submit(); + } + }); /*! * Smooth Scroll - v1.4.13 - 2013-11-02 diff --git a/resources/views/ManageAccount/Modals/EditAccount.blade.php b/resources/views/ManageAccount/Modals/EditAccount.blade.php index 9ecd5557..28ea256a 100644 --- a/resources/views/ManageAccount/Modals/EditAccount.blade.php +++ b/resources/views/ManageAccount/Modals/EditAccount.blade.php @@ -94,77 +94,7 @@- We use Stripe to handle payments. Stripe allows you - accept payment in 139 currencies. -
- -- If you don't have an existing account with Stripe you will be prompted to create - one. The process will only take a couple of minutes. -
- - @if($account->stripe_access_token) -
-
-
- @else
-
- {!! Form::model($account, array('url' => route('postEditAccountPayment'), 'class' => 'ajax ')) !!}
- - We use Stripe to handle payments. Stripe allows you - accept payment in 139 currencies. Once you have created Stripe account you can find you Secret Key and Publishable key here: https://dashboard.stripe.com/account/apikeys. -
- -