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

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