mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
Ability to configure the duration of a reservation slot
Merge branch 'slot-duration' into dev
This commit is contained in:
commit
d044a3147a
@ -1,10 +1,12 @@
|
|||||||
# Changelog Fab Manager
|
# Changelog Fab Manager
|
||||||
|
|
||||||
- An administrator can delete a member
|
- An administrator can delete a member
|
||||||
|
- Ability to configure the duration of a reservation slot. Previously, only 60 minutes slots were allowed
|
||||||
- Improved user experience in defining slots in the calendar management
|
- Improved user experience in defining slots in the calendar management
|
||||||
- Improved notification email to the member when a rolling subscription is taken
|
- Improved notification email to the member when a rolling subscription is taken
|
||||||
- Handle Ctrl^C in upgrade scripts
|
- Handle Ctrl^C in upgrade scripts
|
||||||
- Updated moment-timezone
|
- Updated moment-timezone
|
||||||
|
- [TODO DEPLOY] add the `SLOT_DURATION` environment variable (see [doc/environment.md](doc/environment.md#SLOT_DURATION) for configuration details)
|
||||||
|
|
||||||
## v4.2.3 2019 October 22
|
## v4.2.3 2019 October 22
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
|||||||
const BOOKING_SNAP = '00:30:00';
|
const BOOKING_SNAP = '00:30:00';
|
||||||
|
|
||||||
// We do not allow the creation of slots that are not a multiple of 60 minutes
|
// We do not allow the creation of slots that are not a multiple of 60 minutes
|
||||||
const SLOT_MULTIPLE = 60;
|
const SLOT_MULTIPLE = Fablab.slotDuration;
|
||||||
|
|
||||||
/* PUBLIC SCOPE */
|
/* PUBLIC SCOPE */
|
||||||
|
|
||||||
@ -283,12 +283,12 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state
|
|||||||
return uiCalendarConfig.calendars.calendar.fullCalendar('unselect');
|
return uiCalendarConfig.calendars.calendar.fullCalendar('unselect');
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that the selected slot is an N-hours multiple (ie. not decimal)
|
// check that the selected slot is an multiple of SLOT_MULTIPLE (ie. not decimal)
|
||||||
const slots = Math.trunc((end.valueOf() - start.valueOf()) / (60 * 1000)) / SLOT_MULTIPLE;
|
const slots = Math.trunc((end.valueOf() - start.valueOf()) / (60 * 1000)) / SLOT_MULTIPLE;
|
||||||
if (!Number.isInteger(slots)) {
|
if (!Number.isInteger(slots)) {
|
||||||
// otherwise, round it to nearest decimal
|
// otherwise, round it to upper decimal
|
||||||
const nearest = Math.round(slots) * SLOT_MULTIPLE;
|
const upper = Math.ceil(slots) * SLOT_MULTIPLE;
|
||||||
end = moment(start).add(nearest, 'minutes');
|
end = moment(start).add(upper, 'minutes');
|
||||||
}
|
}
|
||||||
|
|
||||||
// then we open a modal window to let the admin specify the slot type
|
// then we open a modal window to let the admin specify the slot type
|
||||||
@ -507,21 +507,25 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
|||||||
|
|
||||||
Tag.query().$promise.then(function (data) { $scope.tags = data; });
|
Tag.query().$promise.then(function (data) { $scope.tags = data; });
|
||||||
|
|
||||||
// When we configure a machine availability, do not let the user change the end time, as the total
|
// When we configure a machine/space availability, do not let the user change the end time, as the total
|
||||||
// time must be dividable by 60 minutes (base slot duration). For training availabilities, the user
|
// time must be dividable by Fablab.slotDuration minutes (base slot duration). For training availabilities, the user
|
||||||
// can configure any duration as it does not matters.
|
// can configure any duration as it does not matters.
|
||||||
$scope.$watch('availability.available_type', function (newValue, oldValue, scope) {
|
$scope.$watch('availability.available_type', function (newValue, oldValue, scope) {
|
||||||
if ((newValue === 'machines') || (newValue === 'space')) {
|
if ((newValue === 'machines') || (newValue === 'space')) {
|
||||||
$scope.endDateReadOnly = true;
|
$scope.endDateReadOnly = true;
|
||||||
const diff = moment($scope.end).diff($scope.start, 'hours'); // the result is rounded down by moment.js
|
const slots = Math.trunc(($scope.end.valueOf() - $scope.start.valueOf()) / (60 * 1000)) / Fablab.slotDuration;
|
||||||
$scope.end = moment($scope.start).add(diff, 'hours').toDate();
|
if (!Number.isInteger(slots)) {
|
||||||
|
// otherwise, round it to upper decimal
|
||||||
|
const upper = Math.ceil(slots) * Fablab.slotDuration;
|
||||||
|
$scope.end = moment($scope.start).add(upper, 'minutes').toDate();
|
||||||
|
}
|
||||||
return $scope.availability.end_at = $scope.end;
|
return $scope.availability.end_at = $scope.end;
|
||||||
} else {
|
} else {
|
||||||
return $scope.endDateReadOnly = false;
|
return $scope.endDateReadOnly = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// When the start date is changed, if we are configuring a machine availability,
|
// When the start date is changed, if we are configuring a machine/space availability,
|
||||||
// maintain the relative length of the slot (ie. change the end time accordingly)
|
// maintain the relative length of the slot (ie. change the end time accordingly)
|
||||||
$scope.$watch('start', function (newValue, oldValue, scope) {
|
$scope.$watch('start', function (newValue, oldValue, scope) {
|
||||||
// for machine or space availabilities, adjust the end time
|
// for machine or space availabilities, adjust the end time
|
||||||
@ -542,7 +546,7 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui
|
|||||||
// Maintain consistency between the end time and the date object in the availability object
|
// Maintain consistency between the end time and the date object in the availability object
|
||||||
return $scope.$watch('end', function (newValue, oldValue, scope) {
|
return $scope.$watch('end', function (newValue, oldValue, scope) {
|
||||||
// we prevent the admin from setting the end of the availability before its begining
|
// we prevent the admin from setting the end of the availability before its begining
|
||||||
if (moment($scope.start).add(1, 'hour').isAfter(newValue)) {
|
if (moment($scope.start).add(Fablab.slotDuration, 'minutes').isAfter(newValue)) {
|
||||||
$scope.end = oldValue;
|
$scope.end = oldValue;
|
||||||
}
|
}
|
||||||
// update availability object
|
// update availability object
|
||||||
|
@ -7,7 +7,7 @@ module ApplicationHelper
|
|||||||
require 'message_format'
|
require 'message_format'
|
||||||
|
|
||||||
## machine/spaces availabilities are divided in multiple slots of 60 minutes
|
## machine/spaces availabilities are divided in multiple slots of 60 minutes
|
||||||
SLOT_DURATION ||= 60
|
SLOT_DURATION ||= Rails.application.secrets.slot_duration || 60
|
||||||
|
|
||||||
##
|
##
|
||||||
# Verify if the provided attribute is in the provided attributes array, whatever it exists or not
|
# Verify if the provided attribute is in the provided attributes array, whatever it exists or not
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
Fablab.withoutSpaces = ('<%= Rails.application.secrets.fablab_without_spaces %>' !== 'false');
|
Fablab.withoutSpaces = ('<%= Rails.application.secrets.fablab_without_spaces %>' !== 'false');
|
||||||
Fablab.withoutOnlinePayment = ('<%= Rails.application.secrets.fablab_without_online_payments %>' === 'true');
|
Fablab.withoutOnlinePayment = ('<%= Rails.application.secrets.fablab_without_online_payments %>' === 'true');
|
||||||
Fablab.withoutInvoices = ('<%= Rails.application.secrets.fablab_without_invoices %>' === 'true');
|
Fablab.withoutInvoices = ('<%= Rails.application.secrets.fablab_without_invoices %>' === 'true');
|
||||||
|
Fablab.slotDuration = parseInt("<%= ApplicationHelper::SLOT_DURATION %>", 10);
|
||||||
Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>";
|
Fablab.disqusShortname = "<%= Rails.application.secrets.disqus_shortname %>";
|
||||||
Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>";
|
Fablab.defaultHost = "<%= Rails.application.secrets.default_host %>";
|
||||||
Fablab.gaId = "<%= Rails.application.secrets.google_analytics_id %>";
|
Fablab.gaId = "<%= Rails.application.secrets.google_analytics_id %>";
|
||||||
|
@ -21,6 +21,8 @@ FABLAB_WITHOUT_SPACES: 'true'
|
|||||||
FABLAB_WITHOUT_ONLINE_PAYMENT: 'false'
|
FABLAB_WITHOUT_ONLINE_PAYMENT: 'false'
|
||||||
FABLAB_WITHOUT_INVOICES: 'false'
|
FABLAB_WITHOUT_INVOICES: 'false'
|
||||||
|
|
||||||
|
SLOT_DURATION: '60'
|
||||||
|
|
||||||
DEFAULT_MAIL_FROM: Fab Manager Demo <noreply@fab-manager.com>
|
DEFAULT_MAIL_FROM: Fab Manager Demo <noreply@fab-manager.com>
|
||||||
|
|
||||||
# Configure carefully!
|
# Configure carefully!
|
||||||
|
@ -20,6 +20,7 @@ development:
|
|||||||
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
|
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
|
||||||
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
|
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
|
||||||
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
|
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
|
||||||
|
slot_duration: <%= ENV["SLOT_DURATION"] %>
|
||||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||||
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
||||||
time_zone: <%= ENV["TIME_ZONE"] %>
|
time_zone: <%= ENV["TIME_ZONE"] %>
|
||||||
@ -62,6 +63,7 @@ test:
|
|||||||
fablab_without_spaces: false
|
fablab_without_spaces: false
|
||||||
fablab_without_online_payments: false
|
fablab_without_online_payments: false
|
||||||
fablab_without_invoices: false
|
fablab_without_invoices: false
|
||||||
|
slot_duration: <%= ENV["SLOT_DURATION"] %>
|
||||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||||
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
||||||
time_zone: Paris
|
time_zone: Paris
|
||||||
@ -104,6 +106,7 @@ staging:
|
|||||||
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
|
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
|
||||||
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
|
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
|
||||||
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
|
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
|
||||||
|
slot_duration: <%= ENV["SLOT_DURATION"] %>
|
||||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||||
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
||||||
delivery_method: <%= ENV['DELIVERY_METHOD'] %>
|
delivery_method: <%= ENV['DELIVERY_METHOD'] %>
|
||||||
@ -157,6 +160,7 @@ production:
|
|||||||
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
|
fablab_without_spaces: <%= ENV["FABLAB_WITHOUT_SPACES"] %>
|
||||||
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
|
fablab_without_online_payments: <%= ENV["FABLAB_WITHOUT_ONLINE_PAYMENT"] %>
|
||||||
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
|
fablab_without_invoices: <%= ENV["FABLAB_WITHOUT_INVOICES"] %>
|
||||||
|
slot_duration: <%= ENV["SLOT_DURATION"] %>
|
||||||
default_host: <%= ENV["DEFAULT_HOST"] %>
|
default_host: <%= ENV["DEFAULT_HOST"] %>
|
||||||
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
default_protocol: <%= ENV["DEFAULT_PROTOCOL"] %>
|
||||||
delivery_method: <%= ENV['DELIVERY_METHOD'] %>
|
delivery_method: <%= ENV['DELIVERY_METHOD'] %>
|
||||||
|
@ -102,6 +102,15 @@ Valid stripe API keys are still required, even if you don't require online payme
|
|||||||
If set to 'true', the invoices will be disabled.
|
If set to 'true', the invoices will be disabled.
|
||||||
This is useful if you have your own invoicing system and you want to prevent Fab-manager from generating and sending invoices to members.
|
This is useful if you have your own invoicing system and you want to prevent Fab-manager from generating and sending invoices to members.
|
||||||
**Very important**: if you disable invoices, you still have to configure VAT in the interface to prevent errors in accounting and prices.
|
**Very important**: if you disable invoices, you still have to configure VAT in the interface to prevent errors in accounting and prices.
|
||||||
|
<a name="SLOT_DURATION"></a>
|
||||||
|
|
||||||
|
SLOT_DURATION
|
||||||
|
|
||||||
|
Machine and space availabilities are divided in multiple slots of the duration set by this variable.
|
||||||
|
Default value is 60 minutes (1 hour).
|
||||||
|
|
||||||
|
⚠ Changing this value during the application life may cause serious issues.
|
||||||
|
Please ensure there's no machine/space availabilities opened to reservation or already reserved **in the future** when you change this value.
|
||||||
<a name="DEFAULT_MAIL_FROM"></a>
|
<a name="DEFAULT_MAIL_FROM"></a>
|
||||||
|
|
||||||
DEFAULT_MAIL_FROM
|
DEFAULT_MAIL_FROM
|
||||||
|
@ -14,6 +14,8 @@ FABLAB_WITHOUT_SPACES=true
|
|||||||
FABLAB_WITHOUT_ONLINE_PAYMENT=true
|
FABLAB_WITHOUT_ONLINE_PAYMENT=true
|
||||||
FABLAB_WITHOUT_INVOICES=false
|
FABLAB_WITHOUT_INVOICES=false
|
||||||
|
|
||||||
|
SLOT_DURATION=60
|
||||||
|
|
||||||
DEFAULT_MAIL_FROM=Fab Manager Demo <noreply@fab-manager.com>
|
DEFAULT_MAIL_FROM=Fab Manager Demo <noreply@fab-manager.com>
|
||||||
DEFAULT_HOST=demo.fab-manager.com
|
DEFAULT_HOST=demo.fab-manager.com
|
||||||
DEFAULT_PROTOCOL=http
|
DEFAULT_PROTOCOL=http
|
||||||
|
Loading…
x
Reference in New Issue
Block a user