PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.25
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.25
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 trunk All 48 releases
fluent-cart / app / Http / Controllers / FrontendControllers / CustomerOrderController.php

CustomerOrderController.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.3.25, at app/Http/Controllers/FrontendControllers/CustomerOrderController.php

552 lines 20.5 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\Http\Controllers\FrontendControllers;
4
5 //use FluentCart\Api\Resource\FrontendResource\CustomerResource;
6 use FluentCart\Api\Resource\CustomerAddressResource;
7 use FluentCart\Api\Resource\CustomerResource;
8 use FluentCart\Api\Resource\OrderDownloadPermissionResource;
9 use FluentCart\App\App;
10 use FluentCart\App\Helpers\Helper;
11 use FluentCart\App\Helpers\Status;
12 use FluentCart\App\Http\Requests\FrontendRequests\CustomerRequests\CustomerProfileAccountDetailsRequest;
13 use FluentCart\App\Http\Requests\FrontendRequests\CustomerRequests\CustomerProfileRequest;
14 use FluentCart\App\Models\Customer;
15 use FluentCart\App\Models\Meta;
16 use FluentCart\App\Models\Order;
17 use FluentCart\App\Models\OrderAddress;
18 use FluentCart\App\Models\OrderItem;
19 use FluentCart\App\Models\OrderMeta;
20 use FluentCart\App\Models\OrderTransaction;
21 use FluentCart\App\Models\ProductDownload;
22 use FluentCart\App\Models\ProductVariation;
23 use FluentCart\App\Models\Subscription;
24 use FluentCart\App\Services\FileSystem\FileManager;
25 use FluentCart\App\Services\Localization\LocalizationManager;
26 use FluentCart\App\Services\OrderService;
27 use FluentCart\App\Services\Payments\PaymentHelper;
28 use FluentCart\Framework\Database\Orm\Builder;
29 use FluentCart\Framework\Database\Orm\Relations\HasMany;
30 use FluentCart\Framework\Http\Request\Request;
31 use FluentCart\App\Services\DateTime\DateTime;
32 use FluentCart\Framework\Support\Arr;
33 use FluentCart\Framework\Support\Collection;
34 use FluentCart\Framework\Validator\Validator;
35 use FluentCartPro\App\Modules\Licensing\Models\License;
36 use FluentCartPro\App\Modules\Licensing\Models\LicenseActivation;
37 use FluentCartPro\App\Modules\Licensing\Services\LicenseHelper;
38
39
40 class CustomerOrderController extends BaseFrontendController
41 {
42
43 public function getOrders(Request $request): \WP_REST_Response
44 {
45
46 $customer = CustomerResource::getCurrentCustomer();
47
48 if (!$customer) {
49 return $this->sendSuccess([
50 'orders' => [
51 'data' => [],
52 'total' => 0,
53 'per_page' => 10,
54 'current_page' => 1,
55 'last_page' => 1
56 ]
57 ]);
58 }
59
60 $perPage = (int)$request->get('per_page', 10);
61 $page = (int)$request->get('page', 1);
62 $search = $request->getSafe('search', 'sanitize_text_field');
63
64 $orders = Order::query()
65 ->select(['invoice_no', 'id', 'parent_id', 'total_amount', 'fee_total', 'uuid', 'type', 'status', 'created_at'])
66 ->with(['order_items' => function ($query) {
67 $query->select('id', 'order_id', 'post_title', 'title', 'quantity', 'payment_type', 'line_meta');
68 }])
69 ->where('customer_id', $customer->id)
70 ->where(function ($query) {
71 $query
72 ->where(function ($query) {
73 $query->where('parent_id', '')->orWhereNull('parent_id');
74 })
75 ->orWhere('type', '!=', 'renewal');
76 })
77 ->searchBy($search)
78 ->withCount('renewals')
79 ->orderBy('created_at', 'DESC')
80 ->paginate($perPage, ['*'], 'page', $page);
81
82 $orders->transform(function ($order) {
83 return [
84 'created_at' => DateTime::gmtToTimezone($order->created_at, Arr::get($order->config, 'user_tz', wp_timezone_string()))->format('Y-m-d H:i:s'),
85 'invoice_no' => $order->invoice_no,
86 'total_amount' => $order->total_amount,
87 'uuid' => $order->uuid,
88 'type' => $order->type,
89 'status' => $order->status,
90 'renewals_count' => $order->renewals_count,
91 'order_items' => $order->order_items->map(function ($item) {
92 return [
93 'id' => $item->id,
94 'post_title' => $item->post_title,
95 'title' => $item->title,
96 'quantity' => $item->quantity,
97 'payment_type' => $item->payment_type,
98 'line_meta' => [
99 'bundle_parent_item_id' => Arr::get($item, 'line_meta.bundle_parent_item_id', null),
100 ]
101 ];
102 }),
103 ];
104 });
105
106 return $this->sendSuccess([
107 'orders' => $orders
108 ]);
109 }
110
111 public function orderDetails($order_uuid): \WP_REST_Response
112 {
113 // Call the method and store the response
114 $errorResponse = $this->checkUserLoggedIn();
115
116 // Check if there is an error response and return it if exists
117 if ($errorResponse !== null) {
118 // Return error if user is not logged in
119 return $errorResponse;
120 }
121
122 $customer = CustomerResource::getCurrentCustomer();
123
124 if (!$customer) {
125 return $this->sendError([
126 'message' => __('Customer not found', 'fluent-cart')
127 ]);
128 }
129
130 $order = Order::query()
131 ->where('uuid', $order_uuid)
132 ->where('customer_id', $customer->id)
133 ->with(['customer', 'transactions', 'shipping_address', 'billing_address'])
134 ->with(['order_items' => function ($query) {
135 $query->with([
136 'variantImages',
137 'product' => function ($productQuery) {
138 $productQuery->addAppends(['view_url']);
139 }
140 ]);
141 }])
142 ->first();
143
144 if (!$order) {
145 return $this->sendError([
146 'message' => __('Order not found', 'fluent-cart')
147 ]);
148 }
149
150 if ($order->type == Status::ORDER_TYPE_RENEWAL) {
151 // We will redirect to the parent order details
152 $parentOrder = Order::query()
153 ->where('id', $order->parent_id)
154 ->first();
155
156 if ($parentOrder && $parentOrder->type == Status::ORDER_TYPE_SUBSCRIPTION) {
157 return $this->sendError([
158 'message' => __('This is a renewal order. Please check the parent order details.', 'fluent-cart'),
159 'parent_order' => [
160 'uuid' => $parentOrder->uuid,
161 ]
162 ]);
163 }
164 }
165
166 $orderItems = [];
167 $variationIds = [];
168 $productIds = [];
169 foreach ($order->order_items as $item) {
170 if ($item->payment_type === 'signup_fee') {
171 continue; // Skip signup fee items
172 }
173
174 // Fee items: include with minimal data for frontend display
175 if ($item->payment_type === 'fee') {
176 $orderItems[] = [
177 'id' => $item->id,
178 'post_title' => '',
179 'title' => $item->title,
180 'quantity' => 1,
181 'unit_price' => $item->unit_price,
182 'subtotal' => $item->subtotal,
183 'payment_type' => 'fee',
184 'meta_lines' => [],
185 'extra_amount' => 0,
186 'image' => '',
187 'variant_image' => '',
188 'url' => '',
189 'line_meta' => [],
190 ];
191 continue;
192 }
193
194 $metaLines = [];
195 $extraAmount = 0;
196
197 if ($item->payment_type == 'subscription' && $signupFee = Arr::get($item->other_info, 'signup_fee')) {
198 $metaLines[] = [
199 'label' => Arr::get($item->other_info, 'signup_fee_name', __('Signup Fee', 'fluent-cart')),
200 'value' => Helper::toDecimal($signupFee, true, $order->currency)
201 ];
202 $extraAmount = (int)$signupFee;
203 }
204
205 $orderItems[] = [
206 'variation_id' => $item->object_id,
207 'product_id' => $item->post_id,
208 'post_title' => $item->post_title,
209 'title' => $item->title,
210 'quantity' => $item->quantity,
211 'unit_price' => $item->unit_price,
212 'subtotal' => $item->subtotal,
213 'payment_type' => $item->payment_type,
214 'meta_lines' => $metaLines,
215 'extra_amount' => $extraAmount,
216 'image' => Arr::get($item, 'productImage.meta_value.0.url', ''),
217 'variant_image' => Arr::get($item, 'variantImages.meta_value.0.url', ''),
218 'url' => $item->is_custom
219 ? ($item->view_url ?? '') : ($item->product->view_url ?? ''),
220 'line_meta' => $item->line_meta,
221 'id' => $item->id
222
223 ];
224 $variationIds[] = $item->object_id;
225 $productIds[] = $item->post_id;
226 }
227
228 $formattedOrderData = [
229 'fulfillment_type' => $order->fulfillment_type,
230 'type' => $order->type,
231 'created_at' => DateTime::gmtToTimezone($order->created_at, Arr::get($order->config, 'user_tz', wp_timezone_string()))->format('Y-m-d H:i:s'),
232 'invoice_no' => $order->invoice_no,
233 'currency' => $order->currency,
234 'uuid' => $order->uuid,
235 'order_items' => $orderItems,
236 'status' => $order->status,
237 'payment_status' => $order->payment_status,
238 'shipping_status' => $order->shipping_status,
239 'fee_total' => $order->fee_total,
240
241 'billing_address_text' => $order->billing_address ? $order->billing_address->getAddressAsText(true, false) : '',
242 'shipping_address_text' => $order->shipping_address ? $order->shipping_address->getAddressAsText(true, false) : '',
243
244 'subtotal' => $order->subtotal,
245 'total_amount' => $order->total_amount,
246 'total_paid' => $order->total_paid,
247 'total_refund' => $order->total_refund,
248 'shipping_total' => $order->shipping_total,
249 'coupon_discount_total' => $order->coupon_discount_total,
250 'manual_discount_total' => $order->manual_discount_total,
251 'tax_total' => $order->tax_total,
252 'tax_behavior' => $order->tax_behavior,
253 'shipping_tax' => $order->shipping_tax,
254 'payment_method' => $order->payment_method,
255 'custom_payment_link' => $this->getCustomPaymentLink($order),
256 ];
257
258 $formattedOrderData['subscriptions'] = $order->subscriptions
259 ->filter(function ($subscription) {
260 return !in_array($subscription->status, [Status::SUBSCRIPTION_PENDING, Status::SUBSCRIPTION_INTENDED]);
261 })
262 ->map(function ($subscription) {
263 return OrderService::transformSubscription($subscription);
264 });
265
266 $formattedOrderData['downloads'] = ProductDownload::query()->whereIn('post_id', $productIds)->get()->filter(function ($download) use ($variationIds) {
267 $ids = $download->product_variation_id;
268 return empty($ids) || array_intersect($variationIds, $ids);
269 })->map(function ($download) use ($order) {
270 return [
271 'file_size' => $download->file_size,
272 'title' => $download->title,
273 'download_url' => Helper::generateDownloadFileLink(
274 $download,
275 $order->id
276 ),
277 ];
278 })->toArray();
279
280
281 // Let's find all the transactions related to this order
282 $orderIds = array_filter([$order->id, $order->parent_id]);
283 if ($order->type === Status::ORDER_TYPE_SUBSCRIPTION) {
284 $renewalOrderIds = Order::query()
285 ->where('parent_id', $order->id)
286 ->where('type', Status::ORDER_TYPE_RENEWAL)
287 ->get()->pluck('id')->toArray();
288
289 $orderIds = array_merge($orderIds, $renewalOrderIds);
290 $orderIds = array_values(array_unique($orderIds));
291 }
292
293 $transactions = OrderTransaction::query()
294 ->whereIn('order_id', $orderIds)
295 ->whereIn('status', [
296 Status::TRANSACTION_SUCCEEDED,
297 Status::TRANSACTION_REFUNDED
298 ])
299 ->orderBy('id', 'DESC')
300 ->with(['order'])
301 ->get();
302
303 $formattedOrderData['transactions'] = $transactions->map(function ($transaction) {
304 return OrderService::transformTransaction($transaction);
305 });
306
307 $formattedOrderData = apply_filters('fluent_cart/customer/order_data', $formattedOrderData, [
308 'order' => $order,
309 'customer' => $customer
310 ]);
311
312 $formattedOrderData['id'] = $order->id;
313
314 $hooksContents = apply_filters('fluent_cart/customer/order_details_section_parts', [
315 'before_summary' => '',
316 'after_summary' => '',
317 'after_licenses' => '',
318 'after_subscriptions' => '',
319 'after_downloads' => '',
320 'after_transactions' => '',
321 'end_of_order' => ''
322 ], [
323 'order' => $order,
324 'formattedData' => $formattedOrderData
325 ]);
326
327 return $this->sendSuccess([
328 'order' => $formattedOrderData,
329 'section_parts' => $hooksContents
330 ]);
331 }
332
333 public function downloadableProducts($order_uuid): \WP_REST_Response
334 {
335
336
337 // Call the method and store the response
338 $errorResponse = $this->checkUserLoggedIn();
339
340 // Check if there is an error response and return it if exists
341 if ($errorResponse !== null) {
342 // Return error if user is not logged in
343 return $errorResponse;
344 }
345
346
347 $order = Order::query()
348 ->where('uuid', $order_uuid)
349 ->with('customer')
350 // ->where(function (Builder $query) {
351 // $query->where('payment_status', Status::PAYMENT_PAID)
352 // ->whereIn('status', [Status::ORDER_COMPLETED, Status::ORDER_PROCESSING]);
353 // })
354 ->first();
355
356
357 if (empty($order) || empty($order->customer) || wp_get_current_user()->ID != $order->customer->user_id) {
358
359 return $this->sendSuccess([
360 'message' => __('Success', 'fluent-cart'),
361 'data' => []
362 ]);
363 }
364
365 return $this->sendSuccess([
366 'message' => __('Success', 'fluent-cart'),
367 'data' => $order->getDownloads('customer-profile')
368 ]);
369 }
370
371 /**
372 * @param $order
373 * @return bool|string
374 */
375 public function getCustomPaymentLink($order)
376 {
377 if (!intval($order->total_amount - $order->total_paid)) {
378 return false;
379 }
380 return PaymentHelper::getCustomPaymentLink($order->uuid);
381 }
382
383 public function getTransactionBillingAddress(Request $request, $transaction_uuid)
384 {
385 // get current customer
386 $customer = CustomerResource::getCurrentCustomer();
387
388 if (empty($customer)) {
389 return $this->sendError([
390 'message' => __('Customer not found', 'fluent-cart')
391 ]);
392 }
393
394 $transaction = OrderTransaction::query()->where('uuid', $transaction_uuid)->first();
395
396 if (empty($transaction)) {
397 return $this->sendError([
398 'message' => __('Transaction not found', 'fluent-cart')
399 ]);
400 }
401
402 $order = Order::query()->where('customer_id', $customer->id)->find($transaction->order_id);
403
404 if (empty($order)) {
405 return $this->sendError([
406 'message' => __('Order not found', 'fluent-cart')
407 ]);
408 }
409
410 $vatTaxId = $order->getMeta('vat_tax_id', '');
411
412 // get order_address by $order->id
413 $billingAddress = OrderAddress::query()
414 ->where('order_id', $order->id)
415 ->where('type', 'billing');
416 if (empty($billingAddress)) {
417 $billingAddress = $billingAddress->where('order_id', $order->parent_id);
418 }
419 $billingAddress = $billingAddress->first();
420
421 $formatData = [
422 'address_1' => '',
423 'address_2' => '',
424 'city' => '',
425 'state' => '',
426 'postcode' => '',
427 'country' => '',
428 'name' => '',
429 'vat_tax_id' => '',
430 'address_id' => ''
431 ];
432
433 if (empty($billingAddress)) {
434 return $this->sendSuccess([
435 'message' => '',
436 'data' => $formatData
437 ]);
438 }
439
440 $formatData = [
441 'address_1' => $billingAddress->address_1,
442 'address_2' => $billingAddress->address_2,
443 'city' => $billingAddress->city,
444 'state' => $billingAddress->state,
445 'postcode' => $billingAddress->postcode,
446 'country' => $billingAddress->country,
447 'name' => $billingAddress->name,
448 'vat_tax_id' => $vatTaxId,
449 'address_id' => $billingAddress->id
450 ];
451
452 return $this->sendSuccess([
453 'message' => __('Success', 'fluent-cart'),
454 'data' => $formatData
455 ]);
456 }
457
458 public function saveTransactionBillingAddress(Request $request, $transaction_uuid)
459 {
460 $transactionUuid = sanitize_text_field($transaction_uuid);
461 $address_id = sanitize_text_field(Arr::get($request->all(), 'address_id'));
462 $transaction = OrderTransaction::query()->where('uuid', $transactionUuid)->first();
463
464 $vatTaxId = sanitize_text_field(Arr::get($request->all(), 'vat_tax_id'));
465 $orderId = $transaction->order_id;
466
467 // get order by $transaction->order_id
468 $customer = CustomerResource::getCurrentCustomer();
469
470 $order = Order::query()->where('customer_id', $customer->id)->find($orderId);
471
472 if (empty($order)) {
473 return $this->sendError([
474 'message' => __('Order not found', 'fluent-cart')
475 ]);
476 }
477
478 $address = null;
479
480 if ($address_id) {
481 $address = OrderAddress::query()
482 ->where('id', $address_id)
483 ->where('order_id', $order->id)
484 ->where('type', 'billing')
485 ->first();
486 }
487
488
489 $rules = App::localization()->getValidationRule($request->all());
490
491 // Validate input
492 $validated = $request->validate($rules);
493 // Sanitize
494 $sanitized = $request->getSafe([
495 'name' => 'sanitize_text_field',
496 'address_1' => 'sanitize_text_field',
497 'address_2' => 'sanitize_text_field',
498 'city' => 'sanitize_text_field',
499 'state' => 'sanitize_text_field',
500 'postcode' => 'sanitize_text_field',
501 'country' => 'sanitize_text_field',
502 ]);
503
504 $sanitized['order_id'] = $orderId;
505 $sanitized['type'] = 'billing';
506
507 OrderMeta::query()->updateOrCreate(
508 [
509 'order_id' => $order->id,
510 //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
511 'meta_key' => 'vat_tax_id'
512 ],
513 [
514 //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
515 'meta_value' => $vatTaxId // replace with your value variable
516 ]
517 );
518
519 if (empty($address)) {
520 // create new order address with $request data
521 $isCreated = OrderAddress::create($sanitized);
522
523 if (is_wp_error($isCreated)) {
524 return $this->sendError([
525 'message' => $isCreated->get_error_message()
526 ]);
527 }
528
529 return $this->sendSuccess([
530 'message' => __('Billing address created successfully', 'fluent-cart'),
531 'address_id' => $isCreated
532 ]);
533 }
534
535 // update address
536 $address->fill($sanitized);
537
538 if (!$address->save()) {
539 return $this->sendError([
540 'message' => __('Failed to update billing address', 'fluent-cart')
541 ]);
542 }
543
544
545 return $this->sendSuccess([
546 'message' => __('Billing address updated successfully', 'fluent-cart'),
547 'formatted_address' => $address->getAddressAsText()
548 ]);
549 }
550
551 }
552