PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.2
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.2
6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 3.6.65 All 196 releases
fluentform / app / Modules / Payments / PaymentMethods / BaseProcessor.php

BaseProcessor.php in Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder 6.2.2, at app/Modules/Payments/PaymentMethods/BaseProcessor.php

1,072 lines 35.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentForm\App\Modules\Payments\PaymentMethods;
4
5 if (!defined('ABSPATH')) {
6 exit; // Exit if accessed directly.
7 }
8
9 use FluentForm\App\Helpers\Helper;
10 use FluentForm\App\Models\Form;
11 use FluentForm\App\Models\OrderItem;
12 use FluentForm\App\Models\Submission;
13 use FluentForm\App\Models\Subscription;
14 use FluentForm\App\Models\SubmissionMeta;
15 use FluentForm\App\Models\Transaction;
16 use FluentForm\App\Modules\Payments\PaymentHelper;
17 use FluentForm\Framework\Helpers\ArrayHelper;
18 use FluentForm\App\Services\Form\SubmissionHandlerService;
19
20 abstract class BaseProcessor
21 {
22 protected $method;
23
24 protected $form = null;
25
26 protected $submission = null;
27
28 protected $submissionId = null;
29
30 public function init()
31 {
32 add_action('fluentform/process_payment_' . $this->method, array($this, 'handlePaymentAction'), 10, 6);
33 }
34
35 public abstract function handlePaymentAction($submissionId, $submissionData, $form, $methodSettings, $hasSubscriptions, $totalPayable);
36
37 public function setSubmissionId($submissionId)
38 {
39 $this->submissionId = $submissionId;
40 }
41
42 public function getSubmissionId()
43 {
44 return $this->submissionId;
45 }
46
47 public function insertTransaction($data)
48 {
49 if (empty($data['transaction_type'])) {
50 $data['transaction_type'] = 'onetime';
51 }
52
53 $data = wp_parse_args($data, $this->getTransactionDefaults());
54
55 if (empty($data['transaction_hash'])) {
56 $data['transaction_hash'] = md5($data['transaction_type'] . '_payment_' . $data['submission_id'] . '-' . $data['form_id'] . '_' . $data['created_at'] . '-' . time() . '-' . wp_rand(100, 999));
57 }
58
59 return Transaction::create($data)->id;
60 }
61
62 public function insertRefund($data)
63 {
64 $submission = $this->getSubmission();
65 $data['created_at'] = current_time('mysql');
66 $data['updated_at'] = current_time('mysql');
67 $data['form_id'] = $submission->form_id;
68 $data['submission_id'] = $submission->id;
69 $data['payment_method'] = $this->method;
70 if (empty($data['transaction_type'])) {
71 $data['transaction_type'] = 'refund';
72 }
73
74 if ($userId = get_current_user_id()) {
75 $data['user_id'] = $userId;
76 }
77
78 if (empty($data['transaction_hash'])) {
79 $data['transaction_hash'] = md5($data['transaction_type'] . '_payment_' . $data['submission_id'] . '-' . $data['form_id'] . '_' . $data['created_at'] . '-' . time() . '-' . wp_rand(100, 999));
80 }
81
82 return Transaction::create($data)->id;
83 }
84
85 public function getTransaction($transactionId, $column = 'id')
86 {
87 return Transaction::where($column, $transactionId)->first();
88 }
89
90 public function getRefund($refundId, $column = 'id')
91 {
92 return Transaction::where($column, $refundId)
93 ->refunds()
94 ->first();
95 }
96
97 public function getTransactionByChargeId($chargeId)
98 {
99 return Transaction::bySubmission($this->submissionId)
100 ->where('charge_id', $chargeId)
101 ->first();
102 }
103
104 public function getLastTransaction($submissionId)
105 {
106 return Transaction::bySubmission($submissionId)
107 ->orderBy('id', 'DESC')
108 ->first();
109 }
110
111 public function changeSubmissionPaymentStatus($newStatus)
112 {
113 do_action_deprecated(
114 'fluentform_before_payment_status_change',
115 [
116 $newStatus,
117 $this->getSubmission()
118 ],
119 FLUENTFORM_FRAMEWORK_UPGRADE,
120 'fluentform/before_payment_status_change',
121 'Use fluentform/before_payment_status_change instead of fluentform_before_payment_status_change.'
122 );
123
124 do_action('fluentform/before_payment_status_change', $newStatus, $this->getSubmission());
125
126 Submission::where('id', $this->submissionId)
127 ->update([
128 'payment_status' => $newStatus,
129 'updated_at' => current_time('mysql')
130 ]);
131
132 $this->submission = null;
133
134 $logData = [
135 'parent_source_id' => $this->getForm()->id,
136 'source_type' => 'submission_item',
137 'source_id' => $this->submissionId,
138 'component' => 'Payment',
139 'status' => 'paid' === $newStatus ? 'success' : $newStatus,
140 'title' => __('Payment Status changed', 'fluentform'),
141 'description' => __('Payment status changed to ', 'fluentform') . $newStatus
142 ];
143
144 do_action('fluentform/log_data', $logData);
145
146 do_action_deprecated(
147 'fluentform_after_payment_status_change',
148 [
149 $newStatus,
150 $this->getSubmission()
151 ],
152 FLUENTFORM_FRAMEWORK_UPGRADE,
153 'fluentform/after_payment_status_change',
154 'Use fluentform/after_payment_status_change instead of fluentform_after_payment_status_change.'
155 );
156
157 do_action('fluentform/after_payment_status_change', $newStatus, $this->getSubmission());
158
159 return true;
160 }
161
162 public function recalculatePaidTotal()
163 {
164 $transactions = Transaction::bySubmission($this->submissionId)
165 ->paid()
166 ->get();
167
168 $total = 0;
169 $subscriptionId = false;
170 $subBillCount = 0;
171
172 foreach ($transactions as $transaction) {
173 $total += $transaction->payment_total;
174 if($transaction->subscription_id) {
175 $subscriptionId = $transaction->subscription_id;
176 $subBillCount += 1;
177 }
178 }
179
180 $refunds = $this->getRefundTotal();
181 if ($refunds) {
182 $total = $total - $refunds;
183 }
184
185 Submission::where('id', $this->submissionId)
186 ->update([
187 'total_paid' => $total,
188 'updated_at' => current_time('mysql')
189 ]);
190
191 if($subscriptionId && $subBillCount) {
192 $this->updateSubscription($subscriptionId, [
193 'bill_count' => $subBillCount
194 ]);
195 }
196 }
197
198 public function getRefundTotal()
199 {
200 $refunds = Transaction::bySubmission($this->submissionId)
201 ->refunds()
202 ->get();
203
204 $total = 0;
205 foreach ($refunds as $refund) {
206 $total += $refund->payment_total;
207 }
208
209 return $total;
210 }
211
212 public function changeTransactionStatus($transactionId, $newStatus)
213 {
214 do_action_deprecated(
215 'fluentform_before_transaction_status_change',
216 [
217 $newStatus,
218 $this->getSubmission(),
219 $transactionId
220 ],
221 FLUENTFORM_FRAMEWORK_UPGRADE,
222 'fluentform/before_transaction_status_change',
223 'Use fluentform/before_transaction_status_change instead of fluentform_before_transaction_status_change.'
224 );
225
226 do_action(
227 'fluentform/before_transaction_status_change',
228 $newStatus,
229 $this->getSubmission(),
230 $transactionId
231 );
232
233 Transaction::where('id', $transactionId)
234 ->update([
235 'status' => $newStatus,
236 'updated_at' => current_time('mysql')
237 ]);
238
239 do_action_deprecated(
240 'fluentform_after_transaction_status_change',
241 [
242 $newStatus,
243 $this->getSubmission(),
244 $transactionId
245 ],
246 FLUENTFORM_FRAMEWORK_UPGRADE,
247 'fluentform/after_transaction_status_change',
248 'Use fluentform/after_transaction_status_change instead of fluentform_after_transaction_status_change.'
249 );
250
251 do_action(
252 'fluentform/after_transaction_status_change',
253 $newStatus,
254 $this->getSubmission(),
255 $transactionId
256 );
257
258 return true;
259 }
260
261 public function updateTransaction($transactionId, $data)
262 {
263 $data['updated_at'] = current_time('mysql');
264
265 return Transaction::where('id', $transactionId)->update($data);
266 }
267
268 public function completePaymentSubmission($isAjax = true)
269 {
270 $returnData = $this->getReturnData();
271 if ($isAjax) {
272 wp_send_json_success($returnData, 200);
273 }
274 return $returnData;
275 }
276
277 public function getReturnData()
278 {
279 $submission = $this->getSubmission();
280 try {
281 $submissionService = new SubmissionHandlerService();
282 if ($this->getMetaData('is_form_action_fired') == 'yes') {
283 $data = $submissionService->getReturnData($submission->id, $this->getForm(),
284 $submission->response);
285
286 $returnData = [
287 'insert_id' => $submission->id,
288 'result' => $data,
289 'error' => ''
290 ];
291 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is checking for payment gateway webhook notification
292 if (!isset($_REQUEST['fluentform_payment_api_notify'])) {
293 // now we have to check if we need this user as auto login
294 if ($loginId = $this->getMetaData('_make_auto_login')) {
295 $this->maybeAutoLogin($loginId, $submission);
296 }
297 }
298 } else {
299 $returnData = $submissionService->processSubmissionData(
300 $this->submissionId, $submission->response, $this->getForm()
301 );
302 $this->setMetaData('is_form_action_fired', 'yes');
303 }
304 return $returnData;
305
306 } catch (\Exception $e) {
307 return [
308 'insert_id' => $submission->id,
309 'result' => '',
310 'error' => $e->getMessage(),
311 ];
312 }
313
314 }
315
316 public function getSubmission()
317 {
318 if (!is_null($this->submission)) {
319 return $this->submission;
320 }
321
322 $submission = Submission::where('id', $this->submissionId)->first();
323
324 if (!$submission) {
325 return false;
326 }
327
328 $submission->response = json_decode($submission->response, true);
329
330 $this->submission = $submission;
331
332 return $this->submission;
333
334 }
335
336 public function getForm()
337 {
338 if (!is_null($this->form)) {
339 return $this->form;
340 }
341
342 $submission = $this->getSubmission();
343
344 $this->form = Form::where('id', $submission->form_id)->first();
345
346 return $this->form;
347 }
348
349 public function getOrderItems()
350 {
351 return OrderItem::bySubmission($this->submissionId)
352 ->products()
353 ->get();
354 }
355
356 public function getDiscountItems()
357 {
358 return OrderItem::bySubmission($this->submissionId)
359 ->discounts()
360 ->get();
361 }
362
363 public function setMetaData($name, $value)
364 {
365 $value = maybe_serialize($value);
366
367 return SubmissionMeta::create([
368 'response_id' => $this->getSubmissionId(),
369 'form_id' => $this->getForm()->id,
370 'meta_key' => $name,
371 'value' => $value,
372 'created_at' => current_time('mysql'),
373 'updated_at' => current_time('mysql')
374 ])->id;
375 }
376
377 public function deleteMetaData($name)
378 {
379 return SubmissionMeta::where('meta_key', $name)
380 ->where('response_id', $this->getSubmissionId())
381 ->delete();
382 }
383
384 public function getMetaData($metaKey)
385 {
386 $meta = SubmissionMeta::where('response_id', $this->getSubmissionId())
387 ->where('meta_key', $metaKey)
388 ->first();
389
390 if ($meta && $meta->value) {
391 return Helper::safeUnserialize($meta->value);
392 }
393
394 return false;
395 }
396
397 public function showPaymentView($returnData)
398 {
399 $redirectUrl = ArrayHelper::get($returnData, 'result.redirectUrl');
400 if ($redirectUrl) {
401 wp_redirect($redirectUrl);
402 exit();
403 }
404
405 $form = $this->getForm();
406
407 if (!empty($returnData['title'])) {
408 $title = $returnData['title'];
409 } else if ($returnData['type'] == 'success') {
410 $title = __('Payment Success', 'fluentform');
411 $title = apply_filters('fluentform/payment_success_title', $title, $this->getSubmission(), $form);
412 } else {
413 $title = __('Payment Failed', 'fluentform');
414 $title = apply_filters('fluentform/payment_failed_title', $title, $this->getSubmission(), $form);
415 }
416
417 $message = $returnData['error'];
418 if (!$message) {
419 $message = $returnData['result']['message'];
420 }
421
422 // Apply payment message filter
423 if ($message) {
424 $message = apply_filters('fluentform/payment_confirmation_message', $message, $this->getSubmission(), $form);
425 }
426
427 $data = [
428 'status' => $returnData['type'],
429 'form' => $form,
430 'title' => $title,
431 'submission' => $this->getSubmission(),
432 'message' => $message,
433 'is_new' => $returnData['is_new'],
434 'data' => $returnData
435 ];
436
437 $data = apply_filters_deprecated(
438 'fluentform_frameless_page_data',
439 [
440 $data
441 ],
442 FLUENTFORM_FRAMEWORK_UPGRADE,
443 'fluentform/frameless_page_data',
444 'Use fluentform/frameless_page_data instead of fluentform_frameless_page_data.'
445 );
446
447 $data = apply_filters('fluentform/frameless_page_data', $data);
448
449 add_filter('pre_get_document_title', function ($title) use ($data) {
450 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- document_title_separator is a WordPress core hook
451 return $data['title'] . ' ' . apply_filters('document_title_separator', '-') . ' ' . $data['form']->title;
452 });
453
454 add_action('wp_enqueue_scripts', function () {
455 wp_enqueue_style('fluent-form-landing', fluentFormMix('css/frameless.css'), [], FLUENTFORM_VERSION);
456 });
457
458 status_header(200);
459 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- loadView() returns complete HTML template with pre-sanitized content
460 echo $this->loadView('frameless/frameless_page_view', $data);
461 exit(200);
462 }
463
464 public function loadView($view, $data = [])
465 {
466 $file = FLUENTFORM_DIR_PATH . 'app/Views/' . $view . '.php';
467 extract($data);
468 ob_start();
469 include($file);
470 return ob_get_clean();
471 }
472
473 public function refund($refund_amount, $transaction, $submission, $method = '', $refundId = '', $refundNote = 'Refunded')
474 {
475 $this->setSubmissionId($submission->id);
476 $status = 'refunded';
477
478 $alreadyRefunded = $this->getRefundTotal();
479 $totalRefund = intval($refund_amount + $alreadyRefunded);
480
481 if ($totalRefund < $transaction->payment_total) {
482 $status = 'partially-refunded';
483 }
484
485 $this->changeTransactionStatus($transaction->id, $status);
486 $this->changeSubmissionPaymentStatus($status);
487 $uniqueHash = md5('refund_' . $submission->id . '-' . $submission->form_id . '-' . time() . '-' . wp_rand(100, 999));
488
489 $refundData = [
490 'form_id' => $submission->form_id,
491 'submission_id' => $submission->id,
492 'transaction_hash' => $uniqueHash,
493 'payment_method' => $transaction->payment_method,
494 'charge_id' => $refundId,
495 'payment_note' => $refundNote,
496 'payment_total' => $refund_amount,
497 'currency' => $transaction->currency,
498 'payment_mode' => $transaction->payment_mode,
499 'created_at' => current_time('mysql'),
500 'updated_at' => current_time('mysql'),
501 'status' => 'refunded',
502 'transaction_type' => 'refund'
503 ];
504
505 $refundId = $this->insertRefund($refundData);
506
507 $logData = [
508 'parent_source_id' => $submission->form_id,
509 'source_type' => 'submission_item',
510 'source_id' => $submission->id,
511 'component' => 'Payment',
512 'status' => 'info',
513 'title' => __('Refund issued', 'fluentform'),
514 'description' => __('Refund issued and refund amount: ', 'fluentform') . number_format($refund_amount / 100, 2)
515 ];
516
517 do_action('fluentform/log_data', $logData);
518
519 $this->recalculatePaidTotal();
520 $refund = $this->getRefund($refundId);
521
522 do_action_deprecated(
523 'fluentform_payment_' . $status . '_' . $method,
524 [
525 $refund,
526 $transaction,
527 $submission
528 ],
529 FLUENTFORM_FRAMEWORK_UPGRADE,
530 'fluentform/payment_' . $status . '_' . $method,
531 'Use fluentform/payment_' . $status . '_' . $method . ' instead of fluentform_payment_' . $status . '_' . $method
532 );
533
534 do_action('fluentform/payment_' . $status . '_' . $method, $refund, $transaction, $submission);
535
536 do_action_deprecated(
537 'fluentform_payment_' . $status,
538 [
539 $refund,
540 $transaction,
541 $submission
542 ],
543 FLUENTFORM_FRAMEWORK_UPGRADE,
544 'fluentform/payment_' . $status,
545 'Use fluentform/payment_' . $status . ' instead of fluentform_payment_' . $status
546 );
547 do_action('fluentform/payment_' . $status, $refund, $transaction, $submission);
548 }
549
550 public function updateRefund($totalRefund, $transaction, $submission, $method = '', $refundId = '', $refundNote = 'Refunded')
551 {
552 if(!$totalRefund) {
553 return;
554 }
555
556 $this->setSubmissionId($submission->id);
557 $existingRefund = Transaction::bySubmission($submission->id)
558 ->refunds()
559 ->first();
560
561 if ($existingRefund) {
562
563 if ($existingRefund->payment_total == $totalRefund) {
564 return;
565 }
566
567 $status = 'refunded';
568 if ($totalRefund < $transaction->payment_total) {
569 $status = 'partially-refunded';
570 }
571 $updateData = [
572 'form_id' => $submission->form_id,
573 'submission_id' => $submission->id,
574 'payment_method' => $transaction->payment_method,
575 'charge_id' => $refundId,
576 'payment_note' => $refundNote,
577 'payment_total' => $totalRefund,
578 'payment_mode' => $transaction->payment_mode,
579 'created_at' => current_time('mysql'),
580 'updated_at' => current_time('mysql'),
581 'status' => 'refunded',
582 'transaction_type' => 'refund'
583 ];
584
585 Transaction::where('id', $existingRefund->id)->update($updateData);
586
587 $existingRefund = Transaction::bySubmission($submission->id)
588 ->refunds()
589 ->first();
590
591 if ($transaction->status != $status) {
592 $this->changeTransactionStatus($transaction->id, $status);
593 }
594
595 do_action_deprecated(
596 'fluentform_payment_refund_updated_' . $method,
597 [
598 $existingRefund,
599 $existingRefund->form_id
600 ],
601 FLUENTFORM_FRAMEWORK_UPGRADE,
602 'fluentform/payment_refund_updated_' . $method,
603 'Use fluentform/payment_refund_updated_' . $method . ' instead of fluentform_payment_refund_updated_' . $method
604 );
605
606 do_action('fluentform/payment_refund_updated_' . $method, $existingRefund, $existingRefund->form_id);
607
608 do_action_deprecated(
609 'fluentform_payment_refund_updated',
610 [
611 $existingRefund,
612 $existingRefund->form_id
613 ],
614 FLUENTFORM_FRAMEWORK_UPGRADE,
615 'fluentform/payment_refund_updated',
616 'Use fluentform/payment_refund_updated instead of fluentform_payment_refund_updated.'
617 );
618
619 do_action('fluentform/payment_refund_updated', $existingRefund, $existingRefund->form_id);
620
621 } else {
622 $this->refund($totalRefund, $transaction, $submission, $method, $refundId, $refundNote);
623 }
624 }
625
626 private function maybeAutoLogin($loginId, $submission)
627 {
628 if (is_user_logged_in() || !$loginId) {
629 return;
630 }
631 if ($loginId != $submission->user_id) {
632 return;
633 }
634
635 wp_clear_auth_cookie();
636 wp_set_current_user($loginId);
637 wp_set_auth_cookie($loginId);
638 $this->deleteMetaData('_make_auto_login');
639 }
640
641 public function getAmountTotal()
642 {
643 $orderItems = $this->getOrderItems();
644
645 $amountTotal = 0;
646 foreach ($orderItems as $item) {
647 $amountTotal += $item->line_total;
648 }
649
650 $discountItems = $this->getDiscountItems();
651 foreach ($discountItems as $discountItem) {
652 $amountTotal -= $discountItem->line_total;
653 }
654
655 return $amountTotal;
656 }
657
658 public function handleSessionRedirectBack($data)
659 {
660 $submissionId = intval($data['fluentform_payment']);
661 $this->setSubmissionId($submissionId);
662
663 $submission = $this->getSubmission();
664
665 $transactionHash = sanitize_text_field($data['transaction_hash']);
666 $transaction = $this->getTransaction($transactionHash, 'transaction_hash');
667
668 if (!$transaction || !$submission) {
669 return;
670 }
671
672 $type = $transaction->status;
673 $form = $this->getForm();
674
675 if ($type == 'paid') {
676 $returnData = $this->getReturnData();
677 } else {
678 $pendingTitle = __('Payment was not marked as paid', 'fluentform');
679 $pendingMessage = __('Looks like you have is still on pending status', 'fluentform');
680 $returnData = [
681 'insert_id' => $submission->id,
682 'title' => apply_filters('fluentform/payment_pending_title', $pendingTitle, $submission, $form),
683 'result' => false,
684 'error' => apply_filters('fluentform/payment_pending_message', $pendingMessage, $submission, $form)
685 ];
686 }
687
688 $returnData['type'] = 'success';
689 $returnData['is_new'] = false;
690
691 $this->showPaymentView($returnData);
692 }
693
694 public function getSubscriptions($status = false)
695 {
696 $subscriptions = Subscription::bySubmission($this->submissionId)
697 ->when($status, function ($q) use ($status) {
698 $q->where('status', $status);
699 })
700 ->get();
701
702 foreach ($subscriptions as $subscription) {
703 $subscription->original_plan = Helper::safeUnserialize($subscription->original_plan);
704 $subscription->vendor_response = Helper::safeUnserialize($subscription->vendor_response);
705 }
706
707 return $subscriptions;
708 }
709
710 public function updateSubscription($id, $data)
711 {
712 $data['updated_at'] = current_time('mysql');
713
714 return Subscription::where('id', $id)->update($data);
715 }
716
717 public function maybeInsertSubscriptionCharge($item)
718 {
719 $exists = Transaction::subscriptionType()
720 ->where('submission_id', $item['submission_id'])
721 ->where('subscription_id', $item['subscription_id'])
722 ->where('charge_id', $item['charge_id'])
723 ->where('payment_method', $item['payment_method'])
724 ->first();
725
726 $isNew = false;
727
728 if ($exists) {
729 // We don't want to update the address and payer email that we already have here
730 if ($exists->billing_address) {
731 unset($item['billing_address']);
732 }
733 if ($exists->payer_email) {
734 unset($item['payer_email']);
735 }
736
737 unset($item['transaction_hash']);
738 unset($item['created_at']);
739
740 Transaction::where('id', $exists->id)->update($item);
741
742 $id = $exists->id;
743 } else {
744 if (empty($item['created_at'])) {
745 $item['created_at'] = current_time('mysql');
746 $item['updated_at'] = current_time('mysql');
747 }
748
749 if (empty($item['transaction_hash'])) {
750 $uniqueHash = md5('subscription_payment_' . $item['submission_id'] . '-' . $item['charge_id'] . '-' . time() . '-' . wp_rand(100, 999));
751 $item['transaction_hash'] = $uniqueHash;
752 }
753
754 $id = Transaction::create($item)->id;
755 $isNew = true;
756 }
757
758
759 $transaction = fluentFormApi('submissions')->transaction($id);
760
761 // We want to update the total amount here
762 $parentSubscription = Subscription::where('id', $transaction->subscription_id)->first();
763
764 // Let's count the total subscription payment
765 if ($parentSubscription) {
766 list($billCount, $paymentTotal) = $this->getPaymentCountsAndTotal($parentSubscription->id);
767
768 Subscription::where('id', $parentSubscription->id)
769 ->update([
770 'bill_count' => $billCount,
771 'payment_total' => $paymentTotal,
772 'updated_at' => current_time('mysql')
773 ]);
774
775 Submission::where('id', $parentSubscription->submission_id)
776 ->update([
777 'payment_total' => $paymentTotal,
778 'total_paid' => $paymentTotal,
779 ]);
780
781 $subscription = Subscription::where('id', $parentSubscription->id)->first();
782
783 if($isNew) {
784 $submission = $this->getSubmission();
785 do_action_deprecated(
786 'fluentform_subscription_received_payment',
787 [
788 $subscription,
789 $submission
790 ],
791 FLUENTFORM_FRAMEWORK_UPGRADE,
792 'fluentform/subscription_received_payment',
793 'Use fluentform/subscription_received_payment instead of fluentform_subscription_received_payment.'
794 );
795 do_action('fluentform/subscription_received_payment', $subscription, $submission);
796
797 do_action_deprecated(
798 'fluentform_subscription_received_payment_' . $submission->payment_method,
799 [
800 $subscription,
801 $submission
802 ],
803 FLUENTFORM_FRAMEWORK_UPGRADE,
804 'fluentform/subscription_received_payment_' . $submission->payment_method,
805 'Use fluentform/subscription_received_payment_' . $submission->payment_method . ' instead of fluentform_subscription_received_payment_' . $submission->payment_method
806 );
807 do_action('fluentform/subscription_received_payment_' . $submission->payment_method, $subscription, $submission);
808 }
809
810 if($subscription->bill_times >= $subscription->bill_count) {
811 // We have to mark the subscription as completed
812 $this->updateSubscriptionStatus($subscription, 'completed');
813 }
814 }
815
816 return $id;
817 }
818
819 public function getPaymentCountsAndTotal($subscriptionId, $paymentMethod = false)
820 {
821 $payments = Transaction::select(['id', 'payment_total'])
822 ->subscriptionType()
823 ->where('subscription_id', $subscriptionId)
824 ->when($paymentMethod, function ($q) use ($paymentMethod) {
825 $q->where('payment_method', $paymentMethod);
826 })
827 ->get();
828
829 $paymentTotal = 0;
830
831 foreach ($payments as $payment) {
832 $paymentTotal += $payment->payment_total;
833 }
834
835 return [count($payments), $paymentTotal];
836 }
837
838 protected function getCancelAtTimeStamp($subscription)
839 {
840 if (!$subscription->bill_times) {
841 return false;
842 }
843
844 $dateTime = current_datetime();
845 $localtime = $dateTime->getTimestamp() + $dateTime->getOffset();
846
847 $billingStartDate = $localtime;
848
849 if ($subscription->expiration_at) {
850 $billingStartDate = strtotime($subscription->expiration_at);
851 }
852
853 $billTimes = $subscription->bill_times;
854
855 $interval = $subscription->billing_interval;
856
857 $interValMaps = [
858 'day' => 'days',
859 'week' => 'weeks',
860 'month' => 'months',
861 'year' => 'years'
862 ];
863
864 if (isset($interValMaps[$interval]) && $billTimes > 1) {
865 $interval = $interValMaps[$interval];
866 }
867
868 return strtotime('+ ' . $billTimes . ' ' . $interval, $billingStartDate);
869 }
870
871 public function updateSubmission($id, $data)
872 {
873 $data['updated_at'] = current_time('mysql');
874
875 return Submission::where('id', $id)->update($data);
876 }
877
878 public function limitLength($string, $limit = 127)
879 {
880 $str_limit = $limit - 3;
881 if (function_exists('mb_strimwidth')) {
882 if (mb_strlen($string) > $limit) {
883 $string = mb_strimwidth($string, 0, $str_limit) . '...';
884 }
885 } else {
886 if (strlen($string) > $limit) {
887 $string = substr($string, 0, $str_limit) . '...';
888 }
889 }
890 return $string;
891 }
892
893 public function getTransactionDefaults()
894 {
895 $submission = $this->getSubmission();
896 if (!$submission) {
897 return [];
898 }
899
900 $data = [];
901
902 if ($customerEmail = PaymentHelper::getCustomerEmail($submission, $this->getForm())) {
903 $data['payer_email'] = $customerEmail;
904 }
905
906 if ($customerName = PaymentHelper::getCustomerName($submission, $this->getForm())) {
907 $data['payer_name'] = $customerName;
908 }
909
910 if ($submission->user_id) {
911 $data['user_id'] = $submission->user_id;
912 } else if ($user = get_user_by('ID', get_current_user_id())) {
913 $data['user_id'] = $user->ID;
914 }
915
916 if (!$submission->user_id && !empty($data['payer_email'])) {
917 $email = $data['payer_email'];
918 $maybeUser = get_user_by('email', $email);
919 if ($maybeUser) {
920
921 $this->updateSubmission($submission->id, [
922 'user_id' => $maybeUser->ID
923 ]);
924
925 if (empty($data['user_id'])) {
926 $data['user_id'] = $maybeUser->ID;
927 }
928 }
929 }
930
931 $address = PaymentHelper::getCustomerAddress($submission);
932 if (!$address) {
933 $address = ArrayHelper::get($submission->response, 'address_1');
934 }
935 if ($address) {
936 $address = array_filter($address);
937 if ($address) {
938 $data['billing_address'] = implode(', ', $address);
939 }
940 }
941
942 $data['created_at'] = current_time('mysql');
943 $data['updated_at'] = current_time('mysql');
944 $data['form_id'] = $submission->form_id;
945 $data['submission_id'] = $submission->id;
946 $data['payment_method'] = $this->method;
947
948 return $data;
949 }
950
951 public function createInitialPendingTransaction($submission = false, $hasSubscriptions = false)
952 {
953 if (!$submission) {
954 $submission = $this->getSubmission();
955 }
956
957 $form = $this->getForm();
958
959 $uniqueHash = md5($submission->id . '-' . $form->id . '-' . time() . '-' . wp_rand(100, 999));
960
961 $transactionData = [
962 'transaction_type' => 'onetime',
963 'transaction_hash' => $uniqueHash,
964 'payment_total' => $this->getAmountTotal(),
965 'status' => 'pending',
966 'currency' => strtoupper($submission->currency),
967 'payment_mode' => $this->getPaymentMode()
968 ];
969 if ($hasSubscriptions) {
970 $subscriptions = $this->getSubscriptions();
971 if ($subscriptions) {
972 $subscriptionInitialTotal = 0;
973 foreach ($subscriptions as $subscription) {
974 if (!$subscription->trial_days) {
975 $subscriptionInitialTotal += $subscription->recurring_amount;
976 }
977 if ($subscription->initial_amount) {
978 $subscriptionInitialTotal += $subscription->initial_amount;
979 }
980 $transactionData['subscription_id'] = $subscription->id;
981 }
982 $transactionData['payment_total'] += $subscriptionInitialTotal;
983 $transactionData['transaction_type'] = 'subscription';
984 }
985 }
986
987 $transactionId = $this->insertTransaction($transactionData);
988
989 $this->updateSubmission($submission->id, [
990 'payment_total' => $transactionData['payment_total']
991 ]);
992
993 return $this->getTransaction($transactionId);
994
995 }
996
997 /**
998 * @param object $subscription
999 * @param string $newStatus
1000 * @param string $note
1001 * @return object
1002 */
1003 public function updateSubscriptionStatus($subscription, $newStatus, $note = '')
1004 {
1005 if (!$note) {
1006 $note = sprintf(
1007 /* translators: 1: new status, 2: old status */
1008 __('Subscription status has been changed to %1$s from %2$s', 'fluentform'),
1009 $newStatus,
1010 $subscription->status
1011 );
1012 }
1013
1014 $oldStatus = $subscription->status;
1015
1016 if($oldStatus == $newStatus) {
1017 return $subscription;
1018 }
1019
1020 Subscription::where('id', $subscription->id)
1021 ->update([
1022 'status' => $newStatus,
1023 'updated_at' => current_time('mysql')
1024 ]);
1025
1026 $logData = [
1027 'parent_source_id' => $this->getForm()->id,
1028 'source_type' => 'submission_item',
1029 'source_id' => $this->submissionId,
1030 'component' => 'Payment',
1031 'status' => 'info',
1032 'title' => __('Subscription Status changed to ', 'fluentform') . $newStatus,
1033 'description' => $note
1034 ];
1035
1036 do_action('fluentform/log_data', $logData);
1037
1038 $subscription->status = $newStatus;
1039
1040 $submission = $this->getSubmission();
1041
1042 do_action_deprecated(
1043 'fluentform_subscription_payment_' . $newStatus,
1044 [
1045 $subscription,
1046 $submission,
1047 false
1048 ],
1049 FLUENTFORM_FRAMEWORK_UPGRADE,
1050 'fluentform/subscription_payment_' . $newStatus,
1051 'Use fluentform/subscription_payment_' . $newStatus . ' instead of fluentform_subscription_payment_' . $newStatus
1052 );
1053
1054 do_action('fluentform/subscription_payment_' . $newStatus, $subscription, $submission, false);
1055
1056 do_action_deprecated(
1057 'fluentform_subscription_payment_' . $newStatus . '_' . $submission->payment_method,
1058 [
1059 $subscription,
1060 $submission,
1061 false
1062 ],
1063 FLUENTFORM_FRAMEWORK_UPGRADE,
1064 'fluentform/subscription_payment_' . $newStatus . '_' . $submission->payment_method,
1065 'Use fluentform/subscription_payment_' . $newStatus . '_' . $submission->payment_method . ' instead of fluentform_subscription_payment_' . $newStatus . '_' . $submission->payment_method
1066 );
1067 do_action('fluentform/subscription_payment_' . $newStatus . '_' . $submission->payment_method, $subscription, $submission, false);
1068
1069 return $subscription;
1070 }
1071 }
1072