mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-07 10:44:29 -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;
|
||||
|
||||
private string $api_endpoint_url = '';
|
||||
|
||||
public function gatewayTypes()
|
||||
{
|
||||
return [
|
||||
@ -45,16 +47,6 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
}
|
||||
|
||||
public function init()
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Omnipay PayPal_Express gateway.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function initializeOmnipayGateway(): self
|
||||
{
|
||||
$this->omnipay_gateway = Omnipay::create(
|
||||
$this->company_gateway->gateway->provider
|
||||
@ -62,6 +54,8 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
@ -89,32 +83,121 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
|
||||
public function processPaymentView($data)
|
||||
{
|
||||
$this->initializeOmnipayGateway();
|
||||
$this->init();
|
||||
|
||||
$data['gateway'] = $this;
|
||||
|
||||
$this->payment_hash->data = array_merge((array) $this->payment_hash->data, ['amount' => $data['total']['amount_with_fee']]);
|
||||
$this->payment_hash->save();
|
||||
|
||||
$access_token = $this->omnipay_gateway->getToken();
|
||||
|
||||
$headers = [
|
||||
'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);
|
||||
$data['client_id'] = $this->company_gateway->getConfigField('clientId');
|
||||
$data['token'] = $this->getClientToken();
|
||||
$data['order_id'] = $this->createOrder($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)
|
||||
{
|
||||
$this->initializeOmnipayGateway();
|
||||
@ -221,6 +304,8 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
return $items;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private function feeCalc($invoice, $invoice_total)
|
||||
{
|
||||
$invoice->service()->removeUnpaidGatewayFees();
|
||||
@ -241,4 +326,6 @@ class PayPalRestPaymentDriver extends BaseDriver
|
||||
|
||||
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')])
|
||||
|
||||
@section('gateway_head')
|
||||
<link href="{{ asset('css/card-js.min.css') }}" rel="stylesheet" type="text/css">
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
@ -12,6 +10,15 @@
|
||||
@endsection
|
||||
|
||||
@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 class="card_container">
|
||||
@ -101,83 +108,16 @@
|
||||
@endsection
|
||||
|
||||
@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>
|
||||
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()) {
|
||||
let orderId;
|
||||
|
||||
// Renders card fields
|
||||
paypal.HostedFields.render({
|
||||
// Call your server to set up the transaction
|
||||
createOrder: () => {
|
||||
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: "cxcxcx",
|
||||
quantity: "333",
|
||||
},
|
||||
],
|
||||
}),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((orderData) => {
|
||||
orderId = orderData.id; // needed later to complete capture
|
||||
return orderData.id;
|
||||
});
|
||||
|
||||
createOrder: function(data, actions) {
|
||||
return "{!! $order_id !!}"
|
||||
},
|
||||
styles: {
|
||||
".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>
|
||||
@endpush
|
Loading…
x
Reference in New Issue
Block a user