2021-07-20 13:26:24 +02:00
< ? php
/**
* Invoice Ninja ( https :// invoiceninja . com ) .
*
* @ link https :// github . com / invoiceninja / invoiceninja source repository
*
2024-04-12 06:15:41 +02:00
* @ copyright Copyright ( c ) 2024. Invoice Ninja LLC ( https :// invoiceninja . com )
2021-07-20 13:26:24 +02:00
*
* @ license https :// www . elastic . co / licensing / elastic - license
*/
namespace App\PaymentDrivers ;
2023-05-24 01:37:29 +02:00
use App\Models\Invoice ;
2021-07-20 13:26:24 +02:00
use App\Models\Payment ;
2024-03-19 00:38:54 +01:00
use App\Utils\CurlUtils ;
use App\Models\SystemLog ;
use App\Models\GatewayType ;
2021-07-20 13:26:24 +02:00
use App\Models\PaymentHash ;
2021-07-21 10:18:14 +02:00
use App\Models\PaymentType ;
2024-03-19 00:38:54 +01:00
use App\Factory\ClientFactory ;
use App\Exceptions\SystemError ;
use App\Jobs\Util\SystemLogger ;
2023-10-26 04:57:44 +02:00
use App\Utils\Traits\MakesHash ;
2024-03-19 00:38:54 +01:00
use App\Models\ClientGatewayToken ;
use App\Repositories\ClientRepository ;
use App\PaymentDrivers\PayTrace\CreditCard ;
use App\Repositories\ClientContactRepository ;
use App\Http\Requests\Payments\PaymentWebhookRequest ;
use App\Models\ClientContact ;
use App\PaymentDrivers\Factory\PaytraceCustomerFactory ;
2021-07-20 13:26:24 +02:00
class PaytracePaymentDriver extends BaseDriver
{
use MakesHash ;
2022-06-21 11:57:17 +02:00
public $refundable = true ;
2021-07-20 13:26:24 +02:00
2022-06-21 11:57:17 +02:00
public $token_billing = true ;
2021-07-20 13:26:24 +02:00
2022-06-21 11:57:17 +02:00
public $can_authorise_credit_card = true ;
2021-07-20 13:26:24 +02:00
2022-06-21 11:57:17 +02:00
public $gateway ;
public $payment_method ;
2021-07-20 13:26:24 +02:00
public static $methods = [
GatewayType :: CREDIT_CARD => CreditCard :: class , //maps GatewayType => Implementation class
];
2024-01-14 05:05:00 +01:00
public const SYSTEM_LOG_TYPE = SystemLog :: TYPE_PAYTRACE ; //define a constant for your gateway ie TYPE_YOUR_CUSTOM_GATEWAY - set the const in the SystemLog model
2021-07-20 13:26:24 +02:00
public function init ()
{
return $this ; /* This is where you boot the gateway with your auth credentials*/
}
/* Returns an array of gateway types for the payment gateway */
public function gatewayTypes () : array
{
$types = [];
2022-06-21 11:57:17 +02:00
$types [] = GatewayType :: CREDIT_CARD ;
2021-07-20 13:26:24 +02:00
return $types ;
}
/* Sets the payment method initialized */
public function setPaymentMethod ( $payment_method_id )
{
$class = self :: $methods [ $payment_method_id ];
$this -> payment_method = new $class ( $this );
2022-06-21 11:57:17 +02:00
2021-07-20 13:26:24 +02:00
return $this ;
}
public function authorizeView ( array $data )
{
return $this -> payment_method -> authorizeView ( $data ); //this is your custom implementation from here
}
public function authorizeResponse ( $request )
{
return $this -> payment_method -> authorizeResponse ( $request ); //this is your custom implementation from here
}
public function processPaymentView ( array $data )
{
return $this -> payment_method -> paymentView ( $data ); //this is your custom implementation from here
}
public function processPaymentResponse ( $request )
{
return $this -> payment_method -> paymentResponse ( $request ); //this is your custom implementation from here
}
public function refund ( Payment $payment , $amount , $return_client_response = false )
{
2021-07-21 10:18:14 +02:00
$data = [
'amount' => $amount ,
2021-07-23 04:12:42 +02:00
'transaction_id' => $payment -> transaction_reference ,
2022-08-08 23:39:38 +02:00
'integrator_id' => $this -> company_gateway -> getConfigField ( 'integratorId' ),
2021-07-21 10:18:14 +02:00
];
2021-07-23 04:12:42 +02:00
$response = $this -> gatewayRequest ( '/v1/transactions/refund/for_transaction' , $data );
2021-07-21 10:18:14 +02:00
2022-06-21 11:57:17 +02:00
if ( $response && $response -> success ) {
2021-07-21 10:18:14 +02:00
SystemLogger :: dispatch ([ 'server_response' => $response , 'data' => $data ], SystemLog :: CATEGORY_GATEWAY_RESPONSE , SystemLog :: EVENT_GATEWAY_SUCCESS , SystemLog :: TYPE_PAYTRACE , $this -> client , $this -> client -> company );
2022-06-21 11:57:17 +02:00
return [
'transaction_reference' => $response -> transaction_id ,
'transaction_response' => json_encode ( $response ),
'success' => true ,
'description' => $response -> status_message ,
'code' => $response -> response_code ,
];
2021-07-21 10:18:14 +02:00
}
SystemLogger :: dispatch ([ 'server_response' => $response , 'data' => $data ], SystemLog :: CATEGORY_GATEWAY_RESPONSE , SystemLog :: EVENT_GATEWAY_FAILURE , SystemLog :: TYPE_PAYTRACE , $this -> client , $this -> client -> company );
return [
'transaction_reference' => null ,
'transaction_response' => json_encode ( $response ),
'success' => false ,
'description' => $response -> status_message ,
'code' => 422 ,
];
2021-07-20 13:26:24 +02:00
}
public function tokenBilling ( ClientGatewayToken $cgt , PaymentHash $payment_hash )
{
2021-07-21 10:18:14 +02:00
$amount = array_sum ( array_column ( $payment_hash -> invoices (), 'amount' )) + $payment_hash -> fee_total ;
2023-05-24 01:37:29 +02:00
$_invoice = collect ( $payment_hash -> data -> invoices ) -> first ();
$invoice = Invoice :: withTrashed () -> find ( $this -> decodePrimaryKey ( $_invoice -> invoice_id ));
if ( $invoice ) {
$invoice_id = ctrans ( 'texts.invoice_number' ) . '# ' . $invoice -> number ;
}
$invoice_id = ctrans ( 'texts.invoice_number' ) . '# ' . substr ( $payment_hash -> hash , 0 , 6 );
2021-07-21 10:18:14 +02:00
$data = [
'customer_id' => $cgt -> token ,
2021-07-23 06:15:51 +02:00
'integrator_id' => $this -> company_gateway -> getConfigField ( 'integratorId' ),
2021-07-21 10:18:14 +02:00
'amount' => $amount ,
2023-05-24 01:37:29 +02:00
'invoice_id' => $invoice_id ,
2021-07-21 10:18:14 +02:00
];
$response = $this -> gatewayRequest ( '/v1/transactions/sale/by_customer' , $data );
2022-06-21 11:57:17 +02:00
if ( $response && $response -> success ) {
2021-07-21 10:18:14 +02:00
$data = [
'gateway_type_id' => $cgt -> gateway_type_id ,
'payment_type' => PaymentType :: CREDIT_CARD_OTHER ,
'transaction_reference' => $response -> transaction_id ,
'amount' => $amount ,
];
$payment = $this -> createPayment ( $data );
$payment -> meta = $cgt -> meta ;
$payment -> save ();
$payment_hash -> payment_id = $payment -> id ;
$payment_hash -> save ();
return $payment ;
}
$error = $response -> status_message ;
2022-06-21 11:57:17 +02:00
if ( property_exists ( $response , 'approval_message' ) && $response -> approval_message ) {
2021-07-21 10:18:14 +02:00
$error .= " - { $response -> approval_message } " ;
2022-06-21 11:57:17 +02:00
}
2021-07-21 10:18:14 +02:00
$data = [
'response' => $response ,
'error' => $error ,
'error_code' => 500 ,
];
$this -> processUnsuccessfulTransaction ( $data , false );
2021-07-20 13:26:24 +02:00
}
public function processWebhookRequest ( PaymentWebhookRequest $request , Payment $payment = null )
{
}
/*Helpers*/
2021-07-21 06:23:33 +02:00
private function generateAuthHeaders ()
2021-07-20 13:26:24 +02:00
{
2023-05-24 00:08:01 +02:00
$api_endpoint = $this -> company_gateway -> getConfigField ( 'testMode' ) ? 'https://api.sandbox.paytrace.com' : 'https://api.paytrace.com' ;
$url = " { $api_endpoint } /oauth/token " ;
2024-01-14 05:05:00 +01:00
2021-07-20 13:26:24 +02:00
$data = [
'grant_type' => 'password' ,
2021-07-23 06:15:51 +02:00
'username' => $this -> company_gateway -> getConfigField ( 'username' ),
2022-06-21 11:57:17 +02:00
'password' => $this -> company_gateway -> getConfigField ( 'password' ),
2021-07-20 13:26:24 +02:00
];
$response = CurlUtils :: post ( $url , $data , $headers = false );
2021-07-21 06:23:33 +02:00
$auth_data = json_decode ( $response );
2021-07-20 13:26:24 +02:00
2023-10-15 08:21:56 +02:00
if ( ! isset ( $auth_data ) || ! property_exists ( $auth_data , 'access_token' )) {
2021-10-23 02:45:22 +02:00
throw new SystemError ( 'Error authenticating with PayTrace' );
2022-06-21 11:57:17 +02:00
}
2021-10-23 01:06:30 +02:00
2022-06-21 11:57:17 +02:00
$headers = [];
$headers [] = 'Content-type: application/json' ;
$headers [] = 'Authorization: Bearer ' . $auth_data -> access_token ;
2021-07-21 02:43:39 +02:00
2021-07-21 06:23:33 +02:00
return $headers ;
}
public function getAuthToken ()
{
2023-05-24 00:08:01 +02:00
$api_endpoint = $this -> company_gateway -> getConfigField ( 'testMode' ) ? 'https://api.sandbox.paytrace.com' : 'https://api.paytrace.com' ;
2021-07-21 07:34:20 +02:00
$headers = $this -> generateAuthHeaders ();
2021-07-21 06:23:33 +02:00
2023-05-24 00:08:01 +02:00
$response = CurlUtils :: post ( " { $api_endpoint } /v1/payment_fields/token/create " , [], $headers );
2021-07-21 02:43:39 +02:00
2021-07-21 07:34:20 +02:00
$response = json_decode ( $response );
2021-07-21 02:43:39 +02:00
2022-06-21 11:57:17 +02:00
if ( $response ) {
2021-07-21 07:34:20 +02:00
return $response -> clientKey ;
2022-06-21 11:57:17 +02:00
}
2021-07-21 02:43:39 +02:00
2021-07-21 06:23:33 +02:00
return false ;
}
public function gatewayRequest ( $uri , $data , $headers = false )
{
2024-01-14 05:05:00 +01:00
2023-05-24 00:08:01 +02:00
$api_endpoint = $this -> company_gateway -> getConfigField ( 'testMode' ) ? 'https://api.sandbox.paytrace.com' : 'https://api.paytrace.com' ;
$base_url = " { $api_endpoint } { $uri } " ;
2021-07-21 06:23:33 +02:00
$headers = $this -> generateAuthHeaders ();
$response = CurlUtils :: post ( $base_url , json_encode ( $data ), $headers );
$response = json_decode ( $response );
2022-06-21 11:57:17 +02:00
if ( $response ) {
2021-07-21 06:23:33 +02:00
return $response ;
2022-06-21 11:57:17 +02:00
}
2021-07-20 13:26:24 +02:00
return false ;
}
2024-03-16 02:36:40 +01:00
2024-03-20 22:01:13 +01:00
public function getClientRequiredFields () : array
{
2024-08-30 06:16:35 +02:00
$fields = [];
if ( $this -> company_gateway -> require_client_name ) {
$fields [] = [ 'name' => 'client_name' , 'label' => ctrans ( 'texts.client_name' ), 'type' => 'text' , 'validation' => 'required' ];
}
$fields [] = [ 'name' => 'contact_first_name' , 'label' => ctrans ( 'texts.first_name' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'contact_last_name' , 'label' => ctrans ( 'texts.last_name' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'contact_email' , 'label' => ctrans ( 'texts.email' ), 'type' => 'text' , 'validation' => 'required,email:rfc' ];
if ( $this -> company_gateway -> require_client_phone ) {
$fields [] = [ 'name' => 'client_phone' , 'label' => ctrans ( 'texts.client_phone' ), 'type' => 'tel' , 'validation' => 'required' ];
}
2024-03-20 22:01:13 +01:00
$fields [] = [ 'name' => 'client_address_line_1' , 'label' => ctrans ( 'texts.address1' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'client_city' , 'label' => ctrans ( 'texts.city' ), 'type' => 'text' , 'validation' => 'required' ];
2024-03-20 23:40:19 +01:00
$fields [] = [ 'name' => 'client_postal_code' , 'label' => ctrans ( 'texts.postal_code' ), 'type' => 'text' , 'validation' => 'required' ];
2024-03-20 22:01:13 +01:00
$fields [] = [ 'name' => 'client_state' , 'label' => ctrans ( 'texts.state' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'client_country_id' , 'label' => ctrans ( 'texts.country' ), 'type' => 'text' , 'validation' => 'required' ];
2024-08-30 06:16:35 +02:00
if ( $this -> company_gateway -> require_shipping_address ) {
$fields [] = [ 'name' => 'client_shipping_address_line_1' , 'label' => ctrans ( 'texts.shipping_address1' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'client_shipping_city' , 'label' => ctrans ( 'texts.shipping_city' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'client_shipping_state' , 'label' => ctrans ( 'texts.shipping_state' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'client_shipping_postal_code' , 'label' => ctrans ( 'texts.shipping_postal_code' ), 'type' => 'text' , 'validation' => 'required' ];
$fields [] = [ 'name' => 'client_shipping_country_id' , 'label' => ctrans ( 'texts.shipping_country' ), 'type' => 'text' , 'validation' => 'required' ];
}
if ( $this -> company_gateway -> require_custom_value1 ) {
$fields [] = [ 'name' => 'client_custom_value1' , 'label' => $this -> helpers -> makeCustomField ( $this -> client -> company -> custom_fields , 'client1' ), 'type' => 'text' , 'validation' => 'required' ];
}
if ( $this -> company_gateway -> require_custom_value2 ) {
$fields [] = [ 'name' => 'client_custom_value2' , 'label' => $this -> helpers -> makeCustomField ( $this -> client -> company -> custom_fields , 'client2' ), 'type' => 'text' , 'validation' => 'required' ];
}
if ( $this -> company_gateway -> require_custom_value3 ) {
$fields [] = [ 'name' => 'client_custom_value3' , 'label' => $this -> helpers -> makeCustomField ( $this -> client -> company -> custom_fields , 'client3' ), 'type' => 'text' , 'validation' => 'required' ];
}
if ( $this -> company_gateway -> require_custom_value4 ) {
$fields [] = [ 'name' => 'client_custom_value4' , 'label' => $this -> helpers -> makeCustomField ( $this -> client -> company -> custom_fields , 'client4' ), 'type' => 'text' , 'validation' => 'required' ];
}
2024-03-20 22:01:13 +01:00
return $fields ;
}
2024-03-16 02:36:40 +01:00
public function auth () : bool
{
try {
$this -> init () -> generateAuthHeaders () && strlen ( $this -> company_gateway -> getConfigField ( 'integratorId' )) > 2 ;
return true ;
2024-06-14 09:09:44 +02:00
} catch ( \Exception $e ) {
2024-03-16 02:36:40 +01:00
}
return false ;
}
2024-03-19 00:38:54 +01:00
public function importCustomers ()
{
$data = [
'integrator_id' => $this -> company_gateway -> getConfigField ( 'integratorId' ),
];
$response = $this -> gatewayRequest ( '/v1/customer/export' , $data );
nlog ( $response );
if ( $response && $response -> success ) {
2024-06-14 09:09:44 +02:00
2024-03-19 00:38:54 +01:00
$client_repo = new ClientRepository ( new ClientContactRepository ());
$factory = new PaytraceCustomerFactory ();
2024-06-14 09:09:44 +02:00
foreach ( $response -> customers as $customer ) {
2024-03-19 00:38:54 +01:00
$data = $factory -> convertToNinja ( $customer , $this -> company_gateway -> company );
2024-06-14 09:09:44 +02:00
2024-03-19 00:38:54 +01:00
$client = false ;
2024-06-14 09:09:44 +02:00
if ( str_contains ( $data [ 'contacts' ][ 0 ][ 'email' ], " @ " )) {
2024-03-19 00:38:54 +01:00
$client = ClientContact :: query ()
-> where ( 'company_id' , $this -> company_gateway -> company_id )
-> where ( 'email' , $data [ 'contacts' ][ 0 ][ 'email' ])
-> first () -> client ? ? false ;
}
2024-06-14 09:09:44 +02:00
if ( ! $client ) {
2024-03-19 00:38:54 +01:00
$client = $client_repo -> save ( $data , ClientFactory :: create ( $this -> company_gateway -> company_id , $this -> company_gateway -> user_id ));
2024-06-14 09:09:44 +02:00
}
2024-03-19 00:38:54 +01:00
$this -> client = $client ;
2024-06-14 09:09:44 +02:00
if ( ClientGatewayToken :: query () -> where ( 'client_id' , $client -> id ) -> where ( 'token' , $data [ 'card' ][ 'token' ]) -> exists ()) {
2024-03-19 00:38:54 +01:00
continue ;
2024-06-14 09:09:44 +02:00
}
2024-03-19 00:38:54 +01:00
$cgt = [];
$cgt [ 'token' ] = $data [ 'card' ][ 'token' ];
$cgt [ 'payment_method_id' ] = GatewayType :: CREDIT_CARD ;
$payment_meta = new \stdClass ();
$payment_meta -> exp_month = $data [ 'card' ][ 'expiry_month' ];
$payment_meta -> exp_year = $data [ 'card' ][ 'expiry_year' ];
$payment_meta -> brand = 'CC' ;
$payment_meta -> last4 = $data [ 'card' ][ 'last4' ];
$payment_meta -> type = GatewayType :: CREDIT_CARD ;
$cgt [ 'payment_meta' ] = $payment_meta ;
$token = $this -> storeGatewayToken ( $cgt , []);
2024-06-14 09:09:44 +02:00
2024-03-19 00:38:54 +01:00
}
}
}
2021-07-20 13:26:24 +02:00
}