mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
Add Stripe form and duplicate Stripe Elements in backend Angular app
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
angular.module("admin.payments").controller "PaymentCtrl", ($scope, Payment, Loading) ->
|
||||
$scope.form_data = Payment.form_data
|
||||
$scope.submitted = false
|
||||
|
||||
$scope.submitPayment = () ->
|
||||
return false if $scope.submitted == true
|
||||
$scope.submitted = true
|
||||
Loading.message = t("submitting_payment")
|
||||
Payment.purchase()
|
||||
@@ -0,0 +1,35 @@
|
||||
angular.module("admin.payments").directive "stripeElements", ($injector, StripeElements) ->
|
||||
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
|
||||
|
||||
StripeElements.stripe = stripe
|
||||
StripeElements.card = card
|
||||
1
app/assets/javascripts/admin/payments/payments.js.coffee
Normal file
1
app/assets/javascripts/admin/payments/payments.js.coffee
Normal file
@@ -0,0 +1 @@
|
||||
angular.module("admin.payments", ['OfnStripe','Loading','RailsFlashLoader','ngResource','admin.resources', 'ofn.admin','Navigation'])
|
||||
@@ -0,0 +1,47 @@
|
||||
angular.module('admin.payments').factory 'Payment', (StripeElements, currentOrderNumber, paymentMethods, PaymentMethods, PaymentResource, Navigation, RailsFlashLoader)->
|
||||
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'
|
||||
StripeElements.requestToken(@form_data, @submit)
|
||||
else
|
||||
@submit()
|
||||
|
||||
submit: =>
|
||||
munged = @preprocess()
|
||||
PaymentResource.create({order_id: munged.order_id}, munged, (response, headers, status)=>
|
||||
Navigation.go "/admin/orders/" + munged.order_id + "/payments"
|
||||
, (response) ->
|
||||
RailsFlashLoader.loadFlash({error: t("error saving payment")})
|
||||
)
|
||||
@@ -0,0 +1,47 @@
|
||||
angular.module("admin.payments").factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) ->
|
||||
new class StripeElements
|
||||
# TODO: add locale here for translations of error messages etc. from Stripe
|
||||
|
||||
# These are both set from the StripeElements directive
|
||||
stripe: null
|
||||
card: null
|
||||
|
||||
# New Stripe Elements method
|
||||
requestToken: (secrets, submit, loading_message = t("processing_payment")) ->
|
||||
return unless @stripe? && @card?
|
||||
|
||||
Loading.message = loading_message
|
||||
cardData = @makeCardData(secrets)
|
||||
|
||||
@stripe.createToken(@card, cardData).then (response) =>
|
||||
if(response.error)
|
||||
Loading.clear()
|
||||
RailsFlashLoader.loadFlash({error: t("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) ->
|
||||
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
|
||||
|
||||
# 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}
|
||||
@@ -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'
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
<!-- 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| %>
|
||||
@@ -0,0 +1,2 @@
|
||||
/replace 'code[erb-loud]:contains("button @order.cart?")'
|
||||
= button_tag t(:update), type: 'button', "ng-click" => "submitPayment()"
|
||||
@@ -2,7 +2,7 @@
|
||||
<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', "ng-init" => "form_data.amount=#{@order.outstanding_balance}" %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="omega nine columns">
|
||||
@@ -12,7 +12,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>
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
-# = 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')
|
||||
= admin_inject_json "admin.payments", "railsFlash", "flash"
|
||||
= admin_inject_json "admin.payments", "currentOrderNumber", @order.number
|
||||
= admin_inject_json_ams_array "admin.payments", "paymentMethods", @payment_methods, Api::PaymentMethodSerializer
|
||||
.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'}
|
||||
%stripe-elements
|
||||
|
||||
Reference in New Issue
Block a user