@@ -204,7 +211,7 @@
- {{ 'app.admin.calendar.divided_in_slots' }}
+ {{ 'app.admin.calendar.divided_in_slots' }}
{{ 'app.admin.calendar.reservable' }}
diff --git a/app/controllers/api/availabilities_controller.rb b/app/controllers/api/availabilities_controller.rb
index cec87315d..3f0e5600c 100644
--- a/app/controllers/api/availabilities_controller.rb
+++ b/app/controllers/api/availabilities_controller.rb
@@ -147,7 +147,7 @@ class API::AvailabilitiesController < API::ApiController
def availability_params
params.require(:availability).permit(:start_at, :end_at, :available_type, :machine_ids, :training_ids, :nb_total_places,
- :is_recurrent, :period, :nb_periods, :end_date,
+ :is_recurrent, :period, :nb_periods, :end_date, :slot_duration,
machine_ids: [], training_ids: [], space_ids: [], tag_ids: [], plan_ids: [],
machines_attributes: %i[id _destroy], plans_attributes: %i[id _destroy])
end
diff --git a/app/controllers/api/slots_controller.rb b/app/controllers/api/slots_controller.rb
index 9efff2509..f3d4a52ea 100644
--- a/app/controllers/api/slots_controller.rb
+++ b/app/controllers/api/slots_controller.rb
@@ -1,7 +1,8 @@
# frozen_string_literal: true
# API Controller for resources of type Slot
-# Slots are used to cut Availabilities into reservable slots of ApplicationHelper::SLOT_DURATION minutes
+# Slots are used to cut Availabilities into reservable slots. The duration of these slots is configured per
+# availability by Availability.slot_duration, or otherwise globally by ApplicationHelper::SLOT_DURATION minutes
class API::SlotsController < API::ApiController
before_action :authenticate_user!
before_action :set_slot, only: %i[update cancel]
diff --git a/app/models/availability.rb b/app/models/availability.rb
index d9a7f458c..71579e532 100644
--- a/app/models/availability.rb
+++ b/app/models/availability.rb
@@ -89,7 +89,8 @@ class Availability < ApplicationRecord
def available_space_places
return unless available_type == 'space'
- ((end_at - start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i * nb_total_places
+ duration = slot_duration || ApplicationHelper::SLOT_DURATION
+ ((end_at - start_at) / duration.minutes).to_i * nb_total_places
end
def title(filter = {})
@@ -159,9 +160,10 @@ class Availability < ApplicationRecord
private
def length_must_be_slot_multiple
- return unless end_at < (start_at + ApplicationHelper::SLOT_DURATION.minutes)
+ duration = slot_duration || ApplicationHelper::SLOT_DURATION
+ return unless end_at < (start_at + duration.minutes)
- errors.add(:end_at, I18n.t('availabilities.length_must_be_slot_multiple', MIN: ApplicationHelper::SLOT_DURATION))
+ errors.add(:end_at, I18n.t('availabilities.length_must_be_slot_multiple', MIN: duration))
end
def should_be_associated
diff --git a/app/models/slot.rb b/app/models/slot.rb
index b44e30775..fe6bf84d4 100644
--- a/app/models/slot.rb
+++ b/app/models/slot.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
-# Time range of duration defined by ApplicationHelper::SLOT_DURATION, slicing an Availability.
+# Time range, slicing an Availability.
+# Its duration is defined by globally by ApplicationHelper::SLOT_DURATION but can be overridden per availability
# During a slot a Reservation is possible
# Only reserved slots are persisted in DB, others are instantiated on the fly
class Slot < ApplicationRecord
diff --git a/app/services/availabilities/availabilities_service.rb b/app/services/availabilities/availabilities_service.rb
index 98cadc034..4d6fd05f7 100644
--- a/app/services/availabilities/availabilities_service.rb
+++ b/app/services/availabilities/availabilities_service.rb
@@ -17,12 +17,13 @@ class Availabilities::AvailabilitiesService
slots = []
availabilities.each do |a|
- ((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
- next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > DateTime.current || user.admin?
+ slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION
+ ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i|
+ next unless (a.start_at + (i * slot_duration).minutes) > DateTime.current || user.admin?
slot = Slot.new(
- start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
- end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
+ start_at: a.start_at + (i * slot_duration).minutes,
+ end_at: a.start_at + (i * slot_duration).minutes + slot_duration.minutes,
availability_id: a.id,
availability: a,
machine: machine,
@@ -43,12 +44,13 @@ class Availabilities::AvailabilitiesService
slots = []
availabilities.each do |a|
- ((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
- next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > DateTime.current || user.admin?
+ slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION
+ ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i|
+ next unless (a.start_at + (i * slot_duration).minutes) > DateTime.current || user.admin?
slot = Slot.new(
- start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
- end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
+ start_at: a.start_at + (i * slot_duration).minutes,
+ end_at: a.start_at + (i * slot_duration).minutes + slot_duration.minutes,
availability_id: a.id,
availability: a,
space: space,
diff --git a/app/services/availabilities/public_availabilities_service.rb b/app/services/availabilities/public_availabilities_service.rb
index 9c3f63a0f..1f55330ff 100644
--- a/app/services/availabilities/public_availabilities_service.rb
+++ b/app/services/availabilities/public_availabilities_service.rb
@@ -15,13 +15,14 @@ class Availabilities::PublicAvailabilitiesService
.where(lock: false)
slots = []
availabilities.each do |a|
+ slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION
a.machines.each do |machine|
next unless machine_ids&.include?(machine.id.to_s)
- ((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
+ ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i|
slot = Slot.new(
- start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
- end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
+ start_at: a.start_at + (i * slot_duration).minutes,
+ end_at: a.start_at + (i * slot_duration).minutes + slot_duration.minutes,
availability_id: a.id,
availability: a,
machine: machine,
@@ -45,13 +46,14 @@ class Availabilities::PublicAvailabilitiesService
slots = []
availabilities.each do |a|
+ slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION
space = a.spaces.first
- ((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
- next unless (a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes) > DateTime.current
+ ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i|
+ next unless (a.start_at + (i * slot_duration).minutes) > DateTime.current
slot = Slot.new(
- start_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes,
- end_at: a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes,
+ start_at: a.start_at + (i * slot_duration).minutes,
+ end_at: a.start_at + (i * slot_duration).minutes + slot_duration.minutes,
availability_id: a.id,
availability: a,
space: space,
diff --git a/app/views/api/availabilities/index.json.jbuilder b/app/views/api/availabilities/index.json.jbuilder
index e98ad286c..c36ca47e5 100644
--- a/app/views/api/availabilities/index.json.jbuilder
+++ b/app/views/api/availabilities/index.json.jbuilder
@@ -5,6 +5,7 @@ json.array!(@availabilities) do |availability|
json.title availability.title
json.start availability.start_at.iso8601
json.end availability.end_at.iso8601
+ json.slot_duration availability.slot_duration
json.available_type availability.available_type
json.machine_ids availability.machine_ids
json.training_ids availability.training_ids
diff --git a/app/views/api/availabilities/show.json.jbuilder b/app/views/api/availabilities/show.json.jbuilder
index a3788e23b..90a9390b7 100644
--- a/app/views/api/availabilities/show.json.jbuilder
+++ b/app/views/api/availabilities/show.json.jbuilder
@@ -3,6 +3,7 @@
json.extract! @availability, :id, :title, :lock, :is_recurrent, :occurrence_id, :period, :nb_periods, :end_date
json.start_at @availability.start_at.iso8601
json.end_at @availability.end_at.iso8601
+json.slot_duration @availability.slot_duration
json.available_type @availability.available_type
json.machine_ids @availability.machine_ids
json.plan_ids @availability.plan_ids
diff --git a/app/views/exports/availabilities_index.xlsx.axlsx b/app/views/exports/availabilities_index.xlsx.axlsx
index e45e778fe..cc8d3fd2f 100644
--- a/app/views/exports/availabilities_index.xlsx.axlsx
+++ b/app/views/exports/availabilities_index.xlsx.axlsx
@@ -16,10 +16,11 @@ wb.add_worksheet(name: t('export_availabilities.machines')) do |sheet|
# data rows
@availabilities.where(available_type: 'machines').order(:start_at).each do |a|
+ slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION
a.machines.each do |m|
- ((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
- start_at = a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes
- end_at = a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes
+ ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i|
+ start_at = a.start_at + (i * slot_duration).minutes
+ end_at = a.start_at + (i * slot_duration).minutes + slot_duration.minutes
reservations = 0
if a.slots&.map(&:start_at)&.include? start_at
reservations = Reservation.where(reservable: m).includes(:slots).where('slots.id' => a.slots, 'slots.start_at' => start_at).count
@@ -83,9 +84,10 @@ if Rails.application.secrets.fablab_without_spaces != 'false'
# data rows
@availabilities.where(available_type: 'space').order(:start_at).each do |a|
- ((a.end_at - a.start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i.times do |i|
- start_at = a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes
- end_at = a.start_at + (i * ApplicationHelper::SLOT_DURATION).minutes + ApplicationHelper::SLOT_DURATION.minutes
+ slot_duration = a.slot_duration || ApplicationHelper::SLOT_DURATION
+ ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i|
+ start_at = a.start_at + (i * slot_duration).minutes
+ end_at = a.start_at + (i * slot_duration).minutes + slot_duration.minutes
reservations = a.slots.where(start_at: start_at).count
data = [
diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml
index 81657a02c..551c5f3aa 100644
--- a/config/locales/app.admin.en.yml
+++ b/config/locales/app.admin.en.yml
@@ -65,7 +65,7 @@ en:
select_nb_period: "Please select a number of periods for the recurrence"
select_end_date: "Please select the date of the last occurrence"
about_to_create: "You are about to create the following {TYPE, select, machines{machine} training{training} space{space} other{other}} {NUMBER, plural, one{slot} other{slots}}:"
- divided_in_slots: "{COUNT, plural, =1{This slot} other{These slots}} will be open for booking in {DURATION}-minutes increments. Contact your system administrator to change this setting."
+ divided_in_slots: "{COUNT, plural, =1{This slot} other{These slots}} will be open for booking in {DURATION}-minutes increments."
reservable: "Reservable(s):"
labels: "Label(s):"
none: "None"
@@ -98,6 +98,8 @@ en:
legend: "Legend"
and: "and"
external_sync: "Calendar synchronization"
+ divide_this_availability: "Divide this availability in slots of"
+ minutes: "minutes"
# import external iCal calendar
icalendar:
icalendar_import: "iCalendar import"
diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml
index 37f08b720..c083c1e93 100644
--- a/config/locales/app.admin.fr.yml
+++ b/config/locales/app.admin.fr.yml
@@ -65,7 +65,7 @@ fr:
select_nb_period: "Veuillez choisir un nombre de périodes pour la récurrence"
select_end_date: "Veuillez choisir la date de dernière occurrence"
about_to_create: "Vous vous apprêtez à créer {NUMBER, plural, one{le créneau} other{les créneaux}} {TYPE, select, machines{machine} training{formation} space{espace} other{autre}} suivant :"
- divided_in_slots: "{COUNT, plural, =1{Ce créneau sera proposé} other{Ces créneaux seront proposés}} à la réservation par tranches de {DURATION} minutes. Contactez votre administrateur système pour modifier ce paramètre."
+ divided_in_slots: "{COUNT, plural, =1{Ce créneau sera proposé} other{Ces créneaux seront proposés}} à la réservation par tranches de {DURATION} minutes."
reservable: "Réservable(s) :"
labels: "Étiquette(s) :"
none: "Aucune"
diff --git a/db/migrate/20200415141809_add_slot_duration_to_availability.rb b/db/migrate/20200415141809_add_slot_duration_to_availability.rb
new file mode 100644
index 000000000..67b094b8e
--- /dev/null
+++ b/db/migrate/20200415141809_add_slot_duration_to_availability.rb
@@ -0,0 +1,8 @@
+# frozen_string_literal:true
+
+# From this migration any availability can override the default SLOT_DURATION value for its own slots
+class AddSlotDurationToAvailability < ActiveRecord::Migration[5.2]
+ def change
+ add_column :availabilities, :slot_duration, :integer
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 1af0e13a3..cbd50fd4a 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_04_08_101654) do
+ActiveRecord::Schema.define(version: 2020_04_15_141809) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
@@ -18,8 +18,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
enable_extension "unaccent"
create_table "abuses", id: :serial, force: :cascade do |t|
- t.integer "signaled_id"
t.string "signaled_type"
+ t.integer "signaled_id"
t.string "first_name"
t.string "last_name"
t.string "email"
@@ -48,8 +48,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
t.string "locality"
t.string "country"
t.string "postal_code"
- t.integer "placeable_id"
t.string "placeable_type"
+ t.integer "placeable_id"
t.datetime "created_at"
t.datetime "updated_at"
end
@@ -63,8 +63,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
end
create_table "assets", id: :serial, force: :cascade do |t|
- t.integer "viewable_id"
t.string "viewable_type"
+ t.integer "viewable_id"
t.string "attachment"
t.string "type"
t.datetime "created_at"
@@ -94,6 +94,7 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
t.string "period"
t.integer "nb_periods"
t.datetime "end_date"
+ t.integer "slot_duration"
end
create_table "availability_tags", id: :serial, force: :cascade do |t|
@@ -131,8 +132,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
end
create_table "credits", id: :serial, force: :cascade do |t|
- t.integer "creditable_id"
t.string "creditable_type"
+ t.integer "creditable_id"
t.integer "plan_id"
t.integer "hours"
t.datetime "created_at"
@@ -284,8 +285,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
end
create_table "invoices", id: :serial, force: :cascade do |t|
- t.integer "invoiced_id"
t.string "invoiced_type"
+ t.integer "invoiced_id"
t.string "stp_invoice_id"
t.integer "total"
t.datetime "created_at"
@@ -348,15 +349,15 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
create_table "notifications", id: :serial, force: :cascade do |t|
t.integer "receiver_id"
- t.integer "attached_object_id"
t.string "attached_object_type"
+ t.integer "attached_object_id"
t.integer "notification_type_id"
t.boolean "is_read", default: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "receiver_type"
t.boolean "is_send", default: false
- t.jsonb "meta_data", default: {}
+ t.jsonb "meta_data", default: "{}"
t.index ["notification_type_id"], name: "index_notifications_on_notification_type_id"
t.index ["receiver_id"], name: "index_notifications_on_receiver_id"
end
@@ -456,8 +457,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
create_table "prices", id: :serial, force: :cascade do |t|
t.integer "group_id"
t.integer "plan_id"
- t.integer "priceable_id"
t.string "priceable_type"
+ t.integer "priceable_id"
t.integer "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@@ -564,8 +565,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
t.text "message"
t.datetime "created_at"
t.datetime "updated_at"
- t.integer "reservable_id"
t.string "reservable_type"
+ t.integer "reservable_id"
t.integer "nb_reserve_places"
t.integer "statistic_profile_id"
t.index ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_id"
@@ -574,8 +575,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
create_table "roles", id: :serial, force: :cascade do |t|
t.string "name"
- t.integer "resource_id"
t.string "resource_type"
+ t.integer "resource_id"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
@@ -866,8 +867,8 @@ ActiveRecord::Schema.define(version: 2020_04_08_101654) do
create_table "wallet_transactions", id: :serial, force: :cascade do |t|
t.integer "wallet_id"
- t.integer "transactable_id"
t.string "transactable_type"
+ t.integer "transactable_id"
t.string "transaction_type"
t.integer "amount"
t.datetime "created_at", null: false