PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.0.3
GiveWP – Donation Plugin and Fundraising Platform v3.0.3
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
413 lines
1 <?php
2
3 namespace Give\LegacyPaymentGateways\Adapters;
4
5 use Exception;
6 use Give\DonationForms\V2\Models\DonationForm;
7 use Give\Donations\Models\Donation;
8 use Give\Donations\ValueObjects\DonationType;
9 use Give\Donors\Models\Donor;
10 use Give\Framework\PaymentGateways\Contracts\PaymentGatewayInterface;
11 use Give\Framework\PaymentGateways\Controllers\GatewayPaymentController;
12 use Give\Framework\PaymentGateways\Controllers\GatewaySubscriptionController;
13 use Give\Framework\PaymentGateways\Log\PaymentGatewayLog;
14 use Give\Framework\PaymentGateways\PaymentGateway;
15 use Give\Framework\PaymentGateways\Traits\HandleHttpResponses;
16 use Give\Helpers\Form\Utils;
17 use Give\PaymentGateways\Actions\GetGatewayDataFromRequest;
18 use Give\PaymentGateways\DataTransferObjects\FormData;
19 use Give\PaymentGateways\DataTransferObjects\SubscriptionData;
20 use Give\Session\SessionDonation\DonationAccessor;
21 use Give\Subscriptions\Models\Subscription;
22 use Give\Subscriptions\ValueObjects\SubscriptionMode;
23 use Give\Subscriptions\ValueObjects\SubscriptionPeriod;
24 use Give\Subscriptions\ValueObjects\SubscriptionStatus;
25
26 /**
27 * Class LegacyPaymentGatewayAdapter
28 * @since 2.18.0
29 */
30 class LegacyPaymentGatewayAdapter
31 {
32 use HandleHttpResponses;
33
34 /**
35 * Get legacy form field markup to display gateway specific payment fields
36 *
37 * @since 2.18.0
38 * @since 2.19.0 Added missing $args parameter for ID prefixing and general backwards compatibility.
39 */
40 public function getLegacyFormFieldMarkup(
41 int $formId,
42 array $args,
43 PaymentGateway $registeredGateway
44 ): string {
45 return $registeredGateway->getLegacyFormFieldMarkup($formId, $args);
46 }
47
48 /**
49 * First we create a payment, then move on to the gateway processing
50 *
51 * @since 3.0.0 Catch and handle errors from the gateway here
52 * @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.
53 * @since 2.24.0 add support for payment mode
54 * @since 2.21.0 Replace give_insert_payment with donation model. Store legacy subscription data in donation meta.
55 * Attach subscription id to donation.
56 * @since 2.19.0 Replace is_recurring with is_donation_recurring to detect recurring donations.
57 * @since 2.18.0
58 *
59 * @throws Exception
60 */
61 public function handleBeforeGateway(array $legacyDonationData, PaymentGateway $registeredGateway)
62 {
63 $formData = FormData::fromRequest($legacyDonationData);
64
65 $this->validateGatewayNonce($formData->gatewayNonce);
66
67 $this->validateDonationFormStatus($formData->formId);
68
69 $donor = $this->getOrCreateDonor(
70 $formData->donorInfo->wpUserId,
71 $formData->donorInfo->email,
72 $formData->donorInfo->firstName,
73 $formData->donorInfo->lastName
74 );
75
76 $donation = $formData->toDonation($donor->id);
77
78 if (give_recurring_is_donation_recurring($legacyDonationData)) {
79 $subscriptionData = SubscriptionData::fromRequest($legacyDonationData);
80
81 $paymentMode = !empty($legacyDonationData['payment_mode']) ? new SubscriptionMode(
82 $legacyDonationData['payment_mode']
83 ) : null;
84
85 if ($paymentMode === null) {
86 $paymentMode = give_is_test_mode() ? SubscriptionMode::TEST() : SubscriptionMode::LIVE();
87 }
88
89 $subscription = Subscription::create([
90 'amount' => $donation->amount,
91 'period' => new SubscriptionPeriod($subscriptionData->period),
92 'frequency' => (int)$subscriptionData->frequency,
93 'donorId' => $donor->id,
94 'installments' => (int)$subscriptionData->times,
95 'status' => SubscriptionStatus::PENDING(),
96 'mode' => $paymentMode,
97 'donationFormId' => $formData->formId,
98 ]);
99
100 $donation->type = DonationType::SUBSCRIPTION();
101 $donation->subscriptionId = $subscription->id;
102 $donation->save();
103
104 give()->subscriptions->updateLegacyParentPaymentId($subscription->id, $donation->id);
105
106 $this->setSession($donation->id);
107
108 /**
109 * Filter hook to provide gateway data before initial transaction for subscription is processed by the gateway.
110 *
111 * @since 2.21.2
112 */
113 $gatewayData = apply_filters(
114 "givewp_create_subscription_gateway_data_{$registeredGateway::id()}",
115 (new GetGatewayDataFromRequest)(),
116 $donation,
117 $subscription
118 );
119
120 $gatewayData = $this->addUrlsToGatewayData($donation, $gatewayData, $registeredGateway);
121
122 $controller = new GatewaySubscriptionController($registeredGateway);
123 try {
124 $controller->create($donation, $subscription, $gatewayData);
125 } catch (Exception $exception) {
126 PaymentGatewayLog::error(
127 $exception->getMessage(),
128 [
129 'Payment Gateway' => $registeredGateway::id(),
130 'Donation' => $donation->toArray(),
131 'Subscription' => $subscription->toArray(),
132 ]
133 );
134
135 $message = __(
136 'An unexpected error occurred while processing the subscription. Please try again or contact the site administrator.',
137 'give'
138 );
139
140 $this->handleExceptionResponse($exception, $message);
141 }
142 } else {
143 $donation->type = DonationType::SINGLE();
144 $donation->save();
145
146 $this->setSession($donation->id);
147
148 /**
149 * Filter hook to provide gateway data before transaction is processed by the gateway.
150 *
151 * @since 2.21.2
152 */
153 $gatewayData = apply_filters(
154 "givewp_create_payment_gateway_data_{$registeredGateway::id()}",
155 (new GetGatewayDataFromRequest)(),
156 $donation
157 );
158
159 $gatewayData = $this->addUrlsToGatewayData($donation, $gatewayData, $registeredGateway);
160
161 $controller = new GatewayPaymentController($registeredGateway);
162
163 try {
164 $controller->create($donation, $gatewayData);
165 } catch (Exception $exception) {
166 PaymentGatewayLog::error(
167 $exception->getMessage(),
168 [
169 'Payment Gateway' => $registeredGateway::id(),
170 'Donation' => $donation->toArray(),
171 ]
172 );
173
174 $message = __(
175 'An unexpected error occurred while processing the donation. Please try again or contact the site administrator.',
176 'give'
177 );
178
179 $this->handleExceptionResponse($exception, $message);
180 }
181 }
182 }
183
184 /**
185 * @since 2.30.0
186 */
187 protected function getGatewayDataSuccessUrl(int $donationId): string
188 {
189 $formId = give_get_payment_form_id($donationId);
190 $isEmbedDonationForm = !Utils::isLegacyForm($formId);
191 $donationFormPageUrl = (new DonationAccessor())->get()->formEntry->currentUrl ?: get_permalink($formId);
192
193 return $isEmbedDonationForm ?
194 Utils::createSuccessPageURL($donationFormPageUrl) :
195 give_get_success_page_url();
196 }
197
198 /**
199 * @since 2.30.0
200 */
201 protected function getGatewayDataFailedUrl(int $donationId): string
202 {
203 $formId = give_get_payment_form_id($donationId);
204 $isEmbedDonationForm = !Utils::isLegacyForm($formId);
205 $donationFormPageUrl = (new DonationAccessor())->get()->formEntry->currentUrl ?: get_permalink($formId);
206
207 return $isEmbedDonationForm ?
208 Utils::createFailedPageURL($donationFormPageUrl) :
209 give_get_failed_transaction_uri();
210 }
211
212 /**
213 * @since 2.30.0
214 */
215 protected function getGatewayDataCancelUrl(int $donationId): string
216 {
217 $formId = give_get_payment_form_id($donationId);
218
219 return (new DonationAccessor())->get()->formEntry->currentUrl ?: get_permalink($formId);
220 }
221
222 /**
223 * Validate Gateway Nonce
224 *
225 * @since 2.18.0
226 */
227 private function validateGatewayNonce(string $gatewayNonce)
228 {
229 if (!wp_verify_nonce($gatewayNonce, 'give-gateway')) {
230 wp_die(
231 esc_html__(
232 'We\'re unable to recognize your session. Please refresh the screen to try again; otherwise contact your website administrator for assistance.',
233 'give'
234 ),
235 esc_html__('Error', 'give'),
236 ['response' => 403]
237 );
238 }
239 }
240
241 /**
242 * Validate Donation Form Status
243 *
244 * @since 2.33.2
245 */
246 private function validateDonationFormStatus(int $formId)
247 {
248 $donationForm = DonationForm::find($formId);
249
250 if (!$donationForm || $donationForm->status->isTrash()) {
251 wp_die(
252 esc_html__(
253 'This donation form is not accepting donations.',
254 'give'
255 ),
256 esc_html__('Error', 'give'),
257 ['response' => 403]
258 );
259 }
260 }
261
262 /**
263 * Set donation id to purchase session for use in the donation receipt.
264 *
265 * @since 2.21.0
266 *
267 * @param $donationId
268 *
269 * @return void
270 */
271 private function setSession($donationId)
272 {
273 $purchaseSession = (array)give()->session->get('give_purchase');
274
275 if ($purchaseSession && array_key_exists('purchase_key', $purchaseSession)) {
276 $purchaseSession['donation_id'] = $donationId;
277 give()->session->set('give_purchase', $purchaseSession);
278 }
279 }
280
281 /**
282 * @since 2.21.0
283 *
284 * @param int|null $userId
285 * @param string $donorEmail
286 * @param string $firstName
287 * @param string $lastName
288 *
289 * @return Donor
290 * @throws Exception
291 */
292 private function getOrCreateDonor(
293 int $userId,
294 string $donorEmail,
295 string $firstName,
296 string $lastName
297 ): Donor {
298 // first check if donor exists as a user
299 $donor = Donor::whereUserId($userId);
300
301 // If they exist as a donor & user then make sure they don't already own this email before adding to their additional emails list..
302 if ($donor && !$donor->hasEmail($donorEmail)) {
303 $donor->additionalEmails = array_merge($donor->additionalEmails ?? [], [$donorEmail]);
304 $donor->save();
305 }
306
307 // if donor is not a user than check for any donor matching this email
308 if (!$donor) {
309 $donor = Donor::whereEmail($donorEmail);
310 }
311
312 // if no donor exists then create a new one using their personal information from the form.
313 if (!$donor) {
314 $donor = Donor::create([
315 'name' => trim("$firstName $lastName"),
316 'firstName' => $firstName,
317 'lastName' => $lastName,
318 'email' => $donorEmail,
319 'userId' => $userId ?: null,
320 ]);
321 }
322
323 return $donor;
324 }
325
326 /**
327 * @since 2.29.0
328 */
329 public function addOptRefundCheckbox(int $donationId, PaymentGatewayInterface $registeredGateway)
330 {
331 $donation = Donation::find($donationId);
332 if ($donation->gatewayId === $registeredGateway::id()) {
333 ?>
334 <div id="give-gateway-opt-refund-wrap"
335 class="give-gateway-opt-refund give-admin-box-inside give-hidden">
336 <p>
337 <input type="checkbox" id="give-gateway-opt-refund" name="give_gateway_opt_refund" value="1" />
338 <label for="give-gateway-opt-refund">
339 <?php
340 esc_html_e(sprintf('Refund the donation at %s?', $registeredGateway->getName()), 'give');
341 ?>
342 </label>
343 </p>
344 </div>
345 <script>
346 if (!!document.getElementById("give-payment-status") &&
347 1 === document.querySelectorAll("div.give-admin-box > div.give-hidden[id*=\"opt-refund\"] input[type=\"checkbox\"]").length
348 ) {
349 document.getElementById("give-payment-status").addEventListener("change", function(event) {
350 const refundCheckbox = document.getElementById("give-gateway-opt-refund");
351
352 if (null === refundCheckbox) {
353 return;
354 }
355
356 refundCheckbox.checked = false;
357
358 if ("refunded" === event.target.value) {
359 document.getElementById("give-gateway-opt-refund-wrap").style.display = "block";
360 } else {
361 document.getElementById("give-gateway-opt-refund-wrap").style.display = "none";
362 }
363 });
364 }
365 </script>
366 <?php
367 }
368 }
369
370 /**
371 * @since 2.29.0
372 */
373 public function maybeRefundOnGateway(
374 int $donationId,
375 string $newStatus,
376 string $oldStatus,
377 PaymentGateway $registeredGateway
378 ) {
379 $gatewayOptRefund = !empty($_POST['give_gateway_opt_refund']) ? give_clean(
380 $_POST['give_gateway_opt_refund']
381 ) : '';
382 $canProcessRefund = !empty($gatewayOptRefund) ? $gatewayOptRefund : false;
383
384 // Only move forward if refund requested.
385 if (!$canProcessRefund) {
386 return;
387 }
388
389 $donation = Donation::find($donationId);
390 if ($donation->gatewayId === $registeredGateway::id() &&
391 'refunded' === $newStatus &&
392 'refunded' !== $oldStatus) {
393 $controller = new GatewayPaymentController($registeredGateway);
394 $controller->refund($donation);
395 }
396 }
397
398 /**
399 * @since 2.30.0
400 */
401 protected function addUrlsToGatewayData(Donation $donation, $gatewayData, PaymentGateway $registeredGateway)
402 {
403 return array_merge($gatewayData, [
404 'successUrl' => add_query_arg(
405 ['payment-confirmation' => $registeredGateway::id()],
406 $this->getGatewayDataSuccessUrl($donation->id)
407 ),
408 'cancelUrl' => $this->getGatewayDataCancelUrl($donation->id),
409 'failedUrl' => $this->getGatewayDataFailedUrl($donation->id)
410 ]);
411 }
412 }
413