PluginProbe
Stripe Payment Forms by WP Simple Pay – Accept Credit Card Payments + Subscriptions with Stripe / trunk
Stripe Payment Forms by WP Simple Pay – Accept Credit Card Payments + Subscriptions with Stripe vtrunk
4.17.3 trunk 2.2.0 2.3.0 2.3.1 2.3.2 2.3.3 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.6.2 2.6.3 4.10.0 4.11.1 4.12.2 4.14.1 4.14.2 4.14.3 4.15.0 4.16.0 All 59 releases
stripe / src / Report / ActivityOverviewReport.php

ActivityOverviewReport.php in Stripe Payment Forms by WP Simple Pay – Accept Credit Card Payments + Subscriptions with Stripe trunk, at src/Report/ActivityOverviewReport.php

498 lines 12.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Report: Activity Overview
4 *
5 * Top stats (with deltas) and top 5 forms (with deltas), and a DYK blurb.
6 *
7 * @package SimplePay
8 * @subpackage Core
9 * @copyright Copyright (c) 2023, Sandhills Development, LLC
10 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
11 * @since 4.7.3
12 */
13
14 namespace SimplePay\Core\Report;
15
16 use DateInterval;
17 use stdClass;
18
19 /**
20 * ActivityOverviewReport class.
21 *
22 * @since 4.7.3
23 */
24 class ActivityOverviewReport {
25
26 use ReportTrait;
27
28 /**
29 * The report date range.
30 *
31 * The start and end dates of the range are used to determine the dates that
32 * are calculated for each stat.
33 *
34 * e.g if the range has 7 days then gross volume would be the total amount
35 * of all transactions for each of the 7 days compared to the total amount
36 * of all transactions for the previous 7 days.
37 *
38 * @since 4.7.3
39 * @var \SimplePay\Core\Report\DateRange
40 */
41 protected $range;
42
43 /**
44 * The report currency.
45 *
46 * @since 4.7.3
47 * @var string
48 */
49 protected $currency;
50
51 /**
52 * The report ranges.
53 *
54 * @since 4.7.3
55 * @var array<string, \SimplePay\Core\Report\DateRange>
56 */
57 protected $ranges;
58
59 /**
60 * ActivityOverviewReport.
61 *
62 * @since 4.7.3
63 *
64 * @param \SimplePay\Core\Report\DateRange $range The report date range.
65 * @param string $currency The report currency.
66 */
67 public function __construct( $range, $currency ) {
68 $this->range = $range;
69 $this->currency = $currency;
70
71 // The current range is the range passed in.
72 $current = $range;
73
74 // The previous range is created by offsetting the current range by the
75 // number of days in the current range.
76 $diff = $this->range->end->diff( $this->range->start );
77
78 // If the difference is less than a day, set the difference to 1 day.
79 $days = 0 === $diff->days ? 1 : $diff->days - 1;
80
81 $interval = new DateInterval( sprintf( 'P%dD', $days ) );
82
83 $previous = new DateRange(
84 'custom',
85 $range->start->sub( $interval )->format( 'Y-m-d 00:00:00' ),
86 $range->end->sub( $interval )->format( 'Y-m-d 23:59:59' )
87 );
88
89 $this->ranges = array(
90 'current' => $current,
91 'previous' => $previous,
92 );
93 }
94
95 /**
96 * Formats the transaction data for the report.
97 *
98 * @since 4.7.3
99 *
100 * @return array<int, array<string, mixed>>
101 */
102 public function get_stats() {
103 $stats = $this->get_stats_data();
104 $current = $stats['current'];
105 $previous = $stats['previous'];
106
107 return array(
108 // Gross Volume.
109 array(
110 'id' => 'gross-volume',
111 'label' => __( 'Gross Volume', 'stripe' ),
112 'icon' => '💰',
113 'type' => 'currency',
114 'value' => array(
115 'raw' => $current->gross_volume,
116 'rendered' => simpay_format_currency(
117 $current->gross_volume,
118 $this->currency,
119 true,
120 false
121 ),
122 ),
123 'delta' => $this->get_delta(
124 $current->gross_volume,
125 $previous->gross_volume
126 ),
127 ),
128 // Successful Payments.
129 array(
130 'id' => 'successful-payments',
131 'label' => __( 'Successful Payments', 'stripe' ),
132 'icon' => '�
133 ',
134 'type' => 'number',
135 'value' => array(
136 'raw' => $current->successful_payments,
137 'rendered' => $current->successful_payments,
138 ),
139 'delta' => $this->get_delta(
140 $current->successful_payments,
141 $previous->successful_payments
142 ),
143 ),
144 // Customers.
145 array(
146 'id' => 'new-customers',
147 'label' => __( 'Customers', 'stripe' ),
148 'icon' => '👤',
149 'value' => array(
150 'raw' => $current->customers,
151 'rendered' => $current->customers,
152 ),
153 'delta' => $this->get_delta(
154 $current->customers,
155 $previous->customers
156 ),
157 ),
158 // All Payments.
159 array(
160 'id' => 'all-payments',
161 'label' => __( 'All Payments', 'stripe' ),
162 'icon' => '📊',
163 'value' => array(
164 'raw' => $current->all_payments,
165 'rendered' => $current->all_payments,
166 ),
167 'delta' => $this->get_delta(
168 $current->all_payments,
169 $previous->all_payments
170 ),
171 ),
172 );
173 }
174
175 /**
176 * Formats the top forms data for the report.
177 *
178 * @since 4.7.3
179 *
180 * @return array<int, array<string, mixed>>
181 */
182 public function get_top_forms() {
183 $top_forms = $this->get_top_forms_data();
184 $current = $top_forms['current'];
185 $previous = $top_forms['previous'];
186
187 $top_forms = array_map(
188 function( $form ) use ( $current, $previous ) {
189 /** @var float $current_gross */
190 $current_gross = isset( $current[ $form->id ] )
191 ? (float) $current[ $form->id ]->gross_volume
192 : (float) 0;
193
194 /** @var float $previous_gross */
195 $previous_gross = isset( $previous[ $form->id ] )
196 ? (float) $previous[ $form->id ]->gross_volume
197 : (float) 0;
198
199 $delta = $this->get_delta( $current_gross, $previous_gross );
200
201 $form_title = get_post_meta(
202 $form->id,
203 '_company_name',
204 true
205 );
206
207 if ( empty( $form_title ) ) {
208 $form_title = __( '(no title)', 'stripe' );
209 }
210
211 return array(
212 'id' => $form->id,
213 'title' => $form_title,
214 'href' => add_query_arg(
215 array(
216 'post' => $form->id,
217 'action' => 'edit',
218 ),
219 admin_url( 'post.php' )
220 ),
221 'gross_volume' => array(
222 'raw' => $form->gross_volume,
223 'rendered' => simpay_format_currency(
224 $form->gross_volume,
225 $this->currency
226 ),
227 ),
228 'delta' => $delta,
229 );
230 },
231 $current
232 );
233
234 return array_values( $top_forms );
235 }
236
237 /**
238 * Returns a tip to display in the report.
239 *
240 * @since 4.7.3
241 *
242 * @return array<string, string>
243 */
244 public function get_tip() {
245 $tips = $this->get_tips();
246
247 return $tips[ array_rand( $tips ) ];
248 }
249
250 /**
251 * Returns the transaction data for to be used in the stats.
252 *
253 * @since 4.7.3
254 *
255 * @return array<string, \stdClass>
256 */
257 private function get_stats_data() {
258 $stats = array();
259 $periods = array( 'current', 'previous' );
260
261 foreach ( $periods as $period ) {
262 $period_stats = new stdClass();
263
264 // Gross volume.
265 $period_stats->gross_volume = $this->get_gross_volume( $period );
266
267 // Customers.
268 $period_stats->customers = $this->get_customers( $period );
269
270 // Successful payments.
271 $period_stats->successful_payments = $this->get_payments(
272 $period,
273 array( 'succeeded' )
274 );
275
276 // All payments.
277 $period_stats->all_payments = $this->get_payments( $period );
278
279 $stats[ $period ] = $period_stats;
280 }
281
282 return $stats;
283 }
284
285 /**
286 * Returns the transaction data for to be used in the Top Forms list.
287 *
288 * @since 4.7.3
289 *
290 * @return array<string, array<int, \stdClass>>
291 */
292 private function get_top_forms_data() {
293 global $wpdb;
294
295 $forms = array();
296 $periods = array( 'current', 'previous' );
297
298 foreach ( $periods as $period ) {
299 $forms[ $period ] = $wpdb->get_results(
300 $wpdb->prepare(
301 "SELECT DISTINCT form_id as id, SUM(amount_total) as gross_volume FROM {$wpdb->prefix}wpsp_transactions WHERE livemode = %d AND currency = %s AND status = 'succeeded' AND object IN ('payment_intent', 'setup_intent') AND date_created BETWEEN %s AND %s GROUP BY form_id ORDER BY gross_volume DESC LIMIT 0, 5",
302 simpay_is_test_mode() ? 0 : 1,
303 $this->currency,
304 $this->ranges[ $period ]->start->format( 'Y-m-d 00:00:00' ),
305 $this->ranges[ $period ]->end->format( 'Y-m-d 23:59:59' )
306 ),
307 OBJECT_K
308 );
309 }
310
311 return $forms;
312 }
313
314 /**
315 * Returns the gross volume for the given period.
316 *
317 * @since 4.7.3
318 *
319 * @param string $period The period to get the gross volume for.
320 * @return float
321 */
322 private function get_gross_volume( $period ) {
323 global $wpdb;
324
325 $select_value = simpay_is_zero_decimal( $this->currency )
326 ? 'SUM(amount_total)'
327 : 'SUM(amount_total / 100)';
328
329 $volume = $wpdb->get_var(
330 $wpdb->prepare(
331 "SELECT {$select_value} FROM {$wpdb->prefix}wpsp_transactions WHERE livemode = %d AND currency = %s AND status = 'succeeded' AND object IN ('payment_intent', 'setup_intent') AND date_created BETWEEN %s AND %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
332 simpay_is_test_mode() ? 0 : 1,
333 $this->currency,
334 $this->ranges[ $period ]->start->format( 'Y-m-d 00:00:00' ),
335 $this->ranges[ $period ]->end->format( 'Y-m-d 23:59:59' )
336 )
337 );
338
339 return null === $volume ? 0 : $volume;
340 }
341
342 /**
343 * Returns the number of payments for the given period and state(s).
344 *
345 * @since 4.7.3
346 *
347 * @param string $period The period to get the gross volume for.
348 * @param string|array<string> $states The state(s) to get the number of payments for.
349 * @return float
350 */
351 private function get_payments( $period, $states = array() ) {
352 global $wpdb;
353
354 if ( is_string( $states ) ) {
355 $states = array( $states );
356 }
357
358 if ( empty( $states ) ) {
359 $select = "SUM(CASE WHEN object != 'checkout_session' THEN 1 ELSE 0 END)";
360 } else {
361 $in = implode( ',', $states );
362
363 $select = $wpdb->prepare(
364 'SUM(CASE WHEN status IN(%s) THEN 1 ELSE 0 END)',
365 $in
366 );
367 }
368
369 $payments = $wpdb->get_var(
370 $wpdb->prepare(
371 "SELECT {$select} FROM {$wpdb->prefix}wpsp_transactions WHERE livemode = %d AND currency = %s AND date_created BETWEEN %s AND %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
372 simpay_is_test_mode() ? 0 : 1,
373 $this->currency,
374 $this->ranges[ $period ]->start->format( 'Y-m-d 00:00:00' ),
375 $this->ranges[ $period ]->end->format( 'Y-m-d 23:59:59' )
376 )
377 );
378
379 return null === $payments ? 0 : $payments;
380 }
381
382 /**
383 * Returns the number of customers (unique by email) for the given period.
384 *
385 * @since 4.7.3
386 *
387 * @param string $period The period to get the gross volume for.
388 * @return int
389 */
390 private function get_customers( $period ) {
391 global $wpdb;
392
393 $customers = $wpdb->get_var(
394 $wpdb->prepare(
395 "SELECT COUNT(DISTINCT email) FROM {$wpdb->prefix}wpsp_transactions WHERE livemode = %d AND currency = %s AND status = 'succeeded' AND object IN ('payment_intent', 'setup_intent') AND date_created BETWEEN %s AND %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
396 simpay_is_test_mode() ? 0 : 1,
397 $this->currency,
398 $this->ranges[ $period ]->start->format( 'Y-m-d 00:00:00' ),
399 $this->ranges[ $period ]->end->format( 'Y-m-d 23:59:59' )
400 )
401 );
402
403 return null === $customers ? 0 : $customers;
404 }
405
406 /**
407 * Returns an array of tips to display in the report.
408 *
409 * @since 4.7.3
410 *
411 * @return array<array<string, string>>
412 */
413 private function get_tips() {
414 $tips = array(
415 array(
416 'title' => __(
417 'Set up automatic tax collection',
418 'stripe'
419 ),
420 'href' => 'https://wpsimplepay.com/how-to-collect-taxes-for-stripe-payments-in-wordpress/',
421 'text' => __(
422 'Charge a fixed tax rate to everyone or collect different taxes dynamically based on customer location',
423 'stripe'
424 ),
425 ),
426 array(
427 'title' => __(
428 'Dynamically customize payment receipts',
429 'stripe'
430 ),
431 'href' => 'https://wpsimplepay.com/how-to-easily-customize-stripe-email-receipts-in-wordpress/ ',
432 'text' => __(
433 'Customize every single detail based on the data collected from users.',
434 'stripe'
435 ),
436 ),
437 array(
438 'title' => __(
439 'We support 10+ payment methods',
440 'stripe'
441 ),
442 'href' => 'https://wpsimplepay.com/how-to-allow-users-to-choose-a-payment-method-in-wordpress/',
443 'text' => __(
444 'Offer multiple payment methods and allow users to pay with their favorite.',
445 'stripe'
446 ),
447 ),
448 array(
449 'title' => __(
450 'Smart inventory management',
451 'stripe'
452 ),
453 'href' => 'https://wpsimplepay.com/how-to-create-an-order-form-with-wordpress-step-by-step/',
454 'text' => __(
455 'Automatically hide your payment form after a set number of payments.',
456 'stripe'
457 ),
458 ),
459 array(
460 'title' => __(
461 'Encourage payments with discount codes',
462 'stripe'
463 ),
464 'href' => 'https://wpsimplepay.com/how-to-add-a-coupon-code-field-to-your-wordpress-payment-forms/',
465 'text' => __(
466 'Offer a fixed amount or a percentage discount for a specified duration or forever.',
467 'stripe'
468 ),
469 ),
470 array(
471 'title' => __(
472 'Remove Stripe processing fees',
473 'stripe'
474 ),
475 'href' => 'https://wpsimplepay.com/how-to-remove-credit-card-processing-fees-in-wordpress/',
476 'text' => __(
477 'Charge an additional fee to ensure you receive the full payment amount.',
478 'stripe'
479 ),
480 ),
481 );
482
483 return array_map(
484 function( $tip ) {
485 $tip['href'] = simpay_ga_url(
486 $tip['href'],
487 'activity-reports',
488 $tip['title']
489 );
490
491 return $tip;
492 },
493 $tips
494 );
495 }
496
497 }
498