1/* global console, Klarna */ 2jQuery( function ( $ ) { 3 "use strict" 4 5 var klarna_payments = { 6 authorization_response: {}, 7 iframe_loaded: false, 8 show_form: false, 9 klarna_container_selector: "#klarna_container_2", 10 checkout_values: {}, 11 addresses: {}, 12 cart_total: klarna_payments_params.cart_total, // in minor units 13 submit_button_selectors: klarna_payments_params.submit_button_selectors.join( ", " ), 14 log: ( ...args ) => { 15 if ( klarna_payments_params.debug ) { 16 console.log( ...args ) 17 } 18 }, 19 20 check_changes: function () { 21 $( 22 ".woocommerce-billing-fields input, .woocommerce-billing-fields select, .woocommerce-shipping-fields input, .woocommerce-shipping-fields select", 23 ).each( function () { 24 var fieldName = $( this ).attr( "name" ) 25 var fieldValue = $( this ).val() 26 if ( klarna_payments.checkout_values[ fieldName ] !== fieldValue ) { 27 klarna_payments.checkout_values[ fieldName ] = fieldValue 28 $( this ).trigger( "change" ) 29 } 30 } ) 31 }, 32 33 debounce_changes: function ( func, wait, immediate ) { 34 var timeout 35 return function () { 36 var context = this, 37 args = arguments 38 var later = function () { 39 timeout = null 40 if ( ! immediate ) func.apply( context, args ) 41 } 42 var callNow = immediate && ! timeout 43 clearTimeout( timeout ) 44 timeout = setTimeout( later, wait ) 45 if ( callNow ) func.apply( context, args ) 46 } 47 }, 48 49 start: function () { 50 // Store all billing and shipping values. 51 $( document ).ready( function () { 52 $( "#customer_details input, #customer_details select" ).each( function () { 53 var fieldName = $( this ).attr( "name" ) 54 var fieldValue = $( this ).val() 55 klarna_payments.checkout_values[ fieldName ] = fieldValue 56 } ) 57 if ( klarna_payments.isKlarnaPaymentsSelected() ) { 58 klarna_payments.initKlarnaCredit() 59 klarna_payments.load().then( klarna_payments.loadHandler ) 60 } 61 } ) 62 63 /** 64 * When WooCommerce updates checkout 65 * Happens on initial page load, country, state and postal code changes 66 */ 67 $( "body" ).on( "updated_checkout", function ( event, data ) { 68 // Unblock the payments element if blocked 69 var blocked_el = $( ".woocommerce-checkout-payment" ) 70 var blocked_el_data = blocked_el.data() 71 if ( blocked_el.length && 1 === blocked_el_data[ "blockUI.isBlocked" ] ) { 72 blocked_el.unblock() 73 } 74 75 // Check if we need to hide the shipping fields 76 klarna_payments.maybeHideShippingAddress() 77 78 if (klarna_payments.isKlarnaPaymentsSelected()) { 79 data = data || { fragments: null } 80 81 klarna_payments.initKlarnaCredit() 82 klarna_payments.load( data.fragments ).then( klarna_payments.loadHandler ) 83 } 84 } ) 85 86 /** 87 * Clear auth token if there's checkout error. 88 */ 89 $( document.body ).on( "checkout_error", function () { 90 $( 'input[name="klarna_payments_authorization_token"]' ).remove() 91 } ) 92 93 /** 94 * Phone field changes. Has to be 5 characters or longer for KP to work. 95 */ 96 $( "form.checkout" ).on( 97 "keyup", 98 "#billing_phone", 99 klarna_payments.debounce_changes( function () { 100 if ( klarna_payments.isKlarnaPaymentsSelected() ) { 101 //$('#place_order').attr('disabled', true); 102 if ( $( this ).val().length > 4 ) { 103 klarna_payments.initKlarnaCredit() 104 klarna_payments.load().then( klarna_payments.loadHandler ) 105 } 106 } 107 }, 750 ), 108 ) 109 110 /** 111 * Email field changes, check if WooCommerce says field is valid. 112 */ 113 $( "form.checkout" ).on( 114 "keyup", 115 "#billing_email", 116 klarna_payments.debounce_changes( function () { 117 if ( klarna_payments.isKlarnaPaymentsSelected() ) { 118 //$('#place_order').attr('disabled', true); 119 if ( ! $( this ).parent().hasClass( "woocommerce-invalid" ) ) { 120 klarna_payments.initKlarnaCredit() 121 klarna_payments.load().then( klarna_payments.loadHandler ) 122 } 123 } 124 }, 750 ), 125 ) 126 127 /** 128 * Billing company field changes. 129 */ 130 $( "form.checkout" ).on( 131 "keyup", 132 "#billing_company", 133 klarna_payments.debounce_changes( function () { 134 if ( klarna_payments.isKlarnaPaymentsSelected() ) { 135 klarna_payments.initKlarnaCredit() 136 klarna_payments.load().then( klarna_payments.loadHandler ) 137 } 138 }, 750 ), 139 ) 140 141 /** 142 * When changing payment method. 143 */ 144 $( "body" ).on( "change", 'input[name="payment_method"]', function () { 145 // If Klarna Payments is selected and iframe is not loaded yet, disable the form. Also collapse any unselected Klarna Payments gateways. 146 if ( klarna_payments.isKlarnaPaymentsSelected() ) { 147 klarna_payments.initKlarnaCredit() 148 klarna_payments.load().then( klarna_payments.loadHandler ) 149 klarna_payments.collapseGateways() 150 } 151 152 // Enable the form if any other payment method is selected. 153 if ( ! klarna_payments.isKlarnaPaymentsSelected() ) { 154 $( "#place_order" ).attr( "disabled", false ) 155 } 156 157 // Check if we need to hide the shipping fields 158 klarna_payments.maybeHideShippingAddress() 159 } ) 160 }, 161 162 load: function ( fragments = null ) { 163 var $defer = $.Deferred() 164 165 // Dont run load during checkout completion. 166 if ( $( "form.checkout" ).hasClass( "processing" ) ) { 167 return $defer.reject() 168 } 169 170 var klarna_payments_container_selector_id = "#" + klarna_payments.getSelectorContainerID() 171 klarna_payments.log( klarna_payments_container_selector_id ) 172 173 if ( klarna_payments_container_selector_id ) { 174 var klarnaLoadedInterval = setInterval( function () { 175 var Klarna = false 176 177 try { 178 Klarna = window.Klarna 179 } catch ( e ) { 180 klarna_payments.log( e ) 181 } 182
183 if ( Klarna && Klarna.Payments ) { 184 clearInterval( klarnaLoadedInterval ) 185 clearTimeout( klarnaLoadedTimeout ) 186 187 var options = { 188 container: klarna_payments_container_selector_id, 189 // purchased_amount is used on the checkout page in any of Klarna payment methods that show a cost breakdown (the "Learn more" OSM widget). 190 purchase_amount: klarna_payments.cart_total, 191 } 192 193 // When the payment methods are combined into a single method, the category is omitted so the widget displays all payment options available in the Klarna session. 194 var payment_method_category = klarna_payments.getSelectedPaymentCategory() 195 if ( "klarna_payments" !== payment_method_category ) { 196 options.payment_method_category = payment_method_category 197 } 198 199 if ( fragments && fragments.kp_cart_total ) { 200 // Update the global instance. If we don't do this, the initial cart total will be used on further loads. 201 klarna_payments.cart_total = fragments.kp_cart_total 202 options.purchase_amount = klarna_payments.cart_total 203 } 204 205 if ( "US" === $( "#billing_country" ).val() ) { 206 var address = klarna_payments.get_address_from_checkout_form() 207 208 Klarna.Payments.load( options, address, function ( response ) { 209 $defer.resolve( response ) 210 } ) 211 } else { 212 Klarna.Payments.load( options, function ( response ) { 213 $defer.resolve( response ) 214 } ) 215 } 216 } 217 }, 100 ) 218 219 var klarnaLoadedTimeout = setTimeout( function () { 220 clearInterval( klarnaLoadedInterval ) 221 $defer.reject() 222 }, 3000 ) 223 224 return $defer.promise() 225 } 226 }, 227 228 loadHandler: function ( response ) { 229 klarna_payments.iframe_loaded = true 230 231 if ( response.show_form ) { 232 klarna_payments.show_form = true 233 } 234 }, 235 236 isKlarnaPaymentsSelected: function () { 237 if ( $( 'input[name="payment_method"]:checked' ).length ) { 238 var selected_value = $( 'input[name="payment_method"]:checked' ).val() 239 return selected_value.indexOf( "klarna_payments" ) !== -1 240 } 241 242 return false 243 }, 244 245 isTermsAccepted: function () { 246 if ( ! $( "#terms" ).length || $( "#terms" ).is( ":checked" ) ) { 247 return true 248 } 249 250 return false 251 }, 252 253 setRadioButtonValues: function () { 254 $( 'input[name="payment_method"]' ).each( function () { 255 if ( $( this ).val().indexOf( "klarna_payments" ) !== -1 ) { 256 $( this ).val( "klarna_payments" ) 257 } 258 } ) 259 }, 260 261 getSelectorContainerID: function () { 262 var containerID = $( 'input[name="payment_method"]:checked' ).attr( "id" ).replace( "payment_method_", "" ) 263 264 return containerID + "_container" 265 }, 266 267 getSelectedPaymentCategory: function () { 268 var selected_category = $( 'input[name="payment_method"]:checked' ) 269 .attr( "id" ) 270 .replace( "payment_method_", "" ) 271 klarna_payments.log( selected_category ) 272 return selected_category.replace( "klarna_payments_", "" ) 273 }, 274 275 authorize: function () { 276 var $defer = $.Deferred() 277 var address = klarna_payments.get_address() 278 279 klarna_payments.authorization_response = {} 280 281 // The category must match the load() call, so it is omitted here as well when the payment methods are combined into a single method. 282 var options = {} 283 var payment_method_category = klarna_payments.getSelectedPaymentCategory() 284 if ( "klarna_payments" !== payment_method_category ) { 285 options.payment_method_category = payment_method_category 286 } 287 288 try { 289 Klarna.Payments.authorize( 290 address, 291 options, 292 function ( response ) { 293 klarna_payments.authorization_response = response 294 $defer.resolve( response ) 295 }, 296 ) 297 } catch ( e ) { 298 klarna_payments.logToFile( e ) 299 } 300 301 return $defer.promise() 302 }, 303 304 get_address: function () { 305 var address = { 306 billing_address: { 307 given_name: klarna_payments.addresses.billing.given_name, 308 family_name: klarna_payments.addresses.billing.family_name, 309 email: klarna_payments.addresses.billing.email, 310 phone: klarna_payments.addresses.billing.phone, 311 country: klarna_payments.addresses.billing.country, 312 region: klarna_payments.addresses.billing.region, 313 postal_code: klarna_payments.addresses.billing.postal_code, 314 city: klarna_payments.addresses.billing.city, 315 street_address: klarna_payments.addresses.billing.street_address, 316 street_address2: klarna_payments.addresses.billing.street_address2, 317 organization_name: 318 "b2b" === klarna_payments_params.customer_type 319 ? klarna_payments.addresses.billing.organization_name 320 : "", 321 }, 322 shipping_address: {}, 323 } 324 325 address.shipping_address = $.extend( {}, address.billing_address ) 326 327 if ( $( "#ship-to-different-address" ).find( "input" ).is( ":checked" ) ) { 328 address.shipping_address.given_name = klarna_payments.addresses.shipping.given_name 329 address.shipping_address.family_name = klarna_payments.addresses.shipping.family_name 330 address.shipping_address.country = klarna_payments.addresses.shipping.country 331 address.shipping_address.region = klarna_payments.addresses.shipping.regi
331on 332 address.shipping_address.postal_code = klarna_payments.addresses.shipping.postal_code 333 address.shipping_address.city = klarna_payments.addresses.shipping.city 334 address.shipping_address.street_address = klarna_payments.addresses.shipping.street_address 335 address.shipping_address.street_address2 = klarna_payments.addresses.shipping.street_address2 336 } 337 338 return address 339 }, 340 341 get_address_from_checkout_form: function () { 342 var address = { 343 billing_address: { 344 given_name: klarna_payments.checkout_values.billing_first_name, 345 family_name: klarna_payments.checkout_values.billing_last_name, 346 email: klarna_payments.checkout_values.billing_email, 347 phone: klarna_payments.checkout_values.billing_phone, 348 country: klarna_payments.checkout_values.billing_country, 349 region: klarna_payments.checkout_values.billing_state, 350 postal_code: klarna_payments.checkout_values.billing_postcode, 351 city: klarna_payments.checkout_values.billing_city, 352 street_address: klarna_payments.checkout_values.billing_address_1, 353 street_address2: klarna_payments.checkout_values.billing_address_2, 354 organization_name: 355 "b2b" === klarna_payments_params.customer_type 356 ? klarna_payments.checkout_values.billing_company 357 : "", 358 }, 359 shipping_address: {}, 360 } 361 362 address.shipping_address = $.extend( {}, address.billing_address ) 363 364 if ( $( "#ship-to-different-address" ).find( "input" ).is( ":checked" ) ) { 365 address.shipping_address.given_name = klarna_payments.checkout_values.shipping_first_name 366 address.shipping_address.family_name = klarna_payments.checkout_values.shipping_last_name 367 address.shipping_address.country = klarna_payments.checkout_values.shipping_country 368 address.shipping_address.region = klarna_payments.checkout_values.shipping_state 369 address.shipping_address.postal_code = klarna_payments.checkout_values.shipping_postcode 370 address.shipping_address.city = klarna_payments.checkout_values.shipping_city 371 address.shipping_address.street_address = klarna_payments.checkout_values.shipping_address_1 372 address.shipping_address.street_address2 = klarna_payments.checkout_values.shipping_address_2 373 } 374 375 return address 376 }, 377 378 collapseGateways: function () { 379 $( 'input[name="payment_method"]' ).each( function () { 380 if ( $( this ).is( ":checked" ) ) { 381 $( this ).siblings( "div.payment_box" ).show() 382 } else { 383 $( this ).siblings( "div.payment_box" ).hide() 384 } 385 } ) 386 }, 387 388 maybeHideShippingAddress: function () { 389 if ( false !== klarna_payments.isKlarnaPaymentsSelected() ) { 390 if ( "b2b" === klarna_payments_params.customer_type ) { 391 jQuery( "#customer_details .col-2" ).hide() 392 } 393 } else { 394 jQuery( "#customer_details .col-2" ).show() 395 } 396 }, 397 398 initKlarnaCredit: function ( client_token ) { 399 var client_token = klarna_payments.getClientToken() 400 window.klarnaInitData = { client_token: client_token } 401 Klarna.Payments.init( klarnaInitData ) 402 }, 403 404 printErrorMessage: function ( message ) { 405 $( "#klarna-payments-error-notice" ).remove() 406 const is_pay_for_order = true == klarna_payments_params.pay_for_order 407 const $target = is_pay_for_order ? $( "div.woocommerce-notices-wrapper" ) : $( "form.checkout" ) 408 409 $target.prepend( 410 '<div id="klarna-payments-error-notice" class="woocommerce-NoticeGroup"><ul class="woocommerce-error" role="alert"><li>' + 411 message + 412 "</li></ul></div>", 413 ) 414 $.scroll_to_notices( $target ) 415 }, 416 417 authorizeKlarnaOrder: function ( order_id, order_key ) { 418 klarna_payments.authorize().done( function ( response ) { 419 if ( "authorization_token" in response ) { 420 $( "body" ).trigger( "kp_auth_success" ) 421 $.ajax( klarna_payments_params.place_order_url, { 422 type: "POST", 423 dataType: "json", 424 async: true, 425 data: { 426 order_key: order_key, 427 order_id: order_id, 428 auth_token: klarna_payments.authorization_response.authorization_token, 429 nonce: klarna_payments_params.place_order_nonce, 430 }, 431 success: function ( response ) { 432 // Log the success. 433 klarna_payments.log( "kp_place_order success" ) 434 klarna_payments.log( response ) 435 }, 436 error: function ( response ) { 437 // Log the error. 438 klarna_payments.logToFile( response ) 439 }, 440 complete: function ( response ) { 441 if ( response.responseJSON.success === true ) { 442 window.location.href = response.responseJSON.data 443 } else { 444 $( "form.checkout" ).removeClass( "processing" ).unblock() 445 $( "form.checkout" ) 446 .find( ".input-text, select, input:checkbox" ) 447 .trigger( "validate" ) 448 .blur() 449 $( "form.checkout" ).trigger( "update_checkout" ) 450 } 451 }, 452 } ) 453 } else { 454 $( "body" ).trigger( "kp_auth_failed" ) 455 456 // Re-enable the form. 457 $( "body" ).trigger( "updated_checkout" ) 458 $( "form.checkout" ).removeClass( "processing" ) 459 $( "form.checkout" ).unblock() 460 461 const reason = response.show_form ? "aborted by customer" : "rejected by
461Klarna" 462 klarna_payments.logToFile( 463 `(Order ${ order_id }): No authorization_token in response. Reason: ${ reason }.`, 464 ) 465 $( "form.woocommerce-checkout" ).removeClass( "processing" ).unblock() 466 $.ajax( klarna_payments_params.auth_failed_url, { 467 type: "POST", 468 dataType: "json", 469 async: true, 470 data: { 471 show_form: response.show_form, 472 order_key: order_key, 473 order_id: order_id, 474 nonce: klarna_payments_params.auth_failed_nonce, 475 }, 476 } ) 477 } 478 } ) 479 }, 480 481 klarnaPayForOrder: function ( event ) { 482 if ( klarna_payments.isKlarnaPaymentsSelected() ) { 483 event.preventDefault() 484 485 if ( ! klarna_payments.isTermsAccepted() ) { 486 klarna_payments.printErrorMessage( klarna_payments_params.i18n.terms_not_checked ) 487 return 488 } 489 490 klarna_payments.addresses = klarna_payments_params.addresses 491 klarna_payments.authorizeKlarnaOrder( 492 klarna_payments_params.order_id, 493 klarna_payments_params.order_key, 494 ) 495 } 496 }, 497 498 getClientToken: function () { 499 if ( $( "#kp_client_token" ).length > 0 ) { 500 return $( "#kp_client_token" ).val() 501 } else { 502 return klarna_payments_params.client_token 503 } 504 }, 505 506 orderSubmit: function ( event ) { 507 if ( klarna_payments.isKlarnaPaymentsSelected() ) { 508 event.preventDefault() 509 510 if ( $( "form.checkout" ).is( ".processing" ) ) { 511 return false 512 } 513 514 $( "form.checkout" ).addClass( "processing" ) 515 $( "form.checkout" ).block( { 516 message: null, 517 overlayCSS: { 518 background: "#fff", 519 opacity: 0.6, 520 }, 521 } ) 522 523 $.ajax( { 524 type: "POST", 525 url: klarna_payments_params.submit_order, 526 data: $( "form.checkout" ).serialize(), 527 dataType: "json", 528 success: function ( data ) { 529 try { 530 if ( "success" === data.result ) { 531 klarna_payments.logToFile( 532 "Successfully placed order. Starting authorization with Klarna", 533 ) 534 klarna_payments.addresses = data.addresses 535 klarna_payments.authorizeKlarnaOrder( data.order_id, data.order_key ) 536 } else { 537 throw "Result failed" 538 } 539 } catch ( err ) { 540 if ( data.messages ) { 541 klarna_payments.logToFile( "Checkout error | " + data.messages ) 542 klarna_payments.failOrder( "submission", data.messages ) 543 // If requested, reload the page. 544 } else if ( true === data.reload ) { 545 window.location.reload() 546 } else { 547 klarna_payments.logToFile( "Checkout error | " + err ) 548 klarna_payments.failOrder( 549 "submission", 550 '<div class="woocommerce-error">' + "Checkout error" + "</div>", 551 ) 552 } 553 } 554 }, 555 error: function ( data ) { 556 try { 557 klarna_payments.logToFile( "AJAX error | " + JSON.stringify( data ) ) 558 } catch ( e ) { 559 klarna_payments.logToFile( "AJAX error | Failed to parse error message." ) 560 } 561 klarna_payments.failOrder( 562 "ajax-error", 563 '<div class="woocommerce-error">Internal Server Error</div>', 564 ) 565 }, 566 } ) 567 } 568 }, 569 570 /** 571 * Fails the order with Klarna on a checkout error and timeout. 572 * @param {string} event 573 */ 574 failOrder: function ( event, error_message ) { 575 // Re-enable the form. 576 $( "body" ).trigger( "updated_checkout" ) 577 $( "form.checkout" ).removeClass( "processing" ) 578 $( "form.checkout" ).unblock() 579 580 // Print error messages, and trigger checkout_error, and scroll to notices. 581 $( ".woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message" ).remove() 582 $( "form.checkout" ).prepend( 583 '<div class="woocommerce-NoticeGroup woocommerce-NoticeGroup-checkout">' + error_message + "</div>", 584 ) // eslint-disable-line max-len 585 $( "form.checkout" ).removeClass( "processing" ).unblock() 586 $( "form.checkout" ).find( ".input-text, select, input:checkbox" ).trigger( "validate" ).blur() 587 $( document.body ).trigger( "checkout_error", [ error_message ] ) 588 $.scroll_to_notices( $( "form.checkout" ) ) 589 }, 590 591 /** 592 * Logs the message to the klarna payments log in WooCommerce. 593 * @param {string} message 594 */ 595 logToFile: function ( message ) { 596 klarna_payments.log( message ) 597 $.ajax( { 598 url: klarna_payments_params.log_to_file_url, 599 type: "POST", 600 dataType: "json", 601 data: { 602 message: message, 603 nonce: klarna_payments_params.log_to_file_nonce, 604 }, 605 } ) 606 }, 607 } 608 klarna_payments.start() 609 $( document ).ready( function () { 610 klarna_payments.setRadioButtonValues() 611 } ) 612 613 $( document ).ajaxComplete( function () { 614 klarna_payments.setRadioButtonValues() 615 } ) 616 617 $( document ).on( "click", klarna_payments.submit_button_selectors, function ( e ) { 618 // No strict comparison: wp_localize_script() converts booleans to strings "1", respectively, "0". 619 if ( true == klarna_payments_params.pay_for_order ) { 620 klarna_payments.klarnaPayForOrder( e ) 621 } else { 622 klarna_payments.orderSubmit( e ) 623 } 624 } ) 625} )
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.