osb/app/Http/Controllers/PaypalController.php

274 lines
6.8 KiB
PHP
Raw Permalink Normal View History

2020-07-27 04:49:59 +00:00
<?php
namespace App\Http\Controllers;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
2020-07-27 04:49:59 +00:00
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use PayPalCheckoutSdk\Core\PayPalHttpClient;
use PayPalCheckoutSdk\Core\ProductionEnvironment;
use PayPalCheckoutSdk\Core\SandboxEnvironment;
use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
use PayPalHttp\HttpException;
use App\Models\{Checkout,Invoice,Payment,PaymentItem};
2020-07-27 04:49:59 +00:00
class PaypalController extends Controller
{
private PayPalHttpClient $client;
protected const cart_url = 'u/checkout/cart';
2020-07-27 04:49:59 +00:00
// Create a new instance with our paypal credentials
public function __construct()
{
if (config('paypal.settings.mode') == 'sandbox')
$environment = new SandboxEnvironment(config('paypal.sandbox_client_id'),config('paypal.sandbox_secret'));
else
$environment = new ProductionEnvironment(config('paypal.live_client_id'),config('paypal.live_secret'));
$this->client = new PayPalHttpClient($environment);
}
public function cancel()
2020-07-27 04:49:59 +00:00
{
return redirect()
->to(self::cart_url);
2020-07-27 04:49:59 +00:00
}
/**
* Authorize a paypal payment, and redirect the user to pay.
*
* @return RedirectResponse
* @throws \PayPalHttp\IOException
2020-07-27 04:49:59 +00:00
*/
public function authorise()
2020-07-27 04:49:59 +00:00
{
$co = Checkout::where('name','ilike','paypal')->firstOrFail();
2020-07-27 04:49:59 +00:00
$currency = 'AUD'; // @todo TO determine from DB.;
$cart = request()->session()->get('invoice.cart');
2020-07-27 04:49:59 +00:00
if (! $cart)
return redirect()
->to('u/home');
2020-07-27 04:49:59 +00:00
$invoices = Invoice::find($cart);
$paypal = new OrdersCreateRequest();
$paypal->prefer('return=minimal');
// Paypal Purchase Units
$items = collect();
foreach ($invoices as $io) {
$fee = $co->fee($io->due,count($cart));
2020-07-27 04:49:59 +00:00
$total = round($io->due+$fee,2);
$items->push([
'reference_id'=>$io->id,
'invoice_id'=>$io->id,
'description'=>'Invoice Payment',
'custom_id'=>sprintf('%s:%s',$io->account_id,$fee*100),
'amount'=>[
'value'=>$total,
'currency_code'=>$currency,
'breakdown'=>[
'item_total'=>[
'value'=>$total,
'currency_code'=>$currency,
]
],
],
'items'=>[
[
'name'=>'Invoice: '.$io->id,
'unit_amount'=>[
'value'=>$total,
'currency_code'=>$currency,
],
'quantity'=>1,
'description'=>'Invoice Payment',
'category'=>'DIGITAL_GOODS',
],
]
]);
}
$data = collect();
$data->put('intent','CAPTURE');
$data->put('purchase_units',$items->toArray());
$data->put('application_context',[
'return_url' => url('pay/paypal/capture'),
'cancel_url' => url(self::cart_url),
2020-07-27 04:49:59 +00:00
]);
$paypal->body = $data->toArray();
try {
$response = $this->client->execute($paypal);
} catch (HttpException $e) {
Log::error('Paypal Exception',['request'=>$paypal,'response'=>$e->getMessage()]);
return redirect()
->to(self::cart_url)
->withErrors('Paypal Exception: '.$e->getCode());
2020-07-27 04:49:59 +00:00
} catch (\HttpException $e) {
Log::error('HTTP Exception',['request'=>$this->client,'response'=>$e->getMessage()]);
2020-07-27 04:49:59 +00:00
return redirect()
->to(self::cart_url)
->withErrors('HTTP Exception: '.$e->getCode());
2020-07-27 04:49:59 +00:00
}
// Get the approval link
$redirect_url = '';
foreach ($response->result->links as $link) {
if ($link->rel == 'approve') {
$redirect_url = $link->href;
break;
}
}
if ($redirect_url)
return redirect()
->away($redirect_url);
2020-07-27 04:49:59 +00:00
return redirect()
->to(self::cart_url)
->withErrors('An error occurred with Paypal?');
2020-07-27 04:49:59 +00:00
}
/**
* Capture a paypal payment
*
* @param Request $request
* @return RedirectResponse
* @throws \PayPalHttp\IOException
2020-07-27 04:49:59 +00:00
*/
public function capture(Request $request)
{
$paypal = new OrdersCaptureRequest($request->query('token'));
$paypal->prefer('return=representation');
$redirect_url = '';
try {
$response = $this->client->execute($paypal);
} catch (HttpException $e) {
$result = json_decode($e->getMessage());
Log::error(sprintf('Paypal Declined: Code: %s, DebugID: %s, Name: %s,Message: %s',$e->getCode(),$result->debug_id,$result->name,$result->message));
switch ($result->name) {
case 'UNPROCESSABLE_ENTITY':
foreach ($result->details as $detail)
Log::error(sprintf('Paypal Declined: Issue: %s Message: %s',$detail->issue,$detail->description));
// If we got a redirect link, lets redirect
foreach ($result->links as $link) {
if ($link->rel == 'redirect') {
$redirect_url = $link->href;
break;
}
}
break;
default:
Log::error(sprintf('Paypal Unhandled: %s',$result));
}
// If we got a redirect.
if ($redirect_url) {
Log::error('Paypal Capture: Redirect back to Paypal.');
return redirect()
->away($redirect_url);
2020-07-27 04:49:59 +00:00
}
return redirect()
->to(self::cart_url)
->withErrors('An error occurred with Paypal?');
2020-07-27 04:49:59 +00:00
} catch (\HttpException $e) {
Log::error('HTTP Exception',['request'=>$paypal,'response'=>$e->getMessage()]);
return redirect()
->to(self::cart_url)
->withErrors('HTTP Exception: '.$e->getCode());
2020-07-27 04:49:59 +00:00
}
if ((! $response) || (! $response->result->purchase_units)) {
2020-07-27 04:49:59 +00:00
Log::error('Paypal Capture: No Purchase Units?');
return redirect()
->to(self::cart_url)
->withErrors('Paypal Exception: NPU');
2020-07-27 04:49:59 +00:00
}
$co = Checkout::where('name','ilike','paypal')->firstOrFail();
2020-07-27 04:49:59 +00:00
// If we got here, we got a payment
foreach ($response->result->purchase_units as $pu) {
foreach ($pu->payments->captures as $cap) {
$po = new Payment;
$po->active = TRUE;
2020-07-27 04:49:59 +00:00
switch ($cap->status) {
case 'PENDING':
$po->pending_status = TRUE;
$po->pending = $cap->status_details->reason;
break;
case 'FAILED':
Log::error(sprintf('Paypal Payment Failed: Invoice: %s (%s).',$pu->invoice_id,$cap->error->details[0]->description));
continue 2;
default:
$po->pending_status = TRUE;
$po->pending = $cap->status_details->reason ?? 'Unknown Status';
break;
}
2022-06-13 05:46:38 +00:00
$po->paid_at = Carbon::parse($cap->create_time);
$po->checkout_id = $co->id;
2020-07-27 04:49:59 +00:00
$po->checkout_data = $cap->id;
list($account_id,$fee) = explode(':',$cap->custom_id);
$po->fees_amt = $fee/100;
$po->total_amt = $cap->amount->value-$po->fees_amt;
$po->account_id = $account_id;
$pio = new PaymentItem;
$pio->site_id = 1; // @todo To implement
$pio->invoice_id = $cap->invoice_id;
2022-04-22 05:23:08 +00:00
$pio->amount = $cap->amount->value-$po->fees_amt;
2020-07-27 04:49:59 +00:00
$po->items->push($pio);
// @todo To store payment fees on invoice
try {
$po->pushNew();
} catch (\Exception $e) {
Log::error('Error recording payment',['po'=>$po,'e'=>$e->getMessage(),'token'=>$request->query('token')]);
}
}
}
$request->session()->forget('invoice.cart');
2020-07-27 04:49:59 +00:00
Log::info('Paypal Payment Recorded',['po'=>$po->id]);
return redirect()
->to('u/home')
->with('success','Payment recorded thank you.');
2020-07-27 04:49:59 +00:00
}
}