PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.4.0
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.4.0
1.4.15 1.4.14 1.4.13 1.4.12 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.54 1.3.53 1.3.52 1.3.51 1.3.50 1.3.49 1.3.48 1.3.47 1.3.46 All 178 releases
disco / app / Analytics / Services / OrderService.php

OrderService.php in Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO 1.4.0, at app/Analytics/Services/OrderService.php

205 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php //phpcs:ignore
2
3 /**
4 * OrderService — composes order queries into service-level results.
5 *
6 * @package Disco
7 * @subpackage Disco\App\Analytics\Services
8 * @since 1.3.37
9 */
10
11 namespace Disco\App\Analytics\Services;
12
13 use Disco\App\Analytics\Queries\OrderQuery;
14
15 /**
16 * Provides order analytics at the service layer.
17 *
18 * Used by the REST controller for the orders and single-order endpoints.
19 * No SQL lives here — all DB work is delegated to OrderQuery.
20 */
21 class OrderService extends BaseService {
22
23 /**
24 * Returns a paginated, lightweight order list for the admin table.
25 *
26 * Only completed orders with at least one disco_campaign meta are included.
27 * Fixed sort: revenue (order_total) ASC.
28 *
29 * @param array $args date_from, date_to, campaign_id, customer_id, page, limit.
30 * @return array { current_period: array, pagination: array, data: array }
31 */
32 public static function get_orders_table( array $args ): array {
33 $limit = min( absint( $args['limit'] ?? 10 ), 100 );
34 $page = max( 1, absint( $args['page'] ?? 1 ) );
35
36 $date_to = $args['date_to'] ?? '';
37 $date_from = $args['date_from'] ?? '';
38
39 $query = new OrderQuery;
40 $result = $query->get_order_list( self::build_table_query_args( $args, $limit, $page ) );
41
42 $data = array();
43
44 foreach ( $result['rows'] as $row ) {
45 $data[] = self::format_order_row( $row, $query );
46 }
47
48 return array(
49 'current_period' => array(
50 'from' => $date_from,
51 'to' => $date_to,
52 ),
53 'compare_period' => self::resolve_compare_period( $date_from, $date_to ),
54 'pagination' => self::build_pagination( $result, $page, $limit ),
55 'data' => $data,
56 );
57 }
58
59 /**
60 * Returns a single order with full line items.
61 *
62 * @param int $order_id WooCommerce order ID.
63 * @return array|\WP_Error
64 */
65 public static function get_order( int $order_id ) {
66 $query = new OrderQuery;
67 $row = $query->get_order( $order_id );
68 /** @var object{order_id: int, order_date: string, order_status: string, customer_id: int, customer_name: string, customer_email: string, order_total: string, discount_amount: string} $row */
69
70 if ( ! $row ) {
71 return new \WP_Error(
72 'disco_not_found',
73 __( 'Order not found.', 'disco' ),
74 array( 'status' => 404 )
75 );
76 }
77
78 return array(
79 'id' => (int) $row->order_id,
80 'order_date' => $row->order_date,
81 'order_status' => $row->order_status,
82 'customer_id' => (int) $row->customer_id,
83 'customer_name' => $row->customer_name ?? '',
84 'customer_email' => $row->customer_email ?? '',
85 'campaigns' => $query->get_campaigns_for_order( $order_id ),
86 'order_total' => round( (float) $row->order_total, 2 ),
87 'discount_amount' => round( (float) $row->discount_amount, 2 ),
88 'products' => self::format_line_items( $query->get_line_items( $order_id ) ),
89 );
90 }
91
92 /**
93 * Maps service-level $args onto the argument array OrderQuery expects.
94 *
95 * Whitelists orderby, normalizes sort direction, casts filter IDs.
96 *
97 * @param array $args Raw service args.
98 * @param int $limit Sanitized per-page limit.
99 * @param int $page Sanitized page number.
100 * @return array Query args for OrderQuery::get_order_list().
101 */
102 private static function build_table_query_args( array $args, int $limit, int $page ): array {
103 $orderby_map = array(
104 'revenue' => 'order_total',
105 'date' => 'order_date',
106 );
107 $orderby = $orderby_map[ $args['orderby'] ?? 'revenue' ] ?? 'order_total';
108 $order = 'desc';
109
110 if ( strtolower( $args['order'] ?? 'desc' ) === 'asc' ) {
111 $order = 'asc';
112 }
113
114 return array(
115 'date_from' => $args['date_from'] ?? '',
116 'date_to' => $args['date_to'] ?? '',
117 'search' => $args['search'] ?? '',
118 'campaign_id' => ! empty( $args['campaign_id'] ) ? (int) $args['campaign_id'] : 0,
119 'customer_id' => ! empty( $args['customer_id'] ) ? (int) $args['customer_id'] : 0,
120 'orderby' => $orderby,
121 'order' => $order,
122 'per_page' => $limit,
123 'page' => $page,
124 'status' => 'wc-completed',
125 );
126 }
127
128 /**
129 * Formats one raw order row into the API response shape.
130 *
131 * Resolves campaigns as { id, name, intent } ('Unknown' for deleted) and
132 * line items as { id, name, quantity }.
133 *
134 * @param object $row Raw row from OrderQuery::get_order_list().
135 * @param \Disco\App\Analytics\Queries\OrderQuery $query Query instance for campaign/line-item lookups.
136 * @return array Formatted order row.
137 * @phpstan-param object{order_id: int|string, order_date: string|null, customer_id: int|string, customer_name: string|null, customer_email: string|null, order_total: string|null} $row
138 */
139 private static function format_order_row( object $row, OrderQuery $query ): array {
140 $order_id = (int) $row->order_id;
141
142 $campaigns = array_map(
143 function ( $campaign ) {
144 return array(
145 'id' => $campaign['campaign_id'],
146 'name' => $campaign['campaign_name'],
147 'intent' => $campaign['campaign_intent'],
148 );
149 },
150 $query->get_campaigns_for_order( $order_id )
151 );
152
153 $products = array_map(
154 function ( $item ) {
155 return array(
156 'id' => (int) $item->product_id,
157 'name' => $item->product_name ?? '',
158 'quantity' => (int) $item->qty,
159 );
160 },
161 $query->get_line_items( $order_id )
162 );
163
164 return array(
165 'id' => $order_id,
166 'date' => $row->order_date,
167 'campaigns' => $campaigns,
168 'customer_id' => (int) $row->customer_id,
169 'customer_name' => $row->customer_name ?? '',
170 'customer_email' => $row->customer_email ?? '',
171 'total_spent' => round( (float) $row->order_total, 2 ),
172 'quantity' => array_sum( array_column( $products, 'quantity' ) ),
173 'products' => $products,
174 );
175 }
176
177 /**
178 * Formats raw line items for the single-order response, including per-line discount.
179 *
180 * @param array $items Raw line items from OrderQuery::get_line_items().
181 * @return array Formatted line items.
182 */
183 private static function format_line_items( array $items ): array {
184 $products_data = array();
185
186 foreach ( $items as $item ) {
187 $sub = (float) $item->line_subtotal;
188 $tot = (float) $item->line_total;
189 $products_data[] = array(
190 'item_id' => (int) $item->item_id,
191 'id' => (int) $item->product_id,
192 'name' => $item->product_name ?? '',
193 'qty' => (int) $item->qty,
194 'unit_price' => (float) $item->unit_price,
195 'line_total' => round( $tot, 2 ),
196 'line_subtotal' => round( $sub, 2 ),
197 'discount' => round( $sub - $tot, 2 ),
198 );
199 }
200
201 return $products_data;
202 }
203
204 }
205