mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-06-23 20:00:33 -04:00
Working on Paypal REST integration
This commit is contained in:
parent
8e62c5ac51
commit
f647139918
@ -37,6 +37,8 @@ class PayPalRestPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
public const SYSTEM_LOG_TYPE = SystemLog::TYPE_PAYPAL;
|
public const SYSTEM_LOG_TYPE = SystemLog::TYPE_PAYPAL;
|
||||||
|
|
||||||
|
private string $api_endpoint_url = '';
|
||||||
|
|
||||||
public function gatewayTypes()
|
public function gatewayTypes()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@ -45,16 +47,6 @@ class PayPalRestPaymentDriver extends BaseDriver
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function init()
|
public function init()
|
||||||
{
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize Omnipay PayPal_Express gateway.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function initializeOmnipayGateway(): self
|
|
||||||
{
|
{
|
||||||
$this->omnipay_gateway = Omnipay::create(
|
$this->omnipay_gateway = Omnipay::create(
|
||||||
$this->company_gateway->gateway->provider
|
$this->company_gateway->gateway->provider
|
||||||
@ -62,6 +54,8 @@ class PayPalRestPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
$this->omnipay_gateway->initialize((array) $this->company_gateway->getConfig());
|
$this->omnipay_gateway->initialize((array) $this->company_gateway->getConfig());
|
||||||
|
|
||||||
|
$this->api_endpoint_url = $this->company_gateway->getConfigField('testMode') ? 'https://api-m.sandbox.paypal.com' : 'https://api-m.paypal.com';
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,32 +83,121 @@ class PayPalRestPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
public function processPaymentView($data)
|
public function processPaymentView($data)
|
||||||
{
|
{
|
||||||
$this->initializeOmnipayGateway();
|
$this->init();
|
||||||
|
|
||||||
$data['gateway'] = $this;
|
$data['gateway'] = $this;
|
||||||
|
|
||||||
$this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['total']['amount_with_fee']]);
|
$this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['total']['amount_with_fee']]);
|
||||||
$this->payment_hash->save();
|
$this->payment_hash->save();
|
||||||
|
|
||||||
$access_token = $this->omnipay_gateway->getToken();
|
$data['client_id'] = $this->company_gateway->getConfigField('clientId');
|
||||||
|
$data['token'] = $this->getClientToken();
|
||||||
$headers = [
|
$data['order_id'] = $this->createOrder($data);
|
||||||
'Accept' => 'application/json',
|
|
||||||
'Content-type' => 'application/json',
|
|
||||||
'Accept-Language' => 'en_US',
|
|
||||||
];
|
|
||||||
|
|
||||||
$r = Http::withToken($access_token)
|
|
||||||
->withHeaders($headers)
|
|
||||||
->post("https://api-m.sandbox.paypal.com/v1/identity/generate-token",['body' => '']);
|
|
||||||
|
|
||||||
nlog($r->body());
|
|
||||||
dd($r);
|
|
||||||
|
|
||||||
return render('gateways.paypal.pay', $data);
|
return render('gateways.paypal.pay', $data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function processPaymentResponse($request)
|
||||||
|
{
|
||||||
|
$this->init();
|
||||||
|
|
||||||
|
nlog($request->all());
|
||||||
|
|
||||||
|
$response = json_decode($request['gateway_response'], true);
|
||||||
|
|
||||||
|
$order_id = $response['orderID'];
|
||||||
|
|
||||||
|
nlog($order_id);
|
||||||
|
|
||||||
|
$r = $this->gatewayRequest("/v2/checkout/orders/{$order_id}/capture", 'post', []);
|
||||||
|
|
||||||
|
dd($r->body());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getClientToken(): string
|
||||||
|
{
|
||||||
|
|
||||||
|
$r = $this->gatewayRequest('/v1/identity/generate-token', 'post', ['body' => '']);
|
||||||
|
|
||||||
|
if($r->successful())
|
||||||
|
return $r->json()['client_token'];
|
||||||
|
|
||||||
|
throw new PaymentFailed('Unable to gain client token from Paypal. Check your configuration', 401);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function createOrder(array $data): string
|
||||||
|
{
|
||||||
|
|
||||||
|
$_invoice = collect($this->payment_hash->data->invoices)->first();
|
||||||
|
|
||||||
|
$invoice = Invoice::withTrashed()->find($this->decodePrimaryKey($_invoice->invoice_id));
|
||||||
|
|
||||||
|
$order = [
|
||||||
|
"intent" => "CAPTURE",
|
||||||
|
"purchase_units" => [
|
||||||
|
[
|
||||||
|
"description" =>ctrans('texts.invoice_number').'# '.$invoice->number,
|
||||||
|
"invoice_id" => $invoice->number,
|
||||||
|
'reference_id' => 'PUHF',
|
||||||
|
'description' => 'Sporting Goods',
|
||||||
|
'custom_id' => 'CUST-HighFashions',
|
||||||
|
'soft_descriptor' => 'HighFashions',
|
||||||
|
"amount" => [
|
||||||
|
"value" => (string)$data['amount_with_fee'],
|
||||||
|
"currency_code"=> $this->client->currency()->code,
|
||||||
|
"breakdown" => [
|
||||||
|
"item_total" => [
|
||||||
|
"currency_code" => $this->client->currency()->code,
|
||||||
|
"value" => (string)$data['amount_with_fee']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"items"=> [
|
||||||
|
[
|
||||||
|
"name" => ctrans('texts.invoice_number').'# '.$invoice->number,
|
||||||
|
"quantity" => "1",
|
||||||
|
"unit_amount" => [
|
||||||
|
"currency_code" => $this->client->currency()->code,
|
||||||
|
"value" => (string)$data['amount_with_fee']
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$r = $this->gatewayRequest('/v2/checkout/orders', 'post', $order);
|
||||||
|
|
||||||
|
return $r->json()['id'];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function gatewayRequest(string $uri, string $verb, array $data, ?array $headers = [])
|
||||||
|
{
|
||||||
|
$r = Http::withToken($this->omnipay_gateway->getToken())
|
||||||
|
->withHeaders($this->getHeaders($headers))
|
||||||
|
->{$verb}("{$this->api_endpoint_url}{$uri}", $data);
|
||||||
|
|
||||||
|
if($r->successful())
|
||||||
|
return $r;
|
||||||
|
|
||||||
|
throw new PaymentFailed("Gateway failure - {$r->body()}", 401);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHeaders(array $headers = []): array
|
||||||
|
{
|
||||||
|
return array_merge([
|
||||||
|
'Accept' => 'application/json',
|
||||||
|
'Content-type' => 'application/json',
|
||||||
|
'Accept-Language' => 'en_US',
|
||||||
|
], $headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
public function processPaymentResponse($request)
|
public function processPaymentResponse($request)
|
||||||
{
|
{
|
||||||
$this->initializeOmnipayGateway();
|
$this->initializeOmnipayGateway();
|
||||||
@ -221,6 +304,8 @@ class PayPalRestPaymentDriver extends BaseDriver
|
|||||||
return $items;
|
return $items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
private function feeCalc($invoice, $invoice_total)
|
private function feeCalc($invoice, $invoice_total)
|
||||||
{
|
{
|
||||||
$invoice->service()->removeUnpaidGatewayFees();
|
$invoice->service()->removeUnpaidGatewayFees();
|
||||||
@ -241,4 +326,6 @@ class PayPalRestPaymentDriver extends BaseDriver
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title' => ctrans('texts.payment_type_credit_card')])
|
@extends('portal.ninja2020.layout.payments', ['gateway_title' => ctrans('texts.payment_type_credit_card'), 'card_title' => ctrans('texts.payment_type_credit_card')])
|
||||||
|
|
||||||
@section('gateway_head')
|
@section('gateway_head')
|
||||||
<link href="{{ asset('css/card-js.min.css') }}" rel="stylesheet" type="text/css">
|
|
||||||
|
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
type="text/css"
|
type="text/css"
|
||||||
@ -12,6 +10,15 @@
|
|||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('gateway_content')
|
@section('gateway_content')
|
||||||
|
<form action="{{ route('client.payments.response') }}" method="post" id="server_response">
|
||||||
|
@csrf
|
||||||
|
<input type="hidden" name="payment_hash" value="{{ $payment_hash }}">
|
||||||
|
<input type="hidden" name="company_gateway_id" value="{{ $gateway->company_gateway->id }}">
|
||||||
|
<input type="hidden" name="gateway_response" id="gateway_response">
|
||||||
|
<input type="hidden" name="amount_with_fee" id="amount_with_fee" value="{{ $total['amount_with_fee'] }}"/>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="alert alert-failure mb-4" hidden id="errors"></div>
|
||||||
|
|
||||||
<div id="paypal-button-container" class="paypal-button-container"></div>
|
<div id="paypal-button-container" class="paypal-button-container"></div>
|
||||||
<div class="card_container">
|
<div class="card_container">
|
||||||
@ -101,83 +108,16 @@
|
|||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@push('footer')
|
@push('footer')
|
||||||
<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&client-id=AdRZZt44vJYAtXirmzMjnvUMoFIloN9kpuSgshQB7SJqLHbgtMP_rcmhy83FYY4a-c3R-_e4wZC8E3oG" data-client-token="{!! $token !!}">
|
<script src="https://www.paypal.com/sdk/js?components=buttons,hosted-fields&intent=capture&client-id={!! $client_id !!}" data-client-token="{!! $token !!}">
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
paypal
|
|
||||||
.Buttons({
|
|
||||||
// Sets up the transaction when a payment button is clicked
|
|
||||||
createOrder: function () {
|
|
||||||
return fetch("/api/orders", {
|
|
||||||
method: "post",
|
|
||||||
// use the "body" param to optionally pass additional order information
|
|
||||||
// like product skus and quantities
|
|
||||||
body: JSON.stringify({
|
|
||||||
cart: [
|
|
||||||
{
|
|
||||||
sku: "213434",
|
|
||||||
quantity: "1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((order) => order.id);
|
|
||||||
},
|
|
||||||
// Finalize the transaction after payer approval
|
|
||||||
onApprove: function (data) {
|
|
||||||
return fetch(`/api/orders/${data.orderID}/capture`, {
|
|
||||||
method: "post",
|
|
||||||
})
|
|
||||||
.then((response) => response.json())
|
|
||||||
.then((orderData) => {
|
|
||||||
// Successful capture! For dev/demo purposes:
|
|
||||||
console.log(
|
|
||||||
"Capture result",
|
|
||||||
orderData,
|
|
||||||
JSON.stringify(orderData, null, 2)
|
|
||||||
);
|
|
||||||
const transaction = orderData.purchase_units[0].payments.captures[0];
|
|
||||||
alert(`Transaction ${transaction.status}: ${transaction.id}
|
|
||||||
|
|
||||||
See console for all available details
|
|
||||||
`);
|
|
||||||
// When ready to go live, remove the alert and show a success message within this page. For example:
|
|
||||||
// var element = document.getElementById('paypal-button-container');
|
|
||||||
// element.innerHTML = '<h3>Thank you for your payment!</h3>';
|
|
||||||
// Or go to another URL: actions.redirect('thank_you.html');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.render("#paypal-button-container");
|
|
||||||
|
|
||||||
// If this returns false or the card fields aren't visible, see Step #1.
|
|
||||||
if (paypal.HostedFields.isEligible()) {
|
if (paypal.HostedFields.isEligible()) {
|
||||||
let orderId;
|
|
||||||
|
|
||||||
// Renders card fields
|
|
||||||
paypal.HostedFields.render({
|
paypal.HostedFields.render({
|
||||||
// Call your server to set up the transaction
|
|
||||||
createOrder: () => {
|
createOrder: function(data, actions) {
|
||||||
return fetch("/api/orders", {
|
return "{!! $order_id !!}"
|
||||||
method: "post",
|
|
||||||
// use the "body" param to optionally pass additional order information
|
|
||||||
// like product skus and quantities
|
|
||||||
body: JSON.stringify({
|
|
||||||
cart: [
|
|
||||||
{
|
|
||||||
sku: "cxcxcx",
|
|
||||||
quantity: "333",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((orderData) => {
|
|
||||||
orderId = orderData.id; // needed later to complete capture
|
|
||||||
return orderData.id;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
styles: {
|
styles: {
|
||||||
".valid": {
|
".valid": {
|
||||||
@ -261,9 +201,34 @@ if (paypal.HostedFields.isEligible()) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
// Hides card fields if the merchant isn't eligible
|
|
||||||
document.querySelector("#card-form").style = "display: none";
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
document.querySelector("#card-form").style = "display: none";
|
||||||
|
|
||||||
|
paypal.Buttons({
|
||||||
|
env: 'sandbox', // sandbox | production
|
||||||
|
|
||||||
|
client: {
|
||||||
|
sandbox: "{{ $gateway->company_gateway->getConfigField('clientId') }}",
|
||||||
|
|
||||||
|
},
|
||||||
|
createOrder: function(data, actions) {
|
||||||
|
return "{!! $order_id !!}"
|
||||||
|
},
|
||||||
|
onApprove: function(data, actions) {
|
||||||
|
|
||||||
|
return actions.order.capture().then(function(details) {
|
||||||
|
|
||||||
|
console.log(details);
|
||||||
|
});
|
||||||
|
|
||||||
|
// document.getElementById("gateway_response").value =JSON.stringify( data );
|
||||||
|
// document.getElementById("server_response").submit();
|
||||||
|
|
||||||
|
}
|
||||||
|
}).render('#paypal-button-container');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
Loading…
x
Reference in New Issue
Block a user