PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.16.9
GiveWP – Donation Plugin and Fundraising Platform v4.16.9
4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.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 All 255 releases
give / includes / payments / functions.php

functions.php in GiveWP – Donation Plugin and Fundraising Platform 4.16.9, at includes/payments/functions.php

1,947 lines 51.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Payment Functions
4 *
5 * @package Give
6 * @subpackage Payments
7 * @copyright Copyright (c) 2016, GiveWP
8 * @license https://opensource.org/licenses/gpl-license GNU Public License
9 * @since 1.0
10 */
11
12 // Exit if accessed directly.
13 use Give\Donations\Models\Donation;
14 use Give\Helpers\Form\Utils;
15 use Give\ValueObjects\Money;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20
21 /**
22 * Get Payments
23 *
24 * Retrieve payments from the database.
25 *
26 * Since 1.0, this function takes an array of arguments, instead of individual
27 * parameters. All of the original parameters remain, but can be passed in any
28 * order via the array.
29 *
30 * @since 1.0
31 *
32 * @param array $args {
33 * Optional. Array of arguments passed to payments query.
34 *
35 * @type int $offset The number of payments to offset before retrieval.
36 * Default is 0.
37 * @type int $number The number of payments to query for. Use -1 to request all
38 * payments. Default is 20.
39 * @type string $mode Default is 'live'.
40 * @type string $order Designates ascending or descending order of payments.
41 * Accepts 'ASC', 'DESC'. Default is 'DESC'.
42 * @type string $orderby Sort retrieved payments by parameter. Default is 'ID'.
43 * @type string $status The status of the payments. Default is 'any'.
44 * @type string $user User. Default is null.
45 * @type string $meta_key Custom field key. Default is null.
46 *
47 * }
48 *
49 * @return array $payments Payments retrieved from the database
50 */
51 function give_get_payments( $args = [] ) {
52
53 // Fallback to post objects to ensure backwards compatibility.
54 if ( ! isset( $args['output'] ) ) {
55 $args['output'] = 'posts';
56 }
57
58 $args = apply_filters( 'give_get_payments_args', $args );
59 $payments = new Give_Payments_Query( $args );
60
61 return $payments->get_payments();
62 }
63
64 /**
65 * Retrieve payment by a given field
66 *
67 * @since 1.0
68 *
69 * @param string $field The field to retrieve the payment with.
70 * @param mixed $value The value for $field.
71 *
72 * @return mixed
73 */
74 function give_get_payment_by( $field = '', $value = '' ) {
75
76 if ( empty( $field ) || empty( $value ) ) {
77 return false;
78 }
79
80 switch ( strtolower( $field ) ) {
81
82 case 'id':
83 $payment = new Give_Payment( $value );
84 $id = $payment->ID;
85
86 if ( empty( $id ) ) {
87 return false;
88 }
89
90 break;
91
92 case 'key':
93 $payment = give_get_payments(
94 [
95 'meta_key' => '_give_payment_purchase_key',
96 'meta_value' => $value,
97 'posts_per_page' => 1,
98 'fields' => 'ids',
99 ]
100 );
101
102 if ( $payment ) {
103 $payment = new Give_Payment( $payment[0] );
104 }
105
106 break;
107
108 case 'payment_number':
109 $payment = give_get_payments(
110 [
111 'meta_key' => '_give_payment_number',
112 'meta_value' => $value,
113 'posts_per_page' => 1,
114 'fields' => 'ids',
115 ]
116 );
117
118 if ( $payment ) {
119 $payment = new Give_Payment( $payment[0] );
120 }
121
122 break;
123
124 default:
125 return false;
126 }// End switch().
127
128 if ( $payment ) {
129 return $payment;
130 }
131
132 return false;
133 }
134
135 /**
136 * Derive Campaign ID from Form ID
137 *
138 * Automatically derives a campaign ID from a form ID when a campaign exists for that form.
139 * This function provides a centralized way to handle campaign ID derivation across different
140 * parts of the codebase.
141 *
142 * @since 4.3.2
143 *
144 * @param int $form_id The form ID to derive the campaign ID from.
145 *
146 * @return int The derived campaign ID, or 0 if no campaign is found.
147 */
148 function give_derive_campaign_id_from_form_id( $form_id ) {
149 $derived_campaign_id = 0;
150
151 // Method 1: Use modern Campaign model (if available)
152 if ( class_exists( 'Give\\Campaigns\\Models\\Campaign' ) ) {
153 $campaign = \Give\Campaigns\Models\Campaign::findByFormId( $form_id );
154 if ( $campaign ) {
155 $derived_campaign_id = $campaign->id;
156 }
157 }
158
159 // Method 2: Fallback to direct database query
160 if ( ! $derived_campaign_id && class_exists( 'Give\\Framework\\Database\\DB' ) ) {
161 $campaign_id_from_db = \Give\Framework\Database\DB::table( 'give_campaign_forms' )
162 ->where( 'form_id', $form_id )
163 ->value( 'campaign_id' );
164
165 if ( $campaign_id_from_db ) {
166 $derived_campaign_id = (int) $campaign_id_from_db;
167 }
168 }
169
170 /**
171 * Filter the derived campaign ID.
172 *
173 * @since 4.3.2
174 *
175 * @param int $derived_campaign_id The derived campaign ID.
176 * @param int $form_id The form ID used for derivation.
177 * @return int The derived campaign ID.
178 */
179 return apply_filters( 'give_derive_campaign_id_from_form_id', $derived_campaign_id, $form_id );
180 }
181
182 /**
183 * Insert Payment
184 *
185 * @since 1.0
186 *
187 * @param array $payment_data Arguments passed.
188 *
189 * @return int|bool Payment ID if payment is inserted, false otherwise.
190 */
191 function give_insert_payment( $payment_data = [] ) {
192
193 if ( empty( $payment_data ) ) {
194 return false;
195 }
196
197 /**
198 * Fire the filter on donation data before insert.
199 *
200 * @since 1.8.15
201 *
202 * @param array $payment_data Arguments passed.
203 */
204 $payment_data = apply_filters( 'give_pre_insert_payment', $payment_data );
205
206 $payment = new Give_Payment();
207 $gateway = ! empty( $payment_data['gateway'] ) ? $payment_data['gateway'] : '';
208 $gateway = empty( $gateway ) && isset( $_POST['give-gateway'] ) ? give_clean( $_POST['give-gateway'] ) : $gateway; // WPCS: input var ok, sanitization ok, CSRF ok.
209 $form_id = isset( $payment_data['give_form_id'] ) ? $payment_data['give_form_id'] : 0;
210 $price_id = give_get_payment_meta_price_id( $payment_data );
211 $form_title = isset( $payment_data['give_form_title'] ) ? $payment_data['give_form_title'] : get_the_title( $form_id );
212
213 // Set properties.
214 $payment->total = $payment_data['price'];
215 $payment->status = ! empty( $payment_data['status'] ) ? $payment_data['status'] : 'pending';
216 $payment->currency = ! empty( $payment_data['currency'] ) ? $payment_data['currency'] : give_get_currency( $payment_data['give_form_id'], $payment_data );
217 $payment->user_info = $payment_data['user_info'];
218 $payment->gateway = $gateway;
219 $payment->form_title = $form_title;
220 $payment->form_id = $form_id;
221
222 // Set campaign_id: Use explicit value if provided, otherwise derive from form_id
223 if ( ! empty( $payment_data['campaign_id'] ) ) {
224 $payment->campaign_id = $payment_data['campaign_id'];
225 } else {
226 // Try to automatically derive campaign_id from form_id
227 $derived_campaign_id = give_derive_campaign_id_from_form_id( $form_id );
228 $payment->campaign_id = $derived_campaign_id;
229 }
230
231 $payment->price_id = $price_id;
232 $payment->donor_id = ( ! empty( $payment_data['donor_id'] ) ? $payment_data['donor_id'] : '' );
233 $payment->user_id = $payment_data['user_info']['id'];
234 $payment->first_name = $payment_data['user_info']['first_name'];
235 $payment->last_name = $payment_data['user_info']['last_name'];
236 $payment->title_prefix = ! empty( $payment_data['user_info']['title'] ) ? $payment_data['user_info']['title'] : '';
237 $payment->email = $payment_data['user_info']['email'];
238 $payment->ip = give_get_ip();
239 $payment->key = $payment_data['purchase_key'];
240 $payment->mode = ( ! empty( $payment_data['mode'] ) ? (string) $payment_data['mode'] : ( give_is_test_mode() ? 'test' : 'live' ) );
241 $payment->parent_payment = ! empty( $payment_data['parent'] ) ? absint( $payment_data['parent'] ) : '';
242
243 // Add the donation.
244 $args = [
245 'price' => $payment->total,
246 'price_id' => $payment->price_id,
247 ];
248
249 $payment->add_donation( $payment->form_id, $args );
250
251 // Set date if present.
252 if ( isset( $payment_data['post_date'] ) ) {
253 $payment->date = $payment_data['post_date'];
254 }
255
256 // Save payment.
257 $payment->save();
258
259 // Setup donor id.
260 $payment_data['user_info']['donor_id'] = $payment->donor_id;
261
262 // Set donation id to purchase session only donor session for donation exist.
263 $purchase_session = (array) Give()->session->get( 'give_purchase' );
264 if ( $purchase_session && array_key_exists( 'purchase_key', $purchase_session ) ) {
265 $purchase_session['donation_id'] = $payment->ID;
266 Give()->session->set( 'give_purchase', $purchase_session );
267 }
268
269 /**
270 * Fires while inserting payments.
271 *
272 * @since 1.0
273 *
274 * @param int $payment_id The payment ID.
275 * @param array $payment_data Arguments passed.
276 */
277 do_action( 'give_insert_payment', $payment->ID, $payment_data );
278
279 // Return payment ID upon success.
280 if ( ! empty( $payment->ID ) ) {
281 return $payment->ID;
282 }
283
284 // Return false if no payment was inserted.
285 return false;
286
287 }
288
289 /**
290 * Create payment.
291 *
292 * @param $payment_data
293 *
294 * @return bool|int
295 */
296 function give_create_payment( $payment_data ) {
297
298 $form_id = intval( $payment_data['post_data']['give-form-id'] );
299 $price_id = isset( $payment_data['post_data']['give-price-id'] ) ? $payment_data['post_data']['give-price-id'] : '';
300
301 // Collect payment data.
302 $insert_payment_data = [
303 'price' => $payment_data['price'],
304 'give_form_title' => $payment_data['post_data']['give-form-title'],
305 'give_form_id' => $form_id,
306 'give_price_id' => $price_id,
307 'date' => $payment_data['date'],
308 'user_email' => $payment_data['user_email'],
309 'purchase_key' => $payment_data['purchase_key'],
310 'currency' => give_get_currency( $form_id, $payment_data ),
311 'user_info' => $payment_data['user_info'],
312 'status' => 'pending',
313 'gateway' => 'paypal',
314 ];
315
316 /**
317 * Filter the payment params.
318 *
319 * @since 1.8
320 *
321 * @param array $insert_payment_data
322 */
323 $insert_payment_data = apply_filters( 'give_create_payment', $insert_payment_data );
324
325 // Record the pending payment.
326 return give_insert_payment( $insert_payment_data );
327 }
328
329 /**
330 * Updates a payment status.
331 *
332 * @param int $payment_id Payment ID.
333 * @param string $new_status New Payment Status. Default is 'publish'.
334 *
335 * @since 1.0
336 *
337 * @return bool
338 */
339 function give_update_payment_status( $payment_id, $new_status = 'publish' ) {
340
341 $updated = false;
342 $payment = new Give_Payment( $payment_id );
343
344 if ( $payment && $payment->ID > 0 ) {
345
346 $payment->status = $new_status;
347 $updated = $payment->save();
348
349 }
350
351 return $updated;
352 }
353
354
355 /**
356 * Deletes a Donation
357 *
358 * @since 1.0
359 *
360 * @param int $payment_id Payment ID (default: 0).
361 * @param bool $update_donor If we should update the donor stats (default:true).
362 *
363 * @return void
364 */
365 function give_delete_donation( $payment_id = 0, $update_donor = true ) {
366 $payment = new Give_Payment( $payment_id );
367
368 // Bailout.
369 if ( ! $payment->ID ) {
370 return;
371 }
372
373 $amount = give_donation_amount( $payment_id );
374 $status = $payment->post_status;
375 $donor = new Give_Donor( $payment->donor_id );
376
377 // Only undo donations that aren't these statuses.
378 $dont_undo_statuses = apply_filters(
379 'give_undo_donation_statuses',
380 [
381 'pending',
382 'cancelled',
383 ]
384 );
385
386 if ( ! in_array( $status, $dont_undo_statuses ) ) {
387 give_undo_donation( $payment_id );
388 }
389
390 // Only undo donations that aren't these statuses.
391 $status_to_decrease_stats = apply_filters( 'give_decrease_donor_statuses', [ 'publish' ] );
392
393 if ( in_array( $status, $status_to_decrease_stats ) ) {
394
395 // Only decrease earnings if they haven't already been decreased (or were never increased for this payment).
396 give_decrease_total_earnings( $amount );
397
398 // @todo: Refresh only range related stat cache
399 give_delete_donation_stats();
400
401 if ( $donor->id && $update_donor ) {
402
403 // Decrement the stats for the donor.
404 $donor->decrease_donation_count();
405 $donor->decrease_value( $amount );
406
407 }
408 }
409
410 /**
411 * Fires before deleting payment.
412 *
413 * @param int $payment_id Payment ID.
414 *
415 * @since 1.0
416 */
417 do_action( 'give_payment_delete', $payment_id );
418
419 if ( $donor->id && $update_donor ) {
420 // Remove the payment ID from the donor.
421 $donor->remove_payment( $payment_id );
422 }
423
424 // Remove the payment.
425 wp_delete_post( $payment_id, true );
426
427 Give()->payment_meta->delete_all_meta( $payment_id );
428
429 /**
430 * Fires after payment deleted.
431 *
432 * @param int $payment_id Payment ID.
433 *
434 * @since 1.0
435 */
436 do_action( 'give_payment_deleted', $payment_id );
437 }
438
439 /**
440 * Undo Donation
441 *
442 * Undoes a donation, including the decrease of donations and earning stats.
443 * Used for when refunding or deleting a donation.
444 *
445 * @param int $payment_id Payment ID.
446 *
447 * @since 1.0
448 *
449 * @return void
450 */
451 function give_undo_donation( $payment_id ) {
452
453 $payment = new Give_Payment( $payment_id );
454
455 $maybe_decrease_earnings = apply_filters( 'give_decrease_earnings_on_undo', true, $payment, $payment->form_id );
456 if ( true === $maybe_decrease_earnings ) {
457 // Decrease earnings.
458 give_decrease_form_earnings( $payment->form_id, $payment->total, $payment_id );
459 }
460
461 $maybe_decrease_donations = apply_filters( 'give_decrease_donations_on_undo', true, $payment, $payment->form_id );
462 if ( true === $maybe_decrease_donations ) {
463 // Decrease donation count.
464 give_decrease_donation_count( $payment->form_id );
465 }
466
467 }
468
469
470 /**
471 * Count Payments
472 *
473 * Returns the total number of payments recorded.
474 *
475 * @param array $args Arguments passed.
476 *
477 * @since 1.0
478 *
479 * @return object $stats Contains the number of payments per payment status.
480 */
481 function give_count_payments( $args = [] ) {
482 // Backward compatibility.
483 if ( ! empty( $args['start-date'] ) ) {
484 $args['start_date'] = $args['start-date'];
485 unset( $args['start-date'] );
486 }
487
488 if ( ! empty( $args['end-date'] ) ) {
489 $args['end_date'] = $args['end-date'];
490 unset( $args['end-date'] );
491 }
492
493 if ( ! empty( $args['form_id'] ) ) {
494 $args['give_forms'] = $args['form_id'];
495 unset( $args['form_id'] );
496 }
497
498 // Extract all donations
499 $args['number'] = - 1;
500 $args['group_by'] = 'post_status';
501 $args['count'] = 'true';
502
503 $donations_obj = new Give_Payments_Query( $args );
504 $donations_count = $donations_obj->get_payment_by_group();
505
506 /**
507 * Filter the payment counts group by status
508 *
509 * @since 1.0
510 */
511 return (object) apply_filters( 'give_count_payments', $donations_count, $args, $donations_obj );
512 }
513
514
515 /**
516 * Check For Existing Payment
517 *
518 * @param int $payment_id Payment ID.
519 *
520 * @since 1.0
521 *
522 * @return bool $exists True if payment exists, false otherwise.
523 */
524 function give_check_for_existing_payment( $payment_id ) {
525 global $wpdb;
526
527 return (bool) $wpdb->get_var(
528 $wpdb->prepare(
529 "
530 SELECT ID
531 FROM {$wpdb->posts}
532 WHERE ID=%s
533 AND post_status=%s
534 ",
535 $payment_id,
536 'publish'
537 )
538 );
539 }
540
541 /**
542 * Get Payment Status
543 *
544 * @param WP_Post|Give_Payment|int $payment_id Payment object or payment ID.
545 * @param bool $return_label Whether to return the translated status label instead of status value.
546 * Default false.
547 *
548 * @since 1.0
549 *
550 * @return bool|mixed True if payment status exists, false otherwise.
551 */
552 function give_get_payment_status( $payment_id, $return_label = false ) {
553
554 if ( ! is_numeric( $payment_id ) ) {
555 if (
556 $payment_id instanceof Give_Payment
557 || $payment_id instanceof WP_Post
558 ) {
559 $payment_id = $payment_id->ID;
560 }
561 }
562
563 if ( ! $payment_id > 0 ) {
564 return false;
565 }
566
567 $payment_status = get_post_status( $payment_id );
568
569 $statuses = give_get_payment_statuses();
570
571 if ( empty( $payment_status ) || ! is_array( $statuses ) || empty( $statuses ) ) {
572 return false;
573 }
574
575 if ( array_key_exists( $payment_status, $statuses ) ) {
576 if ( true === $return_label ) {
577 // Return translated status label.
578 return $statuses[ $payment_status ];
579 } else {
580 // Account that our 'publish' status is labeled 'Complete'
581 $post_status = 'publish' === $payment_status ? 'Complete' : $payment_status;
582
583 // Make sure we're matching cases, since they matter
584 return array_search( strtolower( $post_status ), array_map( 'strtolower', $statuses ) );
585 }
586 }
587
588 return false;
589 }
590
591 /**
592 * Retrieves all available statuses for payments.
593 *
594 * @since 1.0
595 *
596 * @return array $payment_status All the available payment statuses.
597 */
598 function give_get_payment_statuses() {
599 $payment_statuses = [
600 'pending' => __( 'Pending', 'give' ),
601 'publish' => __( 'Complete', 'give' ),
602 'refunded' => __( 'Refunded', 'give' ),
603 'failed' => __( 'Failed', 'give' ),
604 'cancelled' => __( 'Cancelled', 'give' ),
605 'abandoned' => __( 'Abandoned', 'give' ),
606 'preapproval' => __( 'Pre-Approved', 'give' ),
607 'processing' => __( 'Processing', 'give' ),
608 'revoked' => __( 'Revoked', 'give' ),
609 ];
610
611 return apply_filters( 'give_payment_statuses', $payment_statuses );
612 }
613
614 /**
615 * Get Payment Status Keys
616 *
617 * Retrieves keys for all available statuses for payments
618 *
619 * @since 1.0
620 *
621 * @return array $payment_status All the available payment statuses.
622 */
623 function give_get_payment_status_keys() {
624 $statuses = array_keys( give_get_payment_statuses() );
625 asort( $statuses );
626
627 return array_values( $statuses );
628 }
629
630 /**
631 * Get Earnings By Date
632 *
633 * @param int $day Day number. Default is null.
634 * @param int $month_num Month number. Default is null.
635 * @param int $year Year number. Default is null.
636 * @param int $hour Hour number. Default is null.
637 *
638 * @since 1.0
639 *
640 * @since 2.12.0 default value for the $day parameter is removed to prevent PHP8 warnings.
641 *
642 * @return int $earnings Earnings
643 */
644 function give_get_earnings_by_date( $day, $month_num, $year = null, $hour = null ) {
645 // This is getting deprecated soon. Use Give_Payment_Stats with the get_earnings() method instead.
646 global $wpdb;
647
648 $args = [
649 'post_type' => 'give_payment',
650 'nopaging' => true,
651 'year' => $year,
652 'monthnum' => $month_num,
653 'post_status' => [ 'publish' ],
654 'fields' => 'ids',
655 'update_post_term_cache' => false,
656 ];
657 if ( ! empty( $day ) ) {
658 $args['day'] = $day;
659 }
660
661 if ( isset( $hour ) ) {
662 $args['hour'] = $hour;
663 }
664
665 $args = apply_filters( 'give_get_earnings_by_date_args', $args );
666 $key = Give_Cache::get_key( 'give_stats', $args );
667
668 if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
669 $earnings = false;
670 } else {
671 $earnings = Give_Cache::get( $key );
672 }
673
674 if ( false === $earnings ) {
675 $donations = get_posts( $args );
676 $earnings = 0;
677
678 $donation_table = Give()->payment_meta->table_name;
679 $donation_table_col = Give()->payment_meta->get_meta_type() . '_id';
680
681 if ( $donations ) {
682 $donations = implode( ',', $donations );
683 $earning_totals = $wpdb->get_var( "SELECT SUM(meta_value) FROM {$donation_table} WHERE meta_key = '_give_payment_total' AND {$donation_table_col} IN ({$donations})" );
684
685 /**
686 * Filter The earnings by dates.
687 *
688 * @since 1.8.17
689 *
690 * @param float $earning_totals Total earnings between the dates.
691 * @param array $donations Donations lists.
692 * @param array $args Donation query args.
693 */
694 $earnings = apply_filters( 'give_get_earnings_by_date', $earning_totals, $donations, $args );
695 }
696 // Cache the results for one hour.
697 Give_Cache::set( $key, $earnings, HOUR_IN_SECONDS );
698 }
699
700 return round( $earnings, 2 );
701 }
702
703 /**
704 * Get Donations (sales) By Date
705 *
706 * @param int $day Day number. Default is null.
707 * @param int $month_num Month number. Default is null.
708 * @param int $year Year number. Default is null.
709 * @param int $hour Hour number. Default is null.
710 *
711 * @since 1.0
712 *
713 * @return int $count Sales
714 */
715 function give_get_sales_by_date( $day = null, $month_num = null, $year = null, $hour = null ) {
716
717 // This is getting deprecated soon. Use Give_Payment_Stats with the get_sales() method instead.
718 $args = [
719 'post_type' => 'give_payment',
720 'nopaging' => true,
721 'year' => $year,
722 'fields' => 'ids',
723 'post_status' => [ 'publish' ],
724 'update_post_meta_cache' => false,
725 'update_post_term_cache' => false,
726 ];
727
728 $show_free = apply_filters( 'give_sales_by_date_show_free', true, $args );
729
730 if ( false === $show_free ) {
731 $args['meta_query'] = [
732 [
733 'key' => '_give_payment_total',
734 'value' => 0,
735 'compare' => '>',
736 'type' => 'NUMERIC',
737 ],
738 ];
739 }
740
741 if ( ! empty( $month_num ) ) {
742 $args['monthnum'] = $month_num;
743 }
744
745 if ( ! empty( $day ) ) {
746 $args['day'] = $day;
747 }
748
749 if ( isset( $hour ) ) {
750 $args['hour'] = $hour;
751 }
752
753 $args = apply_filters( 'give_get_sales_by_date_args', $args );
754
755 $key = Give_Cache::get_key( 'give_stats', $args );
756
757 if ( ! empty( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'give-refresh-reports' ) ) {
758 $count = false;
759 } else {
760 $count = Give_Cache::get( $key );
761 }
762
763 if ( false === $count ) {
764 $donations = new WP_Query( $args );
765 $count = (int) $donations->post_count;
766 // Cache the results for one hour.
767 Give_Cache::set( $key, $count, HOUR_IN_SECONDS );
768 }
769
770 return $count;
771 }
772
773 /**
774 * Checks whether a payment has been marked as complete.
775 *
776 * @param int $payment_id Payment ID to check against.
777 *
778 * @since 1.0
779 *
780 * @return bool $ret True if complete, false otherwise.
781 */
782 function give_is_payment_complete( $payment_id ) {
783 $ret = false;
784 $payment_status = '';
785
786 if ( $payment_id > 0 && 'give_payment' === get_post_type( $payment_id ) ) {
787 $payment_status = get_post_status( $payment_id );
788
789 if ( 'publish' === $payment_status ) {
790 $ret = true;
791 }
792 }
793
794 /**
795 * Filter the flag
796 *
797 * @since 1.0
798 */
799 return apply_filters( 'give_is_payment_complete', $ret, $payment_id, $payment_status );
800 }
801
802 /**
803 * Get Total Donations.
804 *
805 * @since 1.0
806 *
807 * @return int $count Total number of donations.
808 */
809 function give_get_total_donations() {
810
811 $payments = give_count_payments();
812
813 return $payments->publish;
814 }
815
816 /**
817 * Get Total Earnings
818 *
819 * @param bool $recalculate Recalculate earnings forcefully.
820 *
821 * @since 1.0
822 *
823 * @return float $total Total earnings.
824 */
825 function give_get_total_earnings( $recalculate = false ) {
826
827 $total = get_option( 'give_earnings_total', 0 );
828 $meta_table = give_v20_bc_table_details( 'payment' );
829
830 // Calculate total earnings.
831 if ( ! $total || $recalculate ) {
832 global $wpdb;
833
834 $total = (float) 0;
835
836 $args = apply_filters(
837 'give_get_total_earnings_args',
838 [
839 'offset' => 0,
840 'number' => - 1,
841 'status' => [ 'publish' ],
842 'fields' => 'ids',
843 ]
844 );
845
846 $payments = give_get_payments( $args );
847 if ( $payments ) {
848
849 /**
850 * If performing a donation, we need to skip the very last payment in the database,
851 * since it calls give_increase_total_earnings() on completion,
852 * which results in duplicated earnings for the very first donation.
853 */
854 if ( did_action( 'give_update_payment_status' ) ) {
855 array_pop( $payments );
856 }
857
858 if ( ! empty( $payments ) ) {
859 $payments = implode( ',', $payments );
860 $total += $wpdb->get_var( "SELECT SUM(meta_value) FROM {$meta_table['name']} WHERE meta_key = '_give_payment_total' AND {$meta_table['column']['id']} IN({$payments})" );
861 }
862 }
863
864 update_option( 'give_earnings_total', $total, false );
865 }
866
867 if ( $total < 0 ) {
868 $total = 0; // Don't ever show negative earnings.
869 }
870
871 return apply_filters( 'give_total_earnings', round( $total, give_get_price_decimals() ), $total );
872 }
873
874 /**
875 * Increase the Total Earnings
876 *
877 * @param int $amount The amount you would like to increase the total earnings by. Default is 0.
878 *
879 * @since 1.0
880 *
881 * @return float $total Total earnings.
882 */
883 function give_increase_total_earnings( $amount = 0 ) {
884 $total = give_get_total_earnings();
885 $total += $amount;
886 update_option( 'give_earnings_total', $total, false );
887
888 return $total;
889 }
890
891 /**
892 * Decrease the Total Earnings
893 *
894 * @param int $amount The amount you would like to decrease the total earnings by.
895 *
896 * @since 1.0
897 *
898 * @return float $total Total earnings.
899 */
900 function give_decrease_total_earnings( $amount = 0 ) {
901 $total = give_get_total_earnings();
902 $total -= $amount;
903 if ( $total < 0 ) {
904 $total = 0;
905 }
906 update_option( 'give_earnings_total', $total, false );
907
908 return $total;
909 }
910
911 /**
912 * Get Payment Meta for a specific Payment
913 *
914 * @param int $payment_id Payment ID.
915 * @param string $meta_key The meta key to pull.
916 * @param bool $single Pull single meta entry or as an object.
917 *
918 * @since 1.0
919 *
920 * @return mixed $meta Payment Meta.
921 */
922 function give_get_payment_meta( $payment_id = 0, $meta_key = '_give_payment_meta', $single = true ) {
923 return give_get_meta( $payment_id, $meta_key, $single );
924 }
925
926 /**
927 * Update the meta for a payment
928 *
929 * @param int $payment_id Payment ID.
930 * @param string $meta_key Meta key to update.
931 * @param string $meta_value Value to update to.
932 * @param string $prev_value Previous value.
933 *
934 * @return mixed Meta ID if successful, false if unsuccessful.
935 */
936 function give_update_payment_meta( $payment_id = 0, $meta_key = '', $meta_value = '', $prev_value = '' ) {
937 return give_update_meta( $payment_id, $meta_key, $meta_value );
938 }
939
940 /**
941 * Get the user_info Key from Payment Meta
942 *
943 * @param int $payment_id Payment ID.
944 *
945 * @since 1.0
946 *
947 * @return array $user_info User Info Meta Values.
948 */
949 function give_get_payment_meta_user_info( $payment_id ) {
950 $donor_id = 0;
951 $donor_info = [
952 'first_name' => give_get_meta( $payment_id, '_give_donor_billing_first_name', true ),
953 'last_name' => give_get_meta( $payment_id, '_give_donor_billing_last_name', true ),
954 'email' => give_get_meta( $payment_id, '_give_donor_billing_donor_email', true ),
955 ];
956
957 if ( empty( $donor_info['first_name'] ) ) {
958 $donor_id = give_get_payment_donor_id( $payment_id );
959 $donor_info['first_name'] = Give()->donor_meta->get_meta( $donor_id, '_give_donor_first_name', true );
960 }
961
962 if ( empty( $donor_info['last_name'] ) ) {
963 $donor_id = $donor_id ? $donor_id : give_get_payment_donor_id( $payment_id );
964 $donor_info['last_name'] = Give()->donor_meta->get_meta( $donor_id, '_give_donor_last_name', true );
965 }
966
967 if ( empty( $donor_info['email'] ) ) {
968 $donor_id = $donor_id ? $donor_id : give_get_payment_donor_id( $payment_id );
969 $donor_info['email'] = Give()->donors->get_column_by( 'email', 'id', $donor_id );
970 }
971
972 $donor_info['title'] = Give()->donor_meta->get_meta( $donor_id, '_give_donor_title_prefix', true );
973
974 $donor_info['address'] = give_get_donation_address( $payment_id );
975 $donor_info['id'] = give_get_payment_user_id( $payment_id );
976 $donor_info['donor_id'] = give_get_payment_donor_id( $payment_id );
977
978 return $donor_info;
979 }
980
981 /**
982 * Get the donations Key from Payment Meta
983 *
984 * Retrieves the form_id from a (Previously titled give_get_payment_meta_donations)
985 *
986 * @param int $payment_id Payment ID.
987 *
988 * @since 1.0
989 *
990 * @return int $form_id Form ID.
991 */
992 function give_get_payment_form_id( $payment_id ) {
993 return (int) give_get_meta( $payment_id, '_give_payment_form_id', true );
994 }
995
996 /**
997 * Get the user email associated with a payment
998 *
999 * @param int $payment_id Payment ID.
1000 *
1001 * @since 1.0
1002 *
1003 * @return string $email User email.
1004 */
1005 function give_get_payment_user_email( $payment_id ) {
1006 $email = give_get_meta( $payment_id, '_give_payment_donor_email', true );
1007
1008 if ( empty( $email ) && ( $donor_id = give_get_payment_donor_id( $payment_id ) ) ) {
1009 $email = Give()->donors->get_column( 'email', $donor_id );
1010 }
1011
1012 return $email;
1013 }
1014
1015 /**
1016 * Is the payment provided associated with a user account
1017 *
1018 * @param int $payment_id The payment ID.
1019 *
1020 * @since 1.3
1021 *
1022 * @return bool $is_guest_payment If the payment is associated with a user (false) or not (true)
1023 */
1024 function give_is_guest_payment( $payment_id ) {
1025 $payment_user_id = give_get_payment_user_id( $payment_id );
1026 $is_guest_payment = ! empty( $payment_user_id ) && $payment_user_id > 0 ? false : true;
1027
1028 return (bool) apply_filters( 'give_is_guest_payment', $is_guest_payment, $payment_id );
1029 }
1030
1031 /**
1032 * Get the user ID associated with a payment
1033 *
1034 * @param int $payment_id Payment ID.
1035 *
1036 * @since 1.3
1037 *
1038 * @return int $user_id User ID.
1039 */
1040 function give_get_payment_user_id( $payment_id ) {
1041 global $wpdb;
1042 $paymentmeta_table = Give()->payment_meta->table_name;
1043 $donationmeta_primary_key = Give()->payment_meta->get_meta_type() . '_id';
1044
1045 return (int) $wpdb->get_var(
1046 $wpdb->prepare(
1047 "
1048 SELECT user_id
1049 FROM $wpdb->donors
1050 WHERE id=(
1051 SELECT meta_value
1052 FROM $paymentmeta_table
1053 WHERE {$donationmeta_primary_key}=%s
1054 AND meta_key=%s
1055 )
1056 ",
1057 $payment_id,
1058 '_give_payment_donor_id'
1059 )
1060 );
1061 }
1062
1063 /**
1064 * Get the donor ID associated with a payment.
1065 *
1066 * @param int $payment_id Payment ID.
1067 *
1068 * @since 1.0
1069 *
1070 * @return int $payment->customer_id Donor ID.
1071 */
1072 function give_get_payment_donor_id( $payment_id ) {
1073 return give_get_meta( $payment_id, '_give_payment_donor_id', true );
1074 }
1075
1076 /**
1077 * Get the donor email associated with a donation.
1078 *
1079 * @param int $payment_id Payment ID.
1080 *
1081 * @since 2.1.0
1082 *
1083 * @return string
1084 */
1085 function give_get_donation_donor_email( $payment_id ) {
1086 return give_get_meta( $payment_id, '_give_payment_donor_email', true );
1087 }
1088
1089 /**
1090 * Get the IP address used to make a donation
1091 *
1092 * @param int $payment_id Payment ID.
1093 *
1094 * @since 1.0
1095 *
1096 * @return string $ip User IP.
1097 */
1098 function give_get_payment_user_ip( $payment_id ) {
1099 return give_get_meta( $payment_id, '_give_payment_donor_ip', true );
1100 }
1101
1102 /**
1103 * Get the date a payment was completed
1104 *
1105 * @param int $payment_id Payment ID.
1106 *
1107 * @since 1.0
1108 *
1109 * @return string $date The date the payment was completed.
1110 */
1111 function give_get_payment_completed_date( $payment_id = 0 ) {
1112 return give_get_meta( $payment_id, '_give_completed_date', true );
1113 }
1114
1115 /**
1116 * Get the gateway associated with a payment
1117 *
1118 * @param int $payment_id Payment ID.
1119 *
1120 * @since 1.0
1121 *
1122 * @return string $gateway Gateway.
1123 */
1124 function give_get_payment_gateway( $payment_id ) {
1125 return give_get_meta( $payment_id, '_give_payment_gateway', true );
1126 }
1127
1128 /**
1129 * Check if donation have specific gateway or not
1130 *
1131 * @since 2.1.0
1132 *
1133 * @param int|Give_Payment $donation_id Donation ID
1134 * @param string $gateway_id Gateway ID
1135 *
1136 * @return bool
1137 */
1138 function give_has_payment_gateway( $donation_id, $gateway_id ) {
1139 $donation_gateway = $donation_id instanceof Give_Payment ?
1140 $donation_id->gateway :
1141 give_get_payment_gateway( $donation_id );
1142
1143 return $gateway_id === $donation_gateway;
1144 }
1145
1146 /**
1147 * Get the currency code a payment was made in
1148 *
1149 * @param int $payment_id Payment ID.
1150 *
1151 * @since 1.0
1152 *
1153 * @return string $currency The currency code.
1154 */
1155 function give_get_payment_currency_code( $payment_id = 0 ) {
1156 return give_get_meta( $payment_id, '_give_payment_currency', true );
1157 }
1158
1159 /**
1160 * Get the currency name a payment was made in
1161 *
1162 * @param int $payment_id Payment ID.
1163 *
1164 * @since 1.0
1165 *
1166 * @return string $currency The currency name.
1167 */
1168 function give_get_payment_currency( $payment_id = 0 ) {
1169 $currency = give_get_payment_currency_code( $payment_id );
1170
1171 return apply_filters( 'give_payment_currency', give_get_currency_name( $currency ), $payment_id );
1172 }
1173
1174 /**
1175 * Get the key for a donation
1176 *
1177 * @param int $payment_id Payment ID.
1178 *
1179 * @since 1.0
1180 *
1181 * @return string $key Donation key.
1182 */
1183 function give_get_payment_key( $payment_id = 0 ) {
1184 return give_get_meta( $payment_id, '_give_payment_purchase_key', true );
1185 }
1186
1187 /**
1188 * Get the payment order number
1189 *
1190 * This will return the payment ID if sequential order numbers are not enabled or the order number does not exist
1191 *
1192 * @param int $payment_id Payment ID.
1193 *
1194 * @since 1.0
1195 *
1196 * @return string $number Payment order number.
1197 */
1198 function give_get_payment_number( $payment_id = 0 ) {
1199 return Give()->seq_donation_number->get_serial_code( $payment_id );
1200 }
1201
1202
1203 /**
1204 * Get Donation Amount
1205 *
1206 * Get the fully formatted or unformatted donation amount which is sent through give_currency_filter()
1207 * and give_format_amount() to format the amount correctly in case of formatted amount.
1208 *
1209 * @param int|Give_Payment $donation_id Donation ID or Donation Object.
1210 * @param bool|array $format_args Currency Formatting Arguments.
1211 *
1212 * @since 1.0
1213 * @since 1.8.17 Added filter and internally use functions.
1214 *
1215 * @return string $amount Fully formatted donation amount.
1216 */
1217 function give_donation_amount( $donation_id, $format_args = [] ) {
1218 if ( ! $donation_id ) {
1219 return '';
1220 } elseif ( ! is_numeric( $donation_id ) && ( $donation_id instanceof Give_Payment ) ) {
1221 $donation_id = $donation_id->ID;
1222 }
1223
1224 $amount = $formatted_amount = give_get_payment_total( $donation_id );
1225 $currency_code = give_get_payment_currency_code( $donation_id );
1226
1227 if ( is_bool( $format_args ) ) {
1228 $format_args = [
1229 'currency' => (bool) $format_args,
1230 'amount' => (bool) $format_args,
1231 ];
1232 }
1233
1234 $format_args = wp_parse_args(
1235 $format_args,
1236 [
1237 'currency' => false,
1238 'amount' => false,
1239
1240 // Define context of donation amount, by default keep $type as blank.
1241 // Pass as 'stats' to calculate donation report on basis of base amount for the Currency-Switcher Add-on.
1242 // For Eg. In Currency-Switcher add on when donation has been made through
1243 // different currency other than base currency, in that case for correct
1244 // report calculation based on base currency we will need to return donation
1245 // base amount and not the converted amount .
1246 'type' => '',
1247 ]
1248 );
1249
1250 if ( $format_args['amount'] || $format_args['currency'] ) {
1251
1252 if ( $format_args['amount'] ) {
1253
1254 $formatted_amount = give_format_amount(
1255 $amount,
1256 ! is_array( $format_args['amount'] ) ?
1257 [
1258 'sanitize' => false,
1259 'currency' => $currency_code,
1260 ] :
1261 $format_args['amount']
1262 );
1263 }
1264
1265 if ( $format_args['currency'] ) {
1266 $formatted_amount = give_currency_filter(
1267 $formatted_amount,
1268 ! is_array( $format_args['currency'] ) ?
1269 [ 'currency_code' => $currency_code ] :
1270 $format_args['currency']
1271 );
1272 }
1273 }
1274
1275 /**
1276 * Filter Donation amount.
1277 *
1278 * @since 1.8.17
1279 *
1280 * @param string $formatted_amount Formatted/Un-formatted amount.
1281 * @param float $amount Donation amount.
1282 * @param int $donation_id Donation ID.
1283 * @param string $type Donation amount type.
1284 */
1285 return apply_filters( 'give_donation_amount', (string) $formatted_amount, $amount, $donation_id, $format_args );
1286 }
1287
1288 /**
1289 * Payment Subtotal
1290 *
1291 * Retrieves subtotal for payment and then returns a full formatted amount. This
1292 * function essentially calls give_get_payment_subtotal()
1293 *
1294 * @param int $payment_id Payment ID.
1295 *
1296 * @since 1.5
1297 *
1298 * @see give_get_payment_subtotal()
1299 *
1300 * @return array Fully formatted payment subtotal.
1301 */
1302 function give_payment_subtotal( $payment_id = 0 ) {
1303 $subtotal = give_get_payment_subtotal( $payment_id );
1304
1305 return give_currency_filter( give_format_amount( $subtotal, [ 'sanitize' => false ] ), [ 'currency_code' => give_get_payment_currency_code( $payment_id ) ] );
1306 }
1307
1308 /**
1309 * Get Payment Subtotal
1310 *
1311 * Retrieves subtotal for payment and then returns a non formatted amount.
1312 *
1313 * @param int $payment_id Payment ID.
1314 *
1315 * @since 1.5
1316 *
1317 * @return float $subtotal Subtotal for payment (non formatted).
1318 */
1319 function give_get_payment_subtotal( $payment_id = 0 ) {
1320 $payment = new Give_Payment( $payment_id );
1321
1322 return $payment->subtotal;
1323 }
1324
1325 /**
1326 * Retrieves the donation ID
1327 *
1328 * @param int $payment_id Payment ID.
1329 *
1330 * @since 1.0
1331 *
1332 * @return string The donation ID.
1333 */
1334 function give_get_payment_transaction_id( $payment_id = 0 ) {
1335 $transaction_id = give_get_meta( $payment_id, '_give_payment_transaction_id', true );
1336
1337 if ( empty( $transaction_id ) ) {
1338 $gateway = give_get_payment_gateway( $payment_id );
1339 $transaction_id = apply_filters( "give_get_payment_transaction_id-{$gateway}", $payment_id );
1340 }
1341
1342 return $transaction_id;
1343 }
1344
1345 /**
1346 * Sets a Transaction ID in post meta for the given Payment ID.
1347 *
1348 * @param int $payment_id Payment ID.
1349 * @param string $transaction_id The transaction ID from the gateway.
1350 *
1351 * @since 1.0
1352 *
1353 * @return bool|mixed
1354 */
1355 function give_set_payment_transaction_id( $payment_id = 0, $transaction_id = '' ) {
1356
1357 if ( empty( $payment_id ) || empty( $transaction_id ) ) {
1358 return false;
1359 }
1360
1361 $transaction_id = apply_filters( 'give_set_payment_transaction_id', $transaction_id, $payment_id );
1362
1363 return give_update_payment_meta( $payment_id, '_give_payment_transaction_id', $transaction_id );
1364 }
1365
1366 /**
1367 * Retrieve the donation ID based on the key
1368 *
1369 * @param string $key the key to search for.
1370 *
1371 * @since 1.0
1372 * @global object $wpdb Used to query the database using the WordPress Database API.
1373 *
1374 * @return int $purchase Donation ID.
1375 */
1376 function give_get_donation_id_by_key( $key ) {
1377 global $wpdb;
1378
1379 $meta_table = give_v20_bc_table_details( 'payment' );
1380
1381 $purchase = $wpdb->get_var(
1382 $wpdb->prepare(
1383 "
1384 SELECT {$meta_table['column']['id']}
1385 FROM {$meta_table['name']}
1386 WHERE meta_key = '_give_payment_purchase_key'
1387 AND meta_value = %s
1388 ORDER BY {$meta_table['column']['id']} DESC
1389 LIMIT 1
1390 ",
1391 $key
1392 )
1393 );
1394
1395 if ( $purchase != null ) {
1396 return $purchase;
1397 }
1398
1399 return 0;
1400 }
1401
1402
1403 /**
1404 * Retrieve the donation ID based on the transaction ID
1405 *
1406 * @param string $key The transaction ID to search for.
1407 *
1408 * @since 1.3
1409 * @global object $wpdb Used to query the database using the WordPress Database API.
1410 *
1411 * @return int $purchase Donation ID.
1412 */
1413 function give_get_purchase_id_by_transaction_id( $key ) {
1414 global $wpdb;
1415 $meta_table = give_v20_bc_table_details( 'payment' );
1416
1417 $purchase = $wpdb->get_var( $wpdb->prepare( "SELECT {$meta_table['column']['id']} FROM {$meta_table['name']} WHERE meta_key = '_give_payment_transaction_id' AND meta_value = %s LIMIT 1", $key ) );
1418
1419 if ( $purchase != null ) {
1420 return $purchase;
1421 }
1422
1423 return 0;
1424 }
1425
1426 /**
1427 * Retrieve all notes attached to a donation
1428 *
1429 * @param int $payment_id The donation ID to retrieve notes for.
1430 * @param string $search Search for notes that contain a search term.
1431 *
1432 * @since 1.0
1433 *
1434 * @return array $notes Donation Notes
1435 */
1436 function give_get_payment_notes( $payment_id = 0, $search = '' ) {
1437 return Give_Comment::get( $payment_id, 'payment', [], $search );
1438 }
1439
1440
1441 /**
1442 * Add a note to a payment
1443 *
1444 * @param int $payment_id The payment ID to store a note for.
1445 * @param string $note The note to store.
1446 *
1447 * @since 1.0
1448 *
1449 * @return int The new note ID
1450 */
1451 function give_insert_payment_note( $payment_id = 0, $note = '' ) {
1452 return Give_Comment::add( $payment_id, $note, 'payment' );
1453 }
1454
1455 /**
1456 * Deletes a payment note
1457 *
1458 * @param int $comment_id The comment ID to delete.
1459 * @param int $payment_id The payment ID the note is connected to.
1460 *
1461 * @since 1.0
1462 *
1463 * @return bool True on success, false otherwise.
1464 */
1465 function give_delete_payment_note( $comment_id = 0, $payment_id = 0 ) {
1466 return Give_Comment::delete( $comment_id, $payment_id, 'payment' );
1467 }
1468
1469 /**
1470 * Gets the payment note HTML
1471 *
1472 * @param object|int $note The comment object or ID.
1473 * @param int $payment_id The payment ID the note is connected to.
1474 *
1475 * @since 1.0
1476 *
1477 * @return string
1478 */
1479 function give_get_payment_note_html( $note, $payment_id = 0 ) {
1480
1481 if ( is_numeric( $note ) ) {
1482 if ( ! give_has_upgrade_completed( 'v230_move_donor_note' ) ) {
1483 $note = get_comment( $note );
1484 } else {
1485 $note = Give()->comment->db->get( $note );
1486 }
1487 }
1488
1489 if ( ! empty( $note->user_id ) ) {
1490 $user = get_userdata( $note->user_id );
1491 $user = $user->display_name;
1492 } else {
1493 $user = __( 'System', 'give' );
1494 }
1495
1496 $date_format = give_date_format() . ', ' . get_option( 'time_format' );
1497
1498 $delete_note_url = wp_nonce_url(
1499 add_query_arg(
1500 [
1501 'give-action' => 'delete_payment_note',
1502 'note_id' => $note->comment_ID,
1503 'payment_id' => $payment_id,
1504 ]
1505 ),
1506 'give_delete_payment_note_' . $note->comment_ID
1507 );
1508
1509 $note_html = '<div class="give-payment-note" id="give-payment-note-' . $note->comment_ID . '">';
1510 $note_html .= '<p>';
1511 $note_html .= '<strong>' . $user . '</strong>&nbsp;&ndash;&nbsp;<span style="color:#aaa;font-style:italic;">' . date_i18n( $date_format, strtotime( $note->comment_date ) ) . '</span><br/>';
1512 $note_html .= nl2br( $note->comment_content );
1513 $note_html .= '&nbsp;&ndash;&nbsp;<a href="' . esc_url( $delete_note_url ) . '" class="give-delete-payment-note" data-note-id="' . absint( $note->comment_ID ) . '" data-payment-id="' . absint( $payment_id ) . '" aria-label="' . __( 'Delete this donation note.', 'give' ) . '">' . __( 'Delete', 'give' ) . '</a>';
1514 $note_html .= '</p>';
1515 $note_html .= '</div>';
1516
1517 return $note_html;
1518
1519 }
1520
1521
1522 /**
1523 * Filter where older than one week
1524 *
1525 * @param string $where Where clause.
1526 *
1527 * @access public
1528 * @since 1.0
1529 *
1530 * @return string $where Modified where clause.
1531 */
1532 function give_filter_where_older_than_week( $where = '' ) {
1533 // Payments older than one week.
1534 $start = date( 'Y-m-d', strtotime( '-7 days' ) );
1535 $where .= " AND post_date <= '{$start}'";
1536
1537 return $where;
1538 }
1539
1540
1541 /**
1542 * Get Payment Form ID.
1543 *
1544 * Retrieves the form title and appends the level name if present.
1545 *
1546 * @param int|Give_Payment $donation_id Donation Data Object.
1547 * @param array $args a. only_level = If set to true will only return the level name if multi-level
1548 * enabled. b. separator = The separator between the Form Title and the Donation
1549 * Level.
1550 *
1551 * @since 4.16.5 lookup option values by level ID (price_id) first before falling back to amount-based matching
1552 * @since 4.14.5 add currency compatibility to determine whether the level is same as donation amount
1553 * @since 3.18.0 check if donation form is V3 form
1554 * @since 1.5
1555 *
1556 * @return string $form_title Returns the full title if $only_level is false, otherwise returns the levels title.
1557 */
1558 function give_get_donation_form_title( $donation_id, $args = [] ) {
1559 // Backward compatibility.
1560 if ( ! is_numeric( $donation_id ) && $donation_id instanceof Give_Payment ) {
1561 $donation_id = $donation_id->ID;
1562 }
1563
1564 if ( ! $donation_id ) {
1565 return '';
1566 }
1567
1568 $defaults = [
1569 'only_level' => false,
1570 'separator' => '',
1571 ];
1572
1573 $args = wp_parse_args( $args, $defaults );
1574
1575 $form_id = give_get_payment_form_id( $donation_id );
1576 $form_title = give_get_meta( $donation_id, '_give_payment_form_title', true );
1577
1578 // Check if the donation form is V3 form
1579 if (Utils::isV3Form($form_id)) {
1580 $default_currency = give_get_option('currency'); // default currency
1581 $payment_currency = give_get_payment_currency_code($donation_id); // donation currency
1582 $options = give()->form_meta->get_meta($form_id, '_give_donation_levels', true) ?? [];
1583 $donation = Donation::find($donation_id);
1584 $price_id = give_get_meta( $donation_id, '_give_payment_price_id', true );
1585
1586 if ( $price_id !== '' && $price_id !== 'custom' && ! is_null( $price_id ) ) {
1587 foreach ( $options as $option ) {
1588 if ( isset( $option['_give_id']['level_id'] ) && (string) $option['_give_id']['level_id'] === (string) $price_id ) {
1589 $form_title = sprintf('%s %s %s', $form_title, $args['separator'], $option['_give_text']);
1590 return apply_filters('give_get_donation_form_title', $form_title, $donation_id);
1591 }
1592 }
1593 }
1594
1595 // Different currencies - use exchange rate from currency switcher
1596 $exchange_rate = give_get_meta($donation_id, '_give_cs_exchange_rate', true);
1597
1598 foreach ( $options as $option ) {
1599 if (!isset($option['_give_amount'], $option['_give_text'])) {
1600 continue;
1601 }
1602
1603 $matched = false;
1604
1605 if ($default_currency === $payment_currency) {
1606 $matched = Money::of($option['_give_amount'], $default_currency)->getMinorAmount() == $donation->amount->getAmount();
1607 } elseif (!empty($exchange_rate) && is_numeric($exchange_rate)) {
1608 $option_amount_converted = $option['_give_amount'] * $exchange_rate;
1609 $option_money = Money::of($option_amount_converted, $payment_currency);
1610 $diff = abs($option_money->getMinorAmount() - $donation->amount->getAmount());
1611 $matched = ($diff < 2);
1612 }
1613
1614 if ($matched) {
1615 $form_title = sprintf('%s %s %s', $form_title, $args['separator'], $option['_give_text']);
1616 return apply_filters('give_get_donation_form_title', $form_title, $donation_id);
1617 }
1618 }
1619 }
1620
1621 $price_id = give_get_meta( $donation_id, '_give_payment_price_id', true );
1622
1623 $only_level = $args['only_level'];
1624 $separator = $args['separator'];
1625 $level_label = '';
1626
1627 $cache_key = Give_Cache::get_key(
1628 'give_forms',
1629 [
1630 $form_id,
1631 $price_id,
1632 $form_title,
1633 $only_level,
1634 $separator,
1635 ],
1636 false
1637 );
1638
1639 $form_title_html = Give_Cache::get_db_query( $cache_key );
1640
1641 if ( is_null( $form_title_html ) ) {
1642 if ( true === $only_level ) {
1643 $form_title = '';
1644 }
1645
1646 $form_title_html = $form_title;
1647
1648 if ( 'custom' === $price_id ) {
1649
1650 $custom_amount_text = give_get_meta( $form_id, '_give_custom_amount_text', true );
1651 $level_label = ! empty( $custom_amount_text ) ? $custom_amount_text : __( 'Custom Amount', 'give' );
1652
1653 // Show custom amount level only in backend otherwise hide it.
1654 if ( 'set' === give_get_meta( $form_id, '_give_price_option', true ) && ! is_admin() ) {
1655 $level_label = '';
1656 }
1657 } elseif ( give_has_variable_prices( $form_id ) ) {
1658 $level_label = give_get_price_option_name( $form_id, $price_id, $donation_id, false );
1659 }
1660
1661 // Only add separator if there is a form title.
1662 if (
1663 ! empty( $form_title_html ) &&
1664 ! empty( $level_label )
1665 ) {
1666 $form_title_html .= " {$separator} ";
1667 }
1668
1669 $form_title_html .= "<span class=\"donation-level-text-wrap\">{$level_label}</span>";
1670 Give_Cache::set_db_query( $cache_key, $form_title_html );
1671 }
1672
1673 /**
1674 * Filter form title with level html
1675 *
1676 * @since 1.0
1677 * @todo: remove third param after 2.1.0
1678 */
1679 return apply_filters( 'give_get_donation_form_title', $form_title_html, $donation_id, '' );
1680 }
1681
1682 /**
1683 * Get Price ID
1684 *
1685 * Retrieves the Price ID when provided a proper form ID and price (donation) total
1686 *
1687 * @param int $form_id Form ID.
1688 * @param string $price Donation Amount.
1689 *
1690 * @return string $price_id
1691 */
1692 function give_get_price_id( $form_id, $price ) {
1693 $price_id = null;
1694
1695 if ( give_has_variable_prices( $form_id ) ) {
1696
1697 $levels = give_get_meta( $form_id, '_give_donation_levels', true );
1698
1699 foreach ( $levels as $level ) {
1700
1701 $level_amount = give_maybe_sanitize_amount( $level['_give_amount'] );
1702
1703 // Check that this indeed the recurring price.
1704 if ( $level_amount == $price ) {
1705
1706 $price_id = $level['_give_id']['level_id'];
1707 break;
1708
1709 }
1710 }
1711
1712 if ( is_null( $price_id ) && give_is_custom_price_mode( $form_id ) ) {
1713 $price_id = 'custom';
1714 }
1715 }
1716
1717 // Price ID must be numeric or string.
1718 $price_id = ! is_numeric( $price_id ) && ! is_string( $price_id ) ? 0 : $price_id;
1719
1720 /**
1721 * Filter the price id
1722 *
1723 * @since 2.0
1724 *
1725 * @param string $price_id
1726 * @param int $form_id
1727 */
1728 return apply_filters( 'give_get_price_id', $price_id, $form_id );
1729 }
1730
1731 /**
1732 * Get/Print give form dropdown html
1733 *
1734 * This function is wrapper to public method forms_dropdown of Give_HTML_Elements class to get/print form dropdown html.
1735 * Give_HTML_Elements is defined in includes/class-give-html-elements.php.
1736 *
1737 * @param array $args Arguments for form dropdown.
1738 * @param bool $echo This parameter decides if print form dropdown html output or not.
1739 *
1740 * @since 1.6
1741 *
1742 * @return string
1743 */
1744 function give_get_form_dropdown( $args = [], $echo = false ) {
1745 $form_dropdown_html = Give()->html->forms_dropdown( $args );
1746
1747 if ( ! $echo ) {
1748 return $form_dropdown_html;
1749 }
1750
1751 echo $form_dropdown_html;
1752 }
1753
1754 /**
1755 * Get/Print give form variable price dropdown html
1756 *
1757 * @param array $args Arguments for form dropdown.
1758 * @param bool $echo This parameter decide if print form dropdown html output or not.
1759 *
1760 * @since 1.6
1761 * @since 2.12.0 Show "Custom" choice in select field if donation created with cusotm amount
1762 *
1763 * @return string|bool
1764 */
1765 function give_get_form_variable_price_dropdown( $args = [], $echo = false ) {
1766
1767 // Check for give form id.
1768 if ( empty( $args['id'] ) ) {
1769 return false;
1770 }
1771
1772 $form = new Give_Donate_Form( $args['id'] );
1773
1774 // Check if form has variable prices or not.
1775 if ( ! $form->ID || ! $form->has_variable_prices() ) {
1776 return false;
1777 }
1778
1779 $variable_prices = $form->get_prices();
1780 $variable_price_options = [];
1781
1782 // Check if multi donation form support custom donation or not.
1783 // Check if donation amount is a custom or not.
1784 if (
1785 $form->is_custom_price_mode() ||
1786 'custom' === $args['selected']
1787 ) {
1788 $variable_price_options['custom'] = _x( 'Custom', 'custom donation dropdown item', 'give' );
1789 }
1790
1791 // Get variable price and ID from variable price array.
1792 foreach ( $variable_prices as $variable_price ) {
1793 $variable_price_options[ $variable_price['_give_id']['level_id'] ] = ! empty( $variable_price['_give_text'] ) ? $variable_price['_give_text'] : give_currency_filter( give_format_amount( $variable_price['_give_amount'], [ 'sanitize' => false ] ) );
1794 }
1795
1796 // Update options.
1797 $args = array_merge(
1798 $args,
1799 [
1800 'options' => $variable_price_options,
1801 ]
1802 );
1803
1804 // Generate select html.
1805 $form_dropdown_html = Give()->html->select( $args );
1806
1807 if ( ! $echo ) {
1808 return $form_dropdown_html;
1809 }
1810
1811 echo $form_dropdown_html;
1812 }
1813
1814 /**
1815 * Get the price_id from the payment meta.
1816 *
1817 * Some gateways use `give_price_id` and others were using just `price_id`;
1818 * This checks for the difference and falls back to retrieving it from the form as a last resort.
1819 *
1820 * @param array $payment_meta Payment Meta.
1821 *
1822 * @since 1.8.6
1823 *
1824 * @return string
1825 */
1826 function give_get_payment_meta_price_id( $payment_meta ) {
1827
1828 if ( isset( $payment_meta['give_price_id'] ) ) {
1829 $price_id = $payment_meta['give_price_id'];
1830 } elseif ( isset( $payment_meta['price_id'] ) ) {
1831 $price_id = $payment_meta['price_id'];
1832 } else {
1833 $price_id = give_get_price_id( $payment_meta['give_form_id'], $payment_meta['price'] );
1834 }
1835
1836 /**
1837 * Filter the price id
1838 *
1839 * @since 1.8.6
1840 *
1841 * @param string $price_id
1842 * @param array $payment_meta
1843 */
1844 return apply_filters( 'give_get_payment_meta_price_id', $price_id, $payment_meta );
1845
1846 }
1847
1848
1849 /**
1850 * Get payment total amount
1851 *
1852 * @since 2.1.0
1853 *
1854 * @param int $payment_id
1855 *
1856 * @return float
1857 */
1858 function give_get_payment_total( $payment_id = 0 ) {
1859 return round(
1860 floatval( give_get_meta( $payment_id, '_give_payment_total', true ) ),
1861 give_get_price_decimals( $payment_id )
1862 );
1863 }
1864
1865 /**
1866 * Get donation address
1867 *
1868 * since 2.1.0
1869 *
1870 * @param int $donation_id
1871 *
1872 * @return array
1873 */
1874 function give_get_donation_address( $donation_id ) {
1875 $address['line1'] = give_get_meta( $donation_id, '_give_donor_billing_address1', true, '' );
1876 $address['line2'] = give_get_meta( $donation_id, '_give_donor_billing_address2', true, '' );
1877 $address['city'] = give_get_meta( $donation_id, '_give_donor_billing_city', true, '' );
1878 $address['state'] = give_get_meta( $donation_id, '_give_donor_billing_state', true, '' );
1879 $address['zip'] = give_get_meta( $donation_id, '_give_donor_billing_zip', true, '' );
1880 $address['country'] = give_get_meta( $donation_id, '_give_donor_billing_country', true, '' );
1881
1882 return $address;
1883 }
1884
1885
1886 /**
1887 * Check if donation completed or not
1888 *
1889 * @since 2.1.0
1890 *
1891 * @param int $donation_id
1892 *
1893 * @return bool
1894 */
1895 function give_is_donation_completed( $donation_id ) {
1896 global $wpdb;
1897
1898 /**
1899 * Filter the flag
1900 *
1901 * @since 2.1.0
1902 *
1903 * @param bool
1904 * @param int $donation_id
1905 */
1906 return apply_filters(
1907 'give_is_donation_completed',
1908 (bool) $wpdb->get_var(
1909 $wpdb->prepare(
1910 "
1911 SELECT meta_value
1912 FROM {$wpdb->donationmeta}
1913 WHERE EXISTS (
1914 SELECT ID
1915 FROM {$wpdb->posts}
1916 WHERE post_status=%s
1917 AND ID=%d
1918 )
1919 AND {$wpdb->donationmeta}.meta_key=%s
1920 ",
1921 'publish',
1922 $donation_id,
1923 '_give_completed_date'
1924 )
1925 ),
1926 $donation_id
1927 );
1928 }
1929
1930 /**
1931 * Verify if donation anonymous or not
1932 *
1933 * @since 2.2.1
1934 * @param $donation_id
1935 *
1936 * @return bool
1937 */
1938 function give_is_anonymous_donation( $donation_id ) {
1939 $value = false;
1940
1941 if ( (int) give_get_meta( $donation_id, '_give_anonymous_donation', true ) ) {
1942 $value = true;
1943 }
1944
1945 return $value;
1946 }
1947