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 +38 -44 1.6.4 → 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'],
@@ -523,9 +531,10 @@
523 531 private static function syncCustomerNames($order, $args)
524 532 {
525 533 $customer = $order->customer;
526 534
527 - 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())) {
528 537 return;
529 538 }
530 539
531 540 $firstName = Arr::get($args, 'billing_address.first_name');
@@ -535,18 +544,13 @@
535 544 'first_name' => $firstName,
536 545 'last_name' => $lastName,
537 546 ]);
538 547
539 - $user = get_user_by('email', $customer->email);
540 -
541 - if (empty($user)) {
542 - 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);
543 552 }
544 -
545 - if (is_user_logged_in() && $user->ID === get_current_user_id()) {
546 - update_user_meta($user->ID, 'first_name', $firstName);
547 - update_user_meta($user->ID, 'last_name', $lastName);
548 - }
549 553 }
550 554
551 555 public static function updateStock($order)
552 556 {
@@ -574,16 +578,18 @@
574 578 if ($current_user->ID) {
575 579 $billingAddress['email'] = $current_user->user_email;
576 580 $billingAddress['user_id'] = $current_user->ID;
577 581 } else {
578 - static::handleUserCreation($orderData, $billingAddress);
582 + unset($billingAddress['user_id']);
579 583 }
580 584
581 585 $customer = CustomerResource::create($billingAddress);
582 586 $customer = Arr::get($customer, 'data', null);
583 587 $customerId = Arr::get($customer, 'id', null);
584 - static::createCustomerAddress($billingAddress, $customerId);
585 - static::createCustomerAddress($shippingAddress, $customerId);
588 + if ($customer && $customer->wasRecentlyCreated) {
589 + static::createCustomerAddress($billingAddress, $customerId);
590 + static::createCustomerAddress($shippingAddress, $customerId);
591 + }
586 592
587 593 return $customer;
588 594 }
589 595
@@ -588,17 +594,13 @@
588 594 }
589 595
590 596 private static function updateExistingCustomer($customer, $orderData, $billingAddress, $shippingAddress)
591 597 {
592 - if (empty($customer->user_id)) {
593 - $currentLoggedInUser = wp_get_current_user();
594 - if ($currentLoggedInUser && $currentLoggedInUser->user_email === $customer->email) {
595 - $userId = get_current_user_id();
596 - $customer->update(['user_id' => $userId]);
597 - $billingAddress['user_id'] = $userId;
598 - }
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;
599 602 }
600 -
601 603 $customer->load(['billing_address', 'shipping_address']);
602 604
603 605 if ($customer->billing_address->count() < 1) {
604 606 static::createCustomerAddress($billingAddress, $customer->id);
@@ -605,25 +607,10 @@
605 607 }
606 608 if ($customer->shipping_address->count() < 1) {
607 609 static::createCustomerAddress($shippingAddress, $customer->id);
608 610 }
609 -
610 - static::handleUserCreation($orderData, $billingAddress, $customer);
611 611 }
612 612
613 - private static function handleUserCreation($orderData, &$billingAddress, $customer = null)
614 - {
615 - $userEmail = Arr::get($billingAddress, 'email');
616 - $user = get_user_by('email', $userEmail);
617 -
618 - if ($user) {
619 - $billingAddress['user_id'] = $user->ID;
620 - if ($customer) {
621 - $customer->update(['user_id' => $user->ID]);
622 - }
623 - }
624 - }
625 -
626 613 private static function getCustomerEmail($billingAddress)
627 614 {
628 615 return is_user_logged_in() ? wp_get_current_user()->user_email : $billingAddress['email'];
629 616 }
@@ -1003,9 +990,16 @@
1003 990
1004 991
1005 992 if ($cart->requireShipping()) {
1006 993 if (!empty($data['fc_selected_shipping_method'])) {
1007 - $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 +
1008 1002 $shippingCountry = Arr::get($data, 'billing_country', '');
1009 1003 $shippingState = Arr::get($data, 'billing_state', '');
1010 1004 $shipToDifferent = Arr::get($data, 'ship_to_different', 'no') === 'yes';
1011 1005
@@ -1021,9 +1015,9 @@
1021 1015 $errors['shipping_method']['unavailable'] = __('We don\'t ship to this address. Please select a different address.', 'fluent-cart');
1022 1016 } else {
1023 1017 $found = false;
1024 1018 foreach ($availableShippingMethods as $shippingMethod) {
1025 - if ($shippingMethod->id == $selectedMethod) {
1019 + if ((int) $shippingMethod->id === $selectedMethod) {
1026 1020 $found = true;
1027 1021 break;
1028 1022 }
1029 1023 }