1 <?php
2 3 4 5 6 7 8 9 10 11
12
13 if ( ! defined( 'ABSPATH' ) ) exit;
14
15
16 class WC_API_Reports extends WC_API_Resource {
17
18
19 protected $base = '/reports';
20
21
22 private $report;
23
24 25 26 27 28 29 30 31 32 33
34 public function register_routes( $routes ) {
35
36
37 $routes[ $this->base ] = array(
38 array( array( $this, 'get_reports' ), WC_API_Server::READABLE ),
39 );
40
41
42 $routes[ $this->base . '/sales'] = array(
43 array( array( $this, 'get_sales_report' ), WC_API_Server::READABLE ),
44 );
45
46
47 $routes[ $this->base . '/sales/top_sellers' ] = array(
48 array( array( $this, 'get_top_sellers_report' ), WC_API_Server::READABLE ),
49 );
50
51 return $routes;
52 }
53
54 55 56 57 58 59
60 public function get_reports() {
61
62 return array( 'reports' => array( 'sales', 'sales/top_sellers' ) );
63 }
64
65 66 67 68 69 70 71 72
73 public function get_sales_report( $fields = null, $filter = array() ) {
74
75
76 $check = $this->validate_request();
77
78 if ( is_wp_error( $check ) )
79 return $check;
80
81
82 $this->setup_report( $filter );
83
84
85 $totals = $this->report->get_order_report_data( array(
86 'data' => array(
87 '_order_total' => array(
88 'type' => 'meta',
89 'function' => 'SUM',
90 'name' => 'sales'
91 ),
92 '_order_tax' => array(
93 'type' => 'meta',
94 'function' => 'SUM',
95 'name' => 'tax'
96 ),
97 '_order_shipping_tax' => array(
98 'type' => 'meta',
99 'function' => 'SUM',
100 'name' => 'shipping_tax'
101 ),
102 '_order_shipping' => array(
103 'type' => 'meta',
104 'function' => 'SUM',
105 'name' => 'shipping'
106 ),
107 'ID' => array(
108 'type' => 'post_data',
109 'function' => 'COUNT',
110 'name' => 'order_count'
111 )
112 ),
113 'filter_range' => true,
114 ) );
115
116
117 $total_items = absint( $this->report->get_order_report_data( array(
118 'data' => array(
119 '_qty' => array(
120 'type' => 'order_item_meta',
121 'order_item_type' => 'line_item',
122 'function' => 'SUM',
123 'name' => 'order_item_qty'
124 )
125 ),
126 'query_type' => 'get_var',
127 'filter_range' => true,
128 ) ) );
129
130
131 $total_discount = $this->report->get_order_report_data( array(
132 'data' => array(
133 'discount_amount' => array(
134 'type' => 'order_item_meta',
135 'order_item_type' => 'coupon',
136 'function' => 'SUM',
137 'name' => 'discount_amount'
138 )
139 ),
140 'where' => array(
141 array(
142 'key' => 'order_item_type',
143 'value' => 'coupon',
144 'operator' => '='
145 )
146 ),
147 'query_type' => 'get_var',
148 'filter_range' => true,
149 ) );
150
151
152 $users_query = new WP_User_Query(
153 array(
154 'fields' => array( 'user_registered' ),
155 'role' => 'customer',
156 )
157 );
158
159 $customers = $users_query->get_results();
160
161 foreach ( $customers as $key => $customer ) {
162 if ( strtotime( $customer->user_registered ) < $this->report->start_date || strtotime( $customer->user_registered ) > $this->report->end_date )
163 unset( $customers[ $key ] );
164 }
165
166 $total_customers = count( $customers );
167
168
169 $orders = $this->report->get_order_report_data( array(
170 'data' => array(
171 '_order_total' => array(
172 'type' => 'meta',
173 'function' => 'SUM',
174 'name' => 'total_sales'
175 ),
176 '_order_shipping' => array(
177 'type' => 'meta',
178 'function' => 'SUM',
179 'name' => 'total_shipping'
180 ),
181 '_order_tax' => array(
182 'type' => 'meta',
183 'function' => 'SUM',
184 'name' => 'total_tax'
185 ),
186 '_order_shipping_tax' => array(
187 'type' => 'meta',
188 'function' => 'SUM',
189 'name' => 'total_shipping_tax'
190 ),
191 'ID' => array(
192 'type' => 'post_data',
193 'function' => 'COUNT',
194 'name' => 'total_orders',
195 'distinct' => true,
196 ),
197 'post_date' => array(
198 'type' => 'post_data',
199 'function' => '',
200 'name' => 'post_date'
201 ),
202 ),
203 'group_by' => $this->report->group_by_query,
204 'order_by' => 'post_date ASC',
205 'query_type' => 'get_results',
206 'filter_range' => true,
207 ) );
208
209
210 $order_items = $this->report->get_order_report_data( array(
211 'data' => array(
212 '_qty' => array(
213 'type' => 'order_item_meta',
214 'order_item_type' => 'line_item',
215 'function' => 'SUM',
216 'name' => 'order_item_count'
217 ),
218 'post_date' => array(
219 'type' => 'post_data',
220 'function' => '',
221 'name' => 'post_date'
222 ),
223 ),
224 'where' => array(
225 array(
226 'key' => 'order_item_type',
227 'value' => 'line_item',
228 'operator' => '='
229 )
230 ),
231 'group_by' => $this->report->group_by_query,
232 'order_by' => 'post_date ASC',
233 'query_type' => 'get_results',
234 'filter_range' => true,
235 ) );
236
237
238 $discounts = $this->report->get_order_report_data( array(
239 'data' => array(
240 'discount_amount' => array(
241 'type' => 'order_item_meta',
242 'order_item_type' => 'coupon',
243 'function' => 'SUM',
244 'name' => 'discount_amount'
245 ),
246 'post_date' => array(
247 'type' => 'post_data',
248 'function' => '',
249 'name' => 'post_date'
250 ),
251 ),
252 'where' => array(
253 array(
254 'key' => 'order_item_type',
255 'value' => 'coupon',
256 'operator' => '='
257 )
258 ),
259 'group_by' => $this->report->group_by_query . ', order_item_name',
260 'order_by' => 'post_date ASC',
261 'query_type' => 'get_results',
262 'filter_range' => true,
263 ) );
264
265 $period_totals = array();
266
267
268 for ( $i = 0; $i <= $this->report->chart_interval; $i ++ ) {
269
270 switch ( $this->report->chart_groupby ) {
271 case 'day' :
272 $time = date( 'Y-m-d', strtotime( "+{$i} DAY", $this->report->start_date ) );
273 break;
274 case 'month' :
275 $time = date( 'Y-m', strtotime( "+{$i} MONTH", $this->report->start_date ) );
276 break;
277 }
278
279
280 $customer_count = 0;
281 foreach ( $customers as $customer ) {
282
283 if ( date( ( 'day' == $this->report->chart_groupby ) ? 'Y-m-d' : 'Y-m', strtotime( $customer->user_registered ) ) == $time ) {
284 $customer_count++;
285 }
286 }
287
288 $period_totals[ $time ] = array(
289 'sales' => wc_format_decimal( 0.00, 2 ),
290 'orders' => 0,
291 'items' => 0,
292 'tax' => wc_format_decimal( 0.00, 2 ),
293 'shipping' => wc_format_decimal( 0.00, 2 ),
294 'discount' => wc_format_decimal( 0.00, 2 ),
295 'customers' => $customer_count,
296 );
297 }
298
299
300 foreach ( $orders as $order ) {
301
302 $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) );
303
304 if ( ! isset( $period_totals[ $time ] ) )
305 continue;
306
307 $period_totals[ $time ]['sales'] = wc_format_decimal( $order->total_sales, 2 );
308 $period_totals[ $time ]['orders'] = (int) $order->total_orders;
309 $period_totals[ $time ]['tax'] = wc_format_decimal( $order->total_tax + $order->total_shipping_tax, 2 );
310 $period_totals[ $time ]['shipping'] = wc_format_decimal( $order->total_shipping, 2 );
311 }
312
313
314 foreach ( $order_items as $order_item ) {
315
316 $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $order_item->post_date ) ) : date( 'Y-m', strtotime( $order_item->post_date ) );
317
318 if ( ! isset( $period_totals[ $time ] ) )
319 continue;
320
321 $period_totals[ $time ]['items'] = (int) $order_item->order_item_count;
322 }
323
324
325 foreach ( $discounts as $discount ) {
326
327 $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $discount->post_date ) ) : date( 'Y-m', strtotime( $discount->post_date ) );
328
329 if ( ! isset( $period_totals[ $time ] ) )
330 continue;
331
332 $period_totals[ $time ]['discount'] = wc_format_decimal( $discount->discount_amount, 2 );
333 }
334
335 $sales_data = array(
336 'total_sales' => wc_format_decimal( $totals->sales, 2 ),
337 'average_sales' => wc_format_decimal( $totals->sales / ( $this->report->chart_interval + 1 ), 2 ),
338 'total_orders' => (int) $totals->order_count,
339 'total_items' => $total_items,
340 'total_tax' => wc_format_decimal( $totals->tax + $totals->shipping_tax, 2 ),
341 'total_shipping' => wc_format_decimal( $totals->shipping, 2 ),
342 'total_discount' => is_null( $total_discount ) ? wc_format_decimal( 0.00, 2 ) : wc_format_decimal( $total_discount, 2 ),
343 'totals_grouped_by' => $this->report->chart_groupby,
344 'totals' => $period_totals,
345 'total_customers' => $total_customers,
346 );
347
348 return array( 'sales' => apply_filters( 'woocommerce_api_report_response', $sales_data, $this->report, $fields, $this->server ) );
349 }
350
351 352 353 354 355 356 357 358
359 public function get_top_sellers_report( $fields = null, $filter = array() ) {
360
361
362 $check = $this->validate_request();
363
364 if ( is_wp_error( $check ) ) {
365 return $check;
366 }
367
368
369 $this->setup_report( $filter );
370
371 $top_sellers = $this->report->get_order_report_data( array(
372 'data' => array(
373 '_product_id' => array(
374 'type' => 'order_item_meta',
375 'order_item_type' => 'line_item',
376 'function' => '',
377 'name' => 'product_id'
378 ),
379 '_qty' => array(
380 'type' => 'order_item_meta',
381 'order_item_type' => 'line_item',
382 'function' => 'SUM',
383 'name' => 'order_item_qty'
384 )
385 ),
386 'order_by' => 'order_item_qty DESC',
387 'group_by' => 'product_id',
388 'limit' => isset( $filter['limit'] ) ? absint( $filter['limit'] ) : 12,
389 'query_type' => 'get_results',
390 'filter_range' => true,
391 ) );
392
393 $top_sellers_data = array();
394
395 foreach ( $top_sellers as $top_seller ) {
396
397 $product = get_product( $top_seller->product_id );
398
399 $top_sellers_data[] = array(
400 'title' => $product->get_title(),
401 'product_id' => $top_seller->product_id,
402 'quantity' => $top_seller->order_item_qty,
403 );
404 }
405
406 return array( 'top_sellers' => apply_filters( 'woocommerce_api_report_response', $top_sellers_data, $this->report, $fields, $this->server ) );
407 }
408
409 410 411 412 413 414
415 private function setup_report( $filter ) {
416
417 include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' );
418
419 $this->report = new WC_Admin_Report();
420
421 if ( empty( $filter['period'] ) ) {
422
423
424 $filter['period'] = 'custom';
425
426 if ( ! empty( $filter['date_min'] ) || ! empty( $filter['date_max'] ) ) {
427
428
429 $_GET['start_date'] = $this->server->parse_datetime( $filter['date_min'] );
430 $_GET['end_date'] = isset( $filter['date_max'] ) ? $this->server->parse_datetime( $filter['date_max'] ) : null;
431
432 } else {
433
434
435 $_GET['start_date'] = $_GET['end_date'] = date( 'Y-m-d', current_time( 'timestamp' ) );
436 }
437
438 } else {
439
440
441 if ( ! in_array( $filter['period'], array( 'week', 'month', 'last_month', 'year' ) ) ) {
442 $filter['period'] = 'week';
443 }
444
445
446
447 if ( 'week' === $filter['period'] ) {
448 $filter['period'] = '7day';
449 }
450 }
451
452 $this->report->calculate_current_range( $filter['period'] );
453 }
454
455 456 457 458 459 460 461 462 463 464
465 protected function validate_request( $id = null, $type = null, $context = null ) {
466
467 if ( ! current_user_can( 'view_woocommerce_reports' ) ) {
468
469 return new WP_Error( 'woocommerce_api_user_cannot_read_report', __( 'You do not have permission to read this report', 'woocommerce' ), array( 'status' => 401 ) );
470
471 } else {
472
473 return true;
474 }
475 }
476 }
477