From 7c86adde4bc3e5d4fff9616b895dc5e82fad7d69 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Wed, 5 Feb 2020 16:53:47 +0100 Subject: [PATCH 1/4] Ability to configure allowing or preventing member book a machine/formation/event slot if he already have a reservation the same day at the same time --- CHANGELOG.md | 16 +++-- .../javascripts/controllers/events.js.erb | 69 ++++++++++++++++++- .../javascripts/controllers/machines.js.erb | 2 +- app/assets/javascripts/directives/cart.js.erb | 60 ++++++++++++++-- .../shared/_reserve_slot_same_time.html.erb | 18 +++++ app/views/api/members/show.json.jbuilder | 18 +++++ app/views/application/index.html.erb | 1 + config/application.yml.default | 1 + config/locales/app.shared.en.yml | 3 + config/locales/app.shared.es.yml | 3 + config/locales/app.shared.fr.yml | 3 + config/locales/app.shared.pt.yml | 3 + config/secrets.yml | 4 ++ doc/environment.md | 5 ++ setup/env.example | 1 + setup/setup.sh | 2 +- 16 files changed, 193 insertions(+), 16 deletions(-) create mode 100644 app/assets/templates/shared/_reserve_slot_same_time.html.erb diff --git a/CHANGELOG.md b/CHANGELOG.md index 57ebfbbb7..81396d814 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog Fab Manager +- Ability to configure allowing or preventing member book a machine/formation/event slot if he already have a reservation the same day at the same time - Ability to create and delete periodic calendar availabilities (recurrence) - Ability to fully customize the home page - Automated setup assistant @@ -45,6 +46,7 @@ - [TODO DEPLOY] add the `PHONE_REQUIRED` environment variable (see [doc/environment.md](doc/environment.md#PHONE_REQUIRED) for configuration details) - [TODO DEPLOY] add the `EVENTS_IN_CALENDAR` environment variable (see [doc/environment.md](doc/environment.md#EVENTS_IN_CALENDAR) for configuration details) - [TODO DEPLOY] add the `USER_CONFIRMATION_NEEDED_TO_SIGN_IN` environment variable (see [doc/environment.md](doc/environment.md#USER_CONFIRMATION_NEEDED_TO_SIGN_IN) for configuration details) +- [TODO DEPLOY] add the `BOOK_SLOT_AT_SAME_TIME` environment variable (see [doc/environment.md](doc/environment.md#BOOK_SLOT_AT_SAME_TIME) for configuration details) - [TODO DEPLOY] -> (only dev) `bundle install && yarn install` - [TODO DEPLOY] `rake db:migrate && rake db:seed` - [TODO DEPLOY] `rake fablab:fix:name_stylesheet` @@ -140,7 +142,7 @@ ## v4.0.4 2019 August 14 - Fix a bug: #140 VAT rate is erroneous in invoices. - Note: this bug was introduced in v4.0.3 and requires (if you are on v4.0.3) to regenerate the invoices since August 1st (if + Note: this bug was introduced in v4.0.3 and requires (if you are on v4.0.3) to regenerate the invoices since August 1st (if - [TODO DEPLOY] `rake fablab:maintenance:regenerate_invoices[2019,8]` ## v4.0.3 2019 August 01 @@ -184,7 +186,7 @@ - Refactored user's profile to keep invoicing data after an user was deleted - Refactored user's profile to keep statistical data after an user was deleted - Ability to delete an user (fixes #129 and #120) -- Ask user acceptance before deposing analytics cookies +- Ask user acceptance before deposing analytics cookies - Fix a bug: (spanish) some translations are not loaded correctly - Fix a bug: some users may not appear in the admin's general listing - Fix a bug: Availabilities export report an erroneous number of reservations for machine availabilities (#131) @@ -381,8 +383,8 @@ - Fix a security issue: sprockets < 2.12.5 has a security vulnerability as described in [CVE-2018-3760](https://nvd.nist.gov/vuln/detail/CVE-2018-3760) - Ensure elasticSearch indices are started with green status on new installations - Refactored User.to_json to remove code duplication -- Fixed syntax and typos in README -- [TODO DEPLOY] **IMPORTANT** Please read [elastic_upgrade.md](doc/elastic_upgrade.md) for instructions on upgrading ElasticSearch. +- Fixed syntax and typos in README +- [TODO DEPLOY] **IMPORTANT** Please read [elastic_upgrade.md](doc/elastic_upgrade.md) for instructions on upgrading ElasticSearch. - [TODO DEPLOY] `rake fablab:fix:categories_slugs` - [TODO DEPLOY] -> (only dev) `bundle install` - [TODO DEPLOY] `rake db:seed` @@ -395,7 +397,7 @@ - Set Stripe API version, all fab-managers has to use this version because codebase relies on it - Fix a security issue: OmniAuth < 1.3.2 has a security vulnerability described in [CVE-2017-18076](https://nvd.nist.gov/vuln/detail/CVE-2017-18076) - Fix a security issue: rack-protection < 1.5.5 has a security vulnerability described in [CVE-2018-1000119](https://nvd.nist.gov/vuln/detail/CVE-2018-1000119) -- Fix a security issue: http gem < 0.7.3 has a security vulnerability described in [CVE-2015-1828](https://nvd.nist.gov/vuln/detail/CVE-2015-1828), updates twitter gem as a dependency +- Fix a security issue: http gem < 0.7.3 has a security vulnerability described in [CVE-2015-1828](https://nvd.nist.gov/vuln/detail/CVE-2015-1828), updates twitter gem as a dependency ## v2.6.3 2018 January 2 @@ -451,12 +453,12 @@ ## v2.5.13 2017 September 11 -- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with recursive events which the initial event was deleted +- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with recursive events which the initial event was deleted ## v2.5.12 2017 September 11 - Fix a bug: Long words overflow from homepage's events blocks -- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with non-recursive events +- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with non-recursive events ## v2.5.11 2017 September 7 diff --git a/app/assets/javascripts/controllers/events.js.erb b/app/assets/javascripts/controllers/events.js.erb index 1de803312..4e1717060 100644 --- a/app/assets/javascripts/controllers/events.js.erb +++ b/app/assets/javascripts/controllers/events.js.erb @@ -246,13 +246,34 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' $scope.reserveSuccess = false; if (!$scope.isAuthenticated()) { return $scope.login(null, function (user) { - $scope.reserve.toReserve = !$scope.reserve.toReserve; if (user.role !== 'admin') { return $scope.ctrl.member = user; } + const sameTimeReservations = findReservationsAtSameTime(); + if (sameTimeReservations.length > 0) { + showReserveSlotSameTimeModal(sameTimeReservations, function(res) { + return $scope.reserve.toReserve = !$scope.reserve.toReserve; + }); + } else { + return $scope.reserve.toReserve = !$scope.reserve.toReserve; + } }); } else { - return $scope.reserve.toReserve = !$scope.reserve.toReserve; + if ($scope.currentUser.role === 'admin') { + return $scope.reserve.toReserve = !$scope.reserve.toReserve; + } else { + Member.get({ id: $scope.currentUser.id }, function (member) { + $scope.ctrl.member = member; + const sameTimeReservations = findReservationsAtSameTime(); + if (sameTimeReservations.length > 0) { + showReserveSlotSameTimeModal(sameTimeReservations, function(res) { + return $scope.reserve.toReserve = !$scope.reserve.toReserve; + }); + } else { + return $scope.reserve.toReserve = !$scope.reserve.toReserve; + } + }); + } } } }; @@ -798,6 +819,49 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' } }; + /** + * find user reservations the same date at the same time with event + * + */ + var findReservationsAtSameTime = function () { + let sameTimeReservations = [ + 'training_reservations', + 'machine_reservations', + 'space_reservations', + 'events_reservations' + ].map(k => { + return _.filter($scope.ctrl.member[k], r => { + if (r.reservable_type === 'Event' && r.reservable.id === $scope.event.id) { + return false; + }; + return moment($scope.event.start_time).isSame(r.start_at) || + (moment($scope.event.end_time).isAfter(r.start_at) && moment($scope.event.end_time).isBefore(r.end_at)) || + (moment($scope.event.start_time).isAfter(r.start_at) && moment($scope.event.start_time).isBefore(r.end_at)) || + (moment($scope.event.start_time).isBefore(r.start_at) && moment($scope.event.end_time).isAfter(r.end_at)); + }); + }); + return _.union(...sameTimeReservations); + }; + + /** + * A modal for show reservations the same date at the same time + * + * @param sameTimeReservations {Array} reservations the same date at the same time + * @param callback {function} callback will invoke when user confirm + */ + var showReserveSlotSameTimeModal = function(sameTimeReservations, callback) { + const modalInstance = $uibModal.open({ + animation: true, + templateUrl: '<%= asset_path "shared/_reserve_slot_same_time.html" %>', + size: 'md', + controller: 'ReserveSlotSameTimeController', + resolve: { + sameTimeReservations: function() { return sameTimeReservations; }, + } + }); + modalInstance.result.then(callback); + }; + // !!! MUST BE CALLED AT THE END of the controller return initialize(); } @@ -879,4 +943,3 @@ Application.Controllers.controller('DeleteRecurrentEventController', ['$scope', } } ]); - diff --git a/app/assets/javascripts/controllers/machines.js.erb b/app/assets/javascripts/controllers/machines.js.erb index 733b1dca1..ea6f3c9f7 100644 --- a/app/assets/javascripts/controllers/machines.js.erb +++ b/app/assets/javascripts/controllers/machines.js.erb @@ -579,7 +579,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat }); if ($scope.currentUser.role !== 'admin') { - return $scope.ctrl.member = $scope.currentUser; + return Member.get({ id: $scope.currentUser.id }, function (member) { $scope.ctrl.member = member; }); } }; diff --git a/app/assets/javascripts/directives/cart.js.erb b/app/assets/javascripts/directives/cart.js.erb index ff2c4a810..816253088 100644 --- a/app/assets/javascripts/directives/cart.js.erb +++ b/app/assets/javascripts/directives/cart.js.erb @@ -10,8 +10,8 @@ * DS102: Remove unnecessary code created because of implicit returns * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md */ -Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', 'growl', 'Auth', 'Price', 'Wallet', 'CustomAsset', 'Slot', 'helpers', '_t', - function ($rootScope, $uibModal, dialogs, growl, Auth, Price, Wallet, CustomAsset, Slot, helpers, _t) { +Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', 'growl', 'Auth', 'Price', 'Wallet', 'CustomAsset', 'Slot', 'helpers', '_t', '$uibModal', + function ($rootScope, $uibModal, dialogs, growl, Auth, Price, Wallet, CustomAsset, Slot, helpers, _t, $uibModal) { return ({ restrict: 'E', scope: { @@ -72,8 +72,38 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', * @param slot {Object} fullCalendar event object */ $scope.validateSlot = function (slot) { - slot.isValid = true; - return updateCartPrice(); + let sameTimeReservations = [ + 'training_reservations', + 'machine_reservations', + 'space_reservations', + 'events_reservations' + ].map(k => { + return _.filter($scope.user[k], r => { + return slot.start.isSame(r.start_at) || + (slot.end.isAfter(r.start_at) && slot.end.isBefore(r.end_at)) || + (slot.start.isAfter(r.start_at) && slot.start.isBefore(r.end_at)) || + (slot.start.isBefore(r.start_at) && slot.end.isAfter(r.end_at)); + }); + }); + sameTimeReservations = _.union(...sameTimeReservations); + if (sameTimeReservations.length > 0) { + const modalInstance = $uibModal.open({ + animation: true, + templateUrl: '<%= asset_path "shared/_reserve_slot_same_time.html" %>', + size: 'md', + controller: 'ReserveSlotSameTimeController', + resolve: { + sameTimeReservations: function() { return sameTimeReservations; }, + } + }); + modalInstance.result.then(function(res) { + slot.isValid = true; + return updateCartPrice(); + }); + } else { + slot.isValid = true; + return updateCartPrice(); + } }; /** @@ -614,3 +644,25 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', }); } ]); + +/** + * Controller of modal for show reservations the same date at the same time + */ +Application.Controllers.controller('ReserveSlotSameTimeController', ['$scope', '$uibModalInstance', 'sameTimeReservations', 'growl', '_t', + function ($scope, $uibModalInstance, sameTimeReservations, growl, _t) { + $scope.sameTimeReservations = sameTimeReservations; + $scope.bookSlotAtSameTime = Fablab.bookSlotAtSameTime; + /** + * Confirmation callback + */ + $scope.ok = function () { + $uibModalInstance.close({}); + } + /** + * Cancellation callback + */ + $scope.cancel = function () { + $uibModalInstance.dismiss('cancel'); + } + } +]); diff --git a/app/assets/templates/shared/_reserve_slot_same_time.html.erb b/app/assets/templates/shared/_reserve_slot_same_time.html.erb new file mode 100644 index 000000000..16f8b9e00 --- /dev/null +++ b/app/assets/templates/shared/_reserve_slot_same_time.html.erb @@ -0,0 +1,18 @@ + + + + diff --git a/app/views/api/members/show.json.jbuilder b/app/views/api/members/show.json.jbuilder index 335136632..eca6a2c07 100644 --- a/app/views/api/members/show.json.jbuilder +++ b/app/views/api/members/show.json.jbuilder @@ -15,9 +15,26 @@ json.training_reservations @member.reservations.where(reservable_type: 'Training json.start_at r.slots.first.start_at json.end_at r.slots.first.end_at json.reservable r.reservable + json.reservable_type 'Training' json.is_valid @member.statistic_profile.training_ids.include?(r.reservable_id) json.canceled_at r.slots.first.canceled_at end +json.machine_reservations @member.reservations.where(reservable_type: 'Machine') do |r| + json.id r.id + json.start_at r.slots.first.start_at + json.end_at r.slots.first.end_at + json.reservable r.reservable + json.reservable_type 'Machine' + json.canceled_at r.slots.first.canceled_at +end +json.space_reservations @member.reservations.where(reservable_type: 'Space') do |r| + json.id r.id + json.start_at r.slots.first.start_at + json.end_at r.slots.first.end_at + json.reservable r.reservable + json.reservable_type 'Space' + json.canceled_at r.slots.first.canceled_at +end json.all_projects @member.all_projects do |project| if requested_current || project.state == 'published' @@ -65,6 +82,7 @@ json.events_reservations @member.reservations.where(reservable_type: 'Event').jo end end json.reservable r.reservable + json.reservable_type 'Event' end json.invoices @member.invoices.order('reference DESC') do |i| json.id i.id diff --git a/app/views/application/index.html.erb b/app/views/application/index.html.erb index b11337511..a7c7ffcaf 100644 --- a/app/views/application/index.html.erb +++ b/app/views/application/index.html.erb @@ -28,6 +28,7 @@ Fablab.withoutOnlinePayment = ('<%= Rails.application.secrets.fablab_without_online_payments %>' === 'true'); Fablab.withoutInvoices = ('<%= Rails.application.secrets.fablab_without_invoices %>' === 'true'); Fablab.phoneRequired = ('<%= Rails.application.secrets.phone_required %>' === 'true'); + Fablab.bookSlotAtSameTime = ('<%= Rails.application.secrets.book_slot_at_same_time %>' === 'true'); Fablab.eventsInCalendar = ('<%= Rails.application.secrets.events_in_calendar %>' === 'true'); Fablab.slotDuration = parseInt("<%= ApplicationHelper::SLOT_DURATION %>", 10); Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>"; diff --git a/config/application.yml.default b/config/application.yml.default index 790a7ee6d..eb3c5ed9f 100644 --- a/config/application.yml.default +++ b/config/application.yml.default @@ -21,6 +21,7 @@ FABLAB_WITHOUT_SPACES: 'true' FABLAB_WITHOUT_ONLINE_PAYMENT: 'false' FABLAB_WITHOUT_INVOICES: 'false' PHONE_REQUIRED: 'true' +BOOK_SLOT_AT_SAME_TIME: 'true' USER_CONFIRMATION_NEEDED_TO_SIGN_IN: 'false' diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index dc22183b4..beeb04ea4 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -439,3 +439,6 @@ en: a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." none: "None" online_payment_disabled: "Online payment is not available. Please contact the Fablab reception directly." + slot_at_same_time: "Booking slot with others reservations at the same time" + do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot with others slots at the same time ?" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because you really have following reservation at the same time." diff --git a/config/locales/app.shared.es.yml b/config/locales/app.shared.es.yml index 3e79b184c..2a16d1a3b 100644 --- a/config/locales/app.shared.es.yml +++ b/config/locales/app.shared.es.yml @@ -416,3 +416,6 @@ es: a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." none: "Ninguno" online_payment_disabled: "El pago en línea no está disponible. Póngase en contacto directamente con la recepción de Fablab." + slot_at_same_time: "Booking slot with others reservations at the same time" + do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot with others slots in same time ?" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because you really have following reservation at the same time." diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index b0fe0c49f..44a15ce34 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -439,3 +439,6 @@ fr: a_problem_occurred_during_the_payment_process_please_try_again_later: "Il y a eu un problème lors de la procédure de paiement. Veuillez réessayer plus tard." none: "Aucune" online_payment_disabled: "Le payment par carte bancaire n'est pas disponible. Merci de contacter directement l'accueil du Fablab." + slot_at_same_time: "Réserver un créneau avec autres réservations en même temps" + do_you_really_want_to_book_slot_at_same_time: "Êtes-vous sûr de réserver ce créneau avec autres réservations en même temps ?" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Impossible de réserver ce créneau parce qu'il y a déjà des réservations ci-desous en même temps." diff --git a/config/locales/app.shared.pt.yml b/config/locales/app.shared.pt.yml index f3e770b8e..745657122 100755 --- a/config/locales/app.shared.pt.yml +++ b/config/locales/app.shared.pt.yml @@ -439,3 +439,6 @@ pt: a_problem_occurred_during_the_payment_process_please_try_again_later: "Um problema ocorreu durante o processo de pagamento. Por favor tente novamente mais tarde." none: "Vazio" online_payment_disabled: "O pagamento online não está disponível. Entre em contato diretamente com a recepção do Fablab." + slot_at_same_time: "Booking slot with others reservations at the same time" + do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot with others slots in same time ?" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because you really have following reservation at the same time." diff --git a/config/secrets.yml b/config/secrets.yml index cafc95b44..b6e272da1 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -21,6 +21,7 @@ development: fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %> fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> phone_required: <%= ENV["PHONE_REQUIRED"] %> + book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> slot_duration: <%= ENV["SLOT_DURATION"] %> @@ -67,6 +68,7 @@ test: fablab_without_online_payments: false fablab_without_invoices: false phone_required: true + book_slot_at_same_time: true user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: false slot_duration: 60 @@ -113,6 +115,7 @@ staging: fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %> fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> phone_required: <%= ENV["PHONE_REQUIRED"] %> + book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> slot_duration: <%= ENV["SLOT_DURATION"] %> @@ -171,6 +174,7 @@ production: fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %> fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %> phone_required: <%= ENV["PHONE_REQUIRED"] %> + book_slot_at_same_time: <%= ENV["BOOK_SLOT_AT_SAME_TIME"] %> user_confirmation_needed_to_sign_in: <%= ENV["USER_CONFIRMATION_NEEDED_TO_SIGN_IN"] %> events_in_calendar: <%= ENV["EVENTS_IN_CALENDAR"] %> slot_duration: <%= ENV["SLOT_DURATION"] %> diff --git a/doc/environment.md b/doc/environment.md index 0e44f11bd..7cef275b4 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -107,6 +107,11 @@ This is useful if you have your own invoicing system and you want to prevent Fab PHONE_REQUIRED If set to 'false' the phone number won't be required to register a new user on the software. + + + BOOK_SLOT_AT_SAME_TIME + +If set to 'false' user won't book a machine/formation/event slot if he already have a reservation the same day at the same time. USER_CONFIRMATION_NEEDED_TO_SIGN_IN diff --git a/setup/env.example b/setup/env.example index 7591de428..da00c4ee8 100644 --- a/setup/env.example +++ b/setup/env.example @@ -14,6 +14,7 @@ FABLAB_WITHOUT_SPACES=true FABLAB_WITHOUT_ONLINE_PAYMENT=true FABLAB_WITHOUT_INVOICES=false PHONE_REQUIRED=false +BOOK_SLOT_AT_SAME_TIME=true EVENTS_IN_CALENDAR=false SLOT_DURATION=60 diff --git a/setup/setup.sh b/setup/setup.sh index 159b4c44d..36fb64644 100755 --- a/setup/setup.sh +++ b/setup/setup.sh @@ -211,7 +211,7 @@ configure_env_file() local doc variables secret doc=$(\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/doc/environment.md) variables=(STRIPE_API_KEY STRIPE_PUBLISHABLE_KEY STRIPE_CURRENCY INVOICE_PREFIX FABLAB_WITHOUT_PLANS FABLAB_WITHOUT_SPACES FABLAB_WITHOUT_ONLINE_PAYMENT FABLAB_WITHOUT_INVOICES \ - PHONE_REQUIRED USER_CONFIRMATION_NEEDED_TO_SIGN_IN EVENTS_IN_CALENDAR SLOT_DURATION DEFAULT_MAIL_FROM DELIVERY_METHOD DEFAULT_HOST DEFAULT_PROTOCOL SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \ + PHONE_REQUIRED BOOK_SLOT_AT_SAME_TIME USER_CONFIRMATION_NEEDED_TO_SIGN_IN EVENTS_IN_CALENDAR SLOT_DURATION DEFAULT_MAIL_FROM DELIVERY_METHOD DEFAULT_HOST DEFAULT_PROTOCOL SMTP_ADDRESS SMTP_PORT SMTP_USER_NAME SMTP_PASSWORD SMTP_AUTHENTICATION \ SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS GA_ID RECAPTCHA_SITE_KEY RECAPTCHA_SECRET_KEY DISQUS_SHORTNAME TWITTER_NAME \ FACEBOOK_APP_ID LOG_LEVEL ALLOWED_EXTENSIONS ALLOWED_MIME_TYPES MAX_IMAGE_SIZE MAX_CAO_SIZE MAX_IMPORT_SIZE DISK_SPACE_MB_ALERT \ SUPERADMIN_EMAIL APP_LOCALE RAILS_LOCALE MOMENT_LOCALE SUMMERNOTE_LOCALE ANGULAR_LOCALE MESSAGEFORMAT_LOCALE FULLCALENDAR_LOCALE ELASTICSEARCH_LANGUAGE_ANALYZER TIME_ZONE \ From 54bcc392f3b3547a6fba24a144f41784aefc36e3 Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 11 Feb 2020 10:48:29 +0100 Subject: [PATCH 2/4] typo and syntax --- CHANGELOG.md | 4 ++-- app/assets/javascripts/controllers/events.js.erb | 11 +++++------ app/assets/javascripts/directives/cart.js.erb | 10 +++++----- doc/environment.md | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81396d814..34d4e7092 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog Fab Manager -- Ability to configure allowing or preventing member book a machine/formation/event slot if he already have a reservation the same day at the same time +- Ability to configure the policy (allow or prevent) for members booking a machine/formation/event slot, if they already have a reservation the same day at the same time - Ability to create and delete periodic calendar availabilities (recurrence) - Ability to fully customize the home page - Automated setup assistant @@ -142,7 +142,7 @@ ## v4.0.4 2019 August 14 - Fix a bug: #140 VAT rate is erroneous in invoices. - Note: this bug was introduced in v4.0.3 and requires (if you are on v4.0.3) to regenerate the invoices since August 1st (if + Note: this bug was introduced in v4.0.3 and requires (if you are on v4.0.3) to regenerate the invoices since August 1st - [TODO DEPLOY] `rake fablab:maintenance:regenerate_invoices[2019,8]` ## v4.0.3 2019 August 01 diff --git a/app/assets/javascripts/controllers/events.js.erb b/app/assets/javascripts/controllers/events.js.erb index 4e1717060..d81811991 100644 --- a/app/assets/javascripts/controllers/events.js.erb +++ b/app/assets/javascripts/controllers/events.js.erb @@ -820,8 +820,7 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' }; /** - * find user reservations the same date at the same time with event - * + * Find user's reservations, the same date at the same time, with event */ var findReservationsAtSameTime = function () { let sameTimeReservations = [ @@ -829,18 +828,18 @@ Application.Controllers.controller('ShowEventController', ['$scope', '$state', ' 'machine_reservations', 'space_reservations', 'events_reservations' - ].map(k => { - return _.filter($scope.ctrl.member[k], r => { + ].map(function(k) { + return _.filter($scope.ctrl.member[k], function(r) { if (r.reservable_type === 'Event' && r.reservable.id === $scope.event.id) { return false; - }; + } return moment($scope.event.start_time).isSame(r.start_at) || (moment($scope.event.end_time).isAfter(r.start_at) && moment($scope.event.end_time).isBefore(r.end_at)) || (moment($scope.event.start_time).isAfter(r.start_at) && moment($scope.event.start_time).isBefore(r.end_at)) || (moment($scope.event.start_time).isBefore(r.start_at) && moment($scope.event.end_time).isAfter(r.end_at)); }); }); - return _.union(...sameTimeReservations); + return _.union.apply(null, sameTimeReservations); }; /** diff --git a/app/assets/javascripts/directives/cart.js.erb b/app/assets/javascripts/directives/cart.js.erb index 816253088..efafc2763 100644 --- a/app/assets/javascripts/directives/cart.js.erb +++ b/app/assets/javascripts/directives/cart.js.erb @@ -77,15 +77,15 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', 'machine_reservations', 'space_reservations', 'events_reservations' - ].map(k => { - return _.filter($scope.user[k], r => { + ].map(function (k) { + return _.filter($scope.user[k], function(r) { return slot.start.isSame(r.start_at) || (slot.end.isAfter(r.start_at) && slot.end.isBefore(r.end_at)) || (slot.start.isAfter(r.start_at) && slot.start.isBefore(r.end_at)) || (slot.start.isBefore(r.start_at) && slot.end.isAfter(r.end_at)); - }); + }) }); - sameTimeReservations = _.union(...sameTimeReservations); + sameTimeReservations = _.union.apply(null, sameTimeReservations); if (sameTimeReservations.length > 0) { const modalInstance = $uibModal.open({ animation: true, @@ -93,7 +93,7 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', size: 'md', controller: 'ReserveSlotSameTimeController', resolve: { - sameTimeReservations: function() { return sameTimeReservations; }, + sameTimeReservations: function() { return sameTimeReservations; } } }); modalInstance.result.then(function(res) { diff --git a/doc/environment.md b/doc/environment.md index 7cef275b4..8e43aadb8 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -111,7 +111,7 @@ If set to 'false' the phone number won't be required to register a new user on t BOOK_SLOT_AT_SAME_TIME -If set to 'false' user won't book a machine/formation/event slot if he already have a reservation the same day at the same time. +If set to 'false', users won't be able to book a machine/formation/event slot if they already have a reservation the same day at the same time. USER_CONFIRMATION_NEEDED_TO_SIGN_IN From 392ddc6aa5d2f8201adb658c9963adbbd6de618b Mon Sep 17 00:00:00 2001 From: Sylvain Date: Tue, 11 Feb 2020 11:01:24 +0100 Subject: [PATCH 3/4] wording --- config/locales/app.shared.en.yml | 6 +++--- config/locales/app.shared.es.yml | 6 +++--- config/locales/app.shared.fr.yml | 6 +++--- config/locales/app.shared.pt.yml | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index beeb04ea4..f17d977c9 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -439,6 +439,6 @@ en: a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." none: "None" online_payment_disabled: "Online payment is not available. Please contact the Fablab reception directly." - slot_at_same_time: "Booking slot with others reservations at the same time" - do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot with others slots at the same time ?" - unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because you really have following reservation at the same time." + slot_at_same_time: "Conflict with others reservations" + do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot? Other bookings take place at the same time" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because the following reservation occurs at the same time." diff --git a/config/locales/app.shared.es.yml b/config/locales/app.shared.es.yml index 2a16d1a3b..b38f43409 100644 --- a/config/locales/app.shared.es.yml +++ b/config/locales/app.shared.es.yml @@ -416,6 +416,6 @@ es: a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." none: "Ninguno" online_payment_disabled: "El pago en línea no está disponible. Póngase en contacto directamente con la recepción de Fablab." - slot_at_same_time: "Booking slot with others reservations at the same time" - do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot with others slots in same time ?" - unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because you really have following reservation at the same time." + slot_at_same_time: "Conflict with others reservations" + do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot? Other bookings take place at the same time" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because the following reservation occurs at the same time." diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index 44a15ce34..bf9024597 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -439,6 +439,6 @@ fr: a_problem_occurred_during_the_payment_process_please_try_again_later: "Il y a eu un problème lors de la procédure de paiement. Veuillez réessayer plus tard." none: "Aucune" online_payment_disabled: "Le payment par carte bancaire n'est pas disponible. Merci de contacter directement l'accueil du Fablab." - slot_at_same_time: "Réserver un créneau avec autres réservations en même temps" - do_you_really_want_to_book_slot_at_same_time: "Êtes-vous sûr de réserver ce créneau avec autres réservations en même temps ?" - unable_to_book_slot_because_really_have_reservation_at_same_time: "Impossible de réserver ce créneau parce qu'il y a déjà des réservations ci-desous en même temps." + slot_at_same_time: "Conflit avec d'autres réservations" + do_you_really_want_to_book_slot_at_same_time: "Êtes-vous sûr de réserver ce créneau ? D'autres réservations ont lieu en même temps" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Impossible de réserver ce créneau car les réservations ci-dessous ont lieu en même temps." diff --git a/config/locales/app.shared.pt.yml b/config/locales/app.shared.pt.yml index 745657122..fc16a7180 100755 --- a/config/locales/app.shared.pt.yml +++ b/config/locales/app.shared.pt.yml @@ -439,6 +439,6 @@ pt: a_problem_occurred_during_the_payment_process_please_try_again_later: "Um problema ocorreu durante o processo de pagamento. Por favor tente novamente mais tarde." none: "Vazio" online_payment_disabled: "O pagamento online não está disponível. Entre em contato diretamente com a recepção do Fablab." - slot_at_same_time: "Booking slot with others reservations at the same time" - do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot with others slots in same time ?" - unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because you really have following reservation at the same time." + slot_at_same_time: "Conflict with others reservations" + do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot? Other bookings take place at the same time" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because the following reservation occurs at the same time." From 7242eb32f8db277fd6d68bf4f97b23592b79b617 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Wed, 12 Feb 2020 14:54:06 +0100 Subject: [PATCH 4/4] allow admin reserve a slot at the same time --- .../templates/shared/_reserve_slot_same_time.html.erb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/templates/shared/_reserve_slot_same_time.html.erb b/app/assets/templates/shared/_reserve_slot_same_time.html.erb index 16f8b9e00..3f5a8afaa 100644 --- a/app/assets/templates/shared/_reserve_slot_same_time.html.erb +++ b/app/assets/templates/shared/_reserve_slot_same_time.html.erb @@ -3,8 +3,8 @@

{{ 'app.shared.cart.slot_at_same_time' }}

-