diff --git a/app/frontend/src/javascript/controllers/application.js.erb b/app/frontend/src/javascript/controllers/application.js.erb index c25601eb5..e3dd67d92 100644 --- a/app/frontend/src/javascript/controllers/application.js.erb +++ b/app/frontend/src/javascript/controllers/application.js.erb @@ -92,7 +92,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco templateUrl: '/shared/signupModal.html', size: 'md', resolve: { - settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['phone_required', 'recaptcha_site_key', 'confirmation_required']" }).$promise; }] + settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['phone_required', 'recaptcha_site_key', 'confirmation_required', 'address_required']" }).$promise; }] }, controller: ['$scope', '$uibModalInstance', 'Group', 'CustomAsset', 'settingsPromise', 'growl', '_t', function ($scope, $uibModalInstance, Group, CustomAsset, settingsPromise, growl, _t) { // default parameters for the date picker in the account creation modal @@ -107,6 +107,9 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco // is the phone number required to sign-up? $scope.phoneRequired = (settingsPromise.phone_required === 'true'); + // is the address required to sign-up? + $scope.addressRequired = (settingsPromise.address_required === 'true'); + // reCaptcha v2 site key (or undefined) $scope.recaptchaSiteKey = settingsPromise.recaptcha_site_key; diff --git a/app/frontend/src/javascript/controllers/profile.js b/app/frontend/src/javascript/controllers/profile.js index e7fcf4788..cba08dba6 100644 --- a/app/frontend/src/javascript/controllers/profile.js +++ b/app/frontend/src/javascript/controllers/profile.js @@ -13,8 +13,8 @@ 'use strict'; -Application.Controllers.controller('CompleteProfileController', ['$scope', '$rootScope', '$state', '$window', '_t', 'growl', 'CSRF', 'Auth', 'Member', 'settingsPromise', 'activeProviderPromise', 'groupsPromise', 'cguFile', 'memberPromise', 'Session', 'dialogs', 'AuthProvider', 'phoneRequiredPromise', - function ($scope, $rootScope, $state, $window, _t, growl, CSRF, Auth, Member, settingsPromise, activeProviderPromise, groupsPromise, cguFile, memberPromise, Session, dialogs, AuthProvider, phoneRequiredPromise) { +Application.Controllers.controller('CompleteProfileController', ['$scope', '$rootScope', '$state', '$window', '_t', 'growl', 'CSRF', 'Auth', 'Member', 'settingsPromise', 'activeProviderPromise', 'groupsPromise', 'cguFile', 'memberPromise', 'Session', 'dialogs', 'AuthProvider', + function ($scope, $rootScope, $state, $window, _t, growl, CSRF, Auth, Member, settingsPromise, activeProviderPromise, groupsPromise, cguFile, memberPromise, Session, dialogs, AuthProvider) { /* PUBLIC SCOPE */ // API URL where the form will be posted @@ -48,7 +48,10 @@ Application.Controllers.controller('CompleteProfileController', ['$scope', '$roo $scope.cgu = cguFile.custom_asset; // is the phone number required in _member_form? - $scope.phoneRequired = (phoneRequiredPromise.setting.value === 'true'); + $scope.phoneRequired = (settingsPromise.phone_required === 'true'); + + // is the address required in _member_form? + $scope.addressRequired = (settingsPromise.address_required === 'true'); // Angular-Bootstrap datepicker configuration for birthday $scope.datePicker = { diff --git a/app/frontend/src/javascript/models/setting.ts b/app/frontend/src/javascript/models/setting.ts index b42653b85..ccde19dc3 100644 --- a/app/frontend/src/javascript/models/setting.ts +++ b/app/frontend/src/javascript/models/setting.ts @@ -98,7 +98,10 @@ export enum SettingName { ConfirmationRequired = 'confirmation_required', WalletModule = 'wallet_module', StatisticsModule = 'statistics_module', - UpcomingEventsShown = 'upcoming_events_shown' + UpcomingEventsShown = 'upcoming_events_shown', + PaymentSchedulePrefix = 'payment_schedule_prefix', + TrainingsModule = 'trainings_module', + AddressRequired = 'address_required' } export interface Setting { diff --git a/app/frontend/src/javascript/router.js b/app/frontend/src/javascript/router.js index 5b2b67dbd..b1f5540ba 100644 --- a/app/frontend/src/javascript/router.js +++ b/app/frontend/src/javascript/router.js @@ -130,12 +130,11 @@ angular.module('application.router', ['ui.router']) } }, resolve: { - settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['fablab_name', 'name_genre']" }).$promise; }], + settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['fablab_name', 'name_genre', 'phone_required', 'address_required']" }).$promise; }], activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }], groupsPromise: ['Group', function (Group) { return Group.query().$promise; }], cguFile: ['CustomAsset', function (CustomAsset) { return CustomAsset.get({ name: 'cgu-file' }).$promise; }], - memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }], - phoneRequiredPromise: ['Setting', function (Setting) { return Setting.get({ name: 'phone_required' }).$promise; }] + memberPromise: ['Member', 'currentUser', function (Member, currentUser) { return Member.get({ id: currentUser.id }).$promise; }] } }) diff --git a/app/frontend/templates/admin/settings/general.html b/app/frontend/templates/admin/settings/general.html index ff9c0e9aa..454672502 100644 --- a/app/frontend/templates/admin/settings/general.html +++ b/app/frontend/templates/admin/settings/general.html @@ -424,6 +424,18 @@ +
+

{{ 'app.admin.settings.address' }}

+

+ {{ 'app.admin.settings.address_required_info' }} +

+
+ + +
+

{{ 'app.admin.settings.captcha' }}

diff --git a/app/models/invoicing_profile.rb b/app/models/invoicing_profile.rb index ed2b21fe0..963e8790f 100644 --- a/app/models/invoicing_profile.rb +++ b/app/models/invoicing_profile.rb @@ -20,6 +20,8 @@ class InvoicingProfile < ApplicationRecord has_many :operated_invoices, foreign_key: :operator_profile_id, class_name: 'Invoice', dependent: :nullify has_many :operated_payment_schedules, foreign_key: :operator_profile_id, class_name: 'PaymentSchedule', dependent: :nullify + validates :address, presence: true, if: -> { Setting.get('address_required') } + def full_name # if first_name or last_name is nil, the empty string will be used as a temporary replacement (first_name || '').humanize.titleize + ' ' + (last_name || '').humanize.titleize diff --git a/app/models/setting.rb b/app/models/setting.rb index d83d35101..f2e34af1a 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -108,7 +108,8 @@ class Setting < ApplicationRecord statistics_module upcoming_events_shown payment_schedule_prefix - trainings_module] } + trainings_module + address_required] } # WARNING: when adding a new key, you may also want to add it in app/policies/setting_policy.rb#public_whitelist def value diff --git a/app/models/user.rb b/app/models/user.rb index 23372aa39..01307ab03 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -203,7 +203,8 @@ class User < ApplicationRecord def need_completion? statistic_profile.gender.nil? || profile.first_name.blank? || profile.last_name.blank? || username.blank? || email.blank? || encrypted_password.blank? || group_id.nil? || statistic_profile.birthday.blank? || - (Setting.get('phone_required') && profile.phone.blank?) + (Setting.get('phone_required') && profile.phone.blank?) || + (Setting.get('address_required') && invoicing_profile.address&.address&.blank?) end ## Retrieve the requested data in the User and user's Profile tables diff --git a/app/policies/setting_policy.rb b/app/policies/setting_policy.rb index c24709daf..491f8c8a7 100644 --- a/app/policies/setting_policy.rb +++ b/app/policies/setting_policy.rb @@ -38,7 +38,7 @@ class SettingPolicy < ApplicationPolicy fablab_name name_genre event_explications_alert space_explications_alert link_name home_content phone_required tracking_id book_overlapping_slots slot_duration events_in_calendar spaces_module plans_module invoicing_module recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id openlab_default - online_payment_module stripe_public_key confirmation_required wallet_module trainings_module] + online_payment_module stripe_public_key confirmation_required wallet_module trainings_module address_required] end ## diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index 77f427439..921822901 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -1073,6 +1073,7 @@ en: machines_sort_by: "machines display order" fab_analytics: "Fab Analytics" phone_required: "phone required" + address_required: "address required" tracking_id: "tracking ID" facebook_app_id: "Facebook App ID" twitter_analytics: "Twitter analytics account" @@ -1109,6 +1110,9 @@ en: phone: "Phone" phone_is_required: "Phone required" phone_required_info: "You can define if the phone number should be required to register a new user on Fab-manager." + address: "Address" + address_required_info: "You can define if the address should be required to register a new user on Fab-manager. Please note that, depending on your country, the regulations may requires addresses for the invoices to be valid." + address_is_required: "Address is required" captcha: "Captcha" captcha_info_html: "You can setup a protection against robots, to prevent them creating members accounts. This protection is using Google reCAPTCHA. Sign up for an API key pair to start using the captcha." site_key: "Site key" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 1af569356..a98083288 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -1109,6 +1109,9 @@ fr: phone: "Téléphone" phone_is_required: "Téléphone requis" phone_required_info: "Vous pouvez définir si le numéro de téléphone doit être requis, lors de l'enregistrement d'un nouvel utilisateur sur Fab-manager." + address: "Adresse" + address_required_info: "Vous pouvez définir si l'adresse doit être requise, lors de l'enregistrement d'un nouvel utilisateur sur Fab-manager. Veuillez noter que, selon votre pays, la réglementation peut exiger des adresses pour que les factures soient valides." + address_is_required: "Adresse requise" captcha: "Captcha" captcha_info_html: "Vous pouvez mettre en place une protection contre les robots, pour les empêcher de créer des comptes membre. Cette protection utilise Google reCAPTCHA. Inscrivez vous pour obtenir une paire de clefs d'API afin d'utiliser le captcha." site_key: "Clef de site"