PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.3.1
GiveWP – Donation Plugin and Fundraising Platform v3.3.1
4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / LegacyPaymentGateways / Adapters / LegacyPaymentGatewayAdapter.php
give / src / LegacyPaymentGateways / Adapters Last commit date
LegacyPaymentGatewayAdapter.php 2 years ago
LegacyPaymentGatewayAdapter.php
396 lines
1 <?php
2
3 namespace Give\LegacyPaymentGateways\Adapters;
4
5 use Exception;
6 use Give\DonationForms\Actions\GetOrCreateDonor;
7 use Give\DonationForms\V2\Models\DonationForm;
8 use Give\Donations\Models\Donation;
9 use Give\Donations\ValueObjects\DonationType;
10 use Give\Donors\Models\Donor;
11 use Give\Framework\PaymentGateways\Contracts\PaymentGatewayInterface;
12 use Give\Framework\PaymentGateways\Controllers\GatewayPaymentController;
13 use Give\Framework\PaymentGateways\Controllers\GatewaySubscriptionController;
14 use Give\Framework\PaymentGateways\Log\PaymentGatewayLog;
15 use Give\Framework\PaymentGateways\PaymentGateway;
16 use Give\Framework\PaymentGateways\Traits\HandleHttpResponses;
17 use Give\Helpers\Form\Utils;
18 use Give\PaymentGateways\Actions\GetGatewayDataFromRequest;
19 use Give\PaymentGateways\DataTransferObjects\FormData;
20 use Give\PaymentGateways\DataTransferObjects\SubscriptionData;
21 use Give\Session\SessionDonation\DonationAccessor;
22 use Give\Subscriptions\Models\Subscription;
23 use Give\Subscriptions\ValueObjects\SubscriptionMode;
24 use Give\Subscriptions\ValueObjects\SubscriptionPeriod;
25 use Give\Subscriptions\ValueObjects\SubscriptionStatus;
26
27 /**
28 * Class LegacyPaymentGatewayAdapter
29 * @since 2.18.0
30 */
31 class LegacyPaymentGatewayAdapter
32 {
33 use HandleHttpResponses;
34
35 /**
36 * Get legacy form field markup to display gateway specific payment fields
37 *
38 * @since 2.18.0
39 * @since 2.19.0 Added missing $args parameter for ID prefixing and general backwards compatibility.
40 */
41 public function getLegacyFormFieldMarkup(
42 int $formId,
43 array $args,
44 PaymentGateway $registeredGateway
45 ): string {
46 return $registeredGateway->getLegacyFormFieldMarkup($formId, $args);
47 }
48
49 /**
50 * First we create a payment, then move on to the gateway processing
51 *
52 * @since 3.2.0 Capture exceptions when get gateway data.
53 * @since 3.0.0 Catch and handle errors from the gateway here
54 * @since 2.30.0 Add success, cancel and failed URLs to gateway data. This will be used in both v2 and v3 forms so gateways can just refer to the gateway data.
55 * @since 2.24.0 add support for payment mode
56 * @since 2.21.0 Replace give_insert_payment with donation model. Store legacy subscription data in donation meta.
57 * Attach subscription id to donation.
58 * @since 2.19.0 Replace is_recurring with is_donation_recurring to detect recurring donations.
59 * @since 2.18.0
60 *
61 * @throws Exception
62 */
63 public function handleBeforeGateway(array $legacyDonationData, PaymentGateway $registeredGateway)
64 {
65 $formData = FormData::fromRequest($legacyDonationData);
66
67 $this->validateGatewayNonce($formData->gatewayNonce);
68
69 $this->validateDonationFormStatus($formData->formId);
70
71 $donor = $this->getOrCreateDonor(
72 $formData->donorInfo->wpUserId,
73 $formData->donorInfo->email,
74 $formData->donorInfo->firstName,
75 $formData->donorInfo->lastName,
76 $formData->donorInfo->honorific
77 );
78
79 $donation = $formData->toDonation($donor->id);
80
81 if (give_recurring_is_donation_recurring($legacyDonationData)) {
82 $subscriptionData = SubscriptionData::fromRequest($legacyDonationData);
83
84 $paymentMode = !empty($legacyDonationData['payment_mode']) ? new SubscriptionMode(
85 $legacyDonationData['payment_mode']
86 ) : null;
87
88 if ($paymentMode === null) {
89 $paymentMode = give_is_test_mode() ? SubscriptionMode::TEST() : SubscriptionMode::LIVE();
90 }
91
92 $subscription = Subscription::create([
93 'amount' => $donation->amount,
94 'period' => new SubscriptionPeriod($subscriptionData->period),
95 'frequency' => (int)$subscriptionData->frequency,
96 'donorId' => $donor->id,
97 'installments' => (int)$subscriptionData->times,
98 'status' => SubscriptionStatus::PENDING(),
99 'mode' => $paymentMode,
100 'donationFormId' => $formData->formId,
101 ]);
102
103 $donation->type = DonationType::SUBSCRIPTION();
104 $donation->subscriptionId = $subscription->id;
105 $donation->save();
106
107 give()->subscriptions->updateLegacyParentPaymentId($subscription->id, $donation->id);
108
109 $this->setSession($donation->id);
110
111 try {
112 /**
113 * Filter hook to provide gateway data before initial transaction for subscription is processed by the gateway.
114 *
115 * @since 2.21.2
116 */
117 $gatewayData = apply_filters(
118 "givewp_create_subscription_gateway_data_{$registeredGateway::id()}",
119 (new GetGatewayDataFromRequest())(),
120 $donation,
121 $subscription
122 );
123
124 $gatewayData = $this->addUrlsToGatewayData($donation, $gatewayData, $registeredGateway);
125
126 $controller = new GatewaySubscriptionController($registeredGateway);
127
128 $controller->create($donation, $subscription, $gatewayData);
129 } catch (Exception $exception) {
130 PaymentGatewayLog::error(
131 $exception->getMessage(),
132 [
133 'Payment Gateway' => $registeredGateway::id(),
134 'Donation' => $donation->toArray(),
135 'Subscription' => $subscription->toArray(),
136 ]
137 );
138
139 $message = __(
140 'An unexpected error occurred while processing the subscription. Please try again or contact the site administrator.',
141 'give'
142 );
143
144 $this->handleExceptionResponse($exception, $message);
145 }
146 } else {
147 $donation->type = DonationType::SINGLE();
148 $donation->save();
149
150 $this->setSession($donation->id);
151
152 try {
153 /**
154 * Filter hook to provide gateway data before transaction is processed by the gateway.
155 *
156 * @since 2.21.2
157 */
158 $gatewayData = apply_filters(
159 "givewp_create_payment_gateway_data_{$registeredGateway::id()}",
160 (new GetGatewayDataFromRequest())(),
161 $donation
162 );
163
164 $gatewayData = $this->addUrlsToGatewayData($donation, $gatewayData, $registeredGateway);
165
166 $controller = new GatewayPaymentController($registeredGateway);
167
168 $controller->create($donation, $gatewayData);
169 } catch (Exception $exception) {
170 PaymentGatewayLog::error(
171 $exception->getMessage(),
172 [
173 'Payment Gateway' => $registeredGateway::id(),
174 'Donation' => $donation->toArray(),
175 ]
176 );
177
178 $message = __(
179 'An unexpected error occurred while processing the donation. Please try again or contact the site administrator.',
180 'give'
181 );
182
183 $this->handleExceptionResponse($exception, $message);
184 }
185 }
186 }
187
188 /**
189 * @since 2.30.0
190 */
191 protected function getGatewayDataSuccessUrl(int $donationId): string
192 {
193 $formId = give_get_payment_form_id($donationId);
194 $isEmbedDonationForm = !Utils::isLegacyForm($formId);
195 $donationFormPageUrl = (new DonationAccessor())->get()->formEntry->currentUrl ?: get_permalink($formId);
196
197 return $isEmbedDonationForm ?
198 Utils::createSuccessPageURL($donationFormPageUrl) :
199 give_get_success_page_url();
200 }
201
202 /**
203 * @since 2.30.0
204 */
205 protected function getGatewayDataFailedUrl(int $donationId): string
206 {
207 $formId = give_get_payment_form_id($donationId);
208 $isEmbedDonationForm = !Utils::isLegacyForm($formId);
209 $donationFormPageUrl = (new DonationAccessor())->get()->formEntry->currentUrl ?: get_permalink($formId);
210
211 return $isEmbedDonationForm ?
212 Utils::createFailedPageURL($donationFormPageUrl) :
213 give_get_failed_transaction_uri();
214 }
215
216 /**
217 * @since 2.30.0
218 */
219 protected function getGatewayDataCancelUrl(int $donationId): string
220 {
221 $formId = give_get_payment_form_id($donationId);
222
223 return (new DonationAccessor())->get()->formEntry->currentUrl ?: get_permalink($formId);
224 }
225
226 /**
227 * Validate Gateway Nonce
228 *
229 * @since 2.18.0
230 */
231 private function validateGatewayNonce(string $gatewayNonce)
232 {
233 if (!wp_verify_nonce($gatewayNonce, 'give-gateway')) {
234 wp_die(
235 esc_html__(
236 'We\'re unable to recognize your session. Please refresh the screen to try again; otherwise contact your website administrator for assistance.',
237 'give'
238 ),
239 esc_html__('Error', 'give'),
240 ['response' => 403]
241 );
242 }
243 }
244
245 /**
246 * Validate Donation Form Status
247 *
248 * @since 2.33.2
249 */
250 private function validateDonationFormStatus(int $formId)
251 {
252 $donationForm = DonationForm::find($formId);
253
254 if (!$donationForm || $donationForm->status->isTrash()) {
255 wp_die(
256 esc_html__(
257 'This donation form is not accepting donations.',
258 'give'
259 ),
260 esc_html__('Error', 'give'),
261 ['response' => 403]
262 );
263 }
264 }
265
266 /**
267 * Set donation id to purchase session for use in the donation receipt.
268 *
269 * @since 2.21.0
270 *
271 * @param $donationId
272 *
273 * @return void
274 */
275 private function setSession($donationId)
276 {
277 $purchaseSession = (array)give()->session->get('give_purchase');
278
279 if ($purchaseSession && array_key_exists('purchase_key', $purchaseSession)) {
280 $purchaseSession['donation_id'] = $donationId;
281 give()->session->set('give_purchase', $purchaseSession);
282 }
283 }
284
285 /**
286 * @since 3.2.0 add honorific and use GetOrCreateDonor action
287 * @since 2.21.0
288 *
289 * @throws Exception
290 */
291 private function getOrCreateDonor(
292 ?int $userId,
293 string $donorEmail,
294 string $firstName,
295 string $lastName,
296 ?string $honorific
297 ): Donor {
298 return (new GetOrCreateDonor())(
299 $userId,
300 $donorEmail,
301 $firstName,
302 $lastName,
303 $honorific
304 );
305 }
306
307 /**
308 * @since 2.29.0
309 */
310 public function addOptRefundCheckbox(int $donationId, PaymentGatewayInterface $registeredGateway)
311 {
312 $donation = Donation::find($donationId);
313 if ($donation->gatewayId === $registeredGateway::id()) {
314 ?>
315 <div id="give-gateway-opt-refund-wrap"
316 class="give-gateway-opt-refund give-admin-box-inside give-hidden">
317 <p>
318 <input type="checkbox" id="give-gateway-opt-refund" name="give_gateway_opt_refund" value="1" />
319 <label for="give-gateway-opt-refund">
320 <?php
321 esc_html_e(sprintf('Refund the donation at %s?', $registeredGateway->getName()), 'give');
322 ?>
323 </label>
324 </p>
325 </div>
326 <script>
327 if (!!document.getElementById("give-payment-status") &&
328 1 === document.querySelectorAll("div.give-admin-box > div.give-hidden[id*=\"opt-refund\"] input[type=\"checkbox\"]").length
329 ) {
330 document.getElementById("give-payment-status").addEventListener("change", function(event) {
331 const refundCheckbox = document.getElementById("give-gateway-opt-refund");
332
333 if (null === refundCheckbox) {
334 return;
335 }
336
337 refundCheckbox.checked = false;
338
339 if ("refunded" === event.target.value) {
340 document.getElementById("give-gateway-opt-refund-wrap").style.display = "block";
341 } else {
342 document.getElementById("give-gateway-opt-refund-wrap").style.display = "none";
343 }
344 });
345 }
346 </script>
347 <?php
348 }
349 }
350
351 /**
352 * @since 2.29.0
353 */
354 public function maybeRefundOnGateway(
355 int $donationId,
356 string $newStatus,
357 string $oldStatus,
358 PaymentGateway $registeredGateway
359 ) {
360 $gatewayOptRefund = !empty($_POST['give_gateway_opt_refund']) ? give_clean(
361 $_POST['give_gateway_opt_refund']
362 ) : '';
363 $canProcessRefund = !empty($gatewayOptRefund) ? $gatewayOptRefund : false;
364
365 // Only move forward if refund requested.
366 if (!$canProcessRefund) {
367 return;
368 }
369
370 $donation = Donation::find($donationId);
371 if (
372 $donation->gatewayId === $registeredGateway::id() &&
373 'refunded' === $newStatus &&
374 'refunded' !== $oldStatus
375 ) {
376 $controller = new GatewayPaymentController($registeredGateway);
377 $controller->refund($donation);
378 }
379 }
380
381 /**
382 * @since 2.30.0
383 */
384 protected function addUrlsToGatewayData(Donation $donation, $gatewayData, PaymentGateway $registeredGateway)
385 {
386 return array_merge($gatewayData, [
387 'successUrl' => add_query_arg(
388 ['payment-confirmation' => $registeredGateway::id()],
389 $this->getGatewayDataSuccessUrl($donation->id)
390 ),
391 'cancelUrl' => $this->getGatewayDataCancelUrl($donation->id),
392 'failedUrl' => $this->getGatewayDataFailedUrl($donation->id)
393 ]);
394 }
395 }
396