|
@@ -19,8 +19,16 @@ |
|
19
|
19
|
* @since 0.0.1 |
|
20
|
20
|
*/ |
|
21
|
21
|
class DB { |
|
22
|
22
|
|
|
23
|
+ /** |
|
24
|
+ * Helper's counting rule (an unconfirmed pre-2.4.0 `no_payment_required` row is not counted; a |
|
25
|
+ * confirmed one adds 0), aliased so the two deprecated queries below spell it `self::…` exactly |
|
26
|
+ * as Pro's AnalyticsModel copies do (AnalyticsModelParityTest compares the bodies). |
|
27
|
+ */ |
|
28
|
+ private const COUNTED_ROW_SQL = Helper::COUNTED_ROW_SQL; |
|
29
|
+ private const COUNTABLE_AMOUNT_SQL = Helper::COUNTABLE_AMOUNT_SQL; |
|
30
|
+ |
|
23
|
31
|
public static function get_table_name() { |
|
24
|
32
|
global $wpdb; |
|
25
|
33
|
|
|
26
|
34
|
$table = "{$wpdb->prefix}better_payment"; |
|
@@ -91,8 +99,17 @@ |
|
91
|
99
|
'better_payment_settings_ai_api_key_openai' => '', |
|
92
|
100
|
'better_payment_settings_ai_api_key_claude' => '', |
|
93
|
101
|
'better_payment_settings_ai_api_key_gemini' => '', |
|
94
|
102
|
'better_payment_settings_ai_api_key_openrouter' => '', |
|
103
|
+ |
|
104
|
+ // E-commerce > Subscription. Booleans follow the 'yes'/'no' string |
|
105
|
+ // convention used across this settings array. |
|
106
|
+ 'better_payment_settings_ecommerce_subscription_renewal_process' => 'auto', |
|
107
|
+ 'better_payment_settings_ecommerce_subscription_stripe_auto_renew' => 'yes', |
|
108
|
+ 'better_payment_settings_ecommerce_subscription_auto_renewal_toggle' => 'yes', |
|
109
|
+ 'better_payment_settings_ecommerce_subscription_myaccount_tab' => 'yes', |
|
110
|
+ 'better_payment_settings_ecommerce_subscription_active_role' => 'subscriber', |
|
111
|
+ 'better_payment_settings_ecommerce_subscription_inactive_role' => 'customer', |
|
95
|
112
|
)); |
|
96
|
113
|
} |
|
97
|
114
|
/** |
|
98
|
115
|
* Get all settings value from options table. |
|
@@ -139,11 +156,43 @@ |
|
139
|
156
|
return update_option('better_payment_settings', $value); |
|
140
|
157
|
} |
|
141
|
158
|
|
|
142
|
159
|
/** |
|
160
|
+ * The UTC `payment_date` bounds for a date range picked in site time. |
|
161
|
+ * |
|
162
|
+ * The admin date filter sends whole days (`Y-m-d`), picked on the site's |
|
163
|
+ * calendar. Compared as-is, `BETWEEN '2026-10-11' AND '2026-10-11'` matched |
|
164
|
+ * only rows at exactly midnight — so the last day of every range was dropped |
|
165
|
+ * — and the days were UTC days, not the site's. A day bound is widened to the |
|
166
|
+ * whole site day (00:00:00 – 23:59:59) and converted to UTC, which is how |
|
167
|
+ * `payment_date` is stored. A bound that already carries a time is passed |
|
168
|
+ * through unchanged. |
|
169
|
+ * |
|
170
|
+ * @since 2.4.1 |
|
171
|
+ * |
|
172
|
+ * @param string $from Lower bound. |
|
173
|
+ * @param string $to Upper bound. |
|
174
|
+ * @return string[] [ from, to ]. |
|
175
|
+ */ |
|
176
|
+ public static function payment_date_range( $from, $to ) { |
|
177
|
+ $from = trim( (string) $from ); |
|
178
|
+ $to = trim( (string) $to ); |
|
179
|
+ |
|
180
|
+ if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $from ) ) { |
|
181
|
+ $from = get_gmt_from_date( $from . ' 00:00:00', 'Y-m-d H:i:s' ); |
|
182
|
+ } |
|
183
|
+ |
|
184
|
+ if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $to ) ) { |
|
185
|
+ $to = get_gmt_from_date( $to . ' 23:59:59', 'Y-m-d H:i:s' ); |
|
186
|
+ } |
|
187
|
+ |
|
188
|
+ return array( $from, $to ); |
|
189
|
+ } |
|
190
|
+ |
|
191
|
+ /** |
|
143
|
192
|
* Get all transactions from better payment table. |
|
144
|
193
|
* |
|
145
|
|
- * @param string $args |
|
194
|
+ * @param array|string $args Filters, as wp_parse_args() reads them (every caller passes an array). |
|
146
|
195
|
* @return array |
|
147
|
196
|
* @since 0.0.1 |
|
148
|
197
|
*/ |
|
149
|
198
|
public static function get_transactions($args = [], $count_only=0, $version = 'v1', $fetchNull = 0, $transaction_type = '') |
|
@@ -204,10 +253,21 @@ |
|
204
|
253
|
$statuses_by_transaction_type = array(); |
|
205
|
254
|
|
|
206
|
255
|
if( !empty($transaction_type) ){ |
|
207
|
256
|
$statuses_by_types = $better_payment_helper_obj->transaction_statuses_with_type_v2(); |
|
208
|
|
- $statuses_by_transaction_type = isset($statuses_by_types[$transaction_type]['statuses']) ? $statuses_by_types[$transaction_type]['statuses'] : $defaults['status']; |
|
209
|
|
- $status = ''; |
|
257
|
+ $transaction_type = is_string( $transaction_type ) ? $transaction_type : 'all'; |
|
258
|
+ |
|
259
|
+ if ( 'null' === $transaction_type ) { |
|
260
|
+ // The count twin of `status=null` below. |
|
261
|
+ $status = 'null'; |
|
262
|
+ $transaction_type = ''; |
|
263
|
+ } else { |
|
264
|
+ // An unknown type is every row, as an unknown `status` is. It used to fall back to the |
|
265
|
+ // string 'all' and fatal in array_map() below. |
|
266
|
+ $transaction_type = isset( $statuses_by_types[ $transaction_type ] ) ? $transaction_type : 'all'; |
|
267
|
+ $statuses_by_transaction_type = $statuses_by_types[ $transaction_type ]['statuses']; |
|
268
|
+ $status = ''; |
|
269
|
+ } |
|
210
|
270
|
} |
|
211
|
271
|
|
|
212
|
272
|
$whereQuery = ''; |
|
213
|
273
|
|
|
@@ -241,19 +301,37 @@ |
|
241
|
301
|
|
|
242
|
302
|
$statuses = array_map(function($status) { |
|
243
|
303
|
return "'" . esc_sql($status) . "'"; |
|
244
|
304
|
}, $statuses_by_type); |
|
245
|
|
- |
|
305
|
+ |
|
246
|
306
|
$statuses = implode(',', $statuses); |
|
247
|
|
- |
|
248
|
|
- $nullDataQuery = $fetchNull ? " OR status IS NULL " : ''; |
|
249
|
|
- $whereQuery .= " AND ( status IN ( $statuses ) " . esc_sql($nullDataQuery) . " ) "; |
|
307
|
+ |
|
308
|
+ $bucket = $transaction_type ? $transaction_type : $status; |
|
309
|
+ |
|
310
|
+ // NULL is the incomplete bucket's own status (PayPal's pending sentinel): `IN ()` |
|
311
|
+ // cannot match it, so the Incomplete tab always ORs it in and lists the rows its |
|
312
|
+ // total and stat card count. |
|
313
|
+ $nullDataQuery = ( $fetchNull || 'incomplete' === $bucket ) ? " OR status IS NULL " : ''; |
|
314
|
+ |
|
315
|
+ // The counting rule, for the tabs: an unconfirmed pre-2.4.0 `no_payment_required` |
|
316
|
+ // row is in no count, so it is listed under Incomplete, never Completed, as |
|
317
|
+ // Helper::transaction_status_type() labels it. A confirmed one stays Completed; |
|
318
|
+ // `refunded` is unchanged. Helper constants only (no request data, no `%`). |
|
319
|
+ $unconfirmed_sql = 'incomplete' === $bucket ? ' OR ' . Helper::UNCONFIRMED_LEGACY_SQL . ' ' : ''; |
|
320
|
+ $counted_sql = 'completed' === $bucket ? ' AND ' . Helper::COUNTED_ROW_SQL . ' ' : ''; |
|
321
|
+ |
|
322
|
+ // `all` is every row, as the All tab's list is: its `IN ()` list would leave NULL and |
|
323
|
+ // unlisted statuses out of the total. |
|
324
|
+ if ( 'all' !== $bucket ) { |
|
325
|
+ $whereQuery .= " AND ( status IN ( $statuses ) " . esc_sql($nullDataQuery) . $unconfirmed_sql . " ) " . $counted_sql; |
|
326
|
+ } |
|
250
|
327
|
} |
|
251
|
328
|
} |
|
252
|
329
|
} |
|
253
|
330
|
|
|
254
|
331
|
if( $args['payment_date_from'] != '' && $args['payment_date_to'] != ''){ |
|
255
|
|
- $whereQuery .= $wpdb->prepare(" AND payment_date BETWEEN %s AND %s", $args['payment_date_from'], $args['payment_date_to']); |
|
332
|
+ $range = self::payment_date_range( $args['payment_date_from'], $args['payment_date_to'] ); |
|
333
|
+ $whereQuery .= $wpdb->prepare(" AND payment_date BETWEEN %s AND %s", $range[0], $range[1]); |
|
256
|
334
|
} |
|
257
|
335
|
|
|
258
|
336
|
if($count_only === 1){ |
|
259
|
337
|
if($valid_search_text){ |
|
@@ -326,40 +404,11 @@ |
|
326
|
404
|
|
|
327
|
405
|
/** |
|
328
|
406
|
* Get transactions analytics |
|
329
|
407
|
* |
|
330
|
|
- * @return int |
|
408
|
+ * @return array<string, mixed> |
|
331
|
409
|
* @since 0.0.1 |
|
332
|
410
|
*/ |
|
333
|
|
- public static function get_transactions_analytics($filtered_transactions = array()) |
|
334
|
|
- { |
|
335
|
|
- global $wpdb; |
|
336
|
|
- $transaction_analytics = []; |
|
337
|
|
- |
|
338
|
|
- $table = self::get_table_name(); |
|
339
|
|
- $better_payment_db_obj = new DB(); |
|
340
|
|
- |
|
341
|
|
- $total_transactions = $better_payment_db_obj->get_transactions_amount_by_statuses(array(), '', '', 'count', 1, $filtered_transactions ); |
|
342
|
|
- |
|
343
|
|
- $completed_statuses = $better_payment_db_obj->allowed_statuses('completed', 'v2'); |
|
344
|
|
- $completed_transactions = $better_payment_db_obj->get_transactions_amount_by_statuses( $completed_statuses, '', '', 'count', 0, $filtered_transactions ); |
|
345
|
|
- |
|
346
|
|
- $incomplete_statuses = $better_payment_db_obj->allowed_statuses('incomplete', 'v2'); |
|
347
|
|
- $incomplete_transactions = $better_payment_db_obj->get_transactions_amount_by_statuses( $incomplete_statuses, '', '', 'count', 1, $filtered_transactions ); |
|
348
|
|
- |
|
349
|
|
- $transaction_analytics['total_transactions'] = $total_transactions; |
|
350
|
|
- $transaction_analytics['completed_transactions'] = $completed_transactions; |
|
351
|
|
- $transaction_analytics['incomplete_transactions'] = $incomplete_transactions; |
|
352
|
|
- |
|
353
|
|
- return $transaction_analytics; |
|
354
|
|
- } |
|
355
|
|
- |
|
356
|
|
- /** |
|
357
|
|
- * Get transactions analytics |
|
358
|
|
- * |
|
359
|
|
- * @return int |
|
360
|
|
- * @since 0.0.1 |
|
361
|
|
- */ |
|
362
|
411
|
public static function get_transactions_analytics_dashboard($filtered_transactions = array()) |
|
363
|
412
|
{ |
|
364
|
413
|
global $wpdb; |
|
365
|
414
|
$transaction_analytics = []; |
|
@@ -433,35 +482,15 @@ |
|
433
|
482
|
return $item; |
|
434
|
483
|
} |
|
435
|
484
|
|
|
436
|
485
|
/** |
|
437
|
|
- * Get transaction details from better payment table. |
|
438
|
|
- * |
|
439
|
|
- * @param string $args |
|
440
|
|
- * @return object |
|
441
|
|
- * @since 0.0.1 |
|
442
|
|
- */ |
|
443
|
|
- public static function get_transactions_by_email($email) |
|
444
|
|
- { |
|
445
|
|
- global $wpdb; |
|
446
|
|
- |
|
447
|
|
- $table = self::get_table_name(); |
|
448
|
|
- $email = sanitize_text_field($email); |
|
449
|
|
- |
|
450
|
|
- $item = $wpdb->get_results( |
|
451
|
|
- $wpdb->prepare( |
|
452
|
|
- "SELECT * FROM $table WHERE email = %s order by payment_date DESC", |
|
453
|
|
- $email |
|
454
|
|
- ) |
|
455
|
|
- ); |
|
456
|
|
- |
|
457
|
|
- return $item; |
|
458
|
|
- } |
|
459
|
|
- |
|
460
|
|
- /** |
|
461
|
486
|
* Get analytics counts and amounts for a specific user via a single SQL aggregate query. |
|
462
|
487
|
* Returns the same shape as get_transactions_analytics_dashboard() without loading all rows. |
|
463
|
488
|
* |
|
489
|
+ * An unconfirmed pre-2.4.0 `no_payment_required` row is left out of every figure; a confirmed |
|
490
|
+ * one counts as completed and adds 0 to the amounts (Helper::COUNTED_ROW_SQL / |
|
491
|
+ * Helper::COUNTABLE_AMOUNT_SQL). |
|
492
|
+ * |
|
464
|
493
|
* @param string $email |
|
465
|
494
|
* @return array |
|
466
|
495
|
*/ |
|
467
|
496
|
public static function get_user_analytics_by_email( $email ) { |
|
@@ -469,25 +498,30 @@ |
|
469
|
498
|
$table = self::get_table_name(); |
|
470
|
499
|
$email = sanitize_text_field( $email ); |
|
471
|
500
|
$ffi_like = '%' . $wpdb->esc_like( '"' . $email . '"' ) . '%'; |
|
472
|
501
|
|
|
502
|
+ // Helper constants only: no request data, and no `%` for prepare() to misread. |
|
503
|
+ $countable_amount = 'CAST(' . Helper::COUNTABLE_AMOUNT_SQL . ' AS DECIMAL(10,2))'; |
|
504
|
+ $completed = "status IN ('paid','Completed','completed','success','" . Helper::LEGACY_FREE_CHECKOUT_STATUS . "')"; |
|
505
|
+ $counted_row = Helper::COUNTED_ROW_SQL; |
|
506
|
+ |
|
473
|
507
|
$row = $wpdb->get_row( |
|
474
|
508
|
$wpdb->prepare( |
|
475
|
509
|
"SELECT |
|
476
|
510
|
COUNT(*) AS total_count, |
|
477
|
|
- SUM(CAST(amount AS DECIMAL(10,2))) AS total_amount, |
|
478
|
|
- SUM(CASE WHEN status IN ('paid','Completed','completed','success') |
|
511
|
+ SUM({$countable_amount}) AS total_amount, |
|
512
|
+ SUM(CASE WHEN {$completed} |
|
479
|
513
|
THEN 1 ELSE 0 END) AS completed_count, |
|
480
|
|
- SUM(CASE WHEN status IN ('paid','Completed','completed','success') |
|
481
|
|
- THEN CAST(amount AS DECIMAL(10,2)) ELSE 0 END) AS completed_amount, |
|
482
|
|
- SUM(CASE WHEN status IN ('pending','Pending','unpaid','incomplete','Incomplete') OR status IS NULL |
|
514
|
+ SUM(CASE WHEN {$completed} |
|
515
|
+ THEN {$countable_amount} ELSE 0 END) AS completed_amount, |
|
516
|
+ SUM(CASE WHEN status IN ('pending','Pending','unpaid','incomplete','Incomplete','failed') OR status IS NULL |
|
483
|
517
|
THEN 1 ELSE 0 END) AS incomplete_count, |
|
484
|
|
- SUM(CASE WHEN status IN ('pending','Pending','unpaid','incomplete','Incomplete') OR status IS NULL |
|
518
|
+ SUM(CASE WHEN status IN ('pending','Pending','unpaid','incomplete','Incomplete','failed') OR status IS NULL |
|
485
|
519
|
THEN CAST(amount AS DECIMAL(10,2)) ELSE 0 END) AS incomplete_amount, |
|
486
|
520
|
SUM(CASE WHEN status = 'refunded' THEN 1 ELSE 0 END) AS refunded_count, |
|
487
|
521
|
SUM(CASE WHEN status = 'refunded' |
|
488
|
522
|
THEN CAST(amount AS DECIMAL(10,2)) ELSE 0 END) AS refunded_amount |
|
489
|
|
- FROM $table WHERE ( email = %s OR form_fields_info LIKE %s )", |
|
523
|
+ FROM $table WHERE ( email = %s OR form_fields_info LIKE %s ) AND {$counted_row}", |
|
490
|
524
|
$email, |
|
491
|
525
|
$ffi_like |
|
492
|
526
|
) |
|
493
|
527
|
); |
|
@@ -532,11 +566,19 @@ |
|
532
|
566
|
$page = max( 1, intval( $args['page'] ) ); |
|
533
|
567
|
$per_page = max( 1, intval( $args['per_page'] ) ); |
|
534
|
568
|
$offset = ( $page - 1 ) * $per_page; |
|
535
|
569
|
|
|
536
|
|
- $type_where = ''; |
|
537
|
|
- if ( 'subscriptions' === $args['type'] ) { |
|
538
|
|
- $type_where = " AND form_fields_info LIKE '%\"subscription_id\"%'"; |
|
570
|
+ $type_where = self::user_transactions_type_where( (string) $args['type'] ); |
|
571
|
+ if ( null === $type_where ) { |
|
572
|
+ // Nothing defines this row type (e.g. 'subscriptions' without Pro): answer |
|
573
|
+ // with no rows, never with every row the user owns. |
|
574
|
+ return [ |
|
575
|
+ 'transactions' => [], |
|
576
|
+ 'total' => 0, |
|
577
|
+ 'pages' => 1, |
|
578
|
+ 'page' => $page, |
|
579
|
+ 'per_page' => $per_page, |
|
580
|
+ ]; |
|
539
|
581
|
} |
|
540
|
582
|
|
|
541
|
583
|
// Match rows where the email column is set directly OR where the email |
|
542
|
584
|
// appears as a quoted value inside the serialized form_fields_info blob. |
|
@@ -574,8 +616,32 @@ |
|
574
|
616
|
]; |
|
575
|
617
|
} |
|
576
|
618
|
|
|
577
|
619
|
/** |
|
620
|
+ * The SQL condition narrowing get_user_transactions_paginated() to a row type. |
|
621
|
+ * |
|
622
|
+ * 'transactions' (or no type) is every row the user owns. Every other type is |
|
623
|
+ * defined by `better_payment/db/user_transactions_type_where` ($where, $type), |
|
624
|
+ * which starts from null: Pro supplies the 'subscriptions' condition for its |
|
625
|
+ * recurring and split payments. A type nobody defines returns null, and the |
|
626
|
+ * caller answers with no rows. |
|
627
|
+ * |
|
628
|
+ * @since 2.4.0 |
|
629
|
+ * |
|
630
|
+ * @param string $type Requested row type. |
|
631
|
+ * @return string|null SQL fragment starting with " AND", '' for all rows, null for none. |
|
632
|
+ */ |
|
633
|
+ private static function user_transactions_type_where( string $type ) { |
|
634
|
+ if ( '' === $type || 'transactions' === $type ) { |
|
635
|
+ return ''; |
|
636
|
+ } |
|
637
|
+ |
|
638
|
+ $where = apply_filters( 'better_payment/db/user_transactions_type_where', null, $type ); |
|
639
|
+ |
|
640
|
+ return is_string( $where ) ? $where : null; |
|
641
|
+ } |
|
642
|
+ |
|
643
|
+ /** |
|
578
|
644
|
* Delete a transaction |
|
579
|
645
|
* |
|
580
|
646
|
* @param int $id |
|
581
|
647
|
* |
|
@@ -620,8 +686,17 @@ |
|
620
|
686
|
|
|
621
|
687
|
/** |
|
622
|
688
|
* Get transactions amount |
|
623
|
689
|
* |
|
690
|
+ * Lite never calls this; Better Payment Pro <= 1.4.3's AnalyticsModel does, and |
|
691
|
+ * tests/Unit/ProCouplingContractTest.php pins it. Pro 1.4.4 carries its own copy |
|
692
|
+ * (better-payment-pro/includes/Models/AnalyticsModel.php). |
|
693
|
+ * |
|
694
|
+ * @deprecated 2.4.0 A fatal guard only: Pro 1.4.3 is unsupported since |
|
695
|
+ * ProCompatibility::MIN_PRO_VERSION 1.4.4, but a site that updates Lite |
|
696
|
+ * first must not fatal on Pro's Analytics screen. Delete once no |
|
697
|
+ * supported site can run Pro 1.4.3. |
|
698
|
+ * |
|
624
|
699
|
* @return array |
|
625
|
700
|
* @since 0.0.1 |
|
626
|
701
|
*/ |
|
627
|
702
|
public function get_transactions_by_statuses($statuses = array(), $payment_date_from = '', $payment_date_to = '', $fetchNull=0) { |
|
@@ -646,17 +721,17 @@ |
|
646
|
721
|
$statuses = implode(',', $statuses); |
|
647
|
722
|
|
|
648
|
723
|
if(!empty($payment_date_from) && !empty($payment_date_to)){ |
|
649
|
724
|
$amount = $wpdb->get_results( |
|
650
|
|
- "SELECT amount, payment_date, email FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ") AND payment_date BETWEEN '" . esc_sql($payment_date_from) . "' AND '" . esc_sql($payment_date_to) . "'" |
|
725
|
+ "SELECT " . self::COUNTABLE_AMOUNT_SQL . " AS amount, payment_date, email FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ") AND " . self::COUNTED_ROW_SQL . " AND payment_date BETWEEN '" . esc_sql($payment_date_from) . "' AND '" . esc_sql($payment_date_to) . "'" |
|
651
|
726
|
); |
|
652
|
727
|
} else if(!empty($payment_date_from) && empty($payment_date_to)){ |
|
653
|
728
|
$amount = $wpdb->get_results( |
|
654
|
|
- "SELECT amount, payment_date, email FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ") AND payment_date >= '" . esc_sql($payment_date_from) . "'" |
|
729
|
+ "SELECT " . self::COUNTABLE_AMOUNT_SQL . " AS amount, payment_date, email FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ") AND " . self::COUNTED_ROW_SQL . " AND payment_date >= '" . esc_sql($payment_date_from) . "'" |
|
655
|
730
|
); |
|
656
|
731
|
} else { |
|
657
|
732
|
$amount = $wpdb->get_results( |
|
658
|
|
- "SELECT amount, payment_date, email FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . " )" |
|
733
|
+ "SELECT " . self::COUNTABLE_AMOUNT_SQL . " AS amount, payment_date, email FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . " ) AND " . self::COUNTED_ROW_SQL |
|
659
|
734
|
); |
|
660
|
735
|
} |
|
661
|
736
|
|
|
662
|
737
|
return $amount; |
|
@@ -664,15 +739,17 @@ |
|
664
|
739
|
|
|
665
|
740
|
/** |
|
666
|
741
|
* Get transactions amount |
|
667
|
742
|
* |
|
668
|
|
- * @return array |
|
743
|
+ * Lite's caller, get_transactions_analytics_dashboard(), always passes |
|
744
|
+ * $filtered_transactions and is answered from that array. Without it the answer |
|
745
|
+ * comes from SQL, which only Better Payment Pro <= 1.4.3's AnalyticsModel asks |
|
746
|
+ * for — see transactions_amount_by_statuses_query(). |
|
747
|
+ * |
|
748
|
+ * @return mixed |
|
669
|
749
|
* @since 0.0.1 |
|
670
|
750
|
*/ |
|
671
|
751
|
public function get_transactions_amount_by_statuses($statuses = array(), $payment_date_from = '', $payment_date_to = '', $count_or_amount = 'amount', $fetchNull=0, $filtered_transactions = array() ) { |
|
672
|
|
- global $wpdb; |
|
673
|
|
- |
|
674
|
|
- $table = DB::get_table_name(); |
|
675
|
752
|
$allowed_statuses = $this->allowed_statuses('all', 'v2'); |
|
676
|
753
|
|
|
677
|
754
|
$nullDataQuery = $fetchNull ? " OR status IS NULL " : ''; |
|
678
|
755
|
|
|
@@ -694,13 +771,19 @@ |
|
694
|
771
|
$filtered_transactions_by_statuses = array(); |
|
695
|
772
|
$filtered_transactions_amount = 0; |
|
696
|
773
|
|
|
697
|
774
|
foreach($filtered_transactions as $filtered_transaction) { |
|
775
|
+ // Helper's counting rule, as the SQL copies below apply it: an unconfirmed pre-2.4.0 |
|
776
|
+ // free checkout is no transaction to count, and a confirmed one adds 0. |
|
777
|
+ if ( Helper::is_unconfirmed_legacy_free_checkout( $filtered_transaction ) ) { |
|
778
|
+ continue; |
|
779
|
+ } |
|
780
|
+ |
|
698
|
781
|
if( in_array($filtered_transaction->status, $statuses_original) ) { |
|
699
|
782
|
$filtered_transactions_by_statuses[] = $filtered_transaction->id; |
|
700
|
|
- $filtered_transactions_amount += ! empty( $filtered_transaction->amount ) ? floatval( $filtered_transaction->amount ) : 0; |
|
783
|
+ $filtered_transactions_amount += Helper::countable_amount( $filtered_transaction ); |
|
701
|
784
|
} |
|
702
|
|
- } |
|
785
|
+ } |
|
703
|
786
|
|
|
704
|
787
|
if($count_or_amount == 'count'){ |
|
705
|
788
|
$filtered_transactions_by_statuses_count = count($filtered_transactions_by_statuses); |
|
706
|
789
|
return $filtered_transactions_by_statuses_count; |
|
@@ -710,11 +793,34 @@ |
|
710
|
793
|
return $filtered_transactions_amount; |
|
711
|
794
|
} |
|
712
|
795
|
} |
|
713
|
796
|
|
|
797
|
+ return $this->transactions_amount_by_statuses_query( $statuses, $nullDataQuery, $payment_date_from, $payment_date_to, $count_or_amount ); |
|
798
|
+ } |
|
799
|
+ |
|
800
|
+ /** |
|
801
|
+ * The SQL count or sum behind get_transactions_amount_by_statuses() when no |
|
802
|
+ * filtered transactions are passed. |
|
803
|
+ * |
|
804
|
+ * @deprecated 2.4.0 A fatal guard only, for Better Payment Pro <= 1.4.3 (see |
|
805
|
+ * get_transactions_by_statuses()). Pro 1.4.4 carries its own copy in |
|
806
|
+ * better-payment-pro/includes/Models/AnalyticsModel.php. |
|
807
|
+ * |
|
808
|
+ * @param string $statuses Quoted, comma-separated statuses for IN(). |
|
809
|
+ * @param string $nullDataQuery " OR status IS NULL " or ''. |
|
810
|
+ * @param string $payment_date_from Lower payment_date bound. |
|
811
|
+ * @param string $payment_date_to Upper payment_date bound. |
|
812
|
+ * @param string $count_or_amount 'count' or 'amount'. |
|
813
|
+ * @return mixed |
|
814
|
+ */ |
|
815
|
+ private function transactions_amount_by_statuses_query( $statuses, $nullDataQuery, $payment_date_from, $payment_date_to, $count_or_amount ) { |
|
816
|
+ global $wpdb; |
|
817
|
+ |
|
818
|
+ $table = DB::get_table_name(); |
|
819
|
+ |
|
714
|
820
|
if($count_or_amount == 'count') { |
|
715
|
821
|
$count = (int) $wpdb->get_var( |
|
716
|
|
- "SELECT count(id) FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . " )" |
|
822
|
+ "SELECT count(id) FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . " ) AND " . self::COUNTED_ROW_SQL |
|
717
|
823
|
); |
|
718
|
824
|
|
|
719
|
825
|
return $count; |
|
720
|
826
|
} |
|
@@ -720,44 +826,18 @@ |
|
720
|
826
|
} |
|
721
|
827
|
|
|
722
|
828
|
if(!empty($payment_date_from) && !empty($payment_date_to)){ |
|
723
|
829
|
$amount = $wpdb->get_var( |
|
724
|
|
- "SELECT sum(amount) FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ") AND payment_date BETWEEN '" . esc_sql($payment_date_from) . "' AND '" . esc_sql($payment_date_to) . "'" |
|
830
|
+ "SELECT sum(" . self::COUNTABLE_AMOUNT_SQL . ") FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ") AND " . self::COUNTED_ROW_SQL . " AND payment_date BETWEEN '" . esc_sql($payment_date_from) . "' AND '" . esc_sql($payment_date_to) . "'" |
|
725
|
831
|
); |
|
726
|
832
|
}else { |
|
727
|
833
|
$amount = $wpdb->get_var( |
|
728
|
834
|
// #TODO Amount based on filtered transactions |
|
729
|
|
- "SELECT sum(amount) FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ")" |
|
835
|
+ "SELECT sum(" . self::COUNTABLE_AMOUNT_SQL . ") FROM $table WHERE ( status IN (" . $statuses . ") " . esc_sql($nullDataQuery) . ") AND " . self::COUNTED_ROW_SQL |
|
730
|
836
|
); |
|
731
|
837
|
} |
|
732
|
838
|
|
|
733
|
839
|
return $amount; |
|
734
|
|
- } |
|
735
|
|
- |
|
736
|
|
- public static function search_transactions($items, $search_text, $offset, $per_page){ |
|
737
|
|
- $filtered_items = array(); |
|
738
|
|
- $search_text = str_replace('%', '', $search_text); |
|
739
|
|
- |
|
740
|
|
- if(count($items) > 0){ |
|
741
|
|
- $filtered_items = array_filter($items, function($item) use ($search_text){ |
|
742
|
|
- $form_fields_info = maybe_unserialize($item->form_fields_info); |
|
743
|
|
- |
|
744
|
|
- if( |
|
745
|
|
- isset($form_fields_info['first_name']) && stripos($form_fields_info['first_name'], $search_text) !== false |
|
746
|
|
- || isset($form_fields_info['last_name']) && stripos($form_fields_info['last_name'], $search_text) !== false |
|
747
|
|
- || isset($form_fields_info['primary_first_name']) && stripos($form_fields_info['primary_first_name'], $search_text) !== false |
|
748
|
|
- || isset($form_fields_info['primary_last_name']) && stripos($form_fields_info['primary_last_name'], $search_text) !== false |
|
749
|
|
- || isset($form_fields_info['email']) && stripos($form_fields_info['email'], $search_text) !== false |
|
750
|
|
- || isset($form_fields_info['primary_email']) && stripos($form_fields_info['primary_email'], $search_text) !== false |
|
751
|
|
- ){ |
|
752
|
|
- return true; |
|
753
|
|
- } |
|
754
|
|
- |
|
755
|
|
- }); |
|
756
|
|
- |
|
757
|
|
- } |
|
758
|
|
- |
|
759
|
|
- return $filtered_items; |
|
760
|
840
|
} |
|
761
|
841
|
|
|
762
|
842
|
public static function mark_as_completed($id) |
|
763
|
843
|
{ |