mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-04 08:17:32 -05:00 
			
		
		
		
	Merge pull request #4369 from beganovich/v5-paypal-refactor
(v5) PayPal refactor
This commit is contained in:
		
						commit
						870dea8981
					
				@ -12,41 +12,28 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace App\PaymentDrivers;
 | 
					namespace App\PaymentDrivers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use App\Events\Payment\PaymentWasCreated;
 | 
					use App\Exceptions\PaymentFailed;
 | 
				
			||||||
use App\Jobs\Mail\PaymentFailureMailer;
 | 
					use App\Jobs\Mail\PaymentFailureMailer;
 | 
				
			||||||
use App\Jobs\Util\SystemLogger;
 | 
					use App\Jobs\Util\SystemLogger;
 | 
				
			||||||
use App\Models\ClientGatewayToken;
 | 
					 | 
				
			||||||
use App\Models\GatewayType;
 | 
					use App\Models\GatewayType;
 | 
				
			||||||
use App\Models\Payment;
 | 
					use App\Models\Invoice;
 | 
				
			||||||
use App\Models\PaymentHash;
 | 
					 | 
				
			||||||
use App\Models\PaymentType;
 | 
					use App\Models\PaymentType;
 | 
				
			||||||
use App\Models\SystemLog;
 | 
					use App\Models\SystemLog;
 | 
				
			||||||
use App\Utils\Ninja;
 | 
					 | 
				
			||||||
use App\Utils\Traits\MakesHash;
 | 
					use App\Utils\Traits\MakesHash;
 | 
				
			||||||
use Exception;
 | 
					 | 
				
			||||||
use Omnipay\Common\Item;
 | 
					use Omnipay\Common\Item;
 | 
				
			||||||
