PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.5.0
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.5.0
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 / Http / Controllers / FrontendControllers / CustomerOrderController.php

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

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