PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
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 1.2.0 All 47 releases
fluent-cart / app / Helpers / CartCheckoutHelper.php

CartCheckoutHelper.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at app/Helpers/CartCheckoutHelper.php

966 lines 31.3 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\Helpers;
4
5 use FluentCart\Api\Resource\CustomerResource;
6 use FluentCart\Api\Resource\FrontendResource\CartResource;
7 use FluentCart\Api\Resource\FrontendResource\CustomerAddressResource;
8 use FluentCart\Api\Resource\ProductResource;
9 use FluentCart\Api\StoreSettings;
10 use FluentCart\App\App;
11 use FluentCart\App\Models\Cart;
12 use FluentCart\App\Models\Customer;
13 use FluentCart\App\Models\ProductVariation;
14 use FluentCart\App\Services\CheckoutService;
15 use FluentCart\App\Services\Localization\LocalizationManager;
16 use FluentCart\App\Services\OrderService;
17 use FluentCart\Framework\Database\Orm\Builder;
18 use FluentCart\Framework\Database\Orm\Model;
19 use FluentCart\Framework\Support\Arr;
20 use FluentCart\Framework\Support\ArrayableInterface;
21 use FluentCart\Framework\Support\Collection;
22
23 class CartCheckoutHelper implements ArrayableInterface
24 {
25 private $cart;
26
27 private ?array $utmData = [];
28
29 private ?array $checkoutData = [];
30
31 protected ?StoreSettings $storeSettings = null;
32
33 static $instance = false;
34
35 protected array $couponDiscountData = [];
36
37
38 public bool $disableCoupon = false;
39
40 public function __construct($disableCoupon = false)
41 {
42 $this->disableCoupon = $disableCoupon;
43 $this->init();
44 }
45
46 public static function make($disableCoupon = false): ?CartCheckoutHelper
47 {
48 if (!self::$instance) {
49 self::$instance = new self($disableCoupon);
50 }
51
52 return self::$instance;
53 }
54
55 /**
56 * Drop the request-scoped instance so the next make() re-initializes from
57 * the current request's cart. Production runs one request per process and
58 * never needs this; long-lived processes (the test suites) call it before
59 * each dispatched request so a helper bound to an earlier cart cannot leak
60 * into the next checkout.
61 */
62 public static function resetInstance(): void
63 {
64 self::$instance = false;
65 }
66
67
68 public function init()
69 {
70
71 $this->storeSettings = new StoreSettings();
72 $cart = CartHelper::getCart();
73
74 if (!$cart) {
75 return;
76 }
77
78 $this->cart = $cart;
79
80 $this->validateCartItems();
81
82 if (
83 Arr::get($this->cart->checkout_data, 'disable_coupons') == 'yes' ||
84 $this->disableCoupon
85 ) {
86 return;
87 }
88
89 $this->applyCoupon();
90 }
91
92 public function hasSubscription(): string
93 {
94 $currentCart = $this->getCart();
95 if (!empty($currentCart->cart_data)) {
96 foreach ($currentCart->cart_data as $key => $value) {
97 if (Arr::get($value, 'other_info.payment_type') === 'subscription') {
98 return 'yes';
99 };
100 }
101 }
102 return 'no';
103 }
104
105 public function isZeroPayment(): bool
106 {
107 return $this->getItemsAmountTotal(false, false) <= 0 && $this->hasSubscription() !== 'yes';
108 }
109
110 protected function applyCoupon()
111 {
112 $this->couponDiscountData = $this->cart->getDiscountLines();
113 }
114
115 public function getCouponDiscountData(): array
116 {
117 return $this->cart->getDiscountLines();
118 }
119
120 public function getAppliedCouponCodes(): array
121 {
122 return $this->cart->coupons ?? [];
123 }
124
125 public function setCouponDiscountData(array $data)
126 {
127 $this->couponDiscountData = $data;
128 }
129
130 public function validateCartItems()
131 {
132
133 $variationIds = (new Collection($this->getItems()))->pluck('id')->toArray();
134 $variations = ProductVariation::query()
135 ->with(['product.detail', 'media'])
136 ->whereIn('id', $variationIds)->get();
137
138 $newCartItems = [];
139
140 // foreach ($variations as $variation) {
141 // if (isset($this->cart->cart_data[$variation->id])) {
142 // $quantity = Arr::get($this->cart->cart_data[$variation->id], 'quantity');
143 // $item = CartHelper::generateCartItemFromVariation($variation, $quantity);
144 // $newCartItems[$variation->id] = $item;
145 // }
146 //
147 // }
148 //
149 // $this->cart->cart_data = $newCartItems;
150 //
151 // $this->cart->update();
152
153 $this->prepareCartData($this->cart);
154
155 }
156
157 public function getCountryList(): array
158 {
159 return Helper::getCountryList();
160 }
161
162 /**
163 * @return StoreSettings
164 */
165 public function getStoreSettings(): StoreSettings
166 {
167 return $this->storeSettings;
168 }
169
170 public function setCart(Cart $cart)
171 {
172 $this->cart = $cart;
173 }
174
175 public function getCart()
176 {
177 return $this->cart;
178 }
179
180 protected function prepareCartData(Cart $cart)
181 {
182 $this->utmData = $cart->utm_data;
183 if ($checkoutData = $this->cart->checkout_data) {
184 $this->checkoutData = $checkoutData;
185 }
186 }
187
188
189 /**
190 * @param ProductVariation $variation
191 *
192 * @return Cart
193 */
194 public static function getCartFromVariation(ProductVariation $variation): Cart
195 {
196 return CartHelper::generateCartFromVariation($variation);
197 }
198
199
200 public function getSettings($setting = '')
201 {
202 if (!$this->storeSettings) {
203 $this->storeSettings = new StoreSettings();
204 }
205
206 if ($setting) {
207 return $this->storeSettings->get($setting);
208 }
209
210 return $this->storeSettings->get();
211 }
212
213 public function getItems(): array
214 {
215 if (empty($this->cart)) {
216 return [];
217 }
218 return $this->cart->cart_data ?? [];
219 }
220
221 public function getUtmData($data): array
222 {
223 $utmKeys = [
224 'utm_campaign',
225 'utm_content',
226 'utm_term',
227 'utm_source',
228 'utm_medium',
229 'utm_id',
230 'refer_url',
231 'fbclid',
232 'gclid'
233 ];
234
235 $utmData = [];
236 foreach ($utmKeys as $key) {
237 $value = Arr::get($data, $key);
238 if ($value) {
239 $utmData[$key] = sanitize_text_field($value);
240 }
241 }
242 return array_merge($utmData, $this->utmData ?? []);
243 }
244
245 public function isEmailLocked()
246 {
247 // To-do disabled this for now
248 return false;
249 // return !!$this->getUser();
250 }
251
252 public function getUserId()
253 {
254 global $current_user;
255 $userId = $current_user->ID ?? null;
256
257 if (!$userId && $this->cart && $this->cart->user_id) {
258 $userId = $this->cart->user_id;
259 }
260
261 return $userId;
262 }
263
264 public function getUser()
265 {
266 static $user;
267
268 if ($user) {
269 return $user;
270 }
271
272 $userId = $this->getUserId();
273
274 if (!$userId) {
275 return false;
276 }
277
278 $user = get_user_by('ID', $userId);
279
280 if ($user) {
281 return $user;
282 }
283 }
284
285 public function getCustomer($email = '')
286 {
287
288 if (empty($email)) {
289 return CustomerResource::getCurrentCustomer();
290 }
291 $customer = Customer::query();
292 $customer = $customer->where('email', $email);
293 $customer = $customer->with('billing_address')
294 ->with('shipping_address')
295 ->first();
296
297
298 if (!$customer && $this->cart && $this->cart->customer) {
299 $customer = $this->cart->customer;
300 }
301
302 return $customer ?? false;
303 }
304
305 public function requireShippingAddress(): bool
306 {
307 $shippableTypes = ['physical'];
308
309 foreach ($this->getItems() as $item) {
310 if (in_array($item['fulfillment_type'], $shippableTypes)) {
311 return true;
312 }
313 }
314 return false;
315 }
316
317
318 public function getEmail()
319 {
320 $user = $this->getUser();
321 if ($user) {
322 return $user->user_email;
323 }
324
325 if ($customer = $this->getCustomer()) {
326 return $customer->email;
327 }
328
329 if ($this->cart) {
330 return $this->cart->email;
331 }
332
333 }
334
335 public function getFullName()
336 {
337 return trim($this->getFirstName() . ' ' . $this->getLastName());
338 }
339
340 public function getFirstName()
341 {
342 if ($this->cart && $this->cart->first_name) {
343 return $this->cart->first_name;
344 }
345
346 $user = $this->getUser();
347 if (!empty($user->first_name)) {
348 return $user->first_name;
349 }
350
351 if ($customer = $this->getCustomer()) {
352 if ($customer->first_name) {
353 return $customer->first_name;
354 }
355 }
356
357 return '';
358 }
359
360
361 /**
362 * @param $productId
363 *
364 * @return array|null
365 */
366 public function getOriginalProduct($productId): ?array
367 {
368 return ProductResource::find($productId);
369 }
370
371 /**
372 * @param $itemId
373 *
374 * @return Builder|Builder[]|\FluentCart\Framework\Database\Orm\Collection|Model|null
375 */
376 public function getOriginalItem($itemId)
377 {
378 return ProductVariation::query()->find($itemId);
379 }
380
381 public function getLastName()
382 {
383 if ($this->cart && $this->cart->last_name) {
384 return $this->cart->last_name;
385 }
386
387 $user = $this->getUser();
388 if ($user && $user->last_name) {
389 return $user->last_name;
390 }
391
392 if ($customer = $this->getCustomer()) {
393 if ($customer->last_name) {
394 return $customer->last_name;
395 }
396 }
397
398 return '';
399 }
400
401 public function getBillingAddress($withNameEmail = false)
402 {
403 $checkoutBilling = Arr::get($this->checkoutData, 'billing', []);
404
405 if ($customer = $this->getCustomer()) {
406 $customerBilling = CustomerAddressResource::find($customer->id, ['type' => 'billing']);
407 $checkoutBilling = wp_parse_args($checkoutBilling, $customerBilling);
408 }
409
410 if ($withNameEmail) {
411 $checkoutBilling['first_name'] = $this->getFirstName();
412 $checkoutBilling['last_name'] = $this->getLastName();
413 $checkoutBilling['email'] = $this->getEmail();
414 }
415
416 return $checkoutBilling;
417 }
418
419 public function getShippingAddress()
420 {
421 $checkoutShipping = Arr::get($this->checkoutData, 'shipping', []);
422
423 //todo : will add dynamic shipping from saved item later
424
425 // $customerAddress = new CustomerAddress();
426 // if ($customer = $this->getCustomer()) {
427 // $primaryShipping = $customerAddress->getAddress($customer->id, 'shipping');
428 // $checkoutShipping = wp_parse_args($checkoutShipping, $primaryShipping);
429 // }
430 return $checkoutShipping;
431 }
432
433 public function getAddressBaseFields($type = 'billing'): array
434 {
435 $getCart = CartHelper::getCart();
436
437 $selectedCountry = Arr::get($getCart, 'checkout_data.form_data.' . $type . '_country');
438
439 if (empty($selectedCountry)) {
440 $HTTP_CF_IP_COUNTRY = Arr::get( App::request()->server(), 'HTTP_CF_IPCOUNTRY');
441 $selectedCountry = $HTTP_CF_IP_COUNTRY ?? $selectedCountry;
442 }
443
444 $states = [];
445 if (empty(Arr::get($getCart, 'checkout_data.form_data.' . $type . '_state'))) {
446 $states = [
447 [
448 'name' => __('Select an option', 'fluent-cart'),
449 'value' => ''
450 ]
451 ];
452 }
453
454 $addressLocale = [];
455 if (!empty($selectedCountry)) {
456 $states = array_merge($states, LocalizationManager::getInstance()->statesOptions($selectedCountry));
457 $addressLocale = LocalizationManager::getInstance()->addressLocales($selectedCountry);
458 }
459
460 $stateLabel = Arr::get($addressLocale, 'state.label', __('State', 'fluent-cart'));
461 $countries = [
462 [
463 'name' => __('Select a Country', 'fluent-cart'),
464 'value' => ''
465 ]
466 ];
467 $countries = array_merge($countries, $this->getCountryList());
468
469
470 if (empty($states) && !Arr::get($addressLocale, 'state.hidden')) {
471 $stateInput = [
472 'type' => 'text',
473 'data-type' => 'text',
474 'label' => '',
475 'required' => 'yes',
476 'autocomplete' => 'address-level2',
477 'placeholder' => $stateLabel,
478 'value' => '',
479 ];
480 } else {
481 $stateInput = [
482 'type' => 'select',
483 'data-type' => 'select',
484 'label' => '',
485 'options' => $states,
486 'required' => 'yes',
487 'autocomplete' => 'address-level2',
488 'placeholder' => $stateLabel,
489 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_state') ?? '',
490 ];
491 }
492
493 return [
494 'address_section' => [
495 'type' => 'section',
496 'title' => __('Address', 'fluent-cart'),
497 'schema' => [
498 'label' => [
499 'type' => 'text',
500 'data-type' => 'text',
501 'label' => '',
502 'required' => 'yes',
503 'autocomplete' => 'label',
504 'value' => '',
505 'maxlength' => 15,
506 'placeholder' => esc_attr__('e.g Home, Office', 'fluent-cart'),
507 ],
508 'name' => [
509 'type' => 'text',
510 'data-type' => 'text',
511 'label' => '',
512 'required' => 'no',
513 'autocomplete' => 'name',
514 'placeholder' => esc_attr__('Name', 'fluent-cart'),
515 ],
516 'country' => [
517 'type' => 'select',
518 'options' => $countries,
519 'data-type' => 'text',
520 'label' => '',
521 'required' => 'yes',
522 'autocomplete' => 'country',
523 'placeholder' => esc_attr__('Country / Region', 'fluent-cart'),
524 'value' => $selectedCountry,
525 ],
526 'address_1' => [
527 'type' => 'text',
528 'data-type' => 'text',
529 'label' => '',
530 /* translators: use local order of street name and house number. */
531 'placeholder' => esc_attr__('Street Address', 'fluent-cart'),
532 'required' => 'yes',
533 'autocomplete' => 'address-line1',
534 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_address_1'),
535 ],
536 'address_2' => [
537 'type' => 'text',
538 'data-type' => 'text',
539 'label' => '',
540 'label_class' => array(''),
541 'placeholder' => esc_attr__('Apt, suite, unit', 'fluent-cart'),
542 'autocomplete' => 'address-line2',
543 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_address_2', ''),
544 ],
545 'state' => $stateInput,
546 'city_zip' => [
547 'type' => 'section',
548 'schema' => [
549 'city' => [
550 'type' => 'text',
551 'data-type' => 'text',
552 'label' => '',
553 'required' => 'yes',
554 'autocomplete' => 'address-level2',
555 'placeholder' => esc_attr__('Town / City', 'fluent-cart'),
556 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_city'),
557 ],
558 'postcode' => [
559 'type' => 'text',
560 'data-type' => 'text',
561 'label' => '',
562 'required' => 'yes',
563 'validate' => array('postcode'),
564 'autocomplete' => 'postal-code',
565 'placeholder' => esc_attr__('Postcode / ZIP', 'fluent-cart'),
566 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_postcode'),
567 ],
568 ]
569 ]
570 ]
571 ]
572 ];
573 }
574
575 public function getAddressFields($type = 'billing')
576 {
577 $addresses = [];
578 $customer = CustomerResource::getCurrentCustomer();
579 $getCart = CartHelper::getCart();
580
581 if (!empty($customer)) {
582 $customerId = $customer->id;
583 $addresses = CustomerAddressResource::get([
584 'type' => $type,
585 'customer_id' => $customerId,
586 'status' => 'active'
587 ]);
588 }
589
590 $requiredOnLoggedOut = $this->getAddressBaseFields($type);
591 $fieldsToUnset = ['name', 'address_2'];
592 foreach ($fieldsToUnset as $field) {
593 unset($requiredOnLoggedOut['address_section']['schema'][$field]);
594 }
595
596 $requireAdditionalAddress = (new StoreSettings())->get('additional_address_field');
597
598 if ($requireAdditionalAddress == 'yes') {
599
600 $schema = [
601 'company_name' => [
602 'id' => 'company_name',
603 'type' => 'text',
604 'data-type' => 'text',
605 'label' => '',
606 'autocomplete' => 'organization',
607 'placeholder' => esc_attr__('Company Name', 'fluent-cart'),
608 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_company_name'),
609 ],
610 'phone' => [
611 'id' => 'phone',
612 'type' => 'text',
613 'data-type' => 'text',
614 'label' => '',
615 'disabled' => false,
616 'placeholder' => esc_attr__('Phone', 'fluent-cart'),
617 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_phone'),
618 ]
619 ];
620
621
622 $requiredOnLoggedOut['address_section']['schema'] = array_merge(
623 $requiredOnLoggedOut['address_section']['schema'],
624 $schema
625 );
626 }
627
628 $addressLabel = $type === 'billing' ?
629 __('Billing Address', 'fluent-cart') :
630 __('Shipping Address', 'fluent-cart');
631
632 $requiredOnLoggedIn = [
633 'address' => [
634 'type' => 'section',
635 'title' => $addressLabel,
636 'schema' => [
637 'address' => [
638 'id' => 'address',
639 'type' => 'address_select',
640 'data-type' => 'hidden',
641 'required' => 'no',
642 'label' => '',
643 'disabled' => false,
644 'options' => $addresses,
645 'value' => Arr::get($getCart, 'checkout_data.form_data.' . $type . '_address_id'),
646 ]
647 ]
648 ]
649 ];
650
651 $customerName = $this->getFullName();
652 $customerEmail = $this->getEmail();
653 $fullNameDisabled = $type === 'billing' && is_user_logged_in() && !empty($customerName);
654 $savedFullName = Arr::get($getCart, 'checkout_data.form_data.' . $type . '_full_name');
655 $savedEmail = Arr::get($getCart, 'checkout_data.form_data.' . $type . '_email');
656 if (!empty($savedFullName)) {
657 $customerName = $savedFullName;
658 }
659 if (!empty($savedEmail)) {
660 $customerEmail = $savedEmail;
661 }
662
663 $fields = [
664 'personal_information' => [
665 'type' => 'section',
666 'schema' => [
667 'full_name' => [
668 'id' => 'full_name',
669 'type' => 'text',
670 'data-type' => 'text',
671 'label' => '',
672 'required' => 'yes',
673 'autocomplete' => 'given-name',
674 'value' => $customerName,
675 'placeholder' => esc_attr__('Full Name', 'fluent-cart'),
676 ],
677 'email' => [
678 'id' => 'email',
679 'type' => 'text',
680 'data-type' => 'email',
681 'required' => 'yes',
682 'label' => '',
683 'autocomplete' => 'email username',
684 'value' => $customerEmail,
685 'disabled' => is_user_logged_in(),
686 'placeholder' => esc_attr__('Email address', 'fluent-cart'),
687 ]
688 ]
689 ],
690 ];
691
692 $currentCustomer = CustomerResource::getCurrentCustomer();
693
694 $hasAddress = true;
695
696 if (empty($currentCustomer) || $currentCustomer->billing_address->count() === 0) {
697 $hasAddress = false;
698 }
699
700 $fields = $fields + ($hasAddress ? $requiredOnLoggedIn : $requiredOnLoggedOut);
701
702 return apply_filters('fluent_cart/checkout_address_fields', $fields, []);
703 }
704
705 public function getBillingAddressFields($viewData = [])
706 {
707 $labels = Arr::get($viewData, 'labels', []);
708 $fields = $this->getAddressFields();
709 $allowCreateAccount = Arr::get($viewData, 'block_allow_create_account', []);
710 $label = Arr::get($allowCreateAccount, 'label', __('Create My Account', 'fluent-cart'));
711 $customer = CustomerResource::getCurrentCustomer();
712
713 if (isset($fields['address_section'])) {
714 $fields['address_section']['title'] = $labels['billing_address'] ?? __('Billing Address', 'fluent-cart');
715 }
716
717 if ((new StoreSettings())->get('user_account_creation_mode') === 'user_choice') {
718 $isUserLoggedIn = is_user_logged_in();
719
720 // Show the view if the user is not logged in or does not have an account
721 if (!$isUserLoggedIn || ($customer === null)) {
722 $checked = $this->hasSubscription() === 'yes' ? 'yes' : 'no';
723 $disabled = $this->hasSubscription() === 'yes';
724 $fields['personal_information']['schema']['allow_create_account'] = [
725 'id' => 'allow_create',
726 'type' => 'checkbox',
727 'data-type' => 'text',
728 'label' => $label,
729 'skip_prefix' => true,
730 'autocomplete' => 'given-name',
731 'value' => 'yes',
732 'checked' => $checked,
733 'disabled' => $disabled
734 ];
735 }
736 }
737
738 unset($fields['address_section']['schema']['label']);
739
740 return apply_filters('fluent_cart/checkout_billing_fields', $fields, [
741 'viewData' => $viewData,
742 'customer' => $customer,
743 'labels' => $labels,
744 'has_subscription' => $this->hasSubscription()
745 ]);
746 }
747
748 public function getShippingAddressFields($viewData = [])
749 {
750 $labels = Arr::get($viewData, 'labels', []);
751 $fields = $this->getAddressFields('shipping');
752 $addressSchema = [];
753
754 if (isset($fields['address_section'])) {
755 $addressSchema = $fields['address_section']['schema'];
756 $fields['address_section']['title'] = $labels['shipping_address'] ?? __('Shipping Address', 'fluent-cart');
757 }
758
759 // Remove email field
760 if (isset($fields['personal_information']['schema']['email'])) {
761 unset($fields['personal_information']['schema']['email']);
762 unset($fields['tax_information']);
763 }
764
765 // Extract name field and remove personal information section
766 $fullNameField = $fields['personal_information']['schema'] ?? [];
767 unset($fields['personal_information']);
768
769 if (isset($fields['address_section']) && !empty($addressSchema) && is_array($addressSchema)) {
770 $fields['address_section']['schema'] = array_merge(
771 $fullNameField,
772 $addressSchema
773 );
774 }
775
776 // Remove label if user is not logged in
777 if (!is_user_logged_in()) {
778 unset($fields['address_section']['schema']['label']);
779 }
780
781 return apply_filters('fluent_cart/checkout_shipping_fields', $fields, [
782 'viewData' => $viewData,
783 'labels' => $labels,
784 ]);
785 }
786
787 public function getItemsAmountTotal($formatted = true, $withCurrency = true, $shippingTotal = 0)
788 {
789 $checkoutItems = new CheckoutService($this->getItems());
790
791 $subscriptionItems = $checkoutItems->subscriptions;
792 $onetimeItems = $checkoutItems->onetime;
793
794 $items = array_merge($onetimeItems, $subscriptionItems);
795
796 $total = OrderService::getItemsAmountTotal($items, false, $withCurrency, $shippingTotal);
797
798 if (!$formatted) {
799 return $total;
800 }
801
802 return Helper::toDecimal($total, $withCurrency);
803 }
804
805 public function getItemsAmountTotalWithShipping($shippingTotal = 0, $formatted = true, $withCurrency = true)
806 {
807 return $this->getItemsAmountTotal(true, true, $shippingTotal);
808 }
809
810 public function getItemsAmountSubtotal($formatted = true, $withCurrency = true)
811 {
812 $checkoutItems = new CheckoutService($this->getItems());
813 $subscriptionItems = $checkoutItems->subscriptions;
814 $onetimeItems = $checkoutItems->onetime;
815
816 $items = array_merge($onetimeItems, $subscriptionItems);
817
818
819 $subtotal = OrderService::getItemsAmountWithoutDiscount($items);
820
821 return $formatted ? Helper::toDecimal($subtotal, $withCurrency) : $subtotal;
822 }
823
824 public function getSignupFields()
825 {
826 $fields = array(
827 'full_name' => array(
828 'id' => 'full_name',
829 'type' => 'text',
830 'data-type' => 'text',
831 'label' => __('Full Name', 'fluent-cart'),
832 'required' => 'yes',
833 'autocomplete' => 'given-name',
834 'placeholder' => esc_attr__('e.g. James Brown', 'fluent-cart'),
835 ),
836 'email' => array(
837 'id' => 'billing_email',
838 'type' => 'text',
839 'data-type' => 'email',
840 'required' => 'yes',
841 'label' => __('Email Address', 'fluent-cart'),
842 'autocomplete' => 'email username',
843 'placeholder' => esc_attr__('e.g. name@domain.com', 'fluent-cart'),
844 ),
845 'password' => array(
846 'id' => 'password',
847 'type' => 'text',
848 'data-type' => 'password',
849 'required' => 'no',
850 'label' => __('Password', 'fluent-cart'),
851 'autocomplete' => 'current-password',
852 'placeholder' => esc_attr__('Enter Strong password', 'fluent-cart'),
853 ),
854 );
855
856 return apply_filters('fluent_cart/checkout_signup_fields', $fields, []);
857 }
858
859 public function getLoginFields()
860 {
861 $fields = array(
862 'user_login' => array(
863 'id' => 'username_email',
864 'type' => 'text',
865 'data-type' => 'text',
866 'required' => 'yes',
867 'label' => __('Username or Email Address', 'fluent-cart'),
868 'autocomplete' => 'email username',
869 'placeholder' => esc_attr__('e.g. name@domain.com or username', 'fluent-cart'),
870 ),
871 'password' => array(
872 'id' => 'password',
873 'type' => 'text',
874 'data-type' => 'password',
875 'required' => 'yes',
876 'label' => __('Password', 'fluent-cart'),
877 'autocomplete' => 'current-password',
878 'placeholder' => esc_attr__('Enter password', 'fluent-cart'),
879 ),
880 );
881
882 return apply_filters('fluent_cart/checkout_login_fields', $fields, []);
883 }
884
885 public function getCartHash()
886 {
887 if ($this->cart == null) {
888 return null;
889 }
890
891 return $this->cart->cart_hash;
892 }
893
894
895 public function toArray(): array
896 {
897 return [
898 'address_fields' => $this->getAddressFields(),
899 'billing_address' => $this->getBillingAddress(),
900 'billing_address_fields' => $this->getBillingAddressFields(),
901 'cart_hash' => $this->getCartHash(),
902 'customer' => $this->getCustomer(),
903 'info' => [
904 'email' => $this->getEmail(),
905 'first_name' => $this->getFirstName(),
906 'last_name' => $this->getLastName(),
907 'user_id' => $this->getUserId()
908 ],
909 'is_email_locked' => $this->isEmailLocked(),
910 'items' => $this->getItems(),
911 'settings' => $this->getSettings(),
912 'user' => $this->getUser(),
913 ];
914 }
915
916 public function getCouponFields()
917 {
918 $fields = array(
919 'coupon' => array(
920 'name_prefix' => 'coupon_',
921 'id' => 'coupon',
922 'type' => 'text',
923 'data-type' => 'text',
924 'label' => '',
925 'required' => 'no',
926 'placeholder' => __('Apply Here', 'fluent-cart'),
927 ),
928 'applied_coupons' => array(
929 'type' => 'hidden',
930 'data-type' => 'hidden',
931 'label' => '',
932 ),
933 );
934
935 return apply_filters('fluent_cart/checkout_coupon_fields', $fields, []);
936 }
937
938 public function getManualDiscountAmount()
939 {
940 if (empty($this->cart)) {
941 return 0;
942 }
943
944 if ($this->cart->order) {
945 return $this->cart->order->manual_discount_total;
946 }
947
948 return (int)Arr::get($this->cart->checkout_data, 'manual_discount.amount', 0)
949 + (int)Arr::get($this->cart->checkout_data, 'upgrade_discount.amount', 0)
950 + $this->getProrateCreditAmount();
951 }
952
953 public function getProrateCreditAmount()
954 {
955 if (empty($this->cart)) {
956 return 0;
957 }
958
959 if ($this->cart->order) {
960 return (int) Arr::get($this->cart->order->config, 'prorate_credit', 0);
961 }
962
963 return (int) Arr::get($this->cart->checkout_data, 'prorate_credit.amount', 0);
964 }
965 }
966