mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-10-31 06:27:34 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			314 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /**
 | |
|  * Invoice Ninja (https://invoiceninja.com).
 | |
|  *
 | |
|  * @link https://github.com/invoiceninja/invoiceninja source repository
 | |
|  *
 | |
|  * @copyright Copyright (c) 2021. 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 stdClass 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 bool [type] [description]
 | |
|      */
 | |
|     public function canAuthoriseCreditCard(): bool
 | |
|     {
 | |
|         return $this->can_authorise_credit_card;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Refunds a given payment.
 | |
|      * @param $payment
 | |
|      * @param int $amount
 | |
|      * @return false
 | |
|      */
 | |
|     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
 | |
|      * @param $input
 | |
|      * @return array
 | |
|      */
 | |
| 
 | |
|     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, "Gateway fee adjustment for Invoice {$invoice->number}");
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| }
 |