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