From 1449169b16b862ef84fc7c4ec49b4e1490cf78c1 Mon Sep 17 00:00:00 2001 From: stveep Date: Mon, 1 May 2017 11:03:23 +0100 Subject: [PATCH] Basic UI for adding credit card details and getting a Stripe token without making a payment --- .../checkout/payment_controller.js.coffee | 19 +------ .../credit_cards_controller.js.coffee | 25 ++++++++ .../darkswarm/services/credit_card.js.coffee | 16 ++++++ .../darkswarm/services/dates.js.coffee | 18 ++++++ .../darkswarm/services/stripe.js.coffee | 6 +- .../spree/users_controller_decorator.rb | 7 +++ app/models/spree/credit_card_decorator.rb | 2 + .../spree/checkout/payment/_gateway.html.haml | 5 +- app/views/spree/users/show.html.haml | 57 +++++++++++++++++++ 9 files changed, 134 insertions(+), 21 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/controllers/credit_cards_controller.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/credit_card.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/dates.js.coffee diff --git a/app/assets/javascripts/darkswarm/controllers/checkout/payment_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/checkout/payment_controller.js.coffee index bf062cbb83..236bf5fb14 100644 --- a/app/assets/javascripts/darkswarm/controllers/checkout/payment_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/checkout/payment_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "PaymentCtrl", ($scope, $timeout, savedCreditCards) -> +Darkswarm.controller "PaymentCtrl", ($scope, $timeout, savedCreditCards, Dates) -> angular.extend(this, new FieldsetMixin($scope)) defaultCard = [ {id: null, formatted: t("new_credit_card")} ] $scope.savedCreditCards = defaultCard.concat savedCreditCards if savedCreditCards @@ -7,22 +7,9 @@ Darkswarm.controller "PaymentCtrl", ($scope, $timeout, savedCreditCards) -> $scope.name = "payment" - $scope.months = [ - {key: t("january"), value: "1"}, - {key: t("february"), value: "2"}, - {key: t("march"), value: "3"}, - {key: t("april"), value: "4"}, - {key: t("may"), value: "5"}, - {key: t("june"), value: "6"}, - {key: t("july"), value: "7"}, - {key: t("august"), value: "8"}, - {key: t("september"), value: "9"}, - {key: t("october"), value: "10"}, - {key: t("november"), value: "11"}, - {key: t("december"), value: "12"}, - ] + $scope.months = Dates.months - $scope.years = [moment().year()..(moment().year()+15)] + $scope.years = Dates.years $scope.secrets.card_month = "1" $scope.secrets.card_year = moment().year() diff --git a/app/assets/javascripts/darkswarm/controllers/credit_cards_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/credit_cards_controller.js.coffee new file mode 100644 index 0000000000..17193cfd5a --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/credit_cards_controller.js.coffee @@ -0,0 +1,25 @@ +Darkswarm.controller "CreditCardsCtrl", ($scope, $timeout, CreditCard, savedCreditCards, StripeJS, Dates, Loading) -> + angular.extend(this, new FieldsetMixin($scope)) + $scope.savedCreditCards = savedCreditCards + $scope.CreditCard = CreditCard + $scope.allow_name_change = true + $scope.disable_fields = false + + $scope.months = Dates.months + $scope.years = Dates.years + + $scope.secrets = CreditCard.secrets + + + + $scope.storeCard = => + Loading.message = "Saving" + CreditCard.requestToken($scope.secrets) + + + + + + # Need to call Spree::Gateway::StripeConnect#provider.store(creditcard) + # creditcard should be formatted as for a payment + # The token then needs to be associated with the Customer (in Stripe) - can be done in Ruby. diff --git a/app/assets/javascripts/darkswarm/services/credit_card.js.coffee b/app/assets/javascripts/darkswarm/services/credit_card.js.coffee new file mode 100644 index 0000000000..e5aeec61fc --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/credit_card.js.coffee @@ -0,0 +1,16 @@ +Darkswarm.factory 'CreditCard', ($injector, $rootScope, StripeJS, Navigation, $http, RailsFlashLoader, Loading)-> + new class CreditCard + errors: {} + + requestToken: (secrets) -> + #$scope.secrets.name = $scope.secrets.first_name + " " + $scope.secrets.last_name + secrets.name = @full_name(secrets) + StripeJS.requestToken(secrets, @submit) + + submit: => + $rootScope.$apply -> + Loading.clear() + Navigation.go '/account' + + full_name: (secrets) -> + secrets.first_name + " " + secrets.last_name diff --git a/app/assets/javascripts/darkswarm/services/dates.js.coffee b/app/assets/javascripts/darkswarm/services/dates.js.coffee new file mode 100644 index 0000000000..d9a0b6e8c4 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/dates.js.coffee @@ -0,0 +1,18 @@ +Darkswarm.factory "Dates", -> + new class Dates + months: [ + {key: t("january"), value: "1"}, + {key: t("february"), value: "2"}, + {key: t("march"), value: "3"}, + {key: t("april"), value: "4"}, + {key: t("may"), value: "5"}, + {key: t("june"), value: "6"}, + {key: t("july"), value: "7"}, + {key: t("august"), value: "8"}, + {key: t("september"), value: "9"}, + {key: t("october"), value: "10"}, + {key: t("november"), value: "11"}, + {key: t("december"), value: "12"}, + ] + + years: [moment().year()..(moment().year()+15)] diff --git a/app/assets/javascripts/darkswarm/services/stripe.js.coffee b/app/assets/javascripts/darkswarm/services/stripe.js.coffee index 706be74300..01fc54a30f 100644 --- a/app/assets/javascripts/darkswarm/services/stripe.js.coffee +++ b/app/assets/javascripts/darkswarm/services/stripe.js.coffee @@ -1,7 +1,7 @@ Darkswarm.factory 'StripeJS', ($rootScope, Loading, RailsFlashLoader) -> new class StripeJS - requestToken: (secrets, submit) -> - Loading.message = "Processing Payment..." + requestToken: (secrets, submit, loading_message = t("processing_payment")) -> + Loading.message = loading_message params = number: secrets.card_number cvc: secrets.card_verification_value @@ -13,7 +13,7 @@ Darkswarm.factory 'StripeJS', ($rootScope, Loading, RailsFlashLoader) -> if response.error $rootScope.$apply -> Loading.clear() - RailsFlashLoader.loadFlash({error: "Error: #{response.error.message}"}) + RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"}) else secrets.token = response['id'] secrets.cc_type = @mapCC(response.card.brand) diff --git a/app/controllers/spree/users_controller_decorator.rb b/app/controllers/spree/users_controller_decorator.rb index a56c59d6fa..d31ad77715 100644 --- a/app/controllers/spree/users_controller_decorator.rb +++ b/app/controllers/spree/users_controller_decorator.rb @@ -2,4 +2,11 @@ Spree::UsersController.class_eval do layout 'darkswarm' before_filter :enable_embedded_shopfront + before_filter :set_credit_card, only: :show + + private + + def set_credit_card + @credit_card = Spree::CreditCard.new(user: @user) + end end diff --git a/app/models/spree/credit_card_decorator.rb b/app/models/spree/credit_card_decorator.rb index 0744bf5da5..32c14a1285 100644 --- a/app/models/spree/credit_card_decorator.rb +++ b/app/models/spree/credit_card_decorator.rb @@ -10,4 +10,6 @@ Spree::CreditCard.class_eval do def has_payment_profile? gateway_customer_profile_id.present? || gateway_payment_profile_id.present? end + + end diff --git a/app/views/spree/checkout/payment/_gateway.html.haml b/app/views/spree/checkout/payment/_gateway.html.haml index 8fbf7dc052..b78733ee01 100644 --- a/app/views/spree/checkout/payment/_gateway.html.haml +++ b/app/views/spree/checkout/payment/_gateway.html.haml @@ -2,12 +2,13 @@ .small-6.columns %label = t :first_name - %input{type: :text, disabled: true, "ng-value" => "order.bill_address.firstname"} + -# Changing name not permitted by default (in checkout) - can be enabled by setting an allow_name_change variable in $scope + %input{type: :text, "ng-disabled" => "!allow_name_change", "ng-value" => "order.bill_address.firstname"} .small-6.columns %label = t :last_name - %input{type: :text, disabled: true, "ng-value" => "order.bill_address.lastname"} + %input{type: :text, "ng-disabled" => "!allow_name_change", "ng-value" => "order.bill_address.lastname"} .small-6.columns = validated_input t(:card_number), "secrets.card_number", "ng-required" => "!secrets.selected_card", maxlength: 19, autocomplete: "off", "ng-disabled" => "!!secrets.selected_card" diff --git a/app/views/spree/users/show.html.haml b/app/views/spree/users/show.html.haml index 8272cc9eeb..304813f9c7 100644 --- a/app/views/spree/users/show.html.haml +++ b/app/views/spree/users/show.html.haml @@ -1,5 +1,9 @@ .darkswarm = inject_orders_by_distributor + = inject_saved_credit_cards + + :javascript + Stripe.setPublishableKey("#{ENV['STRIPE_INSTANCE_PUBLISHABLE_KEY']}") .row.pad-top .small-12.columns.pad-top @@ -9,6 +13,59 @@ = @user.email (#{link_to t(:edit), spree.edit_account_path}) + %h3 + = t(:my_credit_cards) + .credit_cards{"ng-controller" => "CreditCardsCtrl"} + %h4 + = t(:saved_cards) + .row + .card_list.small-12.columns + %span{"ng-repeat" => "card in savedCreditCards"} + %span{"ng-bind" => "card.formatted"} + %h4 + = t(:add_new_credit_card) + .row + .new_card.small-12.columns + %form{novalidate: true, "ng-submit" => "storeCard()"} + -# render "spree/checkout/payment/gateway" + .row + .small-6.columns + %label + = t :first_name + -# Changing name not permitted by default (in checkout) - can be enabled by setting an allow_name_change variable in $scope + %input{type: :text, "ng-model" => "secrets.first_name","ng-disabled" => "!allow_name_change", "ng-value" => "order.bill_address.firstname"} + + .small-6.columns + %label + = t :last_name + %input{type: :text, "ng-model" => "secrets.last_name", "ng-disabled" => "!allow_name_change", "ng-value" => "order.bill_address.lastname"} + + .small-6.columns + %label + = t(:card_number) + %input{type: :text, "ng-model" => "secrets.card_number", "ng-required" => "!secrets.selected_card", maxlength: 19, autocomplete: "off", "ng-disabled" => "!!secrets.selected_card"} + .small-6.columns + %label + = t(:card_securitycode) + %input{type: :text, "ng-model" => "secrets.card_verification_value", "ng-required" => "!secrets.selected_card", autocomplete: "off", "ng-disabled" => "!!secrets.selected_card"} + + .row + .small-12.columns + %label{for: "secrets.card_month"} + = t :card_expiry_date, "ng-disabled" => "!!secrets.selected_card" + + .row + .small-6.columns + %select{"ng-model" => "secrets.card_month", "ng-options" => "currMonth.value as currMonth.key for currMonth in months", name: "secrets.card_month", "ng-required" => "!secrets.selected_card", "ng-disabled" => "!!secrets.selected_card"} + .small-6.columns + %select{"ng-model" => "secrets.card_year", "ng-options" => "year for year in years", name: "secrets.card_year", "ng-required" => "!secrets.selected_card", "ng-disabled" => "!!secrets.selected_card"} + + + %p + %button.button.primary{type: :submit} + = t :add_card + + %h3= t(:my_orders) .orders{"ng-controller" => "OrdersCtrl", "ng-cloak" => true} .my-open-orders{ ng: { show: 'Orders.changeable_orders.length > 0' } } %h3= t(:open_orders)