Skip to content

Commit

Permalink
Merge pull request openfoodfoundation#2420 from stveep/stripe-admin-2
Browse files Browse the repository at this point in the history
Stripe admin 2
  • Loading branch information
mkllnk authored Aug 30, 2018
2 parents d1f7828 + 17f2ba4 commit 1b88ede
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 18 deletions.
1 change: 1 addition & 0 deletions app/assets/javascripts/admin/all.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
//= require ./orders/orders
//= require ./order_cycles/order_cycles
//= require ./payment_methods/payment_methods
//= require ./payments/payments
//= require ./product_import/product_import
//= require ./products/products
//= require ./resources/resources
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
angular.module("admin.payments").controller "PaymentCtrl", ($scope, Payment, StatusMessage) ->
$scope.form_data = Payment.form_data
$scope.submitted = false
$scope.StatusMessage = StatusMessage

$scope.submitPayment = () ->
return false if $scope.submitted
$scope.submitted = true
StatusMessage.display 'progress', t("spree.admin.payments.source_forms.stripe.submitting_payment")
Payment.purchase()
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
angular.module('admin.payments').directive "stripeElements", ($injector, AdminStripeElements) ->
restrict: 'E'
template: "<label for='card-element'>\
<div id='card-element'></div>\
<div id='card-errors' class='error'></div>\
</label>"

link: (scope, elem, attr)->
if $injector.has('stripeObject')
stripe = $injector.get('stripeObject')

card = stripe.elements().create 'card',
hidePostalCode: false
style:
base:
fontFamily: "Roboto, Arial, sans-serif"
fontSize: '16px'
color: '#5c5c5c'
'::placeholder':
color: '#6c6c6c'
card.mount('#card-element')

# Elements validates user input as it is typed. To help your customers
# catch mistakes, you should listen to change events on the card Element
# and display any errors:
card.addEventListener 'change', (event) ->
displayError = document.getElementById('card-errors')
if event.error
displayError.textContent = event.error.message
else
displayError.textContent = ''

return

AdminStripeElements.stripe = stripe
AdminStripeElements.card = card
1 change: 1 addition & 0 deletions app/assets/javascripts/admin/payments/payments.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
angular.module("admin.payments", ['ofn.admin'])
47 changes: 47 additions & 0 deletions app/assets/javascripts/admin/payments/services/payment.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
angular.module('admin.payments').factory 'Payment', (AdminStripeElements, currentOrderNumber, paymentMethods, PaymentMethods, PaymentResource, StatusMessage, $window)->
new class Payment
order: currentOrderNumber
form_data: {}

paymentMethodType: ->
PaymentMethods.byID[@form_data.payment_method].method_type

preprocess: ->
munged_payment = {}
munged_payment["payment"] = {payment_method_id: @form_data.payment_method, amount: @form_data.amount}
munged_payment["order_id"] = @order
# Not tested with Gateway other than Stripe. Could fall back to Rails for this?
# Works ok without extra source_attrs for Cash, Bank Transfer etc.
switch @paymentMethodType()
when 'gateway'
angular.extend munged_payment.payment, {
source_attributes:
number: @form_data.card_number
month: @form_data.card_month
year: @form_data.card_year
verification_value: @form_data.card_verification_value
}
when 'stripe'
angular.extend munged_payment.payment, {
source_attributes:
gateway_payment_profile_id: @form_data.token
cc_type: @form_data.cc_type
last_digits: @form_data.card.last4
month: @form_data.card.exp_month
year: @form_data.card.exp_year
}
munged_payment

purchase: ->
if @paymentMethodType() == 'stripe'
AdminStripeElements.requestToken(@form_data, @submit)
else
@submit()

