mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-20 09:52:19 +01:00
read stripe_currency from the UI
We prevent the currency from being changed if any stripe payment was made, because a stripe user cannot made pay with different currencies. If we try to charge a user with a different currency than the currency he used for a previous payment, this will fail; so we must prevent this case
This commit is contained in:
parent
401cf6b7ec
commit
78518e17fb
@ -17,8 +17,8 @@
|
||||
/**
|
||||
* Controller used in the admin invoices listing page
|
||||
*/
|
||||
Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'Invoice', 'AccountingPeriod', 'AuthService', 'invoices', 'closedPeriods', '$uibModal', 'growl', '$filter', 'Setting', 'settings', 'stripeSecretKey', '_t', 'Member', 'uiTourService',
|
||||
function ($scope, $state, Invoice, AccountingPeriod, AuthService, invoices, closedPeriods, $uibModal, growl, $filter, Setting, settings, stripeSecretKey, _t, Member, uiTourService) {
|
||||
Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'Invoice', 'AccountingPeriod', 'AuthService', 'invoices', 'closedPeriods', '$uibModal', 'growl', '$filter', 'Setting', 'settings', 'stripeSecretKey', '_t', 'Member', 'uiTourService', 'Payment', 'onlinePaymentStatus',
|
||||
function ($scope, $state, Invoice, AccountingPeriod, AuthService, invoices, closedPeriods, $uibModal, growl, $filter, Setting, settings, stripeSecretKey, _t, Member, uiTourService, Payment, onlinePaymentStatus) {
|
||||
/* PRIVATE STATIC CONSTANTS */
|
||||
|
||||
// number of invoices loaded each time we click on 'load more...'
|
||||
@ -178,6 +178,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
// is the stripe private set?
|
||||
$scope.stripeSecretKey = (stripeSecretKey.isPresent ? STRIPE_SK_HIDDEN : '');
|
||||
|
||||
// has any online payment been already made?
|
||||
$scope.onlinePaymentStatus = onlinePaymentStatus.status;
|
||||
|
||||
// Placeholding date for the invoice creation
|
||||
$scope.today = moment();
|
||||
|
||||
@ -619,6 +622,9 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
|
||||
Setting.isPresent({ name: 'stripe_secret_key' }, function (res) {
|
||||
$scope.stripeSecretKey = (res.isPresent ? STRIPE_SK_HIDDEN : '');
|
||||
})
|
||||
Payment.onlinePaymentStatus(function (res) {
|
||||
$scope.onlinePaymentStatus = res.status;
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -10,7 +10,10 @@ Application.Directives.directive('textSetting', ['Setting', 'growl', '_t',
|
||||
faIcon: '@',
|
||||
placeholder: '@',
|
||||
required: '<',
|
||||
type: '@'
|
||||
type: '@',
|
||||
maxLength: '@',
|
||||
minLength: '@',
|
||||
readOnly: '<'
|
||||
},
|
||||
templateUrl: '<%= asset_path "admin/settings/text.html" %>',
|
||||
link ($scope, element, attributes) {
|
||||
|
@ -839,9 +839,10 @@ angular.module('application.router', ['ui.router'])
|
||||
'accounting_VAT_code', 'accounting_VAT_label', 'accounting_subscription_code', 'accounting_subscription_label', \
|
||||
'accounting_Machine_code', 'accounting_Machine_label', 'accounting_Training_code', 'accounting_Training_label', \
|
||||
'accounting_Event_code', 'accounting_Event_label', 'accounting_Space_code', 'accounting_Space_label', \
|
||||
'feature_tour_display', 'online_payment_module', 'stripe_public_key']` }).$promise;
|
||||
'feature_tour_display', 'online_payment_module', 'stripe_public_key', 'stripe_currency']` }).$promise;
|
||||
}],
|
||||
stripeSecretKey: ['Setting', function (Setting) { return Setting.isPresent({ name: 'stripe_secret_key' }).$promise; }],
|
||||
onlinePaymentStatus: ['Payment', function (Payment) { return Payment.onlinePaymentStatus().$promise; }],
|
||||
invoices: [ 'Invoice', function (Invoice) {
|
||||
return Invoice.list({
|
||||
query: { number: '', customer: '', date: null, order_by: '-reference', page: 1, size: 20 }
|
||||
|
@ -7,6 +7,10 @@ Application.Services.factory('Payment', ['$resource', function ($resource) {
|
||||
method: 'POST',
|
||||
url: '/api/payments/confirm_payment',
|
||||
isArray: false
|
||||
},
|
||||
onlinePaymentStatus: {
|
||||
method: 'GET',
|
||||
url: '/api/payments/online_payment_status'
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -42,6 +42,23 @@
|
||||
<button class="btn btn-default m-t-lg" ng-click="requireStripeKeys(allSettings.online_payment_module)" translate>{{ 'app.admin.invoices.payment.edit_keys' }}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t" ng-show="allSettings.online_payment_module === 'true'">
|
||||
<h3 class="m-l" translate>{{ 'app.admin.invoices.payment.currency' }}</h3>
|
||||
<p class="alert alert-warning m-h-md" ng-bind-html="'app.admin.invoices.payment.currency_info_html' | translate"></p>
|
||||
<p class="alert alert-danger m-h-md" ng-bind-html="'app.admin.invoices.payment.currency_alert_html' | translate"></p>
|
||||
<div class="col-md-4 m-l">
|
||||
<text-setting name="stripe_currency"
|
||||
settings="allSettings"
|
||||
label="app.admin.invoices.payment.stripe_currency"
|
||||
fa-icon="fa-money"
|
||||
placeholder="XXX"
|
||||
required="true"
|
||||
min-length="3"
|
||||
max-length="3"
|
||||
read-only="onlinePaymentStatus">
|
||||
</text-setting>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<form class="{{classes}}" name="setting-number-form">
|
||||
<form class="{{classes}}" name="settingNumberForm">
|
||||
<label for="setting-{{setting.name}}" class="control-label m-r" translate>{{ label }}</label>
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
@ -11,5 +11,5 @@
|
||||
<i class="fa fa-lightbulb-o"></i> {{ helperText | translate }}
|
||||
</span>
|
||||
</div>
|
||||
<button name="button" class="btn btn-warning" ng-click="save(setting)" ng-disabled="setting-number-form.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
<button name="button" class="btn btn-warning" ng-click="save(setting)" ng-disabled="settingNumberForm.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
</form>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<form class="{{classes}}" name="setting-select-multiple-form">
|
||||
<form class="{{classes}}" name="settingSelectMultipleForm">
|
||||
<div class="form-group">
|
||||
<label for="setting-{{setting.name}}" class="control-label m-r" translate>{{ label }}</label>
|
||||
<select class="form-control"
|
||||
@ -13,7 +13,7 @@
|
||||
<button ng-click="removeItem()" class="btn btn-default"><i class="fa fa-trash"></i></button>
|
||||
<button ng-click="addItem()" class="btn btn-default"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
<button name="button" class="btn btn-warning m-t" ng-click="save(setting)" ng-disabled="setting-select-multiple-form.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
<button name="button" class="btn btn-warning m-t" ng-click="save(setting)" ng-disabled="settingSelectMultipleForm.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
</form>
|
||||
|
||||
<script type="text/ng-template" id="newSelectOption.html">
|
||||
|
@ -1,4 +1,4 @@
|
||||
<form class="{{classes}}" name="setting-select-form">
|
||||
<form class="{{classes}}" name="settingSelectForm">
|
||||
<div class="form-group">
|
||||
<label for="setting-{{setting.name}}" class="control-label m-r" translate>{{ label }}</label>
|
||||
<select class="form-control"
|
||||
@ -12,5 +12,5 @@
|
||||
<option ng-if="option5" ng-value="option5[0]" translate>{{ option5[1] }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<button name="button" class="btn btn-warning m-t" ng-click="save(setting)" ng-disabled="setting-select-form.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
<button name="button" class="btn btn-warning m-t" ng-click="save(setting)" ng-disabled="settingSelectForm.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
</form>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<form class="{{classes}}" name="setting-text-form">
|
||||
<form class="{{classes}}" name="settingTextForm">
|
||||
<label for="setting-{{setting.name}}" class="control-label m-r" translate>{{ label }}</label>
|
||||
<div ng-class="{'form-group': faIcon}">
|
||||
<div ng-class="{'input-group': faIcon}">
|
||||
@ -10,8 +10,11 @@
|
||||
id="setting-{{setting.name}}"
|
||||
placeholder="{{placeholder}}"
|
||||
ng-model="setting.value"
|
||||
ng-required="required">
|
||||
ng-required="required"
|
||||
ng-minlength="minLength"
|
||||
ng-maxlength="maxLength"
|
||||
ng-readonly="readOnly">
|
||||
</div>
|
||||
</div>
|
||||
<button name="button" class="btn btn-warning m-t" ng-click="save(setting)" ng-disabled="setting-text-form.$invalid" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
<button name="button" class="btn btn-warning m-t" ng-click="save(setting)" ng-disabled="settingTextForm.$invalid || readOnly" translate>{{ 'app.shared.buttons.save' }}</button>
|
||||
</form>
|
||||
|
@ -27,7 +27,7 @@ class API::PaymentsController < API::ApiController
|
||||
{
|
||||
payment_method: params[:payment_method_id],
|
||||
amount: amount[:amount],
|
||||
currency: Rails.application.secrets.stripe_currency,
|
||||
currency: Setting.get('stripe_currency'),
|
||||
confirmation_method: 'manual',
|
||||
confirm: true,
|
||||
customer: current_user.stp_customer_id
|
||||
@ -56,6 +56,16 @@ class API::PaymentsController < API::ApiController
|
||||
render generate_payment_response(intent, res)
|
||||
end
|
||||
|
||||
def online_payment_status
|
||||
authorize :payment
|
||||
|
||||
key = Setting.get('stripe_secret_key')
|
||||
render json: { status: false } and return unless key
|
||||
|
||||
charges = Stripe::Charge.list({ limit: 1 }, { api_key: key })
|
||||
render json: { status: charges.data.length.positive? }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def on_reservation_success(intent, details)
|
||||
|
@ -98,7 +98,8 @@ class Setting < ApplicationRecord
|
||||
openlab_default
|
||||
online_payment_module
|
||||
stripe_public_key
|
||||
stripe_secret_key] }
|
||||
stripe_secret_key
|
||||
stripe_currency] }
|
||||
# WARNING: when adding a new key, you may also want to add it in app/policies/setting_policy.rb#public_whitelist
|
||||
|
||||
def value
|
||||
|
8
app/policies/payment_policy.rb
Normal file
8
app/policies/payment_policy.rb
Normal file
@ -0,0 +1,8 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Check the access policies for API::PaymentsController
|
||||
class PaymentPolicy < ApplicationPolicy
|
||||
def online_payment_status?
|
||||
user.admin?
|
||||
end
|
||||
end
|
@ -12,9 +12,9 @@ class SyncMembersOnStripeWorker
|
||||
logger.debug "#{index} / #{total}"
|
||||
begin
|
||||
stp_customer = Stripe::Customer.retrieve(member.stp_customer_id, api_key: Setting.get('stripe_secret_key'))
|
||||
StripeWorker.perform(:create_stripe_customer, member.id) if stp_customer.nil? || stp_customer[:deleted]
|
||||
StripeWorker.new.create_stripe_customer(member.id) if stp_customer.nil? || stp_customer[:deleted]
|
||||
rescue Stripe::InvalidRequestError
|
||||
StripeWorker.perform(:create_stripe_customer, member.id)
|
||||
StripeWorker.new.create_stripe_customer(member.id)
|
||||
end
|
||||
end
|
||||
logger.debug 'Sync is done'
|
||||
|
@ -627,6 +627,10 @@ en:
|
||||
stripe_keys_saved: "Stripe keys successfully saved."
|
||||
error_saving_stripe_keys: "Unable to save the Stripe keys. Please try again later."
|
||||
edit_keys: "Edit keys"
|
||||
currency: "Currency"
|
||||
currency_info_html: "Please specify below the currency used for online payment. You should provide a three-letter ISO code, from the list of <a href='https://stripe.com/docs/currencies' target='_blank'>Stripe supported currencies</a>."
|
||||
currency_alert_html: "<strong>Warning</strong>: the currency cannot be changed after the first online payment was made. Please define this setting carefully before opening Fab-manager to your members."
|
||||
stripe_currency: "Stripe currency"
|
||||
#management of users, labels, groups, and so on
|
||||
members:
|
||||
users_management: "Users management"
|
||||
@ -1096,6 +1100,7 @@ en:
|
||||
openlab_app_secret: "OpenLab secret"
|
||||
openlab_default: "default gallery view"
|
||||
online_payment_module: "online payment module"
|
||||
stripe_currency: "Stripe currency"
|
||||
general:
|
||||
general: "General"
|
||||
title: "Title"
|
||||
|
@ -627,6 +627,10 @@ fr:
|
||||
stripe_keys_saved: "Les clefs Stripe ont bien été enregistrées."
|
||||
error_saving_stripe_keys: "Impossible d'enregitrer les clefs Stripe. Veuillez réessayer ultérieurement."
|
||||
edit_keys: "Modifier les clefs"
|
||||
currency: "Devise"
|
||||
currency_info_html: "Veuillez indiquer la devise à utiliser lors des paiements en ligne. Vous devez fournir un code ISO à trois lettres, issu de la liste des <a href='https://stripe.com/docs/currencies' target='_blank'>devises supportées par Stripe</a>."
|
||||
currency_alert_html: "<strong>Attention</strong> : la devise ne peut pas être modifiée après que le premier payment en ligne ait été effectué. Veuillez définir attentivement ce paramètre avant d'ouvrir Fab-manager à vos members."
|
||||
stripe_currency: "Devise Stripe"
|
||||
#management of users, labels, groups, and so on
|
||||
members:
|
||||
users_management: "Gestion des utilisateurs"
|
||||
@ -1096,6 +1100,7 @@ fr:
|
||||
openlab_app_secret: "secret OpenLab"
|
||||
openlab_default: "l'affichage par défaut de la galerie"
|
||||
online_payment_module: "module de paiement en ligne"
|
||||
stripe_currency: "la devise Stripe"
|
||||
general:
|
||||
general: "Général"
|
||||
title: "Titre"
|
||||
|
@ -164,6 +164,7 @@ Rails.application.routes.draw do
|
||||
|
||||
# payments handling
|
||||
post 'payments/confirm_payment' => 'payments/confirm_payment'
|
||||
get 'payments/online_payment_status' => 'payments/online_payment_status'
|
||||
|
||||
# FabAnalytics
|
||||
get 'analytics/data' => 'analytics#data'
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
development:
|
||||
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
|
||||
stripe_currency: <%= ENV["STRIPE_CURRENCY"] %>
|
||||
fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %>
|
||||
user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %>
|
||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||
@ -42,7 +41,6 @@ development:
|
||||
|
||||
test:
|
||||
secret_key_base: 83daf5e7b80d990f037407bab78dff9904aaf3c195a50f84fa8695a22287e707dfbd9524b403b1dcf116ae1d8c06844c3d7ed942564e5b46be6ae3ead93a9d30
|
||||
stripe_currency: usd
|
||||
fablab_without_wallet: false
|
||||
user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %>
|
||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||
@ -72,7 +70,6 @@ test:
|
||||
|
||||
staging:
|
||||
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
|
||||
stripe_currency: <%= ENV["STRIPE_CURRENCY"] %>
|
||||
fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %>
|
||||
user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %>
|
||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||
@ -113,7 +110,6 @@ staging:
|
||||
# instead read values from the environment.
|
||||
production:
|
||||
secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
|
||||
stripe_currency: <%= ENV["STRIPE_CURRENCY"] %>
|
||||
fablab_without_wallet: <%= ENV["FABLAB_WITHOUT_WALLET"] %>
|
||||
user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %>
|
||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||
|
@ -880,6 +880,8 @@ unless Setting.find_by(name: 'allowed_cad_mime_types').try(:value)
|
||||
)
|
||||
end
|
||||
|
||||
Setting.set('stripe_currency', 'EUR') unless Setting.find_by(name: 'stripe_currency').try(:value)
|
||||
|
||||
if StatisticCustomAggregation.count.zero?
|
||||
# available reservations hours for machines
|
||||
machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: 2)
|
||||
|
@ -51,16 +51,6 @@ When using docker-compose, you should provide the name of the service in your [d
|
||||
Used by the authentication system to generate random tokens, eg. for resetting passwords.
|
||||
Used by Rails to verify the integrity of signed cookies.
|
||||
You can generate such a random key by running `rails secret`.
|
||||
<a name="STRIPE_CURRENCY"></a>
|
||||
|
||||
STRIPE_CURRENCY
|
||||
|
||||
Currency used by stripe to charge the final customer.
|
||||
See https://support.stripe.com/questions/which-currencies-does-stripe-support for a list of available 3-letters ISO code.
|
||||
|
||||
**BEWARE**: stripe currency cannot be changed during the application life.
|
||||
Changing the currency after the application has already run, may result in several bugs and prevent the users to pay through stripe.
|
||||
So set this setting carefully before starting the application for the first time.
|
||||
<a name="INVOICE_PREFIX"></a>
|
||||
|
||||
INVOICE_PREFIX
|
||||
|
@ -6,9 +6,7 @@ POSTGRES_PASSWORD=
|
||||
REDIS_HOST=fabmanager-redis
|
||||
ELASTICSEARCH_HOST=fabmanager-elastic
|
||||
|
||||
# Stripe
|
||||
SECRET_KEY_BASE=83daf5e7b80d990f037407bab78dff9904aaf3c195a50f84fa8695a22287e707dfbd9524b403b1dcf116ae1d8c06844c3d7ed942564e5b46be6ae3ead93a9d30
|
||||
STRIPE_CURRENCY=eur
|
||||
|
||||
# Invoices
|
||||
INVOICE_PREFIX=Demo-FabLab_facture
|
||||
|
@ -128,7 +128,8 @@ namespace :fablab do
|
||||
%w[_ OPENLAB_DEFAULT openlab_default],
|
||||
%w[! FABLAB_WITHOUT_ONLINE_PAYMENT online_payment_module false],
|
||||
%w[_ STRIPE_PUBLISHABLE_KEY stripe_public_key],
|
||||
%w[_ STRIPE_API_KEY stripe_secret_key]
|
||||
%w[_ STRIPE_API_KEY stripe_secret_key],
|
||||
%w[_ STRIPE_CURRENCY stripe_currency]
|
||||
]
|
||||
|
||||
mapping.each do |m|
|
||||
|
@ -4,8 +4,6 @@ ELASTICSEARCH_HOST=elasticsearch
|
||||
|
||||
SECRET_KEY_BASE=
|
||||
|
||||
STRIPE_CURRENCY=eur
|
||||
|
||||
INVOICE_PREFIX=Demo-FabLab_facture
|
||||
FABLAB_WITHOUT_ONLINE_PAYMENT=false
|
||||
PHONE_REQUIRED=false
|
||||
|
@ -234,7 +234,7 @@ configure_env_file()
|
||||
|
||||
local doc variables secret
|
||||
doc=$(\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/doc/environment.md)
|
||||
variables=(STRIPE_CURRENCY INVOICE_PREFIX FABLAB_WITHOUT_ONLINE_PAYMENT FABLAB_WITHOUT_WALLET \
|
||||
variables=(INVOICE_PREFIX FABLAB_WITHOUT_ONLINE_PAYMENT FABLAB_WITHOUT_WALLET \
|
||||
USER_CONFIRMATION_NEEDED_TO_SIGN_IN DEFAULT_HOST DEFAULT_PROTOCOL DELIVERY_METHOD SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \
|
||||
SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS \
|
||||
LOG_LEVEL MAX_IMAGE_SIZE MAX_CAO_SIZE MAX_IMPORT_SIZE DISK_SPACE_MB_ALERT \
|
||||
|
8
test/fixtures/history_values.yml
vendored
8
test/fixtures/history_values.yml
vendored
@ -653,3 +653,11 @@ history_value_68:
|
||||
value: <%= ENV["STRIPE_API_KEY"] %>
|
||||
created_at: 2020-06-08 17:12:16.846525000 Z
|
||||
updated_at: 2020-06-08 17:12:16.846525000 Z
|
||||
|
||||
history_value_69:
|
||||
id: 69
|
||||
setting_id: 69
|
||||
invoicing_profile_id: 1
|
||||
value: usd
|
||||
created_at: 2020-06-08 17:12:16.846525000 Z
|
||||
updated_at: 2020-06-08 17:12:16.846525000 Z
|
||||
|
6
test/fixtures/settings.yml
vendored
6
test/fixtures/settings.yml
vendored
@ -400,3 +400,9 @@ setting_68:
|
||||
name: stripe_secret_key
|
||||
created_at: 2020-06-08 17:12:16.846525000 Z
|
||||
updated_at: 2020-06-08 17:12:16.846525000 Z
|
||||
|
||||
setting_69:
|
||||
id: 69
|
||||
name: stripe_currency
|
||||
created_at: 2020-06-08 17:12:16.846525000 Z
|
||||
updated_at: 2020-06-08 17:12:16.846525000 Z
|
||||
|
Loading…
x
Reference in New Issue
Block a user