mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Creating basic angular StripeJS wrapper service for requesting tokens
This commit is contained in:
@@ -22,6 +22,6 @@ Darkswarm.controller "CheckoutCtrl", ($scope, localStorageService, Checkout, Cur
|
||||
event.preventDefault()
|
||||
$scope.submitted = true
|
||||
if form.$valid
|
||||
$scope.Checkout.submit()
|
||||
$scope.Checkout.purchase()
|
||||
else
|
||||
$scope.$broadcast 'purchaseFormInvalid', form
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $http, Navigation, CurrentHub, RailsFlashLoader, Loading)->
|
||||
Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeJS, PaymentMethods, $http, Navigation, CurrentHub, RailsFlashLoader, Loading)->
|
||||
new class Checkout
|
||||
errors: {}
|
||||
secrets: {}
|
||||
order: CurrentOrder.order
|
||||
|
||||
submit: ->
|
||||
purchase: ->
|
||||
if @paymentMethod()?.method_type == 'stripe'
|
||||
StripeJS.requestToken(@secrets, @submit)
|
||||
else
|
||||
@submit()
|
||||
|
||||
submit: =>
|
||||
Loading.message = t 'submitting_order'
|
||||
$http.put('/checkout', {order: @preprocess()}).success (data, status)=>
|
||||
Navigation.go data.path
|
||||
@@ -53,6 +59,16 @@ Darkswarm.factory 'Checkout', (CurrentOrder, ShippingMethods, PaymentMethods, $h
|
||||
last_name: @order.bill_address.lastname
|
||||
}
|
||||
|
||||
if @paymentMethod()?.method_type == 'stripe'
|
||||
angular.extend munged_order.payments_attributes[0], {
|
||||
source_attributes:
|
||||
gateway_payment_profile_id: @secrets.token
|
||||
cc_type: @secrets.cc_type
|
||||
last_digits: @secrets.card.last4
|
||||
month: @secrets.card.exp_month
|
||||
year: @secrets.card.exp_year
|
||||
}
|
||||
|
||||
munged_order
|
||||
|
||||
shippingMethod: ->
|
||||
|
||||
36
app/assets/javascripts/darkswarm/services/stripe.js.coffee
Normal file
36
app/assets/javascripts/darkswarm/services/stripe.js.coffee
Normal file
@@ -0,0 +1,36 @@
|
||||
Darkswarm.factory 'StripeJS', ($rootScope, Loading, RailsFlashLoader) ->
|
||||
new class StripeJS
|
||||
requestToken: (secrets, submit) ->
|
||||
Loading.message = "Processing Payment..."
|
||||
params =
|
||||
number: secrets.card_number
|
||||
cvc: secrets.card_verification_value
|
||||
exp_month: secrets.card_month or 0
|
||||
exp_year: secrets.card_year or 0
|
||||
|
||||
# This is the global Stripe object created by Stripe.js, included in the _stripe partial
|
||||
Stripe.card.createToken params, (status, response) =>
|
||||
if response.error
|
||||
$rootScope.$apply ->
|
||||
Loading.clear()
|
||||
RailsFlashLoader.loadFlash({error: "Error: #{response.error.message}"})
|
||||
else
|
||||
secrets.token = response['id']
|
||||
secrets.cc_type = @mapCC(response.card.brand)
|
||||
secrets.card = response.card
|
||||
submit()
|
||||
|
||||
mapCC: (ccType) ->
|
||||
if ccType == 'MasterCard'
|
||||
return 'mastercard'
|
||||
else if ccType == 'Visa'
|
||||
return 'visa'
|
||||
else if ccType == 'American Express'
|
||||
return 'amex'
|
||||
else if ccType == 'Discover'
|
||||
return 'discover'
|
||||
else if ccType == 'Diners Club'
|
||||
return 'dinersclub'
|
||||
else if ccType == 'JCB'
|
||||
return 'jcb'
|
||||
return
|
||||
@@ -16,6 +16,7 @@ describe "CheckoutCtrl", ->
|
||||
$provide.value "CurrentHub", CurrentHubMock
|
||||
null
|
||||
Checkout =
|
||||
purchase: ->
|
||||
submit: ->
|
||||
navigate: ->
|
||||
bindFieldsToLocalStorage: ->
|
||||
@@ -42,17 +43,17 @@ describe "CheckoutCtrl", ->
|
||||
preventDefault: ->
|
||||
|
||||
beforeEach ->
|
||||
spyOn(Checkout, "submit")
|
||||
spyOn(Checkout, "purchase")
|
||||
scope.submitted = false
|
||||
|
||||
it "delegates to the service when valid", ->
|
||||
scope.purchase(event, {$valid: true})
|
||||
expect(Checkout.submit).toHaveBeenCalled()
|
||||
expect(Checkout.purchase).toHaveBeenCalled()
|
||||
expect(scope.submitted).toBe(true)
|
||||
|
||||
it "does nothing when invalid", ->
|
||||
scope.purchase(event, {$valid: false})
|
||||
expect(Checkout.submit).not.toHaveBeenCalled()
|
||||
expect(Checkout.purchase).not.toHaveBeenCalled()
|
||||
expect(scope.submitted).toBe(true)
|
||||
|
||||
it "is enabled", ->
|
||||
|
||||
@@ -15,6 +15,11 @@ describe 'Checkout service', ->
|
||||
id: 123
|
||||
test: "bar"
|
||||
method_type: "check"
|
||||
},
|
||||
{
|
||||
id: 666
|
||||
test: "qux"
|
||||
method_type: "stripe"
|
||||
}]
|
||||
shippingMethods = [
|
||||
{
|
||||
@@ -46,6 +51,7 @@ describe 'Checkout service', ->
|
||||
$provide.value "currentOrder", orderData
|
||||
$provide.value "shippingMethods", shippingMethods
|
||||
$provide.value "paymentMethods", paymentMethods
|
||||
$provide.value "StripeInstancePublishableKey", "instance_publishable_key"
|
||||
null
|
||||
|
||||
inject ($injector, _$httpBackend_, $rootScope)->
|
||||
@@ -83,31 +89,41 @@ describe 'Checkout service', ->
|
||||
Checkout.order.payment_method_id = 99
|
||||
expect(Checkout.paymentMethod()).toEqual paymentMethods[0]
|
||||
|
||||
it "Posts the Checkout to the server", ->
|
||||
$httpBackend.expectPUT("/checkout", {order: Checkout.preprocess()}).respond 200, {path: "test"}
|
||||
Checkout.submit()
|
||||
$httpBackend.flush()
|
||||
|
||||
describe "when there is an error", ->
|
||||
it "redirects when a redirect is given", ->
|
||||
$httpBackend.expectPUT("/checkout").respond 400, {path: 'path'}
|
||||
describe "submitting", ->
|
||||
it "Posts the Checkout to the server", ->
|
||||
$httpBackend.expectPUT("/checkout", {order: Checkout.preprocess()}).respond 200, {path: "test"}
|
||||
Checkout.submit()
|
||||
$httpBackend.flush()
|
||||
expect(Navigation.go).toHaveBeenCalledWith 'path'
|
||||
|
||||
it "sends flash messages to the flash service", ->
|
||||
spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location
|
||||
$httpBackend.expectPUT("/checkout").respond 400, {flash: {error: "frogs"}}
|
||||
Checkout.submit()
|
||||
describe "when there is an error", ->
|
||||
it "redirects when a redirect is given", ->
|
||||
$httpBackend.expectPUT("/checkout").respond 400, {path: 'path'}
|
||||
Checkout.submit()
|
||||
$httpBackend.flush()
|
||||
expect(Navigation.go).toHaveBeenCalledWith 'path'
|
||||
|
||||
$httpBackend.flush()
|
||||
expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith {error: "frogs"}
|
||||
it "sends flash messages to the flash service", ->
|
||||
spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location
|
||||
$httpBackend.expectPUT("/checkout").respond 400, {flash: {error: "frogs"}}
|
||||
Checkout.submit()
|
||||
|
||||
it "puts errors into the scope", ->
|
||||
$httpBackend.expectPUT("/checkout").respond 400, {errors: {error: "frogs"}}
|
||||
Checkout.submit()
|
||||
$httpBackend.flush()
|
||||
expect(Checkout.errors).toEqual {error: "frogs"}
|
||||
$httpBackend.flush()
|
||||
expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith {error: "frogs"}
|
||||
|
||||
it "puts errors into the scope", ->
|
||||
$httpBackend.expectPUT("/checkout").respond 400, {errors: {error: "frogs"}}
|
||||
Checkout.submit()
|
||||
$httpBackend.flush()
|
||||
expect(Checkout.errors).toEqual {error: "frogs"}
|
||||
|
||||
describe "when using the Stripe Connect gateway", ->
|
||||
beforeEach inject ($injector, StripeJS) ->
|
||||
Checkout.order.payment_method_id = 666
|
||||
|
||||
it "requests a Stripe token before submitting", inject (StripeJS) ->
|
||||
spyOn(StripeJS, "requestToken")
|
||||
Checkout.purchase()
|
||||
expect(StripeJS.requestToken).toHaveBeenCalled()
|
||||
|
||||
describe "data preprocessing", ->
|
||||
beforeEach ->
|
||||
@@ -155,3 +171,23 @@ describe 'Checkout service', ->
|
||||
Checkout.order.payment_method_id = 123
|
||||
source_attributes = Checkout.preprocess().payments_attributes[0].source_attributes
|
||||
expect(source_attributes).not.toBeDefined()
|
||||
|
||||
describe "when the payment method is the Stripe Connect gateway", ->
|
||||
beforeEach ->
|
||||
Checkout.order.payment_method_id = 666
|
||||
Checkout.secrets =
|
||||
token: "stripe_token"
|
||||
cc_type: "mastercard"
|
||||
card:
|
||||
last4: "1234"
|
||||
exp_year: "2099"
|
||||
exp_month: "10"
|
||||
|
||||
it "creates source attributes for the submitted card", ->
|
||||
source_attributes = Checkout.preprocess().payments_attributes[0].source_attributes
|
||||
expect(source_attributes).toBeDefined()
|
||||
expect(source_attributes.gateway_payment_profile_id).toBe "stripe_token"
|
||||
expect(source_attributes.cc_type).toBe "mastercard"
|
||||
expect(source_attributes.last_digits).toBe "1234"
|
||||
expect(source_attributes.year).toBe "2099"
|
||||
expect(source_attributes.month).toBe "10"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
describe 'StripeJS Service', ->
|
||||
$httpBackend = StripeJS = null
|
||||
StripeMock = { card: {} }
|
||||
|
||||
beforeEach ->
|
||||
module 'Darkswarm'
|
||||
module ($provide) ->
|
||||
$provide.value "railsFlash", null
|
||||
null
|
||||
|
||||
inject (_StripeJS_, _$httpBackend_) ->
|
||||
$httpBackend = _$httpBackend_
|
||||
StripeJS = _StripeJS_
|
||||
|
||||
describe "requestToken", ->
|
||||
secrets = {}
|
||||
submit = null
|
||||
response = null
|
||||
|
||||
beforeEach inject ($window) ->
|
||||
$window.Stripe = StripeMock
|
||||
|
||||
describe "with satifactory data", ->
|
||||
beforeEach ->
|
||||
submit = jasmine.createSpy()
|
||||
response = { id: "token", card: { brand: 'MasterCard', last4: "5678", exp_month: 10, exp_year: 2099 } }
|
||||
StripeMock.card.createToken = (params, callback) => callback(200, response)
|
||||
|
||||
it "saves the response data to secrets, and submits the form", ->
|
||||
StripeJS.requestToken(secrets, submit)
|
||||
expect(secrets.token).toEqual "token"
|
||||
expect(secrets.cc_type).toEqual "mastercard"
|
||||
expect(submit).toHaveBeenCalled()
|
||||
|
||||
describe "with unsatifactory data", ->
|
||||
beforeEach ->
|
||||
submit = jasmine.createSpy()
|
||||
response = { id: "token", error: { message: 'There was a problem' } }
|
||||
StripeMock.card.createToken = (params, callback) => callback(400, response)
|
||||
|
||||
it "doesn't submit the form, shows an error message instead", inject (Loading, RailsFlashLoader) ->
|
||||
spyOn(Loading, "clear")
|
||||
spyOn(RailsFlashLoader, "loadFlash")
|
||||
StripeJS.requestToken(secrets, submit)
|
||||
expect(submit).not.toHaveBeenCalled()
|
||||
expect(Loading.clear).toHaveBeenCalled()
|
||||
expect(RailsFlashLoader.loadFlash).toHaveBeenCalledWith({error: "Error: There was a problem"})
|
||||
Reference in New Issue
Block a user