Add paypal payments
This commit is contained in:
parent
9887996da8
commit
1242dffa20
@ -39,3 +39,9 @@ PUSHER_APP_CLUSTER=mt1
|
|||||||
|
|
||||||
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
|
||||||
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
|
||||||
|
|
||||||
|
PAYPAL_MODE=sandbox
|
||||||
|
PAYPAL_SANDBOX_CLIENT_ID=
|
||||||
|
PAYPAL_SANDBOX_SECRET=
|
||||||
|
PAYPAL_LIVE_CLIENT_ID=
|
||||||
|
PAYPAL_LIVE_SECRET=
|
34
app/Http/Controllers/CheckoutController.php
Normal file
34
app/Http/Controllers/CheckoutController.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
use App\Models\Checkout;
|
||||||
|
|
||||||
|
class CheckoutController extends Controller
|
||||||
|
{
|
||||||
|
public function cart_invoice(Request $request,Invoice $o=NULL)
|
||||||
|
{
|
||||||
|
if ($o) {
|
||||||
|
$request->session()->put('invoice.cart.'.$o->id,$o->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $request->session()->get('invoice.cart'))
|
||||||
|
return redirect()->to('u/home');
|
||||||
|
|
||||||
|
return View('u.invoice.cart')
|
||||||
|
->with('invoices',Invoice::find(array_values($request->session()->get('invoice.cart'))));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fee(Request $request,Checkout $o): float
|
||||||
|
{
|
||||||
|
return $o->fee($request->post('total',0));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pay(Request $request,Checkout $o)
|
||||||
|
{
|
||||||
|
return redirect('pay/paypal/authorise');
|
||||||
|
}
|
||||||
|
}
|
251
app/Http/Controllers/PaypalController.php
Normal file
251
app/Http/Controllers/PaypalController.php
Normal file
@ -0,0 +1,251 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Models\PaymentItem;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
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;
|
||||||
|
use App\Models\Invoice;
|
||||||
|
use App\Models\Payment;
|
||||||
|
|
||||||
|
class PaypalController extends Controller
|
||||||
|
{
|
||||||
|
private $client;
|
||||||
|
private $o = NULL;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
$this->o = Checkout::where('name','paypal')->firstOrFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel(Request $request)
|
||||||
|
{
|
||||||
|
return redirect()->to('u/invoice/cart');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authorize a paypal payment, and redirect the user to pay.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function authorise(Request $request)
|
||||||
|
{
|
||||||
|
$currency = 'AUD'; // @todo TO determine from DB.;
|
||||||
|
$cart = $request->session()->get('invoice.cart');
|
||||||
|
|
||||||
|
if (! $cart)
|
||||||
|
return redirect()->to('u/home');
|
||||||
|
|
||||||
|
$invoices = Invoice::find($cart);
|
||||||
|
|
||||||
|
$paypal = new OrdersCreateRequest();
|
||||||
|
$paypal->prefer('return=minimal');
|
||||||
|
|
||||||
|
// Paypal Purchase Units
|
||||||
|
$items = collect();
|
||||||
|
foreach ($invoices as $io) {
|
||||||
|
$fee = $this->o->fee($io->due,count($cart));
|
||||||
|
$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('u/invoice/cart'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$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('u/invoice/cart')->withErrors('Paypal Exception: '.$e->getCode());
|
||||||
|
|
||||||
|
} catch (\HttpException $e) {
|
||||||
|
Log::error('HTTP Exception',['request'=>$request,'response'=>$e->getMessage()]);
|
||||||
|
|
||||||
|
return redirect()->to('u/invoice/cart')->withErrors('HTTP Exception: '.$e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to('u/invoice/cart')->withErrors('An error occurred with Paypal?');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capture a paypal payment
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()->to('u/invoice/cart')->withErrors('An error occurred with Paypal?');
|
||||||
|
|
||||||
|
} catch (\HttpException $e) {
|
||||||
|
Log::error('HTTP Exception',['request'=>$paypal,'response'=>$e->getMessage()]);
|
||||||
|
|
||||||
|
return redirect()->to('u/invoice/cart')->withErrors('HTTP Exception: '.$e->getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $response OR ! $response->result->purchase_units) {
|
||||||
|
Log::error('Paypal Capture: No Purchase Units?');
|
||||||
|
|
||||||
|
return redirect()->to('u/invoice/cart')->withErrors('Paypal Exception: NPU');
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we got here, we got a payment
|
||||||
|
foreach ($response->result->purchase_units as $pu) {
|
||||||
|
foreach ($pu->payments->captures as $cap) {
|
||||||
|
$po = new Payment;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
$po->date_payment = Carbon::parse($cap->create_time);
|
||||||
|
$po->checkout_id = $this->o->id;
|
||||||
|
$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;
|
||||||
|
$pio->alloc_amt = $cap->amount->value-$po->fees_amt;
|
||||||
|
|
||||||
|
$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');
|
||||||
|
Log::info('Paypal Payment Recorded',['po'=>$po->id]);
|
||||||
|
return redirect()->to('u/home')->with('success','Payment recorded thank you.');
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,6 @@ class AccountController extends Controller
|
|||||||
$io->items->push($o);
|
$io->items->push($o);
|
||||||
}
|
}
|
||||||
|
|
||||||
return View('u.invoice',['o'=>$io]);
|
return View('u.invoice.home',['o'=>$io]);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -55,7 +55,7 @@ class UserHomeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function invoice(Invoice $o): View
|
public function invoice(Invoice $o): View
|
||||||
{
|
{
|
||||||
return View('u.invoice',['o'=>$o]);
|
return View('u.invoice.home',['o'=>$o]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,7 +66,7 @@ class UserHomeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function invoice_pdf(Invoice $o)
|
public function invoice_pdf(Invoice $o)
|
||||||
{
|
{
|
||||||
return PDF::loadView('u.invoice', ['o'=>$o])->stream(sprintf('%s.pdf',$o->invoice_account_id));
|
return PDF::loadView('u.invoice.home',['o'=>$o])->stream(sprintf('%s.pdf',$o->invoice_account_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,4 +13,31 @@ class Checkout extends Model
|
|||||||
{
|
{
|
||||||
return $this->hasMany(Payment::class);
|
return $this->hasMany(Payment::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** SCOPES **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a record
|
||||||
|
*
|
||||||
|
* @param $query
|
||||||
|
* @param string $term
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public function scopeActive($query)
|
||||||
|
{
|
||||||
|
return $query->where('active',TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** FUNCTIONS **/
|
||||||
|
|
||||||
|
public function fee(float $amt,int $items=1): float
|
||||||
|
{
|
||||||
|
if (! $this->fee_passon OR ! $items)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
$fee = $amt+$this->fee_fixed/$items;
|
||||||
|
$fee /= (1-$this->fee_variable);
|
||||||
|
|
||||||
|
return round($fee-$amt,2);
|
||||||
|
}
|
||||||
}
|
}
|
@ -94,7 +94,18 @@ class Invoice extends Model
|
|||||||
|
|
||||||
public function getPaidAttribute()
|
public function getPaidAttribute()
|
||||||
{
|
{
|
||||||
return $this->currency()->round($this->paymentitems->sum('alloc_amt'));
|
return $this->currency()->round(
|
||||||
|
$this->paymentitems
|
||||||
|
->filter(function($item) { return ! $item->payment->pending_status; })
|
||||||
|
->sum('alloc_amt'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPendingPaidAttribute()
|
||||||
|
{
|
||||||
|
return $this->currency()->round(
|
||||||
|
$this->paymentitems
|
||||||
|
->filter(function($item) { return $item->payment->pending_status; })
|
||||||
|
->sum('alloc_amt'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getSubTotalAttribute()
|
public function getSubTotalAttribute()
|
||||||
|
@ -4,11 +4,12 @@ namespace App\Models;
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
use App\Traits\PushNew;
|
||||||
use App\Traits\NextKey;
|
use App\Traits\NextKey;
|
||||||
|
|
||||||
class Payment extends Model
|
class Payment extends Model
|
||||||
{
|
{
|
||||||
use NextKey;
|
use NextKey,PushNew;
|
||||||
const RECORD_ID = 'payment';
|
const RECORD_ID = 'payment';
|
||||||
public $incrementing = FALSE;
|
public $incrementing = FALSE;
|
||||||
|
|
||||||
@ -20,6 +21,9 @@ class Payment extends Model
|
|||||||
protected $dateFormat = 'U';
|
protected $dateFormat = 'U';
|
||||||
protected $with = ['account.country.currency','items'];
|
protected $with = ['account.country.currency','items'];
|
||||||
|
|
||||||
|
// Array of items that can be updated with PushNew
|
||||||
|
protected $pushable = ['items'];
|
||||||
|
|
||||||
public function account()
|
public function account()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(Account::class);
|
return $this->belongsTo(Account::class);
|
||||||
|
@ -4,7 +4,21 @@ namespace App\Models;
|
|||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
use App\Traits\NextKey;
|
||||||
|
use App\Traits\PushNew;
|
||||||
|
|
||||||
class PaymentItem extends Model
|
class PaymentItem extends Model
|
||||||
{
|
{
|
||||||
|
use NextKey,PushNew;
|
||||||
|
const RECORD_ID = 'payment_item';
|
||||||
|
public $incrementing = FALSE;
|
||||||
|
|
||||||
|
const CREATED_AT = 'date_orig';
|
||||||
|
const UPDATED_AT = 'date_last';
|
||||||
|
|
||||||
protected $table = 'ab_payment_item';
|
protected $table = 'ab_payment_item';
|
||||||
|
|
||||||
|
public function payment() {
|
||||||
|
return $this->belongsTo(Payment::class);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
namespace App;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
"laravel/passport": "^8.2",
|
"laravel/passport": "^8.2",
|
||||||
"laravel/socialite": "^4.2",
|
"laravel/socialite": "^4.2",
|
||||||
"leenooks/laravel": "^6.0",
|
"leenooks/laravel": "^6.0",
|
||||||
|
"paypal/paypal-checkout-sdk": "^1.0",
|
||||||
"spatie/laravel-demo-mode": "^2.5",
|
"spatie/laravel-demo-mode": "^2.5",
|
||||||
"spinen/laravel-quickbooks-client": "^3.1"
|
"spinen/laravel-quickbooks-client": "^3.1"
|
||||||
},
|
},
|
||||||
|
1334
composer.lock
generated
1334
composer.lock
generated
File diff suppressed because it is too large
Load Diff
45
config/paypal.php
Normal file
45
config/paypal.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
/**
|
||||||
|
* Set our Sandbox and Live credentials
|
||||||
|
*/
|
||||||
|
'sandbox_client_id' => env('PAYPAL_SANDBOX_CLIENT_ID', ''),
|
||||||
|
'sandbox_secret' => env('PAYPAL_SANDBOX_SECRET', ''),
|
||||||
|
'live_client_id' => env('PAYPAL_LIVE_CLIENT_ID', ''),
|
||||||
|
'live_secret' => env('PAYPAL_LIVE_SECRET', ''),
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SDK configuration settings
|
||||||
|
*/
|
||||||
|
'settings' => [
|
||||||
|
/**
|
||||||
|
* Payment Mode
|
||||||
|
*
|
||||||
|
* Available options are 'sandbox' or 'live'
|
||||||
|
*/
|
||||||
|
'mode' => env('PAYPAL_MODE', 'sandbox'),
|
||||||
|
|
||||||
|
// Specify the max connection attempt (3000 = 3 seconds)
|
||||||
|
'http.ConnectionTimeOut' => 3000,
|
||||||
|
|
||||||
|
// Specify whether or not we want to store logs
|
||||||
|
'log.LogEnabled' => true,
|
||||||
|
|
||||||
|
// Specigy the location for our paypal logs
|
||||||
|
'log.FileName' => storage_path() . '/logs/paypal.log',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log Level
|
||||||
|
*
|
||||||
|
* Available options: 'DEBUG', 'INFO', 'WARN' or 'ERROR'
|
||||||
|
*
|
||||||
|
* Logging is most verbose in the DEBUG level and decreases
|
||||||
|
* as you proceed towards ERROR. WARN or ERROR would be a
|
||||||
|
* recommended option for live environments.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
'log.LogLevel' => 'DEBUG'
|
||||||
|
],
|
||||||
|
];
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddpendingToPayment extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('ab_payment', function (Blueprint $table) {
|
||||||
|
$table->string('pending')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('ab_payment', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('pending');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
111
resources/views/theme/backend/adminlte/u/invoice/cart.blade.php
Normal file
111
resources/views/theme/backend/adminlte/u/invoice/cart.blade.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
@extends('adminlte::layouts.app')
|
||||||
|
|
||||||
|
@section('htmlheader_title')
|
||||||
|
Payment Cart
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('contentheader_title')
|
||||||
|
Payment Cart
|
||||||
|
@endsection
|
||||||
|
@section('contentheader_description')
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('main-content')
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-4">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">Invoices to Pay</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ url('u/checkout/pay') }}">
|
||||||
|
{{ csrf_field() }}
|
||||||
|
<input type="hidden" name="type" value="invoice">
|
||||||
|
|
||||||
|
<div class="input-group flex-nowrap mb-5">
|
||||||
|
<div class="input-group-prepend">
|
||||||
|
<span class="input-group-text">Payment Method</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<select class="form-control" id="paymethod" name="checkout_id[]" required>
|
||||||
|
<option></option>
|
||||||
|
@foreach (\App\Models\Checkout::active()->orderBy('name')->get() as $oo)
|
||||||
|
<option value="{{ $oo->id }}">{{ $oo->name }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table id="invoices" class="table table-sm w-100">
|
||||||
|
<tr>
|
||||||
|
<th>Invoice</th>
|
||||||
|
<th class="text-right">Balance Due</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
@foreach ($invoices as $io)
|
||||||
|
<input type="hidden" name="invoice_id[]" value="{{ $io->id }}">
|
||||||
|
<tr>
|
||||||
|
<td>{{ $io->id }}</td>
|
||||||
|
<td class="text-right">{{ $io->due }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th class="text-right">Sub Total</th>
|
||||||
|
<td class="text-right">{{ number_format($invoices->sum('due'),2) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="text-right">Payment Fees</th>
|
||||||
|
<td class="text-right"><span id="payfee">TBA</span></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="text-right">Payment Total</th>
|
||||||
|
<th class="text-right"><span id="paytotal">TBA</span></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th colspan="2">
|
||||||
|
<input type="submit" class="btn btn-dark mt-2" name="pay" value="Cancel">
|
||||||
|
<input type="submit" class="btn btn-success mt-2 float-right" name="pay" value="Submit" disabled>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('page-scripts')
|
||||||
|
@css('//cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/css/select2.min.css','select-css')
|
||||||
|
@js('//cdnjs.cloudflare.com/ajax/libs/select2/4.0.12/js/select2.min.js','select-js')
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$('#paymethod').select2({
|
||||||
|
placeholder: 'Payment method...',
|
||||||
|
|
||||||
|
}).on('change',function(item) {
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
data: {total: {{ $invoices->sum('due') }},count: {{ $invoices->count() }} },
|
||||||
|
dataType: "json",
|
||||||
|
cache: true,
|
||||||
|
url: '{{ url('api/u/checkout/fee') }}'+'/'+$(this).val(),
|
||||||
|
timeout: 25000,
|
||||||
|
error: function(x) {
|
||||||
|
alert("Failed to submit, please try again...");
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
$("span[id=payfee]").html(data.toFixed(2));
|
||||||
|
$("span[id=paytotal]").html(({{ $invoices->sum('due') }}+data).toFixed(2));
|
||||||
|
$("input[type=submit]").prop('disabled',false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@append
|
@ -155,6 +155,11 @@
|
|||||||
<td class="text-right">${{ number_format($o->total,$o->currency()->rounding) }}</td>
|
<td class="text-right">${{ number_format($o->total,$o->currency()->rounding) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@if($o->id)
|
@if($o->id)
|
||||||
|
<tr>
|
||||||
|
<th> </th>
|
||||||
|
<th>Payments To Clear:</th>
|
||||||
|
<td class="text-right">${{ number_format($o->pending_paid,$o->currency()->rounding) }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th>Payments:</th>
|
<th>Payments:</th>
|
||||||
@ -182,8 +187,10 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<a href="javascript:window.print();" class="btn btn-default"><i class="fa fa-print"></i> Print</a>
|
<a href="javascript:window.print();" class="btn btn-default"><i class="fa fa-print"></i> Print</a>
|
||||||
@if($o->id)
|
@if($o->id)
|
||||||
<button type="button" class="btn btn-success float-right"><i class="fa fa-credit-card"></i> Submit Payment</button>
|
<a href="{{ url('u/invoice/cart',$o->id) }}" class="btn btn-success float-right">
|
||||||
<a href="{{ url(sprintf('u/invoice/%s/pdf',$o->id)) }}" class="btn btn-primary float-right" style="margin-right: 5px;">
|
<i class="fa fa-credit-card"></i> Pay
|
||||||
|
</a>
|
||||||
|
<a href="{{ url(sprintf('u/invoice/%s/pdf',$o->id)) }}" class="btn btn-primary float-right mr-2">
|
||||||
<i class="fa fa-download"></i> Download PDF
|
<i class="fa fa-download"></i> Download PDF
|
||||||
</a>
|
</a>
|
||||||
@endif
|
@endif
|
@ -29,5 +29,7 @@ Route::group(['middleware'=>['auth:api','role:reseller']], function() {
|
|||||||
Route::group(['middleware'=>'auth:api'], function() {
|
Route::group(['middleware'=>'auth:api'], function() {
|
||||||
Route::get('/u/services/{o}','UserServicesController@services')
|
Route::get('/u/services/{o}','UserServicesController@services')
|
||||||
->where('o','[0-9]+')
|
->where('o','[0-9]+')
|
||||||
->middleware('can:view,o');;
|
->middleware('can:view,o');
|
||||||
|
Route::post('/u/checkout/fee/{o}','CheckoutController@fee')
|
||||||
|
->where('o','[0-9]+');
|
||||||
});
|
});
|
@ -57,9 +57,14 @@ Route::group(['middleware'=>['theme:adminlte-be','auth'],'prefix'=>'u'],function
|
|||||||
Route::get('account/{o}/invoice','User\AccountController@view_invoice_next')
|
Route::get('account/{o}/invoice','User\AccountController@view_invoice_next')
|
||||||
->where('o','[0-9]+')
|
->where('o','[0-9]+')
|
||||||
->middleware('can:view,o');
|
->middleware('can:view,o');
|
||||||
|
Route::post('checkout/pay','CheckoutController@pay');
|
||||||
Route::get('invoice/{o}','UserHomeController@invoice')
|
Route::get('invoice/{o}','UserHomeController@invoice')
|
||||||
->where('o','[0-9]+')
|
->where('o','[0-9]+')
|
||||||
->middleware('can:view,o');
|
->middleware('can:view,o');
|
||||||
|
Route::get('invoice/cart','CheckoutController@cart_invoice');
|
||||||
|
Route::get('invoice/cart/{o}','CheckoutController@cart_invoice')
|
||||||
|
->where('o','[0-9]+')
|
||||||
|
->middleware('can:view,o');
|
||||||
Route::get('invoice/{o}/pdf','UserHomeController@invoice_pdf')
|
Route::get('invoice/{o}/pdf','UserHomeController@invoice_pdf')
|
||||||
->where('o','[0-9]+')
|
->where('o','[0-9]+')
|
||||||
->middleware('can:view,o');
|
->middleware('can:view,o');
|
||||||
@ -90,9 +95,13 @@ Route::group(['middleware'=>['theme:metronic-fe']],function() {
|
|||||||
|
|
||||||
Route::get('product_order/{o}','OrderController@product_order');
|
Route::get('product_order/{o}','OrderController@product_order');
|
||||||
Route::get('product_info/{o}','OrderController@product_info');
|
Route::get('product_info/{o}','OrderController@product_info');
|
||||||
Route::redirect('/home','/u/home');
|
Route::redirect('home','u/home');
|
||||||
Route::demoAccess('/uc-access');
|
Route::demoAccess('uc-access');
|
||||||
Route::redirect('/under-construction','http://www.graytech.net.au');
|
Route::redirect('under-construction','http://www.graytech.net.au');
|
||||||
Route::get('/u/{type}/{action}/{id}','UserHomeController@oldsite');
|
Route::get('u/{type}/{action}/{id}','UserHomeController@oldsite');
|
||||||
|
|
||||||
Route::get('/search','SearchController@search');
|
Route::get('search','SearchController@search');
|
||||||
|
|
||||||
|
Route::get('pay/paypal/authorise','PaypalController@authorise');
|
||||||
|
Route::get('pay/paypal/cancel','PaypalController@cancel');
|
||||||
|
Route::get('pay/paypal/capture','PaypalController@capture');
|
Loading…
Reference in New Issue
Block a user