| Conditions | 1 |
| Paths | 1 |
| Total Lines | 384 |
| Lines | 0 |
| Ratio | 0 % |
| Changes | 2 | ||
| Bugs | 0 | Features | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
| 1 | /*global jQuery, wcStripePaymentRequestParams, PaymentRequest, Stripe, Promise */ |
||
| 4 | (function( $ ) { |
||
| 5 | |||
| 6 | /** |
||
| 7 | * WooCommerce Stripe PaymentRequest class. |
||
| 8 | * |
||
| 9 | * @type {Object} |
||
| 10 | */ |
||
| 11 | var wcStripePaymentRequest = { |
||
| 12 | |||
| 13 | /** |
||
| 14 | * Initialize class events. |
||
| 15 | */ |
||
| 16 | init: function() { |
||
| 17 | var self = this; |
||
| 18 | |||
| 19 | if ( self.hasPaymentRequestSupport() ) { |
||
| 20 | $( document.body ) |
||
| 21 | .on( 'click', '.cart_totals a.checkout-button', self.initPaymentRequest ); |
||
| 22 | } |
||
| 23 | }, |
||
| 24 | |||
| 25 | /** |
||
| 26 | * Check if browser support PaymentRequest class and if is under HTTPS. |
||
| 27 | * |
||
| 28 | * @return {Bool} |
||
| 29 | */ |
||
| 30 | hasPaymentRequestSupport: function() { |
||
| 31 | return window.PaymentRequest && 'https:' === window.location.protocol; |
||
| 32 | }, |
||
| 33 | |||
| 34 | /** |
||
| 35 | * Get Stripe supported methods. |
||
| 36 | * |
||
| 37 | * @return {Array} |
||
| 38 | */ |
||
| 39 | getSupportedMethods: function() { |
||
| 40 | return [ |
||
| 41 | 'amex', |
||
| 42 | 'diners', |
||
| 43 | 'discover', |
||
| 44 | 'jcb', |
||
| 45 | 'mastercard', |
||
| 46 | 'visa' |
||
| 47 | ]; |
||
| 48 | }, |
||
| 49 | |||
| 50 | /** |
||
| 51 | * Get WC AJAX endpoint URL. |
||
| 52 | * |
||
| 53 | * @param {String} endpoint Endpoint. |
||
| 54 | * @return {String} |
||
| 55 | */ |
||
| 56 | getAjaxURL: function( endpoint ) { |
||
| 57 | return wcStripePaymentRequestParams.ajax_url |
||
| 58 | .toString() |
||
| 59 | .replace( '%%endpoint%%', 'wc_stripe_' + endpoint ); |
||
| 60 | }, |
||
| 61 | |||
| 62 | /** |
||
| 63 | * Initialize the PaymentRequest. |
||
| 64 | * |
||
| 65 | * @param {Object} evt DOM events. |
||
| 66 | */ |
||
| 67 | initPaymentRequest: function( evt ) { |
||
| 68 | evt.preventDefault(); |
||
| 69 | var self = wcStripePaymentRequest; |
||
| 70 | var data = { |
||
| 71 | security: wcStripePaymentRequestParams.nonce.payment |
||
| 72 | }; |
||
| 73 | |||
| 74 | $.ajax({ |
||
| 75 | type: 'POST', |
||
| 76 | data: data, |
||
| 77 | url: self.getAjaxURL( 'get_cart_details' ), |
||
| 78 | success: function( response ) { |
||
| 79 | self.openPaymentRequest( response ); |
||
| 80 | } |
||
| 81 | }); |
||
| 82 | }, |
||
| 83 | |||
| 84 | /** |
||
| 85 | * Open Payment Request modal. |
||
| 86 | * |
||
| 87 | * @param {Object} details Payment request details. |
||
| 88 | */ |
||
| 89 | openPaymentRequest: function( details ) { |
||
| 90 | var self = this; |
||
| 91 | |||
| 92 | // PaymentRequest options. |
||
| 93 | var supportedInstruments = [{ |
||
| 94 | supportedMethods: self.getSupportedMethods() |
||
| 95 | }]; |
||
| 96 | var options = { |
||
| 97 | requestPayerPhone: true, |
||
| 98 | requestPayerEmail: true |
||
| 99 | }; |
||
| 100 | if ( details.shipping_required ) { |
||
| 101 | options.requestShipping = true; |
||
| 102 | } |
||
| 103 | var paymentDetails = details.order_data; |
||
| 104 | |||
| 105 | // Init PaymentRequest. |
||
| 106 | var request = new PaymentRequest( supportedInstruments, paymentDetails, options ); |
||
| 107 | |||
| 108 | // Set up shipping. |
||
| 109 | request.addEventListener( 'shippingaddresschange', function( evt ) { |
||
| 110 | evt.updateWith( new Promise( function( resolve, reject ) { |
||
| 111 | self.updateShippingOptions( paymentDetails, request.shippingAddress, resolve, reject ); |
||
| 112 | })); |
||
| 113 | }); |
||
| 114 | request.addEventListener( 'shippingoptionchange', function( evt ) { |
||
| 115 | evt.updateWith( new Promise( function( resolve, reject ) { |
||
| 116 | self.updateShippingDetails( paymentDetails, request.shippingOption, resolve, reject ); |
||
| 117 | })); |
||
| 118 | }); |
||
| 119 | |||
| 120 | // Open Payment Request UI. |
||
| 121 | request.show().then( function( payment ) { |
||
| 122 | self.processPayment( payment ); |
||
| 123 | }) |
||
| 124 | .catch( function( err ) { |
||
| 125 | console.error( err ); |
||
| 126 | }); |
||
| 127 | }, |
||
| 128 | |||
| 129 | /** |
||
| 130 | * Update shipping options. |
||
| 131 | * |
||
| 132 | * @param {Object} details Payment details. |
||
| 133 | * @param {PaymentAddress} address Shipping address. |
||
| 134 | * @param {Function} resolve The callback to invoke with updated line items and shipping options. |
||
| 135 | * @param {Function} reject The callback to invoke in case of failure. |
||
| 136 | */ |
||
| 137 | updateShippingOptions: function( details, address, resolve, reject ) { |
||
| 138 | var self = this; |
||
| 139 | var data = { |
||
| 140 | security: wcStripePaymentRequestParams.nonce.shipping, |
||
| 141 | country: address.country, |
||
| 142 | state: address.region, |
||
| 143 | postcode: address.postalCode, |
||
| 144 | city: address.city, |
||
| 145 | address: typeof address.addressLine[0] === 'undefined' ? '' : address.addressLine[0], |
||
| 146 | address_2: typeof address.addressLine[1] === 'undefined' ? '' : address.addressLine[1] |
||
| 147 | }; |
||
| 148 | |||
| 149 | $.ajax({ |
||
| 150 | type: 'POST', |
||
| 151 | data: data, |
||
| 152 | url: self.getAjaxURL( 'get_shipping_options' ), |
||
| 153 | success: function( response ) { |
||
| 154 | details.shippingOptions = response; |
||
| 155 | if ( details.shippingOptions.length == 1 ) { |
||
| 156 | // The sole shipping option was auto-selected. Update the details |
||
| 157 | // (including the total). |
||
| 158 | self.updateShippingDetails( |
||
| 159 | details, details.shippingOptions[0].id, resolve, reject ); |
||
| 160 | } else { |
||
| 161 | resolve( details ); |
||
| 162 | } |
||
| 163 | } |
||
| 164 | }); |
||
| 165 | }, |
||
| 166 | |||
| 167 | /** |
||
| 168 | * Updates the shipping price and the total based on the shipping option. |
||
| 169 | * |
||
| 170 | * @param {Object} details The line items and shipping options. |
||
| 171 | * @param {String} shippingOption User's preferred shipping option to use for shipping price calculations. |
||
| 172 | * @param {Function} resolve The callback to invoke with updated line items and shipping options. |
||
| 173 | * @param {Function} reject The callback to invoke in case of failure. |
||
| 174 | */ |
||
| 175 | updateShippingDetails: function( details, shippingOption, resolve, reject ) { |
||
| 176 | var self = this; |
||
| 177 | var selected = null; |
||
| 178 | var data = { |
||
| 179 | security: wcStripePaymentRequestParams.nonce.update_shipping, |
||
| 180 | shipping_method: [ |
||
| 181 | shippingOption |
||
| 182 | ] |
||
| 183 | }; |
||
| 184 | |||
| 185 | $.ajax({ |
||
| 186 | type: 'POST', |
||
| 187 | data: data, |
||
| 188 | url: self.getAjaxURL( 'update_shipping_method' ), |
||
| 189 | success: function( response ) { |
||
| 190 | details.shippingOptions.forEach( function( value, index ) { |
||
| 191 | if ( value.id === shippingOption ) { |
||
| 192 | selected = index; |
||
| 193 | value.selected = true; |
||
| 194 | details.total.amount.value = parseFloat( response.total ); |
||
| 195 | |||
| 196 | if ( response.items ) { |
||
| 197 | details.displayItems = response.items; |
||
| 198 | } |
||
| 199 | } else { |
||
| 200 | value.selected = false; |
||
| 201 | } |
||
| 202 | }); |
||
| 203 | |||
| 204 | if ( null === selected ) { |
||
| 205 | reject( wcStripePaymentRequestParams.i18n.unknown_shipping.toString().replace( '[option]', shippingOption ) ); |
||
| 206 | } |
||
| 207 | |||
| 208 | resolve( details ); |
||
| 209 | } |
||
| 210 | }); |
||
| 211 | }, |
||
| 212 | |||
| 213 | /** |
||
| 214 | * Get order data. |
||
| 215 | * |
||
| 216 | * @param {PaymentResponse} payment Payment Response instance. |
||
| 217 | * |
||
| 218 | * @return {Object} |
||
| 219 | */ |
||
| 220 | getOrderData: function( payment ) { |
||
| 221 | var billing = payment.details.billingAddress; |
||
| 222 | var shipping = payment.shippingAddress; |
||
| 223 | var data = { |
||
| 224 | _wpnonce: wcStripePaymentRequestParams.nonce.checkout, |
||
| 225 | billing_first_name: billing.recipient.split( ' ' ).slice( 0, 1 ).join( ' ' ), |
||
| 226 | billing_last_name: billing.recipient.split( ' ' ).slice( 1 ).join( ' ' ), |
||
| 227 | billing_company: billing.organization, |
||
| 228 | billing_email: payment.payerEmail, |
||
| 229 | billing_phone: payment.payerPhone, |
||
| 230 | billing_country: billing.country, |
||
| 231 | billing_address_1: typeof billing.addressLine[0] === 'undefined' ? '' : billing.addressLine[0], |
||
| 232 | billing_address_2: typeof billing.addressLine[1] === 'undefined' ? '' : billing.addressLine[1], |
||
| 233 | billing_city: billing.city, |
||
| 234 | billing_state: billing.region, |
||
| 235 | billing_postcode: billing.postalCode, |
||
| 236 | shipping_first_name: '', |
||
| 237 | shipping_last_name: '', |
||
| 238 | shipping_company: '', |
||
| 239 | shipping_country: '', |
||
| 240 | shipping_address_1: '', |
||
| 241 | shipping_address_2: '', |
||
| 242 | shipping_city: '', |
||
| 243 | shipping_state: '', |
||
| 244 | shipping_postcode: '', |
||
| 245 | shipping_method: [ payment.shippingOption ], |
||
| 246 | order_comments: '', |
||
| 247 | payment_method: 'stripe', |
||
| 248 | // 'wc-stripe-payment-token': 'new', |
||
| 249 | stripe_token: '', |
||
| 250 | }; |
||
| 251 | |||
| 252 | if ( shipping ) { |
||
| 253 | data.shipping_first_name = shipping.recipient.split( ' ' ).slice( 0, 1 ).join( ' ' ); |
||
| 254 | data.shipping_last_name = shipping.recipient.split( ' ' ).slice( 1 ).join( ' ' ); |
||
| 255 | data.shipping_company = shipping.organization; |
||
| 256 | data.shipping_country = shipping.country; |
||
| 257 | data.shipping_address_1 = typeof shipping.addressLine[0] === 'undefined' ? '' : shipping.addressLine[0]; |
||
| 258 | data.shipping_address_2 = typeof shipping.addressLine[1] === 'undefined' ? '' : shipping.addressLine[1]; |
||
| 259 | data.shipping_city = shipping.city; |
||
| 260 | data.shipping_state = shipping.region; |
||
| 261 | data.shipping_postcode = shipping.postalCode; |
||
| 262 | } |
||
| 263 | |||
| 264 | return data; |
||
| 265 | }, |
||
| 266 | |||
| 267 | /** |
||
| 268 | * Get credit card data. |
||
| 269 | * |
||
| 270 | * @param {PaymentResponse} payment Payment Response instance. |
||
| 271 | * |
||
| 272 | * @return {Object} |
||
| 273 | */ |
||
| 274 | getCardData: function( payment ) { |
||
| 275 | var billing = payment.details.billingAddress; |
||
| 276 | var data = { |
||
| 277 | number: payment.details.cardNumber, |
||
| 278 | cvc: payment.details.cardSecurityCode, |
||
| 279 | exp_month: parseInt( payment.details.expiryMonth, 10 ) || 0, |
||
| 280 | exp_year: parseInt( payment.details.expiryYear, 10 ) || 0, |
||
| 281 | name: billing.recipient, |
||
| 282 | address_line1: typeof billing.addressLine[0] === 'undefined' ? '' : billing.addressLine[0], |
||
| 283 | address_line2: typeof billing.addressLine[1] === 'undefined' ? '' : billing.addressLine[1], |
||
| 284 | address_state: billing.region, |
||
| 285 | address_city: billing.city, |
||
| 286 | address_zip: billing.postalCode, |
||
| 287 | address_country: billing.country |
||
| 288 | }; |
||
| 289 | |||
| 290 | return data; |
||
| 291 | }, |
||
| 292 | |||
| 293 | /** |
||
| 294 | * Generate error message HTML. |
||
| 295 | * |
||
| 296 | * @param {String} message Error message. |
||
| 297 | * @return {Object} |
||
| 298 | */ |
||
| 299 | getErrorMessageHTML: function( message ) { |
||
| 300 | return $( '<div class="woocommerce-error" />' ).text( message ); |
||
| 301 | }, |
||
| 302 | |||
| 303 | /** |
||
| 304 | * Abort payment and display error messages. |
||
| 305 | * |
||
| 306 | * @param {PaymentResponse} payment Payment response instance. |
||
| 307 | * @param {String} message Error message to display. |
||
| 308 | */ |
||
| 309 | abortPayment: function( payment, message ) { |
||
| 310 | payment.complete( '' ).then( function() { |
||
| 311 | var $form = $( '.shop_table.cart' ).closest( 'form' ); |
||
| 312 | $( '.woocommerce-error' ).remove(); |
||
| 313 | $form.before( message ); |
||
| 314 | $( 'html, body' ).animate({ |
||
| 315 | scrollTop: $form.prev( '.woocommerce-error' ).offset().top |
||
| 316 | }, 600 ); |
||
| 317 | }) |
||
| 318 | .catch( function( err ) { |
||
| 319 | console.error( err ); |
||
| 320 | }); |
||
| 321 | }, |
||
| 322 | |||
| 323 | /** |
||
| 324 | * Complete payment. |
||
| 325 | * |
||
| 326 | * @param {PaymentResponse} payment Payment response instance. |
||
| 327 | * @param {String} url Order thank you page URL. |
||
| 328 | */ |
||
| 329 | completePayment: function( payment, url ) { |
||
| 330 | payment.complete( 'success' ).then( function() { |
||
| 331 | // Success, then redirect to the Thank You page. |
||
| 332 | window.location = url; |
||
| 333 | }) |
||
| 334 | .catch( function( err ) { |
||
| 335 | console.error( err ); |
||
| 336 | }); |
||
| 337 | }, |
||
| 338 | |||
| 339 | /** |
||
| 340 | * Process payment. |
||
| 341 | * |
||
| 342 | * @param {PaymentResponse} payment Payment response instance. |
||
| 343 | */ |
||
| 344 | processPayment: function( payment ) { |
||
| 345 | var self = this; |
||
| 346 | var orderData = self.getOrderData( payment ); |
||
| 347 | var cardData = self.getCardData( payment ); |
||
| 348 | |||
| 349 | Stripe.setPublishableKey( wcStripePaymentRequestParams.stripe.key ); |
||
| 350 | Stripe.createToken( cardData, function( status, response ) { |
||
| 351 | if ( response.error ) { |
||
| 352 | self.abortPayment( payment, self.getErrorMessageHTML( response.error.message ) ); |
||
| 353 | } else { |
||
| 354 | // Check if we allow prepaid cards. |
||
| 355 | if ( 'no' === wcStripePaymentRequestParams.stripe.allow_prepaid_card && 'prepaid' === response.card.funding ) { |
||
| 356 | self.abortPayment( payment, self.getErrorMessageHTML( wcStripePaymentRequestParams.i18n.no_prepaid_card ) ); |
||
| 357 | } else { |
||
| 358 | // Token contains id, last4, and card type. |
||
| 359 | orderData.stripe_token = response.id; |
||
| 360 | |||
| 361 | $.ajax({ |
||
| 362 | type: 'POST', |
||
| 363 | data: orderData, |
||
| 364 | dataType: 'json', |
||
| 365 | url: self.getAjaxURL( 'create_order' ), |
||
| 366 | success: function( response ) { |
||
| 367 | if ( 'success' === response.result ) { |
||
| 368 | self.completePayment( payment, response.redirect ); |
||
| 369 | } else { |
||
| 370 | self.abortPayment( payment, response.messages ); |
||
| 371 | } |
||
| 372 | }, |
||
| 373 | complete: function( jqXHR, textStatus ) { |
||
| 374 | if ( 'success' !== textStatus ) { |
||
| 375 | console.error( jqXHR ); |
||
| 376 | } |
||
| 377 | } |
||
| 378 | }); |
||
| 379 | } |
||
| 380 | } |
||
| 381 | }); |
||
| 382 | } |
||
| 383 | }; |
||
| 384 | |||
| 385 | wcStripePaymentRequest.init(); |
||
| 386 | |||
| 387 | })( jQuery ); |
||
| 388 |