mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
[ongoing] spaces reservation calendar
This commit is contained in:
parent
1efd506a5d
commit
8e86c4b212
@ -171,3 +171,344 @@ Application.Controllers.controller 'ShowSpaceController', ['$scope', '$state', '
|
||||
, (error)->
|
||||
growl.warning(_t('space_show.the_space_cant_be_deleted_because_it_is_already_reserved_by_some_users'))
|
||||
]
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Controller used in the spaces reservation agenda page.
|
||||
# This controller is very similar to the machine reservation controller with one major difference: here, there is many places
|
||||
# per slots.
|
||||
##
|
||||
|
||||
Application.Controllers.controller "ReserveSpaceController", ["$scope", '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'availabilitySpacesPromise', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig'
|
||||
($scope, $stateParams, Auth, $timeout, Availability, Member, availabilitySpacesPromise, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig) ->
|
||||
|
||||
|
||||
|
||||
### PRIVATE STATIC CONSTANTS ###
|
||||
|
||||
# Color of the selected event backgound
|
||||
SELECTED_EVENT_BG_COLOR = '#ffdd00'
|
||||
|
||||
# Slot free to be booked
|
||||
FREE_SLOT_BORDER_COLOR = '<%= AvailabilityHelper::SPACE_COLOR %>'
|
||||
|
||||
|
||||
|
||||
### PUBLIC SCOPE ###
|
||||
|
||||
## bind the spaces availabilities with full-Calendar events
|
||||
$scope.eventSources = [ { events: availabilitySpacesPromise, textColor: 'black' } ]
|
||||
|
||||
## the user to deal with, ie. the current user for non-admins
|
||||
$scope.ctrl =
|
||||
member: {}
|
||||
|
||||
## list of plans, classified by group
|
||||
$scope.plansClassifiedByGroup = []
|
||||
for group in groupsPromise
|
||||
groupObj = { id: group.id, name: group.name, plans: [] }
|
||||
for plan in plansPromise
|
||||
groupObj.plans.push(plan) if plan.group_id == group.id
|
||||
$scope.plansClassifiedByGroup.push(groupObj)
|
||||
|
||||
## mapping of fullCalendar events.
|
||||
$scope.events =
|
||||
reserved: [] # Slots that the user wants to book
|
||||
modifiable: null # Slot that the user wants to change
|
||||
placable: null # Destination slot for the change
|
||||
paid: [] # Slots that were just booked by the user (transaction ok)
|
||||
moved: null # Slots that were just moved by the user (change done) -> {newSlot:* oldSlot: *}
|
||||
|
||||
## the moment when the slot selection changed for the last time, used to trigger changes in the cart
|
||||
$scope.selectionTime = null
|
||||
|
||||
## the last clicked event in the calender
|
||||
$scope.selectedEvent = null
|
||||
|
||||
## indicates the state of the current view : calendar or plans information
|
||||
$scope.plansAreShown = false
|
||||
|
||||
## will store the user's plan if he choosed to buy one
|
||||
$scope.selectedPlan = null
|
||||
|
||||
## the moment when the plan selection changed for the last time, used to trigger changes in the cart
|
||||
$scope.planSelectionTime = null
|
||||
|
||||
## Selected space
|
||||
$scope.space = spacePromise
|
||||
|
||||
## fullCalendar (v2) configuration
|
||||
$scope.calendarConfig = CalendarConfig
|
||||
minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss'))
|
||||
maxTime: moment.duration(moment(settingsPromise.booking_window_end).format('HH:mm:ss'))
|
||||
eventClick: (event, jsEvent, view) ->
|
||||
calendarEventClickCb(event, jsEvent, view)
|
||||
eventRender: (event, element, view) ->
|
||||
eventRenderCb(event, element, view)
|
||||
|
||||
## Application global settings
|
||||
$scope.settings = settingsPromise
|
||||
|
||||
## Global config: message to the end user concerning the subscriptions rules
|
||||
$scope.subscriptionExplicationsAlert = settingsPromise.subscription_explications_alert
|
||||
|
||||
## Global config: message to the end user concerning the space reservation
|
||||
$scope.spaceExplicationsAlert = settingsPromise.space_explications_alert
|
||||
|
||||
|
||||
##
|
||||
# Change the last selected slot's appearence to looks like 'added to cart'
|
||||
##
|
||||
$scope.markSlotAsAdded = ->
|
||||
$scope.selectedEvent.backgroundColor = SELECTED_EVENT_BG_COLOR
|
||||
updateCalendar()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Change the last selected slot's appearence to looks like 'never added to cart'
|
||||
##
|
||||
$scope.markSlotAsRemoved = (slot) ->
|
||||
slot.backgroundColor = 'white'
|
||||
slot.title = ''
|
||||
slot.borderColor = FREE_SLOT_BORDER_COLOR
|
||||
slot.id = null
|
||||
slot.isValid = false
|
||||
slot.is_reserved = false
|
||||
slot.can_modify = false
|
||||
slot.offered = false
|
||||
slot.is_completed = false if slot.is_completed
|
||||
updateCalendar()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback when a slot was successfully cancelled. Reset the slot style as 'ready to book'
|
||||
##
|
||||
$scope.slotCancelled = ->
|
||||
$scope.markSlotAsRemoved($scope.selectedEvent)
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Change the last selected slot's appearence to looks like 'currently looking for a new destination to exchange'
|
||||
##
|
||||
$scope.markSlotAsModifying = ->
|
||||
$scope.selectedEvent.backgroundColor = '#eee'
|
||||
$scope.selectedEvent.title = _t('space_reserve.i_change')
|
||||
updateCalendar()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Change the last selected slot's appearence to looks like 'the slot being exchanged will take this place'
|
||||
##
|
||||
$scope.changeModifyTrainingSlot = ->
|
||||
if $scope.events.placable
|
||||
$scope.events.placable.backgroundColor = 'white'
|
||||
$scope.events.placable.title = ''
|
||||
if !$scope.events.placable or $scope.events.placable._id != $scope.selectedEvent._id
|
||||
$scope.selectedEvent.backgroundColor = '#bbb'
|
||||
$scope.selectedEvent.title = _t('space_reserve.i_shift')
|
||||
updateCalendar()
|
||||
|
||||
|
||||
##
|
||||
# When modifying an already booked reservation, callback when the modification was successfully done.
|
||||
##
|
||||
$scope.modifyTrainingSlot = ->
|
||||
$scope.events.placable.title = if $scope.currentUser.role isnt 'admin' then _t('space_reserve.i_ve_reserved') else ''
|
||||
$scope.events.placable.backgroundColor = 'white'
|
||||
$scope.events.placable.borderColor = $scope.events.modifiable.borderColor
|
||||
$scope.events.placable.id = $scope.events.modifiable.id
|
||||
$scope.events.placable.is_reserved = true
|
||||
$scope.events.placable.can_modify = true
|
||||
|
||||
$scope.events.modifiable.backgroundColor = 'white'
|
||||
$scope.events.modifiable.title = ''
|
||||
$scope.events.modifiable.borderColor = FREE_SLOT_BORDER_COLOR
|
||||
$scope.events.modifiable.id = null
|
||||
$scope.events.modifiable.is_reserved = false
|
||||
$scope.events.modifiable.can_modify = false
|
||||
$scope.events.modifiable.is_completed = false if $scope.events.modifiable.is_completed
|
||||
|
||||
updateCalendar()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Cancel the current booking modification, reseting the whole process
|
||||
##
|
||||
$scope.cancelModifyTrainingSlot = ->
|
||||
if $scope.events.placable
|
||||
$scope.events.placable.backgroundColor = 'white'
|
||||
$scope.events.placable.title = $scope.events.placable.training.name
|
||||
$scope.events.modifiable.title = if $scope.currentUser.role isnt 'admin' then _t('i_ve_reserved') else ''
|
||||
$scope.events.modifiable.backgroundColor = 'white'
|
||||
|
||||
updateCalendar()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback to deal with the reservations of the user selected in the dropdown list instead of the current user's
|
||||
# reservations. (admins only)
|
||||
##
|
||||
$scope.updateMember = ->
|
||||
if $scope.ctrl.member
|
||||
Member.get {id: $scope.ctrl.member.id}, (member) ->
|
||||
$scope.ctrl.member = member
|
||||
Availability.spaces {spaceId: $scope.space.id, member_id: $scope.ctrl.member.id}, (spaces) ->
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar 'removeEvents'
|
||||
$scope.eventSources.splice(0, 1,
|
||||
events: spaces
|
||||
textColor: 'black'
|
||||
)
|
||||
# as the events are re-fetched for the new user, we must re-init the cart
|
||||
$scope.events.reserved = []
|
||||
$scope.selectedPlan = null
|
||||
$scope.plansAreShown = false
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Add the provided plan to the current shopping cart
|
||||
# @param plan {Object} the plan to subscribe
|
||||
##
|
||||
$scope.selectPlan = (plan) ->
|
||||
# toggle selected plan
|
||||
if $scope.selectedPlan != plan
|
||||
$scope.selectedPlan = plan
|
||||
else
|
||||
$scope.selectedPlan = null
|
||||
$scope.planSelectionTime = new Date()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Changes the user current view from the plan subsription screen to the machine reservation agenda
|
||||
# @param e {Object} see https://docs.angularjs.org/guide/expression#-event-
|
||||
##
|
||||
$scope.doNotSubscribePlan = (e)->
|
||||
e.preventDefault()
|
||||
$scope.plansAreShown = false
|
||||
$scope.selectedPlan = null
|
||||
$scope.planSelectionTime = new Date()
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Switch the user's view from the reservation agenda to the plan subscription
|
||||
##
|
||||
$scope.showPlans = ->
|
||||
$scope.plansAreShown = true
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Once the reservation is booked (payment process successfully completed), change the event style
|
||||
# in fullCalendar, update the user's subscription and free-credits if needed
|
||||
# @param reservation {Object}
|
||||
##
|
||||
$scope.afterPayment = (reservation)->
|
||||
$scope.events.paid[0].backgroundColor = 'white'
|
||||
$scope.events.paid[0].is_reserved = true
|
||||
$scope.events.paid[0].can_modify = true
|
||||
updateSpaceSlotId($scope.events.paid[0], reservation)
|
||||
$scope.events.paid[0].borderColor = '#b2e774'
|
||||
$scope.events.paid[0].title = _t('space_reserve.i_ve_reserved')
|
||||
|
||||
|
||||
if $scope.selectedPlan
|
||||
$scope.ctrl.member.subscribed_plan = angular.copy($scope.selectedPlan)
|
||||
Auth._currentUser.subscribed_plan = angular.copy($scope.selectedPlan)
|
||||
$scope.plansAreShown = false
|
||||
$scope.selectedPlan = null
|
||||
$scope.ctrl.member.training_credits = angular.copy(reservation.user.training_credits)
|
||||
$scope.ctrl.member.machine_credits = angular.copy(reservation.user.machine_credits)
|
||||
Auth._currentUser.training_credits = angular.copy(reservation.user.training_credits)
|
||||
Auth._currentUser.machine_credits = angular.copy(reservation.user.machine_credits)
|
||||
|
||||
refetchCalendar()
|
||||
|
||||
|
||||
|
||||
### PRIVATE SCOPE ###
|
||||
|
||||
##
|
||||
# Kind of constructor: these actions will be realized first when the controller is loaded
|
||||
##
|
||||
initialize = ->
|
||||
if $scope.currentUser.role isnt 'admin'
|
||||
Member.get id: $scope.currentUser.id, (member) ->
|
||||
$scope.ctrl.member = member
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Triggered when the user clicks on a reservation slot in the agenda.
|
||||
# Defines the behavior to adopt depending on the slot status (already booked, free, ready to be reserved ...),
|
||||
# the user's subscription (current or about to be took) and the time (the user cannot modify a booked reservation
|
||||
# if it's too late).
|
||||
# @see http://fullcalendar.io/docs/mouse/eventClick/
|
||||
##
|
||||
calendarEventClickCb = (event, jsEvent, view) ->
|
||||
$scope.selectedEvent = event
|
||||
if $stateParams.id is 'all'
|
||||
$scope.training = event.training
|
||||
$scope.selectionTime = new Date()
|
||||
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Triggered when fullCalendar tries to graphicaly render an event block.
|
||||
# Append the event tag into the block, just after the event title.
|
||||
# @see http://fullcalendar.io/docs/event_rendering/eventRender/
|
||||
##
|
||||
eventRenderCb = (event, element, view)->
|
||||
if $scope.currentUser.role is 'admin' and event.tags.length > 0
|
||||
html = ''
|
||||
for tag in event.tags
|
||||
html += "<span class='label label-success text-white' title='#{tag.name}'>#{tag.name}</span>"
|
||||
element.find('.fc-time').append(html)
|
||||
return
|
||||
|
||||
|
||||
|
||||
##
|
||||
# After payment, update the id of the newly reserved slot with the id returned by the server.
|
||||
# This will allow the user to modify the reservation he just booked.
|
||||
# @param slot {Object}
|
||||
# @param reservation {Object}
|
||||
##
|
||||
updateSpaceSlotId = (slot, reservation)->
|
||||
angular.forEach reservation.slots, (s)->
|
||||
if slot.start_at == slot.start_at
|
||||
slot.id = s.id
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Update the calendar's display to render the new attributes of the events
|
||||
##
|
||||
updateCalendar = ->
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents'
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Asynchronously fetch the events from the API and refresh the calendar's view with these new events
|
||||
##
|
||||
refetchCalendar = ->
|
||||
$timeout ->
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar 'refetchEvents'
|
||||
uiCalendarConfig.calendars.calendar.fullCalendar 'rerenderEvents'
|
||||
|
||||
|
||||
|
||||
## !!! MUST BE CALLED AT THE END of the controller
|
||||
initialize()
|
||||
|
||||
]
|
@ -87,7 +87,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", '$sta
|
||||
# Color of the selected event backgound
|
||||
SELECTED_EVENT_BG_COLOR = '#ffdd00'
|
||||
|
||||
# Slot already booked by the current user
|
||||
# Slot free to be booked
|
||||
FREE_SLOT_BORDER_COLOR = '<%= AvailabilityHelper::TRAINING_COLOR %>'
|
||||
|
||||
|
||||
|
@ -445,6 +445,39 @@ angular.module('application.router', ['ui.router']).
|
||||
]
|
||||
.state 'app.logged.space_reserve',
|
||||
url: '/spaces/:id/reserve'
|
||||
abstract: Fablab.withoutSpaces
|
||||
views:
|
||||
'main@':
|
||||
templateUrl: '<%= asset_path "spaces/reserve.html" %>'
|
||||
controller: 'ReserveSpaceController'
|
||||
resolve:
|
||||
spacePromise: ['Space', '$stateParams', (Space, $stateParams)->
|
||||
Space.get(id: $stateParams.id).$promise
|
||||
]
|
||||
availabilitySpacesPromise: ['Availability', '$stateParams', (Availability, $stateParams)->
|
||||
Availability.spaces({spaceId: $stateParams.id}).$promise
|
||||
]
|
||||
plansPromise: ['Plan', (Plan)->
|
||||
Plan.query().$promise
|
||||
]
|
||||
groupsPromise: ['Group', (Group)->
|
||||
Group.query().$promise
|
||||
]
|
||||
settingsPromise: ['Setting', (Setting)->
|
||||
Setting.query(names: "['booking_window_start',
|
||||
'booking_window_end',
|
||||
'booking_move_enable',
|
||||
'booking_move_delay',
|
||||
'booking_cancel_enable',
|
||||
'booking_cancel_delay',
|
||||
'subscription_explications_alert',
|
||||
'space_explications_alert']").$promise
|
||||
]
|
||||
translations: [ 'Translations', (Translations) ->
|
||||
Translations.query(['app.logged.space_reserve', 'app.shared.plan_subscribe', 'app.shared.member_select',
|
||||
'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal',
|
||||
'app.shared.wallet', 'app.shared.coupon_input', 'app.shared.cart']).$promise
|
||||
]
|
||||
|
||||
# trainings
|
||||
.state 'app.public.trainings_list',
|
||||
|
@ -17,6 +17,11 @@ Application.Services.factory 'Availability', ["$resource", ($resource)->
|
||||
url: '/api/availabilities/trainings/:trainingId'
|
||||
params: {trainingId: "@trainingId"}
|
||||
isArray: true
|
||||
spaces:
|
||||
method: 'GET'
|
||||
url: '/api/availabilities/spaces/:spaceId'
|
||||
params: {spaceId: "@spaceId"}
|
||||
isArray: true
|
||||
update:
|
||||
method: 'PUT'
|
||||
]
|
||||
|
@ -7,17 +7,7 @@
|
||||
</div>
|
||||
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
|
||||
<section class="heading-title">
|
||||
<h1 ng-hide="training" translate>{{ 'trainings_planning' }}</h1>
|
||||
<h1 ng-show="training"><span translate>{{ 'planning_of' }}</span> {{training.name}}</h1>
|
||||
</section>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
||||
<section class="heading-actions wrapper">
|
||||
<a class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs"
|
||||
ui-sref="app.logged.trainings_reserve({id:'all'})"
|
||||
ng-show="training"
|
||||
role="button"
|
||||
translate>{{ 'all_trainings' }}</a>
|
||||
<h1 translate translate-values="{NAME:space.name}">{{ 'space_reserve.planning_of_space_NAME' }}</h1>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
@ -37,8 +27,6 @@
|
||||
<select-member></select-member>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<cart slot="selectedEvent"
|
||||
slot-selection-time="selectionTime"
|
||||
events="events"
|
||||
@ -55,27 +43,17 @@
|
||||
on-slot-modify-unselect="changeModifyTrainingSlot"
|
||||
on-slot-cancel-success="slotCancelled"
|
||||
after-payment="afterPayment"
|
||||
reservable-id="{{training.id}}"
|
||||
reservable-type="Training"
|
||||
reservable-name="{{training.name}}"
|
||||
limit-to-one-slot="true"></cart>
|
||||
reservable-id="{{space.id}}"
|
||||
reservable-type="Space"
|
||||
reservable-name="{{space.name}}"></cart>
|
||||
|
||||
|
||||
<uib-alert type="info m">
|
||||
<p class="text-sm font-bold">
|
||||
<i class="fa fa-lightbulb-o"></i>
|
||||
<span ng-bind-html="trainingInformationMessage"></span>
|
||||
</p>
|
||||
</uib-alert>
|
||||
|
||||
<uib-alert type="warning m">
|
||||
<p class="text-sm">
|
||||
<i class="fa fa-warning"></i>
|
||||
<span ng-bind-html="trainingExplicationsAlert"></span>
|
||||
<span ng-bind-html="spaceExplicationsAlert"></span>
|
||||
</p>
|
||||
</uib-alert>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
@ -156,6 +156,34 @@ class API::AvailabilitiesController < API::ApiController
|
||||
end
|
||||
end
|
||||
|
||||
def spaces
|
||||
if params[:member_id]
|
||||
@user = User.find(params[:member_id])
|
||||
else
|
||||
@user = current_user
|
||||
end
|
||||
@current_user_role = current_user.is_admin? ? 'admin' : 'user'
|
||||
@space = Space.friendly.find(params[:space_id])
|
||||
@slots = []
|
||||
@reservations = Reservation.where('reservable_type = ? and reservable_id = ?', @space.class.to_s, @space.id).includes(:slots, user: [:profile]).references(:slots, :user).where('slots.start_at > ?', Time.now)
|
||||
if @user.is_admin?
|
||||
@availabilities = @space.availabilities.includes(:tags).where("end_at > ? AND available_type = 'space'", Time.now)
|
||||
else
|
||||
end_at = 1.month.since
|
||||
end_at = 3.months.since if is_subscription_year(@user)
|
||||
@availabilities = @space.availabilities.includes(:tags).where("end_at > ? AND end_at < ? AND available_type = 'space'", Time.now, end_at).where('availability_tags.tag_id' => @user.tag_ids.concat([nil]))
|
||||
end
|
||||
@availabilities.each do |a|
|
||||
((a.end_at - a.start_at)/SLOT_DURATION.minutes).to_i.times do |i|
|
||||
if (a.start_at + (i * SLOT_DURATION).minutes) > Time.now
|
||||
slot = Slot.new(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, title: '')
|
||||
slot = verify_space_is_reserved(slot, @reservations, current_user, @current_user_role)
|
||||
@slots << slot
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def reservations
|
||||
authorize Availability
|
||||
@reservation_slots = @availability.slots.includes(reservation: [user: [:profile]]).order('slots.start_at ASC')
|
||||
@ -203,6 +231,28 @@ class API::AvailabilitiesController < API::ApiController
|
||||
slot
|
||||
end
|
||||
|
||||
def verify_space_is_reserved(slot, reservations, user, user_role)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
if slot.availability.spaces.first.id == r.reservable_id
|
||||
if s.start_at == slot.start_at and s.canceled_at == nil
|
||||
slot.id = s.id
|
||||
slot.is_reserved = true
|
||||
slot.title = t('availabilities.not_available')
|
||||
slot.can_modify = true if user_role === 'admin'
|
||||
slot.reservation = r
|
||||
end
|
||||
if s.start_at == slot.start_at and r.user == user and s.canceled_at == nil
|
||||
slot.title = t('availabilities.i_ve_reserved')
|
||||
slot.can_modify = true
|
||||
slot.is_reserved_by_current_user = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
slot
|
||||
end
|
||||
|
||||
def verify_training_event_is_reserved(availability, reservations, user)
|
||||
reservations.each do |r|
|
||||
r.slots.each do |s|
|
||||
|
@ -21,7 +21,23 @@ module AvailabilityHelper
|
||||
end
|
||||
|
||||
def machines_slot_border_color(slot)
|
||||
slot.is_reserved ? (slot.is_reserved_by_current_user ? IS_RESERVED_BY_CURRENT_USER : IS_COMPLETED) : MACHINE_COLOR
|
||||
if slot.is_reserved
|
||||
slot.is_reserved_by_current_user ? IS_RESERVED_BY_CURRENT_USER : IS_COMPLETED
|
||||
else
|
||||
MACHINE_COLOR
|
||||
end
|
||||
end
|
||||
|
||||
def space_slot_border_color(slot)
|
||||
if slot.is_reserved
|
||||
if slot.is_reserved_by_current_user
|
||||
IS_RESERVED_BY_CURRENT_USER
|
||||
elsif slot.availability.is_completed
|
||||
IS_COMPLETED
|
||||
end
|
||||
else
|
||||
SPACE_COLOR
|
||||
end
|
||||
end
|
||||
|
||||
def trainings_events_border_color(availability)
|
||||
@ -30,10 +46,15 @@ module AvailabilityHelper
|
||||
elsif availability.is_completed
|
||||
IS_COMPLETED
|
||||
else
|
||||
if availability.available_type == 'training'
|
||||
TRAINING_COLOR
|
||||
else
|
||||
EVENT_COLOR
|
||||
case availability.available_type
|
||||
when 'training'
|
||||
TRAINING_COLOR
|
||||
when 'event'
|
||||
EVENT_COLOR
|
||||
when 'space'
|
||||
SPACE_COLOR
|
||||
else
|
||||
'#000'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -99,6 +99,13 @@ class Price < ActiveRecord::Base
|
||||
_amount += get_slot_price(amount, slot, admin, _elements)
|
||||
end
|
||||
|
||||
# Space reservation
|
||||
when Space
|
||||
amount = reservable.prices.find_by(group_id: user.group_id, plan_id: plan.try(:id)).amount
|
||||
slots.each do |slot|
|
||||
_amount += get_slot_price(amount, slot, admin, _elements)
|
||||
end
|
||||
|
||||
# Unknown reservation type
|
||||
else
|
||||
raise NotImplementedError
|
||||
|
@ -126,6 +126,28 @@ class Reservation < ActiveRecord::Base
|
||||
self.invoice.invoice_items.push InvoiceItem.new(amount: ii_amount, stp_invoice_item_id: (ii.id if ii), description: description)
|
||||
end
|
||||
|
||||
# === Space reservation ===
|
||||
when Space
|
||||
base_amount = reservable.prices.find_by(group_id: user.group_id, plan_id: plan.try(:id)).amount
|
||||
|
||||
slots.each_with_index do |slot, index|
|
||||
description = reservable.name + " #{I18n.l slot.start_at, format: :long} - #{I18n.l slot.end_at, format: :hour_minute}"
|
||||
|
||||
ii_amount = base_amount # ii_amount default to base_amount
|
||||
ii_amount = 0 if slot.offered and on_site # if it's a local payment and slot is offered free
|
||||
|
||||
unless on_site # if it's local payment then do not create Stripe::InvoiceItem
|
||||
ii = Stripe::InvoiceItem.create(
|
||||
customer: user.stp_customer_id,
|
||||
amount: ii_amount,
|
||||
currency: Rails.application.secrets.stripe_currency,
|
||||
description: description
|
||||
)
|
||||
invoice_items << ii
|
||||
end
|
||||
self.invoice.invoice_items.push InvoiceItem.new(amount: ii_amount, stp_invoice_item_id: (ii.id if ii), description: description)
|
||||
end
|
||||
|
||||
# === Unknown reservation type ===
|
||||
else
|
||||
raise NotImplementedError
|
||||
|
@ -11,17 +11,19 @@ module UsersCredits
|
||||
if user
|
||||
@manager = Managers::User.new(user)
|
||||
elsif reservation
|
||||
if reservation.reservable_type == "Training"
|
||||
if reservation.reservable_type == 'Training'
|
||||
@manager = Managers::Training.new(reservation, plan)
|
||||
elsif reservation.reservable_type == "Machine"
|
||||
elsif reservation.reservable_type == 'Machine'
|
||||
@manager = Managers::Machine.new(reservation, plan)
|
||||
elsif reservation.reservable_type == "Event"
|
||||
elsif reservation.reservable_type == 'Event'
|
||||
@manager = Managers::Event.new(reservation, plan)
|
||||
elsif reservation.reservable_type == 'Space'
|
||||
@manager = Managers::Space.new(reservation, plan)
|
||||
else
|
||||
raise ArgumentError, "reservation.reservable_type must be Training, Machine or Event"
|
||||
raise ArgumentError, 'reservation.reservable_type must be Training, Machine, Space or Event'
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "you have to pass either a reservation or a user to initialize a UsersCredits::Manager"
|
||||
raise ArgumentError, 'you have to pass either a reservation or a user to initialize a UsersCredits::Manager'
|
||||
end
|
||||
end
|
||||
|
||||
@ -152,5 +154,14 @@ module UsersCredits
|
||||
def update_credits
|
||||
end
|
||||
end
|
||||
|
||||
class Space < Reservation
|
||||
def will_use_credits?
|
||||
false
|
||||
end
|
||||
|
||||
def update_credits
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
26
app/views/api/availabilities/spaces.json.jbuilder
Normal file
26
app/views/api/availabilities/spaces.json.jbuilder
Normal file
@ -0,0 +1,26 @@
|
||||
json.array!(@slots) do |slot|
|
||||
json.id slot.id if slot.id
|
||||
json.can_modify slot.can_modify
|
||||
json.title slot.title
|
||||
json.start slot.start_at.iso8601
|
||||
json.end slot.end_at.iso8601
|
||||
json.is_reserved slot.is_reserved
|
||||
json.backgroundColor 'white'
|
||||
json.borderColor space_slot_border_color(slot)
|
||||
|
||||
json.availability_id slot.availability_id
|
||||
json.space do
|
||||
json.id slot.availability.spaces.first.id
|
||||
json.name slot.availability.spaces.first.name
|
||||
end
|
||||
# the user who booked the slot ...
|
||||
json.user do
|
||||
json.id slot.reservation.user.id
|
||||
json.name slot.reservation.user.profile.full_name
|
||||
end if @current_user_role == 'admin' and slot.reservation # ... if the slot was reserved
|
||||
json.tag_ids slot.availability.tag_ids
|
||||
json.tags slot.availability.tags do |t|
|
||||
json.id t.id
|
||||
json.name t.name
|
||||
end
|
||||
end
|
@ -112,6 +112,14 @@ en:
|
||||
cancel_my_selection: "Cancel my selection"
|
||||
i_ve_reserved: "I've reserved"
|
||||
|
||||
space_reserve:
|
||||
# book a space
|
||||
space_reserve:
|
||||
planning_of_space_NAME: "Planning of the {{NAME}} space" # angular interpolation
|
||||
i_ve_reserved: "I've reserved"
|
||||
i_shift: "I shift"
|
||||
i_change: "I change"
|
||||
|
||||
notifications:
|
||||
notifications_center: "Notifications center"
|
||||
mark_all_as_read: "Mark all as read"
|
||||
|
@ -112,6 +112,14 @@ fr:
|
||||
cancel_my_selection: "Annuler ma sélection"
|
||||
i_ve_reserved: "J'ai réservé"
|
||||
|
||||
space_reserve:
|
||||
# réserver un espace
|
||||
space_reserve:
|
||||
planning_of_space_NAME: "Planning de l'espace {{NAME}}" # angular interpolation
|
||||
i_ve_reserved: "J'ai réservé"
|
||||
i_shift: "Je déplace"
|
||||
i_change: "Je change"
|
||||
|
||||
notifications:
|
||||
notifications_center: "Centre de notifications"
|
||||
mark_all_as_read: "Tout marquer comme lu"
|
||||
|
@ -81,6 +81,7 @@ Rails.application.routes.draw do
|
||||
resources :availabilities do
|
||||
get 'machines/:machine_id', action: 'machine', on: :collection
|
||||
get 'trainings/:training_id', action: 'trainings', on: :collection
|
||||
get 'spaces/:space_id', action: 'spaces', on: :collection
|
||||
get 'reservations', on: :member
|
||||
get 'public', on: :collection
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user