PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.4.14
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.4.14
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 1.3.45 All 177 releases
disco / app / Analytics / Services / OrderService.php

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

206 lines 6.6 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 'quantity' => 'quantity',
107 );
108 $orderby = $orderby_map[ $args['orderby'] ?? 'revenue' ] ?? 'order_total';
109 $order = 'desc';
110
111 if ( strtolower( $args['order'] ?? 'desc' ) === 'asc' ) {
112 $order = 'asc';
113 }
114
115 return array(
116 'date_from' => $args['date_from'] ?? '',
117 'date_to' => $args['date_to'] ?? '',
118 'search' => $args['search'] ?? '',
119 'campaign_id' => ! empty( $args['campaign_id'] ) ? (int) $args['campaign_id'] : 0,
120 'customer_id' => ! empty( $args['customer_id'] ) ? (int) $args['customer_id'] : 0,
121 'orderby' => $orderby,
122 'order' => $order,
123 'per_page' => $limit,
124 'page' => $page,
125 'status' => 'wc-completed',
126 );
127 }
128
129 /**
130 * Formats one raw order row into the API response shape.
131 *
132 * Resolves campaigns as { id, name, intent } ('Unknown' for deleted) and
133 * line items as { id, name, quantity }.
134 *
135 * @param object $row Raw row from OrderQuery::get_order_list().
136 * @param \Disco\App\Analytics\Queries\OrderQuery $query Query instance for campaign/line-item lookups.
137 * @return array Formatted order row.
138 * @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
139 */
140 private static function format_order_row( object $row, OrderQuery $query ): array {
141 $order_id = (int) $row->order_id;
142
143 $campaigns = array_map(
144 function ( $campaign ) {
145 return array(
146 'id' => $campaign['campaign_id'],
147 'name' => $campaign['campaign_name'],
148 'intent' => $campaign['campaign_intent'],
149 );
150 },
151 $query->get_campaigns_for_order( $order_id )
152 );
153
154 $products = array_map(
155 function ( $item ) {
156 return array(
157 'id' => (int) $item->product_id,
158 'name' => $item->product_name ?? '',
159 'quantity' => (int) $item->qty,
160 );
161 },
162 $query->get_line_items( $order_id )
163 );
164
165 return array(
166 'id' => $order_id,
167 'date' => $row->order_date,
168 'campaigns' => $campaigns,
169 'customer_id' => (int) $row->customer_id,
170 'customer_name' => $row->customer_name ?? '',
171 'customer_email' => $row->customer_email ?? '',
172 'total_spent' => round( (float) $row->order_total, 2 ),
173 'quantity' => array_sum( array_column( $products, 'quantity' ) ),
174 'products' => $products,
175 );
176 }
177
178 /**
179 * Formats raw line items for the single-order response, including per-line discount.
180 *
181 * @param array $items Raw line items from OrderQuery::get_line_items().
182 * @return array Formatted line items.
183 */
184 private static function format_line_items( array $items ): array {
185 $products_data = array();
186
187 foreach ( $items as $item ) {
188 $sub = (float) $item->line_subtotal;
189 $tot = (float) $item->line_total;
190 $products_data[] = array(
191 'item_id' => (int) $item->item_id,
192 'id' => (int) $item->product_id,
193 'name' => $item->product_name ?? '',
194 'qty' => (int) $item->qty,
195 'unit_price' => (float) $item->unit_price,
196 'line_total' => round( $tot, 2 ),
197 'line_subtotal' => round( $sub, 2 ),
198 'discount' => round( $sub - $tot, 2 ),
199 );
200 }
201
202 return $products_data;
203 }
204
205 }
206