Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added code for IPN handling #7

Merged
merged 4 commits into from Mar 4, 2018
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+281 −11
Diff settings

Always

Just for now

@@ -4,14 +4,60 @@
use App\Order;
use App\PayPal;
use App\PayPalIPN;
use Illuminate\Http\Request;
use PayPal\IPN\Event\IPNInvalid;
use PayPal\IPN\Event\IPNVerificationFailure;
use PayPal\IPN\Event\IPNVerified;
use PayPal\IPN\Listener\Http\ArrayListener;
use App\Repositories\IPNRepository;
/**
* Class PayPalController
* @package App\Http\Controllers
*/
class PayPalController extends Controller
{
/**
* @param IPNRepository $repository
*/
public function __construct(IPNRepository $repository)
{
$this->repository = $repository;
}
/**
* @param $order_id
* @param $env
* @param Request $request
*/
public function webhook($order_id, $env, Request $request)
{
$listener = new ArrayListener;
if ($env == 'sandbox') {
$listener->useSandbox();
}
$listener->setData($request->all());
$listener = $listener->run();
$listener->onInvalid(function (IPNInvalid $event) use ($order_id) {
$this->repository->handle($event, PayPalIPN::IPN_INVALID, $order_id);
});
$listener->onVerified(function (IPNVerified $event) use ($order_id) {
$this->repository->handle($event, PayPalIPN::IPN_VERIFIED, $order_id);
});
$listener->onVerificationFailure(function (IPNVerificationFailure $event) use ($order_id) {
$this->repository->handle($event, PayPalIPN::IPN_FAILURE, $order_id);
});
$listener->listen();
}
/**
* @param Request $request
*/
@@ -95,13 +141,4 @@ public function cancelled($order_id)
'message' => 'You have cancelled your recent PayPal payment !',
]);
}
/**
* @param $order_id
* @param $env
*/
public function webhook($order_id, $env)
{
// to do with next blog post
}
}
Copy path View file
@@ -19,7 +19,6 @@ class Kernel extends HttpKernel
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\PreferredDomain::class,
];
/**
@@ -59,5 +58,6 @@ class Kernel extends HttpKernel
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'authorize' => \App\Http\Middleware\AuthorizeDevice::class,
'nocache' => \App\Http\Middleware\NoCache::class,
];
}
Copy path View file
@@ -0,0 +1,28 @@
<?php
namespace App\Http\Middleware;
use Closure;
/**
* Class NoCache
* @package App\Http\Middleware
*/
class NoCache
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$response = $next($request);
$response->header('Cache-Control', 'no-cache, must-revalidate');
return $response;
}
}
@@ -12,6 +12,6 @@ class VerifyCsrfToken extends Middleware
* @var array
*/
protected $except = [
//
'/webhook/paypal/*',
];
}
Copy path View file
@@ -3,13 +3,19 @@
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class Order
* @package App
*/
class Order extends Model
{
use SoftDeletes;
const COMPLETED = 1;
const PENDING = 0;
/**
* @var string
*/
@@ -24,4 +30,34 @@ class Order extends Model
* @var array
*/
protected $fillable = ['transaction_id', 'amount', 'payment_status'];
/**
* @param Builder $query
* @param string $transaction_id
* @return mixed
*/
public function scopeFindByTransactionId($query, $transaction_id)
{
return $query->where('transaction_id', $transaction_id);
}
/**
* Payment completed.
*
* @return boolean
*/
public function paid()
{
return in_array($this->payment_status, [self::COMPLETED]);
}
/**
* Payment is still pending.
*
* @return boolean
*/
public function unpaid()
{
return in_array($this->payment_status, [self::PENDING]);
}
}
Copy path View file
@@ -0,0 +1,65 @@
<?php
namespace App;
use App\Order;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
/**
* Class PayPalIPN
* @package App
*/
class PayPalIPN extends Model
{
use SoftDeletes;
const COMPLETED = "Completed";
const IPN_FAILURE = "FALIURE";
const IPN_INVALID = "INVALID";
const IPN_VERIFIED = "VERIFIED";
/**
* @var boolean
*/
public $timestamps = true;
/**
* @var array
*/
protected $dates = ['deleted_at'];
/**
* @var array
*/
protected $fillable = ['order_id', 'verified', 'transaction_id', 'payment_status', 'request_method', 'request_url', 'request_headers', 'payload'];
/**
* @var string
*/
protected $table = 'paypal_ipn_records';
/**
* @return boolena
*/
public function isCompleted()
{
return in_array($this->payment_status, [self::COMPLETED]);
}
/**
* @return boolena
*/
public function isVerified()
{
return in_array($this->verified, [self::IPN_VERIFIED]);
}
/**
* @return mixed
*/
public function orders()
{
return $this->belongsTo(Order::class);
}
}
@@ -0,0 +1,64 @@
<?php
namespace App\Repositories;
use App\Order;
use App\PayPalIPN;
use Illuminate\Http\Request;
/**
* Class IPNRepository
* @package App\Repositories
*/
class IPNRepository
{
/**
* @param Request $request
*/
public function __construct(Request $request)
{
$this->request = $request;
}
/**
* @param $event
* @param $verified
* @param $order_id
*/
public function handle($event, $verified, $order_id)
{
$object = $event->getMessage();
if (is_numeric($order_id)) {
$order = Order::find($order_id);
}
if (empty($order)) {
$order = Order::findByTransactionId(
$object->get('txn_id')
)->first();
}
$paypal = PayPalIPN::create([
'verified' => $verified,
'transaction_id' => $object->get('txn_id'),
'order_id' => $order ? $order->id : null,
'payment_status' => $object->get('payment_status'),
'request_method' => $this->request->method(),
'request_url' => $this->request->url(),
'request_headers' => json_encode($this->request->header()),
'payload' => json_encode($this->request->all()),
]);
if ($paypal->isVerified() && $paypal->isCompleted()) {
if ($order && $order->unpaid()) {
$order->update([
'payment_status' => $order::COMPLETED,
]);
// notify customer
// notify order handling staff
// update database logic
}
}
}
}
@@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateTablePaypalIpnRecords extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('paypal_ipn_records', function (Blueprint $table) {
$table->increments('id');
$table->integer('order_id')->nullable();
$table->string('verified');
$table->string('transaction_id');
$table->string('payment_status');
$table->string('request_method')->nullable();
$table->string('request_url')->nullable();
$table->longText('request_headers')->nullable();
$table->longText('payload')->nullable();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('paypal_ipn_records');
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.