From e520c64de2761b330253452026e8e56ab3302b6c Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Mon, 10 Sep 2018 11:23:06 +0200 Subject: [PATCH 01/21] First commit of Subscription --- ...ss-klarna-checkout-for-woocommerce-api.php | 45 ++++- ...-checkout-for-woocommerce-confirmation.php | 49 ++--- ...larna-checkout-for-woocommerce-gateway.php | 111 +++++++++--- ...for-woocommerce-order-lines-from-order.php | 43 +++++ ...-checkout-for-woocommerce-subscription.php | 168 ++++++++++++++++++ klarna-checkout-for-woocommerce.php | 64 ++++--- 6 files changed, 407 insertions(+), 73 deletions(-) create mode 100644 includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php create mode 100644 includes/class-klarna-checkout-for-woocommerce-subscription.php diff --git a/includes/class-klarna-checkout-for-woocommerce-api.php b/includes/class-klarna-checkout-for-woocommerce-api.php index cf08e2c2..64dd22e3 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api.php +++ b/includes/class-klarna-checkout-for-woocommerce-api.php @@ -572,7 +572,6 @@ public function get_request_body( $request_type = null ) { } $request_body = wp_json_encode( apply_filters( 'kco_wc_api_request_args', $request_args ) ); - return $request_body; } @@ -710,4 +709,48 @@ private function extract_error_messages( $response ) { return $error; } + /** + * Create a recurring order with Klarna + * + * @param object $order The WooCommerce order. + * @param string $recurring_token The Recurring token from Klarna + * @return void + */ + public function request_create_recurring_order( $order, $recurring_token ) { + $request_url = $this->get_api_url_base() . '/customer-token/v1/tokens/' . $recurring_token . '/order'; + $request_args = array( + 'headers' => $this->get_request_headers(), + 'user-agent' => $this->get_user_agent(), + 'body' => $this->get_recurring_body( $order ), + ); + $response = wp_safe_remote_post( $request_url, $request_args ); + if ( 200 === $response['response']['code'] ) { + return true; + } else { + return false; + } + } + + public function get_recurring_body( $order ) { + $order_id = $order->get_id(); + + $order_lines = array(); + + foreach ( $order->get_items() as $item ) { + array_push( $order_lines, KCO_WC()->order_lines_from_order->get_order_line_items( $item ) ); + } + foreach ( $order->get_fees() as $fee ) { + array_push( $order_lines, KCO_WC()->order_lines_from_order->get_order_line_fees( $fee ) ); + } + array_push( $order_lines, KCO_WC()->order_lines_from_order->get_order_line_shipping( $order ) ); + + $body = array( + 'order_amount' => KCO_WC()->order_lines_from_order->get_order_amount( $order_id ), + 'order_lines' => $order_lines, + 'purchase_currency' => $order->get_currency(), + 'order_tax_amount' => KCO_WC()->order_lines_from_order->get_total_tax( $order_id ), + ); + + return json_encode( $body ); + } } diff --git a/includes/class-klarna-checkout-for-woocommerce-confirmation.php b/includes/class-klarna-checkout-for-woocommerce-confirmation.php index 6c39e357..ccb5eaf5 100644 --- a/includes/class-klarna-checkout-for-woocommerce-confirmation.php +++ b/includes/class-klarna-checkout-for-woocommerce-confirmation.php @@ -96,35 +96,37 @@ public function maybe_submit_wc_checkout() { return; } - // Prevent duplicate orders if confirmation page is reloaded manually by customer + // Prevent duplicate orders if confirmation page is reloaded manually by customer $klarna_order_id = sanitize_key( $_GET['kco_wc_order_id'] ); - $query = new WC_Order_Query( array( - 'limit' => -1, - 'orderby' => 'date', - 'order' => 'DESC', - 'return' => 'ids', - 'payment_method' => 'kco', - 'date_created' => '>' . ( time() - DAY_IN_SECONDS ) - ) ); - $orders = $query->get_orders(); - $order_id_match = null; - foreach( $orders as $order_id ) { - + $query = new WC_Order_Query( + array( + 'limit' => -1, + 'orderby' => 'date', + 'order' => 'DESC', + 'return' => 'ids', + 'payment_method' => 'kco', + 'date_created' => '>' . ( time() - DAY_IN_SECONDS ), + ) + ); + $orders = $query->get_orders(); + $order_id_match = null; + foreach ( $orders as $order_id ) { + $order_klarna_order_id = get_post_meta( $order_id, '_wc_klarna_order_id', true ); - - if( $order_klarna_order_id === $klarna_order_id ) { - $order_id_match = $order_id; - break; - } + + if ( $order_klarna_order_id === $klarna_order_id ) { + $order_id_match = $order_id; + break; + } } - // _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 ) { + // _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.' ); - $order = wc_get_order( $order_id_match ); + $order = wc_get_order( $order_id_match ); $location = $order->get_checkout_order_received_url(); wp_safe_redirect( $location, $status ); exit; - + } ?> @@ -143,7 +145,8 @@ public function maybe_submit_wc_checkout() { session->get( 'kco_wc_extra_fields_values', array() ); - foreach ( $extra_field_values as $field_name => $field_value ) { ?> + foreach ( $extra_field_values as $field_name => $field_value ) { + ?> var elementName = ""; var elementValue = ; diff --git a/includes/class-klarna-checkout-for-woocommerce-gateway.php b/includes/class-klarna-checkout-for-woocommerce-gateway.php index 58b7af1d..c30a267c 100644 --- a/includes/class-klarna-checkout-for-woocommerce-gateway.php +++ b/includes/class-klarna-checkout-for-woocommerce-gateway.php @@ -19,7 +19,20 @@ public function __construct() { $this->method_title = __( 'Klarna Checkout', 'klarna-checkout-for-woocommerce' ); $this->method_description = __( 'Klarna Checkout replaces standard WooCommerce checkout page.', 'klarna-checkout-for-woocommerce' ); $this->has_fields = false; - $this->supports = apply_filters( 'kco_wc_supports', array( 'products' ) ); + $this->supports = apply_filters( + 'kco_wc_supports', array( + 'products', + 'subscriptions', + 'subscription_cancellation', + 'subscription_suspension', + 'subscription_reactivation', + 'subscription_amount_changes', + 'subscription_date_changes', + 'subscription_payment_method_change', + 'subscription_payment_method_change_admin', + 'multiple_subscriptions', + ) + ); // Load the form fields. $this->init_form_fields(); @@ -34,10 +47,12 @@ public function __construct() { $this->testmode = 'yes' === $this->get_option( 'testmode' ); $this->logging = 'yes' === $this->get_option( 'logging' ); - add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( - $this, - 'process_admin_options', - ) ); + add_action( + 'woocommerce_update_options_payment_gateways_' . $this->id, array( + $this, + 'process_admin_options', + ) + ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'show_thank_you_snippet' ) ); @@ -55,8 +70,8 @@ public function __construct() { * @return string */ public function get_icon() { - $icon_src = 'https://cdn.klarna.com/1.0/shared/image/generic/logo/en_us/basic/logo_black.png?width=100'; - $icon_html = 'Klarna Checkout'; + $icon_src = 'https://cdn.klarna.com/1.0/shared/image/generic/logo/en_us/basic/logo_black.png?width=100'; + $icon_html = 'Klarna Checkout'; return apply_filters( 'wc_klarna_checkout_icon_html', $icon_html ); } @@ -81,9 +96,9 @@ public function process_payment( $order_id ) { * This plugin doesn't handle order management, but it allows Klarna Order Management plugin to process refunds * and then return true or false. * - * @param int $order_id WooCommerce order ID. + * @param int $order_id WooCommerce order ID. * @param null|int $amount Refund amount. - * @param string $reason Reason for refund. + * @param string $reason Reason for refund. * * @return bool */ @@ -167,8 +182,8 @@ public function enqueue_scripts() { $form = get_transient( WC()->session->get( 'kco_wc_order_id' ) ); } - $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'); - + $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' ); + $checkout_localize_params = array( 'update_cart_url' => WC_AJAX::get_endpoint( 'kco_wc_update_cart' ), 'update_cart_nonce' => wp_create_nonce( 'kco_wc_update_cart' ), @@ -188,7 +203,7 @@ public function enqueue_scripts() { 'save_form_data' => WC_AJAX::get_endpoint( 'kco_wc_save_form_data' ), 'save_form_data_nonce' => wp_create_nonce( 'kco_wc_save_form_data' ), 'form' => $form, - 'standard_woo_checkout_fields' => $standard_woo_checkout_fields, + 'standard_woo_checkout_fields' => $standard_woo_checkout_fields, ); wp_localize_script( 'kco', 'kco_params', $checkout_localize_params ); @@ -214,7 +229,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'; @@ -242,13 +257,55 @@ public function admin_enqueue_scripts( $hook ) { */ private function check_if_eu( $store_base_location ) { $eu_countries = array( - 'AL', 'AD', 'AM', 'AT', 'BY', 'BE', 'BA', 'BG', 'CH', 'CY', 'CZ', 'DE', - 'DK', 'EE', 'ES', 'FO', 'FI', 'FR', 'GB', 'GE', 'GI', 'GR', 'HU', 'HR', - 'IE', 'IS', 'IT', 'LT', 'LU', 'LV', 'MC', 'MK', 'MT', 'NO', 'NL', 'PL', - 'PT', 'RO', 'RU', 'SE', 'SI', 'SK', 'SM', 'TR', 'UA', 'VA', + 'AL', + 'AD', + 'AM', + 'AT', + 'BY', + 'BE', + 'BA', + 'BG', + 'CH', + 'CY', + 'CZ', + 'DE', + 'DK', + 'EE', + 'ES', + 'FO', + 'FI', + 'FR', + 'GB', + 'GE', + 'GI', + 'GR', + 'HU', + 'HR', + 'IE', + 'IS', + 'IT', + 'LT', + 'LU', + 'LV', + 'MC', + 'MK', + 'MT', + 'NO', + 'NL', + 'PL', + 'PT', + 'RO', + 'RU', + 'SE', + 'SI', + 'SK', + 'SM', + 'TR', + 'UA', + 'VA', ); - if( in_array( $store_base_location, $eu_countries ) ) { + if ( in_array( $store_base_location, $eu_countries ) ) { return 'EU'; } else { return ''; @@ -281,14 +338,14 @@ public function show_thank_you_snippet( $order_id = null ) { $klarna_country = WC()->checkout()->get_value( 'billing_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'] ); + $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 - $log_order = clone $klarna_post_order; + $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 ); - + if ( 'ACCEPTED' === $klarna_post_order->fraud_status ) { $order->payment_complete(); // translators: Klarna order ID. @@ -348,10 +405,12 @@ public function address_notice( $order ) { public function show_log_in_notice() { if ( isset( $_GET['login_required'] ) && 'yes' === $_GET['login_required'] ) { wc_add_notice( - sanitize_textarea_field( __( - 'An account is already registered with your email address. Please log in.', - 'klarna-checkout-for-woocommerce' - ) ), + sanitize_textarea_field( + __( + 'An account is already registered with your email address. Please log in.', + 'klarna-checkout-for-woocommerce' + ) + ), 'error' ); } diff --git a/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php b/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php new file mode 100644 index 00000000..3b70e26a --- /dev/null +++ b/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php @@ -0,0 +1,43 @@ +get_total() * 100 ); + } + + public function get_total_tax( $order_id ) { + $order = wc_get_order( $order_id ); + return intval( $order->get_total_tax( $order_id ) * 100 ); + } + + public function get_order_line_items( $order_item ) { + return array( + 'name' => $order_item->get_name(), + 'quantity' => $order_item->get_quantity(), + 'total_amount' => intval( $order_item->get_total() * 100 ), + 'unit_price' => intval( $order_item->get_total() / $order_item->get_quantity() * 100 ), + ); + } + + public function get_order_line_shipping( $order ) { + return array( + 'name' => $order->get_shipping_method(), + 'quantity' => 1, + 'total_amount' => intval( $order->get_shipping_total() * 100 ), + 'unit_price' => intval( $order->get_shipping_total() * 100 ), + ); + } + + public function get_order_line_fees( $order_fee ) { + return array( + 'name' => $order_fee->get_name(), + 'quantity' => $order_fee->get_quantity(), + 'total_amount' => intval( $order_fee->get_total() * 100 ), + 'unit_price' => intval( $order_fee->get_total() / $order_item->get_quantity() * 100 ), + ); + } +} diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php new file mode 100644 index 00000000..0b594637 --- /dev/null +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -0,0 +1,168 @@ +cart->cart_contents ) ) { + foreach ( WC()->cart->cart_contents as $cart_item ) { + if ( WC_Subscriptions_Product::is_subscription( $cart_item['product_id'] ) ) { + $subscription_product_id = $cart_item['product_id']; + return true; + } + } + } + } + return false; + } + + /** + * Creates the extra merchant data array needed for a subscription. + * + * @param array $request_args The Klarna request arguments. + * @return array + */ + public function create_extra_merchant_data( $request_args ) { + if ( class_exists( 'WC_Subscriptions_Cart' ) && WC_Subscriptions_Cart::cart_contains_subscription() ) { + $subscription_product_id = false; + if ( ! empty( WC()->cart->cart_contents ) ) { + foreach ( WC()->cart->cart_contents as $cart_item ) { + if ( WC_Subscriptions_Product::is_subscription( $cart_item['product_id'] ) ) { + $subscription_product_id = $cart_item['product_id']; + break; + } + } + } + + if ( $subscription_product_id ) { + $subscription_expiration_time = WC_Subscriptions_Product::get_expiration_date( $subscription_product_id ); + if ( 0 !== $subscription_expiration_time ) { + $end_time = date( 'Y-m-d\TH:i', strtotime( $subscription_expiration_time ) ); + } else { + $end_time = date( 'Y-m-d\TH:i', strtotime( '+50 year' ) ); + } + + $emd_subscription = array( + 'subscription_name' => 'Subscription: ' . get_the_title( $subscription_product_id ), + 'start_time' => date( 'Y-m-d\TH:i' ), + 'end_time' => $end_time, + 'auto_renewal_of_subscription' => false, + ); + + if ( is_user_logged_in() ) { + // User is logged in - add user_login as unique_account_identifier. + $current_user = wp_get_current_user(); + + $emd_account = array( + 'unique_account_identifier' => $current_user->user_login, + 'account_registration_date' => date( 'Y-m-d\TH:i', strtotime( $current_user->user_registered ) ), + 'account_last_modified' => date( 'Y-m-d\TH:i' ), + ); + } else { + // User is not logged in - send empty params. + $emd_account = array( + 'unique_account_identifier' => '', + ); + } + $emd = array( + 'Subscription' => array( $emd_subscription ), + 'customer_account_info' => array( $emd_account ), + ); + $request_args['attachment']['content_type'] = 'application/vnd.klarna.internal.emd-v2+json'; + $request_args['attachment']['body'] = json_encode( $emd ); + } + } + return $request_args; + } + + /** + * Marks the order as a recurring order for Klarna + * + * @param array $request_args The Klarna request arguments. + * @return array + */ + public function set_recurring( $request_args ) { + // Check if we have a subscription product. If yes set recurring field. + if ( $this->check_if_subscription() ) { + $request_args['recurring'] = true; + } + return $request_args; + } + + /** + * Sets the recurring token for the subscription order + * + * @return void + */ + public function set_recurring_token_for_order( $order_id = null ) { + $wc_order = wc_get_order( $order_id ); + if ( wcs_order_contains_subscription( $wc_order ) ) { + $klarna_api = new Klarna_Checkout_For_WooCommerce_API(); + $klarna_order = $klarna_api->get_order(); + if ( isset( $klarna_order->recurring_token ) ) { + $recurring_token = $klarna_order->recurring_token; + update_post_meta( $order_id, 'kco_recurring_token', $recurring_token ); + } + } + } + + /** + * Creates an order in Klarna from the recurring token saved. + * + * @param string $renewal_total The total price for the order. + * @param object $renewal_order The WooCommerce order for the renewal. + */ + public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { + $order_id = $renewal_order->get_id(); + + $subscriptions = wcs_get_subscriptions_for_renewal_order( $renewal_order->get_id() ); + reset( $subscriptions ); + $subscription_id = key( $subscriptions ); + + $recurring_token = get_post_meta( $order_id, 'kco_recurring_token', true ); + if ( empty( $recurring_token ) ) { + $recurring_token = get_post_meta( WC_Subscriptions_Renewal_Order::get_parent_order_id( $order_id ), 'kco_recurring_token', true ); + update_post_meta( $order_id, 'kco_recurring_token', $recurring_token ); + } + + $create_order_response = new Klarna_Checkout_For_WooCommerce_API(); + $create_order_response->request_create_recurring_order( $renewal_order, $recurring_token ); + + if ( true === $create_order_response ) { + WC_Subscriptions_Manager::process_subscription_payments_on_order( $renewal_order ); + $renewal_order->add_order_note( __( 'Subscription payment made with Klarna', 'klarna-checkout-for-woocommerce' ) ); + $renewal_order->payment_complete(); + } else { + WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $renewal_order ); + $renewal_order->add_order_note( __( 'Subscription payment failed to create with Klarna', 'klarna-checkout-for-woocommerce' ) ); + } + } +} +new Klarna_Checkout_Subscription(); diff --git a/klarna-checkout-for-woocommerce.php b/klarna-checkout-for-woocommerce.php index 92bcffb9..6e830008 100644 --- a/klarna-checkout-for-woocommerce.php +++ b/klarna-checkout-for-woocommerce.php @@ -91,6 +91,13 @@ class Klarna_Checkout_For_WooCommerce { */ public $logger; + /** + * Reference to order lines from order class. + * + * @var $log + */ + public $order_lines_from_order; + /** * Returns the *Singleton* instance of this class. * @@ -206,17 +213,21 @@ public function order_management_check() { // If plugin is not active show Activate button. if ( ! is_plugin_active( $plugin_slug . '/' . $plugin_slug . '.php' ) && current_user_can( 'activate_plugins' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; - $plugin = plugins_api( 'plugin_information', array( - 'slug' => $plugin_slug, - ) ); + $plugin = plugins_api( + 'plugin_information', array( + 'slug' => $plugin_slug, + ) + ); $plugin = (array) $plugin; $status = install_plugin_install_status( $plugin ); $name = wp_kses( $plugin['name'], array() ); - $url = add_query_arg( array( - '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ), - 'action' => 'activate', - 'plugin' => $status['file'], - ), network_admin_url( 'plugins.php' ) ); + $url = add_query_arg( + array( + '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ), + 'action' => 'activate', + 'plugin' => $status['file'], + ), network_admin_url( 'plugins.php' ) + ); $description = $name . ' is not active. Please activate it so you can capture, cancel, update and refund Klarna orders.'; ?>
@@ -233,9 +244,11 @@ public function order_management_check() { } else { // If plugin file does not exist, show Install button. if ( current_user_can( 'install_plugins' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; - $plugin = plugins_api( 'plugin_information', array( - 'slug' => $plugin_slug, - ) ); + $plugin = plugins_api( + 'plugin_information', array( + 'slug' => $plugin_slug, + ) + ); $plugin = (array) $plugin; $status = install_plugin_install_status( $plugin ); if ( 'install' === $status['status'] && $status['url'] ) { @@ -294,6 +307,8 @@ public function init_gateways() { include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-status.php'; include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-create-local-order-fallback.php'; include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-gdpr.php'; + include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-subscription.php'; + include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php'; include_once KCO_WC_PLUGIN_PATH . '/includes/klarna-checkout-for-woocommerce-functions.php'; include_once KCO_WC_PLUGIN_PATH . '/vendor/autoload.php'; @@ -302,11 +317,12 @@ public function init_gateways() { include_once KCO_WC_PLUGIN_PATH . '/includes/class-wc-klarna-banners.php'; } - $this->api = new Klarna_Checkout_For_WooCommerce_API(); - $this->merchant_urls = new Klarna_Checkout_For_WooCommerce_Merchant_URLs(); - $this->order_lines = new Klarna_Checkout_For_WooCommerce_Order_Lines(); - $this->credentials = new Klarna_Checkout_For_WooCommerce_Credentials(); - $this->logger = new Klarna_Checkout_For_WooCommerce_Logging(); + $this->api = new Klarna_Checkout_For_WooCommerce_API(); + $this->merchant_urls = new Klarna_Checkout_For_WooCommerce_Merchant_URLs(); + $this->order_lines = new Klarna_Checkout_For_WooCommerce_Order_Lines(); + $this->credentials = new Klarna_Checkout_For_WooCommerce_Credentials(); + $this->logger = new Klarna_Checkout_For_WooCommerce_Logging(); + $this->order_lines_from_order = new Klarna_Checkout_For_Woocommerce_Order_Lines_From_Order(); load_plugin_textdomain( 'klarna-checkout-for-woocommerce', false, plugin_basename( __DIR__ ) . '/languages' ); add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateways' ) ); @@ -330,7 +346,7 @@ public function add_gateways( $methods ) { * Filters cart item quantity output. * * @param string $output HTML output. - * @param array $cart_item Cart item. + * @param array $cart_item Cart item. * @param string $cart_item_key Cart item key. * * @return string $output @@ -344,12 +360,14 @@ public function add_quantity_field( $output, $cart_item, $cart_item_key ) { if ( $_product->is_sold_individually() ) { $return_value = sprintf( '1 ', $cart_key ); } else { - $return_value = woocommerce_quantity_input( array( - 'input_name' => 'cart[' . $cart_key . '][qty]', - 'input_value' => $cart_item['quantity'], - 'max_value' => $_product->backorders_allowed() ? '' : $_product->get_stock_quantity(), - 'min_value' => '1', - ), $_product, false ); + $return_value = woocommerce_quantity_input( + array( + 'input_name' => 'cart[' . $cart_key . '][qty]', + 'input_value' => $cart_item['quantity'], + 'max_value' => $_product->backorders_allowed() ? '' : $_product->get_stock_quantity(), + 'min_value' => '1', + ), $_product, false + ); } $output = $return_value; From ccc0e0a76c85abd3010d5e9387eb7a805972faa9 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Thu, 13 Sep 2018 10:04:17 +0200 Subject: [PATCH 02/21] Added taxes to order lines on recurring order --- ...ss-klarna-checkout-for-woocommerce-api.php | 1 - ...for-woocommerce-order-lines-from-order.php | 42 +++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-api.php b/includes/class-klarna-checkout-for-woocommerce-api.php index 64dd22e3..0a7e6d11 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api.php +++ b/includes/class-klarna-checkout-for-woocommerce-api.php @@ -750,7 +750,6 @@ public function get_recurring_body( $order ) { 'purchase_currency' => $order->get_currency(), 'order_tax_amount' => KCO_WC()->order_lines_from_order->get_total_tax( $order_id ), ); - return json_encode( $body ); } } diff --git a/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php b/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php index 3b70e26a..6d8a40d9 100644 --- a/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php +++ b/includes/class-klarna-checkout-for-woocommerce-order-lines-from-order.php @@ -15,29 +15,47 @@ public function get_total_tax( $order_id ) { } public function get_order_line_items( $order_item ) { + $order_id = $order_item->get_order_id(); + $order = wc_get_order( $order_id ); return array( - 'name' => $order_item->get_name(), - 'quantity' => $order_item->get_quantity(), - 'total_amount' => intval( $order_item->get_total() * 100 ), - 'unit_price' => intval( $order_item->get_total() / $order_item->get_quantity() * 100 ), + 'name' => $order_item->get_name(), + 'quantity' => $order_item->get_quantity(), + 'total_amount' => intval( ( $order_item->get_total() + $order_item->get_total_tax() ) * 100 ), + 'unit_price' => intval( ( $order_item->get_total() + $order_item->get_total_tax() ) / $order_item->get_quantity() * 100 ), + 'total_tax_amount' => intval( $order_item->get_total_tax() * 100 ), + 'tax_rate' => $this->get_order_line_tax_rate( $order ), ); } public function get_order_line_shipping( $order ) { return array( - 'name' => $order->get_shipping_method(), - 'quantity' => 1, - 'total_amount' => intval( $order->get_shipping_total() * 100 ), - 'unit_price' => intval( $order->get_shipping_total() * 100 ), + 'name' => $order->get_shipping_method(), + 'quantity' => 1, + 'total_amount' => intval( ( $order->get_shipping_total() + $order->get_shipping_tax() ) * 100 ), + 'unit_price' => intval( ( $order->get_shipping_total() + $order->get_shipping_tax() ) * 100 ), + 'total_tax_amount' => intval( $order->get_shipping_tax() * 100 ), + 'tax_rate' => $this->get_order_line_tax_rate( $order ), ); } public function get_order_line_fees( $order_fee ) { + $order_id = $order_fee->get_order_id(); + $order = wc_get_order( $order_id ); return array( - 'name' => $order_fee->get_name(), - 'quantity' => $order_fee->get_quantity(), - 'total_amount' => intval( $order_fee->get_total() * 100 ), - 'unit_price' => intval( $order_fee->get_total() / $order_item->get_quantity() * 100 ), + 'name' => $order_fee->get_name(), + 'quantity' => $order_fee->get_quantity(), + 'total_amount' => intval( ( $order_fee->get_total() + $order_fee->get_total_tax() ) * 100 ), + 'unit_price' => intval( ( $order_fee->get_total() + $order_fee->get_total_tax() ) / $order_item->get_quantity() * 100 ), + 'total_tax_amount' => intval( $order_fee->get_total_tax() * 100 ), + 'tax_rate' => $this->get_order_line_tax_rate( $order ), ); } + + public function get_order_line_tax_rate( $order ) { + $tax_items = $order->get_items( 'tax' ); + foreach ( $tax_items as $tax_item ) { + $rate_id = $tax_item->get_rate_id(); + return intval( WC_Tax::_get_tax_rate( $rate_id )['tax_rate'] * 100 ); + } + } } From ebf9c0e4212cf1d526258da869785f521aa21037 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Fri, 14 Sep 2018 08:53:10 +0200 Subject: [PATCH 03/21] Added error message on failed subscription. --- includes/class-klarna-checkout-for-woocommerce-api.php | 2 +- .../class-klarna-checkout-for-woocommerce-subscription.php | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-api.php b/includes/class-klarna-checkout-for-woocommerce-api.php index 0a7e6d11..c183ac76 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api.php +++ b/includes/class-klarna-checkout-for-woocommerce-api.php @@ -727,7 +727,7 @@ public function request_create_recurring_order( $order, $recurring_token ) { if ( 200 === $response['response']['code'] ) { return true; } else { - return false; + return $response['response']; } } diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index 0b594637..fbe32868 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -153,15 +153,14 @@ public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { } $create_order_response = new Klarna_Checkout_For_WooCommerce_API(); - $create_order_response->request_create_recurring_order( $renewal_order, $recurring_token ); - + $create_order_response = $create_order_response->request_create_recurring_order( $renewal_order, $recurring_token ); if ( true === $create_order_response ) { WC_Subscriptions_Manager::process_subscription_payments_on_order( $renewal_order ); $renewal_order->add_order_note( __( 'Subscription payment made with Klarna', 'klarna-checkout-for-woocommerce' ) ); $renewal_order->payment_complete(); } else { WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $renewal_order ); - $renewal_order->add_order_note( __( 'Subscription payment failed to create with Klarna', 'klarna-checkout-for-woocommerce' ) ); + $renewal_order->add_order_note( sprintf( __( 'Subscription payment failed with Klarna. Error code: %1$s. Message: %2$s', 'klarna-checkout-for-woocommerce' ), $create_order_response['code'], $create_order_response['message'] ) ); } } } From 3d087f7b1d5b0ed71a2469a235773ac256a4f8e0 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Mon, 17 Sep 2018 08:39:15 +0200 Subject: [PATCH 04/21] Added handling of customer that are not logged in --- ...checkout-for-woocommerce-api-callbacks.php | 63 ++++++++++++------- ...-checkout-for-woocommerce-subscription.php | 12 ++++ ...rna-checkout-for-woocommerce-functions.php | 2 + 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php index 08f8a9c9..4c8ad5c2 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php +++ b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php @@ -185,22 +185,22 @@ public function validation_cb() { $post_body = file_get_contents( 'php://input' ); $data = json_decode( $post_body, true ); krokedil_log_events( null, 'Klarna validation callback data', $data ); - $all_in_stock = true; - $shipping_chosen = false; - $coupon_valid = true; + $all_in_stock = true; + $shipping_chosen = false; + $coupon_valid = true; + $has_subscription = false; $form_data = get_transient( $data['order_id'] ); $has_required_data = true; $failed_required_check = array(); foreach ( $form_data as $form_row ) { if ( isset( $form_row['required'] ) && '' === $form_row['value'] ) { - $has_required_data = false; - wc_add_notice( 'test', 'error' ); + $has_required_data = false; $failed_required_check[] = $form_row['name']; } } - // Check stock for each item and shipping method. + // Check stock for each item and shipping method and if subscription. $cart_items = $data['order_lines']; foreach ( $cart_items as $cart_item ) { if ( 'physical' === $cart_item['type'] ) { @@ -219,6 +219,9 @@ public function validation_cb() { $needs_shipping = true; } } + if ( class_exists( 'WC_Subscriptions_Cart' ) ) { + $has_subscription = ( WC_Subscriptions_Product::is_subscription( $cart_item_product ) === true ) ? true : $has_subscription; + } } elseif ( 'shipping_fee' === $cart_item['type'] ) { $shipping_chosen = true; } @@ -264,23 +267,37 @@ public function validation_cb() { } } } - do_action( 'kco_validate_checkout', $data, $all_in_stock, $shipping_chosen ); - if ( $all_in_stock && $shipping_chosen && $has_required_data && $coupon_valid ) { - header( 'HTTP/1.0 200 OK' ); - } else { - header( 'HTTP/1.0 303 See Other' ); - if ( ! $all_in_stock ) { - $logger = new WC_Logger(); - $logger->add( 'klarna-checkout-for-woocommerce', 'Stock validation failed for SKU ' . $cart_item['reference'] ); - header( 'Location: ' . wc_get_cart_url() . '?stock_validate_failed' ); - } elseif ( ! $shipping_chosen && $needs_shipping ) { - header( 'Location: ' . wc_get_checkout_url() . '?no_shipping' ); - } elseif ( ! $has_required_data ) { - $validation_hash = base64_encode( json_encode( $failed_required_check ) ); - header( 'Location: ' . wc_get_checkout_url() . '?required_fields=' . $validation_hash ); - } elseif ( ! $coupon_valid ) { - header( 'Location: ' . wc_get_checkout_url() . '?invalid_coupon' ); - } + } + $needs_login = false; + if ( ! empty( $data['merchant_data'] ) ) { + $is_user_logged_in = json_decode( $data['merchant_data'] )->is_user_logged_in; + } + // 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 ) { + $needs_login = true; + } + } + + do_action( 'kco_validate_checkout', $data, $all_in_stock, $shipping_chosen ); + if ( $all_in_stock && $shipping_chosen && $has_required_data && $coupon_valid && ! $needs_login ) { + header( 'HTTP/1.0 200 OK' ); + } else { + header( 'HTTP/1.0 303 See Other' ); + if ( ! $all_in_stock ) { + $logger = new WC_Logger(); + $logger->add( 'klarna-checkout-for-woocommerce', 'Stock validation failed for SKU ' . $cart_item['reference'] ); + header( 'Location: ' . wc_get_cart_url() . '?stock_validate_failed' ); + } elseif ( ! $shipping_chosen && $needs_shipping ) { + header( 'Location: ' . wc_get_checkout_url() . '?no_shipping' ); + } elseif ( ! $has_required_data ) { + $validation_hash = base64_encode( json_encode( $failed_required_check ) ); + header( 'Location: ' . wc_get_checkout_url() . '?required_fields=' . $validation_hash ); + } elseif ( ! $coupon_valid ) { + header( 'Location: ' . wc_get_checkout_url() . '?invalid_coupon' ); + } elseif ( $needs_login ) { + header( 'Location: ' . wc_get_checkout_url() . '?needs_login' ); } } } diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index fbe32868..baf2378b 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -19,6 +19,7 @@ class Klarna_Checkout_Subscription { public function __construct() { // add_filter( 'kco_wc_api_request_args', array( $this, 'create_extra_merchant_data' ) ); add_filter( 'kco_wc_api_request_args', array( $this, 'set_recurring' ) ); + add_filter( 'kco_wc_api_request_args', array( $this, 'set_merchant_data' ) ); add_action( 'woocommerce_thankyou_kco', array( $this, 'set_recurring_token_for_order' ) ); add_action( 'woocommerce_scheduled_subscription_payment_kco', array( $this, 'trigger_scheduled_payment' ), 10, 2 ); } @@ -42,7 +43,17 @@ public function check_if_subscription() { } return false; } + public function set_merchant_data( $request_args ) { + if ( isset( $request_args['merchant_data'] ) ) { + $merchant_data = json_decode( $request_args['merchant_data'] ); + } else { + $merchant_data = array(); + } + $merchant_data['is_user_logged_in'] = is_user_logged_in(); + $request_args['merchant_data'] = json_encode( $merchant_data ); + return $request_args; + } /** * Creates the extra merchant data array needed for a subscription. * @@ -165,3 +176,4 @@ public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { } } new Klarna_Checkout_Subscription(); + diff --git a/includes/klarna-checkout-for-woocommerce-functions.php b/includes/klarna-checkout-for-woocommerce-functions.php index c8025e13..1c22749d 100644 --- a/includes/klarna-checkout-for-woocommerce-functions.php +++ b/includes/klarna-checkout-for-woocommerce-functions.php @@ -473,5 +473,7 @@ function kco_wc_print_notices() { wc_add_notice( __( sprintf( 'The following fields are required:%s.', $fields_string ), 'klarna-checkout-for-woocommerce' ), 'error' ); } elseif ( isset( $_GET['invalid_coupon'] ) ) { wc_add_notice( __( 'Invalid coupon.', 'klarna-checkout-for-woocommerce' ), 'error' ); + } elseif ( isset( $_GET['needs_login'] ) ) { + wc_add_notice( __( 'You must be logged in to checkout.', 'woocommerce' ), 'error' ); } } From 1a8e4daf54b3a0d187b712aa188ba5fca278ee10 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Fri, 21 Sep 2018 09:27:48 +0200 Subject: [PATCH 05/21] Added klarna order id as transaction id for recurring orders --- includes/class-klarna-checkout-for-woocommerce-api.php | 6 +----- ...class-klarna-checkout-for-woocommerce-subscription.php | 8 +++++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-api.php b/includes/class-klarna-checkout-for-woocommerce-api.php index c183ac76..ccfa1fdf 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api.php +++ b/includes/class-klarna-checkout-for-woocommerce-api.php @@ -724,11 +724,7 @@ public function request_create_recurring_order( $order, $recurring_token ) { 'body' => $this->get_recurring_body( $order ), ); $response = wp_safe_remote_post( $request_url, $request_args ); - if ( 200 === $response['response']['code'] ) { - return true; - } else { - return $response['response']; - } + return $response; } public function get_recurring_body( $order ) { diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index baf2378b..c7126b10 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -165,13 +165,15 @@ public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { $create_order_response = new Klarna_Checkout_For_WooCommerce_API(); $create_order_response = $create_order_response->request_create_recurring_order( $renewal_order, $recurring_token ); - if ( true === $create_order_response ) { + if ( 200 === $create_order_response['response']['code'] ) { + $klarna_order_id = json_decode( $create_order_response['body'] )->order_id; + $renewal_order->set_transaction_id( $klarna_order_id ); WC_Subscriptions_Manager::process_subscription_payments_on_order( $renewal_order ); - $renewal_order->add_order_note( __( 'Subscription payment made with Klarna', 'klarna-checkout-for-woocommerce' ) ); + $renewal_order->add_order_note( sprintf( __( 'Subscription payment made with Klarna. Klarna order id: %s', 'klarna-checkout-for-woocommerce' ), $klarna_order_id ) ); $renewal_order->payment_complete(); } else { WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $renewal_order ); - $renewal_order->add_order_note( sprintf( __( 'Subscription payment failed with Klarna. Error code: %1$s. Message: %2$s', 'klarna-checkout-for-woocommerce' ), $create_order_response['code'], $create_order_response['message'] ) ); + $renewal_order->add_order_note( sprintf( __( 'Subscription payment failed with Klarna. Error code: %1$s. Message: %2$s', 'klarna-checkout-for-woocommerce' ), $create_order_response['response']['code'], $create_order_response['response']['message'] ) ); } } } From 7f476582fe80a2409535d8a6591b637c48618f68 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Tue, 25 Sep 2018 09:29:52 +0200 Subject: [PATCH 06/21] Added support for Abanded cart --- assets/js/klarna-checkout-for-woocommerce.js | 3 +- .../js/klarna-checkout-for-woocommerce.min.js | 2 +- ...s-klarna-checkout-for-woocommerce-ajax.php | 16 ++++++-- ...ss-klarna-checkout-for-woocommerce-api.php | 24 +++++++++++- ...t-for-woocommerce-checkout-form-fields.php | 24 ++++++++++++ klarna-checkout-for-woocommerce.php | 1 + languages/klarna-checkout-for-woocommerce.pot | 38 ++++++++++--------- 7 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php diff --git a/assets/js/klarna-checkout-for-woocommerce.js b/assets/js/klarna-checkout-for-woocommerce.js index 09b5807c..632ea0e7 100644 --- a/assets/js/klarna-checkout-for-woocommerce.js +++ b/assets/js/klarna-checkout-for-woocommerce.js @@ -365,6 +365,7 @@ jQuery(function($) { success: function (response) { kco_wc.log(response); $('.woocommerce-checkout-review-order-table').replaceWith(response.data.html); + $('#billing_email').val(response.data.email); }, error: function (response) { kco_wc.log(response); @@ -400,5 +401,5 @@ jQuery(function($) { if (event.keyCode == 13) { event.preventDefault(); } - }); + }); }); diff --git a/assets/js/klarna-checkout-for-woocommerce.min.js b/assets/js/klarna-checkout-for-woocommerce.min.js index a32c4295..c991cca1 100644 --- a/assets/js/klarna-checkout-for-woocommerce.min.js +++ b/assets/js/klarna-checkout-for-woocommerce.min.js @@ -1 +1 @@ -jQuery(function(s){if("undefined"==typeof kco_params)return!1;var u={bodyEl:s("body"),checkoutFormSelector:"form.checkout",orderNotesValue:"",orderNotesSelector:"textarea#order_comments",orderNotesEl:s("textarea#order_comments"),extraFieldsValues:{},extraFieldsSelectorText:'div#kco-extra-fields input[type="text"], div#kco-extra-fields input[type="password"], div#kco-extra-fields textarea',extraFieldsSelectorNonText:'div#kco-extra-fields select, div#kco-extra-fields input[type="radio"], div#kco-extra-fields input[type="checkbox"], div#kco-extra-fields input.checkout-date-picker, input#terms input[type="checkbox"]',paymentMethodEl:s('input[name="payment_method"]'),paymentMethod:"",selectAnotherSelector:"#klarna-checkout-select-other",formFields:[],documentReady:function(){u.log(kco_params),u.setFormData(),0session->get( 'chosen_payment_method' ) ) { @@ -176,8 +176,8 @@ public static function kco_wc_update_klarna_order() { WC()->cart->calculate_fees(); WC()->cart->calculate_totals(); - if( ! WC()->cart->needs_payment() ) { - $return = array(); + if ( ! WC()->cart->needs_payment() ) { + $return = array(); $return['redirect_url'] = wc_get_checkout_url(); wp_send_json_error( $return ); wp_die(); @@ -250,13 +250,21 @@ public static function kco_wc_iframe_shipping_address_change() { WC()->cart->calculate_shipping(); WC()->cart->calculate_totals(); + // Mailchimp abandoned cart support + $email = Klarna_Checkout_For_Woocommerce_Checkout_Form_Fields::maybe_set_customer_email(); + KCO_WC()->api->request_pre_update_order(); ob_start(); woocommerce_order_review(); $html = ob_get_clean(); - wp_send_json_success( array( 'html' => $html ) ); + wp_send_json_success( + array( + 'html' => $html, + 'email' => $email, + ) + ); wp_die(); } diff --git a/includes/class-klarna-checkout-for-woocommerce-api.php b/includes/class-klarna-checkout-for-woocommerce-api.php index 07937641..dcb00bdd 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api.php +++ b/includes/class-klarna-checkout-for-woocommerce-api.php @@ -51,7 +51,7 @@ public function request_pre_create_order() { KCO_WC()->logger->log( 'Create Klarna order (' . $request_url . ') ' . stripslashes_deep( json_encode( $request_args ) ) ); krokedil_log_events( null, 'Pre Create Order request args', $log_array ); $response = wp_safe_remote_post( $request_url, $request_args ); - + 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 ) ) ); @@ -72,7 +72,7 @@ public function request_pre_create_order() { return $error; } else { $error = $this->extract_error_messages( $response ); - KCO_WC()->logger->log( 'Create Klarna order ERROR (' . stripslashes_deep( json_encode($error)) . ') ' . stripslashes_deep( json_encode( $response ) ) ); + KCO_WC()->logger->log( 'Create Klarna order ERROR (' . stripslashes_deep( json_encode( $error ) ) . ') ' . stripslashes_deep( json_encode( $response ) ) ); krokedil_log_events( null, 'Pre Create Order response', $error ); return $error; } @@ -175,6 +175,26 @@ public function request_post_get_order( $klarna_order_id ) { return $response; } + /** + * Acknowledges Klarna Checkout order. + * + * @param string $klarna_order_id Klarna order ID. + * + * @return WP_Error|array $response + */ + public function request_pre_get_order( $klarna_order_id ) { + $request_url = $this->get_api_url_base() . '/checkout/v3/orders/' . $klarna_order_id; + $request_args = array( + 'headers' => $this->get_request_headers(), + 'user-agent' => $this->get_user_agent(), + ); + $response = wp_safe_remote_get( $request_url, $request_args ); + krokedil_log_events( null, 'Pre Get Order response', stripslashes_deep( $response ) ); + KCO_WC()->logger->log( 'Pre Get Order response (' . $request_url . ') ' . stripslashes_deep( json_encode( $response ) ) ); + + return $response; + } + /** * Acknowledges Klarna Checkout order. * diff --git a/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php b/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php new file mode 100644 index 00000000..43372457 --- /dev/null +++ b/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php @@ -0,0 +1,24 @@ +'; + } + + public static function maybe_set_customer_email() { + $klarna_order = KCO_WC()->api->request_pre_get_order( WC()->session->get( 'kco_wc_order_id', true ) ); + $klarna_order = json_decode( $klarna_order['body'] ); + $email = $klarna_order->billing_address->email; + WC()->customer->set_billing_email( $email ); + + return $email; + } +} new Klarna_Checkout_For_Woocommerce_Checkout_Form_Fields(); diff --git a/klarna-checkout-for-woocommerce.php b/klarna-checkout-for-woocommerce.php index 083acd10..8c4bb43a 100644 --- a/klarna-checkout-for-woocommerce.php +++ b/klarna-checkout-for-woocommerce.php @@ -300,6 +300,7 @@ public function init_gateways() { include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-status.php'; include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-create-local-order-fallback.php'; include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-gdpr.php'; + include_once KCO_WC_PLUGIN_PATH . '/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php'; include_once KCO_WC_PLUGIN_PATH . '/includes/klarna-checkout-for-woocommerce-functions.php'; include_once KCO_WC_PLUGIN_PATH . '/vendor/autoload.php'; diff --git a/languages/klarna-checkout-for-woocommerce.pot b/languages/klarna-checkout-for-woocommerce.pot index 847bc432..f086a57e 100644 --- a/languages/klarna-checkout-for-woocommerce.pot +++ b/languages/klarna-checkout-for-woocommerce.pot @@ -16,22 +16,6 @@ msgstr "" "X-Poedit-SourceCharset: UTF-8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../klarna-checkout-for-woocommerce.php:170 -msgid "Settings" -msgstr "" - -#: ../klarna-checkout-for-woocommerce.php:171 -msgid "Support" -msgstr "" - -#: ../klarna-checkout-for-woocommerce.php:228 -msgid "Activate Now" -msgstr "" - -#: ../klarna-checkout-for-woocommerce.php:252 -msgid "Install Now" -msgstr "" - #: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:79 msgid "You need to specify a terms page in WooCommerce Settings to be able to use Klarna Checkout." msgstr "" @@ -48,10 +32,12 @@ msgstr "" 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:293 +#: ../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 msgid "Payment via Klarna Checkout, order ID: %s" @@ -61,6 +47,8 @@ msgstr "" 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 msgid "Klarna order is under review, order ID: %s." @@ -392,3 +380,19 @@ msgstr "" #: ../includes/klarna-checkout-for-woocommerce-status-report.php:22 msgid "Displays the number of orders created via the API callback feature during the last month." msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:170 +msgid "Settings" +msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:171 +msgid "Support" +msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:232 +msgid "Activate Now" +msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:258 +msgid "Install Now" +msgstr "" From e4d2ac8a1aa6122d38b60615f4f914822021c13d Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Tue, 25 Sep 2018 11:18:53 +0200 Subject: [PATCH 07/21] Removed setters for before WC 3.0.0 --- .../class-klarna-checkout-for-woocommerce-ajax.php | 12 +++--------- klarna-checkout-for-woocommerce.php | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-ajax.php b/includes/class-klarna-checkout-for-woocommerce-ajax.php index f0d38319..7cae608d 100644 --- a/includes/class-klarna-checkout-for-woocommerce-ajax.php +++ b/includes/class-klarna-checkout-for-woocommerce-ajax.php @@ -164,7 +164,7 @@ public static function kco_wc_change_payment_method() { * Updates Klarna order. */ public static function kco_wc_update_klarna_order() { - + wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true ); if ( 'kco' === WC()->session->get( 'chosen_payment_method' ) ) { @@ -176,8 +176,8 @@ public static function kco_wc_update_klarna_order() { WC()->cart->calculate_fees(); WC()->cart->calculate_totals(); - if( ! WC()->cart->needs_payment() ) { - $return = array(); + if ( ! WC()->cart->needs_payment() ) { + $return = array(); $return['redirect_url'] = wc_get_checkout_url(); wp_send_json_error( $return ); wp_die(); @@ -210,37 +210,31 @@ public static function kco_wc_iframe_shipping_address_change() { $customer_data = array(); if ( isset( $address['email'] ) ) { - $customer_data['email'] = $address['email']; $customer_data['billing_email'] = $address['email']; } if ( isset( $address['postal_code'] ) ) { - $customer_data['postcode'] = $address['postal_code']; $customer_data['billing_postcode'] = $address['postal_code']; $customer_data['shipping_postcode'] = $address['postal_code']; } if ( isset( $address['given_name'] ) ) { - $customer_data['first_name'] = $address['given_name']; $customer_data['billing_first_name'] = $address['given_name']; $customer_data['shipping_first_name'] = $address['given_name']; } if ( isset( $address['family_name'] ) ) { - $customer_data['last_name'] = $address['family_name']; $customer_data['billing_last_name'] = $address['family_name']; $customer_data['shipping_last_name'] = $address['family_name']; } if ( isset( $address['region'] ) ) { - $customer_data['state'] = $address['region']; $customer_data['billing_state'] = $address['region']; $customer_data['shipping_state'] = $address['region']; } if ( isset( $address['country'] ) && kco_wc_country_code_converter( $address['country'] ) ) { $country = kco_wc_country_code_converter( $address['country'] ); - $customer_data['country'] = $country; $customer_data['billing_country'] = $country; $customer_data['shipping_country'] = $country; } diff --git a/klarna-checkout-for-woocommerce.php b/klarna-checkout-for-woocommerce.php index 083acd10..0c1b4abb 100644 --- a/klarna-checkout-for-woocommerce.php +++ b/klarna-checkout-for-woocommerce.php @@ -37,7 +37,7 @@ */ define( 'KCO_WC_VERSION', '1.6.1' ); define( 'KCO_WC_MIN_PHP_VER', '5.3.0' ); -define( 'KCO_WC_MIN_WC_VER', '2.5.0' ); +define( 'KCO_WC_MIN_WC_VER', '3.0.0' ); define( 'KCO_WC_MAIN_FILE', __FILE__ ); define( 'KCO_WC_PLUGIN_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) ); define( 'KCO_WC_PLUGIN_URL', untrailingslashit( plugin_dir_url( __FILE__ ) ) ); From 67dbbeb7c3d4d9e62332145e0721dcb972235753 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Tue, 25 Sep 2018 11:20:16 +0200 Subject: [PATCH 08/21] Removed test code. --- .../class-klarna-checkout-for-woocommerce-api-callbacks.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php index 08f8a9c9..566cd46f 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php +++ b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php @@ -194,8 +194,7 @@ public function validation_cb() { $failed_required_check = array(); foreach ( $form_data as $form_row ) { if ( isset( $form_row['required'] ) && '' === $form_row['value'] ) { - $has_required_data = false; - wc_add_notice( 'test', 'error' ); + $has_required_data = false; $failed_required_check[] = $form_row['name']; } } From c40354ae898916d5fc0d8b0fab78eb7bf0f94528 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Tue, 25 Sep 2018 11:26:40 +0200 Subject: [PATCH 09/21] Removed error notice. Fixed #78 --- ...s-klarna-checkout-for-woocommerce-api-callbacks.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php index 566cd46f..7e7db5eb 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php +++ b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php @@ -192,10 +192,12 @@ public function validation_cb() { $form_data = get_transient( $data['order_id'] ); $has_required_data = true; $failed_required_check = array(); - foreach ( $form_data as $form_row ) { - if ( isset( $form_row['required'] ) && '' === $form_row['value'] ) { - $has_required_data = false; - $failed_required_check[] = $form_row['name']; + if ( false !== $form_data ) { + foreach ( $form_data as $form_row ) { + if ( isset( $form_row['required'] ) && '' === $form_row['value'] ) { + $has_required_data = false; + $failed_required_check[] = $form_row['name']; + } } } From 7e85c0a2baaba4b04cdcf4a5ced545866d2615ed Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Tue, 25 Sep 2018 13:54:14 +0200 Subject: [PATCH 10/21] Added states to checkout fields. Adresses issue #19 --- assets/js/klarna-checkout-for-woocommerce.js | 11 ++++++- .../js/klarna-checkout-for-woocommerce.min.js | 2 +- ...s-klarna-checkout-for-woocommerce-ajax.php | 10 +++--- ...t-for-woocommerce-checkout-form-fields.php | 33 ++++++++++++++++++- languages/klarna-checkout-for-woocommerce.pot | 2 +- 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/assets/js/klarna-checkout-for-woocommerce.js b/assets/js/klarna-checkout-for-woocommerce.js index 632ea0e7..5aab47ba 100644 --- a/assets/js/klarna-checkout-for-woocommerce.js +++ b/assets/js/klarna-checkout-for-woocommerce.js @@ -321,6 +321,15 @@ jQuery(function($) { }); }, + setFieldValues: function( data ) { + // Billing fields + $('#billing_email').val(data.email); + $('#billing_state').val(data.states.billing_state); + + // Shipping fields + $('#shipping_state').val(data.states.shipping_state); + }, + init: function () { $(document).ready(kco_wc.documentReady); @@ -365,7 +374,7 @@ jQuery(function($) { success: function (response) { kco_wc.log(response); $('.woocommerce-checkout-review-order-table').replaceWith(response.data.html); - $('#billing_email').val(response.data.email); + kco_wc.setFieldValues( response.data ); }, error: function (response) { kco_wc.log(response); diff --git a/assets/js/klarna-checkout-for-woocommerce.min.js b/assets/js/klarna-checkout-for-woocommerce.min.js index c991cca1..f745cbb6 100644 --- a/assets/js/klarna-checkout-for-woocommerce.min.js +++ b/assets/js/klarna-checkout-for-woocommerce.min.js @@ -1 +1 @@ -jQuery(function(s){if("undefined"==typeof kco_params)return!1;var u={bodyEl:s("body"),checkoutFormSelector:"form.checkout",orderNotesValue:"",orderNotesSelector:"textarea#order_comments",orderNotesEl:s("textarea#order_comments"),extraFieldsValues:{},extraFieldsSelectorText:'div#kco-extra-fields input[type="text"], div#kco-extra-fields input[type="password"], div#kco-extra-fields textarea',extraFieldsSelectorNonText:'div#kco-extra-fields select, div#kco-extra-fields input[type="radio"], div#kco-extra-fields input[type="checkbox"], div#kco-extra-fields input.checkout-date-picker, input#terms input[type="checkbox"]',paymentMethodEl:s('input[name="payment_method"]'),paymentMethod:"",selectAnotherSelector:"#klarna-checkout-select-other",formFields:[],documentReady:function(){u.log(kco_params),u.setFormData(),0cart->calculate_shipping(); WC()->cart->calculate_totals(); - // Mailchimp abandoned cart support - $email = Klarna_Checkout_For_Woocommerce_Checkout_Form_Fields::maybe_set_customer_email(); + // Send customer data to frontend + $email = Klarna_Checkout_For_Woocommerce_Checkout_Form_Fields::maybe_set_customer_email(); + $states = Klarna_Checkout_For_Woocommerce_Checkout_Form_Fields::maybe_set_customer_state(); KCO_WC()->api->request_pre_update_order(); @@ -261,8 +262,9 @@ public static function kco_wc_iframe_shipping_address_change() { wp_send_json_success( array( - 'html' => $html, - 'email' => $email, + 'html' => $html, + 'email' => $email, + 'states' => $states, ) ); wp_die(); diff --git a/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php b/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php index 43372457..b4ad3b58 100644 --- a/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php +++ b/includes/class-klarna-checkout-for-woocommerce-checkout-form-fields.php @@ -5,20 +5,51 @@ class Klarna_Checkout_For_Woocommerce_Checkout_Form_Fields { + public static $klarna_order; + public function __construct() { add_action( 'kco_wc_after_snippet', array( $this, 'add_email_field_to_form' ) ); + add_action( 'kco_wc_after_snippet', array( $this, 'add_state_fields_to_form' ) ); } public function add_email_field_to_form() { echo ''; } + public function add_state_fields_to_form() { + echo ''; + echo ''; + } + + public static function maybe_set_klarna_order() { + if ( empty( self::$klarna_order ) ) { + self::$klarna_order = KCO_WC()->api->request_pre_get_order( WC()->session->get( 'kco_wc_order_id', true ) ); + } + return self::$klarna_order; + } public static function maybe_set_customer_email() { - $klarna_order = KCO_WC()->api->request_pre_get_order( WC()->session->get( 'kco_wc_order_id', true ) ); + $klarna_order = self::maybe_set_klarna_order(); $klarna_order = json_decode( $klarna_order['body'] ); $email = $klarna_order->billing_address->email; WC()->customer->set_billing_email( $email ); return $email; } + + public static function maybe_set_customer_state() { + $billing_state = ''; + $shipping_state = ''; + if ( 'US' === WC()->customer->get_billing_country() ) { + $klarna_order = self::maybe_set_klarna_order(); + $klarna_order = json_decode( $klarna_order['body'] ); + $billing_state = $klarna_order->billing_address->region; + $shipping_state = $klarna_order->shipping_address->region; + WC()->customer->set_billing_state( $billing_state ); + WC()->customer->set_shipping_state( $shipping_state ); + } + return array( + 'billing_state' => $billing_state, + 'shipping_state' => $shipping_state, + ); + } } new Klarna_Checkout_For_Woocommerce_Checkout_Form_Fields(); diff --git a/languages/klarna-checkout-for-woocommerce.pot b/languages/klarna-checkout-for-woocommerce.pot index f086a57e..a89c25ce 100644 --- a/languages/klarna-checkout-for-woocommerce.pot +++ b/languages/klarna-checkout-for-woocommerce.pot @@ -32,7 +32,7 @@ msgstr "" 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:301 +#: ../includes/class-klarna-checkout-for-woocommerce-ajax.php:303 msgid "This order was made as a fallback due to an error in the checkout (%s). Please verify the order with Klarna." msgstr "" From 3be399dd9c0e3839056cae31996c069715f3341e Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Wed, 26 Sep 2018 08:38:11 +0200 Subject: [PATCH 11/21] Changed how _transaction_id is added. --- ...-checkout-for-woocommerce-subscription.php | 3 +- languages/klarna-checkout-for-woocommerce.pot | 58 +++++++++++-------- 2 files changed, 36 insertions(+), 25 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index c7126b10..44e91cff 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -167,10 +167,9 @@ public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { $create_order_response = $create_order_response->request_create_recurring_order( $renewal_order, $recurring_token ); if ( 200 === $create_order_response['response']['code'] ) { $klarna_order_id = json_decode( $create_order_response['body'] )->order_id; - $renewal_order->set_transaction_id( $klarna_order_id ); WC_Subscriptions_Manager::process_subscription_payments_on_order( $renewal_order ); $renewal_order->add_order_note( sprintf( __( 'Subscription payment made with Klarna. Klarna order id: %s', 'klarna-checkout-for-woocommerce' ), $klarna_order_id ) ); - $renewal_order->payment_complete(); + $renewal_order->payment_complete( $klarna_order_id ); } else { WC_Subscriptions_Manager::process_subscription_payment_failure_on_order( $renewal_order ); $renewal_order->add_order_note( sprintf( __( 'Subscription payment failed with Klarna. Error code: %1$s. Message: %2$s', 'klarna-checkout-for-woocommerce' ), $create_order_response['response']['code'], $create_order_response['response']['message'] ) ); diff --git a/languages/klarna-checkout-for-woocommerce.pot b/languages/klarna-checkout-for-woocommerce.pot index 847bc432..aee102e6 100644 --- a/languages/klarna-checkout-for-woocommerce.pot +++ b/languages/klarna-checkout-for-woocommerce.pot @@ -16,22 +16,6 @@ msgstr "" "X-Poedit-SourceCharset: UTF-8\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: ../klarna-checkout-for-woocommerce.php:170 -msgid "Settings" -msgstr "" - -#: ../klarna-checkout-for-woocommerce.php:171 -msgid "Support" -msgstr "" - -#: ../klarna-checkout-for-woocommerce.php:228 -msgid "Activate Now" -msgstr "" - -#: ../klarna-checkout-for-woocommerce.php:252 -msgid "Install Now" -msgstr "" - #: ../includes/class-klarna-checkout-for-woocommerce-admin-notices.php:79 msgid "You need to specify a terms page in WooCommerce Settings to be able to use Klarna Checkout." msgstr "" @@ -48,25 +32,29 @@ msgstr "" 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:293 +#: ../includes/class-klarna-checkout-for-woocommerce-ajax.php:287 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. -#: ../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 +#. 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:491, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:352 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:475, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:298 +#: ../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 msgid "Klarna Checkout order was rejected." msgstr "" #. 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 +#. 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:497, ../includes/class-klarna-checkout-for-woocommerce-gateway.php:358 msgid "Klarna order is under review, order ID: %s." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:491 +#: ../includes/class-klarna-checkout-for-woocommerce-api-callbacks.php:510 msgid "Order needs manual review, WooCommerce total and Klarna total do not match. Klarna order total: %s." msgstr "" @@ -342,11 +330,11 @@ msgstr "" msgid "Klarna Checkout replaces standard WooCommerce checkout page." msgstr "" -#: ../includes/class-klarna-checkout-for-woocommerce-gateway.php:340 +#: ../includes/class-klarna-checkout-for-woocommerce-gateway.php:397 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:351 +#: ../includes/class-klarna-checkout-for-woocommerce-gateway.php:409 msgid "An account is already registered with your email address. Please log in." msgstr "" @@ -361,6 +349,14 @@ msgstr "" msgid "Shipping" msgstr "" +#: ../includes/class-klarna-checkout-for-woocommerce-subscription.php:171 +msgid "Subscription payment made with Klarna. Klarna order id: %s" +msgstr "" + +#: ../includes/class-klarna-checkout-for-woocommerce-subscription.php:175 +msgid "Subscription payment failed with Klarna. Error code: %1$s. Message: %2$s" +msgstr "" + #: ../includes/klarna-checkout-for-woocommerce-functions.php:57 msgid "Create an account?" msgstr "" @@ -392,3 +388,19 @@ msgstr "" #: ../includes/klarna-checkout-for-woocommerce-status-report.php:22 msgid "Displays the number of orders created via the API callback feature during the last month." msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:177 +msgid "Settings" +msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:178 +msgid "Support" +msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:239 +msgid "Activate Now" +msgstr "" + +#: ../klarna-checkout-for-woocommerce.php:265 +msgid "Install Now" +msgstr "" From 53d54241f3cd0570fe178c96c2145aa8b52000ef Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Wed, 26 Sep 2018 09:32:25 +0200 Subject: [PATCH 12/21] Added recurring token as a editable field. --- assets/css/klarna-checkout-admin.css | 3 +- ...larna-checkout-for-woocommerce-gateway.php | 2 +- ...-checkout-for-woocommerce-subscription.php | 43 +++++++++++++++++-- languages/klarna-checkout-for-woocommerce.pot | 4 +- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/assets/css/klarna-checkout-admin.css b/assets/css/klarna-checkout-admin.css index a020db4e..4dd4a682 100644 --- a/assets/css/klarna-checkout-admin.css +++ b/assets/css/klarna-checkout-admin.css @@ -158,5 +158,4 @@ a.kb-button { outline:none; text-decoration:none; color:black; -} - +} \ No newline at end of file diff --git a/includes/class-klarna-checkout-for-woocommerce-gateway.php b/includes/class-klarna-checkout-for-woocommerce-gateway.php index c30a267c..e8b74029 100644 --- a/includes/class-klarna-checkout-for-woocommerce-gateway.php +++ b/includes/class-klarna-checkout-for-woocommerce-gateway.php @@ -393,7 +393,7 @@ public function admin_footer_text( $text ) { */ public function address_notice( $order ) { if ( $this->id === $order->get_payment_method() ) { - echo '
'; + echo '
'; esc_html_e( 'Order address should not be changed and any changes you make will not be reflected in Klarna system.', 'klarna-checkout-for-woocommerce' ); echo '
'; } diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index 44e91cff..000bfc61 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -22,6 +22,8 @@ public function __construct() { add_filter( 'kco_wc_api_request_args', array( $this, 'set_merchant_data' ) ); add_action( 'woocommerce_thankyou_kco', array( $this, 'set_recurring_token_for_order' ) ); add_action( 'woocommerce_scheduled_subscription_payment_kco', array( $this, 'trigger_scheduled_payment' ), 10, 2 ); + add_action( 'woocommerce_admin_order_data_after_billing_address', array( $this, 'show_recurring_token' ) ); + add_action( 'woocommerce_process_shop_order_meta', array( $this, 'save_kco_recurring_token_update' ), 45, 2 ); } /** @@ -139,7 +141,7 @@ public function set_recurring_token_for_order( $order_id = null ) { $klarna_order = $klarna_api->get_order(); if ( isset( $klarna_order->recurring_token ) ) { $recurring_token = $klarna_order->recurring_token; - update_post_meta( $order_id, 'kco_recurring_token', $recurring_token ); + update_post_meta( $order_id, '_kco_recurring_token', $recurring_token ); } } } @@ -157,10 +159,10 @@ public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { reset( $subscriptions ); $subscription_id = key( $subscriptions ); - $recurring_token = get_post_meta( $order_id, 'kco_recurring_token', true ); + $recurring_token = get_post_meta( $order_id, '_kco_recurring_token', true ); if ( empty( $recurring_token ) ) { - $recurring_token = get_post_meta( WC_Subscriptions_Renewal_Order::get_parent_order_id( $order_id ), 'kco_recurring_token', true ); - update_post_meta( $order_id, 'kco_recurring_token', $recurring_token ); + $recurring_token = get_post_meta( WC_Subscriptions_Renewal_Order::get_parent_order_id( $order_id ), '_kco_recurring_token', true ); + update_post_meta( $order_id, '_kco_recurring_token', $recurring_token ); } $create_order_response = new Klarna_Checkout_For_WooCommerce_API(); @@ -175,6 +177,39 @@ public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { $renewal_order->add_order_note( sprintf( __( 'Subscription payment failed with Klarna. Error code: %1$s. Message: %2$s', 'klarna-checkout-for-woocommerce' ), $create_order_response['response']['code'], $create_order_response['response']['message'] ) ); } } + + public function show_recurring_token( $order ) { + if ( wcs_order_contains_subscription( $order ) && get_post_meta( $order->get_id(), '_kco_recurring_token' ) ) { + ?> +
+
+ ' . __( 'Klarna recurring token' ) . ':' . get_post_meta( $order->id, '_kco_recurring_token', true ) . '

'; + ?> +
+
+ '_kco_recurring_token', + 'label' => __( 'Klarna recurring token' ), + 'wrapper_class' => '_billing_company_field', + ) + ); + ?> +
+
+ Date: Wed, 26 Sep 2018 09:57:59 +0200 Subject: [PATCH 13/21] Removed support for changing payment method. --- includes/class-klarna-checkout-for-woocommerce-gateway.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-gateway.php b/includes/class-klarna-checkout-for-woocommerce-gateway.php index e8b74029..ce9dc182 100644 --- a/includes/class-klarna-checkout-for-woocommerce-gateway.php +++ b/includes/class-klarna-checkout-for-woocommerce-gateway.php @@ -28,8 +28,6 @@ public function __construct() { 'subscription_reactivation', 'subscription_amount_changes', 'subscription_date_changes', - 'subscription_payment_method_change', - 'subscription_payment_method_change_admin', 'multiple_subscriptions', ) ); From 13985a21026410db50c4de5c3114bc5111c5177d Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Thu, 27 Sep 2018 10:06:05 +0200 Subject: [PATCH 14/21] Fixed issue of not triggering mailchimp after recent change. --- assets/js/klarna-checkout-for-woocommerce.js | 4 ++++ assets/js/klarna-checkout-for-woocommerce.min.js | 2 +- includes/class-klarna-checkout-for-woocommerce-templates.php | 5 ++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/assets/js/klarna-checkout-for-woocommerce.js b/assets/js/klarna-checkout-for-woocommerce.js index 5aab47ba..1bf43b9b 100644 --- a/assets/js/klarna-checkout-for-woocommerce.js +++ b/assets/js/klarna-checkout-for-woocommerce.js @@ -328,6 +328,10 @@ jQuery(function($) { // Shipping fields $('#shipping_state').val(data.states.shipping_state); + + // Trigger changes + $('#billing_email').change(); + $('#billing_email').blur(); }, init: function () { diff --git a/assets/js/klarna-checkout-for-woocommerce.min.js b/assets/js/klarna-checkout-for-woocommerce.min.js index f745cbb6..d4baa3de 100644 --- a/assets/js/klarna-checkout-for-woocommerce.min.js +++ b/assets/js/klarna-checkout-for-woocommerce.min.js @@ -1 +1 @@ -jQuery(function(s){if("undefined"==typeof kco_params)return!1;var i={bodyEl:s("body"),checkoutFormSelector:"form.checkout",orderNotesValue:"",orderNotesSelector:"textarea#order_comments",orderNotesEl:s("textarea#order_comments"),extraFieldsValues:{},extraFieldsSelectorText:'div#kco-extra-fields input[type="text"], div#kco-extra-fields input[type="password"], div#kco-extra-fields textarea',extraFieldsSelectorNonText:'div#kco-extra-fields select, div#kco-extra-fields input[type="radio"], div#kco-extra-fields input[type="checkbox"], div#kco-extra-fields input.checkout-date-picker, input#terms input[type="checkbox"]',paymentMethodEl:s('input[name="payment_method"]'),paymentMethod:"",selectAnotherSelector:"#klarna-checkout-select-other",formFields:[],documentReady:function(){i.log(kco_params),i.setFormData(),0cart->needs_payment() ) { + if ( ! WC()->cart->needs_payment() ) { return $template; } @@ -98,7 +97,7 @@ public function override_template( $template, $template_name, $template_path ) { if ( 'kco' === key( $available_gateways ) ) { if ( ! isset( $_GET['confirm'] ) ) { - $template = $klarna_checkout_template; + $template = $klarna_checkout_template; } } } From c898612e92aa87eaad7ffea4379b6dad7936fa46 Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Mon, 8 Oct 2018 08:34:57 +0200 Subject: [PATCH 15/21] Added recurring token to Subscription --- ...lass-klarna-checkout-for-woocommerce-api-callbacks.php | 3 ++- includes/class-klarna-checkout-for-woocommerce-api.php | 4 ++-- .../class-klarna-checkout-for-woocommerce-gateway.php | 1 - ...class-klarna-checkout-for-woocommerce-subscription.php | 8 ++++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php index b669649a..81cc81c9 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php +++ b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php @@ -88,7 +88,8 @@ public function push_cb() { if ( ! $order->has_status( array( 'on-hold', 'processing', 'completed' ) ) ) { $response = KCO_WC()->api->request_post_get_order( $klarna_order_id ); - $klarna_order = json_decode( $response['body'] ); + $klarna_order = apply_filters( 'kco_wc_api_callbacks_push_klarna_order', json_decode( $response['body'] ) ); + krokedil_log_events( $order_id, 'Klarna push callback. Updating order status.', $klarna_order ); if ( 'ACCEPTED' === $klarna_order->fraud_status ) { diff --git a/includes/class-klarna-checkout-for-woocommerce-api.php b/includes/class-klarna-checkout-for-woocommerce-api.php index 41aa5047..c3b4c426 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api.php +++ b/includes/class-klarna-checkout-for-woocommerce-api.php @@ -51,7 +51,7 @@ public function request_pre_create_order() { KCO_WC()->logger->log( 'Create Klarna order (' . $request_url . ') ' . stripslashes_deep( json_encode( $request_args ) ) ); krokedil_log_events( null, 'Pre Create Order request args', $log_array ); $response = wp_safe_remote_post( $request_url, $request_args ); - + 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 ) ) ); @@ -72,7 +72,7 @@ public function request_pre_create_order() { return $error; } else { $error = $this->extract_error_messages( $response ); - KCO_WC()->logger->log( 'Create Klarna order ERROR (' . stripslashes_deep( json_encode($error)) . ') ' . stripslashes_deep( json_encode( $response ) ) ); + KCO_WC()->logger->log( 'Create Klarna order ERROR (' . stripslashes_deep( json_encode( $error ) ) . ') ' . stripslashes_deep( json_encode( $response ) ) ); krokedil_log_events( null, 'Pre Create Order response', $error ); return $error; } diff --git a/includes/class-klarna-checkout-for-woocommerce-gateway.php b/includes/class-klarna-checkout-for-woocommerce-gateway.php index ce9dc182..51c0e258 100644 --- a/includes/class-klarna-checkout-for-woocommerce-gateway.php +++ b/includes/class-klarna-checkout-for-woocommerce-gateway.php @@ -343,7 +343,6 @@ public function show_thank_you_snippet( $order_id = null ) { $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 ); - if ( 'ACCEPTED' === $klarna_post_order->fraud_status ) { $order->payment_complete(); // translators: Klarna order ID. diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index 000bfc61..8760438d 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -137,10 +137,14 @@ public function set_recurring( $request_args ) { public function set_recurring_token_for_order( $order_id = null ) { $wc_order = wc_get_order( $order_id ); if ( wcs_order_contains_subscription( $wc_order ) ) { + $subcriptions = wcs_get_subscriptions_for_order( $order_id ); $klarna_api = new Klarna_Checkout_For_WooCommerce_API(); $klarna_order = $klarna_api->get_order(); if ( isset( $klarna_order->recurring_token ) ) { $recurring_token = $klarna_order->recurring_token; + foreach ( $subcriptions as $subcription ) { + update_post_meta( $subcription->get_id(), '_kco_recurring_token', $recurring_token ); + } update_post_meta( $order_id, '_kco_recurring_token', $recurring_token ); } } @@ -179,7 +183,7 @@ public function trigger_scheduled_payment( $renewal_total, $renewal_order ) { } public function show_recurring_token( $order ) { - if ( wcs_order_contains_subscription( $order ) && get_post_meta( $order->get_id(), '_kco_recurring_token' ) ) { + if ( 'shop_subscription' === $order->get_type() && get_post_meta( $order->get_id(), '_kco_recurring_token' ) ) { ?>
@@ -205,7 +209,7 @@ public function show_recurring_token( $order ) { public function save_kco_recurring_token_update( $post_id, $post ) { $order = wc_get_order( $post_id ); - if ( wcs_order_contains_subscription( $order ) && get_post_meta( $post_id, '_kco_recurring_token' ) ) { + if ( 'shop_subscription' === $order->get_type() && get_post_meta( $post_id, '_kco_recurring_token' ) ) { update_post_meta( $post_id, '_kco_recurring_token', wc_clean( $_POST['_kco_recurring_token'] ) ); } From e09f881d313c7239e88b081f79dd926c50c1a42e Mon Sep 17 00:00:00 2001 From: MichaelBengtsson Date: Mon, 8 Oct 2018 09:06:41 +0200 Subject: [PATCH 16/21] Changed how we are calling a class. --- .../class-klarna-checkout-for-woocommerce-subscription.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index 8760438d..b9e8fc57 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -138,8 +138,7 @@ public function set_recurring_token_for_order( $order_id = null ) { $wc_order = wc_get_order( $order_id ); if ( wcs_order_contains_subscription( $wc_order ) ) { $subcriptions = wcs_get_subscriptions_for_order( $order_id ); - $klarna_api = new Klarna_Checkout_For_WooCommerce_API(); - $klarna_order = $klarna_api->get_order(); + $klarna_order = KCO_WC()->api->get_order(); if ( isset( $klarna_order->recurring_token ) ) { $recurring_token = $klarna_order->recurring_token; foreach ( $subcriptions as $subcription ) { From 6b31a69676afb9d6d861e677dad7d4f354f46956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Ho=CC=88gefjord?= Date: Tue, 9 Oct 2018 11:52:59 +0200 Subject: [PATCH 17/21] Added order note if order is created via API callback (push notification) --- .../class-klarna-checkout-for-woocommerce-api-callbacks.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php index 81cc81c9..d07d5dbe 100644 --- a/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php +++ b/includes/class-klarna-checkout-for-woocommerce-api-callbacks.php @@ -486,6 +486,8 @@ private function process_order( $klarna_order ) { $order->save(); + $order->add_order_note( __( 'Order created via Klarna Checkout API callback. Please verify the order in Klarnas system.', 'klarna-checkout-for-woocommerce' ) ); + if ( 'ACCEPTED' === $klarna_order->fraud_status ) { $order->payment_complete( $klarna_order->order_id ); // translators: Klarna order ID. From 338456ac1527eb6e9294a6816b44350274bb43dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Ho=CC=88gefjord?= Date: Tue, 9 Oct 2018 14:42:29 +0200 Subject: [PATCH 18/21] Autoptimize admin notice warning --- ...checkout-for-woocommerce-admin-notices.php | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-admin-notices.php b/includes/class-klarna-checkout-for-woocommerce-admin-notices.php index cec1b1c3..0a18c559 100644 --- a/includes/class-klarna-checkout-for-woocommerce-admin-notices.php +++ b/includes/class-klarna-checkout-for-woocommerce-admin-notices.php @@ -58,10 +58,12 @@ public function check_settings() { if ( ! empty( $_POST ) ) { add_action( 'woocommerce_settings_saved', array( $this, 'check_terms' ) ); add_action( 'woocommerce_settings_saved', array( $this, 'check_account' ) ); + add_action( 'admin_notices', array( $this, 'check_autoptimize' ) ); } else { - add_action( 'admin_notices', array( $this, 'check_terms' ) ); add_action( 'admin_notices', array( $this, 'check_https' ) ); + add_action( 'admin_notices', array( $this, 'check_terms' ) ); add_action( 'admin_notices', array( $this, 'check_account' ) ); + add_action( 'admin_notices', array( $this, 'check_autoptimize' ) ); } } @@ -117,6 +119,21 @@ public function check_account() { echo '
'; } } + + /** + * Check Autoptimize plugin checkout settings if they exist. + */ + public function check_autoptimize() { + if ( 'yes' !== $this->enabled ) { + return; + } + + if ( 'on' === get_option( 'autoptimize_optimize_checkout' ) ) { + echo '
'; + echo '

' . sprintf( __( '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).', 'klarna-checkout-for-woocommerce' ), admin_url( 'options-general.php?page=autoptimize' ) ) . '

'; + echo '
'; + } + } } Klarna_Checkout_For_WooCommerce_Admin_Notices::get_instance(); From 8c19eda850ff2ef097c1d8aa3cd1bde3c6784fed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Ho=CC=88gefjord?= Date: Tue, 9 Oct 2018 15:50:39 +0200 Subject: [PATCH 19/21] Check if WC_Subscription class exist before trying to set recurring token in order. --- includes/class-klarna-checkout-for-woocommerce-subscription.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/class-klarna-checkout-for-woocommerce-subscription.php b/includes/class-klarna-checkout-for-woocommerce-subscription.php index b9e8fc57..71408257 100644 --- a/includes/class-klarna-checkout-for-woocommerce-subscription.php +++ b/includes/class-klarna-checkout-for-woocommerce-subscription.php @@ -136,7 +136,7 @@ public function set_recurring( $request_args ) { */ public function set_recurring_token_for_order( $order_id = null ) { $wc_order = wc_get_order( $order_id ); - if ( wcs_order_contains_subscription( $wc_order ) ) { + if ( class_exists( 'WC_Subscription' ) && wcs_order_contains_subscription( $wc_order ) ) { $subcriptions = wcs_get_subscriptions_for_order( $order_id ); $klarna_order = KCO_WC()->api->get_order(); if ( isset( $klarna_order->recurring_token ) ) { From 87b41af7d17cb0a680bce928b36514c77f0ced59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Ho=CC=88gefjord?= Date: Tue, 9 Oct 2018 15:51:01 +0200 Subject: [PATCH 20/21] Only offer subscriptions for 'SE', 'NO', 'FI', 'DE', 'AT' --- .../class-klarna-checkout-for-woocommerce-gateway.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/includes/class-klarna-checkout-for-woocommerce-gateway.php b/includes/class-klarna-checkout-for-woocommerce-gateway.php index 51c0e258..f609d002 100644 --- a/includes/class-klarna-checkout-for-woocommerce-gateway.php +++ b/includes/class-klarna-checkout-for-woocommerce-gateway.php @@ -126,6 +126,14 @@ public function is_available() { return false; } + // 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) ) { + return false; + } + } + return true; } From a4a4d514264d2460cb7d6901884495b99428174c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niklas=20Ho=CC=88gefjord?= Date: Tue, 9 Oct 2018 16:21:18 +0200 Subject: [PATCH 21/21] Version update (1.7.0) --- klarna-checkout-for-woocommerce.php | 4 ++-- readme.txt | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/klarna-checkout-for-woocommerce.php b/klarna-checkout-for-woocommerce.php index 092a38a5..cf1f2fa8 100644 --- a/klarna-checkout-for-woocommerce.php +++ b/klarna-checkout-for-woocommerce.php @@ -5,7 +5,7 @@ * Description: Klarna Checkout payment gateway for WooCommerce. * Author: Krokedil * Author URI: https://krokedil.com/ - * Version: 1.6.1 + * Version: 1.7.0 * Text Domain: klarna-checkout-for-woocommerce * Domain Path: /languages * @@ -35,7 +35,7 @@ /** * Required minimums and constants */ -define( 'KCO_WC_VERSION', '1.6.1' ); +define( 'KCO_WC_VERSION', '1.7.0' ); define( 'KCO_WC_MIN_PHP_VER', '5.3.0' ); define( 'KCO_WC_MIN_WC_VER', '3.0.0' ); define( 'KCO_WC_MAIN_FILE', __FILE__ ); diff --git a/readme.txt b/readme.txt index 0c85131d..c5873453 100644 --- a/readme.txt +++ b/readme.txt @@ -63,6 +63,15 @@ For help setting up and configuring Klarna Payments for WooCommerce please refer == Changelog == += 2018.10.09 - version 1.7.0 = +* Feature - Added support for recurring payments via WooCommerce Subscriptions (in SE, NO, FI, DE & AT). +* Feature - Fetch and save customer email address in Woo on shipping address change event. Adds support for better compatibility with abandoned cart plugins. +* Tweak - Fetch and save customer state in Woo on shipping address change event. +* Tweak - Added admin notice if Autoptimize plugin is used and "Optimize shop cart/checkout" setting is on. +* Tweak - Removed customer address setters used before WC 3.0.0. +* Tweak - Added order note if order is created via API callback (Klarnas push notification). + + = 2018.09.20 - version 1.6.1 = * Fix - Added no as possible Norwegian locale code. * Fix - Added bussiness name from B2B purchase to WooCommerce order.