Payment refunds (#3687)

* Fix whereClientId when starting payment

* Refunding using Paypal

* Refunding engine

* Cleanup and making refund method work

* Remove "refund" method from BasePaymentController

* Add "refund" to PaypalExpressPaymentDriver

* Extract refunding into own classes

* Apply php-cs-fixer to PaypalExpress

* Refunding with stripe
This commit is contained in:
Benjamin Beganović 2020-05-14 03:04:23 +02:00 committed by GitHub
parent 14577fdfd0
commit a613cfed7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 146 additions and 30 deletions

View File

@ -0,0 +1,31 @@
<?php
namespace App\Exceptions;
use Exception;
class PaymentRefundFailed extends Exception
{
/**
* Report the exception.
*
* @return void
*/
public function report()
{
//
}
/**
* Render the exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function render($request)
{
return response()->json([
'message' => 'Unable to refund the transaction'
], 401);
}
}

View File

@ -72,7 +72,7 @@ class PaymentController extends Controller
public function process()
{
$invoices = Invoice::whereIn('id', $this->transformKeys(request()->invoices))
->whereClientId(auth('contact')->user()->company()->id)
->where('company_id', auth('contact')->user()->company->id)
->get();
$amount = $invoices->sum('balance');

View File

@ -1,4 +1,5 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com)
*
@ -20,7 +21,6 @@ use App\Models\Payment;
use App\Models\PaymentType;
use App\Models\SystemLog;
use App\Utils\Traits\MakesHash;
use Illuminate\Http\Request;
use Omnipay\Common\Item;
/**
@ -61,7 +61,7 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
{
use MakesHash;
protected $refundable = false;
protected $refundable = true;
protected $token_billing = false;
@ -270,4 +270,41 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
return $payment;
}
public function refund(Payment $payment, $amount = null)
{
$this->gateway();
$response = $this->gateway
->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount ?? $payment->amount])
->send();
if ($response->isSuccessful()) {
SystemLogger::dispatch(
[
'server_response' => $response->getMessage(),
'data' => request()->all(),
],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL,
$this->client
);
return true;
}
SystemLogger::dispatch(
[
'server_response' => $response->getMessage(),
'data' => request()->all(),
],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_PAYPAL,
$this->client
);
return false;
}
}

View File

@ -471,6 +471,42 @@ class StripePaymentDriver extends BasePaymentDriver
return $customer;
}
public function refund(Payment $payment, $amount = null)
{
$this->gateway();
$response = $this->gateway
->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount ?? $payment->amount])
->send();
if ($response->isSuccessful()) {
SystemLogger::dispatch(
[
'server_response' => $response->getMessage(),
'data' => request()->all(),
],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_SUCCESS,
SystemLog::TYPE_PAYPAL,
$this->client
);
return true;
}
SystemLogger::dispatch(
[
'server_response' => $response->getMessage(),
'data' => request()->all(),
],
SystemLog::CATEGORY_GATEWAY_RESPONSE,
SystemLog::EVENT_GATEWAY_FAILURE,
SystemLog::TYPE_PAYPAL,
$this->client
);
return false;
}
/************************************** Omnipay API methods **********************************************************/
}

View File

@ -11,9 +11,11 @@
namespace App\Utils\Traits\Payment;
use App\Exceptions\PaymentRefundFailed;
use App\Factory\CreditFactory;
use App\Factory\InvoiceItemFactory;
use App\Models\Activity;
use App\Models\CompanyGateway;
use App\Models\Credit;
use App\Models\Invoice;
use App\Models\Payment;
@ -163,11 +165,18 @@ trait Refundable
$credit_note->number = $this->client->getNextCreditNumber($this->client);
$credit_note->save();
//determine if we need to refund via gateway
if ($data['gateway_refund'] !== false) {
//todo process gateway refund, on success, reduce the credit note balance to 0
}
$gateway = CompanyGateway::find($this->company_gateway_id);
if ($gateway) {
$amount = request()->has('amount') ? request()->amount : null;
$response = $gateway->driver($this->client)->refund($this, $amount);
if (!$response) {
throw new PaymentRefundFailed();
}
}
}
if ($total_refund > 0) {
$this->refunded += $total_refund;

View File

@ -78,6 +78,7 @@
href="{{ route('client.invoice.show', ['invoice' => $invoice->hashed_id])}}">
{{ $invoice->number }}
</a>
<span>Payment: {{ $payment->hashed_id }} Invoice: {{ $invoice->hashed_id }} Amount: {{ $payment->amount }}</span>
</div>
</div>
@endforeach

View File

@ -3,6 +3,8 @@
* Signup Routes
*/
use Omnipay\Omnipay;
Route::get('/', 'BaseController@flutterRoute')->middleware('guest');
Route::get('setup', 'SetupController@index')->middleware('guest');
Route::post('setup/check_db', 'SetupController@checkDB')->middleware('guest');