WC_REST_Report_Sales_V1_Controller

REST API Report Sales controller class.

Defined (1)

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

/includes/api/v1/class-wc-rest-report-sales-controller.php  
  1. class WC_REST_Report_Sales_V1_Controller extends WC_REST_Controller { 
  2.  
  3. /** 
  4. * Endpoint namespace. 
  5. * @var string 
  6. */ 
  7. protected $namespace = 'wc/v1'; 
  8.  
  9. /** 
  10. * Route base. 
  11. * @var string 
  12. */ 
  13. protected $rest_base = 'reports/sales'; 
  14.  
  15. /** 
  16. * Report instance. 
  17. * @var WC_Admin_Report 
  18. */ 
  19. protected $report; 
  20.  
  21. /** 
  22. * Register the routes for sales reports. 
  23. */ 
  24. public function register_routes() { 
  25. register_rest_route( $this->namespace, '/' . $this->rest_base, array( 
  26. array( 
  27. 'methods' => WP_REST_Server::READABLE,  
  28. 'callback' => array( $this, 'get_items' ),  
  29. 'permission_callback' => array( $this, 'get_items_permissions_check' ),  
  30. 'args' => $this->get_collection_params(),  
  31. ),  
  32. 'schema' => array( $this, 'get_public_item_schema' ),  
  33. ) ); 
  34.  
  35. /** 
  36. * Check whether a given request has permission to read report. 
  37. * @param WP_REST_Request $request Full details about the request. 
  38. * @return WP_Error|boolean 
  39. */ 
  40. public function get_items_permissions_check( $request ) { 
  41. if ( ! wc_rest_check_manager_permissions( 'reports', 'read' ) ) { 
  42. return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'woocommerce' ), array( 'status' => rest_authorization_required_code() ) ); 
  43.  
  44. return true; 
  45.  
  46. /** 
  47. * Get sales reports. 
  48. * @param WP_REST_Request $request 
  49. * @return array|WP_Error 
  50. */ 
  51. public function get_items( $request ) { 
  52. $data = array(); 
  53. $item = $this->prepare_item_for_response( null, $request ); 
  54. $data[] = $this->prepare_response_for_collection( $item ); 
  55.  
  56. return rest_ensure_response( $data ); 
  57.  
  58. /** 
  59. * Prepare a report sales object for serialization. 
  60. * @param null $_ 
  61. * @param WP_REST_Request $request Request object. 
  62. * @return WP_REST_Response $response Response data. 
  63. */ 
  64. public function prepare_item_for_response( $_, $request ) { 
  65. // Set date filtering. 
  66. $filter = array( 
  67. 'period' => $request['period'],  
  68. 'date_min' => $request['date_min'],  
  69. 'date_max' => $request['date_max'],  
  70. ); 
  71. $this->setup_report( $filter ); 
  72.  
  73. // New customers. 
  74. $users_query = new WP_User_Query( 
  75. array( 
  76. 'fields' => array( 'user_registered' ),  
  77. 'role' => 'customer',  
  78. ); 
  79.  
  80. $customers = $users_query->get_results(); 
  81.  
  82. foreach ( $customers as $key => $customer ) { 
  83. if ( strtotime( $customer->user_registered ) < $this->report->start_date || strtotime( $customer->user_registered ) > $this->report->end_date ) { 
  84. unset( $customers[ $key ] ); 
  85.  
  86. $total_customers = count( $customers ); 
  87. $report_data = $this->report->get_report_data(); 
  88. $period_totals = array(); 
  89.  
  90. // Setup period totals by ensuring each period in the interval has data. 
  91. for ( $i = 0; $i <= $this->report->chart_interval; $i++ ) { 
  92.  
  93. switch ( $this->report->chart_groupby ) { 
  94. case 'day' : 
  95. $time = date( 'Y-m-d', strtotime( "+{$i} DAY", $this->report->start_date ) ); 
  96. break; 
  97. default : 
  98. $time = date( 'Y-m', strtotime( "+{$i} MONTH", $this->report->start_date ) ); 
  99. break; 
  100.  
  101. // Set the customer signups for each period. 
  102. $customer_count = 0; 
  103. foreach ( $customers as $customer ) { 
  104. if ( date( ( 'day' == $this->report->chart_groupby ) ? 'Y-m-d' : 'Y-m', strtotime( $customer->user_registered ) ) == $time ) { 
  105. $customer_count++; 
  106.  
  107. $period_totals[ $time ] = array( 
  108. 'sales' => wc_format_decimal( 0.00, 2 ),  
  109. 'orders' => 0,  
  110. 'items' => 0,  
  111. 'tax' => wc_format_decimal( 0.00, 2 ),  
  112. 'shipping' => wc_format_decimal( 0.00, 2 ),  
  113. 'discount' => wc_format_decimal( 0.00, 2 ),  
  114. 'customers' => $customer_count,  
  115. ); 
  116.  
  117. // add total sales, total order count, total tax and total shipping for each period 
  118. foreach ( $report_data->orders 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 ]['sales'] = wc_format_decimal( $order->total_sales, 2 ); 
  125. $period_totals[ $time ]['tax'] = wc_format_decimal( $order->total_tax + $order->total_shipping_tax, 2 ); 
  126. $period_totals[ $time ]['shipping'] = wc_format_decimal( $order->total_shipping, 2 ); 
  127.  
  128. foreach ( $report_data->order_counts as $order ) { 
  129. $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $order->post_date ) ) : date( 'Y-m', strtotime( $order->post_date ) ); 
  130.  
  131. if ( ! isset( $period_totals[ $time ] ) ) { 
  132. continue; 
  133.  
  134. $period_totals[ $time ]['orders'] = (int) $order->count; 
  135.  
  136. // Add total order items for each period. 
  137. foreach ( $report_data->order_items as $order_item ) { 
  138. $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $order_item->post_date ) ) : date( 'Y-m', strtotime( $order_item->post_date ) ); 
  139.  
  140. if ( ! isset( $period_totals[ $time ] ) ) { 
  141. continue; 
  142.  
  143. $period_totals[ $time ]['items'] = (int) $order_item->order_item_count; 
  144.  
  145. // Add total discount for each period. 
  146. foreach ( $report_data->coupons as $discount ) { 
  147. $time = ( 'day' === $this->report->chart_groupby ) ? date( 'Y-m-d', strtotime( $discount->post_date ) ) : date( 'Y-m', strtotime( $discount->post_date ) ); 
  148.  
  149. if ( ! isset( $period_totals[ $time ] ) ) { 
  150. continue; 
  151.  
  152. $period_totals[ $time ]['discount'] = wc_format_decimal( $discount->discount_amount, 2 ); 
  153.  
  154. $sales_data = array( 
  155. 'total_sales' => $report_data->total_sales,  
  156. 'net_sales' => $report_data->net_sales,  
  157. 'average_sales' => $report_data->average_sales,  
  158. 'total_orders' => $report_data->total_orders,  
  159. 'total_items' => $report_data->total_items,  
  160. 'total_tax' => wc_format_decimal( $report_data->total_tax + $report_data->total_shipping_tax, 2 ),  
  161. 'total_shipping' => $report_data->total_shipping,  
  162. 'total_refunds' => $report_data->total_refunds,  
  163. 'total_discount' => $report_data->total_coupons,  
  164. 'totals_grouped_by' => $this->report->chart_groupby,  
  165. 'totals' => $period_totals,  
  166. 'total_customers' => $total_customers,  
  167. ); 
  168.  
  169. $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 
  170. $data = $this->add_additional_fields_to_object( $sales_data, $request ); 
  171. $data = $this->filter_response_by_context( $data, $context ); 
  172.  
  173. // Wrap the data in a response object. 
  174. $response = rest_ensure_response( $data ); 
  175. $response->add_links( array( 
  176. 'about' => array( 
  177. 'href' => rest_url( sprintf( '%s/reports', $this->namespace ) ),  
  178. ),  
  179. ) ); 
  180.  
  181. /** 
  182. * Filter a report sales returned from the API. 
  183. * Allows modification of the report sales data right before it is returned. 
  184. * @param WP_REST_Response $response The response object. 
  185. * @param stdClass $data The original report object. 
  186. * @param WP_REST_Request $request Request used to generate the response. 
  187. */ 
  188. return apply_filters( 'woocommerce_rest_prepare_report_sales', $response, (object) $sales_data, $request ); 
  189.  
  190. /** 
  191. * Setup the report object and parse any date filtering. 
  192. * @param array $filter date filtering 
  193. */ 
  194. protected function setup_report( $filter ) { 
  195. include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php' ); 
  196. include_once( WC()->plugin_path() . '/includes/admin/reports/class-wc-report-sales-by-date.php' ); 
  197.  
  198. $this->report = new WC_Report_Sales_By_Date(); 
  199.  
  200. if ( empty( $filter['period'] ) ) { 
  201. // Custom date range. 
  202. $filter['period'] = 'custom'; 
  203.  
  204. if ( ! empty( $filter['date_min'] ) || ! empty( $filter['date_max'] ) ) { 
  205.  
  206. // Overwrite _GET to make use of WC_Admin_Report::calculate_current_range() for custom date ranges. 
  207. $_GET['start_date'] = $filter['date_min']; 
  208. $_GET['end_date'] = isset( $filter['date_max'] ) ? $filter['date_max'] : null; 
  209.  
  210. } else { 
  211.  
  212. // Default custom range to today. 
  213. $_GET['start_date'] = $_GET['end_date'] = date( 'Y-m-d', current_time( 'timestamp' ) ); 
  214. } else { 
  215. $filter['period'] = empty( $filter['period'] ) ? 'week' : $filter['period']; 
  216.  
  217. // Change "week" period to "7day". 
  218. if ( 'week' === $filter['period'] ) { 
  219. $filter['period'] = '7day'; 
  220.  
  221. $this->report->calculate_current_range( $filter['period'] ); 
  222.  
  223. /** 
  224. * Get the Report's schema, conforming to JSON Schema. 
  225. * @return array 
  226. */ 
  227. public function get_item_schema() { 
  228. $schema = array( 
  229. '$schema' => 'http://json-schema.org/draft-04/schema#',  
  230. 'title' => 'sales_report',  
  231. 'type' => 'object',  
  232. 'properties' => array( 
  233. 'total_sales' => array( 
  234. 'description' => __( 'Gross sales in the period.', 'woocommerce' ),  
  235. 'type' => 'string',  
  236. 'context' => array( 'view' ),  
  237. 'readonly' => true,  
  238. ),  
  239. 'net_sales' => array( 
  240. 'description' => __( 'Net sales in the period.', 'woocommerce' ),  
  241. 'type' => 'string',  
  242. 'context' => array( 'view' ),  
  243. 'readonly' => true,  
  244. ),  
  245. 'average_sales' => array( 
  246. 'description' => __( 'Average net daily sales.', 'woocommerce' ),  
  247. 'type' => 'string',  
  248. 'context' => array( 'view' ),  
  249. 'readonly' => true,  
  250. ),  
  251. 'total_orders' => array( 
  252. 'description' => __( 'Total of orders placed.', 'woocommerce' ),  
  253. 'type' => 'integer',  
  254. 'context' => array( 'view' ),  
  255. 'readonly' => true,  
  256. ),  
  257. 'total_items' => array( 
  258. 'description' => __( 'Total of items purchased.', 'woocommerce' ),  
  259. 'type' => 'integer',  
  260. 'context' => array( 'view' ),  
  261. 'readonly' => true,  
  262. ),  
  263. 'total_tax' => array( 
  264. 'description' => __( 'Total charged for taxes.', 'woocommerce' ),  
  265. 'type' => 'string',  
  266. 'context' => array( 'view' ),  
  267. 'readonly' => true,  
  268. ),  
  269. 'total_shipping' => array( 
  270. 'description' => __( 'Total charged for shipping.', 'woocommerce' ),  
  271. 'type' => 'string',  
  272. 'context' => array( 'view' ),  
  273. 'readonly' => true,  
  274. ),  
  275. 'total_refunds' => array( 
  276. 'description' => __( 'Total of refunded orders.', 'woocommerce' ),  
  277. 'type' => 'integer',  
  278. 'context' => array( 'view' ),  
  279. 'readonly' => true,  
  280. ),  
  281. 'total_discount' => array( 
  282. 'description' => __( 'Total of coupons used.', 'woocommerce' ),  
  283. 'type' => 'integer',  
  284. 'context' => array( 'view' ),  
  285. 'readonly' => true,  
  286. ),  
  287. 'totals_grouped_by' => array( 
  288. 'description' => __( 'Group type.', 'woocommerce' ),  
  289. 'type' => 'string',  
  290. 'context' => array( 'view' ),  
  291. 'readonly' => true,  
  292. ),  
  293. 'totals' => array( 
  294. 'description' => __( 'Totals.', 'woocommerce' ),  
  295. 'type' => 'array',  
  296. 'items' => array( 
  297. 'type' => 'array',  
  298. ),  
  299. 'context' => array( 'view' ),  
  300. 'readonly' => true,  
  301. ),  
  302. ),  
  303. ); 
  304.  
  305. return $this->add_additional_fields_schema( $schema ); 
  306.  
  307. /** 
  308. * Get the query params for collections. 
  309. * @return array 
  310. */ 
  311. public function get_collection_params() { 
  312. return array( 
  313. 'context' => $this->get_context_param( array( 'default' => 'view' ) ),  
  314. 'period' => array( 
  315. 'description' => __( 'Report period.', 'woocommerce' ),  
  316. 'type' => 'string',  
  317. 'enum' => array( 'week', 'month', 'last_month', 'year' ),  
  318. 'validate_callback' => 'rest_validate_request_arg',  
  319. 'sanitize_callback' => 'sanitize_text_field',  
  320. ),  
  321. 'date_min' => array( 
  322. /** translators: %s: date format */ 
  323. 'description' => sprintf( __( 'Return sales for a specific start date, the date need to be in the %s format.', 'woocommerce' ), 'YYYY-MM-AA' ),  
  324. 'type' => 'string',  
  325. 'format' => 'date',  
  326. 'validate_callback' => 'wc_rest_validate_reports_request_arg',  
  327. 'sanitize_callback' => 'sanitize_text_field',  
  328. ),  
  329. 'date_max' => array( 
  330. /** translators: %s: date format */ 
  331. 'description' => sprintf( __( 'Return sales for a specific end date, the date need to be in the %s format.', 'woocommerce' ), 'YYYY-MM-AA' ),  
  332. 'type' => 'string',  
  333. 'format' => 'date',  
  334. 'validate_callback' => 'wc_rest_validate_reports_request_arg',  
  335. 'sanitize_callback' => 'sanitize_text_field',  
  336. ),  
  337. );