PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
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
← All changes | api/Checkout/CheckoutApi.php +42 -51 1.6.0 → 1.6.5 View file →
@@ -21,8 +21,9 @@
21 21 use FluentCart\App\Models\Order;
22 22 use FluentCart\App\Models\OrderAddress;
23 23 use FluentCart\App\Models\ShippingMethod;
24 24 use FluentCart\App\Services\CheckoutService;
25 +use FluentCart\App\Services\CustomerIdentity\EmailVerificationService;
25 26 use FluentCart\App\Services\Localization\LocalizationManager;
26 27 use FluentCart\App\Services\OrderService;
27 28 use FluentCart\App\Services\Payments\PaymentHelper;
28 29 use FluentCart\App\Services\Payments\PaymentInstance;
@@ -163,9 +164,14 @@
163 164 }
164 165
165 166 $orderData = OrderService::groupSanitizedData($validatedData);
166 167
167 - $shippingMethodId = Arr::get($orderData, 'others.fc_shipping_method');
168 + // The form posts the method twice: the checked radio (fc_shipping_method) and its
169 + // hidden mirror (fc_selected_shipping_method). validateData() checks only the mirror
170 + // against the address's zones, so pricing from the radio let a request pass with one
171 + // method and be charged by another, from a zone the address is not in. Read from
172 + // $validatedData, not the sanitized copy in others: that is the exact integer checked.
173 + $shippingMethodId = (int) Arr::get($validatedData, 'fc_selected_shipping_method', 0);
168 174
169 175 $shippingMethod = null;
170 176 $shippingCharge = 0;
171 177 if (!$cartCheckoutService->isAllDigital()) {
@@ -291,14 +297,16 @@
291 297 }
292 298
293 299 private static function getOrCreateCustomer(CartCheckoutHelper $cartCheckoutHelper, $orderData)
294 300 {
295 - $customerEmail = static::getCustomerEmail($orderData['billing_address']);
296 - if (is_user_logged_in()) {
297 - $customerEmail = wp_get_current_user()->user_email;
298 - Arr::set($orderData, 'billing_address.email', $customerEmail);
301 + $customer = is_user_logged_in() ? ApiCustomerResource::getCurrentCustomer() : null;
302 + $email = static::getCustomerEmail($orderData['billing_address']);
303 + Arr::set($orderData, 'billing_address.email', $email);
304 + if (!$customer) {
305 + // Reuse the email's customer for the purchase without granting ownership.
306 + $customer = Customer::query()->where('email', $email)->orderBy('id')->first();
299 307 }
300 - $customer = $cartCheckoutHelper->getCustomer($customerEmail);
308 +
301 309 return static::createCustomerWithAddress(
302 310 $customer,
303 311 $orderData,
304 312 $orderData['billing_address'],
@@ -431,15 +439,12 @@
431 439
432 440 static::syncCustomerNames($order, $args);
433 441 $cart = CartHelper::getCart();
434 442
435 - $utmData = [];
436 - if (!empty($cart) && is_array($cart->utm_data) && count($cart->utm_data) > 0) {
437 - $utmData = $cart->utm_data;
438 - }
439 -
440 - $requestUtmData = UtmHelper::getUtmDataOfRequest();
441 - $utmData = wp_parse_args($requestUtmData, $utmData);
443 + $utmData = UtmHelper::resolveUtmData(
444 + UtmHelper::getUtmDataOfRequest(),
445 + !empty($cart) ? $cart->utm_data : []
446 + );
442 447 UtmHelper::addUtmToOrder($order->id, $utmData);
443 448
444 449 $prevOrder = Arr::get($args, 'prev_order', null);
445 450
@@ -526,9 +531,10 @@
526 531 private static function syncCustomerNames($order, $args)
527 532 {
528 533 $customer = $order->customer;
529 534
530 - if (empty($customer)) {
535 + if (empty($customer) || !is_user_logged_in() || (int) $customer->user_id !== get_current_user_id()
536 + || EmailVerificationService::isRequired(get_current_user_id())) {
531 537 return;
532 538 }
533 539
534 540 $firstName = Arr::get($args, 'billing_address.first_name');
@@ -538,18 +544,13 @@
538 544 'first_name' => $firstName,
539 545 'last_name' => $lastName,
540 546 ]);
541 547
542 - $user = get_user_by('email', $customer->email);
543 -
544 - if (empty($user)) {
545 - return;
548 + // Keep profile updates tied to the buyer's stored account link too.
549 + if (is_user_logged_in() && (int) $customer->user_id === get_current_user_id()) {
550 + update_user_meta(get_current_user_id(), 'first_name', $firstName);
551 + update_user_meta(get_current_user_id(), 'last_name', $lastName);
546 552 }
547 -
548 - if (is_user_logged_in() && $user->ID === get_current_user_id()) {
549 - update_user_meta($user->ID, 'first_name', $firstName);
550 - update_user_meta($user->ID, 'last_name', $lastName);
551 - }
552 553 }
553 554
554 555 public static function updateStock($order)
555 556 {
@@ -577,16 +578,18 @@
577 578 if ($current_user->ID) {
578 579 $billingAddress['email'] = $current_user->user_email;
579 580 $billingAddress['user_id'] = $current_user->ID;
580 581 } else {
581 - static::handleUserCreation($orderData, $billingAddress);
582 + unset($billingAddress['user_id']);
582 583 }
583 584
584 585 $customer = CustomerResource::create($billingAddress);
585 586 $customer = Arr::get($customer, 'data', null);
586 587 $customerId = Arr::get($customer, 'id', null);
587 - static::createCustomerAddress($billingAddress, $customerId);
588 - static::createCustomerAddress($shippingAddress, $customerId);
588 + if ($customer && $customer->wasRecentlyCreated) {
589 + static::createCustomerAddress($billingAddress, $customerId);
590 + static::createCustomerAddress($shippingAddress, $customerId);
591 + }
589 592
590 593 return $customer;
591 594 }
592 595
@@ -591,17 +594,13 @@
591 594 }
592 595
593 596 private static function updateExistingCustomer($customer, $orderData, $billingAddress, $shippingAddress)
594 597 {
595 - if (empty($customer->user_id)) {
596 - $currentLoggedInUser = wp_get_current_user();
597 - if ($currentLoggedInUser && $currentLoggedInUser->user_email === $customer->email) {
598 - $userId = get_current_user_id();
599 - $customer->update(['user_id' => $userId]);
600 - $billingAddress['user_id'] = $userId;
601 - }
598 + // Order addresses come from this checkout; saved profile data needs proof.
599 + if (!is_user_logged_in() || (int) $customer->user_id !== get_current_user_id()
600 + || EmailVerificationService::isRequired(get_current_user_id())) {
601 + return;
602 602 }
603 -
604 603 $customer->load(['billing_address', 'shipping_address']);
605 604
606 605 if ($customer->billing_address->count() < 1) {
607 606 static::createCustomerAddress($billingAddress, $customer->id);
@@ -608,25 +607,10 @@
608 607 }
609 608 if ($customer->shipping_address->count() < 1) {
610 609 static::createCustomerAddress($shippingAddress, $customer->id);
611 610 }
612 -
613 - static::handleUserCreation($orderData, $billingAddress, $customer);
614 611 }
615 612
616 - private static function handleUserCreation($orderData, &$billingAddress, $customer = null)
617 - {
618 - $userEmail = Arr::get($billingAddress, 'email');
619 - $user = get_user_by('email', $userEmail);
620 -
621 - if ($user) {
622 - $billingAddress['user_id'] = $user->ID;
623 - if ($customer) {
624 - $customer->update(['user_id' => $user->ID]);
625 - }
626 - }
627 - }
628 -
629 613 private static function getCustomerEmail($billingAddress)
630 614 {
631 615 return is_user_logged_in() ? wp_get_current_user()->user_email : $billingAddress['email'];
632 616 }
@@ -1006,9 +990,16 @@
1006 990
1007 991
1008 992 if ($cart->requireShipping()) {
1009 993 if (!empty($data['fc_selected_shipping_method'])) {
1010 - $selectedMethod = $data['fc_selected_shipping_method'];
994 + // One integer, decided here, is both what is checked and what placeOrder() prices.
995 + // A loose compare let PHP 7.4 match "1<b>2" to method 1, and sanitize_text_field()
996 + // then turned the same string into "12", so the order was priced by method 12.
997 + $rawMethod = $data['fc_selected_shipping_method'];
998 + $isPlainId = (is_string($rawMethod) || is_int($rawMethod)) && (string) absint($rawMethod) === (string) $rawMethod;
999 + $selectedMethod = $isPlainId ? absint($rawMethod) : 0;
1000 + $data['fc_selected_shipping_method'] = $selectedMethod;
1001 +
1011 1002 $shippingCountry = Arr::get($data, 'billing_country', '');
1012 1003 $shippingState = Arr::get($data, 'billing_state', '');
1013 1004 $shipToDifferent = Arr::get($data, 'ship_to_different', 'no') === 'yes';
1014 1005
@@ -1024,9 +1015,9 @@
1024 1015 $errors['shipping_method']['unavailable'] = __('We don\'t ship to this address. Please select a different address.', 'fluent-cart');
1025 1016 } else {
1026 1017 $found = false;
1027 1018 foreach ($availableShippingMethods as $shippingMethod) {
1028 - if ($shippingMethod->id == $selectedMethod) {
1019 + if ((int) $shippingMethod->id === $selectedMethod) {
1029 1020 $found = true;
1030 1021 break;
1031 1022 }
1032 1023 }