1/* global ppecFrontVars, wpec_create_order_vars, wpec_on_approve_vars */ 2 3class WPECPayPalHandler { 4 5 constructor(btnData, wpecHandler) { 6 this.btnData = btnData; 7 8 this.wpecHandler = wpecHandler; 9 10 if (this.btnData.btnStyle.layout === 'horizontal') { 11 this.btnData.btnStyle.tagline = false; 12 } 13 14 this.clientVars = {}; 15 16 this.clientVars[this.btnData.env] = this.btnData.client_id; 17 18 this.buttonArgs = { 19 env: this.btnData.env, 20 client: this.clientVars, 21 style: this.btnData.btnStyle, 22 commit: true, 23 onInit: this.onInitCallback, 24 onClick: this.onClickCallback, 25 createOrder: this.createOrderCallback, 26 onApprove: this.onApproveCallback, 27 onError: this.onErrorCallback, 28 }; 29 30 // TODO: For addon backward compatibility. A vanilla js version has been added. 31 jQuery( document ).trigger( 'wpec_before_render_button', [ 32 new Proxy(this, { 33 get(target, prop, receiver) { 34 // 1. If prop exists on this 'WPECStripeHandler' class, return that 35 if (prop in target) { 36 return Reflect.get(target, prop, receiver); 37 } 38 // 2. If prop exists on the 'ppecHandler' (i.e. wpecHandler), return that 39 if (prop in target.wpecHandler) { 40 const value = target.wpecHandler[prop]; 41 return typeof value === "function" ? value.bind(target.wpecHandler) : value; 42 } 43 44 return undefined; 45 }, 46 }) 47 ] ); 48 49 document.dispatchEvent( 50 new CustomEvent('wpec_before_render_paypal_button', { 51 detail: { 52 handler: this, 53 } 54 }) 55 ); 56 57 try { 58 paypal.Buttons( this.buttonArgs ).render( '#' + this.btnData.id ); 59 } catch (error){ 60 console.log(error) 61 } 62 } 63 64 onInitCallback = (data, actions) => { 65 this.wpecHandler.actions = actions; 66 67 document.addEventListener('wpec_validate_order', (e) => { 68 if ( e.detail.isValid ) { 69 this.wpecHandler.actions?.enable(); 70 } else { 71 this.wpecHandler.actions?.disable(); 72 } 73 }) 74 75 this.wpecHandler.validateOrder(); 76 } 77 78 onClickCallback = () => { 79 this.wpecHandler.checkAndShowInputErrors(); 80 } 81 82 createOrderCallback = async (data, actions) => { 83 this.wpecHandler.calcTotal(); 84 85 //We need to round to 2 decimal places to make sure that the API call will not fail. 86 let itemTotalValueRounded = (this.wpecHandler.data.price * this.wpecHandler.data.quantity).toFixed(2); 87 let itemTotalValueRoundedAsNumber = parseFloat(itemTotalValueRounded); 88 //console.log('Item total value rounded: ' + itemTotalValueRoundedAsNumber); 89 //console.log(this.wpecHandler.data); 90 91 // Checking if shipping will be required 92 let shipping_pref = 'NO_SHIPPING'; // Default value 93 if (this.wpecHandler.data.shipping !== "" || this.wpecHandler.data.shipping_enable === true) { 94 console.log("The physical product checkbox is enabled or there is shipping value has been configured. Setting the shipping preference to collect shipping."); 95 shipping_pref = 'GET_FROM_FILE'; 96 } 97 98 // Create order_data object to be sent to the server. 99 const order_data = { 100 intent: 'CAPTURE', 101 payment_source: { 102 paypal: { 103 experience_context: { 104 payment_method_preference: 'IMMEDIATE_PAYMENT_REQUIRED', 105 shipping_preference: shipping_pref, 106 user_action: 'PAY_NOW', 107 } 108 } 109 }, 110 purchase_units: [{ 111 amount: { 112 value: this.wpecHandler.data.total, 113 currency_code: this.wpecHandler.data.currency, 114 breakdown: { 115 item_total: { 116 currency_code: this.wpecHandler.data.currency, 117 value: itemTotalValueRoundedAsNumber 118 } 119 } 120 }, 121 items: [{ 122 name: this.wpecHandler.data.name, 123 quantity: this.wpecHandler.data.quantity, 124 unit_amount: { 125 value: this.wpecHandler.data.price, 126 currency_code: this.wpecHandler.data.currency 127 } 128 }] 129 }] 130 }; 131 132 if (this.wpecHandler.data.tax) { 133 order_data.purchase_units[0].amount.breakdown.tax_total = { 134 currency_code: this.wpecHandler.data.currency, 135 value: this.wpecHandler.PHP_round(this.wpecHandler.data.tax_amount * this.wpecHandler.data.quantity, this.wpecHandler.data.dec_num) 136 }; 137 order_data.purchase_units[0].items[0].tax = { 138 currency_code: this.wpecHandler.data.currency, 139 value: this.wpecHandler.data.tax_amount 140 }; 141 } 142 if (this.wpecHandler.data.shipping) { 143 order_data.purchase_units[0].amount.breakdown.shipping = { 144 currency_code: this.wpecHandler.data.currency, 145 value: this.wpecHandler.getTotalShippingCost(), 146 }; 147 } 148 if (this.wpecHandler.data.discount) { 149 order_data.purchase_units[0].amount.breakdown.discount = { 150 currency_code: this.wpecHandler.data.currency, 151 value: parseFloat(this.wpecHandler.data.discountAmount) 152 }; 153 } 154 155 //End of create order_data object. 156 //console.log('Order data: ', order_data); 157 158 let nonce = wpec_create_order_vars.nonce; 159 160 let wpec_data_for_create = this.wpecHandler.data;//this.wpecHandler.data is the data object that was passed to the ppecHandler constructor. 161 //console.log('WPEC data for create-order: ', wpec_data_for_create); 162 163 let post_data = 'action=wpec_pp_create_order&data=' + encodeURIComponent(JSON.stringify(order_data)) + '&wpec_data=' + encodeURIComponent(JSON.stringify(wpec_data_for_create)) + '&_wpnonce=' + nonce; 164 try { 165 // Using fetch for AJAX request. This is supported in all modern browsers.
166 const response = await fetch(ppecFrontVars.ajaxUrl, { 167 method: "post", 168 headers: { 169 'Content-Type': 'application/x-www-form-urlencoded' 170 }, 171 body: post_data 172 }); 173 174 const response_data = await response.json(); 175 176 if (response_data.order_id) { 177 console.log('Create-order API call to PayPal completed successfully.'); 178 return response_data.order_id; 179 } else { 180 const error_message = response_data.err_msg 181 console.error('Error occurred during create-order call to PayPal. ', error_message); 182 throw new Error(error_message);//This will trigger the alert in the "catch" block below. 183 } 184 } catch (error) { 185 console.error(error.message); 186 alert('Could not initiate PayPal Checkout...\n\n' + error.message); 187 } 188 } 189 190 onApproveCallback = async (data, actions) => { 191 document.querySelector('div.wp-ppec-overlay[data-ppec-button-id="' + this.wpecHandler.data.id + '"]').style.display = 'flex'; 192 193 console.log('Setting up the AJAX request for capture-order call.'); 194 195 // Create the data object to be sent to the server. 196 let pp_bn_data = {}; 197 pp_bn_data.order_id = data.orderID;//The orderID is the ID of the order that was created in the createOrder method. 198 let wpec_data = this.wpecHandler.data;//this.wpecHandler.data is the data object that was passed to the ppecHandler constructor. 199 //console.log('WPEC data (JSON): ' + JSON.stringify(wpec_data)); 200 201 let nonce = wpec_on_approve_vars.nonce; 202 let post_data = 'action=wpec_pp_capture_order&data=' + encodeURIComponent(JSON.stringify(pp_bn_data)) + '&wpec_data=' + encodeURIComponent(JSON.stringify(wpec_data)) + '&_wpnonce=' + nonce; 203 try { 204 const response = await fetch(ppecFrontVars.ajaxUrl, { 205 method: "post", 206 headers: { 207 'Content-Type': 'application/x-www-form-urlencoded' 208 }, 209 body: post_data 210 }); 211 212 const response_data = await response.json(); 213 214 if (response_data.hasOwnProperty('success') && !response_data.success) { 215 alert(response_data.err_msg); 216 return; 217 } 218 219 console.log('Capture-order API call to PayPal completed successfully.'); 220 221 // Call the completePayment method to do any redirection or display a message to the user. 222 this.wpecHandler.completePayment(response_data); 223 224 } catch (error) { 225 console.error(error); 226 alert('PayPal returned an error! Transaction could not be processed. Enable the debug logging feature to get more details...\n\n' + JSON.stringify(error)); 227 } 228 229 } 230 231 onErrorCallback = (err) => { 232 document.getElementById("place-order-" + this.wpecHandler.data.id).querySelector("button>svg").style.display = 'none'; 233 document.getElementById("place-order-" + this.wpecHandler.data.id).querySelector("button").removeAttribute("disabled"); 234 alert(err); 235 } 236}
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.