PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.1
1.6.6 1.6.5 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 All 49 releases
fluent-cart / app / Services / Filter / TaxFilter.php

TaxFilter.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.1, at app/Services/Filter/TaxFilter.php

256 lines 8.7 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\Filter;
4
5 use FluentCart\App\App;
6 use FluentCart\Framework\Support\Str;
7 use FluentCart\App\Models\OrderTaxRate;
8 use FluentCart\App\Services\Localization\LocalizationManager;
9
10 class TaxFilter extends BaseFilter
11 {
12 public function applySimpleFilter(?string $search = null): void
13 {
14 $isApplied = $this->applySimpleOperatorFilter($search);
15
16 if ($isApplied) {
17 return;
18 }
19
20 $this->query->when($search ?? $this->search, function ($query, $search) {
21 return $query
22 ->where(function ($query) use ($search) {
23 $search = trim($search);
24 $search = Str::of($search)->remove('#')->toString();
25
26 $query->when(
27 is_numeric($search),
28 fn ($query) => $query->where('id', $search)->orWhere('order_id', $search)
29 )->orWhereHas(
30 'tax_rate',
31 fn ($query) => $query->where('country', $search)
32 ->orWhere('state', $search)
33 ->orWhere('postcode', $search)
34 ->orWhere('name', 'LIKE', "%{$search}%")
35 );
36 });
37 });
38 }
39
40 public function tabsMap(): array
41 {
42 return [
43 'filed' => 'filed_at',
44 'not_filed' => 'filed_at',
45 ];
46 }
47
48 public function getModel(): string
49 {
50 return OrderTaxRate::class;
51 }
52
53 public static function getFilterName(): string
54 {
55 return 'taxes';
56 }
57
58 /**
59 * `GET /taxes` mounts under `AdminPolicy` with no per-route permission, so
60 * a caller here is already a super admin and no entry on this map needs a
61 * further bar of its own.
62 *
63 * SCREEN key — `admin_tax_report` loads exactly what the report prints, and
64 * that is why it keeps the narrow `order` select: the report shows a
65 * currency, and a whole order row per line is both wasteful and more than
66 * the screen asked for.
67 *
68 * PUBLIC keys — `tax_rate` and `order` are the two relation names a
69 * consumer can reasonably ask a tax-report endpoint for. They give the
70 * plain, unnarrowed relation; the screen key's select is a property of that
71 * screen, not of the endpoint's published shape.
72 *
73 * @return array<string, callable>
74 */
75 protected function allowedWiths(): array
76 {
77 return [
78 'admin_tax_report' => [$this, 'adminTaxReport'],
79
80 'tax_rate' => [$this, 'publicTaxRate'],
81 'order' => [$this, 'publicOrder'],
82 ];
83 }
84
85 /**
86 * `GET /taxes`, sent by TaxesTable.js — the rate the row was charged at and
87 * the order's currency.
88 *
89 * No select on `tax_rate`: the report prints the rate's country, state,
90 * postcode and name, and the advanced filter matches on the same row. The
91 * `order` select lives INSIDE the relation closure — applied to `$query` it
92 * would narrow the tax-rate query itself, which is a different table.
93 *
94 * @param \FluentCart\Framework\Database\Orm\Builder $query
95 * @return \FluentCart\Framework\Database\Orm\Builder
96 */
97 protected function adminTaxReport($query)
98 {
99 return $query->with([
100 'tax_rate',
101 'order' => function ($orderQuery) {
102 $orderQuery->select(['id', 'currency']);
103 },
104 ]);
105 }
106
107 /**
108 * `with[]=tax_rate` — a public entry point. Covered by the route's own
109 * AdminPolicy, which admits nobody below a super admin.
110 *
111 * @param \FluentCart\Framework\Database\Orm\Builder $query
112 * @return \FluentCart\Framework\Database\Orm\Builder
113 */
114 protected function publicTaxRate($query)
115 {
116 return $query->with(['tax_rate']);
117 }
118
119 /**
120 * `with[]=order` — a public entry point, covered by the same AdminPolicy.
121 *
122 * @param \FluentCart\Framework\Database\Orm\Builder $query
123 * @return \FluentCart\Framework\Database\Orm\Builder
124 */
125 protected function publicOrder($query)
126 {
127 return $query->with(['order']);
128 }
129
130 /**
131 * Sent by TaxesTable.js so the tax report only counts rows whose order was
132 * actually paid.
133 *
134 * @return array<string, callable>
135 */
136 protected function allowedScopes(): array
137 {
138 return [
139 'validOrder' => [$this, 'validOrderScope'],
140 ];
141 }
142
143 /**
144 * Declared `($query)` on purpose: the array form of a `scopes` entry would
145 * otherwise hand this callback raw client arguments, and OrderTaxRate's
146 * `scopeValidOrder()` takes none.
147 *
148 * @param \FluentCart\Framework\Database\Orm\Builder $query
149 * @return \FluentCart\Framework\Database\Orm\Builder
150 */
151 protected function validOrderScope($query)
152 {
153 return $query->scopes(['validOrder']);
154 }
155
156 public function applyActiveViewFilter(?string $activeView = null): void
157 {
158 $activeView = $activeView ?? $this->activeView;
159 if (!$activeView) {
160 return;
161 }
162
163 $whereMethod = $activeView === 'filed' ? 'whereNotNull' : 'whereNull';
164
165 $this->query->{$whereMethod}('filed_at');
166 }
167
168 public static function advanceFilterOptions(): array
169 {
170 return [
171 'tax_rates' => [
172 'label' => __('Tax Property', 'fluent-cart'),
173 'value' => 'tax_rates',
174 'children' => [
175 [
176 'label' => __('Country', 'fluent-cart'),
177 'value' => 'country',
178 'column' => 'country',
179 'filter_type' => 'relation',
180 'relation' => 'tax_rate',
181 'remote_data_key' => 'countries',
182 'type' => 'selections',
183 'is_multiple' => true,
184 'options' => TaxFilter::getCountriesOptions(),
185 ],
186 [
187 'label' => __('Region', 'fluent-cart'),
188 'value' => 'region',
189 'column' => 'state',
190 'filter_type' => 'relation',
191 'relation' => 'tax_rate',
192 'remote_data_key' => 'tax_rate_states',
193 'type' => 'selections',
194 'options' => static::getStatesOptions(),
195 'is_multiple' => true,
196 'limit' => 10,
197 ],
198 [
199 'label' => __('Tax Name', 'fluent-cart'),
200 'value' => 'name',
201 'column' => 'name',
202 'filter_type' => 'relation',
203 'relation' => 'tax_rate',
204 'type' => 'text',
205 ],
206 [
207 'label' => __('Filed', 'fluent-cart'),
208 'value' => 'filed',
209 'column' => 'filed_at',
210 'filter_type' => 'custom',
211 'type' => 'selections',
212 'options' => [
213 'filed' => __('Filed', 'fluent-cart'),
214 'not_filed' => __('Not Filed', 'fluent-cart'),
215 ],
216 'callback' => function ($query, $data) {
217 if ($data === 'filed') {
218 $query->whereNotNull('filed_at');
219 } else {
220 $query->whereNull('filed_at');
221 }
222 },
223 ],
224 ],
225 ],
226 ];
227 }
228
229 public static function getCountriesOptions()
230 {
231 return LocalizationManager::getInstance()->countryIsoList();
232 }
233
234 public static function getStatesOptions()
235 {
236 $statesFromDB = App::db()->table('fct_tax_rates')
237 ->select(['country', 'state'])
238 ->whereNotNull('state')
239 ->where('state', '!=', '')
240 ->groupBy(['country', 'state'])
241 ->get();
242
243 $states = LocalizationManager::getInstance()->states();
244
245 $statesList = [];
246
247 foreach ($statesFromDB as $state) {
248 if (isset($states[$state->country]) && isset($states[$state->country][$state->state])) {
249 $statesList[$state->state] = $states[$state->country][$state->state];
250 }
251 }
252
253 return $statesList;
254 }
255 }
256