https://www.samen-gernand.de/plugins/xt_paypal_checkout/javascript…?209e94b8bcb1a0ca6d26050b7d1c1d3b
1console.log('xt_paypal_checkout.js'); 2 3let previousCountryCode = ""; 4let operation = "add"; 5let count = 0; 6 7const ppc_button_selector = '#paypal_button_container'; 8 9function enableFoundingSources() { 10 if (window.paypal && window.paypal.Buttons) { 11 try { 12 paypal.getFundingSources().forEach(function (fundingSource) { 13 console.log(fundingSource, paypal.isFundingEligible(fundingSource)); 14 15 if (paypal.isFundingEligible(fundingSource)) { 16 let isApplepay = false; 17 let isApplepayAvail = false; 18 if (fundingSource === 'applepay') { 19 isApplepay = true; 20 if (!window.ApplePaySession) { 21 console.log("This device does not support Apple Pay"); 22 } else if (!ApplePaySession.canMakePayments()) { 23 console.log("This device, although an Apple device, is not capable of making Apple Pay payments"); 24 } else 25 isApplepayAvail = true; 26 } 27 let me = document.getElementById("xt_paypal_checkout_" + fundingSource); 28 if (me && (!isApplepay || isApplepayAvail)) { 29 let parent = me.closest(".list-group-item"); 30 if (parent) { 31 parent.style.display = "block"; 32 } 33 } 34 } 35 }); 36 } catch (e) { 37 console.warn('enableFoundingSources: error'); 38 console.log(e); 39 } 40 } else { 41 console.warn("paypal checkout no available. could not resolve eligible fundingSource's"); 42 } 43} 44 45 46function enablePaypalCardForm() { 47 try { 48 49 const cardFields = paypal.CardFields({ 50 51 style: { 52 'input': { 53 'font-size': '12pt', 54 'color': '#3A3A3A', 55 56 }, 57 '.number': { 58 'font-family': 'monospace' 59 }, 60 '.valid': { 61 'color': 'green' 62 }, 63 '.invalid': { 64 'color': 'purple' 65 } 66 }, 67 68 createOrder: (data, actions) => ppcCreateOrder('card_processing', actions), 69 onApprove: (data, actions) => { console.log('enablePaypalCardForm onApprove', data, actions)}, 70 onError: function (err) { 71 console.log('enablePaypalCardForm onError', err); 72 ppcp_log_js('enablePaypalCardForm onError', {}, err); 73 if (err.message) alert(err.message); 74 ppcWaitModal('hide'); 75 //window.location.href = window.XT.baseUrl + '?page=checkout&page_action=payment&error=ERROR_PAYMENT' 76 } 77 }); 78 79 if(cardFields.isEligible()) { 80 81 82 const cardStyle = { 83 'input': { 84 'font-family': 'courier, monospace', 85 'padding': '0.5rem 0.75rem' 86 }, 87 }; 88 89 let cf = cardFields.NumberField({ 90 style: cardStyle, 91 placeholder: "4111 1111 1111 1111" 92 }).render("#card_number"); 93 94 cardFields.ExpiryField({ 95 style: cardStyle, 96 placeholder: "MM/JJ" 97 }).render("#card_expiration_date"); 98 99 cardFields.CVVField({ 100 style: cardStyle, 101 placeholder: "..." 102 }).render("#card_cvv"); 103 104 cardFields.NameField({ 105 style: cardStyle, 106 placeholder: "..." 107 }).render("#card_holder_name"); 108 109 110 111 document.getElementById("card_form").addEventListener("submit", (event) => { 112 event.preventDefault(); 113 console.log('submitting card form'); 114 115 cardFields.getState().then( data => { 116 return data.isFormValid; 117 }).then( cardFormValid => { 118 119 let xt_form = ppcGetCheckoutForm(); 120 let xt_form_valid = xtSimpleCheckForm_ppc(xt_form) 121 if(cardFormValid && xt_form_valid) 122 { 123 124 125 if (cardFormValid && xt_form_valid) { 126 127 const errContainer = document.getElementById('card_container_error'); 128 errContainer.innerHTML = ''; 129 errContainer.style.display = 'none'; 130 131 ppcWaitModal(); 132 cardFields 133 .submit({ 134 cardholderName: document.getElementById("card_holder_name").value, 135 cardNumber: document.getElementById("card_number").value, 136 }) 137 .then((data) => { 138 console.log(data); 139 ppcWaitModal(); 140 xt_form.submit(); 141 }) 142 .catch((err) => { 143 ppcWaitModal('hide');
144 console.log("Payment could not be processed! " + JSON.stringify(err)); 145 146 let errorMsg = ''; 147 err.details.forEach(errDetail => { 148 errorMsg += errDetail.description + '. '; 149 }); 150 errContainer.innerHTML += errorMsg; 151 errContainer.style.display = 'block'; 152 }); 153 } 154 } 155 }); 156 }); 157 158 } 159 160 } catch (e) { 161 console.warn('enablePaypalCardForm: error'); 162 console.log(e); 163 } 164} 165 166 167function enablePaypalButton(fundingSource, position) { 168 if (window.paypal && window.paypal.Buttons) { 169 170 console.log('creating button for fundingSource ' + fundingSource, paypal_checkout_constant); 171 172 let selector = ppc_button_selector + '_' + position; 173 174 try { 175 ppcFix_button_changed_html(selector); 176 } catch (e) { 177 console.log('ppcFix_button_changed_html failed', e); 178 } 179 180 try { 181 let button = paypal.Buttons({ 182 183 fundingSource: fundingSource, 184 style: { 185 label: 'buynow', 186 height: paypal_checkout_constant.BUTTON_SIZE, // medium | large | responsive 187 shape: paypal_checkout_constant.BUTTON_SHAPE, // pill | rect 188 color: paypal_checkout_constant.BUTTON_COLOR, // gold | blue | silver | white | bla 189 tagline: false 190 }, 191 createOrder: (data, actions) => ppcCreateOrder(data, actions), 192 onApprove: (data, actions) => ppcOnApprove(data, actions), 193 onError: function (err) { 194 console.log(err); 195 ppcWaitModal('hide'); 196 //window.location.href = window.XT.baseUrl + '?page=checkout&page_action=payment&error=ERROR_PAYMENT' 197 }, 198 onCancel: function (data) { 199 console.log(data); 200 ppcWaitModal('hide'); 201 }, 202 onInit: function (data, actions) { 203 console.log('ppcp onInit'); 204 205 let form = ppcGetCheckoutForm(); 206 207 if (form) { 208 const valid = xtSimpleCheckForm_ppc(form, false); 209 if (!valid) { 210 actions.disable(); 211 } 212 let cbox = form.querySelectorAll("input[type=checkbox]"); 213 cbox.forEach(box => { 214 box.addEventListener('change', function (event) { 215 const valid = xtSimpleCheckForm_ppc(form, false); 216 if (valid) { 217 actions.enable(); 218 box.classList.remove("xt-form-error"); 219 } else { 220 actions.disable(); 221 } 222 223 }); 224 }); 225 } 226 227 }, 228 onClick: function (data, actions) { 229 console.log('ppcp onClick'); 230 231 let form = ppcGetCheckoutForm(); 232 233 if (form) { 234 const valid = xtSimpleCheckForm_ppc(form, true, true); 235 if (!valid) { 236 actions.reject(); 237 } 238 let cbox = form.querySelectorAll("input[type=checkbox]"); 239 cbox.forEach(box => { 240 box.addEventListener('change', function (event) { 241 const valid = xtSimpleCheckForm_ppc(form, false); 242 if (valid) { 243 actions.resolve(); 244 box.classList.remove("xt-form-error"); 245 } else { 246 actions.reject(); 247 } 248 249 }); 250 }); 251 } 252 253 } 254 }).render(selector); 255 } catch (e) { 256 console.warn('enablePaypalButton: error creating paypal button for selector [' + ppc_button_selector + '_' + position + ']'); 257 console.log(e); 258 } 259 } else { 260 console.warn('enablePaypalButton: paypal checkout no available. could not create button for fundingSource ' + fundingSource) 261 } 262} 263 264function enablePaypalButtons_additional_payment(position, ap_no) { 265 if (window.paypal && window.paypal.Buttons) { 266 267 console.log('creating button for additional payment ' , paypal_checkout_constant); 268 console.log('creating button for additional payment ' , ap_no); 269 270 let selector = ppc_button_selector + '_' + position; 271 272 try { 273 let button = paypal.Buttons({ 274 275 //fundingSource: '', 276 style: { 277 label: 'pay',
278 height: paypal_checkout_constant.BUTTON_SIZE, // medium | large | responsive 279 shape: paypal_checkout_constant.BUTTON_SHAPE, // pill | rect 280 color: paypal_checkout_constant.BUTTON_COLOR, // gold | blue | silver | white | bla 281 tagline: false 282 }, 283 createOrder: (data, actions) => ppcCreateOrder(data, actions, selector, ap_no), 284 onApprove: (data, actions) => { 285 ppcWaitModal(); 286 ppcCaptureOrder(data.orderID, ap_no) 287 .then(function (resJson) { 288 console.log('ppcCaptureOrder succes', resJson); 289 //window.location.href = window.XT.baseUrl + 'pppayment/success?ap=' + ap_no; 290 // TODO window.XT.baseUrl fehlt der lang part zb de/ 291 window.location.href = window.XT.baseUrl + '?page=pppayment&page_action=success&ap=' + ap_no; 292 }).catch((error) => { 293 console.log('ppcCaptureOrder error', error); 294 ppcWaitModal('hide'); 295 }); 296 297 }, 298 299 onError: function (err) { 300 console.log(err); 301 ppcWaitModal('hide'); 302 //window.location.href = window.XT.baseUrl + '?page=checkout&page_action=payment&error=ERROR_PAYMENT' 303 }, 304 onCancel: function (data) { 305 console.log(data); 306 ppcWaitModal('hide'); 307 }, 308 onInit: function (data, actions) { 309 console.log('ppcp onInit'); 310 311 let form = ppcGetCheckoutForm(); 312 313 if (form) { 314 const valid = xtSimpleCheckForm_ppc(form, false); 315 if (!valid) { 316 actions.disable(); 317 } 318 let cbox = form.querySelectorAll("input[type=checkbox]"); 319 cbox.forEach(box => { 320 box.addEventListener('change', function (event) { 321 const valid = xtSimpleCheckForm_ppc(form, false); 322 if (valid) { 323 actions.enable(); 324 box.classList.remove("xt-form-error"); 325 } else { 326 actions.disable(); 327 } 328 329 }); 330 }); 331 } 332 333 }, 334 onClick: function (data, actions) { 335 console.log('ppcp onClick'); 336 337 let form = ppcGetCheckoutForm(); 338 339 if (form) { 340 const valid = xtSimpleCheckForm_ppc(form, true, true); 341 if (!valid) { 342 actions.reject(); 343 } 344 let cbox = form.querySelectorAll("input[type=checkbox]"); 345 cbox.forEach(box => { 346 box.addEventListener('change', function (event) { 347 const valid = xtSimpleCheckForm_ppc(form, false); 348 if (valid) { 349 actions.resolve(); 350 box.classList.remove("xt-form-error"); 351 } else { 352 actions.reject(); 353 } 354 355 }); 356 }); 357 } 358 359 } 360 }).render(selector); 361 } catch (e) { 362 console.warn('enablePaypalButton: error creating paypal button for selector [' + ppc_button_selector + '_' + position + ']'); 363 console.log(e) 364 } 365 } else { 366 console.warn('enablePaypalButton: paypal checkout no available. could not create button for fundingSource ' + fundingSource) 367 } 368} 369 370 371 372function renderAllEligibleButtons() { 373 if (window.paypal && window.paypal.Buttons) { 374
375 paypal.getFundingSources().forEach(function (fundingSource) { 376 377 console.log(fundingSource, paypal.isFundingEligible(fundingSource)); 378 379 var button = paypal.Buttons({ 380 381 fundingSource: fundingSource, 382 createOrder: (data, actions) => ppcCreateOrder(data, actions), 383 onApprove: (data, actions) => ppcOnApprove(data, actions), 384 onError: function (err) { 385 console.log(err); 386 ppcWaitModal('hide'); 387 window.location.replace(window.XT.baseUrl + '?page=checkout&page_action=payment&error=ERROR_PAYMENT'); 388 }, 389 onCancel: function (data) { 390 console.log(data); 391 ppcWaitModal('hide'); 392 } 393 }); 394 395 }); 396 397 } else { 398 console.warn('renderAllEligibleButtons: paypal checkout no available'); 399 } 400} 401 402function renderAllEligibleButtonsCart(position) { 403 console.log("renderAllEligibleButtonsCart position:" + position); 404 if (window.paypal && window.paypal.Buttons) { 405 try { 406 var button = paypal.Buttons({ 407 408 //fundingSource: fundingSource, 409 style: { 410 layout: 'horizontal', // horizontal | vertical 411 label: 'checkout', 412 height: paypal_checkout_constant.BUTTON_SIZE, // medium | large | responsive 413 shape: paypal_checkout_constant.BUTTON_SHAPE, // pill | rect 414 color: paypal_checkout_constant.BUTTON_COLOR, // gold | blue | silver | white | black 415 tagline: false 416 417 }, 418 createOrder: (data, actions, container) => ppcCreateOrder(data, actions, ppc_button_selector + '_' + position), 419 onApprove: (data, actions) => ppcOnApproveCart(data, actions), 420 onCancel: function (data) { 421 console.log(data); 422 ppcWaitModal('hide'); 423 }, 424 onShippingChange: (data, actions) => ppcGetShippingOptions(data, actions), 425 }).render(ppc_button_selector + '_' + position); 426 } catch (e) { 427 console.warn('renderAllEligibleButtonsCart: error creating paypal button for selector [' + ppc_button_selector + '_' + position + ']'); 428 console.log(e) 429 } 430 } else { 431 console.warn('window.paypal not available'); 432 } 433} 434 435function ppcGetShippingOptions(data, actions) { 436 console.log('ppcGetShippingOptions', data, actions); 437 console.log("previous country " + previousCountryCode, "current country " + data.shipping_address.country_code); 438 439 // ja einfach immer, entweder land hat sich geändert oder die versand-id 440 if (true || data.shipping_address.country_code != previousCountryCode || previousCountryCode == "") { 441 442 let url = baseUrl + '?page=PAYPAL_CHECKOUT_GET_SHIPPING_OPTIONS'; 443 444 if (count > 0) { 445 operation = "replace"; // zur zeit wird eh immer ge add'ed in shippingOptions.php 446 } 447 count++; 448 449 return fetch( 450 url, 451 { 452 method: 'POST', 453 redirect: "error", 454 body: JSON.stringify({ 455 oderID: data.orderID, 456 shipping_address: data.shipping_address, 457 selected_shipping_option: data.selected_shipping_option, 458 operation: operation 459 }) 460 } 461 ).then((response) => { 462 console.log('fast zurück von PAYPAL_CHECKOUT_GET_SHIPPING_OPTIONS', response); 463 let json = response.json(); 464 return json; 465 }).then((response) => { 466 console.log('zurück von PAYPAL_CHECKOUT_GET_SHIPPING_OPTIONS', response); 467 if (response && response.error) { 468 // response.error wird imo zZ nicht verwendet 469 // wäre eine ander mgl zb für class.cart.php:_getContent_bottom und änderungen im cart 470 // fangen wir zZ über redirect-error 471 actions.reject(); 472 window.location.replace(window.XT.baseUrl + '?page=cart'); 473 } 474 if (response && response.needReload) { 475 // response.error wird imo zZ nicht verwendet 476 // wäre eine ander mgl zb für class.cart.php:_getContent_bottom und änderungen im cart 477 // fangen wir zZ über redirect-error 478 window.location.replace(window.XT.baseUrl + '?page=cart'); 479 } 480 previousCountryCode = data.shipping_address.country_code; 481 return actions.resolve(); 482 }).catch(reason => { 483 console.error('error in PAYPAL_CHECKOUT_GET_SHIPPING_OPTIONS', reason); 484 actions.reject(); 485 // shippingOptions nur bei express 486 // wenn der reason ein redirect ist gehen wir in den cart 487 // bestimmt hat sich irgend etwas im cart geändert 488 // siehe class.cart.php:_getContent_bottom 489 window.location.replace(window.XT.baseUrl + '?page=cart'); 490 }); 491 } 492 return actions.resolve(); 493} 494 495 496function ppcCreateOrder(data, actions, button_container_selector, ap_no = null) { 497 console.log({'fnc': 'ppcCreateOrder', 'data': data, 'actions': actions, 'container': button_container_selector, 'ap_no' : ap_no}); 498 499 previousCountryCode = ""; 500 operation = "add"; 501 count = 0; 502 503 ppcWaitModal(); 504 505 const form = ppcGetCheckoutForm(); 506 let valid = true; 507 if (form) valid = xtSimpleCheckForm_ppc(form, true, true); 508 509 let isExpress = false;
510 let url = baseUrl + '?page=PAYPAL_CHECKOUT_ORDER_CREATE'; 511 let isAddpay = false; 512 if(typeof ap_no === 'string' && ap_no.length > 0) { 513 isAddpay = true; 514 url = baseUrl + '?page=PAYPAL_CHECKOUT_ORDER_CREATE_ADD_PAY'; 515 } 516 517 const page = window.XT.page.page_name; 518 519 if (valid) { 520 const formData = new URLSearchParams(); 521 if (form) { 522 for (const pair of new FormData(form)) { 523 formData.append(pair[0], pair[1]); 524 } 525 } 526 if (data === 'card_processing') { 527 formData.append('card_processing', "1"); 528 let ppcp_agree_save_method = document.getElementById('ppcp_agree_save_payment_method'); 529 if(ppcp_agree_save_method && ppcp_agree_save_method.checked) 530 { 531 formData.append('ppcp_agree_save_payment_method', "1"); 532 } 533 534 } else if (page !== 'checkout') { 535 // ar we in cart / product => express checkout ? 536 const page = window.XT.page.page_name; 537 538 isExpress = true; 539 formData.append('ppcp_express_checkout', 'true');// apple_pay_checkout ppcp_express_checkout 540 541 // check if cart or product 542 const form = document.getElementById('main_product_form'); 543 if (!form) { 544 // fallback versuch für artikel seite 545 document.querySelector('form[name=product]'); 546 } 547 548 if (form) { // products page, append quantity and products_id to request 549 550 // now check we are not in eg coe_cart_popup. then there no need to add the product to cart 551 // check the pp-container has the product form as parent 552 let add_ADD_PRODUCT_param = true; // weil alles andere Ausnahme sein sollte.... ): 553 const button_container = document.querySelector(button_container_selector); 554 if (button_container) { 555 // das sollte wohl klappen bis hier 556 // jetzt schauen wir nach dont_add_product_when_paypal_button_is_child_of_one_of_this_containers 557 // definiert in paypal-checkout-cart-and-product_ignored_containers.tpl.html (tpl-überschreibbar) 558 if (typeof dont_add_product_when_paypal_button_is_child_of_one_of_this_containers != 'undefined') { 559 dont_add_product_when_paypal_button_is_child_of_one_of_this_containers.forEach(function (container_selector, index) { 560 const container = document.querySelector(container_selector); 561 if (container) 562 add_ADD_PRODUCT_param = (add_ADD_PRODUCT_param && !container.contains(button_container)); 563 }); 564 } 565 566 } 567 568 console.log("add_ADD_PRODUCT_param => " + add_ADD_PRODUCT_param); 569 570 if (add_ADD_PRODUCT_param) { 571 for (const pair of new FormData(form)) { 572 formData.append(pair[0], pair[1]); 573 } 574 } 575 } 576 formData.delete('action'); 577 } 578 579 if (data && data.shippingContact_ap) { 580 formData.append('shippingContact_ap', JSON.stringify(data.shippingContact_ap)); 581 } 582 583 if (data && data.billingContact_ap) { 584 formData.append('billingContact_ap', JSON.stringify(data.billingContact_ap)); 585 } 586 587 if(typeof ap_no === 'string' && ap_no.length > 0) { 588 formData.append('ap_no', ap_no); 589 } 590 591 return fetch( 592 url, 593 { 594 method: 'POST', 595 body: formData, 596 redirect: "error" 597 } 598 ).then(function (response) { 599 console.log(response); 600 ppcWaitModal('hide'); 601 return response.json(); 602 }).then(function (resJson) { 603 console.log(resJson); 604 if(isAddpay) ppcWaitModal('hide'); 605 else ppcWaitModal(); 606 if(typeof data != 'undefined' && data.paymentSource === "card" && resJson.data.payer_action) 607 { 608 window.location.replace(resJson.data.payer_action); 609 } 610 if (typeof isStandardCard != 'undefined' && isStandardCard) 611 ppcWaitModal('hide'); 612 return resJson.data.id; 613 }).catch((error) => { 614 console.log(error, isExpress); 615 ppcWaitModal('hide'); 616 if(isAddpay) throw error; 617 if (!isExpress) window.location.replace(window.XT.baseUrl + '?page=cart'); 618 else if (page != 'product') window.location.replace(window.XT.baseUrl + '?page=cart'); 619 else if (page == 'product') location.reload(); 620 }); 621 } 622} 623 624function ppcCaptureOrder(ppcp_order_id, ap_no = '') { 625 console.log({'fnc': 'ppcCaptureOrder', 'ppcp_order_id': ppcp_order_id}); 626 627 ppcWaitModal(); 628 629 let url = baseUrl + '?page=PAYPAL_CHECKOUT_ORDER_CAPTURE'; 630 631 return fetch( 632 url, 633 { 634 method: 'POST', 635 headers: { 636 'Content-Type': 'application/json' 637 }, 638 body: JSON.stringify({ppcp_order_id: ppcp_order_id, ap_no: ap_no}), 639 redirect: "error" 640 } 641 ).then(function (response) { 642 console.log(response); 643 ppcWaitModal('hide'); 644 return response.json(); 645 }).then(function (resJson) { 646 console.log(resJson); 647 return resJson.id; 648 }).catch((error) => { 649 console.log('ppcCaptureOrder error', error); 650 }); 651 652} 653 654function ppcGetOrder(ppcp_order_id) { 655 console.log({'fnc': 'ppcGetOrder', 'ppcp_order_id': ppcp_order_id}); 656 657 ppcWaitModal(); 658 659 let url = baseUrl + '?page=PAYPAL_CHECKOUT_ORDER_GET&ppcp_order_id=' + ppcp_order_id; 660 661 return fetch( 662 url, 663 { 664 method: 'GET', 665 redirect: "error" 666 } 667 ).then(function (response) { 668 console.log(response); 669 ppcWaitModal('hide'); 670 return response.json(); 671 }).catch((error) => { 672 console.log('ppcGetOrder error', error); 673 }); 674 675} 676 677function ppcOnApprove(data, actions) { 678 console.log({'fnc': 'ppcOnApprove', 'data': data, 'actions': actions}); 679 680 ppcWaitModal(); 681 682 const form = ppcGetCheckoutForm(); 683 684 let url = baseUrl + '?page=checkout&page_action=process'; 685 let formData = new URLSearchParams(); 686 if (form) { 687 for (const pair of new FormData(form)) { 688 formData.append(pair[0], pair[1]); 689 } 690 } 691 formData.delete("page_action"); 692 693 return fetch( 694 url, 695 { 696 method: 'POST', 697 body: formData, 698 redirect: "error" 699 } 700 ).then(function (response) { 701 console.log(response); 702 if (!response.ok) { 703 throw Error(response.statusText); 704 } 705 return response.json(); 706 }).then(function (resJson) { 707 console.log(resJson); 708 709 ppcWaitModal(); 710 setTimeout(function () { 711 document.getElementById("ppc_oops").style.display = "block" 712 }, 3000); 713 714 window.location.replace(baseUrl + '?page=checkout&page_action=success') 715 }).catch((error) => { 716 ppcWaitModal('hide'); 717 console.log(error); 718 window.location.replace(window.XT.baseUrl + '?page=cart') 719 }); 720} 721 722function ppcOnApproveCart(data, actions) { 723 console.log({'fnc': 'ppcOnApproveCart', 'data': data, 'actions': actions}); 724 ppcWaitModal(); 725 window.location.replace(baseUrl + '?page=checkout&ppcp_express_checkout=true'); 726} 727 728function ppcSetupPuiForm() { 729 let pui_div = document.querySelector("div[id=xt_paypal_checkout_pui]"); 730 if (pui_div) { 731 const regexPrefix = /^[0-9]{0,3}?$/; 732 const regexPhone = /^[0-9]{0,14}?$/; 733 const regexDate = /^[1-9]{2}\.[0-9]{2}\.[0-9]{4}$/; 734 735 let inputPrefix = document.getElementById("paypal_checkout_selection_pui_phoneNumberPrefix"); 736 if (inputPrefix) { 737 setInputFilter(inputPrefix, function (value) { 738 return regexPrefix.test(value); 739 }, "0-9 / min2 / max 3"); 740 } 741 742 let inputPhone = document.getElementById("paypal_checkout_selection_pui_phoneNumber"); 743 if (inputPhone) { 744 setInputFilter(inputPhone, function (value) { 745 return regexPhone.test(value); 746 }, "0-9 / min3 / max 14"); 747 } 748 749 let inputDate = document.getElementById("paypal_checkout_selection_pui_birthdate"); 750 if (inputDate && false) { 751 setInputFilter(inputDate, function (value) { 752 return regexDate.test(value); 753 }, "Format 31.01.1980 / 1980-01-31"); 754 } 755 756 let form = pui_div.closest("form"); 757 if (form) { 758 form.addEventListener('submit', function (event) { 759 let paypalSelected = form.querySelector("input[value^=xt_paypal_checkout_]:checked"); 760 if (paypalSelected) { 761 event.preventDefault(); 762 let puiSelected = form.querySelector("input[value=xt_paypal_checkout_pui]:checked"); 763 if (puiSelected) { 764 // regex anpassen 765 const regexPrefixSubmit = /^[0-9]{2,3}?$/; 766 const regexPhoneSubmit = /^[0-9]{3,14}?$/; 767 const regexDateSubmit = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/; 768 769 let validPrefix = regexPrefixSubmit.test(inputPrefix.value); 770 let validPhone = regexPhoneSubmit.test(inputPhone.value); 771 let validDate = regexDateSubmit.test(inputDate.value); 772 773 if (validPrefix && validPhone && validDate) 774 form.submit(); 775 else { 776 if (!validPrefix) { 777 inputPrefix.classList.add("input-error", "ppcp-has-error", "animated", "shake"); 778 inputPrefix.setCustomValidity('min 2'); 779 inputPrefix.reportValidity(); 780 781 setTimeout(function () { 782 inputPrefix.classList.remove("input-error", "ppcp-has-error", "animated", "shake"); 783 }, 1000); 784 } else if (!validPhone) { 785 inputPhone.classList.add("input-error", "ppcp-has-error", "animated", "shake"); 786 inputPhone.setCustomValidity('min 3'); 787 inputPhone.reportValidity(); 788 789 setTimeout(function () { 790 inputPhone.classList.remove("input-error", "ppcp-has-error", "animated", "shake"); 791 }, 1000); 792 } else if (!validDate) { 793 inputDate.classList.add("input-error", "ppcp-has-error", "animated", "shake"); 794 setTimeout(function () { 795 inputDate.classList.remove("input-error", "ppcp-has-error", "animated", "shake"); 796 }, 1000); 797 } 798 799 // ew_evelations 800 setTimeout(function () { 801 802 form.querySelectorAll("button[type=submit], input[type=submit]").forEach(function (btn, index) { 803 btn.removeAttribute("disabled"); 804 btn.removeAttribute("data-loading"); 805 }); 806 }, 100); 807 } 808 } else { 809 form.submit(); 810 } 811 } 812 }); 813 } 814 } 815} 816 817function ppcRemoveBackButton() { 818 try { 819 let form = ppcGetCheckoutForm(); 820 if (form) { 821 form.querySelectorAll('a[href*="checkout/payment"]').forEach( 822 element => element.remove() 823 ); 824 } 825 } catch (e) { 826 console.log(e); 827 } 828} 829 830function ppcRemoveSubmitButton() { 831 try { 832 let form = ppcGetCheckoutForm(); 833 if (form) { 834 form.querySelectorAll("button:not(.paypal-card-button)").forEach( 835 element => element.remove() 836 ); 837 } 838 } catch (e) { 839 console.log(e); 840 } 841} 842 843function ppcWaitModal(close) { 844 845 console.log('ppcWaitModal', close); 846 try { 847 const modal = document.getElementById('ppc_wait_overlay'); 848 if (modal) { 849 if (typeof close === 'undefined') 850 modal.classList.remove("hidden"); 851 else 852 modal.classList.add("hidden"); 853 } else console.warn('ES WURDE KEIN ppc_wait_overlay GEFUNDEN'); 854 } catch (e) { 855 console.info(e); 856 } 857} 858 859function deleteSavedPaymentMethod(paymentToken) 860{ 861 862 let url = baseUrl + '?page=PAYPAL_CHECKOUT_DELETE_PAYMENT_TOKEN'; 863 864 ppcWaitModal(); 865 866 return fetch( 867 url, 868 { 869 method: 'POST', 870 body: JSON.stringify({paymentToken: paymentToken}), 871 redirect: "error" 872 } 873 ) 874} 875 876function ppcSavePaymentMethodInfoModal(close) { 877 try { 878 const modal = document.getElementById('ppc_save_payment_method_info_overlay'); 879 if (modal) { 880 if (typeof close === 'undefined') 881 { 882 modal.classList.remove("hidden"); 883 modal.addEventListener('click', (e) => { 884 if(e.target === e.currentTarget){ 885 ppcSavePaymentMethodInfoModal(true); 886 } 887 }); 888 } 889 else 890 { 891 modal.classList.add("hidden"); 892 modal.removeEventListener('click', e => { }) 893 } 894 } else console.warn('ES WURDE KEIN ppc_save_payment_method_info_overlay GEFUNDEN'); 895 } catch (e) { 896 console.info(e); 897 } 898} 899 900let vaultedPaymentsDeleteLinksAdded = false;
901function addVaultedPaymentDeleteLink() 902{ 903 document.querySelectorAll('[id="xt_paypal_checkout_paypal_vaulted"]', '[id="xt_paypal_checkout_card_vaulted"]').forEach(node => { 904 let link = node.querySelector(".ppcp-delete-payment-token"); 905 if(link && !vaultedPaymentsDeleteLinksAdded) 906 { 907 link.addEventListener("click", ev => { 908 909 if(confirm("{txt key=TEXT_XT_PAYPAL_CHECKOUT_SAVED_PAYMENT_DELETE}")) { 910 try { 911 ppcWaitModal(); 912 deleteSavedPaymentMethod(link.dataset.paymentToken). 913 then(function (response) { 914 console.log(response); 915 window.location.reload(); 916 }).catch((error) => { 917 console.log('deleteSavedPaymentMethod', error); 918 }); 919 } catch (e) { 920 console.log(e); 921 ppcWaitModal('hide'); 922 } 923 } 924 }); 925 } 926 vaultedPaymentsDeleteLinksAdded = true; 927 }) 928} 929document.addEventListener('DOMContentLoaded', function () 930{ 931 console.log('adding delete-vaulted-payment link'); 932 addVaultedPaymentDeleteLink(); 933}); 934 935 936// Restricts input for the given textbox to the given inputFilter function. 937function setInputFilter(textbox, inputFilter, errMsg) { 938 ["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop", "focusout"].forEach(function (event) { 939 textbox.addEventListener(event, function (e) { 940 if (inputFilter(this.value)) { 941 // Accepted value 942 if (["keydown", "mousedown", "focusout"].indexOf(e.type) >= 0) { 943 this.classList.remove("input-error"); 944 this.setCustomValidity(""); 945 } 946 this.oldValue = this.value; 947 this.oldSelectionStart = this.selectionStart; 948 this.oldSelectionEnd = this.selectionEnd; 949 } else if (this.hasOwnProperty("oldValue")) { 950 // Rejected value - restore the previous one 951 this.classList.add("input-error"); 952 this.setCustomValidity(errMsg); 953 this.reportValidity(); 954 this.value = this.oldValue; 955 this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd); 956 } else { 957 // Rejected value - nothing to restore 958 this.value = ""; 959 } 960 }); 961 }); 962} 963 964function ppcFix_button_changed_html(selector) { 965 try { 966 // in templates vor xt 6.5 ist auf der confirmation das $button_changed_html an der falsche stelle eingebunden 967 let submitButton = document.querySelector("form[id=checkout-form] button[type=submit]"); 968 if (!submitButton) { 969 const form = ppcGetCheckoutForm(); 970 if (form) 971 submitButton = form.querySelector("button[type=submit]"); 972 } 973 if (submitButton) { 974 const btnContainer = submitButton.querySelector(selector); 975 console.log(btnContainer); 976 if (btnContainer) { 977 submitButton.parentElement.insertBefore(btnContainer, submitButton); 978 submitButton.parentElement.removeChild(submitButton); 979 } 980 } 981 } catch (e) { 982 console.log(e); 983 } 984} 985 986if (typeof xtSimpleCheckForm_ppc != 'function') { 987 window.xtSimpleCheckForm_ppc = function (form, scrollTo, showTermsWarning) { 988 var errorElements = []; 989 990 if (scrollTo !== true && scrollTo !== false) scrollTo = true; 991 if (showTermsWarning !== true && showTermsWarning !== false) showTermsWarning = false; 992 993 994 form.querySelectorAll('input[type=checkbox].xt-form-required').forEach(function (el) { 995 if (el.checked !== true) { 996 errorElements.push(el); 997 } 998 }); 999 1000 form.querySelectorAll('input[type=radio].xt-form-required').forEach(function (el) { 1001 // 1002 }); 1003 1004 1005 form.querySelectorAll('input[type=text].xt-form-required').forEach(function (el) { 1006 // 1007 }); 1008 1009 // .... 1010 1011 if (errorElements.length) {
1012 errorElements.forEach(function (el) { 1013 el.classList.add('xt-form-error'); 1014 if (el.name == 'conditions_accepted' && showTermsWarning) { 1015 let div = document.getElementById('TEXT_ERROR_CONDITIONS_ACCEPTED'); 1016 if (div) 1017 div.style.display = 'block'; 1018 } 1019 }); 1020 if (scrollTo && !ppcIsInViewport(errorElements[0])) { 1021 errorElements[0].closest('form').scrollIntoView({ 1022 behavior: 'smooth' 1023 }); 1024 } 1025 // evelations button reaktivieren 1026 setTimeout(function () { 1027 console.log('clearing submit button'); 1028 form.querySelectorAll("[data-loading]").forEach((el) => { 1029 el.removeAttribute('data-loading'); 1030 el.removeAttribute('disabled'); 1031 }); 1032 form = document.getElementById("card_form"); 1033 if(form) 1034 { 1035 form.querySelectorAll("[data-loading]").forEach((el) => { 1036 el.removeAttribute('data-loading'); 1037 el.removeAttribute('disabled'); 1038 }); 1039 } 1040 }, 1000); 1041 return false; 1042 } 1043 1044 return true; 1045 }; 1046} 1047 1048function ppcGetCheckoutForm() { 1049 let xt_form = document.getElementById("checkout-form"); 1050 if (!xt_form) xt_form = document.getElementById("checkout_form"); 1051 if (!xt_form) xt_form = document.getElementById("formCard"); // danke dafür ador, hauptsache eigene id's 1052 if (!xt_form) { 1053 let inp = document.querySelector('input[type=hidden][name=action][value=process]'); 1054 if (inp) 1055 xt_form = inp.parentElement; 1056 } 1057 if (!xt_form) console.warn('ES WURDE KEIN FORMULAR GEFUNDEN. form[id=checkout_form] bzw form[id=checkout-form] oder input[type=hidden][name=action][value=process]'); 1058 return xt_form; 1059} 1060 1061function ppcIsInViewport(element) { 1062 const rect = element.getBoundingClientRect(); 1063 return ( 1064 rect.top >= 0 && 1065 rect.left >= 0 && 1066 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && 1067 rect.right <= (window.innerWidth || document.documentElement.clientWidth) 1068 ); 1069} 1070 1071let logWorker = null; 1072if (window.Worker) { 1073 logWorker = new Worker(baseUrl + 'plugins/xt_paypal_checkout/javascript/log-worker.js'); 1074 console.log(logWorker); 1075} 1076 1077 1078 1079async function ppcp_log_js(fnc, data = {}, error = null) { 1080 1081 let url = baseUrl + '?page=PAYPAL_CHECKOUT_LOG'; 1082 1083 if(window.Worker && logWorker !== null && typeof paypal_checkout_constant !== 'undefined') { 1084 logWorker.postMessage({ 1085 url: url, 1086 ppcp_session_id: paypal_checkout_constant.PPCP_SESSION_ID, 1087 fnc: fnc, 1088 data: data, 1089 error: error 1090 }); 1091 } 1092 else if(typeof paypal_checkout_constant !== 'undefined') 1093 { 1094 console.error('ppcp log worker not available.'); 1095 return fetch( 1096 url, 1097 { 1098 method: 'POST', 1099 redirect: "error", 1100 body: JSON.stringify({ppcp_session_id: paypal_checkout_constant.PPCP_SESSION_ID, fnc: fnc, data: data}) 1101 } 1102 ).then((response) => { } 1103 ).catch(error => { 1104 console.error('PAYPAL_CHECKOUT_LOG error.', error); 1105 }); 1106 } 1107} 1108 1109/**** 1110 * 1111 * APPLE PAY 1112 * */ 1113let getShippingOptions_ap = countryCode => { 1114 console.log('getShippingOptions_ap', "current country ap " + currentCountryCode_ap, "new country ap " + countryCode); 1115 1116 let url = baseUrl + '?page=PAYPAL_CHECKOUT_GET_SHIPPING_OPTIONS_AP'; 1117 1118 return fetch( 1119 url, 1120 { 1121 method: 'POST', 1122 headers: { 1123 'Content-Type': 'application/json' 1124 }, 1125 redirect: "error", 1126 body: JSON.stringify({country_code: countryCode}) 1127 } 1128 ).then((response) => { 1129 console.log('fast zurück von PAYPAL_CHECKOUT_GET_SHIPPING_OPTIONS_AP', response); 1130 return response.json(); 1131 }).then(function (resJson) { 1132 console.log(resJson); 1133 return resJson; 1134 }).catch(error => { 1135 console.error('PAYPAL_CHECKOUT_GET_SHIPPING_OPTIONS_AP error. returning empty array', error); 1136 ppcp_log_js('error getShippingOptions_ap', {}, error); 1137 return []; 1138 }); 1139} 1140 1141let setShippingMethod_ap = (countryCode, shippingCode) => { 1142 console.log('setShippingMethod_ap', "shippingCode " + shippingCode + ". countryCode " + countryCode); 1143 1144 let url = baseUrl + '?page=PAYPAL_CHECKOUT_SET_SHIPPING_METHOD_AP'; 1145 1146 return fetch( 1147 url, 1148 { 1149 method: 'POST', 1150 headers: { 1151 'Content-Type': 'application/json' 1152 }, 1153 redirect: "error", 1154 body: JSON.stringify({ 1155 country_code: countryCode, 1156 shipping_code: shippingCode 1157 }) 1158 } 1159 ).then((response) => { 1160 console.log('fast zurück von PAYPAL_CHECKOUT_SET_SHIPPING_METHOD_AP', response); 1161 return response.json(); 1162 }).then(function (resJson) { 1163 console.log(resJson); 1164 return resJson; 1165 }).catch(error => { 1166 console.error('PAYPAL_CHECKOUT_SET_SHIPPING_METHOD_AP error. returning empty array', error); 1167 return []; 1168 }); 1169} 1170 1171let check_applepay = async () => { 1172 return new Promise((resolve, reject) => { 1173 let error_message = ""; 1174 if (!window.ApplePaySession) { 1175 error_message = "This device does not support Apple Pay"; 1176 } else if (!ApplePaySession.canMakePayments()) { 1177 error_message = "This device, although an Apple device, is not capable of making Apple Pay payments"; 1178 } 1179 if (error_message !== "") { 1180 reject(error_message); 1181 } else { 1182 resolve(); 1183 } 1184 }); 1185}; 1186 1187async function setupApplepay(appendToContainer) {
1188 let container = appendToContainer || "paypal_button_container_checkout"; 1189 check_applepay() 1190 .then(() => { 1191 const applepay = paypal.Applepay(); 1192 1193 applepay.config() 1194 .then(async applePayConfig => { 1195 console.log(applePayConfig); 1196 if (applePayConfig.isEligible) { 1197 1198 let appleButton = document.createElement('apple-pay-button'); 1199 appleButton.setAttribute('id', 'btn-apple-pay'); 1200 appleButton.setAttribute('buttonstyle', paypal_checkout_constant.BUTTON_TYPE_AP); // TODO payment config 1201 appleButton.setAttribute('type', 'continue'); 1202 appleButton.setAttribute('locale', paypal_checkout_constant.language); 1203 1204 document.getElementById(container).appendChild(appleButton); 1205 1206 let shippingResult = await getShippingOptions_ap(currentCountryCode_ap); 1207 currentTotal_ap = shippingResult.newTotal; 1208 console.log('applepay shippings', shippingResult); 1209 1210 appleButton.addEventListener('click', e => { 1211 1212 let xt_form = ppcGetCheckoutForm(); 1213 1214 if (xtSimpleCheckForm_ppc(xt_form, true, true)) { 1215 1216 const paymentRequest = { 1217 countryCode: applePayConfig.countryCode, 1218 merchantCapabilities: applePayConfig.merchantCapabilities, 1219 supportedNetworks: applePayConfig.supportedNetworks, 1220 currencyCode: applePayConfig.currencyCode, 1221 1222 billingContact: billingContact_ap, 1223 shippingContact: shippingContact_ap, 1224 shippingContactEditingMode: 'available', //storePickup 1225 1226 requiredShippingContactFields: ["name", "phone", "postalAddress"], 1227 requiredBillingContactFields: ["name", /*"phone",*/ "postalAddress", "email"], 1228 1229 lineItems: [ 1230 { 1231 label: subTotalLabel_ap, 1232 type: "final", 1233 amount: shippingResult.newSubtotal 1234 }, 1235 { 1236 label: paypal_checkout_constant.TEXT_SHIPPING_COSTS + " " + shippingResult.shipping_label, 1237 type: "final", 1238 amount: shippingResult.shipping_price 1239 } 1240 ], 1241 1242 1243 total: { 1244 label: totalLabel_ap, 1245 type: "final", 1246 amount: shippingResult.newTotal 1247 }, 1248 shippingMethods: shippingResult.shippings 1249 }; 1250 1251 1252 const session = new ApplePaySession(4, paymentRequest); 1253 1254 1255 console.log('apple pay session created', session); 1256 1257 1258 session.oncouponcodechanged = (event) => { 1259 console.log('on coupon code changed', event); 1260 } 1261 1262 1263 session.onpaymentmethodselected_DISABLED = (event) => { 1264 console.log('on payment method selected. zZ machen wir hier nichts', event); 1265 1266 // Define ApplePayPaymentMethodUpdate based on the selected payment method. 1267 // No updates or errors are needed, pass an empty object. 1268 // empty object funktioniert leider nicht 1269 const update = {}; 1270 session.completePaymentMethodSelection(update); 1271 } 1272 1273 session.onshippingcontactselected = (event) => { 1274 1275 console.log('applepay on shipping contact selected', event); 1276 1277 // Define ApplePayShippingContactUpdate based on the selected shipping contact. 1278 if (event.shippingContact.countryCode !== currentCountryCode_ap) { 1279 // würde uns eigentlich reichen 1280 // aber die event handler müssen immer ein update object haben 1281 // und dieses mus ein newTotal lineItem haben 1282 } 1283 1284 getShippingOptions_ap(event.shippingContact.countryCode) 1285 .then(shippingResult => { 1286 1287 let type = 'final'; 1288 let errors = []; 1289 if (shippingResult.shippings && shippingResult.shippings.length === 0) { 1290 type = 'pending'; 1291 errors = [new ApplePayError("shippingContactInvalid", "country", paypal_checkout_constant.WARNING_NO_SHIPPING_FOR_ZONE)]; 1292 } 1293 1294 if (shippingResult.success) { 1295 const update = { 1296 newTotal: { 1297 label: totalLabel_ap, 1298 type: type, 1299 amount: shippingResult.newTotal, 1300 }, 1301 newShippingMethods: shippingResult.shippings || [], 1302 1303 errors: errors 1304 1305 }; 1306 session.completeShippingContactSelection(update); 1307 currentCountryCode_ap = event.shippingContact.countryCode; 1308 currentTotal_ap = shippingResult.newTotal; 1309 } else { 1310 throw new Error(shippingResult.msg || "Error fetching shipping options") 1311 } 1312 }) 1313 .catch(error => { 1314 console.log(' error in onshippingcontactselected while retrieving shipping options', error); 1315 ppcp_log_js('error onshippingcontactselected > getShippingOptions_ap', {}, error); 1316 session.completeShippingContactSelection({ 1317 newTotal: {label: totalLabel_ap, type: "pending", amount: currentTotal_ap}, 1318 errors: [new ApplePayError("shippingContactInvalid", "country", "Error fetching shipping options")] 1319 }); 1320 }); 1321 } 1322 1323 session.onshippingmethodselected = (event) => { 1324 console.log('applepay on shipping method selected', event); 1325 // todo hier ansetzen für onepage 1326 1327 setShippingMethod_ap(currentCountryCode_ap, event.shippingMethod.identifier) 1328 .then(shippingResult => { 1329 1330 if (shippingResult.success) { 1331 const update = { 1332 newTotal: { 1333 label: totalLabel_ap, 1334 type: "final", 1335 amount: shippingResult.newTotal, 1336 } 1337 //newShippingMethods: shippingResult.shippings 1338 1339 }; 1340 1341 session.completeShippingMethodSelection(update); 1342 currentTotal_ap = shippingResult.newTotal; 1343 } else { 1344 throw new Error(shippingResult.msg || "Error setting shipping method") 1345 } 1346 }) 1347 .catch(error => { 1348 console.log(' error in onshippingmethodselected while retrieving shipping options', error); 1349 ppcp_log_js('error onshippingmethodselected > setShippingMethod_ap', {}, error); 1350 session.completeShippingMethodSelection({ 1351 newTotal: { 1352 label: totalLabel_ap, 1353 type: "pending", 1354 amount: currentTotal_ap, 1355 } 1356 }); 1357 }); 1358 } 1359 1360 session.onvalidatemerchant = (event) => { 1361 console.log('on validate merchant', event); 1362 applepay.validateMerchant({ 1363 validationUrl: event.validationURL, 1364 displayName: window.location.hostname 1365 }) 1366 .then(validateResult => { 1367 1368 console.log('on validate merchant validateResult', validateResult); 1369 session.completeMerchantValidation(vali
1369dateResult.merchantSession); 1370 }) 1371 .catch(validateError => { 1372 console.error('validateError', validateError); 1373 ppcp_log_js('error onvalidatemerchant', {}, validateError); 1374 session.abort(); 1375 }); 1376 }; 1377 1378 session.onpaymentauthorized = (event) => { 1379 console.log('on apple payment authorized', event); 1380 console.log('Your billing address is:', event.payment.billingContact); 1381 console.log('Your shipping address is:', event.payment.shippingContact); 1382 // The `billingContact` and `shippingContact` object use the `ApplePayPaymentContact` format. 1383 // Find more details about this object at this URL: 1384 // https://developer.apple.com/documentation/apple_pay_on_the_web/applepaypaymentcontact 1385 ppcCreateOrder({ 1386 billingContact_ap: event.payment.billingContact, 1387 shippingContact_ap: event.payment.shippingContact 1388 }) 1389 .then((ppOrderId) => { 1390 console.log('ppc order created. ppOrderId', ppOrderId); 1391 applepay.confirmOrder({ 1392 orderId: ppOrderId, 1393 token: event.payment.token, 1394 billingContact: event.payment.billingContact, 1395 shippingContact: event.payment.shippingContact 1396 }) 1397 .then(confirmResult => { 1398 console.log('confirmResult', confirmResult) 1399 1400 // Submit approval to the server and authorize or capture the order. 1401 ppcCaptureOrder(ppOrderId) 1402 .then(captureResult => { 1403 console.log('ppc capture result applepay. setting ApplePaySession.STATUS_SUCCESS', captureResult); 1404 1405 session.completePayment(ApplePaySession.STATUS_SUCCESS); 1406 1407 ppcWaitModal(); 1408 window.location.replace(baseUrl + '?page=checkout&page_action=payment_process') 1409 }) 1410 .catch(captureError => { 1411 console.error('ppc error when capture applepay', captureError); 1412 session.completePayment(ApplePaySession.STATUS_FAILURE); 1413 ppcp_log_js('error when capture applepay. onpaymentauthorized > ppcCreateOrder > confirmOrder > ppcCaptureOrder', {}, captureError); 1414 }); 1415 1416 }) 1417 .catch(confirmError => { 1418 console.error('Error confirming order with applepay token', confirmError); 1419 session.completePayment(ApplePaySession.STATUS_FAILURE); 1420 1421 ppcp_log_js('Error confirming order with applepay token. onpaymentauthorized > ppcCreateOrder > confirmOrder', 1422 { 1423 orderId: ppOrderId, 1424 token: event && event.payment ? event.payment.token : "n/a", 1425 billingContact: event && event.payment ? event.payment.billingContact : "n/a", 1426 shippingContact: event && event.payment ? event.payment.shippingContact : "n/a" 1427 }, 1428 confirmError 1429 ); 1430 1431 }); 1432 1433 }) 1434 .catch((error) => { 1435 console.log('error onpaymentauthorized > ppcCreateOrder', error); 1436 session.completePayment(ApplePaySession.STATUS_FAILURE); 1437 ppcp_log_js('error onpaymentauthorized > ppcCreateOrder', {}, error); 1438 }); 1439 1440 }; 1441 1442 session.oncancel = event => { 1443 console.log('apple pay session canceled', event); 1444 1445 let url = baseUrl + '?page=PAYPAL_CHECKOUT_RESET_ADDRESSES_AP'; 1446 1447 return fetch( 1448 url, 1449 { 1450 method: 'POST', 1451 //redirect: "error", 1452 body: JSON.stringify({}) 1453 } 1454 ).then((response) => { 1455 console.log('fast zurück von PAYPAL_CHECKOUT_RESET_ADDRESSES_AP', response); 1456 return response.json(); 1457 }).then(function (resJson) { 1458 console.log(resJson); 1459 return resJson; 1460 }).catch(error => { 1461 console.error('PAYPAL_CHECKOUT_RESET_ADDRESSES_AP error', error); 1462 return []; 1463 }); 1464 }; 1465 1466 session.begin(); 1467 } // form validated 1468 }); 1469 } 1470 }) 1471 .catch(applePayConfigError => { 1472 console.error('Error while fetching Apple Pay configuration.', applePayConfigError); 1473 }); 1474 }) 1475 .catch(errorMessage => { 1476 console.log(errorMessage) 1477 }) 1478} 1479 1480/**** 1481 * 1482 * GOOGLE PAY 1483 * */ 1484/* Configure your site's support for payment methods supported by the Google Pay */ 1485const googleBaseRequest = { 1486 apiVersion: 2, 1487 apiVersionMinor: 0 1488}; 1489 1490const googleAllowedCardNetworks = ["AMEX", "DISCOVER", "JCB", "MASTERCARD", "VISA"]; 1491const googleAllowedCardAuthMethods = [ "PAN_ONLY", "CRYPTOGRAM_3DS"]; 1492 1493let googlePayConfig = null; 1494let googlePaymentsClient = null; 1495const googlePaymentsEnvironment = window?.paypal_checkout_constant?.googlePaymentsEnvironment || null; 1496console.log('googlePaymentsEnvironment', googlePaymentsEnvironment); 1497async function setupGooglepay() { 1498 1499 console.log('setupGooglepay'); 1500 1501 try { 1502 googlePayConfig = await paypal.Googlepay().config(); 1503 1504 googlePaymentsClient = getGooglePaymentsClient(); 1505 const readyToPay = await googlePaymentsClient.isReadyToPay(googlePayConfig); 1506 if (readyToPay.result) { 1507 addGooglePayButton(); 1508 } 1509 } 1510 catch(e){ 1511 console.log('setupGooglePay', e); 1512 } 1513} 1514 1515 1516function addGooglePayButton(appendToContainer) { 1517 1518 console.log('addGooglePayButton') 1519 1520 try {
1521 let container = appendToContainer || "paypal_button_container_checkout"; 1522 1523 const baseCardPaymentMethod = { 1524 type: 'CARD', 1525 parameters: { 1526 allowedAuthMethods: googleAllowedCardAuthMethods, 1527 allowedCardNetworks: googleAllowedCardNetworks 1528 } 1529 }; 1530 1531 const button = 1532 googlePaymentsClient.createButton({ 1533 onClick: onGooglePaymentButtonClicked, 1534 allowedPaymentMethods: [baseCardPaymentMethod], 1535 buttonLocale: paypal_checkout_constant.language_short 1536 }); 1537 1538 document.getElementById(container).appendChild(button); 1539 } 1540 catch(e){ 1541 console.log('addGooglePayButton', e); 1542 } 1543} 1544 1545async function onGooglePaymentButtonClicked() 1546{ 1547 let xt_form = ppcGetCheckoutForm(); 1548 let xt_form_valid = xtSimpleCheckForm_ppc(xt_form, true, true) 1549 1550 if(xt_form_valid) { 1551 const paymentDataRequest = await getGooglePaymentDataRequest(); 1552 const paymentsClient = getGooglePaymentsClient(googlePaymentsEnvironment); 1553 1554 await paymentsClient.loadPaymentData(paymentDataRequest).then(result => { 1555 console.log('result' , result); 1556 //alert('reload'); 1557 //window.location.reload(); 1558 window.location.replace(baseUrl + '?page=checkout&page_action=payment_process') 1559 }).catch(err => { 1560 console.log('Google Pay loadPaymentData error/cancel', err); 1561 }); 1562 } 1563} 1564 1565function onGooglePaymentDataChanged(intermediatePaymentData) 1566{ 1567 console.log('intermediatePaymentData', intermediatePaymentData); 1568 1569 return new Promise(function(resolve, reject) { 1570 1571 let shippingAddress = intermediatePaymentData.shippingAddress; 1572 let shippingOptionData = intermediatePaymentData.shippingOptionData; 1573 let paymentDataRequestUpdate = {}; 1574 1575 if (intermediatePaymentData.callbackTrigger === "INITIALIZE" || intermediatePaymentData.callbackTrigger === "SHIPPING_ADDRESS") { 1576 if(false && shippingAddress.administrativeArea === "NJ") { // beispiel 1577 paymentDataRequestUpdate.error = getGoogleUnserviceableAddressError(); 1578 } 1579 else { 1580 paymentDataRequestUpdate.newShippingOptionParameters = getGoogleDefaultShippingOptions(); 1581 let selectedShippingOptionId = paymentDataRequestUpdate.newShippingOptionParameters.defaultSelectedOptionId; 1582 paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(selectedShippingOptionId); 1583 } 1584 } 1585 else if (intermediatePaymentData.callbackTrigger === "SHIPPING_OPTION") { 1586 paymentDataRequestUpdate.newTransactionInfo = calculateNewTransactionInfo(shippingOptionData.id); 1587 } 1588 1589 resolve(paymentDataRequestUpdate); 1590 }); 1591} 1592 1593function onGooglePaymentAuthorized(paymentData) 1594{ 1595 console.log("onGooglePaymentAuthorized", 'paymentData', paymentData); 1596 1597 return new Promise(function (resolve, reject) { 1598 1599 processPayment(paymentData) 1600 .then(function (data) { 1601 resolve({ transactionState: "SUCCESS" }); 1602 console.log('processPayment.then', data); 1603 if(data && data.error) 1604 { 1605 alert(data.error.message); 1606 window.location.reload(); 1607 } 1608 }) 1609 .catch(error => { 1610 console.log('processPayment.catch', error); 1611 1612 ppcp_log_js('error onGooglePaymentAuthorized > processPayment', paymentData, error ); 1613 1614 resolve({ 1615 transactionState: "ERROR", 1616 error: { 1617 message: error.message, 1618 }, 1619 }); 1620 }); 1621 }); 1622} 1623 1624async function processPayment(paymentData) 1625{ 1626 console.log("processPayment", 'paymentData', paymentData); 1627 1628 try { 1629 let orderId = await ppcCreateOrder({}, null); 1630 1631 const { status } = await paypal.Googlepay().confirmOrder({ 1632 orderId: orderId, 1633 paymentMethodData: paymentData.paymentMethodData, 1634 }); 1635 1636 if (status === "APPROVED") { 1637 /* Capture the Order */ 1638 console.log('capturing g-pay order'); 1639 const captureResponse = await ppcCaptureOrder(orderId); 1640 console.log('getting g-pay order'); 1641 const orderResponse = await ppcGetOrder(orderId); 1642 console.log('checking captureResponse === orderId'); 1643 if(captureResponse === orderId) 1644 return { transactionState: "SUCCESS" }; 1645 else 1646 { 1647 console.error('error google processPayment: createOrderId does not match captureOrderId', {payment_data: paymentData, captureResponse:captureResponse} ); 1648 ppcp_log_js('error google processPayment: createOrderId does not match captureOrderId', {payment_data: paymentData, captureResponse:captureResponse} ); 1649 return { 1650 transactionState: "ERROR", 1651 error: { 1652 message: "createOrderId does not match captureOrderId", 1653 } 1654 }; 1655 } 1656 } 1657 else if (status === "PAYER_ACTION_REQUIRED") { 1658 console.log("==== Confirm Payment Completed Payer Action Required ====="); 1659 1660 let isTimedOut = false;
1661 1662 const payerActionPromise = (async () => { 1663 await paypal 1664 .Googlepay() 1665 .initiatePayerAction({orderId: orderId}); 1666 1667 console.log("===== Payer Action Completed ====="); 1668 1669 const orderResponse = await ppcGetOrder(orderId); 1670 1671 ppcp_log_js('check order if already captured', { 1672 orderResponse: orderResponse 1673 }); 1674 1675 console.log("===== 3DS Contingency Result Fetched ====="); 1676 console.log( 1677 orderResponse?.payment_source?.google_pay?.card?.authentication_result 1678 ); 1679 1680 if(isTimedOut) 1681 { 1682 controller.abort(); 1683 console.error('error google processPayment: payerActionPromise timed out'); 1684 return { 1685 transactionState: "ERROR", 1686 error: { 1687 message: "Timed out waiting for Payer Action", 1688 }, 1689 }; 1690 } 1691 1692 const captureResponse = await ppcCaptureOrder(orderId); 1693 1694 if (orderId === orderResponse?.id && orderId === captureResponse) { 1695 return {transactionState: "SUCCESS"}; 1696 } else { 1697 return { 1698 transactionState: "ERROR", 1699 error: { 1700 message: "createOrderId does not match captureOrderId", 1701 }, 1702 }; 1703 } 1704 })(); 1705 1706 const timeoutPromise = new Promise((resolve) => { 1707 setTimeout(() => { 1708 isTimedOut = true; 1709 resolve({ 1710 transactionState: "ERROR", 1711 error: { 1712 message: "Payer action timed out", 1713 }, 1714 }); 1715 }, 29000); 1716 }); 1717 1718 let r = await Promise.race([payerActionPromise, timeoutPromise]); 1719 console.log('race winner', r); 1720 1721 return r; 1722 } 1723 else { 1724 console.error('error google processPayment ', { paymentData: paymentData, status: status } ); 1725 ppcp_log_js('error google processPayment ', {paymentData: paymentData, status: status} ); 1726 return { transactionState: "ERROR" }; 1727 } 1728 1729 } catch (err) { 1730 console.error("error google processPayment", err); 1731 return { 1732 transactionState: "ERROR", 1733 error: { 1734 message: err.message, 1735 }, 1736 }; 1737 } 1738} 1739 1740async function getGooglePaymentDataRequest() 1741{ 1742 const paymentDataRequest = Object.assign({}, googleBaseRequest); 1743 1744 paymentDataRequest.allowedPaymentMethods = googlePayConfig.allowedPaymentMethods; 1745 paymentDataRequest.merchantInfo = googlePayConfig.merchantInfo; 1746 paymentDataRequest.transactionInfo = getGoogleTransactionInfo(); 1747 paymentDataRequest.shippingAddressRequired = false; 1748 paymentDataRequest.callbackIntents = ["PAYMENT_AUTHORIZATION"]; 1749 1750 return paymentDataRequest; 1751} 1752 1753function getGoogleTransactionInfo(){ 1754 1755 return google_transaction_info; 1756} 1757 1758function getGooglePaymentsClient(environment) 1759{ 1760 let env = environment || googlePaymentsEnvironment; 1761 1762 return new google.payments.api.PaymentsClient({ 1763 environment: env, 1764 paymentDataCallbacks: { 1765 //onPaymentDataChanged: onGooglePaymentDataChanged, // später im cart 1766 onPaymentAuthorized: onGooglePaymentAuthorized 1767 } 1768 }); 1769} 1770
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.