Completed
Pull Request — master (#11372)
by Matty
08:38
created

WC_Report_Coupon_Usage::output_report()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 14

Duplication

Lines 23
Ratio 100 %

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 4
nop 0
dl 23
loc 23
rs 9.0856
c 0
b 0
f 0
1
<?php
2
3
if ( ! defined( 'ABSPATH' ) ) {
4
	exit; // Exit if accessed directly
5
}
6
7
/**
8
 * WC_Report_Coupon_Usage
9
 *
10
 * @author      WooThemes
11
 * @category    Admin
12
 * @package     WooCommerce/Admin/Reports
13
 * @version     2.1.0
14
 */
15
class WC_Report_Coupon_Usage extends WC_Admin_Report {
16
17
	/**
18
	 * Chart colours.
19
	 *
20
	 * @var array
21
	 */
22
	public $chart_colours = array();
23
24
	/**
25
	 * Coupon codes.
26
	 *
27
	 * @var array
28
	 */
29
	public $coupon_codes = array();
30
31
	/**
32
	 * Constructor.
33
	 */
34 View Code Duplication
	public function __construct() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
35
		if ( isset( $_GET['coupon_codes'] ) && is_array( $_GET['coupon_codes'] ) ) {
36
			$this->coupon_codes = array_filter( array_map( 'sanitize_text_field', $_GET['coupon_codes'] ) );
37
		} elseif ( isset( $_GET['coupon_codes'] ) ) {
38
			$this->coupon_codes = array_filter( array( sanitize_text_field( $_GET['coupon_codes'] ) ) );
39
		}
40
	}
41
42
	/**
43
	 * Get the legend for the main chart sidebar.
44
	 *
45
	 * @return array
46
	 */
47
	public function get_chart_legend() {
48
		$legend = array();
49
50
		$total_discount_query = array(
51
			'data'         => array(
52
				'discount_amount' => array(
53
					'type'            => 'order_item_meta',
54
					'order_item_type' => 'coupon',
55
					'function'        => 'SUM',
56
					'name'            => 'discount_amount'
57
				)
58
			),
59
			'where'        => array(
60
				array(
61
					'key'      => 'order_item_type',
62
					'value'    => 'coupon',
63
					'operator' => '='
64
				)
65
			),
66
			'query_type'   => 'get_var',
67
			'filter_range' => true,
68
			'order_types'  => wc_get_order_types( 'order-count' ),
69
		);
70
71
		$total_coupons_query = array(
72
			'data'         => array(
73
				'order_item_id' => array(
74
					'type'            => 'order_item',
75
					'order_item_type' => 'coupon',
76
					'function'        => 'COUNT',
77
					'name'            => 'order_coupon_count'
78
				)
79
			),
80
			'where'        => array(
81
				array(
82
					'key'      => 'order_item_type',
83
					'value'    => 'coupon',
84
					'operator' => '='
85
				)
86
			),
87
			'query_type'   => 'get_var',
88
			'filter_range' => true,
89
			'order_types'  => wc_get_order_types( 'order-count' ),
90
		);
91
92 View Code Duplication
		if ( ! empty( $this->coupon_codes ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
93
			$coupon_code_query = array(
94
				'type'     => 'order_item',
95
				'key'      => 'order_item_name',
96
				'value'    => $this->coupon_codes,
97
				'operator' => 'IN'
98
			);
99
100
			$total_discount_query['where'][] = $coupon_code_query;
101
			$total_coupons_query['where'][]  = $coupon_code_query;
102
		}
103
104
		$total_discount = $this->get_order_report_data( $total_discount_query );
105
		$total_coupons  = absint( $this->get_order_report_data( $total_coupons_query ) );
106
107
		$legend[] = array(
108
			'title'            => sprintf( __( '%s discounts in total', 'woocommerce' ), '<strong>' . wc_price( $total_discount ) . '</strong>' ),
109
			'color'            => $this->chart_colours['discount_amount'],
110
			'highlight_series' => 1
111
		);
112
113
		$legend[] = array(
114
			'title'            => sprintf( __( '%s coupons used in total', 'woocommerce' ), '<strong>' . $total_coupons . '</strong>' ),
115
			'color'            => $this->chart_colours['coupon_count'],
116
			'highlight_series' => 0
117
		);
118
119
		return $legend;
120
	}
121
122
	/**
123
	 * Output the report.
124
	 */
125 View Code Duplication
	public function output_report() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
126
		$ranges = array(
127
			'year'       => __( 'Year', 'woocommerce' ),
128
			'last_month' => __( 'Last Month', 'woocommerce' ),
129
			'month'      => __( 'This Month', 'woocommerce' ),
130
			'7day'       => __( 'Last 7 Days', 'woocommerce' )
131
		);
132
133
		$this->chart_colours = array(
134
			'discount_amount' => '#3498db',
135
			'coupon_count'    => '#d4d9dc',
136
		);
137
138
		$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : '7day';
139
140
		if ( ! in_array( $current_range, array( 'custom', 'year', 'last_month', 'month', '7day' ) ) ) {
141
			$current_range = '7day';
142
		}
143
144
		$this->calculate_current_range( $current_range );
145
146
		include( WC()->plugin_path() . '/includes/admin/views/html-report-by-date.php' );
147
	}
148
149
	/**
150
	 * Get chart widgets.
151
	 *
152
	 * @return array
153
	 */
154
	public function get_chart_widgets() {
155
		$widgets = array();
156
157
		$widgets[] = array(
158
			'title'    => '',
159
			'callback' => array( $this, 'coupons_widget' )
160
		);
161
162
		return $widgets;
163
	}
164
165
	/**
166
	 * Output coupons widget.
167
	 */
168
	public function coupons_widget() {
169
		?>
170
		<h4 class="section_title"><span><?php _e( 'Filter by coupon', 'woocommerce' ); ?></span></h4>
171
		<div class="section">
172
			<form method="GET">
173
				<div>
174
					<?php
175
						$used_coupons = $this->get_order_report_data( array(
176
							'data'         => array(
177
								'order_item_name' => array(
178
									'type'            => 'order_item',
179
									'order_item_type' => 'coupon',
180
									'function'        => '',
181
									'distinct'        => true,
182
									'name'            => 'order_item_name'
183
								)
184
							),
185
							'where'        => array(
186
								array(
187
									'key'      => 'order_item_type',
188
									'value'    => 'coupon',
189
									'operator' => '='
190
								)
191
							),
192
							'query_type'   => 'get_col',
193
							'filter_range' => false
194
						) );
195
196
						if ( ! empty( $used_coupons ) && is_array( $used_coupons ) ) :
197
					?>
198
						<select id="coupon_codes" name="coupon_codes" class="wc-enhanced-select" data-placeholder="<?php esc_attr_e( 'Choose coupons&hellip;', 'woocommerce' ); ?>" style="width:100%;">
199
							<option value=""><?php _e( 'All coupons', 'woocommerce' ); ?></option>
200
							<?php
201
								foreach ( $used_coupons as $coupon ) {
202
									echo '<option value="' . esc_attr( $coupon ) . '" ' . selected( in_array( $coupon, $this->coupon_codes ), true, false ) . '>' . $coupon . '</option>';
203
								}
204
							?>
205
						</select>
206
						<input type="submit" class="submit button" value="<?php esc_attr_e( 'Show', 'woocommerce' ); ?>" />
207
						<input type="hidden" name="range" value="<?php if ( ! empty( $_GET['range'] ) ) echo esc_attr( $_GET['range'] ); ?>" />
208
						<input type="hidden" name="start_date" value="<?php if ( ! empty( $_GET['start_date'] ) ) echo esc_attr( $_GET['start_date'] ); ?>" />
209
						<input type="hidden" name="end_date" value="<?php if ( ! empty( $_GET['end_date'] ) ) echo esc_attr( $_GET['end_date'] ); ?>" />
210
						<input type="hidden" name="page" value="<?php if ( ! empty( $_GET['page'] ) ) echo esc_attr( $_GET['page'] ); ?>" />
211
						<input type="hidden" name="tab" value="<?php if ( ! empty( $_GET['tab'] ) ) echo esc_attr( $_GET['tab'] ); ?>" />
212
						<input type="hidden" name="report" value="<?php if ( ! empty( $_GET['report'] ) ) echo esc_attr( $_GET['report'] ); ?>" />
213
					<?php else : ?>
214
						<span><?php _e( 'No used coupons found', 'woocommerce' ); ?></span>
215
					<?php endif; ?>
216
				</div>
217
			</form>
218
		</div>
219
		<h4 class="section_title"><span><?php _e( 'Most Popular', 'woocommerce' ); ?></span></h4>
220
		<div class="section">
221
			<table cellspacing="0">
222
				<?php
223
				$most_popular = $this->get_order_report_data( array(
224
					'data'         => array(
225
						'order_item_name' => array(
226
							'type'            => 'order_item',
227
							'order_item_type' => 'coupon',
228
							'function'        => '',
229
							'name'            => 'coupon_code'
230
						),
231
						'order_item_id'   => array(
232
							'type'            => 'order_item',
233
							'order_item_type' => 'coupon',
234
							'function'        => 'COUNT',
235
							'name'            => 'coupon_count'
236
						),
237
					),
238
					'where'        => array(
239
						array(
240
							'type'     => 'order_item',
241
							'key'      => 'order_item_type',
242
							'value'    => 'coupon',
243
							'operator' => '='
244
						)
245
					),
246
					'order_by'     => 'coupon_count DESC',
247
					'group_by'     => 'order_item_name',
248
					'limit'        => 12,
249
					'query_type'   => 'get_results',
250
					'filter_range' => true
251
				) );
252
253 View Code Duplication
				if ( ! empty( $most_popular ) && is_array( $most_popular ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
254
					foreach ( $most_popular as $coupon ) {
255
						echo '<tr class="' . ( in_array( $coupon->coupon_code, $this->coupon_codes ) ? 'active' : '' ) . '">
256
							<td class="count" width="1%">' . $coupon->coupon_count . '</td>
257
							<td class="name"><a href="' . esc_url( add_query_arg( 'coupon_codes', $coupon->coupon_code ) ) . '">' . $coupon->coupon_code . '</a></td>
258
						</tr>';
259
					}
260
				} else {
261
					echo '<tr><td colspan="2">' . __( 'No coupons found in range', 'woocommerce' ) . '</td></tr>';
262
				}
263
				?>
264
			</table>
265
		</div>
266
		<h4 class="section_title"><span><?php _e( 'Most Discount', 'woocommerce' ); ?></span></h4>
267
		<div class="section">
268
			<table cellspacing="0">
269
				<?php
270
				$most_discount = $this->get_order_report_data( array(
271
					'data'         => array(
272
						'order_item_name' => array(
273
							'type'            => 'order_item',
274
							'order_item_type' => 'coupon',
275
							'function'        => '',
276
							'name'            => 'coupon_code'
277
						),
278
						'discount_amount' => array(
279
							'type'            => 'order_item_meta',
280
							'order_item_type' => 'coupon',
281
							'function'        => 'SUM',
282
							'name'            => 'discount_amount'
283
						)
284
					),
285
					'where'        => array(
286
						array(
287
							'type'     => 'order_item',
288
							'key'      => 'order_item_type',
289
							'value'    => 'coupon',
290
							'operator' => '='
291
						)
292
					),
293
					'order_by'     => 'discount_amount DESC',
294
					'group_by'     => 'order_item_name',
295
					'limit'        => 12,
296
					'query_type'   => 'get_results',
297
					'filter_range' => true
298
				) );
299
300 View Code Duplication
				if ( ! empty( $most_discount ) && is_array( $most_discount ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
301
					foreach ( $most_discount as $coupon ) {
302
						echo '<tr class="' . ( in_array( $coupon->coupon_code, $this->coupon_codes ) ? 'active' : '' ) . '">
303
							<td class="count" width="1%">' . wc_price( $coupon->discount_amount ) . '</td>
304
							<td class="name"><a href="' . esc_url( add_query_arg( 'coupon_codes', $coupon->coupon_code ) ) . '">' . $coupon->coupon_code . '</a></td>
305
						</tr>';
306
					}
307
				} else {
308
					echo '<tr><td colspan="3">' . __( 'No coupons found in range', 'woocommerce' ) . '</td></tr>';
309
				}
310
				?>
311
			</table>
312
		</div>
313
		<script type="text/javascript">
314
			jQuery('.section_title').click(function(){
315
				var next_section = jQuery(this).next('.section');
316
317
				if ( jQuery(next_section).is(':visible') )
318
					return false;
319
320
				jQuery('.section:visible').slideUp();
321
				jQuery('.section_title').removeClass('open');
322
				jQuery(this).addClass('open').next('.section').slideDown();
323
324
				return false;
325
			});
326
			jQuery('.section').slideUp( 100, function() {
327
				<?php if ( empty( $this->coupon_codes ) ) : ?>
328
					jQuery('.section_title:eq(1)').click();
329
				<?php else : ?>
330
					jQuery('.section_title:eq(0)').click();
331
				<?php endif; ?>
332
			});
333
		</script>
334
		<?php
335
	}
336
337
	/**
338
	 * Output an export link.
339
	 */
340 View Code Duplication
	public function get_export_button() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
341
		$current_range = ! empty( $_GET['range'] ) ? sanitize_text_field( $_GET['range'] ) : '7day';
342
		?>
343
		<a
344
			href="#"
345
			download="report-<?php echo esc_attr( $current_range ); ?>-<?php echo date_i18n( 'Y-m-d', current_time( 'timestamp' ) ); ?>.csv"
346
			class="export_csv"
347
			data-export="chart"
348
			data-xaxes="<?php esc_attr_e( 'Date', 'woocommerce' ); ?>"
349
			data-groupby="<?php echo $this->chart_groupby; ?>"
350
		>
351
			<?php _e( 'Export CSV', 'woocommerce' ); ?>
352
		</a>
353
		<?php
354
	}
355
356
	/**
357
	 * Get the main chart.
358
	 *
359
	 * @return string
360
	 */
361
	public function get_main_chart() {
362
		global $wp_locale;
363
364
		// Get orders and dates in range - we want the SUM of order totals, COUNT of order items, COUNT of orders, and the date
365
		$order_coupon_counts_query = array(
366
			'data'         => array(
367
				'order_item_name' => array(
368
					'type'            => 'order_item',
369
					'order_item_type' => 'coupon',
370
					'function'        => 'COUNT',
371
					'name'            => 'order_coupon_count'
372
				),
373
				'post_date'       => array(
374
					'type'     => 'post_data',
375
					'function' => '',
376
					'name'     => 'post_date'
377
				),
378
			),
379
			'where'        => array(
380
				array(
381
					'key'      => 'order_item_type',
382
					'value'    => 'coupon',
383
					'operator' => '='
384
				)
385
			),
386
			'group_by'     => $this->group_by_query,
387
			'order_by'     => 'post_date ASC',
388
			'query_type'   => 'get_results',
389
			'filter_range' => true,
390
			'order_types'  => wc_get_order_types( 'order-count' )
391
		);
392
393
		$order_discount_amounts_query = array(
394
			'data'         => array(
395
				'discount_amount' => array(
396
					'type'            => 'order_item_meta',
397
					'order_item_type' => 'coupon',
398
					'function'        => 'SUM',
399
					'name'            => 'discount_amount'
400
				),
401
				'post_date'       => array(
402
					'type'     => 'post_data',
403
					'function' => '',
404
					'name'     => 'post_date'
405
				),
406
			),
407
			'where'        => array(
408
				array(
409
					'key'      => 'order_item_type',
410
					'value'    => 'coupon',
411
					'operator' => '='
412
				)
413
			),
414
			'group_by'     => $this->group_by_query . ', order_item_name',
415
			'order_by'     => 'post_date ASC',
416
			'query_type'   => 'get_results',
417
			'filter_range' => true,
418
			'order_types'  => wc_get_order_types( 'order-count' )
419
		);
420
421 View Code Duplication
		if ( ! empty( $this->coupon_codes ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
422
			$coupon_code_query = array(
423
				'type'     => 'order_item',
424
				'key'      => 'order_item_name',
425
				'value'    => $this->coupon_codes,
426
				'operator' => 'IN'
427
			);
428
429
			$order_coupon_counts_query['where'][]    = $coupon_code_query;
430
			$order_discount_amounts_query['where'][] = $coupon_code_query;
431
		}
432
433
		$order_coupon_counts    = $this->get_order_report_data( $order_coupon_counts_query );
434
		$order_discount_amounts = $this->get_order_report_data( $order_discount_amounts_query );
435
436
		// Prepare data for report
437
		$order_coupon_counts    = $this->prepare_chart_data( $order_coupon_counts, 'post_date', 'order_coupon_count', $this->chart_interval, $this->start_date, $this->chart_groupby );
438
		$order_discount_amounts = $this->prepare_chart_data( $order_discount_amounts, 'post_date', 'discount_amount', $this->chart_interval, $this->start_date, $this->chart_groupby );
439
440
		// Encode in json format
441
		$chart_data = json_encode( array(
442
			'order_coupon_counts'    => array_values( $order_coupon_counts ),
443
			'order_discount_amounts' => array_values( $order_discount_amounts )
444
		) );
445
		?>
446
		<div class="chart-container">
447
			<div class="chart-placeholder main"></div>
448
		</div>
449
		<script type="text/javascript">
450
			var main_chart;
451
452
			jQuery(function(){
453
				var order_data = jQuery.parseJSON( '<?php echo $chart_data; ?>' );
454
455
				var drawGraph = function( highlight ) {
456
					var series = [
457
						{
458
							label: "<?php echo esc_js( __( 'Number of coupons used', 'woocommerce' ) ); ?>",
459
							data: order_data.order_coupon_counts,
460
							color: '<?php echo $this->chart_colours['coupon_count' ]; ?>',
461
							bars: { fillColor: '<?php echo $this->chart_colours['coupon_count' ]; ?>', fill: true, show: true, lineWidth: 0, barWidth: <?php echo $this->barwidth; ?> * 0.5, align: 'center' },
462
							shadowSize: 0,
463
							hoverable: false
464
						},
465
						{
466
							label: "<?php echo esc_js( __( 'Discount amount', 'woocommerce' ) ); ?>",
467
							data: order_data.order_discount_amounts,
468
							yaxis: 2,
469
							color: '<?php echo $this->chart_colours['discount_amount']; ?>',
470
							points: { show: true, radius: 5, lineWidth: 3, fillColor: '#fff', fill: true },
471
							lines: { show: true, lineWidth: 4, fill: false },
472
							shadowSize: 0,
473
							<?php echo $this->get_currency_tooltip(); ?>
474
						}
475
					];
476
477
					if ( highlight !== 'undefined' && series[ highlight ] ) {
478
						highlight_series = series[ highlight ];
479
480
						highlight_series.color = '#9c5d90';
481
482
						if ( highlight_series.bars )
483
							highlight_series.bars.fillColor = '#9c5d90';
484
485
						if ( highlight_series.lines ) {
486
							highlight_series.lines.lineWidth = 5;
487
						}
488
					}
489
490
					main_chart = jQuery.plot(
491
						jQuery('.chart-placeholder.main'),
492
						series,
493
						{
494
							legend: {
495
								show: false
496
							},
497
							grid: {
498
								color: '#aaa',
499
								borderColor: 'transparent',
500
								borderWidth: 0,
501
								hoverable: true
502
							},
503
							xaxes: [ {
504
								color: '#aaa',
505
								position: "bottom",
506
								tickColor: 'transparent',
507
								mode: "time",
508
								timeformat: "<?php if ( $this->chart_groupby == 'day' ) echo '%d %b'; else echo '%b'; ?>",
509
								monthNames: <?php echo json_encode( array_values( $wp_locale->month_abbrev ) ); ?>,
510
								tickLength: 1,
511
								minTickSize: [1, "<?php echo $this->chart_groupby; ?>"],
512
								font: {
513
									color: "#aaa"
514
								}
515
							} ],
516
							yaxes: [
517
								{
518
									min: 0,
519
									minTickSize: 1,
520
									tickDecimals: 0,
521
									color: '#ecf0f1',
522
									font: { color: "#aaa" }
523
								},
524
								{
525
									position: "right",
526
									min: 0,
527
									tickDecimals: 2,
528
									alignTicksWithAxis: 1,
529
									color: 'transparent',
530
									font: { color: "#aaa" }
531
								}
532
							],
533
						}
534
					);
535
536
					jQuery('.chart-placeholder').resize();
537
				}
538
539
				drawGraph();
540
541
				jQuery('.highlight_series').hover(
542
					function() {
543
						drawGraph( jQuery(this).data('series') );
544
					},
545
					function() {
546
						drawGraph();
547
					}
548
				);
549
			});
550
		</script>
551
		<?php
552
	}
553
554
}
555