1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-17 06:52:27 +01:00

Merge branch 'disable' into dev

This commit is contained in:
Sylvain 2017-10-11 16:11:02 +02:00
commit 18b8d516ee
73 changed files with 869 additions and 348 deletions

View File

@ -6,11 +6,15 @@
- Removed cross hack in full-calendar
- Confirmation before slot delete
- Confirmation and error handling while deleting an event
- Ability to disable groups, machines, plans, spaces and trainings
- Improved responsiveness of machines and spaces lists
- Fix a typo: error message while creating a machine slot
- Fix a bug: events pagination is bogus in admin's monitoring when selecting non default filter
- Fix a bug: social sharing failed for projects with an underscore in their name
- Fix a bug: html tags of events description not stripped when sharing on social network
- Fix a bug: event, space, training or machine main image on description page is deformed on small devices
- Fix a bug: profile completion of non SSO-imported users trigger a fuzzy email
- Fix a bug: creation of negative credits
- Updated test data to allow passing test suite
## v2.5.14 2017 September 12

View File

@ -309,13 +309,13 @@ Application.Controllers.controller 'CreateEventModalController', ["$scope", "$ui
$scope.end = end
## machines list
$scope.machines = machinesPromise
$scope.machines = machinesPromise.filter (m) -> !m.disabled
## trainings list
$scope.trainings = trainingsPromise
$scope.trainings = trainingsPromise.filter (t) -> !t.disabled
## spaces list
$scope.spaces = spacesPromise
$scope.spaces = spacesPromise.filter (s) -> !s.disabled
## machines associated with the created slot
$scope.selectedMachines = []

View File

@ -3,6 +3,15 @@ Application.Controllers.controller "GroupsController", ["$scope", 'groupsPromise
## List of users groups
$scope.groups = groupsPromise
## Default: we show only enabled groups
$scope.groupFiltering = 'enabled'
## Available options for filtering groups by status
$scope.filterDisabled = [
'enabled',
'disabled',
'all',
]
##
@ -31,20 +40,20 @@ Application.Controllers.controller "GroupsController", ["$scope", 'groupsPromise
##
# Saves a new group / Update an existing group to the server (form validation callback)
# @param data {Object} group name
# @param [data] {number} group id, in case of update
# @param [id] {number} group id, in case of update
##
$scope.saveGroup = (data, id) ->
if id?
Group.update {id: id}, { group: data }, (response) ->
growl.success(_t('changes_successfully_saved'))
growl.success(_t('group_form.changes_successfully_saved'))
, (error) ->
growl.error(_t('an_error_occurred_while_saving_changes'))
growl.error(_t('group_form.an_error_occurred_while_saving_changes'))
else
Group.save { group: data }, (resp)->
growl.success(_t('new_group_successfully_saved'))
growl.success(_t('group_form.new_group_successfully_saved'))
$scope.groups[$scope.groups.length-1].id = resp.id
, (error) ->
growl.error(_t('an_error_occurred_when_saving_the_new_group'))
growl.error(_t('.group_forman_error_occurred_when_saving_the_new_group'))
$scope.groups.splice($scope.groups.length-1, 1)
@ -55,10 +64,27 @@ Application.Controllers.controller "GroupsController", ["$scope", 'groupsPromise
##
$scope.removeGroup = (index) ->
Group.delete { id: $scope.groups[index].id }, (resp) ->
growl.success(_t('group_successfully_deleted'))
growl.success(_t('group_form.group_successfully_deleted'))
$scope.groups.splice(index, 1)
, (error) ->
growl.error(_t('unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it'))
growl.error(_t('group_form.unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it'))
##
# Enable/disable the group at the specified index
# @param index {number} group index in the $scope.groups array
##
$scope.toggleDisableGroup = (index) ->
group = $scope.groups[index]
if (!group.disabled && group.users > 0)
growl.error(_t('group_form.unable_to_disable_group_with_users', { USERS: group.users }, 'messageformat'))
else
Group.update {id: group.id}, { group: { disabled: !group.disabled } }, (response) ->
$scope.groups[index] = response
growl.success(_t('group_form.group_successfully_enabled_disabled', { STATUS: response.disabled }, 'messageformat'))
, (error) ->
growl.error(_t('group_form.unable_to_enable_disable_group', { STATUS: !group.disabled }, 'messageformat'))
]

View File

@ -25,13 +25,14 @@ class MembersController
## Retrieve the profiles groups (eg. students ...)
Group.query (groups) ->
$scope.groups = groups.filter (g) -> g.slug != 'admins'
$scope.groups = groups.filter (g) -> g.slug != 'admins' && !g.disabled
## Retrieve the list the available trainings
## Retrieve the list of available trainings
Training.query().$promise.then (data)->
$scope.trainings = data.map (d) ->
id: d.id
name: d.name
disabled: d.disabled
## Default parameters for AngularUI-Bootstrap datepicker
$scope.datePicker =
@ -477,6 +478,14 @@ Application.Controllers.controller "EditMemberController", ["$scope", "$state",
##
# To use as callback in Array.prototype.filter to get only enabled plans
##
$scope.filterDisabledPlans = (plan) ->
!plan.disabled
### PRIVATE SCOPE ###

View File

@ -13,7 +13,7 @@ class PlanController
## groups list
$scope.groups = groups.filter (g) -> g.slug != 'admins'
$scope.groups = groups.filter (g) -> g.slug != 'admins' && !g.disabled
## users with role 'partner', notifiables for a partner plan
$scope.partners = partners.users
@ -175,6 +175,7 @@ Application.Controllers.controller 'EditPlanController', ['$scope', 'groups', 'p
## edited plan data
$scope.plan = planPromise
$scope.plan.type = "Plan" if $scope.plan.type == null
$scope.plan.disabled = 'true' if $scope.plan.disabled
## API URL where the form will be posted
$scope.actionUrl = "/api/plans/" + $stateParams.id
@ -231,26 +232,26 @@ Application.Controllers.controller 'EditPlanController', ['$scope', 'groups', 'p
##
# Retrieve the name of a machine from its ID
# Retrieve the machine from its ID
# @param machine_id {number} machine identifier
# @returns {string} Machine's name
# @returns {Object} Machine
##
$scope.getMachineName = (machine_id) ->
$scope.getMachine = (machine_id) ->
for machine in $scope.machines
if machine.id == machine_id
return machine.name
return machine
##
# Retrieve the name of a space from its ID
# Retrieve the space from its ID
# @param space_id {number} space identifier
# @returns {string} Space's name
# @returns {Object} Space
##
$scope.getSpaceName = (space_id) ->
$scope.getSpace = (space_id) ->
for space in $scope.spaces
if space.id == space_id
return space.name
return space

View File

@ -15,9 +15,11 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
## List of available subscriptions plans (eg. student/month, PME/year ...)
$scope.plans = plans
$scope.enabledPlans = plans.filter (p) -> !p.disabled
## List of groups (eg. normal, student ...)
$scope.groups = groups.filter (g) -> g.slug != 'admins'
$scope.enabledGroups = groups.filter (g) -> g.slug != 'admins' && !g.disabled
## Associate free machine hours with subscriptions
$scope.machineCredits = machineCreditsPromise
@ -29,16 +31,18 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
$scope.trainingCreditsGroups = {}
## List of trainings
$scope.trainings = trainingsPromise
$scope.trainings = trainingsPromise.filter (t) -> !t.disabled
## List of machines
$scope.machines = machinesPromise
$scope.enabledMachines = machinesPromise.filter (m) -> !m.disabled
## List of coupons
$scope.coupons = couponsPromise
## List of spaces
$scope.spaces = spacesPromise
$scope.enabledSpaces = spacesPromise.filter (s) -> !s.disabled
## Associate free space hours with subscriptions
$scope.spaceCredits = spacesCreditsPromise
@ -53,6 +57,16 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
$scope.status =
isopen: false
## Default: we show only enabled plans
$scope.planFiltering = 'enabled'
## Available options for filtering plans by status
$scope.filterDisabled = [
'enabled',
'disabled',
'all',
]
$scope.findTrainingsPricing = (trainingsPricings, trainingId, groupId)->
@ -181,21 +195,37 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
##
# In the Credits tab, while editing a machine credit row, select the current machine from the
# drop-down list of machines as the current item.
# In the Credits tab, return the name of the machine/space associated with the given credit
# @param credit {Object} credit object, inherited from $resource
# @returns {String}
##
$scope.showCreditableName = (credit) ->
selected = _t('pricing.not_set')
if credit and credit.creditable_id
object = $scope.getCreditable(credit)
selected = object.name
if credit.creditable_type == 'Machine'
selected += ' ( id. ' + object.id + ' )'
return selected
##
# In the Credits tab, return the machine/space associated with the given credit
# @param credit {Object} credit object, inherited from $resource
# @returns {Object}
##
$scope.getCreditable = (credit) ->
selected = undefined
if credit and credit.creditable_id
if credit.creditable_type == 'Machine'
angular.forEach $scope.machines, (m)->
if m.id == credit.creditable_id
selected = m.name + ' ( id. ' + m.id + ' )'
selected = m
else if credit.creditable_type == 'Space'
angular.forEach $scope.spaces, (s)->
if s.id == credit.creditable_id
selected = s.name
selected = s
return selected
@ -224,6 +254,9 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
, (resp) ->
$scope.machineCredits[$scope.machineCredits.length-1].id = resp.id
growl.success(_t('pricing.credit_was_successfully_saved'))
, (err) ->
$scope.machineCredits.pop()
growl.error(_t('pricing.error_creating_credit'))
##
@ -287,10 +320,14 @@ Application.Controllers.controller "EditPricingController", ["$scope", "$state",
, (resp) ->
$scope.spaceCredits[$scope.spaceCredits.length - 1].id = resp.id
growl.success(_t('pricing.credit_was_successfully_saved'))
, (err) ->
$scope.spaceCredits.pop()
growl.error(_t('pricing.error_creating_credit'))
##
##
# Removes the newly inserted but not saved space credit / Cancel the current space credit modification
# @param rowform {Object} see http://vitalets.github.io/angular-xeditable/
# @param index {number} credit index in the $scope.spaceCredits array

View File

@ -9,9 +9,11 @@
# Provides :
# - $scope.submited(content)
# - $scope.fileinputClass(v)
# - $scope.onDisableToggled
#
# Requires :
# - $state (Ui-Router) [ 'app.admin.trainings' ]
# - $scope.training
##
class TrainingsController
constructor: ($scope, $state) ->
@ -43,6 +45,14 @@ class TrainingsController
##
# Force the 'public_page' attribute to false when the current training is disabled
##
$scope.onDisableToggled = ->
$scope.training.public_page = !$scope.training.disabled
##
# For use with 'ng-class', returns the CSS class name for the uploads previews.
# The preview may show a placeholder or the content of the file depending on the upload state.
@ -167,6 +177,16 @@ Application.Controllers.controller "TrainingsAdminController", ["$scope", "$stat
## Binding for the parseInt function
$scope.parseInt = parseInt
## Default: we show only enabled trainings
$scope.trainingFiltering = 'enabled'
## Available options for filtering trainings by status
$scope.filterDisabled = [
'enabled',
'disabled',
'all',
]
##
# In the trainings listing tab, return the stringified list of machines associated with the provided training
# @param training {Object} Training object, inherited from $resource

View File

@ -21,13 +21,13 @@ Application.Controllers.controller "CalendarController", ["$scope", "$state", "$
### PUBLIC SCOPE ###
## List of trainings
$scope.trainings = trainingsPromise
$scope.trainings = trainingsPromise.filter (t) -> !t.disabled
## List of machines
$scope.machines = machinesPromise
$scope.machines = machinesPromise.filter (t) -> !t.disabled
## List of spaces
$scope.spaces = spacesPromise
$scope.spaces = spacesPromise.filter (t) -> !t.disabled
## add availabilities source to event sources
$scope.eventSources = []

View File

@ -108,32 +108,40 @@ _reserveMachine = (machine, e) ->
$uibModalInstance.dismiss('cancel')
]
# ... but does not have booked the training, tell him to register for a training session first
# unless all associated trainings are disabled
else
_this.$uibModal.open
templateUrl: '<%= asset_path "machines/request_training_modal.html" %>'
controller: ['$scope', '$uibModalInstance', '$state', ($scope, $uibModalInstance, $state) ->
$scope.machine = machine
$scope.member = _this.$scope.currentUser
# if all trainings are disabled, just redirect the user to the reservation calendar
if machine.trainings.map((t) -> t.disabled).reduce(((acc, val) -> acc && val), true)
_this.$state.go('app.logged.machines_reserve', {id: machine.slug})
# otherwise open the information modal
else
_this.$uibModal.open
templateUrl: '<%= asset_path "machines/request_training_modal.html" %>'
controller: ['$scope', '$uibModalInstance', '$state', ($scope, $uibModalInstance, $state) ->
$scope.machine = machine
$scope.member = _this.$scope.currentUser
# transform the name of the trainings associated with the machine to integrate them in a sentence
$scope.humanizeTrainings = ->
text = ''
angular.forEach $scope.machine.trainings, (training) ->
if text.length > 0
text += _this._t('_or_the_')
text += training.name.substr(0,1).toLowerCase() + training.name.substr(1)
text
# transform the name of the trainings associated with the machine to integrate them in a sentence
$scope.humanizeTrainings = ->
text = ''
angular.forEach $scope.machine.trainings, (training) ->
if text.length > 0
text += _this._t('machines_list._or_the_')
text += training.name.substr(0,1).toLowerCase() + training.name.substr(1)
text
# modal is closed with validation
$scope.ok = ->
$state.go('app.logged.trainings_reserve', {id: $scope.machine.trainings[0].id})
$uibModalInstance.close(machine)
# modal is closed with escaping
$scope.cancel = (e)->
e.preventDefault()
$uibModalInstance.dismiss('cancel')
]
# modal is close with validation
$scope.ok = ->
$state.go('app.logged.trainings_reserve', {id: $scope.machine.trainings[0].id})
$uibModalInstance.close(machine)
# modal is closed with escaping
$scope.cancel = (e)->
e.preventDefault()
$uibModalInstance.dismiss('cancel')
]
# if the user is not logged, open the login modal window
else
_this.$scope.login()
@ -164,6 +172,16 @@ Application.Controllers.controller "MachinesController", ["$scope", "$state", '_
_t: _t
$uibModal: $uibModal
Machine: Machine
## Default: we show only enabled machines
$scope.machineFiltering = 'enabled'
## Available options for filtering machines by status
$scope.filterDisabled = [
'enabled',
'disabled',
'all',
]
]
@ -527,6 +545,14 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", '$stat
##
# To use as callback in Array.prototype.filter to get only enabled plans
##
$scope.filterDisabledPlans = (plan) ->
!plan.disabled
### PRIVATE SCOPE ###
##

View File

@ -73,7 +73,7 @@ Application.Controllers.controller "EditProfileController", ["$scope", "$rootSco
$scope.actionUrl = "/api/members/" + $scope.currentUser.id
## list of groups
$scope.groups = groups
$scope.groups = groups.filter (g) -> !g.disabled
## Form action on the above URL
$scope.method = 'patch'

View File

@ -8,7 +8,7 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
### PUBLIC SCOPE ###
## list of groups
$scope.groups = groupsPromise.filter (g) -> g.slug != 'admins'
$scope.groups = groupsPromise.filter (g) -> g.slug != 'admins' & !g.disabled
## default : do not show the group changing form
## group ID of the current/selected user
@ -148,6 +148,14 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
##
# To use as callback in Array.prototype.filter to get only enabled plans
##
$scope.filterDisabledPlans = (plan) ->
!plan.disabled
### PRIVATE SCOPE ###
##

View File

@ -92,6 +92,17 @@ Application.Controllers.controller 'SpacesController', ['$scope', '$state', 'spa
##
$scope.reserveSpace = (space) ->
$state.go('app.logged.space_reserve', { id: space.slug })
## Default: we show only enabled spaces
$scope.spaceFiltering = 'enabled'
## Available options for filtering spaces by status
$scope.filterDisabled = [
'enabled',
'disabled',
'all',
]
]
@ -438,6 +449,14 @@ Application.Controllers.controller "ReserveSpaceController", ["$scope", '$stateP
##
# To use as callback in Array.prototype.filter to get only enabled plans
##
$scope.filterDisabledPlans = (plan) ->
!plan.disabled
### PRIVATE SCOPE ###
##

View File

@ -338,6 +338,14 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", '$sta
##
# To use as callback in Array.prototype.filter to get only enabled plans
##
$scope.filterDisabledPlans = (plan) ->
!plan.disabled
### PRIVATE SCOPE ###
##

View File

@ -258,3 +258,14 @@ Application.Filters.filter 'maxCount', [ '_t', (_t) ->
max
]
Application.Filters.filter 'filterDisabled', [ ->
(list, filter) ->
if angular.isArray(list)
list.filter (e) ->
switch filter
when 'disabled' then e.disabled
when 'enabled' then !e.disabled
else true
else
list
]

View File

@ -597,4 +597,14 @@ padding: 10px;
border-bottom: 1px dashed #00b3ee;
cursor: help;
}
}
.reservable-card {
@media only screen and (min-width: 768px) {
height: 24em;
}
}
.disabled-reservable {
opacity: 0.5 !important;
}

View File

@ -624,4 +624,16 @@ body.container{
.event-description {
overflow: hidden;
}
}
.disabled-line {
color: $gray;
background-color: $gray-lighter;
& td:first-child:before {
font-family: 'fontawesome' !important;
content: '\f070';
position: absolute;
left: -4px;
}
}

View File

@ -1,13 +1,27 @@
<button type="button" class="btn btn-warning m-b m-t-lg" ng-click="addGroup()" translate>{{ 'add_a_group' }}</button>
<div class="m-t-lg m-b">
<button type="button" class="btn btn-warning" ng-click="addGroup()">
<i class="fa fa-plus m-r"></i>
<span translate>{{ 'group_form.add_a_group' }}</span>
</button>
<div class="form-group pull-right">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-filter"></i></span>
<select ng-model="groupFiltering" class="form-control">
<option ng-repeat="status in filterDisabled" value="{{status}}" translate>{{ 'group_form.status_'+status }}</option>
</select>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th style="width: 80%;" translate>{{ 'group_name' }}</th>
<th style="width: 20%"></th>
<th style="width: 75%;" translate>{{ 'group_form.group_name' }}</th>
<th style="width: 25%"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="group in groups">
<tr ng-repeat="group in groups | filterDisabled:groupFiltering" ng-class="{'disabled-line' : group.disabled && groupFiltering === 'all'}">
<td>
<span editable-text="group.name" e-cols="200" e-name="name" e-form="rowform" e-required>
{{group.name}}
@ -23,10 +37,14 @@
<i class="fa fa-times"></i>
</button>
</form>
<div class="buttons" ng-show="!rowform.$visible" ng-hide="group.slug === 'admins'">
<div class="buttons" ng-hide="rowform.$visible || group.slug === 'admins'">
<button class="btn btn-default" ng-click="rowform.$show()">
<i class="fa fa-edit"></i> <span class="hidden-xs hidden-sm" translate>{{ 'edit' }}</span>
</button>
<button class="btn btn-default" ng-click="toggleDisableGroup($index)">
<span ng-hide="group.disabled"><i class="fa fa-eye-slash"></i> <span translate>{{ 'group_form.disable' }}</span></span>
<span ng-show="group.disabled"><i class="fa fa-eye"></i> <span translate>{{ 'group_form.enable' }}</span></span>
</button>
<button class="btn btn-danger" ng-click="removeGroup($index)">
<i class="fa fa-trash-o"></i>
</button>

View File

@ -40,7 +40,7 @@
<span ng-bind="$item.name"></span>
<input type="hidden" name="user[training_ids][]" value="{{$item.id}}" />
</ui-select-match>
<ui-select-choices repeat="t.id as t in (trainings | filter: $select.search)">
<ui-select-choices ui-disable-choice="t.disabled" repeat="t.id as t in (trainings | filter: $select.search)">
<span ng-bind-html="t.name | highlight: $select.search"></span>
</ui-select-choices>
</ui-select>

View File

@ -85,7 +85,7 @@
<p translate>
{{ 'user_has_no_current_subscription' }}
</p>
<button class="btn btn-default" ng-click="createSubscriptionModal(user, plans)" translate>{{ 'subscribe_to_a_plan' }}</button>
<button class="btn btn-default" ng-click="createSubscriptionModal(user, plans.filter(filterDisabledPlans))" translate>{{ 'subscribe_to_a_plan' }}</button>
</div>
</div>

View File

@ -30,6 +30,22 @@
<ng-include src="'<%= asset_path 'admin/plans/_form.html' %>'"></ng-include>
<div class="input-group m-t-md">
<label for="plan[disabled]" class="control-label m-r-md">{{ 'plan_form.disabled' | translate }}</label>
<input bs-switch
ng-model="plan.disabled"
id="plan[disabled]"
type="checkbox"
class="form-control"
switch-on-text="{{ 'yes' | translate }}"
switch-off-text="{{ 'no' | translate }}"
switch-animate="true"
ng-true-value="'true'"
ng-false-value="'false'"/>
<input type="hidden" name="plan[disabled]" value="{{plan.disabled}}"/>
<span class="help-block" translate>{{ 'plan_form.disable_plan_will_not_unsubscribe_users' }}</span>
</div>
<h2 class="m-t-xl" translate>{{ 'edit_plan.prices' }}</h2>
<div class="form-group col-md-6 col-lg-offset-6">
<input type="hidden" ng-model="plan.parent" name="plan[parent_id]" ng-value="plan.parent"/>
@ -46,8 +62,8 @@
</thead>
<tbody>
<tr ng-repeat="price in plan.prices" ng-if="price.priceable_type === 'Machine'">
<td style="width: 60%;">{{ getMachineName(price.priceable_id) }} (id {{ price.priceable_id }}) *</td>
<tr ng-repeat="price in plan.prices" ng-if="price.priceable_type === 'Machine'" ng-hide="getMachine(price.priceable_id).disabled">
<td style="width: 60%;">{{ getMachine(price.priceable_id).name }} (id {{ price.priceable_id }}) *</td>
<td>
<div class="input-group" ng-class="{'has-error': planForm['plan[prices_attributes][][amount]'].$dirty && planForm['plan[prices_attributes][][amount]'].$invalid}">
<span class="input-group-addon">{{currencySymbol}}</span>
@ -67,8 +83,8 @@
</thead>
<tbody>
<tr ng-repeat="price in plan.prices" ng-if="price.priceable_type === 'Space'">
<td style="width: 60%;">{{ getSpaceName(price.priceable_id) }} *</td>
<tr ng-repeat="price in plan.prices" ng-if="price.priceable_type === 'Space'" ng-hide="getSpace(price.priceable_id).disabled">
<td style="width: 60%;">{{ getSpace(price.priceable_id).name }} *</td>
<td>
<div class="input-group" ng-class="{'has-error': planForm['plan[prices_attributes][][amount]'].$dirty && planForm['plan[prices_attributes][][amount]'].$invalid}">
<span class="input-group-addon">{{currencySymbol}}</span>

View File

@ -10,7 +10,7 @@
</thead>
<tbody>
<tr ng-repeat="(planId, trainingIds) in trainingCreditsGroups" ng-init="plan = getPlanFromId(planId)">
<tr ng-repeat="(planId, trainingIds) in trainingCreditsGroups" ng-init="plan = getPlanFromId(planId)" ng-hide="plan.disabled">
<td>
{{ plan | humanReadablePlanName: groups }}
</td>
@ -58,9 +58,9 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="mc in machineCredits">
<tr ng-repeat="mc in machineCredits" ng-hide="getPlanFromId(mc.plan_id).disabled || getCreditable(mc).disabled">
<td>
<span editable-select="mc.creditable_id" e-name="creditable_id" e-form="rowform" e-ng-options="m.id as m.name+' ( id. '+m.id+' )' for m in machines" e-required>
<span editable-select="mc.creditable_id" e-name="creditable_id" e-form="rowform" e-ng-options="m.id as m.name+' ( id. '+m.id+' )' for m in enabledMachines" e-required>
{{ showCreditableName(mc) }}
</span>
</td>
@ -70,7 +70,7 @@
</span>
</td>
<td>
<span editable-select="mc.plan_id" e-ng-options="p.id as humanReadablePlanName(p, groups, 'short') for p in plans" e-name="plan_id" e-form="rowform">
<span editable-select="mc.plan_id" e-ng-options="p.id as humanReadablePlanName(p, groups, 'short') for p in enabledPlans" e-name="plan_id" e-form="rowform">
{{ getPlanFromId(mc.plan_id) | humanReadablePlanName: groups: 'short' }}
</span>
</td>
@ -110,9 +110,9 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="sc in spaceCredits">
<tr ng-repeat="sc in spaceCredits" ng-hide="getPlanFromId(sc.plan_id).disabled || getCreditable(sc).disabled">
<td>
<span editable-select="sc.creditable_id" e-name="creditable_id" e-form="rowform" e-ng-options="s.id as s.name for s in spaces" e-required>
<span editable-select="sc.creditable_id" e-name="creditable_id" e-form="rowform" e-ng-options="s.id as s.name for s in enabledSpaces" e-required>
{{ showCreditableName(sc) }}
</span>
</td>
@ -122,7 +122,7 @@
</span>
</td>
<td>
<span editable-select="sc.plan_id" e-ng-options="p.id as humanReadablePlanName(p, groups, 'short') for p in plans" e-name="plan_id" e-form="rowform">
<span editable-select="sc.plan_id" e-ng-options="p.id as humanReadablePlanName(p, groups, 'short') for p in enabledPlans" e-name="plan_id" e-form="rowform">
{{ getPlanFromId(sc.plan_id) | humanReadablePlanName: groups: 'short' }}
</span>
</td>

View File

@ -5,17 +5,17 @@
<thead>
<tr>
<th style="width:20%" translate>{{ 'pricing.machines' }}</th>
<th style="width:20%" ng-repeat="group in groups">
<th style="width:20%" ng-repeat="group in enabledGroups">
<span class="text-u-c text-sm">{{group.name}}</span>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="machine in machines">
<tr ng-repeat="machine in enabledMachines">
<td>
{{ machine.name }}
</td>
<td ng-repeat="group in groups">
<td ng-repeat="group in enabledGroups">
<span editable-number="findPriceBy(machinesPrices, machine.id, group.id).amount"
onbeforesave="updatePrice($data, findPriceBy(machinesPrices, machine.id, group.id))">
{{ findPriceBy(machinesPrices, machine.id, group.id).amount | currency}}

View File

@ -5,17 +5,17 @@
<thead>
<tr>
<th style="width:20%" translate>{{ 'pricing.spaces' }}</th>
<th style="width:20%" ng-repeat="group in groups">
<th style="width:20%" ng-repeat="group in enabledGroups">
<span class="text-u-c text-sm">{{group.name}}</span>
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="space in spaces">
<tr ng-repeat="space in enabledSpaces">
<td>
{{ space.name }}
</td>
<td ng-repeat="group in groups">
<td ng-repeat="group in enabledGroups">
<span editable-number="findPriceBy(spacesPrices, space.id, group.id).amount"
onbeforesave="updatePrice($data, findPriceBy(spacesPrices, space.id, group.id))">
{{ findPriceBy(spacesPrices, space.id, group.id).amount | currency}}

View File

@ -6,7 +6,21 @@
<br>{{ 'pricing.for_safety_reasons_please_dont_create_subscriptions_if_you_dont_want_intend_to_use_them_later' | translate }}
</div>
<button type="button" class="btn btn-warning m-t-lg m-b" ui-sref="app.admin.plans.new" translate>{{ 'pricing.add_a_new_subscription_plan' }}</button>
<div class="m-t-lg">
<button type="button" class="btn btn-warning" ui-sref="app.admin.plans.new">
<i class="fa fa-plus m-r"></i>
<span translate>{{ 'pricing.add_a_new_subscription_plan' }}</span>
</button>
<div class="form-group pull-right">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-filter"></i></span>
<select ng-model="planFiltering" class="form-control">
<option ng-repeat="status in filterDisabled" value="{{status}}" translate>{{ 'pricing.status_'+status }}</option>
</select>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
@ -20,11 +34,14 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="plan in plans | orderBy:orderPlans">
<tr ng-repeat="plan in plans | filterDisabled:planFiltering | orderBy:orderPlans"
ng-class="{'disabled-line' : plan.disabled && planFiltering === 'all'}"
ng-init="group = getGroupFromId(groups, plan.group_id)"
ng-hide="group.disabled">
<td>{{getPlanType(plan.type)}}</td>
<td>{{plan.base_name}}</td>
<td>{{ plan.interval | planIntervalFilter:plan.interval_count }}</td>
<td>{{getGroupFromId(groups, plan.group_id).name}}</td>
<td>{{group.name}}</td>
<td class="hidden-xs">{{plan.ui_weight}}</td>
<td>{{plan.amount | currency}}</td>
<td><button type="button" class="btn btn-default" ui-sref="app.admin.plans.edit({id:plan.id})"><i class="fa fa-pencil-square-o"></i></button> <button type="button" class="btn btn-danger" ng-click="deletePlan(plans, plan.id)"><i class="fa fa-trash"></i></button></td>

View File

@ -2,7 +2,7 @@
<thead>
<tr>
<th style="width:20%" translate>{{ 'pricing.trainings' }}</th>
<th style="width:20%" ng-repeat="group in groups">
<th style="width:20%" ng-repeat="group in enabledGroups">
<span class="text-u-c text-sm">{{group.name}}</span>
</th>
</tr>
@ -12,7 +12,7 @@
<td>
{{ training.name }}
</td>
<td ng-repeat="group in groups">
<td ng-repeat="group in enabledGroups">
<span editable-number="findTrainingsPricing(trainingsPricings, training.id, group.id).amount"
onbeforesave="updateTrainingsPricing($data, findTrainingsPricing(trainingsPricings, training.id, group.id))">
{{ findTrainingsPricing(trainingsPricings, training.id, group.id).amount | currency}}

View File

@ -15,21 +15,21 @@
<uib-alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>
<div class="form-group m-b-lg" ng-class="{'has-error': trainingForm['training[name]'].$dirty && trainingForm['training[name]'].$invalid}">
<label for="name" class="col-sm-2 control-label">{{ 'name' | translate }} *</label>
<label for="name" class="col-sm-2 control-label">{{ 'trainings_form.name' | translate }} *</label>
<div class="col-sm-4">
<input name="training[name]"
ng-model="training.name"
type="text"
class="form-control"
id="training_name"
placeholder="{{'name' | translate}}"
placeholder="{{'trainings_form.name' | translate}}"
required/>
<span class="help-block" ng-show="trainingForm['training[name]'].$dirty && trainingForm['training[name]'].$error.required" translate>{{ 'name_is_required' }}</span>
<span class="help-block" ng-show="trainingForm['training[name]'].$dirty && trainingForm['training[name]'].$error.required" translate>{{ 'trainings_form.name_is_required' }}</span>
</div>
</div>
<div class="form-group m-b-lg">
<label for="training_image" class="col-sm-2 control-label">{{ 'illustration' | translate }} *</label>
<label for="training_image" class="col-sm-2 control-label">{{ 'trainings_form.illustration' | translate }} *</label>
<div class="col-sm-10">
<div class="fileinput" data-provides="fileinput" ng-class="fileinputClass(training.training_image)">
<div class="fileinput-new thumbnail" style="width: 334px; height: 250px;">
@ -40,7 +40,7 @@
</div>
<div>
<span class="btn btn-default btn-file">
<span class="fileinput-new">{{ 'add_an_illustration' | translate }} <i class="fa fa-upload fa-fw"></i></span>
<span class="fileinput-new">{{ 'trainings_form.add_an_illustration' | translate }} <i class="fa fa-upload fa-fw"></i></span>
<span class="fileinput-exists" translate>{{ 'change' }}</span>
<input type="file"
ng-model="training.training_image"
@ -57,23 +57,23 @@
<div class="form-group m-b-xl" ng-class="{'has-error': trainingForm['training[description]'].$dirty && trainingForm['training[description]'].$invalid}">
<label for="training_description" class="col-sm-2 control-label">{{ 'description' | translate }} *</label>
<label for="training_description" class="col-sm-2 control-label">{{ 'trainings_form.description' | translate }} *</label>
<div class="col-sm-10">
<input type="hidden" name="training[description]" ng-value="training.description" />
<summernote ng-model="training.description" id="training_description" placeholder="" config="summernoteOpts" name="training[description]" required></summernote>
<span class="help-block" ng-show="trainingForm['training[description]'].$dirty && trainingForm['training[description]'].$error.required" translate>{{ 'description_is_required' }}</span>
<span class="help-block" ng-show="trainingForm['training[description]'].$dirty && trainingForm['training[description]'].$error.required" translate>{{ 'trainings_form.description_is_required' }}</span>
</div>
</div>
<div class="form-group m-b-lg" ng-class="{'has-error': trainingForm['training[machine_ids]'].$dirty && trainingForm['training[machine_ids]'].$invalid}">
<label for="training_machines" class="col-sm-2 control-label">{{ 'associated_machines' | translate }}</label>
<label for="training_machines" class="col-sm-2 control-label">{{ 'trainings_form.associated_machines' | translate }}</label>
<div class="col-sm-4">
<ui-select multiple ng-model="training.machine_ids" class="form-control" id="training_machines">
<ui-select-match>
<span ng-bind="$item.name"></span>
<input type="hidden" name="training[machine_ids][]" value="{{$item.id}}" />
</ui-select-match>
<ui-select-choices repeat="m.id as m in (machines | filter: $select.search)">
<ui-select-choices ui-disable-choice="m.disabled" repeat="m.id as m in (machines | filter: $select.search)">
<span ng-bind-html="m.name | highlight: $select.search"></span>
</ui-select-choices>
</ui-select>
@ -81,7 +81,7 @@
</div>
<div class="form-group m-b-lg" ng-class="{'has-error': trainingForm['training[nb_total_places]'].$dirty && trainingForm['training[nb_total_places]'].$invalid}">
<label for="training_nb_total_places" class="col-sm-2 control-label">{{ 'number_of_tickets' | translate }}</label>
<label for="training_nb_total_places" class="col-sm-2 control-label">{{ 'trainings_form.number_of_tickets' | translate }}</label>
<div class="col-sm-4">
<input ng-model="training.nb_total_places"
type="number"
@ -95,7 +95,7 @@
<div class="form-group">
<label for="training[public_page]" class="control-label col-sm-2" translate>
{{ 'public_page' }}
{{ 'trainings_form.public_page' }}
</label>
<div class="col-sm-10">
<input bs-switch
@ -105,16 +105,35 @@
class="form-control"
switch-on-text="{{ 'yes' | translate }}"
switch-off-text="{{ 'no' | translate }}"
switch-active="{{!training.disabled}}"
switch-animate="true"/>
<input type="hidden" name="training[public_page]" value="{{training.public_page}}">
</div>
</div>
<div class="form-group">
<label for="training[disabled]" class="control-label col-sm-2" translate>
{{ 'trainings_form.disable_training' }}
</label>
<div class="col-sm-10">
<input bs-switch
ng-model="training.disabled"
name="training[disabled]"
type="checkbox"
class="form-control"
switch-on-text="{{ 'yes' | translate }}"
switch-off-text="{{ 'no' | translate }}"
ng-change="onDisableToggled()"
switch-animate="true"/>
<input type="hidden" name="training[disabled]" value="{{training.disabled}}">
</div>
</div>
</div> <!-- ./panel-body -->
<div class="panel-footer no-padder">
<input type="submit"
value="{{ 'validate_your_training' | translate }}"
value="{{ 'trainings_form.validate_your_training' | translate }}"
class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c"
ng-disabled="trainingForm.$invalid"/>
</div>

View File

@ -21,7 +21,20 @@
<div class="col-md-12">
<uib-tabset justified="true">
<uib-tab heading="{{ 'trainings' | translate }}">
<button type="button" class="btn btn-warning m-t m-b" ui-sref="app.admin.trainings_new" translate>{{ 'add_a_new_training' }}</button>
<div class="m-t m-b">
<button type="button" class="btn btn-warning" ui-sref="app.admin.trainings_new">
<i class="fa fa-plus m-r"></i>
<span translate>{{ 'add_a_new_training' }}</span>
</button>
<div class="form-group pull-right">
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-filter"></i></span>
<select ng-model="trainingFiltering" class="form-control">
<option ng-repeat="status in filterDisabled" value="{{status}}" translate>{{ 'status_'+status }}</option>
</select>
</div>
</div>
</div>
<table class="table">
<thead>
@ -33,7 +46,7 @@
</tr>
</thead>
<tbody>
<tr ng-repeat="training in trainings">
<tr ng-repeat="training in trainings | filterDisabled:trainingFiltering" ng-class="{'disabled-line' : training.disabled && trainingFiltering === 'all'}">
<td>{{ training.name }}</td>
<td>{{ showMachines(training) }}</td>
<td>{{ training.nb_total_places }}</td>

View File

@ -7,7 +7,7 @@
</div>
<div class="col-md-8 b-l b-r">
<section class="heading-title">
<h1 translate>{{ 'add_a_new_training' }}</h1>
<h1 translate>{{ 'trainings_new.add_a_new_training' }}</h1>
</section>
</div>
@ -22,8 +22,8 @@
<div class="col-md-9 b-r nopadding">
<div class="alert alert-warning m-lg" role="alert">
{{ 'beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero' | translate }}
{{ 'dont_forget_to_change_them_before_creating_slots_for_this_training' | translate }}
{{ 'trainings_new.beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero' | translate }}
{{ 'trainings_new.dont_forget_to_change_them_before_creating_slots_for_this_training' | translate }}
</div>
<ng-include src="'<%= asset_path 'admin/trainings/_form.html' %>'"></ng-include>

View File

@ -15,21 +15,21 @@
<uib-alert ng-repeat="alert in alerts" type="{{alert.type}}" close="closeAlert($index)">{{alert.msg}}</uib-alert>
<div class="form-group m-b-lg" ng-class="{'has-error': machineForm['machine[name]'].$dirty && machineForm['machine[name]'].$invalid}">
<label for="name" class="col-sm-2 control-label">{{ 'name' | translate }} *</label>
<label for="name" class="col-sm-2 control-label">{{ 'machine_form.name' | translate }} *</label>
<div class="col-sm-4">
<input ng-model="machine.name"
type="text"
name="machine[name]"
class="form-control"
id="machine_name"
placeholder="{{'name' | translate}}"
placeholder="{{'machine_form.name' | translate}}"
required>
<span class="help-block" ng-show="machineForm['machine[name]'].$dirty && machineForm['machine[name]'].$error.required" translate>{{ 'name_is_required' }}</span>
<span class="help-block" ng-show="machineForm['machine[name]'].$dirty && machineForm['machine[name]'].$error.required" translate>{{ 'machine_form.name_is_required' }}</span>
</div>
</div>
<div class="form-group m-b-lg">
<label for="machine_image" class="col-sm-2 control-label">{{ 'illustration' | translate }} *</label>
<label for="machine_image" class="col-sm-2 control-label">{{ 'machine_form.illustration' | translate }} *</label>
<div class="col-sm-10">
<div class="fileinput" data-provides="fileinput" ng-class="fileinputClass(machine.machine_image)">
<div class="fileinput-new thumbnail" style="width: 334px; height: 250px;">
@ -40,7 +40,7 @@
</div>
<div>
<span class="btn btn-default btn-file">
<span class="fileinput-new">{{ 'add_an_illustration' | translate }} <i class="fa fa-upload fa-fw"></i></span>
<span class="fileinput-new">{{ 'machine_form.add_an_illustration' | translate }} <i class="fa fa-upload fa-fw"></i></span>
<span class="fileinput-exists" translate>{{ 'change' }}</span>
<input type="file"
ng-model="machine.machine_image"
@ -57,7 +57,7 @@
<div class="form-group m-b-xl" ng-class="{'has-error': machineForm['machine[description]'].$dirty && machineForm['machine[description]'].$invalid}">
<label for="description" class="col-sm-2 control-label">{{ 'description' | translate }} *</label>
<label for="description" class="col-sm-2 control-label">{{ 'machine_form.description' | translate }} *</label>
<div class="col-sm-10">
<input type="hidden"
name="machine[description]"
@ -69,12 +69,12 @@
name="machine[description]"
required>
</summernote>
<span class="help-block" ng-show="machineForm['machine[description]'].$dirty && machineForm['machine[description]'].$error.required" translate>{{ 'description_is_required' }}</span>
<span class="help-block" ng-show="machineForm['machine[description]'].$dirty && machineForm['machine[description]'].$error.required" translate>{{ 'machine_form.description_is_required' }}</span>
</div>
</div>
<div class="form-group m-b-xl" ng-class="{'has-error': machineForm['machine[spec]'].$dirty && machineForm['machine[spec]'].$invalid}">
<label for="spec" class="col-sm-2 control-label">{{ 'technical_specifications' | translate }} *</label>
<label for="spec" class="col-sm-2 control-label">{{ 'machine_form.technical_specifications' | translate }} *</label>
<div class="col-sm-10">
<input type="hidden"
name="machine[spec]"
@ -86,12 +86,12 @@
name="machine[spec]"
required>
</summernote>
<span class="help-block" ng-show="machineForm['machine[spec]'].$dirty && machineForm['machine[spec]'].$error.required" translate>{{ 'technical_specifications_are_required' }}</span>
<span class="help-block" ng-show="machineForm['machine[spec]'].$dirty && machineForm['machine[spec]'].$error.required" translate>{{ 'machine_form.technical_specifications_are_required' }}</span>
</div>
</div>
<div class="form-group m-b-xl">
<label class="col-sm-2 control-label" translate>{{ 'attached_files_(pdf)' }}</label>
<label class="col-sm-2 control-label" translate>{{ 'machine_form.attached_files_(pdf)' }}</label>
<div class="col-sm-10">
<div ng-repeat="file in machine.machine_files_attributes" ng-show="!file._destroy">
<input type="hidden" ng-model="file.id" name="machine[machine_files_attributes][][id]" ng-value="file.id" />
@ -101,13 +101,30 @@
<div class="form-control" data-trigger="fileinput">
<i class="glyphicon glyphicon-file fileinput-exists"></i> <span class="fileinput-filename">{{file.attachment}}</span>
</div>
<span class="input-group-addon btn btn-default btn-file"><span class="fileinput-new" translate>{{ 'attach_a_file' }}</span>
<span class="input-group-addon btn btn-default btn-file"><span class="fileinput-new" translate>{{ 'machine_form.attach_a_file' }}</span>
<span class="fileinput-exists" translate>{{ 'change' }}</span><input type="file" name="machine[machine_files_attributes][][attachment]" accept=".pdf"></span>
<a class="input-group-addon btn btn-danger fileinput-exists" data-dismiss="fileinput" ng-click="deleteFile(file)"><i class="fa fa-trash-o"></i></a>
</div>
</div>
<a class="btn btn-default" ng-click="addFile()" role="button"> {{ 'add_an_attachment' | translate }} <i class="fa fa-file-o fa-fw"></i></a>
<a class="btn btn-default" ng-click="addFile()" role="button"> {{ 'machine_form.add_an_attachment' | translate }} <i class="fa fa-file-o fa-fw"></i></a>
</div>
</div>
<div class="form-group">
<label for="machine[disabled]" class="control-label col-sm-2" translate>
{{ 'machine_form.disable_machine' }}
</label>
<div class="col-sm-10">
<input bs-switch
ng-model="machine.disabled"
name="machine[disabled]"
type="checkbox"
class="form-control"
switch-on-text="{{ 'yes' | translate }}"
switch-off-text="{{ 'no' | translate }}"
switch-animate="true"/>
<input type="hidden" name="machine[disabled]" value="{{machine.disabled}}">
</div>
</div>
@ -115,7 +132,7 @@
<div class="panel-footer no-padder">
<input type="submit"
value="{{ 'validate_your_machine' | translate }}"
value="{{ 'machine_form.validate_your_machine' | translate }}"
class="r-b btn-valid btn btn-warning btn-block p-lg btn-lg text-u-c"
ng-disabled="machineForm.$invalid"/>
</div>

View File

@ -7,13 +7,13 @@
</div>
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
<section class="heading-title">
<h1 translate>{{ 'the_fablab_s_machines' }}</h1>
<h1 translate>{{ 'machines_list.the_fablab_s_machines' }}</h1>
</section>
</div>
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md" ng-if="isAuthorized('admin')">
<section class="heading-actions wrapper">
<a class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs" ui-sref="app.admin.machines_new" role="button" translate>{{ 'add_a_machine' }}</a>
<a class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs" ui-sref="app.admin.machines_new" role="button" translate>{{ 'machines_list.add_a_machine' }}</a>
</section>
</div>
</div>
@ -22,42 +22,46 @@
<section class="m-lg">
<div class="row" ng-repeat="machine in (machines.length/3 | array)">
<div class="col-xs-12 col-sm-6 col-md-4" ng-repeat="machine in machines.slice(3*$index, 3*$index + 3)">
<div class="widget panel panel-default">
<div class="panel-heading picture" ng-if="!machine.machine_image" ng-click="showMachine(machine)">
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:FontAwesome/icon" bs-holder class="img-responsive">
</div>
<div class="panel-heading picture" style="background-image:url({{machine.machine_image}})" ng-if="machine.machine_image" ng-click="showMachine(machine)">
</div>
<div class="panel-body">
<h1 class="text-center m-b">{{machine.name}}</h1>
</div>
<div class="panel-footer no-padder">
<div class="text-center clearfix">
<div class="col-sm-6 b-r no-padder">
<div class="btn btn-default btn-block no-b padder-v red" ng-click="reserveMachine(machine, $event)">
<i class="fa fa-bookmark"></i> {{ 'book' | translate }}
</div>
</div>
<div class="col-sm-6 no-padder">
<div class="btn btn-default btn-block padder-v no-b red" ng-click="showMachine(machine)">
<i class="fa fa-eye"></i> {{ 'consult' | translate }}
</div>
</div>
</div>
</div>
</div>
<div class="form-group row">
<div class="input-group col-md-3 m-l-lg m-b">
<span class="input-group-addon"><i class="fa fa-filter"></i></span>
<select ng-model="machineFiltering" class="form-control">
<option ng-repeat="status in filterDisabled" value="{{status}}" translate>{{ 'machines_list.status_'+status }}</option>
</select>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-lg-4 reservable-card" ng-class="{'disabled-reservable' : machine.disabled && machineFiltering === 'all'}" ng-repeat="machine in machines | filterDisabled:machineFiltering">
<div class="widget panel panel-default">
<div class="panel-heading picture" ng-if="!machine.machine_image" ng-click="showMachine(machine)">
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:FontAwesome/icon" bs-holder class="img-responsive">
</div>
<div class="panel-heading picture" style="background-image:url({{machine.machine_image}})" ng-if="machine.machine_image" ng-click="showMachine(machine)">
</div>
<div class="panel-body">
<h1 class="text-center m-b">{{machine.name}}</h1>
</div>
<div class="panel-footer no-padder">
<div class="text-center clearfix">
<div class="col-sm-6 b-r no-padder">
<div class="btn btn-default btn-block no-b padder-v red" ng-click="reserveMachine(machine, $event)" ng-hide="machine.disabled">
<i class="fa fa-bookmark m-r-xs"></i>
<span class="hidden-sm" translate>{{ 'machines_list.book' }}</span>
</div>
</div>
<div class="no-padder" ng-class="{'col-sm-6': !machine.disabled}">
<div class="btn btn-default btn-block padder-v no-b red" ng-click="showMachine(machine)">
<i class="fa fa-eye m-r-xs"></i>
<span class="hidden-sm" translate>{{ 'consult' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</section>

View File

@ -8,8 +8,8 @@
<!-- ng-class directive center the last item if the list length is odd -->
<div class="pricing-panel col-xs-6 col-md-6 col-lg-6 text-center"
ng-class="{'col-md-12 col-lg-12':(plansGroup.plans.length % 2 == 1 && key == plansGroup.plans.length-1)}"
ng-repeat="(key, plan) in plansGroup.plans | orderBy:'interval'">
ng-class="{'col-md-12 col-lg-12':(plansGroup.plans.filter(filterDisabledPlans).length % 2 == 1 && key == plansGroup.plans.filter(filterDisabledPlans).length-1)}"
ng-repeat="(key, plan) in plansGroup.plans.filter(filterDisabledPlans) | orderBy:'interval'">
<h3 class="title">{{ plan.base_name }}</h3>

View File

@ -27,8 +27,8 @@
<!-- ng-class directive center the last item if the list length is odd -->
<div class="pricing-panel col-xs-12 col-md-6 col-lg-6 text-center"
ng-class="{'col-md-12 col-lg-12 b-r':(plansGroup.plans.length % 2 == 1 && key == plansGroup.plans.length-1)}"
ng-repeat="(key, plan) in plansGroup.plans | orderBy: '-ui_weight'">
ng-class="{'col-md-12 col-lg-12 b-r':(plansGroup.plans.filter(filterDisabledPlans).length % 2 == 1 && key == plansGroup.plans.filter(filterDisabledPlans).length-1)}"
ng-repeat="(key, plan) in plansGroup.plans.filter(filterDisabledPlans) | orderBy: '-ui_weight'">
<h3 class="title">{{ plan.base_name }}</h3>

View File

@ -107,3 +107,22 @@
<a class="btn btn-default" ng-click="addFile()" role="button"> {{ 'space.add_an_attachment' | translate }} <i class="fa fa-file-o fa-fw"></i></a>
</div>
</div>
<div class="form-group">
<label for="space[disabled]" class="control-label col-sm-2" translate>
{{ 'space.disable_space' }}
</label>
<div class="col-sm-10">
<input bs-switch
ng-model="space.disabled"
name="space[disabled]"
id="space[disabled]"
type="checkbox"
class="form-control"
switch-on-text="{{ 'yes' | translate }}"
switch-off-text="{{ 'no' | translate }}"
switch-animate="true"/>
<input type="hidden" name="space[disabled]" value="{{space.disabled}}">
</div>
</div>

View File

@ -7,13 +7,13 @@
</div>
<div class="col-xs-10 col-sm-10 col-md-8 b-l b-r-md">
<section class="heading-title">
<h1 translate>{{ 'the_spaces' }}</h1>
<h1 translate>{{ 'spaces_list.the_spaces' }}</h1>
</section>
</div>
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md" ng-if="isAuthorized('admin')">
<section class="heading-actions wrapper">
<a class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs" ui-sref="app.admin.space_new" role="button" translate>{{ 'add_a_space' }}</a>
<a class="btn btn-lg btn-warning bg-white b-2x rounded m-t-xs" ui-sref="app.admin.space_new" role="button" translate>{{ 'spaces_list.add_a_space' }}</a>
</section>
</div>
</div>
@ -22,41 +22,47 @@
<section class="m-lg">
<div class="row" ng-repeat="space in (spaces.length/3 | array)">
<div class="col-xs-12 col-sm-6 col-md-4" ng-repeat="space in spaces.slice(3*$index, 3*$index + 3)">
<div class="form-group row">
<div class="input-group col-md-3 m-l-lg m-b">
<span class="input-group-addon"><i class="fa fa-filter"></i></span>
<select ng-model="spaceFiltering" class="form-control">
<option ng-repeat="status in filterDisabled" value="{{status}}" translate>{{ 'spaces_list.status_'+status }}</option>
</select>
</div>
</div>
<div class="widget panel panel-default">
<div class="panel-heading picture" ng-if="!space.space_image" ng-click="showSpace(space)">
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:FontAwesome/icon" bs-holder class="img-responsive">
</div>
<div class="panel-heading picture" style="background-image:url({{space.space_image}})" ng-if="space.space_image" ng-click="showSpace(space)">
</div>
<div class="panel-body">
<h1 class="text-center m-b">{{space.name}}</h1>
</div>
<div class="panel-footer no-padder">
<div class="text-center clearfix">
<div class="col-sm-6 b-r no-padder">
<div class="btn btn-default btn-block no-b padder-v red" ng-click="reserveSpace(space, $event)">
<i class="fa fa-bookmark"></i> {{ 'book' | translate }}
</div>
</div>
<div class="col-sm-6 no-padder">
<div class="btn btn-default btn-block padder-v no-b red" ng-click="showSpace(space)">
<i class="fa fa-eye"></i> {{ 'consult' | translate }}
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4 reservable-card" ng-class="{'disabled-reservable' : space.disabled && spaceFiltering === 'all'}" ng-repeat="space in spaces | filterDisabled:spaceFiltering">
<div class="widget panel panel-default">
<div class="panel-heading picture" ng-if="!space.space_image" ng-click="showSpace(space)">
<img src="data:image/png;base64," data-src="holder.js/100%x100%/text:&#xf03e;/font:FontAwesome/icon" bs-holder class="img-responsive">
</div>
<div class="panel-heading picture" style="background-image:url({{space.space_image}})" ng-if="space.space_image" ng-click="showSpace(space)">
</div>
<div class="panel-body">
<h1 class="text-center m-b">{{space.name}}</h1>
</div>
<div class="panel-footer no-padder">
<div class="text-center clearfix">
<div class="col-sm-6 b-r no-padder">
<div class="btn btn-default btn-block no-b padder-v red" ng-click="reserveSpace(space, $event)" ng-hide="space.disabled">
<i class="fa fa-bookmark m-r-xs"></i>
<span class="hidden-sm" translate>{{ 'spaces_list.book' }}</span>
</div>
</div>
<div class="no-padder" ng-class="{'col-sm-6': !space.disabled}">
<div class="btn btn-default btn-block padder-v no-b red" ng-click="showSpace(space)">
<i class="fa fa-eye m-r-xs"></i>
<span class="hidden-sm" translate>{{ 'consult' }}</span>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -40,6 +40,6 @@ class API::GroupsController < API::ApiController
private
def group_params
params.require(:group).permit(:name)
params.require(:group).permit(:name, :disabled)
end
end

View File

@ -42,7 +42,7 @@ class API::MachinesController < API::ApiController
end
def machine_params
params.require(:machine).permit(:name, :description, :spec, :plan_ids, plan_ids: [], machine_image_attributes: [:attachment],
params.require(:machine).permit(:name, :description, :spec, :disabled, :plan_ids, plan_ids: [], machine_image_attributes: [:attachment],
machine_files_attributes: [:id, :attachment, :_destroy])
end

View File

@ -87,8 +87,7 @@
end if @parameters[:plan][:prices_attributes]
@parameters = @parameters.require(:plan).permit(:base_name, :type, :group_id, :amount, :interval, :interval_count, :is_rolling,
:training_credit_nb,
:ui_weight,
:training_credit_nb, :ui_weight, :disabled,
plan_file_attributes: [:id, :attachment, :_destroy],
prices_attributes: [:id, :amount]
)

View File

@ -43,7 +43,7 @@ class API::SpacesController < API::ApiController
end
def space_params
params.require(:space).permit(:name, :description, :characteristics, :default_places, space_image_attributes: [:attachment],
params.require(:space).permit(:name, :description, :characteristics, :default_places, :disabled, space_image_attributes: [:attachment],
space_files_attributes: [:id, :attachment, :_destroy])
end
end

View File

@ -70,6 +70,6 @@ class API::TrainingsController < API::ApiController
end
def training_params
params.require(:training).permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, :public_page, training_image_attributes: [:attachment], machine_ids: [], plan_ids: [])
params.require(:training).permit(:id, :name, :description, :machine_ids, :plan_ids, :nb_total_places, :public_page, :disabled, training_image_attributes: [:attachment], machine_ids: [], plan_ids: [])
end
end

View File

@ -17,6 +17,7 @@ class OpenAPI::V1::MachinesDoc < OpenAPI::V1::BaseDoc
"id": 1,
"name": "Epilog EXT36 Laser",
"slug": "decoupeuse-laser",
"disabled": null,
"updated_at": "2015-02-17T11:06:00.495+01:00",
"created_at": "2014-06-30T03:32:31.972+02:00",
"description": "La découpeuse Laser, EPILOG Legend 36EXT\r\n\r\nInformations générales :\r\nLa découpeuse laser vous permet de découper ou graver des matériaux. \r\n\r\nPour la découpe, il suffit d'apporter votre fichier vectorisé type illustrator, svg ou dxf avec des \"lignes de coupe\" d'une épaisseur inférieure à 0,01 mm et la machine s'occupera du reste!\r\n\r\nLa gravure est basée sur le spectre noir et blanc. Les nuances sont obtenues par différentes profondeurs de gravure correspondant aux niveaux de gris de votre image. Il suffit pour cela d'apporter une image scannée ou un fichier photo en noir et blanc pour pouvoir reproduire celle-ci sur votre support.\r\n\r\nTypes de matériaux gravables/découpeables ?\r\nDu bois au tissu, du plexiglass au cuir, cette machine permet de découper et graver la plupart des matériaux sauf les métaux. La gravure est néanmoins possible sur les métaux recouverts d'une couche de peinture ou les aluminiums anodisés. \r\nConcernant l'épaisseur des matériaux découpés, il est préférable de ne pas dépasser 5 mm pour le bois et 6 mm pour le plexiglass.\r\n",
@ -26,6 +27,7 @@ class OpenAPI::V1::MachinesDoc < OpenAPI::V1::BaseDoc
"id": 2,
"name": "Découpeuse vinyle",
"slug": "decoupeuse-vinyle",
"disabled": null,
"updated_at": "2014-06-30T15:10:14.272+02:00",
"created_at": "2014-06-30T03:32:31.977+02:00",
"description": "La découpeuse Vinyle, Roland CAMM-1 GX24\r\n\r\nInformations générales :\r\nEnvie de réaliser un tee shirt personnalisé ? Un sticker à l'effigie votre groupe préféré? Un masque pour la réalisation d'un circuit imprimé? Pour cela, il suffit simplement de venir avec votre fichier vectorisé (ne pas oublier de vectoriser les textes) type illustrator svg ou dxf.\r\n \r\nMatériaux utilisés :\r\nCette machine permet de découper principalement : vinyle, vinyle réfléchissant et flex.\r\n",
@ -35,6 +37,7 @@ class OpenAPI::V1::MachinesDoc < OpenAPI::V1::BaseDoc
"id": 3,
"name": "Shopbot / Grande fraiseuse",
"slug": "shopbot-grande-fraiseuse",
"disabled": false,
"updated_at": "2014-08-19T11:01:12.919+02:00",
"created_at": "2014-06-30T03:32:31.982+02:00",
"description": "La fraiseuse numérique ShopBot PRS standard\r\n\r\nInformations générales :\r\nCette machine est une fraiseuse 3 axes, idéale pour l'usinage de pièces de grandes dimensions. De la réalisation d'une chaise ou d'un meuble à la construction d'une maison ou d'un assemblage immense, le ShopBot ouvre de nombreuses portes à votre imagination ! \r\n\r\nMatériaux usinables :\r\nLes principaux matériaux usinables sont le bois, le plastique, le laiton et bien d'autres.\r\nCette machine n'usine pas les métaux.\r\n<object width=\"560\" height=\"315\"><param name=\"movie\" value=\"//www.youtube.com/v/3h8VPLNapag?hl=fr_FR&amp;version=3\"></param><param name=\"allowFullScreen\" value=\"true\"></param><param name=\"allowscriptaccess\" value=\"always\"></param><embed src=\"//www.youtube.com/v/3h8VPLNapag?hl=fr_FR&amp;version=3\" type=\"application/x-shockwave-flash\" width=\"560\" height=\"315\" allowscriptaccess=\"always\" allowfullscreen=\"true\"></embed></object>",
@ -44,6 +47,7 @@ class OpenAPI::V1::MachinesDoc < OpenAPI::V1::BaseDoc
"id": 4,
"name": "Imprimante 3D - Ultimaker",
"slug": "imprimante-3d",
"disabled": null,
"updated_at": "2014-12-11T15:47:02.215+01:00",
"created_at": "2014-06-30T03:32:31.986+02:00",
"description": "L'imprimante 3D ULTIMAKER\r\n\r\nInformations générales :\r\nL'utimaker est une imprimante 3D peu chère utilisant une technologie FFF (Fused Filament Fabrication) avec extrusion thermoplastique.\r\nC'est une machine idéale pour réaliser rapidement des prototypes 3D dans des couleurs différentes.\r\n",
@ -53,6 +57,7 @@ class OpenAPI::V1::MachinesDoc < OpenAPI::V1::BaseDoc
"id": 5,
"name": "Petite Fraiseuse",
"slug": "petite-fraiseuse",
"disabled": true,
"updated_at": "2014-06-30T14:33:37.638+02:00",
"created_at": "2014-06-30T03:32:31.989+02:00",
"description": "La fraiseuse numérique Roland Modela MDX-20\r\n\r\nInformations générales :\r\nCette machine est utilisée pour l'usinage et le scannage 3D de précision. Elle permet principalement d'usiner des circuits imprimés et des moules de petite taille. Le faible diamètre des fraises utilisées (Ø 0,3 mm à Ø 6mm) implique que certains temps d'usinages peuvent êtres long (> 12h), c'est pourquoi cette fraiseuse peut être laissée en autonomie toute une nuit afin d'obtenir le plus précis des usinages au FabLab.\r\n\r\nMatériaux usinables :\r\nLes principaux matériaux usinables sont : bois, plâtre, résine, cire usinable, cuivre.\r\n",
@ -65,6 +70,7 @@ class OpenAPI::V1::MachinesDoc < OpenAPI::V1::BaseDoc
"id": 18,
"name": "Canon IPF 750",
"slug": "canon-ipf-750",
"disabled": true,
"updated_at": "2015-10-12T18:00:24.254+02:00",
"created_at": "2015-10-12T18:00:24.254+02:00",
"description": "PROCHAINEMENT",

View File

@ -17,6 +17,7 @@ class OpenAPI::V1::TrainingsDoc < OpenAPI::V1::BaseDoc
"id": 1,
"name": "Formation Imprimante 3D",
"slug": "formation-imprimante-3d",
"disabled": null,
"updated_at": "2015-02-05T13:49:15.025+01:00",
"created_at": "2014-06-30T03:32:32.126+02:00",
"nb_total_places": 8,
@ -26,6 +27,7 @@ class OpenAPI::V1::TrainingsDoc < OpenAPI::V1::BaseDoc
"id": 2,
"name": "Formation Laser / Vinyle",
"slug": "formation-laser-vinyle",
"disabled": null,
"updated_at": "2015-02-05T13:49:19.046+01:00",
"created_at": "2014-06-30T03:32:32.138+02:00",
"nb_total_places": 8,
@ -35,6 +37,7 @@ class OpenAPI::V1::TrainingsDoc < OpenAPI::V1::BaseDoc
"id": 3,
"name": "Formation Petite fraiseuse numerique",
"slug": "formation-petite-fraiseuse-numerique",
"disabled": true,
"updated_at": "2015-02-05T13:49:23.040+01:00",
"created_at": "2014-06-30T03:32:32.164+02:00",
"nb_total_places": 8,
@ -44,6 +47,7 @@ class OpenAPI::V1::TrainingsDoc < OpenAPI::V1::BaseDoc
"id": 4,
"name": "Formation Shopbot Grande Fraiseuse",
"slug": "formation-shopbot-grande-fraiseuse",
"disabled": false,
"updated_at": "2015-02-03T10:22:21.908+01:00",
"created_at": "2014-06-30T03:32:32.168+02:00",
"nb_total_places": 6,
@ -53,6 +57,7 @@ class OpenAPI::V1::TrainingsDoc < OpenAPI::V1::BaseDoc
"id": 5,
"name": "Formation logiciel 2D",
"slug": "formation-logiciel-2d",
"disabled": false,
"updated_at": "2015-02-05T13:49:27.460+01:00",
"created_at": "2014-06-30T09:37:42.778+02:00",
"nb_total_places": 8,
@ -62,6 +67,7 @@ class OpenAPI::V1::TrainingsDoc < OpenAPI::V1::BaseDoc
"id": 6,
"name": "Pas de Reservation",
"slug": "pas-de-reservation",
"disabled": null,
"updated_at": "2014-07-22T14:18:11.784+02:00",
"created_at": "2014-07-22T14:18:11.784+02:00",
"nb_total_places": null,

View File

@ -4,4 +4,5 @@ class Credit < ActiveRecord::Base
has_many :users_credits, dependent: :destroy
validates :creditable_id, uniqueness: { scope: [:creditable_type, :plan_id] }
validates :hours, numericality: { greater_than_or_equal_to: 0 }
end

View File

@ -1 +1,2 @@
json.extract! group, :id, :slug, :name
json.extract! group, :id, :slug, :name, :disabled
json.users group.users.count

View File

@ -1,5 +1,5 @@
json.array!(@machines) do |machine|
json.extract! machine, :id, :name, :description, :spec, :slug
json.extract! machine, :id, :name, :description, :spec, :slug, :disabled
json.url machine_url(machine, format: :json)
json.machine_image machine.machine_image.attachment.medium.url if machine.machine_image
end

View File

@ -1,11 +1,11 @@
json.extract! @machine, :id, :name, :description, :spec, :created_at, :updated_at, :slug
json.extract! @machine, :id, :name, :description, :spec, :disabled, :created_at, :updated_at, :slug
json.machine_image @machine.machine_image.attachment.large.url if @machine.machine_image
json.machine_files_attributes @machine.machine_files do |f|
json.id f.id
json.attachment f.attachment_identifier
json.attachment_url f.attachment_url
end
json.trainings @machine.trainings.each, :id, :name
json.trainings @machine.trainings.each, :id, :name, :disabled
json.current_user_is_training current_user.is_training_machine?(@machine) if current_user
json.current_user_training_reservation do
json.partial! 'api/reservations/reservation', reservation: current_user.training_reservation_by_machine(@machine)

View File

@ -1,4 +1,4 @@
json.extract! plan, :id, :base_name, :name, :interval, :interval_count, :group_id, :training_credit_nb, :is_rolling, :description, :type, :ui_weight
json.extract! plan, :id, :base_name, :name, :interval, :interval_count, :group_id, :training_credit_nb, :is_rolling, :description, :type, :ui_weight, :disabled
json.amount (plan.amount / 100.00)
json.prices plan.prices, partial: 'api/prices/price', as: :price
json.plan_file_attributes do

View File

@ -1,5 +1,5 @@
json.array!(@plans) do |plan|
json.extract! plan, :id, :base_name, :name, :interval, :interval_count, :group_id, :training_credit_nb, :description, :type, :ui_weight
json.extract! plan, :id, :base_name, :name, :interval, :interval_count, :group_id, :training_credit_nb, :description, :type, :ui_weight, :disabled
json.amount (plan.amount / 100.00)
json.plan_file_url plan.plan_file.attachment_url if plan.plan_file
end

View File

@ -7,5 +7,6 @@ json.array!(@plans) do |plan|
json.interval plan.interval
json.interval_count plan.interval_count
json.type plan.type
json.disabled plan.disabled
json.plan_file_url plan.plan_file.attachment_url if plan.plan_file
end

View File

@ -1,4 +1,4 @@
json.array!(@spaces) do |space|
json.extract! space, :id, :name, :description, :slug, :default_places
json.extract! space, :id, :name, :description, :slug, :default_places, :disabled
json.space_image space.space_image.attachment.medium.url if space.space_image
end

View File

@ -1,4 +1,4 @@
json.extract! @space, :id, :name, :description, :characteristics, :created_at, :updated_at, :slug, :default_places
json.extract! @space, :id, :name, :description, :characteristics, :created_at, :updated_at, :slug, :default_places, :disabled
json.space_image @space.space_image.attachment.large.url if @space.space_image
json.space_files_attributes @space.space_files do |f|
json.id f.id

View File

@ -1,7 +1,7 @@
role = (current_user and current_user.is_admin?) ? 'admin' : 'user'
json.array!(@trainings) do |training|
json.extract! training, :id, :name, :description, :machine_ids, :nb_total_places, :slug
json.extract! training, :id, :name, :description, :machine_ids, :nb_total_places, :slug, :disabled
json.training_image training.training_image.attachment.large.url if training.training_image
json.plan_ids training.plan_ids if role === 'admin'
end

View File

@ -1,2 +1,2 @@
json.extract! @training, :id, :name, :description, :machine_ids, :nb_total_places, :public_page
json.extract! @training, :id, :name, :description, :machine_ids, :nb_total_places, :public_page, :disabled
json.training_image @training.training_image.attachment.large.url if @training.training_image

View File

@ -1,7 +1,14 @@
<% provider = AuthProvider.from_strategy_name(@attached_object.provider) %>
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
<p><%= t('.body.account_completed', PROVIDER: provider.name) %>
<% if provider.name == AuthProvider::SimpleAuthProvider.new.name %>
<p><%= t('.body.account_completed') %>
<%= "#{@attached_object.profile.full_name}" %> &lt;<%= @attached_object.email%>&gt;.</p>
<% else %>
<p><%= t('.body.imported_account_completed', PROVIDER: provider.name) %>
<%= "#{@attached_object.profile.full_name}" %> &lt;<%= @attached_object.email%>&gt;.</p>
<% end %>
<p><%= t('.body.provider_id', UID: @attached_object.uid) %></p>
<% if @attached_object.uid %>
<p><%= t('.body.provider_id', UID: @attached_object.uid) %></p>
<% end %>

View File

@ -1 +1 @@
json.extract! machine, :id, :name, :slug, :updated_at, :created_at
json.extract! machine, :id, :name, :slug, :disabled, :updated_at, :created_at

View File

@ -1 +1 @@
json.extract! training, :id, :name, :slug, :updated_at, :created_at
json.extract! training, :id, :name, :slug, :disabled, :updated_at, :created_at

View File

@ -73,6 +73,9 @@ en:
trainings:
# track and monitor the trainings
training: "Training"
add_a_new_training: "Add a new training"
associated_machines: "Associated machines"
number_of_tickets: "Number of tickets"
year_NUMBER: "Year {{NUMBER}}" # angular interpolation
month_of_NAME: "Month of {{NAME}}" # angular interpolation
NUMBER_reservation: "{NUMBER} {NUMBER, plural, one{reservation} other{reservations}}" # messageFormat interpolation
@ -89,11 +92,16 @@ en:
training_successfully_deleted: "Training successfully deleted."
unable_to_delete_the_training_because_some_users_alredy_booked_it: "Unable to delete the training because some users already booked it."
do_you_really_want_to_delete_this_training: "Do you really want to delete this training?"
status_enabled: "Enabled"
status_disabled: "Disabled"
status_all: "All"
trainings_new:
# create a new training
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero."
dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training."
trainings_new:
add_a_new_training: "Add a new training"
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero."
dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training."
events:
# events tracking and management
@ -196,6 +204,7 @@ en:
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Error : a credit linking this machine with that subscription already exists."
changes_have_been_successfully_saved: "Changes have been successfully saved."
credit_was_successfully_saved: "Credit was successfully saved."
error_creating_credit: "Unable to create credit, an error occurred"
do_you_really_want_to_delete_this_subscription_plan: "Do you really want to delete this subscription plan?"
subscription_plan_was_successfully_deleted: "Subscription plan was successfully deleted."
unable_to_delete_the_specified_subscription_an_error_occurred: "Unable to delete the specified subscription, an error occurred."
@ -230,6 +239,9 @@ en:
add_a_space_credit: "Add a Space credit"
space: "Espace"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Error : a credit linking this space with that subscription already exists."
status_enabled: "Enabled"
status_disabled: "Disabled"
status_all: "All"
coupons_new:
# ajouter un code promotionnel
@ -393,14 +405,8 @@ en:
this_may_take_a_while_please_wait: "Warning: this may take a while, please be patient."
administrator_successfully_deleted: "Administrator successfully deleted."
unable_to_delete_the_administrator: "Unable to delete the administrator."
add_a_group: "Add a group"
group_name: "Group name"
changes_successfully_saved: "Changes successfully saved."
an_error_occurred_while_saving_changes: "An error occurred when saving changes."
new_group_successfully_saved: "New group successfully saved."
an_error_occurred_when_saving_the_new_group: "An error occurred when saving the new group."
group_successfully_deleted: "Group successfully deleted."
unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it: "Unable to delete group because some users and/or groups are still linked to it."
add_a_tag: "Add a tag"
tag_name: "Tag name"
new_tag_successfully_saved: "New tag successfully saved."
@ -420,6 +426,23 @@ en:
an_error_occurred_unable_to_delete_the_specified_provider: "An error occurred: unable to delete the specified provider."
local_database: "Local database"
o_auth2: "OAuth 2.0"
group_form:
add_a_group: "Add a group"
group_name: "Group name"
disable: "Disable"
enable: "Enable"
changes_successfully_saved: "Changes successfully saved."
an_error_occurred_while_saving_changes: "An error occurred when saving changes."
new_group_successfully_saved: "New group successfully saved."
an_error_occurred_when_saving_the_new_group: "An error occurred when saving the new group."
group_successfully_deleted: "Group successfully deleted."
unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it: "Unable to delete group because some users and/or groups are still linked to it."
group_successfully_enabled_disabled: "Group successfully {STATUS, select, true{disabled} other{enabled}}." # messageFormat interpolation
unable_to_enable_disable_group: "Unable to {STATUS, select, true{disable} other{enable}} group." # messageFormat interpolation
unable_to_disable_group_with_users: "Unable to disable group because it still contains {USERS} active {USERS, plural, =1{user} other{users}}." # messageFormat interpolation
status_enabled: "Enabled"
status_disabled: "Disabled"
status_all: "All"
members_new:
# add a member

View File

@ -73,6 +73,9 @@ fr:
trainings:
# suivre et surveiller les formations
training: "Formation"
add_a_new_training: "Ajouter une nouvelle formation"
associated_machines: "Machines associées"
number_of_tickets: "Nombre de places"
year_NUMBER: "Année {{NUMBER}}" # angular interpolation
month_of_NAME: "Mois de {{NAME}}" # angular interpolation
NUMBER_reservation: "{NUMBER} {NUMBER, plural, =0{réservation} one{réservation} other{réservations}}" # messageFormat interpolation
@ -89,11 +92,16 @@ fr:
training_successfully_deleted: "La formation a bien été supprimée."
unable_to_delete_the_training_because_some_users_alredy_booked_it: "La formation ne peut pas être supprimée car elle a déjà été réservée par des utilisateurs."
do_you_really_want_to_delete_this_training: "Êtes-vous sur de vouloir supprimer cette formation ?"
status_enabled: "Actifs"
status_disabled: "Désactivés"
status_all: "Tous"
trainings_new:
# créer une nouvelle formation
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Attention, lors de la création d'une formation, ses tarifs de réservation sont initialisés à zero."
dont_forget_to_change_them_before_creating_slots_for_this_training: "Pensez à les modifier avant de créer des créneaux pour cette formation."
trainings_new:
add_a_new_training: "Ajouter une nouvelle formation"
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Attention, lors de la création d'une formation, ses tarifs de réservation sont initialisés à zero."
dont_forget_to_change_them_before_creating_slots_for_this_training: "Pensez à les modifier avant de créer des créneaux pour cette formation."
events:
# gestion et suivi des évènements
@ -196,6 +204,7 @@ fr:
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Erreur : un crédit associant cette machine et cet abonnement existe déjà."
changes_have_been_successfully_saved: "Les modifications ont bien été enregistrées."
credit_was_successfully_saved: "Le crédit a bien été enregistré."
error_creating_credit: "Impossible de créer le credit, une erreur est survenue"
do_you_really_want_to_delete_this_subscription_plan: "Êtes-vous sûr(e) de vouloir supprimer cette formule d'abonnement ?"
subscription_plan_was_successfully_deleted: "La formule d'abonnement a bien été supprimée."
unable_to_delete_the_specified_subscription_an_error_occurred: "Impossible de supprimer l'abonnement spécifié, une erreur s'est produite."
@ -230,6 +239,9 @@ fr:
add_a_space_credit: "Ajouter un crédit Espace"
space: "Espace"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Erreur : un crédit associant cet espace et cet abonnement existe déjà."
status_enabled: "Actifs"
status_disabled: "Désactivés"
status_all: "Tous"
coupons_new:
# ajouter un code promotionnel
@ -393,14 +405,8 @@ fr:
this_may_take_a_while_please_wait: "Attention : ceci peut prendre un certain temps, merci de patienter."
administrator_successfully_deleted: "L'administrateur a bien été supprimé."
unable_to_delete_the_administrator: "L'administrateur n'a pas pu être supprimé."
add_a_group: "Ajouter un groupe"
group_name: "Nom du groupe"
changes_successfully_saved: "Les modifications ont bien été enregistrées."
an_error_occurred_while_saving_changes: "Une erreur est survenue lors de l'enregistrement des modifications."
new_group_successfully_saved: "Le nouveau groupe a bien été enregistré."
an_error_occurred_when_saving_the_new_group: "Une erreur est survenue lors de l'enregistrement du nouveau groupe."
group_successfully_deleted: "Le groupe a bien été supprimé."
unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it: "Le groupe n'a pas pu être supprimé car des utilisateurs et/ou des abonnements sont toujours associés à ce dernier."
add_a_tag: "Ajouter une étiquette"
tag_name: "Nom de l'étiquette"
new_tag_successfully_saved: "La nouvelle étiquette a bien été enregistrée."
@ -420,6 +426,23 @@ fr:
an_error_occurred_unable_to_delete_the_specified_provider: "Une erreur est survenue : impossible de supprimer le fournisseur spécifié."
local_database: "Base de données locale"
o_auth2: "OAuth 2.0"
group_form:
add_a_group: "Ajouter un groupe"
group_name: "Nom du groupe"
disable: "Désactiver"
enable: "Activer"
changes_successfully_saved: "Les modifications ont bien été enregistrées."
an_error_occurred_while_saving_changes: "Une erreur est survenue lors de l'enregistrement des modifications."
new_group_successfully_saved: "Le nouveau groupe a bien été enregistré."
an_error_occurred_when_saving_the_new_group: "Une erreur est survenue lors de l'enregistrement du nouveau groupe."
group_successfully_deleted: "Le groupe a bien été supprimé."
unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it: "Le groupe n'a pas pu être supprimé car des utilisateurs et/ou des abonnements sont toujours associés à ce dernier."
group_successfully_enabled_disabled: "Le groupe a bien été {STATUS, select, true{désactivé} other{activé}}." # messageFormat interpolation
unable_to_enable_disable_group: "Impossible {STATUS, select, true{de désactiver} other{d'activer}} le groupe." # messageFormat interpolation
unable_to_disable_group_with_users: "Impossible de désactiver le groupe car il contient encore {USERS} {USERS, plural, =0{personne} =1{utilisateur actif} other{utilisateurs actifs}}." # messageFormat interpolation
status_enabled: "Activés"
status_disabled: "Désactivés"
status_all: "Tous"
members_new:
# ajouter un membre

View File

@ -73,6 +73,9 @@ pt:
trainings:
# track and monitor the trainings
training: "Treinamento"
add_a_new_training: "Adicionar um novo treinamento"
associated_machines: "Máquinas associadas"
number_of_tickets: "Número de vagas"
year_NUMBER: "Ano {{NUMBER}}" # angular interpolation
month_of_NAME: "Mês de {{NAME}}" # angular interpolation
NUMBER_reservation: "{NUMBER} {NUMBER, plural, one{reserva} other{reservas}}" # messageFormat interpolation
@ -89,11 +92,16 @@ pt:
training_successfully_deleted: "O treinamento foi deletado com sucesso."
unable_to_delete_the_training_because_some_users_alredy_booked_it: "Não é possível deletar o treinamento, pois alguns membros já o reservaram."
do_you_really_want_to_delete_this_training: "Você realmente quer deletar este treinamento?"
status_enabled: "Ativos"
status_disabled: "Desabilitados"
status_all: "Todos"
trainings_new:
# create a new training
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Cuidado, ao criar um treinamento, seu preço de reserva é inicializado em zero."
dont_forget_to_change_them_before_creating_slots_for_this_training: "Não se esqueça de alterá-lo antes de criar slots para este treinamento."
trainings_new:
add_a_new_training: "Adicionar um novo treinamento"
beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Cuidado, ao criar um treinamento, seu preço de reserva é inicializado em zero."
dont_forget_to_change_them_before_creating_slots_for_this_training: "Não se esqueça de alterá-lo antes de criar slots para este treinamento."
events:
# events tracking and management
@ -196,6 +204,7 @@ pt:
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Erro : um link de crédito entre esta máquina e esta assinatura já existe."
changes_have_been_successfully_saved: "As modificações foram salvas com sucesso."
credit_was_successfully_saved: "Crédito salvo com sucesso."
error_creating_credit: "Unable to create credit, an error occurred" # TODO
do_you_really_want_to_delete_this_subscription_plan: "Você realmente deletar esse plano de assinatura?"
subscription_plan_was_successfully_deleted: "Plano de assinatura foi deletado com sucesso."
unable_to_delete_the_specified_subscription_an_error_occurred: "Não é possível deletar a assinatura específicada, um erro ocorreu."
@ -230,6 +239,9 @@ pt:
add_a_space_credit: "Adicionar espaço de crédito"
space: "Espaço"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Erro: um crédito que vincula esse espaço com essa assinatura já existe."
status_enabled: "Ativos"
status_disabled: "Desabilitados"
status_all: "Todos"
coupons_new:
# ajouter un code promotionnel
@ -420,6 +432,23 @@ pt:
an_error_occurred_unable_to_delete_the_specified_provider: "Ocorreu um erro: não é possível excluir o provedor especificado."
local_database: "Database local"
o_auth2: "OAuth 2.0"
group_form:
add_a_group: "Adicionar grupo"
group_name: "Nome do grupo"
disable: "Desativar"
enable: "Habilitar"
changes_successfully_saved: "Mudanças salvas com sucesso."
an_error_occurred_while_saving_changes: "Um erro ocorreu ao salvar mudanças."
new_group_successfully_saved: "Novo grupo salvo com sucesso."
an_error_occurred_when_saving_the_new_group: "Um erro ocorreu ao salvar novo grupo."
group_successfully_deleted: "Grupo excluido com sucesso."
unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it: "Não é possível excluir o grupo porque alguns usuários e / ou grupos ainda estão vinculados a ele."
group_successfully_enabled_disabled: "Group successfully {STATUS, select, true{disabled} other{enabled}}." # messageFormat interpolation TODO
unable_to_enable_disable_group: "Unable to {STATUS, select, true{disable} other{enable}} group." # messageFormat interpolation TODO
unable_to_disable_group_with_users: "Unable to disable group because it still contains {USERS} active {USERS, plural, =1{user} other{users}}." # messageFormat interpolation TODO
status_enabled: "Ativos"
status_disabled: "Desabilitados"
status_all: "Todos"
members_new:
# add a member

View File

@ -175,9 +175,14 @@ en:
machines_list:
# list of machines
the_fablab_s_machines: "The FabLab's machines"
add_a_machine: "Add a machine"
_or_the_: " or the "
machines_list:
the_fablab_s_machines: "The FabLab's machines"
add_a_machine: "Add a machine"
book: "Book"
_or_the_: " or the "
status_enabled: "Enabled"
status_disabled: "Disabled"
status_all: "All"
machines_show:
# details of a machine
@ -265,8 +270,13 @@ en:
spaces_list:
# list of spaces
the_spaces: "The spaces"
add_a_space: "Add a space"
spaces_list:
the_spaces: "The spaces"
add_a_space: "Add a space"
status_enabled: "Enabled"
status_disabled: "Disabled"
status_all: "All"
book: "Book"
space_show:
# display the details of a space

View File

@ -175,9 +175,14 @@ fr:
machines_list:
# liste des machines
the_fablab_s_machines: "Les machines du FabLab"
add_a_machine: "Ajouter une machine"
_or_the_: " ou la "
machines_list:
the_fablab_s_machines: "Les machines du FabLab"
add_a_machine: "Ajouter une machine"
book: "Réserver"
_or_the_: " ou la "
status_enabled: "Actives"
status_disabled: "Désactivées"
status_all: "Toutes"
machines_show:
# détail d'une machine
@ -267,8 +272,13 @@ fr:
spaces_list:
# liste des espaces
the_spaces: "Les espaces"
add_a_space: "Ajouter un espace"
spaces_list:
the_spaces: "Les espaces"
add_a_space: "Ajouter un espace"
status_enabled: "Activés"
status_disabled: "Désactivés"
status_all: "Tous"
book: "Réserver"
space_show:
# affichage des détails d'un espace

View File

@ -175,9 +175,14 @@ pt:
machines_list:
# list of machines
the_fablab_s_machines: "Lista de máquinas no FabLab"
add_a_machine: "Adicionar uma máquina"
_or_the_: " ou o "
machines_list:
the_fablab_s_machines: "Lista de máquinas no FabLab"
add_a_machine: "Adicionar uma máquina"
book: "Reservar"
_or_the_: " ou o "
status_enabled: "Ativos" # TODO
status_disabled: "Desabilitados" # TODO
status_all: "Todos" # TODO
machines_show:
# details of a machine
@ -265,8 +270,13 @@ pt:
spaces_list:
# list of spaces
the_spaces: "Os espaços"
add_a_space: "Adicionar espaço"
spaces_list:
the_spaces: "Os espaços"
add_a_space: "Adicionar espaço"
status_enabled: "Ativos" # TODO
status_disabled: "Desabilitados" # TODO
status_all: "Todos" # TODO
book: "Reservar"
space_show:
# display the details of a space

View File

@ -230,14 +230,24 @@ en:
as_part_of_a_partner_subscription_some_notifications_may_be_sent_to_this_user: "As part of a partner subscription, some notifications may be sent to this user."
new_partner: "New partner"
email_address_is_required: "Email address is required."
disabled: "Disable subscription"
disable_plan_will_not_unsubscribe_users: "Beware: disabling this plan won't unsubscribe users having active subscriptions with it."
trainings:
# training edition form
add_a_new_training: "Add a new training"
validate_your_training: "Validate your training"
associated_machines: "Associated machines"
number_of_tickets: "Number of tickets"
public_page: "Show in training lists"
trainings_form:
name: "Name"
name_is_required: "Name is required."
illustration: "Illustration"
add_an_illustration: "Add an illustration"
description: "Description"
description_is_required: "Description is required."
add_a_new_training: "Add a new training"
validate_your_training: "Validate your training"
associated_machines: "Associated machines"
number_of_tickets: "Number of tickets"
public_page: "Show in training lists"
disable_training: "Disable the training"
user_admin:
# partial form to edit/create an user (admin view)
@ -405,6 +415,7 @@ en:
add_an_attachment: "Add an attachment"
default_places: "Default maximum tickets"
default_places_is_required: "Default maximum tickets is required."
disable_space: "Disable space"
cart:
# module de panier d'achat de réservations

View File

@ -144,11 +144,20 @@ fr:
machine:
# formulaire d'édition d'une machine
technical_specifications_are_required: "Les caractéristiques techniques sont requises."
attached_files_(pdf): "Pièces jointes (pdf)"
attach_a_file: "Joindre un fichier"
add_an_attachment: "Ajouter une pièce jointe"
validate_your_machine: "Valider votre machine"
machine_form:
name: "Nom"
name_is_required: "Le nom est requis."
illustration: "Visuel"
add_an_illustration: "Ajouter un visuel"
description: "Description"
description_is_required: "La description est requise."
technical_specifications: "Caractéristiques techniques"
technical_specifications_are_required: "Les caractéristiques techniques sont requises."
attached_files_(pdf): "Pièces jointes (pdf)"
attach_a_file: "Joindre un fichier"
add_an_attachment: "Ajouter une pièce jointe"
disable_machine: "Désactiver la machine"
validate_your_machine: "Valider votre machine"
plan_subscribe:
# cadre de souscription à un abonnement
@ -230,14 +239,24 @@ fr:
as_part_of_a_partner_subscription_some_notifications_may_be_sent_to_this_user: "Dans le cadre d'un abonnement partenaire, certaines notifications pourront être adressées à cet utilisateur."
new_partner: "Nouveau partenaire"
email_address_is_required: "L'adresse e-mail est requise."
disabled: "Désactiver l'abonnement"
disable_plan_will_not_unsubscribe_users: "Attention : désactiver l'abonnement ne désabonnera pas les utilisateurs ayant actuellement cet abonnement actif."
trainings:
# formulaire d'édition d'une formation
add_a_new_training: "Ajouter une nouvelle formation"
validate_your_training: "Valider votre formation"
associated_machines: "Machines associées"
number_of_tickets: "Nombre de places"
public_page: "Afficher dans la liste de formation"
trainings_form:
name: "Nom"
name_is_required: "Le nom est requis."
illustration: "Visuel"
add_an_illustration: "Ajouter un visuel"
description: "Description"
description_is_required: "La description est requise."
add_a_new_training: "Ajouter une nouvelle formation"
validate_your_training: "Valider votre formation"
associated_machines: "Machines associées"
number_of_tickets: "Nombre de places"
public_page: "Afficher dans la liste de formation"
disable_training: "Désactiver la formation"
user_admin:
# formulaire partiel d'édition/création utilisateur (vue admin)
@ -405,6 +424,7 @@ fr:
add_an_attachment: "Ajouter une pièce jointe"
default_places: "Maximum de places par défaut"
default_places_is_required: "Le nombre de places maximum par défaut est requis."
disable_space: "Désactiver l'espace"
cart:
# module de panier d'achat de réservations

View File

@ -230,14 +230,24 @@ pt:
as_part_of_a_partner_subscription_some_notifications_may_be_sent_to_this_user: "Como parte da inscrição do parceiro, algumas notificações podem ser enviadas para este usuário."
new_partner: "Novo parceiro"
email_address_is_required: "Email é obrigatório."
disabled: "Disable subscrição"
disable_plan_will_not_unsubscribe_users: "Aviso: desativar a assinatura não desautorizará os usuários que atualmente possuem esta assinatura ativa."
trainings:
# training edition form
add_a_new_training: "Adicionar um novo treinamento"
validate_your_training: "Validar seu treinamento"
associated_machines: "Máquinas associadas"
number_of_tickets: "Número de vagas"
public_page: "Mostrar na lista de treinamentos"
trainings_form:
name: "Nome"
name_is_required: "Nome é obrigatório."
illustration: "Ilustração"
add_an_illustration: "Adicionar ilustração"
description: "Descrição"
description_is_required: "Descrição é obrigatório."
add_a_new_training: "Adicionar um novo treinamento"
validate_your_training: "Validar seu treinamento"
associated_machines: "Máquinas associadas"
number_of_tickets: "Número de vagas"
public_page: "Mostrar na lista de treinamentos"
disable_training: "Disable the training" # TODO
user_admin:
# partial form to edit/create an user (admin view)
@ -405,6 +415,7 @@ pt:
add_an_attachment: "Adicionar um anexo"
default_places: "Tickets máximo padrão"
default_places_is_required: "Tickets máximo padrão é obrigatório."
disable_space: "Disable space" # TODO
cart:
# module de panier d'achat de réservations

View File

@ -228,7 +228,8 @@ en:
notify_admin_profile_complete:
subject: "An imported account has completed its profile"
body:
account_completed: "A previously imported user account via %{PROVIDER} has completed its profile:"
account_completed: "An user account has completed its profile:"
imported_account_completed: "An user account, previously imported through %{PROVIDER}, has completed its profile:"
provider_id: "its provider ID is:"
notify_admin_abuse_reported:

View File

@ -228,7 +228,8 @@ fr:
notify_admin_profile_complete:
subject: "Un compte importé a complété ses informations"
body:
account_completed: "Un compte utilisateur précédemment importé via %{PROVIDER} vient de compléter ses informations de profil :"
account_completed: "Un compte utilisateur vient de compléter ses informations de profil :"
imported_account_completed: "Un compte utilisateur précédemment importé via %{PROVIDER} vient de compléter ses informations de profil :"
provider_id: "Son identifiant fournisseur est %{UID}"
notify_admin_abuse_reported:

View File

@ -228,7 +228,8 @@ pt:
notify_admin_profile_complete:
subject: "Uma conta importada teve o perfil completado"
body:
account_completed: "Uma conta de usuário importada anteriormente via %{PROVIDER} completou seu perfil:"
account_completed: "Uma conta de usuário completou seu perfil:"
imported_account_completed: "Uma conta de usuário importada anteriormente via %{PROVIDER} completou seu perfil:"
provider_id: "Seu ID de provedor é:"
notify_admin_abuse_reported:

View File

@ -0,0 +1,5 @@
class AddDisabledToPlan < ActiveRecord::Migration
def change
add_column :plans, :disabled, :boolean
end
end

View File

@ -0,0 +1,5 @@
class AddDisabledToGroup < ActiveRecord::Migration
def change
add_column :groups, :disabled, :boolean
end
end

View File

@ -0,0 +1,5 @@
class AddDisabledToTraining < ActiveRecord::Migration
def change
add_column :trainings, :disabled, :boolean
end
end

View File

@ -0,0 +1,5 @@
class AddDisabledToMachine < ActiveRecord::Migration
def change
add_column :machines, :disabled, :boolean
end
end

View File

@ -0,0 +1,5 @@
class AddDisabledToSpace < ActiveRecord::Migration
def change
add_column :spaces, :disabled, :boolean
end
end

View File

@ -11,12 +11,12 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170906100906) do
ActiveRecord::Schema.define(version: 20171011125217) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
enable_extension "unaccent"
enable_extension "pg_trgm"
enable_extension "unaccent"
create_table "abuses", force: :cascade do |t|
t.integer "signaled_id"
@ -32,14 +32,14 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "abuses", ["signaled_type", "signaled_id"], name: "index_abuses_on_signaled_type_and_signaled_id", using: :btree
create_table "addresses", force: :cascade do |t|
t.string "address"
t.string "street_number"
t.string "route"
t.string "locality"
t.string "country"
t.string "postal_code"
t.string "address", limit: 255
t.string "street_number", limit: 255
t.string "route", limit: 255
t.string "locality", limit: 255
t.string "country", limit: 255
t.string "postal_code", limit: 255
t.integer "placeable_id"
t.string "placeable_type"
t.string "placeable_type", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
@ -55,9 +55,9 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "assets", force: :cascade do |t|
t.integer "viewable_id"
t.string "viewable_type"
t.string "attachment"
t.string "type"
t.string "viewable_type", limit: 255
t.string "attachment", limit: 255
t.string "type", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
@ -74,12 +74,12 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "availabilities", force: :cascade do |t|
t.datetime "start_at"
t.datetime "end_at"
t.string "available_type"
t.string "available_type", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.integer "nb_total_places"
t.boolean "destroying", default: false
t.boolean "lock", default: false
t.boolean "destroying", default: false
t.boolean "lock", default: false
end
create_table "availability_tags", force: :cascade do |t|
@ -93,7 +93,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "availability_tags", ["tag_id"], name: "index_availability_tags_on_tag_id", using: :btree
create_table "categories", force: :cascade do |t|
t.string "name"
t.string "name", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.string "slug"
@ -102,7 +102,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "categories", ["slug"], name: "index_categories_on_slug", unique: true, using: :btree
create_table "components", force: :cascade do |t|
t.string "name", null: false
t.string "name", limit: 255, null: false
end
create_table "coupons", force: :cascade do |t|
@ -120,7 +120,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "credits", force: :cascade do |t|
t.integer "creditable_id"
t.string "creditable_type"
t.string "creditable_type", limit: 255
t.integer "plan_id"
t.integer "hours"
t.datetime "created_at"
@ -161,7 +161,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "event_themes", ["slug"], name: "index_event_themes_on_slug", unique: true, using: :btree
create_table "events", force: :cascade do |t|
t.string "title"
t.string "title", limit: 255
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
@ -199,10 +199,10 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "exports", ["user_id"], name: "index_exports_on_user_id", using: :btree
create_table "friendly_id_slugs", force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
t.string "slug", limit: 255, null: false
t.integer "sluggable_id", null: false
t.string "sluggable_type", limit: 50
t.string "scope"
t.string "scope", limit: 255
t.datetime "created_at"
end
@ -212,17 +212,18 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "friendly_id_slugs", ["sluggable_type"], name: "index_friendly_id_slugs_on_sluggable_type", using: :btree
create_table "groups", force: :cascade do |t|
t.string "name"
t.string "name", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.string "slug"
t.string "slug", limit: 255
t.boolean "disabled"
end
add_index "groups", ["slug"], name: "index_groups_on_slug", unique: true, using: :btree
create_table "invoice_items", force: :cascade do |t|
t.integer "invoice_id"
t.string "stp_invoice_item_id"
t.string "stp_invoice_item_id", limit: 255
t.integer "amount"
t.datetime "created_at"
t.datetime "updated_at"
@ -235,17 +236,17 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "invoices", force: :cascade do |t|
t.integer "invoiced_id"
t.string "invoiced_type"
t.string "stp_invoice_id"
t.string "invoiced_type", limit: 255
t.string "stp_invoice_id", limit: 255
t.integer "total"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.string "reference"
t.string "avoir_mode"
t.string "reference", limit: 255
t.string "avoir_mode", limit: 255
t.datetime "avoir_date"
t.integer "invoice_id"
t.string "type"
t.string "type", limit: 255
t.boolean "subscription_to_expire"
t.text "description"
t.integer "wallet_amount"
@ -259,17 +260,18 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "invoices", ["wallet_transaction_id"], name: "index_invoices_on_wallet_transaction_id", using: :btree
create_table "licences", force: :cascade do |t|
t.string "name", null: false
t.string "name", limit: 255, null: false
t.text "description"
end
create_table "machines", force: :cascade do |t|
t.string "name", null: false
t.string "name", limit: 255, null: false
t.text "description"
t.text "spec"
t.datetime "created_at"
t.datetime "updated_at"
t.string "slug"
t.string "slug", limit: 255
t.boolean "disabled"
end
add_index "machines", ["slug"], name: "index_machines_on_slug", unique: true, using: :btree
@ -285,14 +287,14 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "notifications", force: :cascade do |t|
t.integer "receiver_id"
t.integer "attached_object_id"
t.string "attached_object_type"
t.string "attached_object_type", limit: 255
t.integer "notification_type_id"
t.boolean "is_read", default: false
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.boolean "is_send", default: false
t.jsonb "meta_data", default: {}
end
add_index "notifications", ["notification_type_id"], name: "index_notifications_on_notification_type_id", using: :btree
@ -361,21 +363,22 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "organizations", ["profile_id"], name: "index_organizations_on_profile_id", using: :btree
create_table "plans", force: :cascade do |t|
t.string "name"
t.string "name", limit: 255
t.integer "amount"
t.string "interval"
t.string "interval", limit: 255
t.integer "group_id"
t.string "stp_plan_id"
t.string "stp_plan_id", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.integer "training_credit_nb", default: 0
t.boolean "is_rolling", default: true
t.integer "training_credit_nb", default: 0
t.boolean "is_rolling", default: true
t.text "description"
t.string "type"
t.string "base_name"
t.integer "ui_weight", default: 0
t.integer "interval_count", default: 1
t.integer "ui_weight", default: 0
t.integer "interval_count", default: 1
t.string "slug"
t.boolean "disabled"
end
add_index "plans", ["group_id"], name: "index_plans_on_group_id", using: :btree
@ -403,11 +406,11 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "profiles", force: :cascade do |t|
t.integer "user_id"
t.string "first_name"
t.string "last_name"
t.string "first_name", limit: 255
t.string "last_name", limit: 255
t.boolean "gender"
t.date "birthday"
t.string "phone"
t.string "phone", limit: 255
t.text "interest"
t.text "software_mastered"
t.datetime "created_at"
@ -437,7 +440,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
t.integer "project_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "title"
t.string "title", limit: 255
t.integer "step_nb"
end
@ -448,27 +451,27 @@ ActiveRecord::Schema.define(version: 20170906100906) do
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "is_valid", default: false
t.string "valid_token"
t.boolean "is_valid", default: false
t.string "valid_token", limit: 255
end
add_index "project_users", ["project_id"], name: "index_project_users_on_project_id", using: :btree
add_index "project_users", ["user_id"], name: "index_project_users_on_user_id", using: :btree
create_table "projects", force: :cascade do |t|
t.string "name"
t.string "name", limit: 255
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "author_id"
t.text "tags"
t.integer "licence_id"
t.string "state"
t.string "slug"
t.string "state", limit: 255
t.string "slug", limit: 255
t.datetime "published_at"
end
add_index "projects", ["slug"], name: "index_projects_on_slug", unique: true, using: :btree
add_index "projects", ["slug"], name: "index_projects_on_slug", using: :btree
create_table "projects_components", force: :cascade do |t|
t.integer "project_id"
@ -508,19 +511,19 @@ ActiveRecord::Schema.define(version: 20170906100906) do
t.datetime "created_at"
t.datetime "updated_at"
t.integer "reservable_id"
t.string "reservable_type"
t.string "stp_invoice_id"
t.string "reservable_type", limit: 255
t.string "stp_invoice_id", limit: 255
t.integer "nb_reserve_places"
end
add_index "reservations", ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_id", using: :btree
add_index "reservations", ["reservable_id", "reservable_type"], name: "index_reservations_on_reservable_id_and_reservable_type", using: :btree
add_index "reservations", ["stp_invoice_id"], name: "index_reservations_on_stp_invoice_id", using: :btree
add_index "reservations", ["user_id"], name: "index_reservations_on_user_id", using: :btree
create_table "roles", force: :cascade do |t|
t.string "name"
t.string "name", limit: 255
t.integer "resource_id"
t.string "resource_type"
t.string "resource_type", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
@ -568,6 +571,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "characteristics"
t.boolean "disabled"
end
create_table "spaces_availabilities", force: :cascade do |t|
@ -594,18 +598,18 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "statistic_fields", force: :cascade do |t|
t.integer "statistic_index_id"
t.string "key"
t.string "label"
t.string "key", limit: 255
t.string "label", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.string "data_type"
t.string "data_type", limit: 255
end
add_index "statistic_fields", ["statistic_index_id"], name: "index_statistic_fields_on_statistic_index_id", using: :btree
create_table "statistic_graphs", force: :cascade do |t|
t.integer "statistic_index_id"
t.string "chart_type"
t.string "chart_type", limit: 255
t.integer "limit"
t.datetime "created_at"
t.datetime "updated_at"
@ -614,17 +618,17 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "statistic_graphs", ["statistic_index_id"], name: "index_statistic_graphs_on_statistic_index_id", using: :btree
create_table "statistic_indices", force: :cascade do |t|
t.string "es_type_key"
t.string "label"
t.string "es_type_key", limit: 255
t.string "label", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "table", default: true
t.boolean "ca", default: true
t.boolean "table", default: true
t.boolean "ca", default: true
end
create_table "statistic_sub_types", force: :cascade do |t|
t.string "key"
t.string "label"
t.string "key", limit: 255
t.string "label", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
end
@ -641,8 +645,8 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "statistic_types", force: :cascade do |t|
t.integer "statistic_index_id"
t.string "key"
t.string "label"
t.string "key", limit: 255
t.string "label", limit: 255
t.boolean "graph"
t.datetime "created_at"
t.datetime "updated_at"
@ -660,7 +664,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
create_table "subscriptions", force: :cascade do |t|
t.integer "plan_id"
t.integer "user_id"
t.string "stp_subscription_id"
t.string "stp_subscription_id", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "expired_at"
@ -679,7 +683,7 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree
create_table "themes", force: :cascade do |t|
t.string "name", null: false
t.string "name", limit: 255, null: false
end
create_table "tickets", force: :cascade do |t|
@ -694,13 +698,14 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "tickets", ["reservation_id"], name: "index_tickets_on_reservation_id", using: :btree
create_table "trainings", force: :cascade do |t|
t.string "name"
t.string "name", limit: 255
t.datetime "created_at"
t.datetime "updated_at"
t.integer "nb_total_places"
t.string "slug"
t.string "slug", limit: 255
t.text "description"
t.boolean "public_page", default: true
t.boolean "public_page", default: true
t.boolean "disabled"
end
add_index "trainings", ["slug"], name: "index_trainings_on_slug", unique: true, using: :btree
@ -755,32 +760,32 @@ ActiveRecord::Schema.define(version: 20170906100906) do
add_index "user_trainings", ["user_id"], name: "index_user_trainings_on_user_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false
t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.string "current_sign_in_ip", limit: 255
t.string "last_sign_in_ip", limit: 255
t.string "confirmation_token", limit: 255
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token"
t.string "unconfirmed_email", limit: 255
t.integer "failed_attempts", default: 0, null: false
t.string "unlock_token", limit: 255
t.datetime "locked_at"
t.datetime "created_at"
t.datetime "updated_at"
t.boolean "is_allow_contact", default: true
t.boolean "is_allow_contact", default: true
t.integer "group_id"
t.string "stp_customer_id"
t.string "username"
t.string "slug"
t.boolean "is_active", default: true
t.boolean "invoicing_disabled", default: false
t.string "stp_customer_id", limit: 255
t.string "username", limit: 255
t.string "slug", limit: 255
t.boolean "is_active", default: true
t.boolean "invoicing_disabled", default: false
t.string "provider"
t.string "uid"
t.string "auth_token"