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

572 lines 21.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\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 'coupon_discount_total' => $order->coupon_discount_total,
263 'manual_discount_total' => $order->manual_discount_total,
264 'prorate_credit' => (int) Arr::get($order->config, 'prorate_credit', 0),
265 'tax_total' => $order->tax_total,
266 'tax_behavior' => $order->tax_behavior,
267 'shipping_tax' => $order->shipping_tax,
268 'display_tax_lines' => $order->getDisplayTaxLines(),
269 'display_shipping_tax_lines' => $order->getDisplayShippingTaxLines(),
270 'is_reverse_charge_tax_order' => $order->isReverseChargeTaxOrder(),
271 'reverse_charge_price_mode' => $order->getOrderRcMode(),
272 'is_b2b_order' => $order->isB2BOrder(),
273 'tax_summary' => TaxSummaryHelper::computeTaxSummary($order),
274 'payment_method' => $order->payment_method,
275 'custom_payment_link' => $this->getCustomPaymentLink($order),
276 ];
277
278 $formattedOrderData['subscriptions'] = $order->subscriptions
279 ->filter(function ($subscription) {
280 return !in_array($subscription->status, [Status::SUBSCRIPTION_PENDING, Status::SUBSCRIPTION_INTENDED]);
281 })
282 ->map(function ($subscription) {
283 return OrderService::transformSubscription($subscription);
284 });
285
286 $formattedOrderData['downloads'] = ProductDownload::query()->whereIn('post_id', $productIds)->get()->filter(function ($download) use ($variationIds) {
287 $ids = $download->product_variation_id;
288 return empty($ids) || array_intersect($variationIds, $ids);
289 })->map(function ($download) use ($order) {
290 return [
291 'file_size' => $download->file_size,
292 'title' => $download->title,
293 'download_url' => Helper::generateDownloadFileLink(
294 $download,
295 $order->id
296 ),
297 ];
298 })->toArray();
299
300
301 // Let's find all the transactions related to this order
302 $orderIds = array_filter([$order->id, $order->parent_id]);
303 if ($order->type === Status::ORDER_TYPE_SUBSCRIPTION) {
304 $renewalOrderIds = Order::query()
305 ->where('parent_id', $order->id)
306 ->where('type', Status::ORDER_TYPE_RENEWAL)
307 ->get()->pluck('id')->toArray();
308
309 $orderIds = array_merge($orderIds, $renewalOrderIds);
310 $orderIds = array_values(array_unique($orderIds));
311 }
312
313 $transactions = OrderTransaction::query()
314 ->whereIn('order_id', $orderIds)
315 ->whereIn('status', [
316 Status::TRANSACTION_SUCCEEDED,
317 Status::TRANSACTION_REFUNDED
318 ])
319 ->orderBy('id', 'DESC')
320 ->with(['order'])
321 ->get();
322
323 $formattedOrderData['transactions'] = $transactions->map(function ($transaction) {
324 return OrderService::transformTransaction($transaction);
325 });
326
327 $formattedOrderData = apply_filters('fluent_cart/customer/order_data', $formattedOrderData, [
328 'order' => $order,
329 'customer' => $customer
330 ]);
331
332 $formattedOrderData['id'] = $order->id;
333
334 $hooksContents = apply_filters('fluent_cart/customer/order_details_section_parts', [
335 'before_summary' => '',
336 'after_summary' => '',
337 'after_licenses' => '',
338 'after_subscriptions' => '',
339 'after_downloads' => '',
340 'after_transactions' => '',
341 'end_of_order' => ''
342 ], [
343 'order' => $order,
344 'formattedData' => $formattedOrderData
345 ]);
346
347 return $this->sendSuccess([
348 'order' => $formattedOrderData,
349 'section_parts' => $hooksContents
350 ]);
351 }
352
353 public function downloadableProducts($order_uuid): \WP_REST_Response
354 {
355
356
357 // Call the method and store the response
358 $errorResponse = $this->checkUserLoggedIn();
359
360 // Check if there is an error response and return it if exists
361 if ($errorResponse !== null) {
362 // Return error if user is not logged in
363 return $errorResponse;
364 }
365
366
367 $order = Order::query()
368 ->where('uuid', $order_uuid)
369 ->with('customer')
370 // ->where(function (Builder $query) {
371 // $query->where('payment_status', Status::PAYMENT_PAID)
372 // ->whereIn('status', [Status::ORDER_COMPLETED, Status::ORDER_PROCESSING]);
373 // })
374 ->first();
375
376
377 if (empty($order) || empty($order->customer) || wp_get_current_user()->ID != $order->customer->user_id) {
378
379 return $this->sendSuccess([
380 'message' => __('Success', 'fluent-cart'),
381 'data' => []
382 ]);
383 }
384
385 return $this->sendSuccess([
386 'message' => __('Success', 'fluent-cart'),
387 'data' => $order->getDownloads('customer-profile')
388 ]);
389 }
390
391 /**
392 * @param $order
393 * @return bool|string
394 */
395 public function getCustomPaymentLink($order)
396 {
397 if (!intval($order->total_amount - $order->total_paid)) {
398 return false;
399 }
400 return PaymentHelper::getCustomPaymentLink($order->uuid);
401 }
402
403 public function getTransactionBillingAddress(Request $request, $transaction_uuid)
404 {
405 // get current customer
406 $customer = CustomerResource::getCurrentCustomer();
407
408 if (empty($customer)) {
409 return $this->sendError([
410 'message' => __('Customer not found', 'fluent-cart')
411 ]);
412 }
413
414 $transaction = OrderTransaction::query()->where('uuid', $transaction_uuid)->first();
415
416 if (empty($transaction)) {
417 return $this->sendError([
418 'message' => __('Transaction not found', 'fluent-cart')
419 ]);
420 }
421
422 $order = Order::query()->where('customer_id', $customer->id)->find($transaction->order_id);
423
424 if (empty($order)) {
425 return $this->sendError([
426 'message' => __('Order not found', 'fluent-cart')
427 ]);
428 }
429
430 $vatTaxId = $order->getMeta('vat_tax_id', '');
431
432 // get order_address by $order->id
433 $billingAddress = OrderAddress::query()
434 ->where('order_id', $order->id)
435 ->where('type', 'billing');
436 if (empty($billingAddress)) {
437 $billingAddress = $billingAddress->where('order_id', $order->parent_id);
438 }
439 $billingAddress = $billingAddress->first();
440
441 $formatData = [
442 'address_1' => '',
443 'address_2' => '',
444 'city' => '',
445 'state' => '',
446 'postcode' => '',
447 'country' => '',
448 'name' => '',
449 'vat_tax_id' => '',
450 'address_id' => ''
451 ];
452
453 if (empty($billingAddress)) {
454 return $this->sendSuccess([
455 'message' => '',
456 'data' => $formatData
457 ]);
458 }
459
460 $formatData = [
461 'address_1' => $billingAddress->address_1,
462 'address_2' => $billingAddress->address_2,
463 'city' => $billingAddress->city,
464 'state' => $billingAddress->state,
465 'postcode' => $billingAddress->postcode,
466 'country' => $billingAddress->country,
467 'name' => $billingAddress->name,
468 'vat_tax_id' => $vatTaxId,
469 'address_id' => $billingAddress->id
470 ];
471
472 return $this->sendSuccess([
473 'message' => __('Success', 'fluent-cart'),
474 'data' => $formatData
475 ]);
476 }
477
478 public function saveTransactionBillingAddress(Request $request, $transaction_uuid)
479 {
480 $transactionUuid = sanitize_text_field($transaction_uuid);
481 $address_id = sanitize_text_field(Arr::get($request->all(), 'address_id'));
482 $transaction = OrderTransaction::query()->where('uuid', $transactionUuid)->first();
483
484 $vatTaxId = sanitize_text_field(Arr::get($request->all(), 'vat_tax_id'));
485 $orderId = $transaction->order_id;
486
487 // get order by $transaction->order_id
488 $customer = CustomerResource::getCurrentCustomer();
489
490 $order = Order::query()->where('customer_id', $customer->id)->find($orderId);
491
492 if (empty($order)) {
493 return $this->sendError([
494 'message' => __('Order not found', 'fluent-cart')
495 ]);
496 }
497
498 $address = null;
499
500 if ($address_id) {
501 $address = OrderAddress::query()
502 ->where('id', $address_id)
503 ->where('order_id', $order->id)
504 ->where('type', 'billing')
505 ->first();
506 }
507
508
509 $rules = App::localization()->getValidationRule($request->all());
510
511 // Validate input
512 $validated = $request->validate($rules);
513 // Sanitize
514 $sanitized = $request->getSafe([
515 'name' => 'sanitize_text_field',
516 'address_1' => 'sanitize_text_field',
517 'address_2' => 'sanitize_text_field',
518 'city' => 'sanitize_text_field',
519 'state' => 'sanitize_text_field',
520 'postcode' => 'sanitize_text_field',
521 'country' => 'sanitize_text_field',
522 ]);
523
524 $sanitized['order_id'] = $orderId;
525 $sanitized['type'] = 'billing';
526
527 OrderMeta::query()->updateOrCreate(
528 [
529 'order_id' => $order->id,
530 //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
531 'meta_key' => 'vat_tax_id'
532 ],
533 [
534 //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
535 'meta_value' => $vatTaxId // replace with your value variable
536 ]
537 );
538
539 if (empty($address)) {
540 // create new order address with $request data
541 $isCreated = OrderAddress::create($sanitized);
542
543 if (is_wp_error($isCreated)) {
544 return $this->sendError([
545 'message' => $isCreated->get_error_message()
546 ]);
547 }
548
549 return $this->sendSuccess([
550 'message' => __('Billing address created successfully', 'fluent-cart'),
551 'address_id' => $isCreated
552 ]);
553 }
554
555 // update address
556 $address->fill($sanitized);
557
558 if (!$address->save()) {
559 return $this->sendError([
560 'message' => __('Failed to update billing address', 'fluent-cart')
561 ]);
562 }
563
564
565 return $this->sendSuccess([
566 'message' => __('Billing address updated successfully', 'fluent-cart'),
567 'formatted_address' => $address->getAddressAsText()
568 ]);
569 }
570
571 }
572