130 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			130 lines
		
	
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								// License: LGPL-3.0-or-later
							 | 
						||
| 
								 | 
							
								// Include the cards/fields partial to use with this.
							 | 
						||
| 
								 | 
							
								// Call appl.card_form.create(card_obj) to start the card creation process.
							 | 
						||
| 
								 | 
							
								// Use the appl.card_form.on_fail callback to handle failures.
							 | 
						||
| 
								 | 
							
								// Use the appl.card_form.on_complete callback to handle completion.
							 | 
						||
| 
								 | 
							
								// This does not create any donations -- do the donation creation inside appl.card_form.on_complete.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Not namespacing card_form; only show one card form on the page at any time
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var request = require('../common/super-agent-promise')
							 | 
						||
| 
								 | 
							
								var format_err = require('../common/format_response_error')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								module.exports = create_card
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// UI state defaults
							 | 
						||
| 
								 | 
							
								appl.def('card_form', {
							 | 
						||
| 
								 | 
							
									loading: false,
							 | 
						||
| 
								 | 
							
									error: false,
							 | 
						||
| 
								 | 
							
									status: '',
							 | 
						||
| 
								 | 
							
									on_complete: function() {},
							 | 
						||
| 
								 | 
							
									on_fail: function() {},
							 | 
						||
| 
								 | 
							
									progress_width: '0%' // Width of the progress bar
							 | 
						||
| 
								 | 
							
								})
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Define some status messages and progress bar widths for each step of the process
							 | 
						||
| 
								 | 
							
								var statuses = {
							 | 
						||
| 
								 | 
							
									before_tokenization: {
							 | 
						||
| 
								 | 
							
										progress_width: '20%',
							 | 
						||
| 
								 | 
							
										status: 'Double-checking your card...'
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									before_create: {
							 | 
						||
| 
								 | 
							
										progress_width: '75%',
							 | 
						||
| 
								 | 
							
										status: 'Looks good! Sending the carrier pigeons...'
							 | 
						||
| 
								 | 
							
									},
							 | 
						||
| 
								 | 
							
									on_complete: {
							 | 
						||
| 
								 | 
							
											progress_width: '100%',
							 | 
						||
| 
								 | 
							
											status: 'Processing payment...'
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Tokenize with stripe, then save to our db.
							 | 
						||
| 
								 | 
							
								// The first argument must be a holder object that has 'type' and 'id' keys.
							 | 
						||
| 
								 | 
							
								// eg: {holder: {type: 'Nonprofit', id: 1}}
							 | 
						||
| 
								 | 
							
								function create_card(holder, card_obj, options) {
							 | 
						||
| 
								 | 
							
								  options = options || {}
							 | 
						||
| 
								 | 
							
									if(appl.card_form.loading) return
							 | 
						||
| 
								 | 
							
									appl.def('card_form', { loading: true, error: false })
							 | 
						||
| 
								 | 
							
									appl.def('card_form', statuses.before_tokenization)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Delete the cvc key from card_obj if
							 | 
						||
| 
								 | 
							
								  // the value of cvc is a blank string.
							 | 
						||
| 
								 | 
							
								  // Otherwise, Stripe will return an error for
							 | 
						||
| 
								 | 
							
								  // incorrect security code.
							 | 
						||
| 
								 | 
							
								  if(card_obj.cvc === '') {
							 | 
						||
| 
								 | 
							
								    delete card_obj['cvc']
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// First, tokenize the card with Stripe.js
							 | 
						||
| 
								 | 
							
									return tokenize_with_stripe(card_obj)
							 | 
						||
| 
								 | 
							
										.catch(display_stripe_err)
							 | 
						||
| 
								 | 
							
										// Then, save a Card record in our db
							 | 
						||
| 
								 | 
							
										.then(function(stripe_resp) {
							 | 
						||
| 
								 | 
							
											appl.def('card_form', statuses.before_create)
							 | 
						||
| 
								 | 
							
											return create_record(holder, stripe_resp, options)
							 | 
						||
| 
								 | 
							
										})
							 | 
						||
| 
								 | 
							
										.then(function(resp) {
							 | 
						||
| 
								 | 
							
											appl.def('card_form', statuses.on_complete)
							 | 
						||
| 
								 | 
							
											return resp.body
							 | 
						||
| 
								 | 
							
										})
							 | 
						||
| 
								 | 
							
										.catch(display_err)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Post to stripe to get back a stripe_card_token
							 | 
						||
| 
								 | 
							
								function tokenize_with_stripe(card_obj) {
							 | 
						||
| 
								 | 
							
									return new Promise(function(resolve, reject) {
							 | 
						||
| 
								 | 
							
										Stripe.card.createToken(card_obj, function(status, resp) {
							 | 
						||
| 
								 | 
							
											if(resp.error) reject(resp)
							 | 
						||
| 
								 | 
							
											else resolve(resp)
							 | 
						||
| 
								 | 
							
										})
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Save a record of the card in our own db
							 | 
						||
| 
								 | 
							
								function create_record(holder, stripe_resp, options={}) {
							 | 
						||
| 
								 | 
							
									var output = {card: {
							 | 
						||
| 
								 | 
							
								            holder_type: holder.type,
							 | 
						||
| 
								 | 
							
								            holder_id: holder.id,
							 | 
						||
| 
								 | 
							
								            email: holder.email,
							 | 
						||
| 
								 | 
							
								            cardholders_name: stripe_resp.name,
							 | 
						||
| 
								 | 
							
								            name: stripe_resp.card.brand + ' *' + stripe_resp.card.last4,
							 | 
						||
| 
								 | 
							
								            stripe_card_token: stripe_resp.id,
							 | 
						||
| 
								 | 
							
								            stripe_card_id: stripe_resp.card.id
							 | 
						||
| 
								 | 
							
								        }}
							 | 
						||
| 
								 | 
							
									if (options['event_id'])
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										output['event_id'] = options['event_id']
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return request.post(options.path || '/cards')
							 | 
						||
| 
								 | 
							
										.send(output)
							 | 
						||
| 
								 | 
							
										.perform()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Set UI state to display an error in the card form.
							 | 
						||
| 
								 | 
							
								function display_err(resp) {
							 | 
						||
| 
								 | 
							
								  if(resp && resp.body) {
							 | 
						||
| 
								 | 
							
								    appl.def('card_form', {
							 | 
						||
| 
								 | 
							
								      loading: false,
							 | 
						||
| 
								 | 
							
								      error: true,
							 | 
						||
| 
								 | 
							
								      status: format_err(resp),
							 | 
						||
| 
								 | 
							
								      progress_width: '0%'
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								    appl.def('loading', false)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function display_stripe_err(resp) {
							 | 
						||
| 
								 | 
							
								  if(resp && resp.error) {
							 | 
						||
| 
								 | 
							
								    appl.def('card_form', {
							 | 
						||
| 
								 | 
							
								      loading: false,
							 | 
						||
| 
								 | 
							
								      error: true,
							 | 
						||
| 
								 | 
							
								      status: resp.error.message,
							 | 
						||
| 
								 | 
							
								      progress_width: '0%'
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
										appl.def('loading', false)
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										throw new Error()
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |