WC_API_Reports

The WooCommerce WC API Reports class.

Defined (3)

The class is defined in the following location(s).

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