1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-14 15:13:29 +01:00
invoiceninja/app/Http/Controllers/OnlinePaymentController.php

395 lines
13 KiB
PHP
Raw Normal View History

2017-01-30 20:40:43 +01:00
<?php
2016-06-20 16:14:43 +02:00
2017-01-30 20:40:43 +01:00
namespace App\Http\Controllers;
use App\Http\Requests\CreateOnlinePaymentRequest;
2016-06-20 16:14:43 +02:00
use App\Models\Account;
2016-12-27 22:56:55 +01:00
use App\Models\Client;
2017-01-30 20:40:43 +01:00
use App\Models\GatewayType;
use App\Models\Invitation;
2016-06-20 16:14:43 +02:00
use App\Models\Payment;
use App\Models\PaymentMethod;
2017-01-30 20:40:43 +01:00
use App\Models\Product;
2016-06-20 16:14:43 +02:00
use App\Ninja\Mailers\UserMailer;
2016-07-12 22:46:41 +02:00
use App\Ninja\Repositories\ClientRepository;
use App\Ninja\Repositories\InvoiceRepository;
2016-07-12 22:46:41 +02:00
use App\Services\InvoiceService;
2017-01-30 20:40:43 +01:00
use App\Services\PaymentService;
use Auth;
use Crawler;
use Exception;
use Input;
use Session;
use URL;
use Utils;
use Validator;
use View;
2016-06-20 16:14:43 +02:00
/**
2017-01-30 20:40:43 +01:00
* Class OnlinePaymentController.
*/
2016-06-20 16:14:43 +02:00
class OnlinePaymentController extends BaseController
{
/**
* @var PaymentService
*/
protected $paymentService;
/**
* @var UserMailer
*/
protected $userMailer;
/**
* @var InvoiceRepository
*/
protected $invoiceRepo;
/**
* OnlinePaymentController constructor.
*
* @param PaymentService $paymentService
2017-01-30 20:40:43 +01:00
* @param UserMailer $userMailer
*/
public function __construct(PaymentService $paymentService, UserMailer $userMailer, InvoiceRepository $invoiceRepo)
2016-06-20 16:14:43 +02:00
{
$this->paymentService = $paymentService;
$this->userMailer = $userMailer;
$this->invoiceRepo = $invoiceRepo;
2016-06-20 16:14:43 +02:00
}
/**
* @param $invitationKey
2017-01-30 20:49:42 +01:00
* @param bool $gatewayType
* @param bool $sourceId
* @param mixed $gatewayTypeAlias
2017-01-30 20:40:43 +01:00
*
* @return \Illuminate\Http\RedirectResponse
*/
2016-09-15 12:41:09 +02:00
public function showPayment($invitationKey, $gatewayTypeAlias = false, $sourceId = false)
2016-06-20 16:14:43 +02:00
{
2017-01-30 17:05:31 +01:00
if (! $invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) {
return response()->view('error', [
'error' => trans('texts.invoice_not_found'),
'hideHeader' => true,
]);
}
2017-06-21 22:36:59 +02:00
if (! $invitation->invoice->canBePaid() && ! request()->update) {
2016-07-18 21:03:28 +02:00
return redirect()->to('view/' . $invitation->invitation_key);
}
$invitation = $invitation->load('invoice.client.account.account_gateways.gateway');
$account = $invitation->account;
if ($account->requiresAuthorization($invitation->invoice) && ! session('authorized:' . $invitation->invitation_key)) {
return redirect()->to('view/' . $invitation->invitation_key);
}
$account->loadLocalizationSettings($invitation->invoice->client);
2016-06-20 16:14:43 +02:00
2017-01-30 17:05:31 +01:00
if (! $gatewayTypeAlias) {
2016-09-15 12:41:09 +02:00
$gatewayTypeId = Session::get($invitation->id . 'gateway_type');
} elseif ($gatewayTypeAlias != GATEWAY_TYPE_TOKEN) {
$gatewayTypeId = GatewayType::getIdFromAlias($gatewayTypeAlias);
} else {
$gatewayTypeId = $gatewayTypeAlias;
2016-06-20 16:14:43 +02:00
}
$paymentDriver = $account->paymentDriver($invitation, $gatewayTypeId);
2016-06-20 16:14:43 +02:00
2017-03-21 16:18:36 +01:00
if (! $paymentDriver) {
return redirect()->to('view/' . $invitation->invitation_key);
}
2016-06-20 16:14:43 +02:00
try {
return $paymentDriver->startPurchase(Input::all(), $sourceId);
} catch (Exception $exception) {
return $this->error($paymentDriver, $exception);
}
}
/**
* @param CreateOnlinePaymentRequest $request
2017-01-30 20:40:43 +01:00
*
* @return \Illuminate\Http\RedirectResponse
*/
2016-06-20 16:14:43 +02:00
public function doPayment(CreateOnlinePaymentRequest $request)
{
$invitation = $request->invitation;
2016-09-15 12:41:09 +02:00
$gatewayTypeId = Session::get($invitation->id . 'gateway_type');
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayTypeId);
2016-06-20 16:14:43 +02:00
2017-06-21 22:36:59 +02:00
if (! $invitation->invoice->canBePaid() && ! request()->update) {
return redirect()->to('view/' . $invitation->invitation_key);
}
2016-06-20 16:14:43 +02:00
try {
$paymentDriver->completeOnsitePurchase($request->all());
2017-06-21 22:36:59 +02:00
if (request()->update) {
return redirect('/client/dashboard')->withMessage(trans('texts.updated_payment_details'));
} elseif ($paymentDriver->isTwoStep()) {
2016-06-20 16:14:43 +02:00
Session::flash('warning', trans('texts.bank_account_verification_next_steps'));
} else {
Session::flash('message', trans('texts.applied_payment'));
}
return $this->completePurchase($invitation);
2016-06-20 16:14:43 +02:00
} catch (Exception $exception) {
2016-06-22 11:22:38 +02:00
return $this->error($paymentDriver, $exception, true);
2016-06-20 16:14:43 +02:00
}
}
/**
2017-01-30 20:40:43 +01:00
* @param bool $invitationKey
2016-09-15 12:41:09 +02:00
* @param mixed $gatewayTypeAlias
2017-01-30 20:40:43 +01:00
*
* @return \Illuminate\Http\RedirectResponse
*/
2016-09-15 12:41:09 +02:00
public function offsitePayment($invitationKey = false, $gatewayTypeAlias = false)
2016-06-20 16:14:43 +02:00
{
$invitationKey = $invitationKey ?: Session::get('invitation_key');
$invitation = Invitation::with('invoice.invoice_items', 'invoice.client.currency', 'invoice.client.account.account_gateways.gateway')
->where('invitation_key', '=', $invitationKey)->firstOrFail();
2017-01-30 17:05:31 +01:00
if (! $gatewayTypeAlias) {
2016-09-15 12:41:09 +02:00
$gatewayTypeId = Session::get($invitation->id . 'gateway_type');
} elseif ($gatewayTypeAlias != GATEWAY_TYPE_TOKEN) {
$gatewayTypeId = GatewayType::getIdFromAlias($gatewayTypeAlias);
} else {
$gatewayTypeId = $gatewayTypeAlias;
}
$paymentDriver = $invitation->account->paymentDriver($invitation, $gatewayTypeId);
2016-06-20 16:14:43 +02:00
if ($error = Input::get('error_description') ?: Input::get('error')) {
return $this->error($paymentDriver, $error);
}
try {
2016-08-13 21:19:37 +02:00
if ($paymentDriver->completeOffsitePurchase(Input::all())) {
Session::flash('message', trans('texts.applied_payment'));
}
2017-01-30 20:40:43 +01:00
return $this->completePurchase($invitation, true);
2016-06-20 16:14:43 +02:00
} catch (Exception $exception) {
return $this->error($paymentDriver, $exception);
}
}
private function completePurchase($invitation, $isOffsite = false)
{
if ($redirectUrl = session('redirect_url:' . $invitation->invitation_key)) {
$separator = strpos($redirectUrl, '?') === false ? '?' : '&';
2017-01-30 20:40:43 +01:00
return redirect()->to($redirectUrl . $separator . 'invoice_id=' . $invitation->invoice->public_id);
} else {
// Allow redirecting to iFrame for offsite payments
2016-12-05 19:56:57 +01:00
if ($isOffsite) {
return redirect()->to($invitation->getLink());
} else {
return redirect()->to('view/' . $invitation->invitation_key);
}
}
}
/**
* @param $paymentDriver
* @param $exception
* @param bool $showPayment
2017-01-30 20:40:43 +01:00
*
* @return \Illuminate\Http\RedirectResponse
*/
2016-06-24 17:15:51 +02:00
private function error($paymentDriver, $exception, $showPayment = false)
2016-06-20 16:14:43 +02:00
{
if (is_string($exception)) {
$displayError = $exception;
$logError = $exception;
} else {
$displayError = $exception->getMessage();
$logError = Utils::getErrorString($exception);
}
$message = sprintf('%s: %s', ucwords($paymentDriver->providerName()), $displayError);
Session::flash('error', $message);
$message = sprintf('Payment Error [%s]: %s', $paymentDriver->providerName(), $logError);
Utils::logError($message, 'PHP', true);
2016-06-22 11:22:38 +02:00
$route = $showPayment ? 'payment/' : 'view/';
2017-01-30 20:40:43 +01:00
2016-06-22 11:22:38 +02:00
return redirect()->to($route . $paymentDriver->invitation->invitation_key);
2016-06-20 16:14:43 +02:00
}
/**
* @param $routingNumber
2017-01-30 20:40:43 +01:00
*
* @return \Illuminate\Http\JsonResponse
*/
2017-01-30 17:05:31 +01:00
public function getBankInfo($routingNumber)
{
2017-01-30 20:40:43 +01:00
if (strlen($routingNumber) != 9 || ! preg_match('/\d{9}/', $routingNumber)) {
2016-06-20 16:14:43 +02:00
return response()->json([
'message' => 'Invalid routing number',
], 400);
}
$data = PaymentMethod::lookupBankData($routingNumber);
if (is_string($data)) {
return response()->json([
'message' => $data,
], 500);
2017-01-30 20:40:43 +01:00
} elseif (! empty($data)) {
2016-06-20 16:14:43 +02:00
return response()->json($data);
}
return response()->json([
'message' => 'Bank not found',
], 404);
}
/**
* @param $accountKey
* @param $gatewayId
2017-01-30 20:40:43 +01:00
*
* @return \Illuminate\Http\JsonResponse
*/
2016-06-20 16:14:43 +02:00
public function handlePaymentWebhook($accountKey, $gatewayId)
{
$gatewayId = intval($gatewayId);
$account = Account::where('accounts.account_key', '=', $accountKey)->first();
2017-01-30 20:40:43 +01:00
if (! $account) {
2016-06-20 16:14:43 +02:00
return response()->json([
'message' => 'Unknown account',
], 404);
}
$accountGateway = $account->getGatewayConfig(intval($gatewayId));
2017-01-30 20:40:43 +01:00
if (! $accountGateway) {
2016-06-20 16:14:43 +02:00
return response()->json([
'message' => 'Unknown gateway',
], 404);
}
2016-06-23 15:15:52 +02:00
$paymentDriver = $accountGateway->paymentDriver();
2016-06-20 16:14:43 +02:00
2016-06-23 15:15:52 +02:00
try {
$result = $paymentDriver->handleWebHook(Input::all());
2017-01-30 20:40:43 +01:00
2016-06-23 15:15:52 +02:00
return response()->json(['message' => $result]);
} catch (Exception $exception) {
2017-03-20 14:54:36 +01:00
//Utils::logError($exception->getMessage(), 'PHP');
2017-01-30 20:40:43 +01:00
2016-06-23 16:05:50 +02:00
return response()->json(['message' => $exception->getMessage()], 500);
2016-06-20 16:14:43 +02:00
}
}
2016-09-15 12:41:09 +02:00
public function handleBuyNow(ClientRepository $clientRepo, InvoiceService $invoiceService, $gatewayTypeAlias = false)
2016-07-12 22:46:41 +02:00
{
if (Crawler::isCrawler()) {
return redirect()->to(NINJA_WEB_URL, 301);
}
2016-07-12 22:46:41 +02:00
$account = Account::whereAccountKey(Input::get('account_key'))->first();
$redirectUrl = Input::get('redirect_url');
$failureUrl = URL::previous();
2016-07-12 22:46:41 +02:00
2017-01-30 17:05:31 +01:00
if (! $account || ! $account->enable_buy_now_buttons || ! $account->hasFeature(FEATURE_BUY_NOW_BUTTONS)) {
return redirect()->to("{$failureUrl}/?error=invalid account");
2016-07-12 22:46:41 +02:00
}
Auth::onceUsingId($account->users[0]->id);
2017-04-02 15:54:07 +02:00
$account->loadLocalizationSettings();
2016-07-12 22:46:41 +02:00
$product = Product::scope(Input::get('product_id'))->first();
2017-01-30 17:05:31 +01:00
if (! $product) {
return redirect()->to("{$failureUrl}/?error=invalid product");
2016-07-12 22:46:41 +02:00
}
2016-12-27 22:56:55 +01:00
// check for existing client using contact_key
$client = false;
if ($contactKey = Input::get('contact_key')) {
$client = Client::scope()->whereHas('contacts', function ($query) use ($contactKey) {
$query->where('contact_key', $contactKey);
})->first();
2016-07-12 22:46:41 +02:00
}
2017-03-20 11:14:06 +01:00
if (! $client) {
$rules = [
'first_name' => 'string|max:100',
'last_name' => 'string|max:100',
'email' => 'email|string|max:100',
];
$validator = Validator::make(Input::all(), $rules);
if ($validator->fails()) {
return redirect()->to("{$failureUrl}/?error=" . $validator->errors()->first());
}
2016-07-12 22:46:41 +02:00
2017-03-20 11:14:06 +01:00
$data = [
'currency_id' => $account->currency_id,
'contact' => Input::all(),
2017-03-30 11:40:04 +02:00
'custom_value1' => Input::get('custom_client1'),
'custom_value2' => Input::get('custom_client2'),
2017-03-20 11:14:06 +01:00
];
if (request()->currency_code) {
$data['currency_code'] = request()->currency_code;
}
2017-03-20 11:14:06 +01:00
$client = $clientRepo->save($data, $client);
}
2016-07-12 22:46:41 +02:00
$data = [
2016-07-16 22:51:05 +02:00
'client_id' => $client->id,
2017-01-29 16:32:59 +01:00
'is_recurring' => filter_var(Input::get('is_recurring'), FILTER_VALIDATE_BOOLEAN),
'is_public' => filter_var(Input::get('is_recurring'), FILTER_VALIDATE_BOOLEAN),
2017-01-29 16:32:59 +01:00
'frequency_id' => Input::get('frequency_id'),
'auto_bill_id' => Input::get('auto_bill_id'),
'start_date' => Input::get('start_date', date('Y-m-d')),
'tax_rate1' => $account->tax_rate1,
'tax_name1' => $account->tax_name1 ?: '',
'tax_rate2' => $account->tax_rate2,
'tax_name2' => $account->tax_name2 ?: '',
2017-03-30 11:40:04 +02:00
'custom_text_value1' => Input::get('custom_invoice1'),
'custom_text_value2' => Input::get('custom_invoice2'),
2016-07-12 22:46:41 +02:00
'invoice_items' => [[
'product_key' => $product->product_key,
'notes' => $product->notes,
'cost' => $product->cost,
'qty' => 1,
'tax_rate1' => $account->tax_rate1,
'tax_name1' => $account->tax_name1 ?: '',
'tax_rate2' => $account->tax_rate2,
'tax_name2' => $account->tax_name2 ?: '',
2017-03-30 11:40:04 +02:00
'custom_value1' => Input::get('custom_product1') ?: $product->custom_value1,
'custom_value2' => Input::get('custom_product2') ?: $product->custom_value2,
2017-01-30 20:40:43 +01:00
]],
2016-07-12 22:46:41 +02:00
];
$invoice = $invoiceService->save($data);
2017-01-29 16:32:59 +01:00
if ($invoice->is_recurring) {
$invoice = $this->invoiceRepo->createRecurringInvoice($invoice->fresh());
}
2016-07-12 22:46:41 +02:00
$invitation = $invoice->invitations[0];
$link = $invitation->getLink();
if ($redirectUrl) {
session(['redirect_url:' . $invitation->invitation_key => $redirectUrl]);
}
2016-09-15 12:41:09 +02:00
if ($gatewayTypeAlias) {
2017-03-21 14:41:01 +01:00
$link = $invitation->getLink('payment') . "/{$gatewayTypeAlias}";
2016-07-12 22:46:41 +02:00
} else {
2017-03-21 14:41:01 +01:00
$link = $invitation->getLink();
}
if (filter_var(Input::get('return_link'), FILTER_VALIDATE_BOOLEAN)) {
return $link;
} else {
return redirect()->to($link);
2016-07-12 22:46:41 +02:00
}
}
2016-06-20 16:14:43 +02:00
}