PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / app / Services / Report / ReportHelper.php

ReportHelper.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at app/Services/Report/ReportHelper.php

256 lines 8.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\Report;
4
5 use FluentCart\App\App;
6 use FluentCart\Api\StoreSettings;
7 use FluentCart\App\Helpers\Status;
8 use FluentCart\Framework\Support\Arr;
9 use FluentCart\Framework\Support\Sanitizer;
10 use FluentCart\App\Services\DateTime\DateTime;
11
12 class ReportHelper
13 {
14 /**
15 * Define the group key based on the data density between the start and end dates.
16 *
17 * @param \DateTime $startDate The start date as a DateTime object.
18 * @param \DateTime $endDate The end date as a DateTime object.
19 * @return string The group key, which can be 'daily', 'monthly', or 'yearly'.
20 */
21
22 public static function defineGroupKey($startDate, $endDate)
23 {
24 $diff = $endDate->diff($startDate);
25 $days = $diff->days;
26
27 if ($days <= 91) {
28 return 'daily';
29 } elseif ($days <= 365) {
30 return 'monthly';
31 } else {
32 return 'yearly';
33 }
34 }
35
36 public static function processGroup($startDate, $endDate, $groupKey = null)
37 {
38 if (!$groupKey || $groupKey === 'default') {
39 $groupKey = static::defineGroupKey($startDate, $endDate);
40 }
41
42 switch ($groupKey) {
43 case 'yearly':
44 $format = '%Y';
45 break;
46 case 'monthly':
47 $format = '%Y-%m';
48 break;
49 default:
50 $format = '%Y-%m-%d';
51 break;
52 }
53
54 $groupBy = "DATE_FORMAT(o.created_at, '{$format}')";
55 $selection = "{$groupBy} AS `group`, YEAR(o.created_at) AS year";
56
57 return [
58 'key' => $groupKey,
59 'by' => $groupBy,
60 'field' => $selection,
61 ];
62 }
63
64 public static function processFilters($params = [])
65 {
66 $storeMode = (new StoreSettings())->get('order_mode') ?: 'live';
67 $mode = $params['filterMode'] ?? $storeMode;
68
69 $filters = [
70 'payment_status' => $params['paymentStatus'] ?? null,
71 'status' => $params['orderStatus'] ?? null,
72 'currency' => $params['currency'] ?? null,
73 'mode' => $mode,
74 ];
75
76 return array_filter($filters);
77 }
78
79 public static function processRequest($params = []): array
80 {
81 $storeMode = (new StoreSettings())->get('order_mode') ?: 'live';
82 $mode = $params['filterMode'] ?? $storeMode;
83
84 $filters = [
85 'payment_status' => Arr::get($params, 'paymentStatus'),
86 'status' => Arr::get($params, 'orderStatus'),
87 'currency' => Arr::get($params, 'currency'),
88 'mode' => $mode,
89 'type' => array_filter(Arr::get($params, 'orderTypes', [])),
90 ];
91
92 $groupKey = Arr::get($params, 'groupKey', 'daily');
93
94 return [
95 'filters' => array_filter($filters),
96 'startDate' => Arr::get($params, 'startDate'),
97 'endDate' => Arr::get($params, 'endDate'),
98 'groupKey' => $groupKey,
99 ];
100 }
101
102 public static function processParams($params = [], $additional = []): array
103 {
104 $params = static::sanitizeParams($params);
105
106 if (!App::isProActive()) {
107 $startDate = (new DateTime())->subMonth()->startOfDay();
108 $endDate = (new DateTime())->endOfDay();
109 } else {
110 $startDate = (new DateTime(Arr::get($params, 'startDate')))->startOfDay();
111 $endDate = (new DateTime(Arr::get($params, 'endDate')))->endOfDay();
112 }
113
114 $compareType = Arr::get($params, 'compareType');
115 $compareDate = Arr::get($params, 'compareDate');
116 $comparePeriod = null;
117
118 if ($compareType && $compareDate) {
119 $comparePeriod = static::getCompareRange(
120 $compareType,
121 ['startDate' => $startDate, 'endDate' => $endDate],
122 $compareDate
123 );
124 }
125
126 $attributes = [
127 'startDate' => $startDate,
128 'endDate' => $endDate,
129 'groupKey' => Arr::get($params, 'groupKey'),
130 'currency' => Arr::get($params, 'currency'),
131 'paymentMode' => Arr::get($params, 'filterMode'),
132 'variationIds' => Arr::get($params, 'variation_ids', []),
133 'comparePeriod' => $comparePeriod
134 ];
135
136 foreach ($additional as $key) {
137 $value = Arr::get($params, $key);
138
139 if ($key === 'orderStatus') {
140 if (!$value || in_array('all', $value)) {
141 $value = [Status::ORDER_ON_HOLD, Status::ORDER_FAILED];
142 }
143 } elseif ($key === 'paymentStatus') {
144 $value = Status::getReportStatuses();
145 } elseif ($key === 'subscriptionType') {
146 $value = $value ?: Status::ORDER_TYPE_SUBSCRIPTION;
147 }
148
149 $attributes[$key] = $value;
150 }
151
152 return $attributes;
153 }
154
155 /**
156 * Whitelist a groupKey value used to build raw SQL (SELECT/GROUP BY clauses)
157 * so an unrecognized or missing value never reaches the query builder.
158 *
159 * @param mixed $value
160 * @return string
161 */
162 public static function sanitizeGroupKey($value)
163 {
164 $acceptedValues = ['billing_country', 'shipping_country', 'payment_method', 'payment_status', 'default', 'daily', 'monthly', 'yearly'];
165 return in_array($value, $acceptedValues) ? $value : 'payment_method';
166 }
167
168 protected static function sanitizeParams($params)
169 {
170 $rules = [
171 'startDate' => 'sanitize_text_field',
172 'endDate' => 'sanitize_text_field',
173 'compareType' => 'sanitize_text_field',
174 'compareDate' => 'sanitize_text_field',
175 'groupKey' => function ($value) {
176 return static::sanitizeGroupKey($value);
177 },
178 'currency' => 'sanitize_text_field',
179 'filterMode' => 'sanitize_text_field',
180 'storeMode' => 'sanitize_text_field',
181 'variation_ids.*' => 'intval',
182 'customDays' => 'intval',
183 'subscriptionType' => 'sanitize_text_field',
184 'orderStatus.*' => 'sanitize_text_field',
185 'orderTypes.*' => 'sanitize_text_field',
186 'filter_type' => 'sanitize_text_field',
187 ];
188
189 /**
190 * Report params whose shape this plugin does not own.
191 *
192 * `advanced_filters` deliberately has no rule above. Its payload describes
193 * filter conditions, and only whoever consumes it knows what shape is
194 * valid — so only they can sanitize it without mangling it (running
195 * sanitize_text_field() over a JSON blob eats everything after the first
196 * '<'). A consumer pushes its own rule in here, and Sanitizer::sanitize()
197 * leaves any key with no rule untouched.
198 *
199 * @param array $rules Sanitization rules, keyed like $params.
200 * @param array $params The raw, unsanitized params.
201 */
202 $rules = apply_filters('fluent_cart/report/sanitize_params_rules', $rules, $params);
203
204 return Sanitizer::sanitize($params, is_array($rules) ? $rules : []);
205 }
206
207 /**
208 * @param string $type
209 * @param array $compareRange
210 * @param array $currentRange
211 * @return array|\DateTime[]|false
212 * @throws \Exception
213 */
214 public static function getCompareRange($type, $currentRange, $compareDate = null)
215 {
216 $currentStartDate = $currentRange['startDate'];
217 $currentendDate = $currentRange['endDate'];
218
219 $diffDays = $currentendDate->diff($currentStartDate)->days;
220
221 if ($type == 'previous_period') {
222 return [
223 $currentStartDate->copy()->subDays($diffDays + 1),
224 $currentStartDate->copy()->subDays(1)->endOfDay()
225 ];
226 } else if ($type == 'previous_month') {
227 $fromDate = $currentStartDate->copy()->subMonths(1);
228
229 return [
230 $fromDate->copy(),
231 $fromDate->addDays($diffDays)->endOfDay()
232 ];
233 } else if ($type == 'previous_quarter') {
234 $fromDate = $currentStartDate->copy()->subMonths(3);
235 return [
236 $fromDate->copy()->startOfMonth(),
237 $fromDate->addDays($diffDays)->endOfDay()
238 ];
239 } else if ($type == 'previous_year') {
240 $fromDate = $currentStartDate->copy()->subYears(1);
241 return [
242 $fromDate->copy(),
243 $fromDate->addDays($diffDays)->endOfDay()
244 ];
245 } else if ($type == 'custom' && $compareDate) {
246 $compareDate = (new DateTime($compareDate))->startOfDay();
247 return [
248 $compareDate->copy(),
249 $compareDate->addDays($diffDays)->endOfDay(),
250 ];
251 } else {
252 return false;
253 }
254 }
255 }
256