use stdClass;
 | 
					use Omnipay\Omnipay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PayPalExpressPaymentDriver extends BasePaymentDriver
 | 
					class PayPalExpressPaymentDriver extends BaseDriver
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    use MakesHash;
 | 
					    use MakesHash;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public $payment_hash;
 | 
					    public $token_billing = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public $required_fields = [];
 | 
					    public $can_authorise_credit_card = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $refundable = true;
 | 
					    private $omnipay_gateway;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $token_billing = false;
 | 
					    const SYSTEM_LOG_TYPE = SystemLog::TYPE_PAYPAL;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected $can_authorise_credit_card = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected $customer_reference = '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function setPaymentMethod($payment_method_id = null)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function gatewayTypes()
 | 
					    public function gatewayTypes()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -55,131 +42,43 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
 | 
				
			|||||||
        ];
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const SYSTEM_LOG_TYPE = SystemLog::TYPE_PAYPAL;
 | 
					    /**
 | 
				
			||||||
 | 
					     * Initialize Omnipay PayPal_Express gateway.
 | 
				
			||||||
    public function checkRequirements()
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function initializeOmnipayGateway(): void
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->company_gateway->require_billing_address) {
 | 
					        $this->omnipay_gateway = Omnipay::create(
 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->address1)) {
 | 
					            $this->company_gateway->gateway->provider
 | 
				
			||||||
                $this->required_fields[] = 'billing_address1';
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->omnipay_gateway->initialize((array) $this->company_gateway->getConfig());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->address2)) {
 | 
					    public function setPaymentMethod($payment_method_id)
 | 
				
			||||||
                $this->required_fields[] = 'billing_address2';
 | 
					    {
 | 
				
			||||||
            }
 | 
					        // PayPal doesn't have multiple ways of paying.
 | 
				
			||||||
 | 
					        // There's just one, off-site redirect.
 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->city)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'billing_city';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->state)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'billing_state';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->postal_code)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'billing_postal_code';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->country_id)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'billing_country';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->company_gateway->require_shipping_address) {
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->shipping_address1)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'shipping_address1';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->shipping_address2)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'shipping_address2';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->shipping_city)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'shipping_city';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->shipping_state)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'shipping_state';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->shipping_postal_code)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'shipping_postal_code';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->shipping_country_id)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'shipping_country';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->company_gateway->require_client_name) {
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->name)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'name';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->company_gateway->require_client_phone) {
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->phone)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'phone';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->company_gateway->require_contact_email) {
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->email)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'contact_email';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->company_gateway->require_contact_name) {
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->first_name)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'contact_first_name';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->last_name)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'contact_last_name';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($this->company_gateway->require_postal_code) {
 | 
					 | 
				
			||||||
            // In case "require_postal_code" is true, we don't need billing address.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            foreach ($this->required_fields as $position => $field) {
 | 
					 | 
				
			||||||
                if (Str::startsWith($field, 'billing')) {
 | 
					 | 
				
			||||||
                    unset($this->required_fields[$position]);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if ($this->checkRequiredResource(auth()->user('contact')->client->postal_code)) {
 | 
					 | 
				
			||||||
                $this->required_fields[] = 'postal_code';
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    public function authorizeView($payment_method)
 | 
				
			||||||
     * Wrapper method for checking if resource is good.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param mixed $resource
 | 
					 | 
				
			||||||
     * @return bool
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function checkRequiredResource($resource): bool
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (is_null($resource) || empty($resource)) {
 | 
					        // PayPal doesn't support direct authorization.
 | 
				
			||||||
            return true;
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return false;
 | 
					    public function authorizeResponse($request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // PayPal doesn't support direct authorization.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    public function processPaymentView($data)
 | 
				
			||||||
     * Processes the payment with this gateway.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param array $data variables required to build payment page
 | 
					 | 
				
			||||||
     * @return void Gateway and payment method specific view
 | 
					 | 
				
			||||||
     * @throws Exception
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function processPaymentView(array $data)
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (count($this->required_fields) > 0) {
 | 
					        if (count($this->required_fields) > 0) {
 | 
				
			||||||
            return redirect()
 | 
					            return redirect()
 | 
				
			||||||
@ -187,37 +86,36 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
 | 
				
			|||||||
                ->with('missing_required_fields', $this->required_fields);
 | 
					                ->with('missing_required_fields', $this->required_fields);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $response = $this->purchase($this->paymentDetails($data), $this->paymentItems($data));
 | 
					        $this->initializeOmnipayGateway();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['amount_with_fee']]);
 | 
				
			||||||
 | 
					        $this->payment_hash->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $response = $this->omnipay_gateway
 | 
				
			||||||
 | 
					            ->purchase($this->generatePaymentDetails($data))
 | 
				
			||||||
 | 
					            ->setItems($this->generatePaymentItems($data))
 | 
				
			||||||
 | 
					            ->send();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($response->isRedirect()) {
 | 
					        if ($response->isRedirect()) {
 | 
				
			||||||
            // redirect to offsite payment gateway
 | 
					            return $response->redirect();
 | 
				
			||||||
            $response->redirect();
 | 
					        }
 | 
				
			||||||
        } elseif ($response->isSuccessful()) {
 | 
					
 | 
				
			||||||
            // payment was successful: update database
 | 
					        PaymentFailureMailer::dispatch($this->client, $response->getData(), $this->client->company, $data['amount_with_fee']);
 | 
				
			||||||
            /* for this driver this method wont be hit*/
 | 
					
 | 
				
			||||||
        } else {
 | 
					        $message = [
 | 
				
			||||||
            // payment failed: display message to customer
 | 
					            'server_response' => $response->getMessage(),
 | 
				
			||||||
 | 
					            'data' => $this->checkout->payment_hash->data,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SystemLogger::dispatch(
 | 
					        SystemLogger::dispatch(
 | 
				
			||||||
                [
 | 
					            $message,
 | 
				
			||||||
                    'server_response' => $response->getData(),
 | 
					 | 
				
			||||||
                    'data' => $data,
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
            SystemLog::CATEGORY_GATEWAY_RESPONSE,
 | 
					            SystemLog::CATEGORY_GATEWAY_RESPONSE,
 | 
				
			||||||
            SystemLog::EVENT_GATEWAY_FAILURE,
 | 
					            SystemLog::EVENT_GATEWAY_FAILURE,
 | 
				
			||||||
            SystemLog::TYPE_PAYPAL,
 | 
					            SystemLog::TYPE_PAYPAL,
 | 
				
			||||||
            $this->client
 | 
					            $this->client
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            throw new Exception('Error Processing Payment', 1);
 | 
					        throw new PaymentFailed($response->getMessage(), $response->getCode());
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function setPaymentHash(PaymentHash $payment_hash)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->payment_hash = $payment_hash;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $this;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function processPaymentResponse($request)
 | 
					    public function processPaymentResponse($request)
 | 
				
			||||||
@ -228,209 +126,112 @@ class PayPalExpressPaymentDriver extends BasePaymentDriver
 | 
				
			|||||||
                ->with('missing_required_fields', $this->required_fields);
 | 
					                ->with('missing_required_fields', $this->required_fields);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $response = $this->completePurchase($request->all());
 | 
					        $this->initializeOmnipayGateway();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $transaction_reference = $response->getTransactionReference() ?: $request->input('token');
 | 
					        $response = $this->omnipay_gateway
 | 
				
			||||||
 | 
					            ->completePurchase(['amount' => $this->payment_hash->data->amount])
 | 
				
			||||||
 | 
					            ->send();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($response->isCancelled()) {
 | 
					        if ($response->isCancelled()) {
 | 
				
			||||||
            return redirect()->route('client.invoices.index')->with('warning', ctrans('texts.status_cancelled'));
 | 
					            return redirect()->route('client.invoices.index')->with('warning', ctrans('texts.status_cancelled'));
 | 
				
			||||||
        } elseif ($response->isSuccessful()) {
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($response->isSuccessful()) {
 | 
				
			||||||
 | 
					            $data = [
 | 
				
			||||||
 | 
					                'payment_method' => $response->getData()['TOKEN'],
 | 
				
			||||||
 | 
					                'payment_type' => PaymentType::PAYPAL,
 | 
				
			||||||
 | 
					                'amount' => $this->payment_hash->data->amount,
 | 
				
			||||||
 | 
					                'transaction_reference' => $response->getTransactionReference(),
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $payment = $this->createPayment($data, \App\Models\Payment::STATUS_COMPLETED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SystemLogger::dispatch(
 | 
					            SystemLogger::dispatch(
 | 
				
			||||||
                [
 | 
					                ['response' => $response, 'data' => $data],
 | 
				
			||||||
                    'server_response' => $response->getData(),
 | 
					 | 
				
			||||||
                    'data' => $request->all(),
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
                SystemLog::CATEGORY_GATEWAY_RESPONSE,
 | 
					                SystemLog::CATEGORY_GATEWAY_RESPONSE,
 | 
				
			||||||
                SystemLog::EVENT_GATEWAY_SUCCESS,
 | 
					                SystemLog::EVENT_GATEWAY_SUCCESS,
 | 
				
			||||||
                SystemLog::TYPE_PAYPAL,
 | 
					                SystemLog::TYPE_PAYPAL,
 | 
				
			||||||
                $this->client
 | 
					                $this->client
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        } elseif (! $response->isSuccessful()) {
 | 
					
 | 
				
			||||||
            PaymentFailureMailer::dispatch($this->client, $response->getMessage, $this->client->company, $response['PAYMENTINFO_0_AMT']);
 | 
					            return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!$response->isSuccessful()) {
 | 
				
			||||||
 | 
					            PaymentFailureMailer::dispatch($this->client, $response->getMessage(), $this->client->company, $response['PAYMENTINFO_0_AMT']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $message = [
 | 
				
			||||||
 | 
					                'server_response' => $response->getMessage(),
 | 
				
			||||||
 | 
					                'data' => $this->payment_hash->data,
 | 
				
			||||||
 | 
					            ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            SystemLogger::dispatch(
 | 
					            SystemLogger::dispatch(
 | 
				
			||||||
                [
 | 
					                $message,
 | 
				
			||||||
                    'data' => $request->all(),
 | 
					 | 
				
			||||||
                    'server_response' => $response->getData(),
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
                SystemLog::CATEGORY_GATEWAY_RESPONSE,
 | 
					                SystemLog::CATEGORY_GATEWAY_RESPONSE,
 | 
				
			||||||
                SystemLog::EVENT_GATEWAY_FAILURE,
 | 
					                SystemLog::EVENT_GATEWAY_FAILURE,
 | 
				
			||||||
                SystemLog::TYPE_PAYPAL,
 | 
					                SystemLog::TYPE_PAYPAL,
 | 
				
			||||||
                $this->client
 | 
					                $this->client
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            throw new Exception($response->getMessage());
 | 
					            throw new PaymentFailed($response->getMessage(), $response->getCode());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $payment = $this->createPayment($response->getData());
 | 
					    public function generatePaymentDetails(array $data)
 | 
				
			||||||
        $payment_hash = PaymentHash::whereRaw('BINARY `hash`= ?', [$request->input('payment_hash')])->firstOrFail();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $payment_hash->payment_id = $payment->id;
 | 
					 | 
				
			||||||
        $payment_hash->save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $this->attachInvoices($payment, $payment_hash);
 | 
					 | 
				
			||||||
        $payment->service()->updateInvoicePayment($payment_hash);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        event(new PaymentWasCreated($payment, $payment->company, Ninja::eventVars()));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return redirect()->route('client.payments.show', ['payment' => $this->encodePrimaryKey($payment->id)]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected function paymentDetails($input): array
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $data = parent::paymentDetails($input);
 | 
					        return [
 | 
				
			||||||
 | 
					            'currency' => $this->client->getCurrencyCode(),
 | 
				
			||||||
        $data['amount'] = $input['amount_with_fee'];
 | 
					            'transactionType' => 'Purchase',
 | 
				
			||||||
        $data['returnUrl'] = $this->buildReturnUrl($input);
 | 
					            'clientIp' => request()->getClientIp(),
 | 
				
			||||||
        $data['cancelUrl'] = $this->buildCancelUrl($input);
 | 
					            'amount' => $data['amount_with_fee'],
 | 
				
			||||||
        $data['description'] = $this->buildDescription($input);
 | 
					            'returnUrl' => route('client.payments.response', [
 | 
				
			||||||
        $data['transactionId'] = $this->buildTransactionId($input);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $data['ButtonSource'] = 'InvoiceNinja_SP';
 | 
					 | 
				
			||||||
        $data['solutionType'] = 'Sole'; // show 'Pay with credit card' option
 | 
					 | 
				
			||||||
        $data['transactionId'] = $data['transactionId'].'-'.time();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $data;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private function buildReturnUrl($input): string
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return route('client.payments.response', [
 | 
					 | 
				
			||||||
                'company_gateway_id' => $this->company_gateway->id,
 | 
					                'company_gateway_id' => $this->company_gateway->id,
 | 
				
			||||||
                'payment_hash' => $this->payment_hash->hash,
 | 
					                'payment_hash' => $this->payment_hash->hash,
 | 
				
			||||||
                'payment_method_id' => GatewayType::PAYPAL,
 | 
					                'payment_method_id' => GatewayType::PAYPAL,
 | 
				
			||||||
        ]);
 | 
					            ]),
 | 
				
			||||||
 | 
					            'cancelUrl' => $this->client->company->domain() . '/client/invoices',
 | 
				
			||||||
 | 
					            'description' => implode(',', collect($this->payment_hash->data->invoices)
 | 
				
			||||||
 | 
					                ->map(function ($invoice) {
 | 
				
			||||||
 | 
					                    return sprintf('%s: %s', ctrans('texts.invoice_number'), $invoice->invoice_number);
 | 
				
			||||||
 | 
					                })->toArray()),
 | 
				
			||||||
 | 
					            'transactionId' => $this->payment_hash->hash . '-' . time(),
 | 
				
			||||||
 | 
					            'ButtonSource' => 'InvoiceNinja_SP',
 | 
				
			||||||
 | 
					            'solutionType' => 'Sole',
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private function buildCancelUrl($input): string
 | 
					    public function generatePaymentItems(array $data)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $url = $this->client->company->domain().'/client/invoices';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $url;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private function buildDescription($input): string
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $invoice_numbers = '';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        foreach ($input['invoices'] as $invoice) {
 | 
					 | 
				
			||||||
            $invoice_numbers .= $invoice->number.' ';
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return ctrans('texts.invoice_number').": {$invoice_numbers}";
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private function buildTransactionId($input): string
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return implode(',', $input['hashed_ids']);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private function paymentItems($input): array
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $items = [];
 | 
					 | 
				
			||||||
        $total = 0;
 | 
					        $total = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        foreach ($input['invoices'] as $invoice) {
 | 
					        $items = collect($this->payment_hash->data->invoices)->map(function ($i) use (&$total) {
 | 
				
			||||||
            foreach ($invoice->line_items as $invoiceItem) {
 | 
					            $invoice = Invoice::findOrFail($this->decodePrimaryKey($i->invoice_id));
 | 
				
			||||||
                // Some gateways require quantity is an integer
 | 
					
 | 
				
			||||||
                if (floatval($invoiceItem->quantity) != intval($invoiceItem->quantity)) {
 | 
					            return collect($invoice->line_items)->map(function ($lineItem) use (&$total) {
 | 
				
			||||||
 | 
					                if (floatval($lineItem->quantity) != intval($lineItem->quantity)) {
 | 
				
			||||||
                    return null;
 | 
					                    return null;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $item = new Item([
 | 
					                $total += $lineItem->cost * $lineItem->quantity;
 | 
				
			||||||
                    'name' => $invoiceItem->product_key,
 | 
					
 | 
				
			||||||
                    'description' => substr($invoiceItem->notes, 0, 100),
 | 
					                return new Item([
 | 
				
			||||||
                    'price' => $invoiceItem->cost,
 | 
					                    'name' => $lineItem->product_key,
 | 
				
			||||||
                    'quantity' => $invoiceItem->quantity,
 | 
					                    'description' => substr($lineItem->notes, 0, 100),
 | 
				
			||||||
 | 
					                    'price' => $lineItem->cost,
 | 
				
			||||||
 | 
					                    'quantity' => $lineItem->quantity,
 | 
				
			||||||
                ]);
 | 
					                ]);
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                $items[] = $item;
 | 
					        if ($total != $data['amount_with_fee']) {
 | 
				
			||||||
 | 
					            $items[0][] = new Item([
 | 
				
			||||||
                $total += $invoiceItem->cost * $invoiceItem->quantity;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if ($total != $input['amount_with_fee']) {
 | 
					 | 
				
			||||||
            $item = new Item([
 | 
					 | 
				
			||||||
                'name' => trans('texts.taxes_and_fees'),
 | 
					                'name' => trans('texts.taxes_and_fees'),
 | 
				
			||||||
                'description' => '',
 | 
					                'description' => '',
 | 
				
			||||||
                'price' => $input['amount_with_fee'] - $total,
 | 
					                'price' => $data['amount_with_fee'] - $total,
 | 
				
			||||||
                'quantity' => 1,
 | 
					                'quantity' => 1,
 | 
				
			||||||
            ]);
 | 
					            ]);
 | 
				
			||||||
 | 
					 | 
				
			||||||
            $items[] = $item;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $items;
 | 
					        return $items[0]->toArray();
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function createPayment($data, $status = Payment::STATUS_COMPLETED): Payment
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $payment_meta = new stdClass;
 | 
					 | 
				
			||||||
        $payment_meta->exp_month = 'xx';
 | 
					 | 
				
			||||||
        $payment_meta->exp_year = 'xx';
 | 
					 | 
				
			||||||
        $payment_meta->brand = 'PayPal';
 | 
					 | 
				
			||||||
        $payment_meta->last4 = 'xxxx';
 | 
					 | 
				
			||||||
        $payment_meta->type = GatewayType::PAYPAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $payment = parent::createPayment($data, $status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $client_contact = $this->getContact();
 | 
					 | 
				
			||||||
        $client_contact_id = $client_contact ? $client_contact->id : null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $payment->amount = $data['PAYMENTINFO_0_AMT'];
 | 
					 | 
				
			||||||
        $payment->type_id = PaymentType::PAYPAL;
 | 
					 | 
				
			||||||
        $payment->transaction_reference = $data['PAYMENTINFO_0_TRANSACTIONID'];
 | 
					 | 
				
			||||||
        $payment->client_contact_id = $client_contact_id;
 | 
					 | 
				
			||||||
        $payment->meta = $payment_meta;
 | 
					 | 
				
			||||||
        $payment->save();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $payment;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function refund(Payment $payment, $amount)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        $this->gateway();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $response = $this->gateway
 | 
					 | 
				
			||||||
            ->refund(['transactionReference' => $payment->transaction_reference, 'amount' => $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 [
 | 
					 | 
				
			||||||
                'transaction_reference' => $response->getData()['REFUNDTRANSACTIONID'],
 | 
					 | 
				
			||||||
                'transaction_response' => json_encode($response->getData()),
 | 
					 | 
				
			||||||
                'success' => true,
 | 
					 | 
				
			||||||
                'description' => $response->getData()['ACK'],
 | 
					 | 
				
			||||||
                'code' => $response->getCode(),
 | 
					 | 
				
			||||||
            ];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        SystemLogger::dispatch([
 | 
					 | 
				
			||||||
            'server_response' => $response->getMessage(), 'data' => request()->all(),
 | 
					 | 
				
			||||||
        ], SystemLog::CATEGORY_GATEWAY_RESPONSE, SystemLog::EVENT_GATEWAY_FAILURE, SystemLog::TYPE_PAYPAL, $this->client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return [
 | 
					 | 
				
			||||||
            'transaction_reference' => $response->getData()['CORRELATIONID'],
 | 
					 | 
				
			||||||
            'transaction_response' => json_encode($response->getData()),
 | 
					 | 
				
			||||||
            'success' => false,
 | 
					 | 
				
			||||||
            'description' => $response->getData()['L_LONGMESSAGE0'],
 | 
					 | 
				
			||||||
            'code' => $response->getData()['L_ERRORCODE0'],
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Detach payment method from PayPal.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param ClientGatewayToken $token
 | 
					 | 
				
			||||||
     * @return void
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function detach(ClientGatewayToken $token)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // PayPal doesn't support this feature.
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user