| @@ -16,8 +16,9 @@ | ||
| 16 | 16 | use FluentCart\App\Models\Product; |
| 17 | 17 | use FluentCart\App\Models\ProductVariation; |
| 18 | 18 | use FluentCart\App\Models\ShippingMethod; |
| 19 | 19 | use FluentCart\App\Modules\PaymentMethods\Core\GatewayManager; |
| 20 | +use FluentCart\App\Modules\Tax\TaxModule; | |
| 20 | 21 | use FluentCart\App\Services\Localization\LocalizationManager; |
| 21 | 22 | use FluentCart\App\Services\Renderer\AddressSelectRenderer; |
| 22 | 23 | use FluentCart\App\Services\Renderer\CartDrawerRenderer; |
| 23 | 24 | use FluentCart\App\Services\Renderer\CartRenderer; |
| @@ -60,8 +61,14 @@ | ||
| 60 | 61 | public function globalCheckoutRouteHandler() |
| 61 | 62 | { |
| 62 | 63 | nocache_headers(); |
| 63 | 64 | |
| 65 | + $nonce = isset($_SERVER['HTTP_X_WP_NONCE']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_X_WP_NONCE'])) : ''; | |
| 66 | + if (!wp_verify_nonce($nonce, 'fluentcart') && !wp_verify_nonce($nonce, 'wp_rest')) { | |
| 67 | + wp_send_json(['message' => __('Invalid nonce', 'fluent-cart')], 403); | |
| 68 | + return; | |
| 69 | + } | |
| 70 | + | |
| 64 | 71 | $startedAt = microtime(true); |
| 65 | 72 | |
| 66 | 73 | $action = App::request()->get('fc_checkout_action'); |
| 67 | 74 | $result = []; |
| @@ -253,8 +260,14 @@ | ||
| 253 | 260 | 'content' => $modalCheckoutRender->getFragment('summary_group'), |
| 254 | 261 | 'type' => 'replace' |
| 255 | 262 | ]; |
| 256 | 263 | |
| 264 | + $fragments[] = [ | |
| 265 | + 'selector' => '[data-fct-modal-checkout-summary]', | |
| 266 | + 'content' => $modalCheckoutRender->getFragment('checkout_summary'), | |
| 267 | + 'type' => 'replace' | |
| 268 | + ]; | |
| 269 | + | |
| 257 | 270 | return [ |
| 258 | 271 | 'fragments' => $fragments, |
| 259 | 272 | 'cart' => $cart, |
| 260 | 273 | 'total' => $cartTotal, |
| @@ -315,9 +328,15 @@ | ||
| 315 | 328 | 'content' => $modalCheckoutRender->getFragment('summary_group'), |
| 316 | 329 | 'type' => 'replace' |
| 317 | 330 | ]; |
| 318 | 331 | |
| 332 | + $fragments[] = [ | |
| 333 | + 'selector' => '[data-fct-modal-checkout-summary]', | |
| 334 | + 'content' => $modalCheckoutRender->getFragment('checkout_summary'), | |
| 335 | + 'type' => 'replace' | |
| 336 | + ]; | |
| 319 | 337 | |
| 338 | + | |
| 320 | 339 | return [ |
| 321 | 340 | 'fragments' => $fragments, |
| 322 | 341 | 'total' => $cartTotal, |
| 323 | 342 | 'formatted_total' => Helper::toDecimal($cartTotal), |
| @@ -390,8 +409,14 @@ | ||
| 390 | 409 | $totalPrice = apply_filters('fluent_cart/cart/estimated_total', $totalPrice, [ |
| 391 | 410 | 'cart' => $cart |
| 392 | 411 | ]); |
| 393 | 412 | |
| 413 | + // Prorate credit and upgrade discount (plan upgrade) are post-tax adjustments on | |
| 414 | + // the payable total. | |
| 415 | + $totalPrice = max(0, $totalPrice | |
| 416 | + - (int) Arr::get($cart->checkout_data, 'prorate_credit.amount', 0) | |
| 417 | + - (int) Arr::get($cart->checkout_data, 'upgrade_discount.amount', 0)); | |
| 418 | + | |
| 394 | 419 | $fragments = []; |
| 395 | 420 | |
| 396 | 421 | $cartRender = (new CheckoutRenderer($cart)); |
| 397 | 422 | $modalCheckoutRender = (new ModalCheckoutRenderer($cart)); |
| @@ -453,8 +478,9 @@ | ||
| 453 | 478 | |
| 454 | 479 | $oldTaxTotal = Arr::get($cart->checkout_data, 'tax_data.tax_total', 0); |
| 455 | 480 | $oldShippingCharge = Arr::get($cart->checkout_data, 'shipping_data.shipping_charge', 0); |
| 456 | 481 | |
| 482 | + $previousFormData = Arr::get($cart->checkout_data, 'form_data', []); | |
| 457 | 483 | $checkoutData = Arr::wrap($cart->checkout_data); |
| 458 | 484 | Arr::set($checkoutData, 'form_data.' . $type . '_address_id', $addressId); |
| 459 | 485 | Arr::set($checkoutData, 'form_data.' . $type . '_country', $country); |
| 460 | 486 | Arr::set($checkoutData, 'form_data.' . $type . '_state', $state); |
| @@ -464,8 +490,14 @@ | ||
| 464 | 490 | Arr::set($checkoutData, 'form_data.shipping_country', $country); |
| 465 | 491 | Arr::set($checkoutData, 'form_data.shipping_state', $state); |
| 466 | 492 | } |
| 467 | 493 | |
| 494 | + $checkoutData = (new TaxModule())->maybeInvalidateVatValidationForCountryChange($checkoutData, [ | |
| 495 | + 'ship_to_different' => Arr::get($previousFormData, 'ship_to_different', 'no'), | |
| 496 | + 'billing_country' => Arr::get($previousFormData, 'billing_country', ''), | |
| 497 | + 'shipping_country' => Arr::get($previousFormData, 'shipping_country', ''), | |
| 498 | + ]); | |
| 499 | + | |
| 468 | 500 | $cart->checkout_data = $checkoutData; |
| 469 | 501 | |
| 470 | 502 | $cart->save(); |
| 471 | 503 | |
| @@ -585,8 +617,10 @@ | ||
| 585 | 617 | ob_start(); |
| 586 | 618 | |
| 587 | 619 | $selectedId = Arr::get($cart->checkout_data, 'shipping_data.shipping_method_id', ''); |
| 588 | 620 | |
| 621 | + $selectedId = CartHelper::resolveAutoSelectShippingMethod($cart, $availableShippingMethods ?: [], $selectedId); | |
| 622 | + | |
| 589 | 623 | if (!$availableShippingMethods || is_wp_error($availableShippingMethods)) { |
| 590 | 624 | (new ShippingMethodsRender($availableShippingMethods, $selectedId))->render(); |
| 591 | 625 | } else { |
| 592 | 626 | foreach ($availableShippingMethods as $method) { |
| @@ -607,8 +641,9 @@ | ||
| 607 | 641 | 'type' => 'replace' |
| 608 | 642 | ] |
| 609 | 643 | ], |
| 610 | 644 | 'country_code' => $data['country_code'], |
| 645 | + 'shipping_method_id' => $selectedId ?: null, | |
| 611 | 646 | ]; |
| 612 | 647 | } |
| 613 | 648 | |
| 614 | 649 | public function handleCartStatusAjax() |
| @@ -726,10 +761,10 @@ | ||
| 726 | 761 | return new \WP_Error('no_cart', __('No active cart found', 'fluent-cart')); |
| 727 | 762 | } |
| 728 | 763 | |
| 729 | 764 | $allData = App::request()->all(); |
| 730 | - $dataKey = (string) Arr::get($allData, 'data_key'); | |
| 731 | - $dataValue = (string) Arr::get($allData, 'data_value'); | |
| 765 | + $dataKey = sanitize_text_field((string) Arr::get($allData, 'data_key')); | |
| 766 | + $dataValue = sanitize_text_field((string) Arr::get($allData, 'data_value')); | |
| 732 | 767 | |
| 733 | 768 | if ($dataKey) { |
| 734 | 769 | $allData[$dataKey] = $dataValue; |
| 735 | 770 | } |
| @@ -751,9 +786,11 @@ | ||
| 751 | 786 | 'order_notes' => 'form_data.order_notes', |
| 752 | 787 | 'shipping_method_id' => 'shipping_data.shipping_method_id', |
| 753 | 788 | '_fct_pay_method' => 'form_data._fct_pay_method', |
| 754 | 789 | 'billing_company_name' => 'form_data.billing_company_name', |
| 755 | - 'fct_billing_tax_id' => 'tax_data.vat_number' | |
| 790 | + 'billing_legal_registration_id' => 'form_data.billing_legal_registration_id', | |
| 791 | + 'is_business' => 'form_data.is_business', | |
| 792 | + 'fct_billing_tax_id' => 'tax_data.vat_number', | |
| 756 | 793 | ]; |
| 757 | 794 | |
| 758 | 795 | $addressFieldKeys = [ |
| 759 | 796 | 'full_name', |
| @@ -792,8 +829,16 @@ | ||
| 792 | 829 | $normalizeData[$key] = $value; |
| 793 | 830 | } |
| 794 | 831 | } |
| 795 | 832 | |
| 833 | + // Force-check the explicit data_key field — bulk POST may have already stored it as a side-effect. | |
| 834 | + if ($dataKey && isset($validKeys[$dataKey]) && !isset($normalizeData[$dataKey])) { | |
| 835 | + $storedValue = (string) Arr::get($prevCheckoutData, $validKeys[$dataKey], ''); | |
| 836 | + if ($storedValue !== $dataValue) { | |
| 837 | + $normalizeData[$dataKey] = $dataValue; | |
| 838 | + } | |
| 839 | + } | |
| 840 | + | |
| 796 | 841 | if (!$normalizeData) { |
| 797 | 842 | return [ |
| 798 | 843 | 'message' => __('No changes detected', 'fluent-cart') |
| 799 | 844 | ]; |
| @@ -809,8 +854,9 @@ | ||
| 809 | 854 | foreach ($normalizeData as $normalizeKey => $normalizeValue) { |
| 810 | 855 | Arr::set($checkoutData, $validKeys[$normalizeKey], $normalizeValue); |
| 811 | 856 | } |
| 812 | 857 | |
| 858 | + $oldTaxTotal = (int) Arr::get($cart->checkout_data, 'tax_data.tax_total', 0); | |
| 813 | 859 | $fillData = [ |
| 814 | 860 | 'checkout_data' => $checkoutData, |
| 815 | 861 | 'cart_data' => $cart->cart_data, |
| 816 | 862 | 'hook_changes' => [ |
| @@ -841,8 +887,10 @@ | ||
| 841 | 887 | $cart->last_name = implode(' ', $nameParts); |
| 842 | 888 | } |
| 843 | 889 | |
| 844 | 890 | $cart->fill($fillData); |
| 891 | + $newTaxTotal = (int) Arr::get($cart->checkout_data, 'tax_data.tax_total', 0); | |
| 892 | + $taxAmountChanged = $oldTaxTotal !== $newTaxTotal; | |
| 845 | 893 | $cart->clearFeeCache(); |
| 846 | 894 | |
| 847 | 895 | $cart = CartHelper::getCart(); |
| 848 | 896 | $sanitizedUtmData = UtmHelper::getUtmDataOfRequest(); |
| @@ -870,30 +918,36 @@ | ||
| 870 | 918 | 'content' => $cartRender->getFragment('cart_summary_fragment'), |
| 871 | 919 | 'type' => 'replace' |
| 872 | 920 | ]; |
| 873 | 921 | |
| 922 | + if ($taxAmountChanged || !empty($hookChanges['shipping'])) { | |
| 923 | + // also update the payment methods | |
| 924 | + if ($enableModalCheckout === 'yes') { | |
| 925 | + $fragments[] = [ | |
| 926 | + 'selector' => '[data-fluent-cart-checkout-payment-methods]', | |
| 927 | + 'content' => $modalCheckoutRender->getFragment('payment_methods'), | |
| 928 | + 'type' => 'replace' | |
| 929 | + ]; | |
| 930 | + } else { | |
| 931 | + $fragments[] = [ | |
| 932 | + 'selector' => '[data-fluent-cart-checkout-payment-methods]', | |
| 933 | + 'content' => $cartRender->getFragment('payment_methods'), | |
| 934 | + 'type' => 'replace' | |
| 935 | + ]; | |
| 936 | + } | |
| 874 | 937 | |
| 875 | - // also update the payment methods | |
| 876 | - if ($enableModalCheckout === 'yes') { | |
| 877 | 938 | $fragments[] = [ |
| 878 | - 'selector' => '[data-fluent-cart-checkout-payment-methods]', | |
| 879 | - 'content' => $modalCheckoutRender->getFragment('payment_methods'), | |
| 880 | - 'type' => 'replace' | |
| 939 | + 'selector' => '[data-fct-modal-checkout-summary-group]', | |
| 940 | + 'content' => $modalCheckoutRender->getFragment('summary_group'), | |
| 941 | + 'type' => 'replace' | |
| 881 | 942 | ]; |
| 882 | - } else { | |
| 943 | + | |
| 883 | 944 | $fragments[] = [ |
| 884 | - 'selector' => '[data-fluent-cart-checkout-payment-methods]', | |
| 885 | - 'content' => $cartRender->getFragment('payment_methods'), | |
| 886 | - 'type' => 'replace' | |
| 945 | + 'selector' => '[data-fct-modal-checkout-summary]', | |
| 946 | + 'content' => $modalCheckoutRender->getFragment('checkout_summary'), | |
| 947 | + 'type' => 'replace' | |
| 887 | 948 | ]; |
| 888 | 949 | } |
| 889 | - | |
| 890 | - | |
| 891 | - $fragments[] = [ | |
| 892 | - 'selector' => '[data-fct-modal-checkout-summary-group]', | |
| 893 | - 'content' => $modalCheckoutRender->getFragment('summary_group'), | |
| 894 | - 'type' => 'replace' | |
| 895 | - ]; | |
| 896 | 950 | } |
| 897 | 951 | |
| 898 | 952 | // Re-render cart summary on payment method change (fees may depend on payment method) |
| 899 | 953 | if (isset($normalizeData['_fct_pay_method'])) { |
| @@ -916,8 +970,14 @@ | ||
| 916 | 970 | 'selector' => '[data-fct-modal-checkout-summary-group]', |
| 917 | 971 | 'content' => $modalCheckoutRender->getFragment('summary_group'), |
| 918 | 972 | 'type' => 'replace' |
| 919 | 973 | ]; |
| 974 | + | |
| 975 | + $fragments[] = [ | |
| 976 | + 'selector' => '[data-fct-modal-checkout-summary]', | |
| 977 | + 'content' => $modalCheckoutRender->getFragment('checkout_summary'), | |
| 978 | + 'type' => 'replace' | |
| 979 | + ]; | |
| 920 | 980 | } |
| 921 | 981 | } |
| 922 | 982 | |
| 923 | 983 | if (($dataKey === 'billing_address_id' || $dataKey === 'shipping_address_id') && $dataValue !== '') { |
| @@ -968,218 +1028,8 @@ | ||
| 968 | 1028 | 'cart' => $cart |
| 969 | 1029 | ]; |
| 970 | 1030 | } |
| 971 | 1031 | |
| 972 | - public function handleSaveCustomerDataAjax() | |
| 973 | - { | |
| 974 | - | |
| 975 | - $key = sanitize_text_field(App::request()->get('data_key')); | |
| 976 | - $value = sanitize_text_field(App::request()->get('data_value')); | |
| 977 | - | |
| 978 | - $cart = CartHelper::getCart(); | |
| 979 | - if (!$cart) { | |
| 980 | - return new \WP_Error('no_cart', __('No active cart found', 'fluent-cart')); | |
| 981 | - } | |
| 982 | - | |
| 983 | - $addressFieldKeys = [ | |
| 984 | - 'full_name', | |
| 985 | - 'country', | |
| 986 | - 'address_1', | |
| 987 | - 'address_2', | |
| 988 | - 'state', | |
| 989 | - 'city', | |
| 990 | - 'postcode' | |
| 991 | - ]; | |
| 992 | - | |
| 993 | - $validKeys = [ | |
| 994 | - 'ship_to_different' => 'form_data.ship_to_different', | |
| 995 | - 'billing_email' => 'form_data.billing_email', | |
| 996 | - 'billing_address_id' => 'form_data.billing_address_id', | |
| 997 | - 'shipping_address_id' => 'form_data.shipping_address_id', | |
| 998 | - 'billing_company' => 'form_data.billing_company', | |
| 999 | - 'order_notes' => 'form_data.order_notes', | |
| 1000 | - 'shipping_method_id' => 'shipping_data.shipping_method_id', | |
| 1001 | - '_fct_pay_method' => 'form_data._fct_pay_method', | |
| 1002 | - ]; | |
| 1003 | - | |
| 1004 | - foreach ($addressFieldKeys as $addressFieldKey) { | |
| 1005 | - $validKeys['billing_' . $addressFieldKey] = 'form_data.billing_' . $addressFieldKey; | |
| 1006 | - $validKeys['shipping_' . $addressFieldKey] = 'form_data.shipping_' . $addressFieldKey; | |
| 1007 | - } | |
| 1008 | - | |
| 1009 | - if (!isset($validKeys[$key])) { | |
| 1010 | - return new \WP_Error('invalid_key', __('Invalid data key', 'fluent-cart')); | |
| 1011 | - } | |
| 1012 | - | |
| 1013 | - $checkoutData = Arr::wrap($cart->checkout_data); | |
| 1014 | - | |
| 1015 | - $prevValue = Arr::get($checkoutData, $validKeys[$key], ''); | |
| 1016 | - if ($prevValue === $value) { | |
| 1017 | - return [ | |
| 1018 | - 'message' => __('Updated', 'fluent-cart') | |
| 1019 | - ]; | |
| 1020 | - } | |
| 1021 | - | |
| 1022 | - $oldCheckoutData = $checkoutData; | |
| 1023 | - Arr::set($checkoutData, $validKeys[$key], $value); | |
| 1024 | - | |
| 1025 | - $fillData = apply_filters('fluent_cart/checkout/before_patch_checkout_data', [ | |
| 1026 | - 'checkout_data' => $checkoutData, | |
| 1027 | - 'cart_data' => $cart->cart_data, | |
| 1028 | - 'hook_changes' => [ | |
| 1029 | - 'shipping' => false, | |
| 1030 | - 'tax' => false | |
| 1031 | - ] | |
| 1032 | - ], [ | |
| 1033 | - 'cart' => $cart, | |
| 1034 | - 'key' => $key, | |
| 1035 | - 'value' => $value, | |
| 1036 | - 'prev_value' => $prevValue, | |
| 1037 | - 'old_checkout_data' => $oldCheckoutData | |
| 1038 | - ]); | |
| 1039 | - | |
| 1040 | - $changes = Arr::get($fillData, 'hook_changes', []); | |
| 1041 | - unset($fillData['hook_changes']); | |
| 1042 | - | |
| 1043 | - | |
| 1044 | - $cart->fill($fillData); | |
| 1045 | - $cart->save(); | |
| 1046 | - $fragments = []; | |
| 1047 | - | |
| 1048 | - | |
| 1049 | - if (Arr::get($changes, 'shipping', false)) { | |
| 1050 | - $fragments[] = [ | |
| 1051 | - 'selector' => '[data-fluent-cart-checkout-page-shipping-methods-wrapper]', | |
| 1052 | - 'content' => (new CheckoutRenderer($cart))->getFragment('shipping_methods'), | |
| 1053 | - 'type' => 'replace' | |
| 1054 | - ]; | |
| 1055 | - } | |
| 1056 | - //(new CartSummaryRender($cart))->render(false); | |
| 1057 | - | |
| 1058 | - ob_start(); | |
| 1059 | - (new CartSummaryRender($cart))->render(false); | |
| 1060 | - $render = ob_get_clean(); | |
| 1061 | - if (array_filter($changes)) { | |
| 1062 | - $fragments[] = [ | |
| 1063 | - 'selector' => '[data-fluent-cart-checkout-page-cart-items-wrapper]', | |
| 1064 | - //'content' => (new CheckoutRender($cart))->getFragment('cart_summary_fragment'), | |
| 1065 | - 'content' => $render, | |
| 1066 | - 'type' => 'replace' | |
| 1067 | - ]; | |
| 1068 | - } | |
| 1069 | - | |
| 1070 | - return [ | |
| 1071 | - 'fragments' => $fragments, | |
| 1072 | - 'message' => __('Data saved successfully', 'fluent-cart'), | |
| 1073 | - 'tax_total_Changes' => Arr::get($changes, 'tax', false), | |
| 1074 | - 'shipping_charge_changes' => Arr::get($changes, 'shipping', false), | |
| 1075 | - 'notify' => false, | |
| 1076 | - 'cart' => $cart | |
| 1077 | - ]; | |
| 1078 | - | |
| 1079 | - // Shipping Module | |
| 1080 | - | |
| 1081 | - add_action('fluent_cart/checkout/customer_data_saved', function ($data) { | |
| 1082 | - // Recalculate tax if needed | |
| 1083 | - | |
| 1084 | - do_action('fluent_cart/checkout/tax_data_changed', $data); | |
| 1085 | - | |
| 1086 | - }); | |
| 1087 | - | |
| 1088 | - do_action('fluent_cart/checkout/customer_data_saved', [ | |
| 1089 | - 'cart' => $cart, | |
| 1090 | - 'key' => $key, | |
| 1091 | - 'value' => $value, | |
| 1092 | - 'old_value' => $prevValue, | |
| 1093 | - 'old_data' => $oldCheckoutData | |
| 1094 | - ]); | |
| 1095 | - | |
| 1096 | - $didTaxChanges = did_action('fluent_cart/checkout/tax_data_changed'); | |
| 1097 | - $didShippingChanges = did_action('fluent_cart/checkout/shipping_data_changed'); | |
| 1098 | - | |
| 1099 | - | |
| 1100 | - if ($cart) { | |
| 1101 | - $checkoutRender = new CheckoutRenderer($cart); | |
| 1102 | - $shippingChanged = false; | |
| 1103 | - // we have to decide for which keys we will update shipping option | |
| 1104 | - $fragments = []; | |
| 1105 | - if ($cart->requireShipping()) { | |
| 1106 | - $watchingKeys = ['ship_to_different', 'billing_address', 'billing_country', 'billing_state']; | |
| 1107 | - if (Arr::get($cart->checkout_data, 'form_data.ship_to_different', null) === 'yes') { | |
| 1108 | - $watchingKeys = ['ship_to_different', 'shipping_address', 'shipping_country', 'shipping_state']; | |
| 1109 | - } | |
| 1110 | - | |
| 1111 | - if (in_array($key, $watchingKeys)) { | |
| 1112 | - $fragments[] = [ | |
| 1113 | - 'selector' => '[data-fluent-cart-checkout-page-shipping-methods-wrapper]', | |
| 1114 | - 'content' => $checkoutRender->getFragment('shipping_methods'), | |
| 1115 | - 'type' => 'replace' | |
| 1116 | - ]; | |
| 1117 | - } | |
| 1118 | - | |
| 1119 | - $shippingChanged = true; | |
| 1120 | - } | |
| 1121 | - | |
| 1122 | - $oldTaxTotal = Arr::get($cart->checkout_data, 'tax_data.tax_total', 0); | |
| 1123 | - $oldShippingCharge = Arr::get($cart->checkout_data, 'shipping_data.shipping_charge', 0); | |
| 1124 | - | |
| 1125 | - $countryCode = Arr::get($cart->checkout_data, 'form_data.shipping_country'); | |
| 1126 | - | |
| 1127 | - if (!$countryCode) { | |
| 1128 | - $countryCode = Arr::get($cart->checkout_data, 'form_data.billing_country'); | |
| 1129 | - } | |
| 1130 | - | |
| 1131 | - if (Arr::get($cart->checkout_data, 'form_data.ship_to_different', 'no') === 'no') { | |
| 1132 | - $countryCode = Arr::get($cart->checkout_data, 'form_data.billing_country'); | |
| 1133 | - } | |
| 1134 | - | |
| 1135 | - $data = [ | |
| 1136 | - 'country_code' => $countryCode, | |
| 1137 | - 'timezone' => '' | |
| 1138 | - ]; | |
| 1139 | - | |
| 1140 | - $list = $this->getShippingMethodsListView($data); | |
| 1141 | - | |
| 1142 | - if ($list === false) { | |
| 1143 | - $cart->checkout_data = array_merge($cart->checkout_data, [ | |
| 1144 | - 'shipping_data' => [ | |
| 1145 | - 'shipping_method_id' => null, | |
| 1146 | - 'shipping_charge' => 0 | |
| 1147 | - ] | |
| 1148 | - ]); | |
| 1149 | - $cart->save(); | |
| 1150 | - } | |
| 1151 | - | |
| 1152 | - do_action('fluent_cart/checkout/form_data_changed', [ | |
| 1153 | - 'cart' => $cart | |
| 1154 | - ]); | |
| 1155 | - | |
| 1156 | - $fragments[] = [ | |
| 1157 | - 'selector' => '[data-fluent-cart-checkout-page-cart-items-wrapper]', | |
| 1158 | - 'content' => $checkoutRender->getFragment('cart_summary_fragment'), | |
| 1159 | - 'type' => 'replace' | |
| 1160 | - ]; | |
| 1161 | - | |
| 1162 | - $newTaxTotal = Arr::get($cart->checkout_data, 'tax_data.tax_total', 0); | |
| 1163 | - $newShippingCharge = Arr::get($cart->checkout_data, 'shipping_data.shipping_charge', 0); | |
| 1164 | - | |
| 1165 | - $checkoutData = [ | |
| 1166 | - 'fragments' => $fragments, | |
| 1167 | - 'message' => __('Data saved successfully', 'fluent-cart'), | |
| 1168 | - 'tax_total_Changes' => $oldTaxTotal != $newTaxTotal, | |
| 1169 | - 'shipping_charge_changes' => $oldShippingCharge != $newShippingCharge, | |
| 1170 | - 'notify' => false | |
| 1171 | - ]; | |
| 1172 | - | |
| 1173 | - return apply_filters('fluent_cart/checkout/checkout_data_changed', $checkoutData, ['cart' => $cart]); | |
| 1174 | - } | |
| 1175 | - | |
| 1176 | - return [ | |
| 1177 | - 'message' => __('Failed to save data', 'fluent-cart'), | |
| 1178 | - 'notify' => false | |
| 1179 | - ]; | |
| 1180 | - } | |
| 1181 | - | |
| 1182 | 1032 | public function handleOrderBumpRequest() |
| 1183 | 1033 | { |
| 1184 | 1034 | $requestData = App::request()->all(); |
| 1185 | 1035 | |
| @@ -1188,9 +1038,9 @@ | ||
| 1188 | 1038 | return new \WP_Error('no_cart', __('No active cart found', 'fluent-cart')); |
| 1189 | 1039 | } |
| 1190 | 1040 | |
| 1191 | 1041 | $checkoutData = $cart->checkout_data; |
| 1192 | - if (!empty($checkoutData['upgrade_data']) || !empty($checkoutData['is_locked'])) { | |
| 1042 | + if (!$cart->acceptsAdditionalItems()) { | |
| 1193 | 1043 | return new \WP_Error('invalid_request', __('This cart is locked or already has an upgrade applied.', 'fluent-cart')); |
| 1194 | 1044 | } |
| 1195 | 1045 | |
| 1196 | 1046 | $upgradeFromVariationId = (int) Arr::get($requestData, 'upgrade_form', 0); |
| @@ -1205,8 +1055,14 @@ | ||
| 1205 | 1055 | 'request_data' => $requestData |
| 1206 | 1056 | ]); |
| 1207 | 1057 | } |
| 1208 | 1058 | |
| 1059 | + // A locked cart may still take bumps through the accepts_additional_items | |
| 1060 | + // filter, but must never let an item it pinned be swapped out. | |
| 1061 | + if (Arr::get($checkoutData, 'is_locked') === 'yes') { | |
| 1062 | + return new \WP_Error('invalid_request', __('This cart is locked and cannot be modified.', 'fluent-cart')); | |
| 1063 | + } | |
| 1064 | + | |
| 1209 | 1065 | if (!$upgradeFromVariationId || !$targetVariationId) { |
| 1210 | 1066 | return new \WP_Error('invalid_request', __('Invalid upgrade request.', 'fluent-cart')); |
| 1211 | 1067 | } |
| 1212 | 1068 | |
| @@ -1285,10 +1141,12 @@ | ||
| 1285 | 1141 | $sanitizedData[$dataKey] = ''; |
| 1286 | 1142 | } else { |
| 1287 | 1143 | $sanitizedData[$dataKey] = sanitize_email($dataValue ?? ''); |
| 1288 | 1144 | } |
| 1289 | - } else if (in_array($dataKey, ['billing_company_name', 'shipping_company_name'])) { | |
| 1145 | + } else if (in_array($dataKey, ['billing_company_name', 'shipping_company_name', 'billing_legal_registration_id'])) { | |
| 1290 | 1146 | $sanitizedData[$dataKey] = sanitize_text_field($dataValue); |
| 1147 | + } else if ($dataKey === 'is_business') { | |
| 1148 | + $sanitizedData[$dataKey] = $dataValue === 'yes' ? 'yes' : 'no'; | |
| 1291 | 1149 | } else if ($dataKey === 'billing_state' && !empty($dataValue)) { |
| 1292 | 1150 | $billingCountry = Arr::get($allData, 'billing_country'); |
| 1293 | 1151 | |
| 1294 | 1152 | $states = LocalizationManager::getInstance()->statesOptions($billingCountry); |