submit: =>
munged = @preprocess()
PaymentResource.create({order_id: munged.order_id}, munged, (response, headers, status)=>
$window.location.pathname = "/admin/orders/" + munged.order_id + "/payments"
, (response) ->
StatusMessage.display 'error', t("spree.admin.payments.source_forms.stripe.error_saving_payment")
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
angular.module("admin.payments").factory 'AdminStripeElements', ($rootScope, StatusMessage) ->
new class AdminStripeElements

# These are both set from the AdminStripeElements directive
stripe: null
card: null

# New Stripe Elements method
requestToken: (secrets, submit) ->
return unless @stripe? && @card?

cardData = @makeCardData(secrets)

@stripe.createToken(@card, cardData).then (response) =>
if(response.error)
StatusMessage.display 'error', response.error.message
else
secrets.token = response.token.id
secrets.cc_type = @mapCC(response.token.card.brand)
secrets.card = response.token.card
submit()

# Maps the brand returned by Stripe to that required by activemerchant
mapCC: (ccType) ->
switch ccType
when 'MasterCard' then return 'master'
when 'Visa' then return 'visa'
when 'American Express' then return 'american_express'
when 'Discover' then return 'discover'
when 'JCB' then return 'jcb'
when 'Diners Club' then return 'diners_club'

# It doesn't matter if any of these are nil, all are optional.
makeCardData: (secrets) ->
{'name': secrets.name,
'address1': secrets.address1,
'city': secrets.city,
'zipcode': secrets.zipcode}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
angular.module("admin.resources").factory 'PaymentResource', ($resource) ->
$resource('/admin/orders/:order_id/payments.json', {order_id: "@order_id"}, {
'create':
method: 'POST'
})
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,13 @@ Darkswarm.factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->

# Maps the brand returned by Stripe to that required by activemerchant
mapCC: (ccType) ->
if ccType == 'MasterCard'
return 'master'
else if ccType == 'Visa'
return 'visa'
else if ccType == 'American Express'
return 'american_express'
else if ccType == 'Discover'
return 'discover'
else if ccType == 'JCB'
return 'jcb'
else if ccType == 'Diners Club'
return 'diners_club'
return
switch ccType
when 'MasterCard' then return 'master'
when 'Visa' then return 'visa'
when 'American Express' then return 'american_express'
when 'Discover' then return 'discover'
when 'JCB' then return 'jcb'
when 'Diners Club' then return 'diners_club'

# It doesn't matter if any of these are nil, all are optional.
makeCardData: (secrets) ->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/replace 'code[erb-loud]:contains("form_for @payment")'
= form_for @payment, :url => admin_order_payments_path(@order), :html => {"ng-app" => "admin.payments", "ng-controller" => "PaymentCtrl"} do |f|
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/ insert_before "fieldset.no-border-top"
%save-bar{ persist: "true" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/replace 'code[erb-loud]:contains("button @order.cart?")'
= button_tag t(:update), type: 'button', "ng-click" => "submitPayment()"
7 changes: 5 additions & 2 deletions app/views/spree/admin/payments/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<%= admin_inject_json "admin.payments", "currentOrderNumber", @order.number %>
<%= admin_inject_json_ams_array "admin.payments", "paymentMethods", @payment_methods, Api::PaymentMethodSerializer %>

<div data-hook="admin_payment_form_fields" class="row">
<div class="alpha three columns">
<div class="field">
<%= f.label :amount, t(:amount) %>
<%= f.text_field :amount, :value => @order.outstanding_balance, :class => 'fullwidth' %>
<%= f.text_field :amount, :value => @order.outstanding_balance, :class => 'fullwidth', "watch-value-as" => 'form_data.amount' %>
</div>
</div>
<div class="omega nine columns">
Expand All @@ -12,7 +15,7 @@
<% @payment_methods.each do |method| %>
<li>
<label data-hook="payment_method_field">
<%= radio_button_tag 'payment[payment_method_id]', method.id, method == @payment_method, { class: "payment_methods_radios" } %>
<%= radio_button_tag 'payment[payment_method_id]', method.id, method == @payment_method, { class: "payment_methods_radios", "ng-model" => 'form_data.payment_method' } %>
<%= t(method.name, :scope => :payment_methods, :default => method.name) %>
</label>
</li>
Expand Down
17 changes: 15 additions & 2 deletions app/views/spree/admin/payments/source_forms/_stripe.html.haml
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
-# = render "spree/admin/payments/source_forms/gateway", payment_method: payment_method
.stripe
%script{:src => "https://js.stripe.com/v3/", :type => "text/javascript"}
- if Stripe.publishable_key
:javascript
angular.module('admin.payments').value("stripeObject", Stripe("#{Stripe.publishable_key}"))

%strong
= t('.no_payment_via_admin_backend')
.row
.three.columns
= label_tag :cardholder_name, t(:cardholder_name)
.six.columns
= text_field_tag :cardholder_name, nil, {size: 40, "ng-model" => 'form_data.name'}
.row
.three.columns
= label_tag :card_details, t(:card_details)
.six.columns
%stripe-elements
3 changes: 2 additions & 1 deletion config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2613,7 +2613,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using
payments:
source_forms:
stripe:
no_payment_via_admin_backend: Creating Stripe-based payments from the admin backend is not possible at this time
error_saving_payment: Error saving payment
submitting_payment: Submitting payment...
products:
new:
title: 'New Product'
Expand Down

0 comments on commit 1b88ede

Please sign in to comment.