2019-09-05 09:00:12 +02:00
< ? php
2020-06-24 16:07:12 +02:00
2019-09-05 09:00:12 +02:00
/**
2020-09-06 11:38:10 +02:00
* Invoice Ninja ( https :// invoiceninja . com ) .
2019-09-05 09:00:12 +02:00
*
* @ link https :// github . com / invoiceninja / invoiceninja source repository
*
2020-01-07 01:13:47 +01:00
* @ copyright Copyright ( c ) 2020. Invoice Ninja LLC ( https :// invoiceninja . com )
2019-09-05 09:00:12 +02:00
*
* @ license https :// opensource . org / licenses / AAL
*/
namespace App\PaymentDrivers ;
2019-10-01 11:59:32 +02:00
use App\Events\Payment\PaymentWasCreated ;
2019-09-25 07:55:52 +02:00
use App\Factory\PaymentFactory ;
2020-06-27 17:39:28 +02:00
use App\Http\Requests\Payments\PaymentWebhookRequest ;
2020-05-26 12:22:50 +02:00
use App\Jobs\Mail\PaymentFailureMailer ;
2019-10-29 03:55:26 +01:00
use App\Jobs\Util\SystemLogger ;
2019-09-17 07:42:10 +02:00
use App\Models\ClientGatewayToken ;
2020-06-27 17:39:28 +02:00
use App\Models\Company ;
use App\Models\CompanyGateway ;
2019-09-08 14:13:55 +02:00
use App\Models\GatewayType ;
2019-09-25 07:55:52 +02:00
use App\Models\Invoice ;
use App\Models\Payment ;
2020-09-04 00:01:17 +02:00
use App\Models\PaymentHash ;
2019-09-25 07:55:52 +02:00
use App\Models\PaymentType ;
2019-10-29 03:55:26 +01:00
use App\Models\SystemLog ;
2020-06-23 16:47:29 +02:00
use App\PaymentDrivers\Stripe\ACH ;
use App\PaymentDrivers\Stripe\Alipay ;
2020-07-14 14:50:16 +02:00
use App\PaymentDrivers\Stripe\Charge ;
2020-06-23 16:47:29 +02:00
use App\PaymentDrivers\Stripe\CreditCard ;
use App\PaymentDrivers\Stripe\SOFORT ;
2020-06-01 14:17:29 +02:00
use App\PaymentDrivers\Stripe\Utilities ;
2019-09-25 07:55:52 +02:00
use App\Utils\Traits\MakesHash ;
2020-10-28 11:10:49 +01:00
use Exception ;
use Illuminate\Contracts\View\Factory ;
2019-09-25 07:55:52 +02:00
use Illuminate\Http\Request ;
use Illuminate\Support\Carbon ;
2020-10-28 11:10:49 +01:00
use Illuminate\View\View ;
use Stripe\Customer ;
2019-09-13 00:33:48 +02:00
use Stripe\PaymentIntent ;
2019-09-14 14:34:05 +02:00
use Stripe\SetupIntent ;
2019-09-05 14:42:26 +02:00
use Stripe\Stripe ;
2020-10-28 11:10:49 +01:00
use Stripe\StripeClient ;
2019-09-05 14:42:26 +02:00
2020-10-10 05:32:10 +02:00
class StripePaymentDriver extends BaseDriver
2019-09-05 09:00:12 +02:00
{
2020-06-01 14:17:29 +02:00
use MakesHash , Utilities ;
2019-09-25 07:55:52 +02:00
2020-07-15 07:05:02 +02:00
public $refundable = true ;
2019-09-05 09:00:12 +02:00
2020-07-15 07:05:02 +02:00
public $token_billing = true ;
2019-09-06 07:22:05 +02:00
2020-07-15 07:05:02 +02:00
public $can_authorise_credit_card = true ;
2019-09-15 13:40:46 +02:00
2020-10-28 11:10:49 +01:00
/** @var StripeClient */
2020-09-18 14:35:53 +02:00
protected $stripe ;
2019-12-30 22:59:12 +01:00
protected $customer_reference = 'customerReferenceParam' ;
2019-09-06 07:22:05 +02:00
2020-10-10 05:32:10 +02:00
public $payment_method ;
2020-06-01 14:03:18 +02:00
2020-09-18 14:35:53 +02:00
2020-06-23 16:47:29 +02:00
public static $methods = [
GatewayType :: CREDIT_CARD => CreditCard :: class ,
GatewayType :: BANK_TRANSFER => ACH :: class ,
GatewayType :: ALIPAY => Alipay :: class ,
GatewayType :: SOFORT => SOFORT :: class ,
GatewayType :: APPLE_PAY => 1 ,
GatewayType :: SEPA => 1 ,
];
2019-12-30 22:59:12 +01:00
/**
* Methods in this class are divided into
2020-09-06 11:38:10 +02:00
* two separate streams .
2019-12-30 22:59:12 +01:00
*
* 1. Omnipay Specific
* 2. Stripe Specific
*
* Our Stripe integration is deeper than
* other gateways and therefore
* relies on direct calls to the API
*/
/************************************** Stripe API methods **********************************************************/
2019-09-05 14:42:26 +02:00
2019-09-17 12:27:48 +02:00
/**
2020-09-06 11:38:10 +02:00
* Initializes the Stripe API .
2019-09-17 12:27:48 +02:00
* @ return void
*/
2020-06-24 16:07:12 +02:00
public function init () : void
2019-12-30 22:59:12 +01:00
{
2020-10-28 11:10:49 +01:00
$this -> stripe = new StripeClient (
2020-09-18 14:35:53 +02:00
$this -> company_gateway -> getConfigField ( 'apiKey' )
);
2020-03-22 21:45:16 +01:00
Stripe :: setApiKey ( $this -> company_gateway -> getConfigField ( 'apiKey' ));
2019-12-30 22:59:12 +01:00
}
2019-09-17 12:27:48 +02:00
2020-06-23 16:47:29 +02:00
public function setPaymentMethod ( $payment_method_id )
2020-06-01 14:03:18 +02:00
{
2020-06-23 16:47:29 +02:00
$class = self :: $methods [ $payment_method_id ];
2020-06-24 16:07:12 +02:00
2020-06-23 16:47:29 +02:00
$this -> payment_method = new $class ( $this );
2020-06-01 14:03:18 +02:00
return $this ;
}
2019-12-30 22:59:12 +01:00
/**
2020-09-06 11:38:10 +02:00
* Returns the gateway types .
2019-12-30 22:59:12 +01:00
*/
2020-06-24 16:07:12 +02:00
public function gatewayTypes () : array
2019-09-08 14:13:55 +02:00
{
$types = [
GatewayType :: CREDIT_CARD ,
];
2020-03-23 18:10:42 +01:00
2019-12-30 22:59:12 +01:00
if ( $this -> company_gateway -> getSofortEnabled () && $this -> invitation && $this -> client () && isset ( $this -> client () -> country ) && in_array ( $this -> client () -> country , [ 'AUT' , 'BEL' , 'DEU' , 'ITA' , 'NLD' , 'ESP' ])) {
2019-09-08 14:13:55 +02:00
$types [] = GatewayType :: SOFORT ;
2019-12-30 22:59:12 +01:00
}
2019-09-08 14:13:55 +02:00
2019-12-30 22:59:12 +01:00
if ( $this -> company_gateway -> getAchEnabled ()) {
$types [] = GatewayType :: BANK_TRANSFER ;
}
2019-09-08 14:13:55 +02:00
2019-12-30 22:59:12 +01:00
if ( $this -> company_gateway -> getSepaEnabled ()) {
2019-09-08 14:13:55 +02:00
$types [] = GatewayType :: SEPA ;
2019-12-30 22:59:12 +01:00
}
2020-03-23 18:10:42 +01:00
2019-12-30 22:59:12 +01:00
if ( $this -> company_gateway -> getBitcoinEnabled ()) {
2019-11-27 10:47:59 +01:00
$types [] = GatewayType :: CRYPTO ;
2019-12-30 22:59:12 +01:00
}
2020-03-23 18:10:42 +01:00
2019-12-30 22:59:12 +01:00
if ( $this -> company_gateway -> getAlipayEnabled ()) {
2019-09-08 14:13:55 +02:00
$types [] = GatewayType :: ALIPAY ;
2019-12-30 22:59:12 +01:00
}
2020-03-23 18:10:42 +01:00
2019-12-30 22:59:12 +01:00
if ( $this -> company_gateway -> getApplePayEnabled ()) {
2019-09-08 14:13:55 +02:00
$types [] = GatewayType :: APPLE_PAY ;
2019-12-30 22:59:12 +01:00
}
2020-03-23 18:10:42 +01:00
2019-09-08 14:13:55 +02:00
return $types ;
2019-09-12 13:46:09 +02:00
}
2019-09-18 04:39:53 +02:00
public function viewForType ( $gateway_type_id )
2019-09-12 13:46:09 +02:00
{
2019-12-30 22:59:12 +01:00
switch ( $gateway_type_id ) {
case GatewayType :: CREDIT_CARD :
2020-03-23 18:10:42 +01:00
return 'gateways.stripe.credit_card' ;
2019-12-30 22:59:12 +01:00
break ;
case GatewayType :: SOFORT :
2020-03-23 18:10:42 +01:00
return 'gateways.stripe.sofort' ;
2019-12-30 22:59:12 +01:00
break ;
case GatewayType :: BANK_TRANSFER :
2020-03-23 18:10:42 +01:00
return 'gateways.stripe.ach' ;
2019-12-30 22:59:12 +01:00
break ;
case GatewayType :: SEPA :
2020-03-23 18:10:42 +01:00
return 'gateways.stripe.sepa' ;
2019-12-30 22:59:12 +01:00
break ;
case GatewayType :: CRYPTO :
case GatewayType :: ALIPAY :
case GatewayType :: APPLE_PAY :
2020-03-23 18:10:42 +01:00
return 'gateways.stripe.other' ;
2019-12-30 22:59:12 +01:00
break ;
default :
break ;
}
2019-09-08 14:13:55 +02:00
}
2019-09-13 00:33:48 +02:00
2019-09-25 07:55:52 +02:00
/**
2020-06-01 14:03:18 +02:00
* Proxy method to pass the data into payment method authorizeView () .
2020-09-06 11:38:10 +02:00
*
* @ param array $data
*
2020-10-28 11:10:49 +01:00
* @ return Factory | View
2019-09-25 07:55:52 +02:00
*/
2020-06-01 14:03:18 +02:00
public function authorizeView ( array $data )
2019-09-14 14:34:05 +02:00
{
2020-06-01 14:03:18 +02:00
return $this -> payment_method -> authorizeView ( $data );
2019-09-16 13:03:25 +02:00
}
2019-09-25 07:55:52 +02:00
/**
2020-03-23 18:10:42 +01:00
* Processes the gateway response for credit card authorization .
*
2020-10-28 11:10:49 +01:00
* @ param Request $request The returning request object
* @ return Factory | View
2019-09-25 07:55:52 +02:00
*/
2020-06-26 13:25:58 +02:00
public function authorizeResponse ( $request )
2019-09-16 13:03:25 +02:00
{
2020-06-01 14:14:41 +02:00
return $this -> payment_method -> authorizeResponse ( $request );
2019-09-14 14:34:05 +02:00
}
2019-09-25 04:07:33 +02:00
/**
2020-03-23 18:10:42 +01:00
* Process the payment with gateway .
2019-12-30 22:59:12 +01:00
*
2020-03-23 18:10:42 +01:00
* @ param array $data
2020-10-28 11:10:49 +01:00
* @ return Factory | View | void
2019-09-25 04:07:33 +02:00
*/
2019-09-25 06:03:28 +02:00
public function processPaymentView ( array $data )
2019-09-25 04:07:33 +02:00
{
2020-06-01 14:29:41 +02:00
return $this -> payment_method -> paymentView ( $data );
2019-09-25 04:07:33 +02:00
}
2019-09-25 06:03:28 +02:00
/**
2020-09-06 11:38:10 +02:00
* Payment Intent Reponse looks like this .
2020-10-28 11:10:49 +01:00
* + " id " : " pi_1FMR7JKmol8YQE9DuC4zMeN3 "
* + " object " : " payment_intent "
* + " allowed_source_types " : array : 1 [ ▼
* 0 => " card "
* ]
* + " amount " : 2372484
* + " canceled_at " : null
* + " cancellation_reason " : null
* + " capture_method " : " automatic "
* + " client_secret " : " pi_1FMR7JKmol8YQE9DuC4zMeN3_secret_J3yseWJG6uV0MmsrAT1FlUklV "
* + " confirmation_method " : " automatic "
* + " created " : 1569381877
* + " ->currency() " : " usd "
* + " description " : " [3] "
* + " last_payment_error " : null
* + " livemode " : false
* + " next_action " : null
* + " next_source_action " : null
* + " payment_method " : " pm_1FMR7ZKmol8YQE9DQWqPuyke "
* + " payment_method_types " : array : 1 [ ▶ ]
* + " receipt_email " : null
* + " setup_future_usage " : " off_session "
* + " shipping " : null
* + " source " : null
* + " status " : " succeeded "
* @ param $request
* @ return
2020-06-24 16:07:12 +02:00
*/
2019-10-03 14:17:48 +02:00
public function processPaymentResponse ( $request ) //We never have to worry about unsuccessful payments as failures are handled at the front end for this driver.
2019-09-25 06:03:28 +02:00
{
2020-06-01 16:19:03 +02:00
return $this -> payment_method -> paymentResponse ( $request );
2019-10-01 11:59:32 +02:00
}
2020-06-24 16:07:12 +02:00
public function createPayment ( $data , $status = Payment :: STATUS_COMPLETED ) : Payment
2019-10-01 11:59:32 +02:00
{
2020-06-09 13:07:18 +02:00
$payment = parent :: createPayment ( $data , $status );
2019-10-01 11:59:32 +02:00
$client_contact = $this -> getContact ();
$client_contact_id = $client_contact ? $client_contact -> id : null ;
2019-10-10 12:43:50 +02:00
$payment -> amount = $this -> convertFromStripeAmount ( $data [ 'amount' ], $this -> client -> currency () -> precision );
2019-12-16 12:34:38 +01:00
$payment -> type_id = $data [ 'payment_type' ];
2019-10-01 11:59:32 +02:00
$payment -> transaction_reference = $data [ 'payment_method' ];
$payment -> client_contact_id = $client_contact_id ;
2020-06-27 17:39:28 +02:00
$payment -> gateway_type_id = GatewayType :: ALIPAY ;
2019-10-01 11:59:32 +02:00
$payment -> save ();
return $payment ;
2019-09-25 06:03:28 +02:00
}
2019-09-25 04:07:33 +02:00
2019-09-13 00:33:48 +02:00
/**
2020-09-06 11:38:10 +02:00
* Creates a new String Payment Intent .
2019-12-30 22:59:12 +01:00
*
2020-10-28 11:10:49 +01:00
* @ param array $data The data array to be passed to Stripe
2019-09-13 00:33:48 +02:00
* @ return PaymentIntent The Stripe payment intent object
2020-10-28 11:10:49 +01:00
* @ throws \Stripe\Exception\ApiErrorException
2019-09-13 00:33:48 +02:00
*/
2020-09-06 11:38:10 +02:00
public function createPaymentIntent ( $data ) : ? PaymentIntent
2019-09-13 00:33:48 +02:00
{
2019-09-16 06:59:59 +02:00
$this -> init ();
2019-09-17 13:54:14 +02:00
2019-09-13 00:33:48 +02:00
return PaymentIntent :: create ( $data );
}
2019-09-14 14:34:05 +02:00
/**
2019-12-30 22:59:12 +01:00
* Returns a setup intent that allows the user
2019-09-17 13:54:14 +02:00
* to enter card details without initiating a transaction .
2019-09-14 14:34:05 +02:00
*
2020-10-28 11:10:49 +01:00
* @ return SetupIntent
* @ throws \Stripe\Exception\ApiErrorException
2019-09-14 14:34:05 +02:00
*/
2020-09-06 11:38:10 +02:00
public function getSetupIntent () : SetupIntent
2019-09-14 14:34:05 +02:00
{
2019-09-16 06:59:59 +02:00
$this -> init ();
2019-09-17 13:54:14 +02:00
2019-09-14 14:34:05 +02:00
return SetupIntent :: create ();
}
2019-09-17 13:54:14 +02:00
/**
2020-09-06 11:38:10 +02:00
* Returns the Stripe publishable key .
* @ return null | string The stripe publishable key
2019-09-17 13:54:14 +02:00
*/
2020-06-24 16:07:12 +02:00
public function getPublishableKey () : ? string
2019-09-14 14:34:05 +02:00
{
return $this -> company_gateway -> getPublishableKey ();
}
2019-09-16 06:59:59 +02:00
2019-09-17 13:54:14 +02:00
/**
2020-09-06 11:38:10 +02:00
* Finds or creates a Stripe Customer object .
2019-12-30 22:59:12 +01:00
*
2020-10-28 11:10:49 +01:00
* @ return null | Customer A Stripe customer object
* @ throws \Laracasts\Presenter\Exceptions\PresenterException
* @ throws \Stripe\Exception\ApiErrorException
2019-09-17 13:54:14 +02:00
*/
2020-10-28 11:10:49 +01:00
public function findOrCreateCustomer () : ? Customer
2019-12-30 22:59:12 +01:00
{
2019-09-16 06:59:59 +02:00
$customer = null ;
$this -> init ();
2019-09-17 07:59:09 +02:00
$client_gateway_token = ClientGatewayToken :: whereClientId ( $this -> client -> id ) -> whereCompanyGatewayId ( $this -> company_gateway -> id ) -> first ();
2019-09-16 06:59:59 +02:00
2019-12-30 22:59:12 +01:00
if ( $client_gateway_token && $client_gateway_token -> gateway_customer_reference ) {
2020-10-28 11:10:49 +01:00
$customer = Customer :: retrieve ( $client_gateway_token -> gateway_customer_reference );
2019-12-30 22:59:12 +01:00
} else {
2019-09-17 07:59:09 +02:00
$data [ 'name' ] = $this -> client -> present () -> name ();
$data [ 'phone' ] = $this -> client -> present () -> phone ();
2019-12-30 22:59:12 +01:00
if ( filter_var ( $this -> client -> present () -> email (), FILTER_VALIDATE_EMAIL )) {
2019-09-17 07:59:09 +02:00
$data [ 'email' ] = $this -> client -> present () -> email ();
2019-12-30 22:59:12 +01:00
}
2019-09-17 07:59:09 +02:00
2020-10-28 11:10:49 +01:00
$customer = Customer :: create ( $data );
2019-09-16 06:59:59 +02:00
}
2019-09-17 07:42:10 +02:00
2020-09-18 09:48:53 +02:00
if ( ! $customer ) {
2020-10-28 11:10:49 +01:00
throw new Exception ( 'Unable to create gateway customer' );
2019-12-30 22:59:12 +01:00
}
2019-09-25 04:07:33 +02:00
2019-09-16 06:59:59 +02:00
return $customer ;
}
2020-10-10 05:32:10 +02:00
public function refund ( Payment $payment , $amount , $return_client_response = false )
2020-05-14 03:04:23 +02:00
{
2020-09-18 14:35:53 +02:00
$this -> init ();
$response = $this -> stripe
-> refunds
-> create ([ 'charge' => $payment -> transaction_reference , 'amount' => $amount ]);
// $response = $this->gateway
// ->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $amount, 'currency' => $payment->client->getCurrencyCode()])
// ->send();
2020-05-14 03:04:23 +02:00
2020-09-18 14:35:53 +02:00
if ( $response -> status == $response :: STATUS_SUCCEEDED ) {
SystemLogger :: dispatch ([ 'server_response' => $response , 'data' => request () -> all (),
2020-06-24 16:07:12 +02:00
], SystemLog :: CATEGORY_GATEWAY_RESPONSE , SystemLog :: EVENT_GATEWAY_SUCCESS , SystemLog :: TYPE_STRIPE , $this -> client );
return [
2020-09-18 14:35:53 +02:00
'transaction_reference' => $response -> charge ,
'transaction_response' => json_encode ( $response ),
'success' => $response -> status == $response :: STATUS_SUCCEEDED ? true : false ,
'description' => $response -> metadata ,
'code' => $response ,
2020-06-24 16:07:12 +02:00
];
2020-05-14 03:04:23 +02:00
}
2020-09-18 14:35:53 +02:00
SystemLogger :: dispatch ([ 'server_response' => $response , 'data' => request () -> all (),
2020-06-24 16:07:12 +02:00
], SystemLog :: CATEGORY_GATEWAY_RESPONSE , SystemLog :: EVENT_GATEWAY_FAILURE , SystemLog :: TYPE_STRIPE , $this -> client );
return [
'transaction_reference' => null ,
2020-09-18 14:35:53 +02:00
'transaction_response' => json_encode ( $response ),
2020-06-24 16:07:12 +02:00
'success' => false ,
2020-09-18 14:35:53 +02:00
'description' => $response -> failure_reason ,
'code' => 422 ,
2020-06-24 16:07:12 +02:00
];
2020-05-14 03:04:23 +02:00
}
2019-09-16 06:59:59 +02:00
2020-06-09 14:42:23 +02:00
public function verificationView ( ClientGatewayToken $payment_method )
{
return $this -> payment_method -> verificationView ( $payment_method );
}
public function processVerification ( ClientGatewayToken $payment_method )
{
return $this -> payment_method -> processVerification ( $payment_method );
}
2020-06-27 17:39:28 +02:00
public function processWebhookRequest ( PaymentWebhookRequest $request , Company $company , CompanyGateway $company_gateway , Payment $payment )
{
if ( $request -> type == 'source.chargable' ) {
$payment -> status_id = Payment :: STATUS_COMPLETED ;
$payment -> save ();
}
return response ([], 200 );
}
2020-09-06 11:38:10 +02:00
public function tokenBilling ( ClientGatewayToken $cgt , PaymentHash $payment_hash )
2020-07-14 14:50:16 +02:00
{
2020-09-04 00:01:17 +02:00
return ( new Charge ( $this )) -> tokenBilling ( $cgt , $payment_hash );
2020-07-14 14:50:16 +02:00
}
2020-07-08 04:20:44 +02:00
2020-07-15 07:05:02 +02:00
/**
* Creates a payment record for the given
* data array .
2020-09-06 11:38:10 +02:00
*
2020-07-15 07:05:02 +02:00
* @ param array $data An array of payment attributes
* @ param float $amount The amount of the payment
* @ return Payment The payment object
*/
2020-09-18 09:48:53 +02:00
public function createPaymentRecord ( $data , $amount ) : ? Payment
2020-07-15 07:05:02 +02:00
{
$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 = Payment :: STATUS_COMPLETED ;
$payment -> gateway_type_id = $data [ 'gateway_type_id' ];
$payment -> type_id = $data [ 'type_id' ];
$payment -> currency_id = $this -> client -> getSetting ( 'currency_id' );
$payment -> date = Carbon :: now ();
$payment -> transaction_reference = $data [ 'transaction_reference' ];
2020-09-06 11:38:10 +02:00
$payment -> amount = $amount ;
2020-07-15 07:05:02 +02:00
$payment -> save ();
2020-08-19 03:06:19 +02:00
return $payment -> service () -> applyNumber () -> save ();
2020-07-15 07:05:02 +02:00
}
2020-09-18 09:48:53 +02:00
/**
* Detach payment method from the Stripe .
* https :// stripe . com / docs / api / payment_methods / detach
2020-10-28 11:10:49 +01:00
*
* @ param ClientGatewayToken $token
* @ return void
*/
2020-09-18 09:48:53 +02:00
public function detach ( ClientGatewayToken $token )
{
2020-10-28 11:10:49 +01:00
$stripe = new StripeClient (
2020-09-18 09:48:53 +02:00
$this -> company_gateway -> getConfigField ( 'apiKey' )
);
try {
$response = $stripe -> paymentMethods -> detach ( $token -> token );
2020-10-28 11:10:49 +01:00
} catch ( Exception $e ) {
2020-09-18 09:48:53 +02:00
SystemLogger :: dispatch ([
'server_response' => $response , 'data' => request () -> all (),
], SystemLog :: CATEGORY_GATEWAY_RESPONSE , SystemLog :: EVENT_GATEWAY_FAILURE , SystemLog :: TYPE_STRIPE , $this -> client );
}
}
2020-10-10 05:32:10 +02:00
2020-10-28 11:10:49 +01:00
2020-10-10 05:32:10 +02:00
public function getCompanyGatewayId () : int
{
return $this -> company_gateway -> id ;
}
2019-12-30 22:59:12 +01:00
}