diff --git a/includes/class-klarna-checkout-for-woocommerce-ajax.php b/includes/class-klarna-checkout-for-woocommerce-ajax.php index 56149032..d5f8dc25 100644 --- a/includes/class-klarna-checkout-for-woocommerce-ajax.php +++ b/includes/class-klarna-checkout-for-woocommerce-ajax.php @@ -287,7 +287,11 @@ public static function kco_wc_checkout_error() { } else { $klarna_order_id = KCO_WC()->api->get_order_id_from_session(); } - + // Check if we have items in cart. If not return redirect URL + if ( WC()->cart->is_empty() && ! is_customize_preview() && apply_filters( 'woocommerce_checkout_redirect_empty_cart', true ) ) { + wp_send_json_success( array( 'redirect' => wc_get_page_permalink( 'cart' ) ) ); + wp_die(); + } // Create order via fallback sequence $order = Klarna_Checkout_For_WooCommerce_Create_Local_Order_Fallback::create( $klarna_order_id, $error_message ); @@ -296,6 +300,7 @@ public static function kco_wc_checkout_error() { krokedil_log_events( null, 'Fallback order creation done. Redirecting customer to thank you page.', '' ); $note = sprintf( __( 'This order was made as a fallback due to an error in the checkout (%s). Please verify the order with Klarna.', 'klarna-checkout-for-woocommerce' ), $error_message ); $order->add_order_note( $note ); + $order->update_status( 'on-hold' ); $redirect_url = $order->get_checkout_order_received_url(); } else { KCO_WC()->logger->log( 'Fallback order creation ERROR. Redirecting customer to simplified thank you page.' . json_decode( $order ) ); @@ -318,7 +323,16 @@ public static function kco_wc_save_form_data() { } if ( ! empty( $_POST['form'] ) ) { $form = $_POST['form']; - set_transient( WC()->session->get( 'kco_wc_order_id' ), $form, 60 * 60 * 24 ); + if ( false === get_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ) ) ) { + set_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ), array( 'form' => $form ), 60 * 60 * 24 ); + } else { + $old_transient = get_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ) ); + $updated_transient = array( 'form' => $form ); + if ( isset( $old_transient['cart_hash'] ) ) { + $updated_transient['cart_hash'] = $old_transient['cart_hash']; + } + set_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ), $updated_transient, 60 * 60 * 24 ); + } } wp_send_json_success(); wp_die(); diff --git a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php index a6c76aeb..dc3b36e0 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php +++ b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php @@ -192,8 +192,13 @@ public function validation_cb() { $has_subscription = false; $needs_login = false; $email_exists = false; + $cart_hash_valid = true; - $form_data = get_transient( $data['order_id'] ); + $kco_transient = get_transient( 'kco_wc_order_id_' . $data['order_id'] ); + $form_data = false; + if ( isset( $kco_transient['form'] ) ) { + $form_data = $kco_transient['form']; + } $has_required_data = true; $failed_required_check = array(); if ( false !== $form_data ) { @@ -240,7 +245,7 @@ public function validation_cb() { } } // Validate any potential coupons. - if ( ! empty( $data['merchant_data'] ) ) { + if ( ! empty( json_decode( $data['merchant_data'] )->coupons ) ) { $coupons = json_decode( $data['merchant_data'] )->coupons; $emails[] = $data['billing_address']['email']; foreach ( $coupons as $coupon ) { @@ -282,10 +287,10 @@ public function validation_cb() { } } - if ( ! empty( $data['merchant_data'] ) ) { + if ( ! empty( json_decode( $data['merchant_data'] )->is_user_logged_in ) ) { $is_user_logged_in = json_decode( $data['merchant_data'] )->is_user_logged_in; } - // Check if any product is subscription product + // Check if any product is subscription product. if ( class_exists( 'WC_Subscriptions_Cart' ) && $has_subscription ) { $checkout = WC()->checkout(); if ( ! $checkout->is_registration_enabled() && ! $is_user_logged_in ) { @@ -297,8 +302,17 @@ public function validation_cb() { } } + // Check cart hash. + if ( ! empty( json_decode( $data['merchant_data'] )->cart_hash ) && ! empty( $kco_transient['cart_hash'] ) ) { + $sent_cart_hash = json_decode( $data['merchant_data'] )->cart_hash; + $saved_cart_hash = $kco_transient['cart_hash']; + if ( $sent_cart_hash !== $saved_cart_hash ) { + $cart_hash_valid = false; + } + } + do_action( 'kco_validate_checkout', $data, $all_in_stock, $shipping_chosen ); - if ( $all_in_stock && $shipping_chosen && $has_required_data && $coupon_valid && ! $needs_login && ! $email_exists ) { + if ( $all_in_stock && $shipping_chosen && $has_required_data && $coupon_valid && $cart_hash_valid && ! $needs_login && ! $email_exists ) { header( 'HTTP/1.0 200 OK' ); } else { header( 'HTTP/1.0 303 See Other' ); @@ -317,6 +331,8 @@ public function validation_cb() { header( 'Location: ' . wc_get_checkout_url() . '?needs_login' ); } elseif ( $email_exists ) { header( 'Location: ' . wc_get_checkout_url() . '?email_exists' ); + } elseif ( ! $cart_hash_valid ) { + header( 'Location: ' . wc_get_checkout_url() . '?invalid_cart_hash' ); } } } diff --git a/includes/class-klarna-checkout-for-woocommerce-api.php b/includes/class-klarna-checkout-for-woocommerce-api.php index 1e9249df..45f3d1ac 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api.php +++ b/includes/class-klarna-checkout-for-woocommerce-api.php @@ -17,13 +17,6 @@ class Klarna_Checkout_For_WooCommerce_API { */ private $settings = array(); - /** - * Merchant data JSON string. - * - * @var string - */ - public static $merchant_data = ''; - /** * Klarna_Checkout_For_WooCommerce_API constructor. */ @@ -54,7 +47,7 @@ public function request_pre_create_order() { if ( is_wp_error( $response ) ) { $error = $this->extract_error_messages( $response ); - KCO_WC()->logger->log( 'Create Klarna order ERROR (' . $error . ') ' . stripslashes_deep( json_encode( $response ) ) ); + KCO_WC()->logger->log( 'Create Klarna order ERROR (' . stripslashes_deep( json_encode( $error ) ) . ') ' . stripslashes_deep( json_encode( $response ) ) ); return $error; } @@ -96,7 +89,7 @@ public function request_pre_retrieve_order( $klarna_order_id ) { $response = wp_safe_remote_get( $request_url, $request_args ); - if ( $response['response']['code'] >= 200 && $response['response']['code'] <= 299 ) { + if ( ! is_wp_error( $response ) && ( $response['response']['code'] >= 200 && $response['response']['code'] <= 299 ) ) { $klarna_order = json_decode( $response['body'] ); $log_order = clone $klarna_order; $log_order->html_snippet = ''; @@ -136,7 +129,7 @@ public function request_pre_update_order() { $response = wp_safe_remote_post( $request_url, $request_args ); - if ( $response['response']['code'] >= 200 && $response['response']['code'] <= 299 ) { + if ( ! is_wp_error( $response ) && ( $response['response']['code'] >= 200 && $response['response']['code'] <= 299 ) ) { WC()->session->set( 'kco_wc_update_md5', md5( serialize( $request_args ) ) ); $klarna_order = json_decode( $response['body'] ); @@ -190,8 +183,8 @@ public function request_pre_get_order( $klarna_order_id ) { ); $response = wp_safe_remote_get( $request_url, $request_args ); - $log_order = $response['body']; - $log_order = (array) json_decode( $log_order ); + $log_order = $response['body']; + $log_order = (array) json_decode( $log_order ); $log_order['html_snippet'] = ''; krokedil_log_events( null, 'Pre Get Order response', stripslashes_deep( $log_order ) ); KCO_WC()->logger->log( 'Pre Get Order response (' . $request_url . ') ' . stripslashes_deep( json_encode( $log_order ) ) ); @@ -353,6 +346,9 @@ public function maybe_clear_session_values( $order ) { WC()->session->__unset( 'kco_wc_order_api' ); WC()->session->__unset( 'kco_wc_extra_fields_values' ); WC()->session->__unset( 'kco_wc_prefill_consent' ); + if ( $order ) { + delete_transient( 'kco_wc_order_id_' . $order->order_id ); + } } } @@ -487,6 +483,26 @@ public function get_merchant_urls() { return KCO_WC()->merchant_urls->get_urls(); } + /** + * Gets merchant data for Klarna purchase. + * + * @return array + */ + public function get_merchant_data() { + $merchant_data = array(); + + // Coupon info. + foreach ( WC()->cart->get_applied_coupons() as $coupon ) { + $merchant_data['coupons'][] = $coupon; + } + + // Cart hash. + $cart_hash = md5( wp_json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total ); + $merchant_data['cart_hash'] = $cart_hash; + + return json_encode( $merchant_data ); + } + /** * Gets Klarna API request headers. * @@ -533,7 +549,7 @@ public function get_request_body( $request_type = null ) { 'order_tax_amount' => KCO_WC()->order_lines->get_order_tax_amount(), 'order_lines' => KCO_WC()->order_lines->get_order_lines(), 'shipping_countries' => $this->get_shipping_countries(), - 'merchant_data' => self::$merchant_data, + 'merchant_data' => $this->get_merchant_data(), ); if ( kco_wc_prefill_allowed() ) { @@ -568,34 +584,35 @@ public function get_request_body( $request_type = null ) { // Allow external payment method plugin to do its thing. // @TODO: Extract this into a hooked function. - if ( 'create' === $request_type ) { - if ( in_array( $this->get_purchase_country(), array( 'SE', 'NO', 'FI' ), true ) ) { - if ( isset( $this->settings['allowed_customer_types'] ) ) { - $customer_types_setting = $this->settings['allowed_customer_types']; - - switch ( $customer_types_setting ) { - case 'B2B': - $allowed_customer_types = array( 'organization' ); - $customer_type = 'organization'; - break; - case 'B2BC': - $allowed_customer_types = array( 'person', 'organization' ); - $customer_type = 'organization'; - break; - case 'B2CB': - $allowed_customer_types = array( 'person', 'organization' ); - $customer_type = 'person'; - break; - default: - $allowed_customer_types = array( 'person' ); - $customer_type = 'person'; - } - - $request_args['options']['allowed_customer_types'] = $allowed_customer_types; - $request_args['customer']['type'] = $customer_type; + if ( in_array( $this->get_purchase_country(), array( 'SE', 'NO', 'FI' ), true ) ) { + if ( isset( $this->settings['allowed_customer_types'] ) ) { + $customer_types_setting = $this->settings['allowed_customer_types']; + + switch ( $customer_types_setting ) { + case 'B2B': + $allowed_customer_types = array( 'organization' ); + $customer_type = 'organization'; + break; + case 'B2BC': + $allowed_customer_types = array( 'person', 'organization' ); + $customer_type = 'organization'; + break; + case 'B2CB': + $allowed_customer_types = array( 'person', 'organization' ); + $customer_type = 'person'; + break; + default: + $allowed_customer_types = array( 'person' ); + $customer_type = 'person'; } - } + $request_args['options']['allowed_customer_types'] = $allowed_customer_types; + if ( 'create' === $request_type ) { + $request_args['customer']['type'] = $customer_type; + } + } + } + if ( 'create' === $request_type ) { $request_args = apply_filters( 'kco_wc_create_order', $request_args ); } @@ -669,31 +686,31 @@ private function get_iframe_colors() { $color_settings = array(); if ( $this->check_option_field( 'color_button' ) ) { - $color_settings['color_button'] = $this->check_option_field( 'color_button' ); + $color_settings['color_button'] = self::add_hash_to_color( $this->check_option_field( 'color_button' ) ); } if ( $this->check_option_field( 'color_button_text' ) ) { - $color_settings['color_button_text'] = $this->check_option_field( 'color_button_text' ); + $color_settings['color_button_text'] = self::add_hash_to_color( $this->check_option_field( 'color_button_text' ) ); } if ( $this->check_option_field( 'color_checkbox' ) ) { - $color_settings['color_checkbox'] = $this->check_option_field( 'color_checkbox' ); + $color_settings['color_checkbox'] = self::add_hash_to_color( $this->check_option_field( 'color_checkbox' ) ); } if ( $this->check_option_field( 'color_checkbox_checkmark' ) ) { - $color_settings['color_checkbox_checkmark'] = $this->check_option_field( 'color_checkbox_checkmark' ); + $color_settings['color_checkbox_checkmark'] = self::add_hash_to_color( $this->check_option_field( 'color_checkbox_checkmark' ) ); } if ( $this->check_option_field( 'color_header' ) ) { - $color_settings['color_header'] = $this->check_option_field( 'color_header' ); + $color_settings['color_header'] = self::add_hash_to_color( $this->check_option_field( 'color_header' ) ); } if ( $this->check_option_field( 'color_link' ) ) { - $color_settings['color_link'] = $this->check_option_field( 'color_link' ); + $color_settings['color_link'] = self::add_hash_to_color( $this->check_option_field( 'color_link' ) ); } if ( $this->check_option_field( 'radius_border' ) ) { - $color_settings['radius_border'] = $this->check_option_field( 'radius_border' ); + $color_settings['radius_border'] = self::add_hash_to_color( $this->check_option_field( 'radius_border' ) ); } if ( count( $color_settings ) > 0 ) { @@ -703,6 +720,14 @@ private function get_iframe_colors() { return false; } + private static function add_hash_to_color( $hex ) { + if ( '' != $hex ) { + $hex = str_replace( '#', '', $hex ); + $hex = '#' . $hex; + } + return $hex; + } + private function check_option_field( $field ) { if ( array_key_exists( $field, $this->settings ) && '' !== $this->settings[ $field ] ) { return $this->settings[ $field ]; @@ -751,10 +776,10 @@ public function request_create_recurring_order( $order, $recurring_token ) { 'user-agent' => $this->get_user_agent(), 'body' => $this->get_recurring_body( $order ), ); - + KCO_WC()->logger->log( 'Create recurring order request (' . $request_url . ') ' . stripslashes_deep( json_encode( $request_args ) ) ); krokedil_log_events( $order->get_id(), 'Create recurring order request', $request_args ); - $response = wp_safe_remote_post( $request_url, $request_args ); + $response = wp_safe_remote_post( $request_url, $request_args ); KCO_WC()->logger->log( 'Create recurring order response' . stripslashes_deep( json_encode( $response ) ) ); krokedil_log_events( $order->get_id(), 'Create recurring order response', $response ); diff --git a/includes/class-klarna-checkout-for-woocommerce-confirmation.php b/includes/class-klarna-checkout-for-woocommerce-confirmation.php index 3ae8e35e..20ae59a6 100644 --- a/includes/class-klarna-checkout-for-woocommerce-confirmation.php +++ b/includes/class-klarna-checkout-for-woocommerce-confirmation.php @@ -41,7 +41,7 @@ public function __construct() { add_filter( 'woocommerce_checkout_fields', array( $this, 'unrequire_fields' ), 99 ); add_filter( 'woocommerce_checkout_posted_data', array( $this, 'unrequire_posted_data' ), 99 ); add_action( 'woocommerce_checkout_after_order_review', array( $this, 'add_kco_order_id_field' ) ); - add_action( 'woocommerce_checkout_create_order', array( $this, 'save_kco_order_id_field' ), 10, 2 ); + add_action( 'woocommerce_checkout_order_processed', array( $this, 'save_kco_order_id_field' ), 10, 2 ); } /** @@ -78,7 +78,6 @@ public function maybe_populate_wc_checkout( $checkout ) { if ( ! $this->is_kco_confirmation() ) { return; } - echo '
'; $klarna_order_id = WC()->session->get( 'kco_wc_order_id' ); @@ -121,68 +120,76 @@ public function maybe_submit_wc_checkout() { } // _wc_klarna_order_id already exist in an order. Let's redirect the customer to the thankyou page for that order if ( $order_id_match ) { - krokedil_log_events( $order_id_match, 'Confirmation page rendered but _wc_klarna_order_id already exist in this order.' ); + krokedil_log_events( $order_id_match, 'Confirmation page rendered but _wc_klarna_order_id already exist in this order.', null ); $order = wc_get_order( $order_id_match ); $location = $order->get_checkout_order_received_url(); - wp_safe_redirect( $location, $status ); + wp_safe_redirect( $location ); exit; - } ?> get_id(), '_wc_klarna_order_id', sanitize_key( $kco_order_id ) ); - update_post_meta( $order->get_id(), '_transaction_id', sanitize_key( $kco_order_id ) ); + update_post_meta( $order_id, '_wc_klarna_order_id', sanitize_key( $kco_order_id ) ); + update_post_meta( $order_id, '_transaction_id', sanitize_key( $kco_order_id ) ); } } diff --git a/includes/class-klarna-checkout-for-woocommerce-create-local-order-fallback.php b/includes/class-klarna-checkout-for-woocommerce-create-local-order-fallback.php index ecda309a..e869227d 100644 --- a/includes/class-klarna-checkout-for-woocommerce-create-local-order-fallback.php +++ b/includes/class-klarna-checkout-for-woocommerce-create-local-order-fallback.php @@ -35,7 +35,7 @@ public static function get_instance() { * Klarna_Checkout_For_WooCommerce_Create_Local_Order_Fallback constructor. */ public function __construct() { - + } @@ -47,73 +47,76 @@ public function __construct() { * @throws Exception WC_Data_Exception. */ public static function create( $klarna_order_id ) { - $response = KCO_WC()->api->request_post_get_order( $klarna_order_id ); - $klarna_order = json_decode( $response['body'] ); - - // Create order - $order = wc_create_order(); - - try { - $order_id = $order->get_id(); - - $cart_hash = md5( json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total ); - - $order->set_created_via( 'checkout' ); - $order->set_cart_hash( $cart_hash ); - $order->set_customer_id( apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() ) ); - $order->set_currency( get_woocommerce_currency() ); - $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ); - $order->set_customer_ip_address( WC_Geolocation::get_ip_address() ); - $order->set_customer_user_agent( wc_get_user_agent() ); - $order->set_shipping_total( WC()->cart->shipping_total ); - $order->set_discount_total( WC()->cart->get_cart_discount_total() ); - $order->set_discount_tax( WC()->cart->get_cart_discount_tax_total() ); - $order->set_cart_tax( WC()->cart->tax_total ); - $order->set_shipping_tax( WC()->cart->shipping_tax_total ); - $order->set_total( WC()->cart->total ); + $response = KCO_WC()->api->request_post_get_order( $klarna_order_id ); + $klarna_order = json_decode( $response['body'] ); + + // Create order + $order = wc_create_order(); + + try { + $order_id = $order->get_id(); + + $cart_hash = md5( json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total ); + + $order->set_created_via( 'checkout' ); + $order->set_cart_hash( $cart_hash ); + $order->set_customer_id( apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() ) ); + $order->set_currency( get_woocommerce_currency() ); + $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) ); + $order->set_customer_ip_address( WC_Geolocation::get_ip_address() ); + $order->set_customer_user_agent( wc_get_user_agent() ); + $order->set_shipping_total( WC()->cart->shipping_total ); + $order->set_discount_total( WC()->cart->get_cart_discount_total() ); + $order->set_discount_tax( WC()->cart->get_cart_discount_tax_total() ); + $order->set_cart_tax( WC()->cart->tax_total ); + $order->set_shipping_tax( WC()->cart->shipping_tax_total ); + $order->set_total( WC()->cart->total ); update_post_meta( $order_id, '_created_via_klarna_fallback', 'yes' ); - - //Add payment method - self::add_order_payment_method( $order ); + update_post_meta( $order_id, '_wc_klarna_order_id', sanitize_key( $klarna_order_id ) ); + update_post_meta( $order_id, '_transaction_id', sanitize_key( $klarna_order_id ) ); + + // Add payment method + self::add_order_payment_method( $order ); - // Process customer data. - self::process_customer_data( $order, $klarna_order ); - - // Process customer data. - self::create_order_line_items( $order, WC()->cart ); + // Process customer data. + self::process_customer_data( $order, $klarna_order ); - //Add fees to order. - self::create_order_fee_lines( $order, WC()->cart ); + // Process customer data. + self::create_order_line_items( $order, WC()->cart ); + + // Add fees to order. + self::create_order_fee_lines( $order, WC()->cart ); // Add shipping self::create_order_shipping_lines( $order ); - + // Tax - self::create_order_tax_lines( $order, WC()->cart ); + self::create_order_tax_lines( $order, WC()->cart ); // Coupons - self::create_order_coupon_lines( $order, WC()->cart ); + self::create_order_coupon_lines( $order, WC()->cart ); - // Save the order. - $order->save(); + // Acknowledge order in Klarna. + self::acknowledge_order_in_klarna( $order, $klarna_order ); - return $order; + // Save the order. + $order->save(); - } catch ( Exception $e ) { - return new WP_Error( 'checkout-error', $e->getMessage() ); - } + return $order; + + } catch ( Exception $e ) { + return new WP_Error( 'checkout-error', $e->getMessage() ); + } + + } - - } - - /** + /** * Set payment method. * - * @param WC_Order $order WooCommerce order. - * + * @param WC_Order $order WooCommerce order. */ - public static function add_order_payment_method( $order ) { + public static function add_order_payment_method( $order ) { $available_gateways = WC()->payment_gateways->payment_gateways(); $payment_method = $available_gateways['kco']; $order->set_payment_method( $payment_method ); @@ -122,7 +125,7 @@ public static function add_order_payment_method( $order ) { /** * Processes customer data on fallback order creation. * - * @param WC_Order $order WooCommerce order. + * @param WC_Order $order WooCommerce order. * @param Klarna_Checkout_Order $klarna_order Klarna order. * * @throws Exception WC_Data_Exception. @@ -179,42 +182,47 @@ private static function process_customer_data( $order, $klarna_order ) { private static function create_order_line_items( &$order, $cart ) { // Remove items as to stop the item lines from being duplicated. - $order->remove_order_items(); + $order->remove_order_items(); - foreach ( $cart->get_cart() as $cart_item_key => $values ) { + foreach ( $cart->get_cart() as $cart_item_key => $values ) { $product = $values['data']; $item = new WC_Order_Item_Product(); $item->legacy_values = $values; // @deprecated For legacy actions. $item->legacy_cart_item_key = $cart_item_key; // @deprecated For legacy actions. - $item->set_props( array( - 'quantity' => $values['quantity'], - 'variation' => $values['variation'], - 'subtotal' => $values['line_subtotal'], - 'total' => $values['line_total'], - 'subtotal_tax' => $values['line_subtotal_tax'], - 'total_tax' => $values['line_tax'], - 'taxes' => $values['line_tax_data'], - ) ); + $item->set_props( + array( + 'quantity' => $values['quantity'], + 'variation' => $values['variation'], + 'subtotal' => $values['line_subtotal'], + 'total' => $values['line_total'], + 'subtotal_tax' => $values['line_subtotal_tax'], + 'total_tax' => $values['line_tax'], + 'taxes' => $values['line_tax_data'], + ) + ); if ( $product ) { - $item->set_props( array( - 'name' => $product->get_name(), - 'tax_class' => $product->get_tax_class(), - 'product_id' => $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(), - 'variation_id' => $product->is_type( 'variation' ) ? $product->get_id() : 0, - ) ); + $item->set_props( + array( + 'name' => $product->get_name(), + 'tax_class' => $product->get_tax_class(), + 'product_id' => $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id(), + 'variation_id' => $product->is_type( 'variation' ) ? $product->get_id() : 0, + ) + ); } $item->set_backorder_meta(); /** * Action hook to adjust item before save. + * * @since 3.0.0 */ do_action( 'woocommerce_checkout_create_order_line_item', $item, $cart_item_key, $values, $order ); // Add item to order and save. $order->add_item( $item ); } - } - - /** + } + + /** * Add fees to the order. * * @param WC_Order $order @@ -224,52 +232,55 @@ public static function create_order_fee_lines( &$order, $cart ) { $item = new WC_Order_Item_Fee(); $item->legacy_fee = $fee; // @deprecated For legacy actions. $item->legacy_fee_key = $fee_key; // @deprecated For legacy actions. - $item->set_props( array( - 'name' => $fee->name, - 'tax_class' => $fee->taxable ? $fee->tax_class : 0, - 'total' => $fee->amount, - 'total_tax' => $fee->tax, - 'taxes' => array( - 'total' => $fee->tax_data, - ), - ) ); + $item->set_props( + array( + 'name' => $fee->name, + 'tax_class' => $fee->taxable ? $fee->tax_class : 0, + 'total' => $fee->amount, + 'total_tax' => $fee->tax, + 'taxes' => array( + 'total' => $fee->tax_data, + ), + ) + ); /** * Action hook to adjust item before save. + * * @since 3.0.0 */ do_action( 'woocommerce_checkout_create_order_fee_item', $item, $fee_key, $fee, $order ); // Add item to order and save. $order->add_item( $item ); } - } - - /** + } + + /** * Add shipping lines to the order. * * @param WC_Order $order */ public static function create_order_shipping_lines( &$order ) { - if ( ! defined( 'WOOCOMMERCE_CART' ) ) { - define( 'WOOCOMMERCE_CART', true ); - } - $order_id = $order->get_id() ; - $this_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); - WC()->cart->calculate_shipping(); - // Store shipping for all packages. - foreach ( WC()->shipping->get_packages() as $package_key => $package ) { - if ( isset( $package['rates'][ $this_shipping_methods[ $package_key ] ] ) ) { - $item_id = $order->add_shipping( $package['rates'][ $this_shipping_methods[ $package_key ] ] ); - if ( ! $item_id ) { - KCO_WC()->logger->log( 'Error: Unable to add shipping item in Create Local Order Fallback.' ); - krokedil_log_events( null, 'Error: Unable to add shipping item in Create Local Order Fallback.', '' ); - } - // Allows plugins to add order item meta to shipping. - do_action( 'woocommerce_add_shipping_order_item', $order_id, $item_id, $package_key ); - } - } - } - + if ( ! defined( 'WOOCOMMERCE_CART' ) ) { + define( 'WOOCOMMERCE_CART', true ); + } + $order_id = $order->get_id(); + $this_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); + WC()->cart->calculate_shipping(); + // Store shipping for all packages. + foreach ( WC()->shipping->get_packages() as $package_key => $package ) { + if ( isset( $package['rates'][ $this_shipping_methods[ $package_key ] ] ) ) { + $item_id = $order->add_shipping( $package['rates'][ $this_shipping_methods[ $package_key ] ] ); + if ( ! $item_id ) { + KCO_WC()->logger->log( 'Error: Unable to add shipping item in Create Local Order Fallback.' ); + krokedil_log_events( null, 'Error: Unable to add shipping item in Create Local Order Fallback.', '' ); + } + // Allows plugins to add order item meta to shipping. + do_action( 'woocommerce_add_shipping_order_item', $order_id, $item_id, $package_key ); + } + } + } + /** * Add tax lines to the order. @@ -280,16 +291,19 @@ public static function create_order_tax_lines( &$order, $cart ) { foreach ( array_keys( $cart->taxes + $cart->shipping_taxes ) as $tax_rate_id ) { if ( $tax_rate_id && apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) !== $tax_rate_id ) { $item = new WC_Order_Item_Tax(); - $item->set_props( array( - 'rate_id' => $tax_rate_id, - 'tax_total' => $cart->get_tax_amount( $tax_rate_id ), - 'shipping_tax_total' => $cart->get_shipping_tax_amount( $tax_rate_id ), - 'rate_code' => WC_Tax::get_rate_code( $tax_rate_id ), - 'label' => WC_Tax::get_rate_label( $tax_rate_id ), - 'compound' => WC_Tax::is_compound( $tax_rate_id ), - ) ); + $item->set_props( + array( + 'rate_id' => $tax_rate_id, + 'tax_total' => $cart->get_tax_amount( $tax_rate_id ), + 'shipping_tax_total' => $cart->get_shipping_tax_amount( $tax_rate_id ), + 'rate_code' => WC_Tax::get_rate_code( $tax_rate_id ), + 'label' => WC_Tax::get_rate_label( $tax_rate_id ), + 'compound' => WC_Tax::is_compound( $tax_rate_id ), + ) + ); /** * Action hook to adjust item before save. + * * @since 3.0.0 */ do_action( 'woocommerce_checkout_create_order_tax_item', $item, $tax_rate_id, $order ); @@ -297,9 +311,9 @@ public static function create_order_tax_lines( &$order, $cart ) { $order->add_item( $item ); } } - } - - /** + } + + /** * Add coupon lines to the order. * * @param WC_Order $order @@ -307,13 +321,16 @@ public static function create_order_tax_lines( &$order, $cart ) { public static function create_order_coupon_lines( &$order, $cart ) { foreach ( $cart->get_coupons() as $code => $coupon ) { $item = new WC_Order_Item_Coupon(); - $item->set_props( array( - 'code' => $code, - 'discount' => $cart->get_coupon_discount_amount( $code ), - 'discount_tax' => $cart->get_coupon_discount_tax_amount( $code ), - ) ); + $item->set_props( + array( + 'code' => $code, + 'discount' => $cart->get_coupon_discount_amount( $code ), + 'discount_tax' => $cart->get_coupon_discount_tax_amount( $code ), + ) + ); /** * Action hook to adjust item before save. + * * @since 3.0.0 */ do_action( 'woocommerce_checkout_create_order_coupon_item', $item, $code, $coupon, $order ); @@ -322,6 +339,23 @@ public static function create_order_coupon_lines( &$order, $cart ) { } } + /** + * Set order number in Klarnas system. + * + * @param WC_Order $order WooCommerce order. + * @param Klarna_Checkout_Order $klarna_order Klarna order. + */ + public static function acknowledge_order_in_klarna( $order, $klarna_order ) { + KCO_WC()->api->request_post_acknowledge_order( $klarna_order->order_id ); + KCO_WC()->api->request_post_set_merchant_reference( + $klarna_order->order_id, + array( + 'merchant_reference1' => $order->get_order_number(), + 'merchant_reference2' => $order->get_id(), + ) + ); + } + } Klarna_Checkout_For_WooCommerce_Create_Local_Order_Fallback::get_instance(); diff --git a/includes/class-klarna-checkout-for-woocommerce-gateway.php b/includes/class-klarna-checkout-for-woocommerce-gateway.php index f609d002..a25b8abc 100644 --- a/includes/class-klarna-checkout-for-woocommerce-gateway.php +++ b/includes/class-klarna-checkout-for-woocommerce-gateway.php @@ -84,6 +84,8 @@ public function process_payment( $order_id ) { $order = wc_get_order( $order_id ); krokedil_set_order_gateway_version( $order_id, KCO_WC_VERSION ); + $this->process_payment_handler( $order_id ); + return array( 'result' => 'success', 'redirect' => $this->get_return_url( $order ), @@ -129,7 +131,7 @@ public function is_available() { // If we have a subscription product in cart and the customer isn't from SE, NO, FI, DE or AT, disable KCO. if ( is_checkout() && class_exists( 'WC_Subscriptions_Cart' ) && WC_Subscriptions_Cart::cart_contains_subscription() ) { $available_recurring_countries = array( 'SE', 'NO', 'FI', 'DE', 'AT' ); - if ( ! in_array(WC()->customer->get_billing_country(), $available_recurring_countries) ) { + if ( ! in_array( WC()->customer->get_billing_country(), $available_recurring_countries ) ) { return false; } } @@ -184,8 +186,11 @@ public function enqueue_scripts() { ); $form = array(); - if ( false !== get_transient( WC()->session->get( 'kco_wc_order_id' ) ) ) { - $form = get_transient( WC()->session->get( 'kco_wc_order_id' ) ); + if ( false !== get_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ) ) ) { + $kco_transient = get_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ) ); + if ( isset( $kco_transient['form'] ) ) { + $form = $kco_transient['form']; + } } $standard_woo_checkout_fields = array( 'billing_first_name', 'billing_last_name', 'billing_address_1', 'billing_address_2', 'billing_postcode', 'billing_city', 'billing_phone', 'billing_email', 'shipping_first_name', 'shipping_last_name', 'shipping_address_1', 'shipping_address_2', 'shipping_postcode', 'shipping_city', 'terms', 'account_username', 'account_password' ); @@ -235,7 +240,7 @@ public function admin_enqueue_scripts( $hook ) { return; } - $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; + $suffix = '';// defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; $store_base_location = wc_get_base_location(); if ( 'US' === $store_base_location['country'] ) { $location = 'US'; @@ -319,19 +324,15 @@ private function check_if_eu( $store_base_location ) { } /** - * Displays Klarna Checkout thank you iframe and clears Klarna order ID value from WC session. + * Process the payment with information from Klarna and return the result. * - * @param int $order_id WooCommerce order ID. + * @param int $order_id WooCommerce order ID. + * + * @return void */ - public function show_thank_you_snippet( $order_id = null ) { - if ( ! WC()->session->get( 'kco_wc_order_id' ) ) { - return; - } - + public function process_payment_handler( $order_id ) { $klarna_order = KCO_WC()->api->get_order(); - echo KCO_WC()->api->get_snippet( $klarna_order ); - - if ( $order_id ) { + if ( $order_id && $klarna_order ) { // Set WC order transaction ID. $order = wc_get_order( $order_id ); @@ -341,16 +342,16 @@ public function show_thank_you_snippet( $order_id = null ) { $environment = $this->testmode ? 'test' : 'live'; update_post_meta( $order_id, '_wc_klarna_environment', $environment ); - $klarna_country = WC()->checkout()->get_value( 'billing_country' ); + $klarna_country = wc_get_base_location()['country']; update_post_meta( $order_id, '_wc_klarna_country', $klarna_country ); $response = KCO_WC()->api->request_post_get_order( $klarna_order->order_id ); $klarna_post_order = json_decode( $response['body'] ); - // Remove html_snippet from what we're logging + // Remove html_snippet from what we're logging. $log_order = clone $klarna_post_order; $log_order->html_snippet = ''; - krokedil_log_events( $order_id, 'Klarna post_order in show_thank_you_snippet', $log_order ); + krokedil_log_events( $order_id, 'Klarna post_order in process_payment_handler', $log_order ); if ( 'ACCEPTED' === $klarna_post_order->fraud_status ) { $order->payment_complete(); // translators: Klarna order ID. @@ -374,6 +375,33 @@ public function show_thank_you_snippet( $order_id = null ) { } } + /** + * Displays Klarna Checkout thank you iframe and clears Klarna order ID value from WC session. + * + * @param int $order_id WooCommerce order ID. + */ + public function show_thank_you_snippet( $order_id = null ) { + if ( ! WC()->session->get( 'kco_wc_order_id' ) ) { + return; + } + + $klarna_order = KCO_WC()->api->get_order(); + echo KCO_WC()->api->get_snippet( $klarna_order ); + + // Clear session storage to prevent error. + echo ''; + + if ( $order_id ) { + $order = wc_get_order( $order_id ); + // Check if we need to finalize purchase here. Should already been done in process_payment. + if ( ! $order->has_status( array( 'on-hold', 'processing', 'completed' ) ) ) { + $this->process_payment_handler( $order_id ); + $order->add_order_note( __( 'Order finalized in thankyou page.', 'klarna-checkout-for-woocommerce' ) ); + WC()->cart->empty_cart(); + } + } + } + /** * Changes footer text in KCO settings page. * diff --git a/includes/class-klarna-checkout-for-woocommerce-order-lines.php b/includes/class-klarna-checkout-for-woocommerce-order-lines.php index 22ffe683..4ed0fb7e 100644 --- a/includes/class-klarna-checkout-for-woocommerce-order-lines.php +++ b/includes/class-klarna-checkout-for-woocommerce-order-lines.php @@ -122,11 +122,6 @@ public function process_cart() { $this->order_lines[] = $klarna_item; } } - foreach ( WC()->cart->get_applied_coupons() as $coupon ) { - $merchant_data = json_decode( Klarna_Checkout_For_WooCommerce_API::$merchant_data, true ); - $merchant_data['coupons'][] = $coupon; - Klarna_Checkout_For_WooCommerce_API::$merchant_data = json_encode( $merchant_data ); - } } /** diff --git a/includes/klarna-checkout-for-woocommerce-functions.php b/includes/klarna-checkout-for-woocommerce-functions.php index 57236218..8f17fb7c 100644 --- a/includes/klarna-checkout-for-woocommerce-functions.php +++ b/includes/klarna-checkout-for-woocommerce-functions.php @@ -477,5 +477,30 @@ function kco_wc_print_notices() { wc_add_notice( __( 'You must be logged in to checkout.', 'woocommerce' ), 'error' ); } elseif ( isset( $_GET['email_exists'] ) ) { wc_add_notice( __( 'An account is already registered with your email address. Please log in.', 'woocommerce' ), 'error' ); + } elseif ( isset( $_GET['invalid_cart_hash'] ) ) { + wc_add_notice( __( 'A mismatch in order totals between WooCommerce and Klarna was detected. Please try again.', 'klarna-checkout-for-woocommerce' ), 'error' ); + } +} + +/** + * Save cart hash to KCO transient. + */ +function kco_wc_save_cart_hash() { + if ( ! empty( WC()->session->get( 'kco_wc_order_id' ) ) ) { + WC()->cart->calculate_totals(); + $cart_hash = md5( wp_json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total ); + + if ( false === get_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ) ) ) { + // No transient exist, lets create a new one. + set_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ), array( 'cart_hash' => $cart_hash ), 60 * 60 * 24 ); + } else { + // A transient exist. Let's update only the cart_hash key. + $old_transient = get_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ) ); + $updated_transient = array( 'cart_hash' => $cart_hash ); + if ( isset( $old_transient['form'] ) ) { + $updated_transient['form'] = $old_transient['form']; + } + set_transient( 'kco_wc_order_id_' . WC()->session->get( 'kco_wc_order_id' ), $updated_transient, 60 * 60 * 24 ); + } } } diff --git a/klarna-checkout-for-woocommerce.php b/klarna-checkout-for-woocommerce.php index 7423e854..b022af11 100644 --- a/klarna-checkout-for-woocommerce.php +++ b/klarna-checkout-for-woocommerce.php @@ -5,12 +5,12 @@ * Description: Klarna Checkout payment gateway for WooCommerce. * Author: Krokedil * Author URI: https://krokedil.com/ - * Version: 1.7.3 + * Version: 1.7.4 * Text Domain: klarna-checkout-for-woocommerce * Domain Path: /languages * * WC requires at least: 3.0 - * WC tested up to: 3.4.7 + * WC tested up to: 3.5.1 * * Copyright (c) 2017-2018 Krokedil * @@ -35,7 +35,7 @@ /** * Required minimums and constants */ -define( 'KCO_WC_VERSION', '1.7.3' ); +define( 'KCO_WC_VERSION', '1.7.4' ); define( 'KCO_WC_MIN_PHP_VER', '5.3.0' ); define( 'KCO_WC_MIN_WC_VER', '3.0.0' ); define( 'KCO_WC_MAIN_FILE', __FILE__ ); @@ -146,6 +146,9 @@ protected function __construct() { add_action( 'admin_notices', array( $this, 'admin_notices' ), 15 ); add_action( 'plugins_loaded', array( $this, 'init' ) ); add_action( 'admin_notices', array( $this, 'order_management_check' ) ); + add_action( 'woocommerce_add_to_cart', 'kco_wc_save_cart_hash' ); + add_action( 'woocommerce_applied_coupon', 'kco_wc_save_cart_hash' ); + add_action( 'kco_wc_before_checkout_form', 'kco_wc_save_cart_hash', 1 ); // Add quantity button in woocommerce_order_review() function. add_filter( 'woocommerce_checkout_cart_item_quantity', array( $this, 'add_quantity_field' ), 10, 3 ); diff --git a/languages/klarna-checkout-for-woocommerce.pot b/languages/klarna-checkout-for-woocommerce.pot index 1b6b892a..c790fc70 100644 --- a/languages/klarna-checkout-for-woocommerce.pot +++ b/languages/klarna-checkout-for-woocommerce.pot @@ -16,45 +16,53 @@ msgstr "" "X-Poedit-SourceCharset: UTF-8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:79 +#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:81 msgid "You need to specify a terms page in WooCommerce Settings to be able to use Klarna Checkout." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:94 +#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:96 msgid "You need to enable and configure https to be able to use Klarna Checkout." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:110 +#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:112 msgid "You need to tick the checkbox When creating an account, automatically generate a username from the customer's email address when having the Allow customers to create an account during checkout setting activated. This can be changed in the Accounts & Privacy tab." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:116 +#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:118 msgid "You need to tick the checkbox When creating an account, automatically generate an account password when having the Allow customers to create an account during checkout setting activated. This can be changed in the Accounts & Privacy tab." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-ajax.php:303 +#: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:133 +msgid "It looks like you are using the Autoptimize plugin and have enabled their Optimize shop cart/checkout setting. This might cause conflicts with the Klarna Checkout plugin. You can deactivate this feature in the Autoptimize settings page (→ Show advanced settings → Misc section)." +msgstr "" + +#: ../includes/class-klarna-checkout-for-woocommerce-ajax.php:301 msgid "This order was made as a fallback due to an error in the checkout (%s). Please verify the order with Klarna." msgstr "" #. translators: Klarna order ID. #. translators: Klarna order ID. #. translators: Klarna order ID. -#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:97, ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:472, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:295 +#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:98, ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:510, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:359 msgid "Payment via Klarna Checkout, order ID: %s" msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:100, ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:494, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:355 +#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:101, ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:513, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:362 msgid "Klarna Checkout order was rejected." msgstr "" #. translators: Klarna order ID. #. translators: Klarna order ID. #. translators: Klarna order ID. -#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:103, ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:478, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:301 +#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:104, ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:516, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:365 msgid "Klarna order is under review, order ID: %s." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:510 +#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:505 +msgid "Order created via Klarna Checkout API callback. Please verify the order in Klarnas system." +msgstr "" + +#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:529 msgid "Order needs manual review, WooCommerce total and Klarna total do not match. Klarna order total: %s." msgstr "" @@ -330,11 +338,11 @@ msgstr "" msgid "Klarna Checkout replaces standard WooCommerce checkout page." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-gateway.php:397 +#: ../includes/class-klarna-checkout-for-woocommerce-gateway.php:404 msgid "Order address should not be changed and any changes you make will not be reflected in Klarna system." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-gateway.php:409 +#: ../includes/class-klarna-checkout-for-woocommerce-gateway.php:416 msgid "An account is already registered with your email address. Please log in." msgstr "" @@ -349,11 +357,11 @@ msgstr "" msgid "Shipping" msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-subscription.php:172 +#: ../includes/class-klarna-checkout-for-woocommerce-subscription.php:177 msgid "Subscription payment made with Klarna. Klarna order id: %s" msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-subscription.php:176 +#: ../includes/class-klarna-checkout-for-woocommerce-subscription.php:181 msgid "Subscription payment failed with Klarna. Error code: %1$s. Message: %2$s" msgstr "" @@ -389,18 +397,18 @@ msgstr "" msgid "Displays the number of orders created via the API callback feature during the last month." msgstr "" -#: ../klarna-checkout-for-woocommerce.php:170 +#: ../klarna-checkout-for-woocommerce.php:177 msgid "Settings" msgstr "" -#: ../klarna-checkout-for-woocommerce.php:171 +#: ../klarna-checkout-for-woocommerce.php:178 msgid "Support" msgstr "" -#: ../klarna-checkout-for-woocommerce.php:232 +#: ../klarna-checkout-for-woocommerce.php:239 msgid "Activate Now" msgstr "" -#: ../klarna-checkout-for-woocommerce.php:258 +#: ../klarna-checkout-for-woocommerce.php:265 msgid "Install Now" msgstr "" diff --git a/readme.txt b/readme.txt index d4aaa406..885a0a44 100644 --- a/readme.txt +++ b/readme.txt @@ -6,7 +6,7 @@ Requires at least: 4.0 Tested up to: 4.9.8 Requires PHP: 5.6 WC requires at least: 3.0.0 -WC tested up to: 3.4.7 +WC tested up to: 3.5.1 Stable tag: trunk License: GPLv3 or later License URI: http://www.gnu.org/licenses/gpl-3.0.html @@ -63,6 +63,19 @@ For help setting up and configuring Klarna Payments for WooCommerce please refer == Changelog == += 2018.11.12 - version 1.7.4 = +* Tweak - Improved handling of order in WooCommerce. Payment now finalized during process_payment. Plugin now allows custom thankyou page. +* Tweak - Add prefix kco_wc_order_id_ to transient name used during purchase. +* Tweak - Order creation caused by checkout_error now sets order status to On hold. +* Fix - Add support for cart_hash control to avoid mismatch in order totals between Klarna & Woo. +* Fix - Changed Klarna country stored in Woo order to prevent issue with Klarna Global. +* Fix - Deletes kco_wc_order_id_ transient on order received page. +* Fix - Added checks to prevent duplicate orders. +* Fix - Added check to ensure hash sign is added to hexcode sent to Klarna (for color display of KCO). +* Fix - Save Klarna order id in Woo order on woocommerce_checkout_order_processed (previously only saved on thankyou page). +* Fix - Improved error handling/display when request to Klarna returns in wp_error. +* Fix - PHP notice fixes. + = 2018.10.19 - version 1.7.3 = * Fix - Fixed issue with no_shipping error on free trial subscriptions. * Fix - json_decode fix to avoid crash when using more than 1 coupon code (props @johanholm). diff --git a/templates/klarna-checkout-order-received.php b/templates/klarna-checkout-order-received.php index 51c6de61..1cdb0559 100644 --- a/templates/klarna-checkout-order-received.php +++ b/templates/klarna-checkout-order-received.php @@ -12,4 +12,8 @@ } wc_empty_cart(); +// Clear session storage to prevent error for customer in the future. +?> + +session ) { if ( null === $order_id ) { if ( WC()->session->get( '_krokedil_events_session' ) ) { @@ -60,7 +60,7 @@ function krokedil_log_events( $order_id, $title, $data ) { $event = array( 'title' => $title, 'data' => $data, - 'timestamp' => current_time( 'Y-m-d H:i:s' ) + 'timestamp' => current_time( 'Y-m-d H:i:s' ), ); $events[] = $event; WC()->session->set( '_krokedil_events_session', $events ); @@ -74,7 +74,7 @@ function krokedil_log_events( $order_id, $title, $data ) { $event = array( 'title' => $title, 'data' => $data, - 'timestamp' => current_time( 'Y-m-d H:i:s' ) + 'timestamp' => current_time( 'Y-m-d H:i:s' ), ); $events[] = $event;