1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00
invoiceninja/app/PaymentDrivers/BasePaymentDriver.php
David Bomba ba75a44eb8
Laravel 7.x Shift (#40)
* Adopt Laravel coding style

The Laravel framework adopts the PSR-2 coding style with some additions.
Laravel apps *should* adopt this coding style as well.

However, Shift allows you to customize the adopted coding style by
adding your own [PHP CS Fixer][1] `.php_cs` config to your project.

You may use [Shift's .php_cs][2] file as a base.

[1]: https://github.com/FriendsOfPHP/PHP-CS-Fixer
[2]: https://gist.github.com/laravel-shift/cab527923ed2a109dda047b97d53c200

* Shift bindings

PHP 5.5.9+ adds the new static `class` property which provides the fully qualified class name. This is preferred over using class name strings as these references are checked by the parser.

* Shift core files

* Shift to Throwable

* Add laravel/ui dependency

* Unindent vendor mail templates

* Shift config files

* Default config files

In an effort to make upgrading the constantly changing config files
easier, Shift defaulted them so you can review the commit diff for
changes. Moving forward, you should use ENV variables or create a
separate config file to allow the core config files to remain
automatically upgradeable.

* Shift Laravel dependencies

* Shift cleanup

* Upgrade to Laravel 7

Co-authored-by: Laravel Shift <shift@laravelshift.com>
2020-09-06 19:38:10 +10:00

310 lines
8.9 KiB
PHP

<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2020. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\PaymentDrivers;
use App\Factory\PaymentFactory;
use App\Http\Requests\ClientPortal\Payments\PaymentResponseRequest;
use App\Models\Client;
use App\Models\ClientContact;
use App\Models\CompanyGateway;
use App\Models\GatewayType;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\PaymentHash;
use App\Utils\Traits\MakesHash;
use App\Utils\Traits\SystemLogTrait;
use Illuminate\Support\Carbon;
use Omnipay\Omnipay;
/**
* Class BasePaymentDriver.
'amount' => $invoice->getRequestedAmount(),
'currency' => $invoice->getCurrencyCode(),
'returnUrl' => $completeUrl,
'cancelUrl' => $this->invitation->getLink(),
'description' => trans('texts.' . $invoice->getEntityType()) . " {$invoice->number}",
'transactionId' => $invoice->number,
'transactionType' => 'Purchase',
'clientIp' => Request::getClientIp(),
];
*/
class BasePaymentDriver
{
use SystemLogTrait;
use MakesHash;
/* The company gateway instance*/
public $company_gateway;
/* The Omnipay payment driver instance*/
protected $gateway;
/* The Invitation */
protected $invitation;
/* Gateway capabilities */
protected $refundable = false;
/* Token billing */
protected $token_billing = false;
/* Authorise payment methods */
protected $can_authorise_credit_card = false;
public function __construct(CompanyGateway $company_gateway, Client $client, $invitation = false)
{
$this->company_gateway = $company_gateway;
$this->invitation = $invitation;
$this->client = $client;
}
/**
* Returns the Omnipay driver.
* @return object Omnipay initialized object
*/
protected function gateway()
{
$this->gateway = Omnipay::create($this->company_gateway->gateway->provider);
$this->gateway->initialize((array) $this->company_gateway->getConfig());
return $this;
}
/**
* Return the configuration fields for the
* Gatway.
* @return array The configuration fields
*/
public function getFields()
{
return $this->gateway->getDefaultParameters();
}
/**
* Returns the default gateway type.
*/
public function gatewayTypes()
{
return [
GatewayType::CREDIT_CARD,
];
}
public function getCompanyGatewayId(): int
{
return $this->company_gateway->id;
}
/**
* Returns whether refunds are possible with the gateway.
* @return bool TRUE|FALSE
*/
public function getRefundable(): bool
{
return $this->refundable;
}
/**
* Returns whether token billing is possible with the gateway.
* @return bool TRUE|FALSE
*/
public function getTokenBilling(): bool
{
return $this->token_billing;
}
/**
* Returns whether gateway can
* authorise and credit card.
* @return [type] [description]
*/
public function canAuthoriseCreditCard(): bool
{
return $this->can_authorise_credit_card;
}
/**
* Refunds a given payment.
* @return void
*/
public function refundPayment($payment, $amount = 0)
{
if ($amount) {
$amount = min($amount, $payment->getCompletedAmount());
} else {
$amount = $payment->getCompletedAmount();
}
if ($payment->is_deleted || ! $amount) {
return false;
}
if ($payment->type_id == Payment::TYPE_CREDIT_CARD) {
return $payment->recordRefund($amount);
}
$details = $this->refundDetails($payment, $amount);
$response = $this->gateway()->refund($details)->send();
if ($response->isSuccessful()) {
return $payment->recordRefund($amount);
} elseif ($this->attemptVoidPayment($response, $payment, $amount)) {
$details = ['transactionReference' => $payment->transaction_reference];
$response = $this->gateway->void($details)->send();
if ($response->isSuccessful()) {
return $payment->markVoided();
}
}
return false;
}
protected function attemptVoidPayment($response, $payment, $amount)
{
// Partial refund not allowed for unsettled transactions
return $amount == $payment->amount;
}
public function authorizeCreditCardView(array $data)
{
}
public function authorizeCreditCardResponse($request)
{
}
public function processPaymentView(array $data)
{
}
public function processPaymentResponse($request)
{
}
/**
* Return the contact if possible.
*
* @return ClientContact The ClientContact object
*/
public function getContact()
{
if ($this->invitation) {
return ClientContact::find($this->invitation->client_contact_id);
} elseif (auth()->guard('contact')->user()) {
return auth()->user();
} else {
return false;
}
}
/************************************* Omnipay ******************************************
authorize($options) - authorize an amount on the customer's card
completeAuthorize($options) - handle return from off-site gateways after authorization
capture($options) - capture an amount you have previously authorized
purchase($options) - authorize and immediately capture an amount on the customer's card
completePurchase($options) - handle return from off-site gateways after purchase
refund($options) - refund an already processed transaction
void($options) - generally can only be called up to 24 hours after submitting a transaction
acceptNotification() - convert an incoming request from an off-site gateway to a generic notification object for further processing
*/
protected function paymentDetails($input): array
{
$data = [
'currency' => $this->client->getCurrencyCode(),
'transactionType' => 'Purchase',
'clientIp' => request()->getClientIp(),
];
return $data;
}
public function purchase($data, $items)
{
$this->gateway();
$response = $this->gateway
->purchase($data)
->setItems($items)
->send();
return $response;
}
public function completePurchase($data)
{
$this->gateway();
return $this->gateway
->completePurchase($data)
->send();
}
public function createPayment($data, $status = Payment::STATUS_COMPLETED): Payment
{
$payment = PaymentFactory::create($this->client->company->id, $this->client->user->id);
$payment->client_id = $this->client->id;
$payment->company_gateway_id = $this->company_gateway->id;
$payment->status_id = $status;
$payment->currency_id = $this->client->getSetting('currency_id');
$payment->date = Carbon::now();
return $payment->service()->applyNumber()->save();
}
public function attachInvoices(Payment $payment, PaymentHash $payment_hash): Payment
{
$paid_invoices = $payment_hash->invoices();
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($paid_invoices, 'invoice_id')))->get();
$payment->invoices()->sync($invoices);
$payment->save();
return $payment;
}
/**
* When a successful payment is made, we need to append the gateway fee
* to an invoice.
*
* @param PaymentResponseRequest $request The incoming payment request
* @return void Success/Failure
*/
public function confirmGatewayFee(PaymentResponseRequest $request) :void
{
/*Payment meta data*/
$payment_hash = $request->getPaymentHash();
/*Payment invoices*/
$payment_invoices = $payment_hash->invoices();
// /*Fee charged at gateway*/
$fee_total = $payment_hash->fee_total;
// Sum of invoice amounts
// $invoice_totals = array_sum(array_column($payment_invoices,'amount'));
/*Hydrate invoices*/
$invoices = Invoice::whereIn('id', $this->transformKeys(array_column($payment_invoices, 'invoice_id')))->get();
$invoices->each(function ($invoice) use ($fee_total) {
if (collect($invoice->line_items)->contains('type_id', '3')) {
$invoice->service()->toggleFeesPaid()->save();
$invoice->client->service()->updateBalance($fee_total)->save();
$invoice->ledger()->updateInvoiceBalance($fee_total, $notes = 'Gateway fee adjustment');
}
});
}
}