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