PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.5.3
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.5.3
1.6.6 1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 All 49 releases
fluent-cart / app / Modules / PaymentMethods / PayPalGateway / API / Webhook.php

Webhook.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.5.3, at app/Modules/PaymentMethods/PayPalGateway/API/Webhook.php

154 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Modules\PaymentMethods\PayPalGateway\API;
4
5 use FluentCart\App\Modules\PaymentMethods\PayPalGateway\PayPalSettingsBase;
6 use FluentCart\Framework\Support\Arr;
7
8 class Webhook
9 {
10 const EVENTS = [
11 ['name' => 'PAYMENT.SALE.COMPLETED'],
12 ['name' => 'PAYMENT.SALE.REFUNDED'], // recurring payment refund
13 ['name' => 'PAYMENT.CAPTURE.REFUNDED'], // one time payment refund
14 ['name' => 'PAYMENT.CAPTURE.COMPLETED'],
15 ['name' => 'BILLING.SUBSCRIPTION.CREATED'],
16 ['name' => 'BILLING.SUBSCRIPTION.ACTIVATED'],
17 ['name' => 'BILLING.SUBSCRIPTION.SUSPENDED'],
18 ['name' => 'BILLING.SUBSCRIPTION.CANCELLED'],
19 ['name' => 'BILLING.SUBSCRIPTION.EXPIRED'],
20 ['name' => 'CUSTOMER.DISPUTE.CREATED'],
21 ['name' => 'CUSTOMER.DISPUTE.UPDATED'],
22 ['name' => 'CUSTOMER.DISPUTE.RESOLVED'],
23
24 // Extra for testing
25 ['name' => 'CHECKOUT.CHECKOUT.BUYER-APPROVED'],
26 ['name' => 'INVOICING.INVOICE.PAID'],
27 ['name' => 'CHECKOUT.ORDER.COMPLETED'],
28 ['name' => 'CHECKOUT.ORDER.PROCESSED'],
29 ['name' => 'CHECKOUT.ORDER.APPROVED'],
30 ['name' => 'PAYMENT.ORDER.CREATED']
31 ];
32
33 const WEBHOOK_ENDPOINT = '?fluent-cart=fct_payment_listener_ipn&method=paypal';
34
35 public static function getWebhookURL(): string
36 {
37 // return 'https://webhook.site/9f647f0d-3514-47b7-acca-95a2c168b917';
38 return trailingslashit(site_url()) . self::WEBHOOK_ENDPOINT;
39 }
40
41 public static function webhookInstruction(): string
42 {
43 $webhook_url = static::getWebhookURL();
44
45 $events = sprintf(
46 '<b>%1$s</b>
47 %2$s
48 <b>%3$s</b>
49 %4$s',
50 __('Payments and Payout:', 'fluent-cart'),
51 __('- Payment capture refunded | Payment sale completed | Payment sale refunded', 'fluent-cart'),
52 __('Billing Subscriptions:', 'fluent-cart'),
53 __('- Billing subscription activated | Billing subscription cancelled | Billing subscription created | Billing subscription expired | Billing subscription suspended', 'fluent-cart')
54 );
55
56 return sprintf(
57 '<div>
58 <br/>
59 <h4>%1$s</h4>
60 <p>%2$s</p>
61 <br/>
62 <p>%3$s</p>
63 <p>%4$s <a href="https://developer.paypal.com/dashboard/applications/production" target="_blank">%5$s</a> > %6$s</p>
64 <p>%7$s <code class="copyable-content">%8$s</code></p>
65 <b>%9$s</b>
66 %10$s
67 <br/>
68 </div>
69 <br/>',
70 __('How to configure webhook?', 'fluent-cart'), // %1$s
71 __('You should configure your PayPal webhooks manually if you connected manually. Follow the instruction to Create webhook and paste the webhook ID below.', 'fluent-cart'), // %2$s
72 __('In your PayPal account:', 'fluent-cart'), // %3$s
73 __('Go to', 'fluent-cart'), // %4$s
74 __('PayPal developers', 'fluent-cart'), // %5$s
75 __('App & Credentials > Your App > Webhooks section > Add webhook', 'fluent-cart'), // %6$s
76 __('Enter The Webhook URL:', 'fluent-cart'), // %7$s
77 $webhook_url, // %8$s
78 __('Select these events', 'fluent-cart'), // %9$s
79 $events // %10$s
80 );
81 }
82
83 public function registerWebhook($mode, $url = '')
84 {
85 $webhookData = API::makeRequest('notifications/webhooks', 'v1', 'POST',
86 [
87 'url' => $url ? $url : static::getWebhookURL(),
88 'event_types' => static::EVENTS
89 ], $mode);
90
91 if (is_wp_error($webhookData)) {
92 // if ERROR: WEBHOOK_URL_ALREADY_EXISTS, then manage
93 return $this->maybeWebhookExists($webhookData, $mode);
94 }
95
96 static::parseAndUpdateSettings($webhookData, $mode);
97 return $webhookData;
98 }
99
100 public static function parseAndUpdateSettings($webhookData, $mode)
101 {
102 $data = [
103 $mode . '_webhook_id' => Arr::get($webhookData, 'id'),
104 $mode . '_webhook_events' => Arr::get($webhookData, 'event_types')
105 ];
106 (new PayPalSettingsBase())->updateNonSensitiveData($data);
107 }
108
109 public function maybeWebhookExists($webhookData, $mode)
110 {
111 $webhookURL = static::getWebhookURL();
112 if (Arr::get($webhookData->get_error_data(), 'name') === 'WEBHOOK_URL_ALREADY_EXISTS') {
113 $webhookData = API::makeRequest('notifications/webhooks', 'v1', 'GET', []);
114 if (is_wp_error($webhookData)) {
115 return $webhookData;
116 }
117
118 $webhooks = Arr::get($webhookData, 'webhooks');
119 $matched = array_filter($webhooks, function ($webhook) use ($webhookURL) {
120 return $webhook['url'] === $webhookURL;
121 });
122
123 if (isset($matched[0])) {
124 static::parseAndUpdateSettings($matched[0], $mode);
125 }
126 }
127 return $webhookData;
128 }
129
130 public function maybeSetWebhook($mode)
131 {
132 $payPalSettings = new PayPalSettingsBase();
133 if (!$payPalSettings->getApiKey($mode)) {
134 return [
135 'status' => 'false',
136 'message' => __('No API key found for webhook setup. Please connect your PayPal account first.', 'fluent-cart')
137 ];
138 }
139
140 $webhookId = $payPalSettings->get($mode . '_webhook_id');
141
142 if ($webhookId) {
143 $webhookData = API::makeRequest('notifications/webhooks/' . $webhookId, 'v1', 'GET', []);
144 if (!is_wp_error($webhookData) && Arr::get($webhookData, 'id') === $webhookId) {
145 static::parseAndUpdateSettings($webhookData, $mode); // update webhook events
146 return $webhookData;
147 }
148 }
149
150 // If there is no Webhook ID found or webhook isn't found, register a new one
151 return (new Webhook())->registerWebhook($mode);
152 }
153 }
154