1var PaymentRequestModel = function (context) { 2 /** 3 * Private property is one of contexts 4 * @type {CheckoutContextWrapper} 5 * @private 6 */ 7 var _context = context; 8 9 /** 10 * Saving a payment modal state between opens 11 * Google Pay needs it because paymentRequest doesn't call 'shippingaddresschange' and 'shippingoptionchange' 12 * if nothing has changes (for ex. if modal was closed with default address and option) 13 * @type {{total: {amount: number}, isShown: boolean, shippingAddress: {country: string, city: string, postalCode: string, recipient: string, region: string, addressLine: string[]}, shippingOptionId: ?string, shippingOptions: object[]}} 14 * @private 15 */ 16 var _state = { 17 isShown: false, 18 shippingOptionId: null, 19 shippingOptions: [], 20 shippingAddress: { 21 recipient: '', 22 country: '', 23 city: '', 24 region: '', 25 postalCode: '', 26 addressLine: [], 27 }, 28 total: { 29 amount: 0, 30 }, 31 }; 32 33 /** 34 * @param shippingOptions {{id: string, label: string, detail: string, amount: number}[]} 35 * @returns {{id: string, label: string, detail: string, amount: number}[]} 36 */ 37 var appendRandStringToShippingOptionId = function (shippingOptions) { 38 var rand = (Math.random() + 1).toString(36).substring(3, 13); 39 40 return shippingOptions.map(function (option) { 41 return Object.assign({}, option, { 42 id: rand + ':' + option.id, 43 }); 44 }); 45 }; 46 47 /** 48 * @param id {string} 49 * @returns {string|null} 50 */ 51 var getShippingOptionIdFromStringWithRand = function (id) { 52 var matches = id.match(/^([\w]{5,10}):([\d]+)$/); 53 54 return matches ? matches[2] : null; 55 }; 56 57 /** 58 * @param token {string} 59 * @param data {{payment_method: string}} 60 * @param options {{handleActions: boolean}?} 61 * @returns {Promise<Object>} 62 */ 63 var _makePayment = function (token, data, options) { 64 return _context.getStripe().confirmCardPayment(token, data, options) 65 }; 66 67 /** 68 * @param token {string} 69 * @param paymentMethod {string} 70 * @returns {Promise<Object>} 71 */ 72 var _processPayment = function (token, paymentMethod) { 73 return _makePayment(token, {payment_method: paymentMethod}, {handleActions: false}) 74 .then(function (result) { 75 if (result.error || result.paymentIntent.status !== 'requires_action') { 76 return result; 77 } 78 79 return _makePayment(token, {payment_method: paymentMethod}); 80 }) 81 .then(function (result) { 82 if (result.error) { 83 throw new Error('Unable to process payment'); 84 } 85 86 return result; 87 }); 88 }; 89 90 /** 91 * @param result {Object} 92 * @returns {Object} 93 */ 94 var _handlePaymentResult = function (result) { 95 console.info('Payment is succeed', result); 96 97 return result; 98 }; 99 100 /** 101 * @param paymentMethod {string} 102 * @returns {Promise} 103 */ 104 var _handlePaymentRequest = function (paymentMethod) { 105 return _context.createTransaction() 106 .then(function () { 107 return _context.createPaymentIntent(paymentMethod); 108 }) 109 .then(function (token) { 110 return _processPayment(token, paymentMethod); 111 }) 112 .then(function (result) { 113 return _handlePaymentResult(result); 114 }) 115 .then(function (result) { 116 return _context.handleIntentResult(result); 117 }) 118 .then(function () { 119 return _context.finishTransaction(); 120 }); 121 }; 122 123 /** 124 * @returns {Promise<Object>} 125 */ 126 var _createPaymentRequest = function () { 127 var shippingAddress = _context.getShippingAddress(); 128 129 _state.shippingAddress.country = shippingAddress.country; 130 _state.shippingAddress.region = shippingAddress.region; 131 _state.shippingAddress.city = shippingAddress.city; 132 _state.shippingAddress.postalCode = shippingAddress.postalCode; 133 _state.shippingAddress.addressLine = shippingAddress.addressLine; 134 _state.shippingAddress.recipient = shippingAddress.recipient; 135 136 if (_context.areShippingOptionsRequired()) { 137 _state.shippingOptions = _context.getRainRequestPaymentShippingOptions(); 138 console.info('creating', 'shippingOptions', _state.shippingOptions); 139 140 _state.shippingOptionId = _state.shippingOptions.length ? _state.shippingOptions[0].id : null; 141 console.info('creating', 'shippingOptionId', _state.shippingOptionId); 142 } 143 144 var totalAmountPromise = new Promise(function (resolve) { 145 if (!_state.shippingOptionId) { 146 return resolve(_context.getTotalAmount()); 147 } 148 149 // Calculate total amount with the first shipping option and rollback changes
150 var shippingOptionId = _context.getShippingOptionId(); 151 152 _context.setShippingOptionId(_state.shippingOptionId); 153 _context.onShippingOptionChange(false).then(function () { 154 var totalAmount = _context.getTotalAmount(); 155 156 _context.setShippingOptionId(shippingOptionId); 157 _context.onShippingOptionChange(false).then(function () { 158 return resolve(totalAmount); 159 }); 160 }); 161 }); 162 163 return totalAmountPromise.then(function (totalAmount) { 164 _state.total.amount = totalAmount; 165 166 console.info('creating', 'total.amount', _state.total.amount); 167 }).then(function () { 168 var paymentRequestOptions = { 169 country: _context.getCountry(), 170 currency: _context.getCurrency(), 171 total: { 172 label: 'Order', 173 amount: _state.total.amount, 174 }, 175 requestPayerName: true, 176 requestPayerEmail: true, 177 requestPayerPhone: true, 178 requestShipping: false, 179 disableWallets: ['browserCard'], 180 }; 181 182 if (_state.shippingOptions.length) { 183 paymentRequestOptions.requestShipping = true; 184 paymentRequestOptions.shippingOptions = appendRandStringToShippingOptionId(_state.shippingOptions); 185 } 186 187 return paymentRequestOptions; 188 }).then(function (paymentRequestOptions) { 189 var paymentRequest = _context.getStripe().paymentRequest(paymentRequestOptions); 190 191 paymentRequest.on('shippingoptionchange', function (event) { 192 console.info('event:shippingoptionchange', event); 193 194 _state.shippingOptionId = event.shippingOption ? getShippingOptionIdFromStringWithRand(event.shippingOption.id) : null; 195 196 console.info('event:shippingoptionchange', 'shippingOptionId', _state.shippingOptionId); 197 console.info('event:shippingoptionchange', 'shippingOptionId', 'update checkout', _state.shippingOptionId); 198 199 _context.setShippingOptionId(_state.shippingOptionId); 200 _context.onShippingOptionChange(false) 201 .catch(function (error) { 202 event.updateWith({status: 'invalid_shipping_address'}); 203 204 return Promise.reject(error); 205 }).then(function () { 206 _state.total.amount = _context.getTotalAmount(); 207 208 console.info('event:shippingoptionchange', 'total.amount', _state.total.amount); 209 210 event.updateWith({ 211 status: 'success', 212 total: { 213 label: 'Order', 214 amount: _state.total.amount, 215 }, 216 }); 217 }); 218 }); 219 220 paymentRequest.on('shippingaddresschange', function (event) { 221 console.info('event:shippingaddresschange', event); 222 223 var shippingAddress = event.shippingAddress; 224 225 _state.shippingAddress.country = shippingAddress.country; 226 _state.shippingAddress.region = shippingAddress.region; 227 _state.shippingAddress.city = shippingAddress.city; 228 _state.shippingAddress.postalCode = shippingAddress.postalCode; 229 _state.shippingAddress.addressLine = shippingAddress.addressLine; 230 _state.shippingAddress.recipient = shippingAddress.recipient; 231 232 _context.setShippingAddress(shippingAddress); 233 234 _context.loadShippingOptions(false) 235 .then(function () { 236 var shippingOptions = _context.getRainRequestPaymentShippingOptions(); 237 console.info('event:shippingaddresschange', 'shippingOptions', shippingOptions); 238 239 _state.shippingOptions = shippingOptions; 240 _state.shippingOptionId = shippingOptions.length ? shippingOptions[0].id : null; 241 242 console.info('event:shippingaddresschange', 'shippingOptionId', 'first from shippingOptions', _state.shippingOptionId); 243 console.info('event:shippingaddresschange', 'shippingOptionId', 'update checkout', _state.shippingOptionId); 244 245 _context.setShippingOptionId(_state.shippingOptionId); 246 247 return _context.onShippingOptionChange(false).then(function () {
248 return {shippingOptions: appendRandStringToShippingOptionId(shippingOptions)}; 249 }); 250 }) 251 .then(function (data) { 252 _state.total.amount = _context.getTotalAmount(); 253 254 console.info('event:shippingaddresschange', 'total.amount', _state.total.amount); 255 256 return Object.assign(data, { 257 total: { 258 label: 'Order', 259 amount: _state.total.amount, 260 }, 261 }); 262 }) 263 .then(function (data) { 264 event.updateWith(Object.assign({status: 'success'}, data)); 265 }) 266 .catch(function (e) { 267 console.error(e); 268 269 event.updateWith({status: 'invalid_shipping_address'}); 270 }); 271 }); 272 273 paymentRequest.on('paymentmethod', function (event) { 274 console.info('event:paymentmethod', event); 275 276 try { 277 var billing = event.paymentMethod.billing_details; 278 279 _context.setBillingInfo(billing.name, billing.email, billing.phone, billing.address); 280 _context.onBillingChange(true); 281 } catch (error) { 282 event.complete('fail'); 283 284 throw error; 285 } 286 287 try { 288 var shipping = event.shippingAddress; 289 290 _context.setShippingAddress(shipping); 291 } catch (error) { 292 event.complete('invalid_shipping_address'); 293 294 throw error; 295 } 296 297 _state.shippingOptionId = event.shippingOption ? getShippingOptionIdFromStringWithRand(event.shippingOption.id) : null; 298 299 if (_context.getShippingOptionId() !== _state.shippingOptionId) { 300 console.warn('event:paymentmethod', 'shippingOptionId', 'checkout value', _context.getShippingOptionId(), '!==', 'modal value', _state.shippingOptionId); 301 } 302 303 _context.loadShippingOptions(true) 304 .then(function () { 305 _context.setShippingOptionId(_state.shippingOptionId); 306 307 return _context.onShippingOptionChange(true); 308 }) 309 .then(function () { 310 return _handlePaymentRequest(event.paymentMethod.id); 311 }) 312 .then(function () { 313 event.complete('success'); 314 }) 315 .catch(function (e) { 316 event.complete('fail'); 317 318 throw e; 319 }); 320 }); 321 322 paymentRequest.on('cancel', function () { 323 console.info('event:cancel', 'reset', 'billingAddress'); 324 325 _context.resetBillingAddress(); 326 _context.onBillingChange(false); 327 328 console.info('event:cancel', 'reset', 'shippingOptionId'); 329 330 _context.setShippingOptionId(null); 331 332 _context.onShippingOptionChange(false).then(function () { 333 console.info('event:cancel', 'reset', 'shippingAddress'); 334 335 _context.resetShippingAddress(); 336 }).then(function () { 337 console.info('event:cancel', 'reset', 'shippingOptions'); 338 339 return _context.loadShippingOptions(false); 340 }).then(function () { 341 console.info('event:cancel', 'reset', 'finished'); 342 343 _state.isShown = false; 344 }); 345 }); 346 347 return paymentRequest; 348 }); 349 }; 350 351 /** 352 * @param paymentRequest {Object} 353 * @returns {Object} 354 */ 355 var _createPaymentRequestButton = function (paymentRequest) { 356 var paymentRequestButton = _context.getStripe().elements().create('paymentRequestButton', { 357 paymentRequest: paymentRequest, 358 }); 359 360 paymentRequestButton.on('click', function () { 361 console.info('event:click', 'total.amount', _context.getTotalAmount()); 362 363 var data = { 364 total: { 365 label: 'Order', 366 amount: _context.getTotalAmount(), 367 }, 368 }; 369 370 if (_context.areShippingOptionsRequired()) { 371 console.info('event:click', 'shippingOptions', _state.shippingOptions); 372 data.shippingOptions = _state.shippingOptions; 373 _state.shippingOptionId = data.shippingOptions.length ? data.shippingOptions[0].id : null; 374 console.info('event:click', 'shippingOptionId', 'first from shippingOptions', _state.shippingOptionId); 375 } 376 377 paymentRequest.update(data); 378 379 _state.isShown = true; 380 381 _context.setShippingAddress(_state.shippingAddress); 382 _context.loadShippingOptions(false).then(function () { 383 var shippingOptions = _context.getRainRequestPaymentShippingOptions(); 384 var shippingOptionId = shippingOptions.length ? shippingOptions[0].id : null; 385 386 console.info('event:click', 'shippingOptions', 'from checkout', shippingOptions); 387 console.info('event:click', 'shippingOptionId', 'first from shippingOptions', 'update checkout', shippingOptionId); 388 389 _context.setShippingOptionId(shippingOptionId); 390 391 return _context.onShippingOptionChange(false).then(function () { 392 if (shippingOptionId !== _state.shippingOptionId) { 393 console.warn('event:click', 'shippingOptionId', 'checkout value', shippingOptionId, '!==', 'modal value', _state.shippingOptionId); 394 } 395 396 var totalAmount = _context.getTotalAmount(); 397 398 if (totalAmount !== _state.total.amount) { 399 console.warn('event:click', 'total.amount', 'checkout value', totalAmount, '!==', 'modal value', _state.total.amount); 400 } 401 402 var shippingOptionIds = shippingOptions.map(function (shippingOption) { 403 return shippingOption.id; 404 }); 405 406 var isShippingOptionsSame = 407 shippingOptions.length === _state.shippingOptions.length 408 && _state.shippingOptions.every(function (shippingOption) { 409 return shippingOptionIds.some(function (shippingOptionId) { 410 return shippingOption.id === shippingOptionId; 411 }); 412 }); 413 414 if (!isShippingOptionsSame) { 415 console.warn('event:click', 'shippingOptions', 'checkout value', shippingOptions, '!==', 'modal value', _state.shippingOptions); 416 } 417 }); 418 }); 419 }); 420 421 return paymentRequestButton; 422 }; 423 424 /** 425 * @returns {Promise<void>} 426 * @private 427 */ 428 var _initPaymentRequestBtn = function () { 429 return _createPaymentRequest().then(function (paymentRequest) { 430 var paymentRequestButton = _createPaymentRequestButton(paymentRequest); 431 432 return paymentRequest.canMakePayment().then(function (result) { 433 if (result) { 434 _context.showPaymentRequestButton(); 435
436 paymentRequestButton.mount('#' + _context.getPaymentRequestButtonId()); 437 } 438 }); 439 }); 440 }; 441 442 /** 443 * @returns {Promise<void>} 444 */ 445 this.init = function () { 446 if (!_context.isEnabled()) { 447 return Promise.resolve(); 448 } 449 450 return _initPaymentRequestBtn(); 451 }; 452};
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.