mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-19 13:54:25 +01:00
Merge branch 'xls' into dev
Conflicts: CHANGELOG.md app/helpers/application_helper.rb config/locales/en.yml config/locales/fr.yml
This commit is contained in:
commit
74154cf1f3
@ -20,6 +20,7 @@
|
||||
- Fix a bug: event category disappear when editing the event
|
||||
- [TODO DEPLOY] `rake fablab:es_add_event_filters`
|
||||
- [TODO DEPLOY] `rake db:migrate`
|
||||
- [TODO DEPLOY] `bundle install`
|
||||
|
||||
## v2.3.0 2016 June 28
|
||||
|
||||
|
5
Gemfile
5
Gemfile
@ -144,3 +144,8 @@ gem 'openlab_ruby'
|
||||
gem 'api-pagination'
|
||||
gem 'has_secure_token'
|
||||
gem 'apipie-rails'
|
||||
|
||||
# XLS files generation
|
||||
gem 'rubyzip', '~> 1.1.0'
|
||||
gem 'axlsx', '2.1.0.pre'
|
||||
gem 'axlsx_rails'
|
||||
|
12
Gemfile.lock
12
Gemfile.lock
@ -54,6 +54,13 @@ GEM
|
||||
descendants_tracker (~> 0.0.4)
|
||||
ice_nine (~> 0.11.0)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
axlsx (2.1.0.pre)
|
||||
htmlentities (~> 4.3.1)
|
||||
nokogiri (>= 1.4.1)
|
||||
rubyzip (~> 1.1.7)
|
||||
axlsx_rails (0.4.0)
|
||||
axlsx (>= 2.0.1)
|
||||
rails (>= 3.1)
|
||||
bcrypt (3.1.10)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
@ -174,6 +181,7 @@ GEM
|
||||
highline (1.7.1)
|
||||
hike (1.2.3)
|
||||
hitimes (1.2.2)
|
||||
htmlentities (4.3.4)
|
||||
http (0.6.4)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
http-cookie (1.0.2)
|
||||
@ -325,6 +333,7 @@ GEM
|
||||
netrc (~> 0.7)
|
||||
rolify (4.0.0)
|
||||
ruby-progressbar (1.7.5)
|
||||
rubyzip (1.1.7)
|
||||
rufus-scheduler (3.0.9)
|
||||
tzinfo
|
||||
rvm-capistrano (1.5.6)
|
||||
@ -440,6 +449,8 @@ DEPENDENCIES
|
||||
api-pagination
|
||||
apipie-rails
|
||||
awesome_print
|
||||
axlsx (= 2.1.0.pre)
|
||||
axlsx_rails
|
||||
bootstrap-sass
|
||||
byebug
|
||||
capistrano
|
||||
@ -488,6 +499,7 @@ DEPENDENCIES
|
||||
recurrence
|
||||
responders (~> 2.0)
|
||||
rolify
|
||||
rubyzip (~> 1.1.0)
|
||||
rvm-capistrano
|
||||
sass-rails (= 5.0.1)
|
||||
sdoc (~> 0.4.0)
|
||||
|
@ -531,6 +531,11 @@ See https://angular-ui.github.io/bootstrap/#uibdateparser-s-format-codes for a l
|
||||
|
||||
**BEWARE**: years format with less than 4 digits will result in problems because the system won't be able to distinct dates with the same less significant digits, eg. 50 could mean 1950 or 2050.
|
||||
|
||||
EXCEL_DATE_FORMAT
|
||||
|
||||
Date format for dates shown in exported Excel files (eg. statistics)
|
||||
See https://support.microsoft.com/en-us/kb/264372 for a list a available formats.
|
||||
|
||||
<a name="i18n-apply"></a>
|
||||
#### Applying changes
|
||||
|
||||
|
@ -142,3 +142,7 @@ config(['$httpProvider', 'AuthProvider', "growlProvider", "unsavedWarningsConfig
|
||||
}]).constant('angularMomentConfig', {
|
||||
timezone: Fablab.timezone
|
||||
});
|
||||
|
||||
angular.isUndefinedOrNull = function(val) {
|
||||
return angular.isUndefined(val) || val === null
|
||||
};
|
||||
|
@ -1,7 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
Application.Controllers.controller "StatisticsController", ["$scope", "$state", "$rootScope", "Statistics", "es", "Member", '_t', 'membersPromise', 'statisticsPromise'
|
||||
, ($scope, $state, $rootScope, Statistics, es, Member, _t, membersPromise, statisticsPromise) ->
|
||||
|
||||
|
||||
Application.Controllers.controller "StatisticsController", ["$scope", "$state", "$rootScope", '$uibModal', "Export", "es", "Member", '_t', 'membersPromise', 'statisticsPromise'
|
||||
, ($scope, $state, $rootScope, $uibModal, Export, es, Member, _t, membersPromise, statisticsPromise) ->
|
||||
|
||||
|
||||
|
||||
@ -56,6 +58,7 @@ Application.Controllers.controller "StatisticsController", ["$scope", "$state",
|
||||
## default: results are not sorted
|
||||
$scope.sorting =
|
||||
ca: 'none'
|
||||
date: 'desc'
|
||||
|
||||
## active tab will be set here
|
||||
$scope.selectedIndex = null
|
||||
@ -148,6 +151,7 @@ Application.Controllers.controller "StatisticsController", ["$scope", "$state",
|
||||
$scope.customFilter.value = null
|
||||
$scope.customFilter.exclude = false
|
||||
$scope.sorting.ca = 'none'
|
||||
$scope.sorting.date = 'desc'
|
||||
buildCustomFiltersList()
|
||||
refreshStats()
|
||||
|
||||
@ -271,6 +275,33 @@ Application.Controllers.controller "StatisticsController", ["$scope", "$state",
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Open a modal dialog asking the user for details about exporting the statistics tables to an excel file
|
||||
##
|
||||
$scope.exportToExcel = ->
|
||||
options =
|
||||
templateUrl: '<%= asset_path "admin/statistics/export.html" %>'
|
||||
size: 'sm'
|
||||
controller: 'ExportStatisticsController'
|
||||
resolve:
|
||||
dates: ->
|
||||
start: $scope.datePickerStart.selected
|
||||
end: $scope.datePickerEnd.selected
|
||||
query: ->
|
||||
custom = buildCustomFilterQuery()
|
||||
buildElasticDataQuery($scope.type.active.key, custom, $scope.agePicker.start, $scope.agePicker.end, moment($scope.datePickerStart.selected), moment($scope.datePickerEnd.selected), $scope.sorting)
|
||||
index: ->
|
||||
key: $scope.selectedIndex.es_type_key
|
||||
type: ->
|
||||
key: $scope.type.active.key
|
||||
|
||||
$uibModal.open options
|
||||
.result['finally'](null).then (info)->
|
||||
console.log(info)
|
||||
|
||||
|
||||
|
||||
|
||||
### PRIVATE SCOPE ###
|
||||
|
||||
##
|
||||
@ -308,12 +339,7 @@ Application.Controllers.controller "StatisticsController", ["$scope", "$state",
|
||||
$scope.sumStat = 0
|
||||
$scope.totalHits = null
|
||||
$scope.searchDate = new Date()
|
||||
custom = null
|
||||
if $scope.customFilter.criterion and $scope.customFilter.criterion.key and $scope.customFilter.value
|
||||
custom = {}
|
||||
custom.key = $scope.customFilter.criterion.key
|
||||
custom.value = $scope.customFilter.value
|
||||
custom.exclude = $scope.customFilter.exclude
|
||||
custom = buildCustomFilterQuery()
|
||||
queryElasticStats $scope.selectedIndex.es_type_key, $scope.type.active.key, custom, (res, err)->
|
||||
if (err)
|
||||
console.error("[statisticsController::refreshStats] Unable to refresh due to "+err)
|
||||
@ -485,8 +511,138 @@ Application.Controllers.controller "StatisticsController", ["$scope", "$state",
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Build and return an object according to the custom filter set by the user, used to request elasticsearch
|
||||
# @return {Object|null}
|
||||
##
|
||||
buildCustomFilterQuery = ->
|
||||
custom = null
|
||||
if !angular.isUndefinedOrNull($scope.customFilter.criterion) and
|
||||
!angular.isUndefinedOrNull($scope.customFilter.criterion.key) and
|
||||
!angular.isUndefinedOrNull($scope.customFilter.value)
|
||||
custom = {}
|
||||
custom.key = $scope.customFilter.criterion.key
|
||||
custom.value = $scope.customFilter.value
|
||||
custom.exclude = $scope.customFilter.exclude
|
||||
custom
|
||||
|
||||
|
||||
|
||||
# init the controller (call at the end !)
|
||||
initialize()
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
||||
Application.Controllers.controller 'ExportStatisticsController', [ '$scope', '$uibModalInstance', 'dates', 'query', 'index', 'type', 'CSRF'
|
||||
, ($scope, $uibModalInstance, dates, query, index, type, CSRF) ->
|
||||
|
||||
## Retrieve Anti-CSRF tokens from cookies
|
||||
CSRF.setMetaTags()
|
||||
|
||||
## Bindings for date range
|
||||
$scope.dates = dates
|
||||
|
||||
## Body of the query to export
|
||||
$scope.query = JSON.stringify(query)
|
||||
|
||||
## API URL where the form will be posted
|
||||
$scope.actionUrl = '/stats/'+index.key+'/export'
|
||||
|
||||
## Key of the current search' statistic type
|
||||
$scope.typeKey = type.key
|
||||
|
||||
## Form action on the above URL
|
||||
$scope.method = "post"
|
||||
|
||||
## Anti-CSRF token to inject into the download form
|
||||
$scope.csrfToken = angular.element('meta[name="csrf-token"]')[0].content
|
||||
|
||||
## Binding of the export type (global / current)
|
||||
$scope.export =
|
||||
type: 'current'
|
||||
|
||||
## datePicker parameters for interval beginning
|
||||
$scope.exportStart =
|
||||
format: Fablab.uibDateFormat
|
||||
opened: false # default: datePicker is not shown
|
||||
minDate: null
|
||||
maxDate: moment().subtract(1, 'day').toDate()
|
||||
options:
|
||||
startingDay: Fablab.weekStartingDay
|
||||
|
||||
## datePicker parameters for interval ending
|
||||
$scope.exportEnd =
|
||||
format: Fablab.uibDateFormat
|
||||
opened: false # default: datePicker is not shown
|
||||
minDate: null
|
||||
maxDate: moment().subtract(1, 'day').toDate()
|
||||
options:
|
||||
startingDay: Fablab.weekStartingDay
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback to open the datepicker (interval start)
|
||||
# @param $event {Object} jQuery event object
|
||||
##
|
||||
$scope.toggleStartDatePicker = ($event) ->
|
||||
$scope.exportStart.opened = !$scope.exportStart.opened
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback to open the datepicker (interval end)
|
||||
# @param $event {Object} jQuery event object
|
||||
##
|
||||
$scope.toggleEndDatePicker = ($event) ->
|
||||
$scope.exportEnd.opened = !$scope.exportEnd.opened
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback when exchanging the export type between 'global' and 'current view'
|
||||
# Adjust the query and the requesting url according to this type.
|
||||
##
|
||||
$scope.setRequest = ->
|
||||
if $scope.export.type == 'global'
|
||||
$scope.actionUrl = '/stats/global/export'
|
||||
$scope.query = JSON.stringify(
|
||||
"query":
|
||||
"bool":
|
||||
"must": [
|
||||
{
|
||||
"range":
|
||||
"date":
|
||||
"gte": moment($scope.dates.start).format()
|
||||
"lte": moment($scope.dates.end).format()
|
||||
}
|
||||
]
|
||||
)
|
||||
else
|
||||
$scope.actionUrl = '/stats/'+index.key+'/export'
|
||||
$scope.query = JSON.stringify(query)
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback to close the modal, telling the caller what is exported
|
||||
##
|
||||
$scope.exportData = ->
|
||||
info =
|
||||
type: $scope.export.type
|
||||
|
||||
if info.type == 'global'
|
||||
info.dates = $scope.dates
|
||||
|
||||
$uibModalInstance.close(info)
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback to cancel the export and close the modal
|
||||
##
|
||||
$scope.cancel = ->
|
||||
$uibModalInstance.dismiss('cancel')
|
||||
]
|
6
app/assets/javascripts/services/export.coffee
Normal file
6
app/assets/javascripts/services/export.coffee
Normal file
@ -0,0 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
Application.Services.factory 'Export', ["$http", ($http)->
|
||||
stats: (scope, query) ->
|
||||
$http.post('/stats/'+scope+'/export', query)
|
||||
]
|
@ -31,13 +31,13 @@
|
||||
<div class="col-md-12">
|
||||
<button type="button" class="btn btn-warning m-t m-b" ui-sref="app.admin.members_new" translate>{{ 'add_a_new_member' }}</button>
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-default" ng-href="api/members/export_members.xls" target="_blank">
|
||||
<a class="btn btn-default" ng-href="api/members/export_members.xlsx" target="_blank">
|
||||
<i class="fa fa-file-excel-o"></i> {{ 'members' | translate }}
|
||||
</a>
|
||||
<a class="btn btn-default" ng-href="api/members/export_subscriptions.xls" target="_blank" ng-if="!fablabWithoutPlans">
|
||||
<a class="btn btn-default" ng-href="api/members/export_subscriptions.xlsx" target="_blank" ng-if="!fablabWithoutPlans">
|
||||
<i class="fa fa-file-excel-o"></i> {{ 'subscriptions' | translate }}
|
||||
</a>
|
||||
<a class="btn btn-default" ng-href="api/members/export_reservations.xls" target="_blank">
|
||||
<a class="btn btn-default" ng-href="api/members/export_reservations.xlsx" target="_blank">
|
||||
<i class="fa fa-file-excel-o"></i> {{ 'reservations' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
|
76
app/assets/templates/admin/statistics/export.html.erb
Normal file
76
app/assets/templates/admin/statistics/export.html.erb
Normal file
@ -0,0 +1,76 @@
|
||||
<div class="modal-header">
|
||||
<img ng-src="{{logoBlack.custom_asset_file_attributes.attachment_url}}" alt="{{logo.custom_asset_file_attributes.attachment}}" class="modal-logo"/>
|
||||
<h1 translate>{{ 'export_statistics_to_excel' }}</h1>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="radio">
|
||||
<label><input type="radio" name="scope" ng-model="export.type" value="global" ng-change="setRequest()">{{ 'export_all_statistics' | translate }}</label>
|
||||
</div>
|
||||
<div ng-show="export.type == 'global'">
|
||||
<ul class="list-unstyled">
|
||||
<li class="row">
|
||||
<span class="col-md-4" translate>{{ 'start' }}</span>
|
||||
<div class="input-group black col-md-7 m-r" id="date_pick_start">
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
uib-datepicker-popup="{{exportEnd.format}}"
|
||||
ng-model="dates.start"
|
||||
name="startDate"
|
||||
is-open="exportStart.opened"
|
||||
min-date="exportStart.minDate"
|
||||
max-date="exportStart.maxDate"
|
||||
datepicker-options="exportStart.options"
|
||||
show-button-bar="false"
|
||||
placeholder="{{ 'start' | translate }}"
|
||||
ng-click="toggleStartDatePicker($event)"
|
||||
ng-change="setRequest()"
|
||||
required="required"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" class="btn btn-default btn-search-datepicker" ng-click="toggleStartDatePicker($event)">
|
||||
<i class="glyphicon glyphicon-calendar"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="row">
|
||||
<span class="col-md-4" translate>{{ 'end' }}</span>
|
||||
<div class="input-group black col-md-7 m-r" id="date_pick_end">
|
||||
<input type="text"
|
||||
class="form-control"
|
||||
uib-datepicker-popup="{{exportEnd.format}}"
|
||||
ng-model="dates.end"
|
||||
name="endDate"
|
||||
is-open="exportEnd.opened"
|
||||
min-date="exportEnd.minDate"
|
||||
max-date="exportEnd.maxDate"
|
||||
datepicker-options="datePickerEnd.options"
|
||||
show-button-bar="false"
|
||||
placeholder="{{ 'end' | translate }}"
|
||||
ng-click="toggleEndDatePicker($event)"
|
||||
ng-change="setRequest()"
|
||||
required="required"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" class="btn btn-default btn-search-datepicker" ng-click="toggleEndDatePicker($event)">
|
||||
<i class="glyphicon glyphicon-calendar"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label><input type="radio" name="scope" ng-model="export.type" value="current" ng-change="setRequest()">{{ 'export_the_current_search_results' | translate }}</label>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<form role=form" ng-submit="exportData()" name="exportForm" method="post" action="{{ actionUrl }}" class="inline">
|
||||
<input name="authenticity_token" type="hidden" ng-value="csrfToken"/>
|
||||
<input name="_method" type="hidden" ng-value="method"/>
|
||||
<input name="type_key" type="hidden" ng-value="typeKey"/>
|
||||
<input name="body" type="hidden" ng-value="query"/>
|
||||
<input type="submit" class="btn btn-info" value="{{ 'export' | translate }}" formtarget="_blank"/>
|
||||
</form>
|
||||
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'cancel' }}</button>
|
||||
</div>
|
@ -12,6 +12,7 @@
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-12 col-md-3 b-t hide-b-md">
|
||||
<section class="heading-actions wrapper">
|
||||
<a class="btn btn-lg btn-default rounded m-t-sm text-sm" ng-click="exportToExcel()"><i class="fa fa-file-excel-o"></i></a>
|
||||
<a class="btn btn-lg btn-warning bg-white b-2x rounded m-t-sm upper text-sm" ui-sref="app.admin.stats_graphs" role="button"><i class="fa fa-line-chart"></i> {{ 'evolution' | translate }}</a>
|
||||
</section>
|
||||
</div>
|
||||
@ -287,4 +288,3 @@
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@ -91,30 +91,24 @@ class API::MembersController < API::ApiController
|
||||
# export subscriptions
|
||||
def export_subscriptions
|
||||
authorize :export
|
||||
@datas = Subscription.includes(:plan, :user).all
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.xls
|
||||
end
|
||||
@subscriptions = Subscription.all.includes(:plan, :user => [:profile])
|
||||
|
||||
render xlsx: 'export_subscriptions.xlsx', filename: "export_subscriptions.xlsx"
|
||||
end
|
||||
|
||||
# export reservations
|
||||
def export_reservations
|
||||
authorize :export
|
||||
@datas = Reservation.includes(:user, :slots).all
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.xls
|
||||
end
|
||||
@reservations = Reservation.all.includes(:slots, :reservable, :user => [:profile])
|
||||
|
||||
render xlsx: 'export_reservations.xlsx', filename: "export_reservations.xlsx"
|
||||
end
|
||||
|
||||
def export_members
|
||||
authorize :export
|
||||
@datas = User.with_role(:member).includes(:group, :subscriptions, :profile)
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.xls
|
||||
end
|
||||
@members = User.with_role(:member).includes(:group, :trainings, :tags, :invoices, :projects, :subscriptions => [:plan], :profile => [:address])
|
||||
|
||||
render xlsx: 'export_members.xlsx', filename: "export_members.xlsx"
|
||||
end
|
||||
|
||||
def merge
|
||||
|
@ -14,9 +14,56 @@ class API::StatisticsController < API::ApiController
|
||||
results = Stats::#{path.classify}.search(query, request.query_parameters.symbolize_keys).response
|
||||
render json: results
|
||||
end
|
||||
|
||||
def export_#{path}
|
||||
authorize :statistic, :export_#{path}?
|
||||
|
||||
query = MultiJson.load(params[:body])
|
||||
type_key = params[:type_key]
|
||||
|
||||
@results = Elasticsearch::Model.client.search({index: 'stats', type: '#{path}', scroll: '30s', body: query})
|
||||
scroll_id = @results['_scroll_id']
|
||||
while @results['hits']['hits'].size != @results['hits']['total']
|
||||
scroll_res = Elasticsearch::Model.client.scroll(scroll: '30s', scroll_id: scroll_id)
|
||||
@results['hits']['hits'].concat(scroll_res['hits']['hits'])
|
||||
scroll_id = scroll_res['_scroll_id']
|
||||
end
|
||||
|
||||
ids = @results['hits']['hits'].map { |u| u['_source']['userId'] }
|
||||
@users = User.includes(:profile).where(:id => ids)
|
||||
|
||||
@index = StatisticIndex.find_by(es_type_key: '#{path}')
|
||||
@type = StatisticType.find_by(key: type_key, statistic_index_id: @index.id)
|
||||
@subtypes = @type.statistic_sub_types
|
||||
@fields = @index.statistic_fields
|
||||
|
||||
render xlsx: 'export_current.xlsx', filename: "#{path}.xlsx"
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def export_global
|
||||
authorize :statistic, :export_global?
|
||||
|
||||
# query all stats with range arguments
|
||||
query = MultiJson.load(params[:body])
|
||||
|
||||
@results = Elasticsearch::Model.client.search({index: 'stats', scroll: '30s', body: query})
|
||||
scroll_id = @results['_scroll_id']
|
||||
while @results['hits']['hits'].size != @results['hits']['total']
|
||||
scroll_res = Elasticsearch::Model.client.scroll(scroll: '30s', scroll_id: scroll_id)
|
||||
@results['hits']['hits'].concat(scroll_res['hits']['hits'])
|
||||
scroll_id = scroll_res['_scroll_id']
|
||||
end
|
||||
|
||||
ids = @results['hits']['hits'].map { |u| u['_source']['userId'] }
|
||||
@users = User.includes(:profile).where(:id => ids)
|
||||
|
||||
@indices = StatisticIndex.all.includes(:statistic_fields, :statistic_types => [:statistic_sub_types])
|
||||
|
||||
render xlsx: 'export_global.xlsx', filename: "statistics.xlsx"
|
||||
end
|
||||
|
||||
def scroll
|
||||
authorize :statistic, :scroll?
|
||||
|
||||
|
@ -56,6 +56,23 @@ module ApplicationHelper
|
||||
amount / 100.00
|
||||
end
|
||||
|
||||
##
|
||||
# Retrieve an item in the given array of items
|
||||
# by default, the "id" is expected to match the given parameter but
|
||||
# this can be overridden by passing a third parameter to specify the
|
||||
# property to match
|
||||
##
|
||||
def get_item(array, id, key = nil)
|
||||
array.each do |i|
|
||||
if key.nil?
|
||||
return i if i.id == id
|
||||
else
|
||||
return i if i[key] == id
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
## inspired by gems/actionview-4.2.5/lib/action_view/helpers/translation_helper.rb
|
||||
|
@ -1,5 +1,6 @@
|
||||
class StatisticPolicy < ApplicationPolicy
|
||||
%w(index account event machine project subscription training user scroll).each do |action|
|
||||
%w(index account event machine project subscription training user scroll export_subscription export_machine
|
||||
export_training export_event export_account export_project export_global).each do |action|
|
||||
define_method "#{action}?" do
|
||||
user.is_admin?
|
||||
end
|
||||
|
@ -1,30 +0,0 @@
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th><%=t('export_members.id')%></th>
|
||||
<th><%=t('export_members.surname')%></th>
|
||||
<th><%=t('export_members.first_name')%></th>
|
||||
<th><%=t('export_members.email')%></th>
|
||||
<th><%=t('export_members.gender')%></th>
|
||||
<th><%=t('export_members.age')%></th>
|
||||
<th><%=t('export_members.phone')%></th>
|
||||
<th><%=t('export_members.group')%></th>
|
||||
<th><%=t('export_members.subscription')%></th>
|
||||
<th><%=t('export_members.subscription_end_date')%></th>
|
||||
<th><%=t('export_members.validated_trainings')%></th>
|
||||
</tr>
|
||||
<% @datas.each do |data| %>
|
||||
<tr>
|
||||
<td><%= data.id %></td>
|
||||
<td><%= data.profile.last_name %></td>
|
||||
<td><%= data.profile.first_name %></td>
|
||||
<td><%= data.email %></td>
|
||||
<td><%= data.profile.gender ? t('export_members.man') : t('export_members.woman') %></td>
|
||||
<td><%= data.profile.age %></td>
|
||||
<td><%= data.profile.phone %></td>
|
||||
<td><%= data.group.name %></td>
|
||||
<td><%= (data.subscription and data.subscription.expired_at > Time.now) ? data.subscription.plan.name : t('export_members.without_subscriptions') %></td>
|
||||
<td><%= (data.subscription and data.subscription.expired_at > Time.now) ? data.subscription.expired_at : '' %></td>
|
||||
<td><%= raw data.trainings.map(&:name).join(' ') %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
53
app/views/api/members/export_members.xlsx.axlsx
Normal file
53
app/views/api/members/export_members.xlsx.axlsx
Normal file
@ -0,0 +1,53 @@
|
||||
wb = xlsx_package.workbook
|
||||
|
||||
header = wb.styles.add_style :b => true, :bg_color => Stylesheet.primary.upcase.gsub('#', 'FF'), :fg_color => 'FFFFFFFF'
|
||||
date = wb.styles.add_style :format_code => Rails.application.secrets.excel_date_format
|
||||
|
||||
wb.add_worksheet(name: t('export_members.members')) do |sheet|
|
||||
|
||||
## data table
|
||||
# heading labels
|
||||
columns = [t('export_members.id'), t('export_members.surname'), t('export_members.first_name'), t('export_members.email'),
|
||||
t('export_members.gender'), t('export_members.age'), t('export_members.address'), t('export_members.phone'),
|
||||
t('export_members.website'), t('export_members.job'), t('export_members.interests'),
|
||||
t('export_members.cad_software_mastered'), t('export_members.group'), t('export_members.subscription'),
|
||||
t('export_members.subscription_end_date'), t('export_members.validated_trainings'), t('export_members.tags'),
|
||||
t('export_members.number_of_invoices'), t('export_members.projects'), t('export_members.facebook'),
|
||||
t('export_members.twitter'), t('export_members.echo_sciences')]
|
||||
sheet.add_row columns, :style => header
|
||||
|
||||
# data rows
|
||||
@members.each do |member|
|
||||
data = [
|
||||
member.id, member.profile.last_name, member.profile.first_name,
|
||||
member.email, member.profile.gender ? t('export_members.man') : t('export_members.woman'), member.profile.age,
|
||||
member.profile.address ? member.profile.address.address : '', member.profile.phone, member.profile.website,
|
||||
member.profile.job, member.profile.interest, member.profile.software_mastered, member.group.name,
|
||||
(member.subscription and member.subscription.expired_at > Time.now) ? member.subscription.plan.name : t('export_members.without_subscriptions'),
|
||||
(member.subscription and member.subscription.expired_at > Time.now) ? member.subscription.expired_at.to_date : nil,
|
||||
member.trainings.map(&:name).join("\n"), member.tags.map(&:name).join("\n"), member.invoices.size,
|
||||
member.projects.map(&:name).join("\n"), member.profile.facebook || '', member.profile.twitter || '',
|
||||
member.profile.echosciences || ''
|
||||
]
|
||||
styles = [nil, nil, nil,
|
||||
nil, nil, nil,
|
||||
nil, nil, nil,
|
||||
nil, nil, nil, nil,
|
||||
nil,
|
||||
date,
|
||||
nil, nil, nil,
|
||||
nil, nil, nil,
|
||||
nil]
|
||||
types = [:integer, :string, :string,
|
||||
:string, :string, :integer,
|
||||
:string, :string, :string,
|
||||
:string, :string, :string, :string,
|
||||
:string,
|
||||
:date,
|
||||
:string, :string, :integer,
|
||||
:string, :string, :string,
|
||||
:string]
|
||||
|
||||
sheet.add_row data, :style => styles, :types => types
|
||||
end
|
||||
end
|
@ -1,24 +0,0 @@
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th><%=t('export_reservations.customer_id')%></th>
|
||||
<th><%=t('export_reservations.customer')%></th>
|
||||
<th><%=t('export_reservations.email')%></th>
|
||||
<th><%=t('export_reservations.reservation_date')%></th>
|
||||
<th><%=t('export_reservations.reservation_type')%></th>
|
||||
<th><%=t('export_reservations.reservation_object')%></th>
|
||||
<th><%=t('export_reservations.slots_number_hours_tickets')%></th>
|
||||
|
||||
</tr>
|
||||
<% @datas.each do |d| %>
|
||||
<tr>
|
||||
<td><%= d.user.id %></td>
|
||||
<td><%= d.user.profile.full_name %></td>
|
||||
<td><%= d.user.email %></td>
|
||||
<td><%= d.created_at %></td>
|
||||
<td><%= d.reservable_type %></td>
|
||||
<td><%= d.reservable.name if !d.reservable.nil? %></td>
|
||||
<td><%= d.slots.count %></td>
|
||||
<td><%= (d.stp_invoice_id.nil?)? t('export_reservations.local_payment') : t('export_reservations.online_payment') %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
32
app/views/api/members/export_reservations.xlsx.axlsx
Normal file
32
app/views/api/members/export_reservations.xlsx.axlsx
Normal file
@ -0,0 +1,32 @@
|
||||
wb = xlsx_package.workbook
|
||||
|
||||
header = wb.styles.add_style :b => true, :bg_color => Stylesheet.primary.upcase.gsub('#', 'FF'), :fg_color => 'FFFFFFFF'
|
||||
date = wb.styles.add_style :format_code => Rails.application.secrets.excel_date_format
|
||||
|
||||
wb.add_worksheet(name: t('export_reservations.reservations')) do |sheet|
|
||||
|
||||
## data table
|
||||
# heading labels
|
||||
columns = [t('export_reservations.customer_id'), t('export_reservations.customer'), t('export_reservations.email'),
|
||||
t('export_reservations.reservation_date'), t('export_reservations.reservation_type'), t('export_reservations.reservation_object'),
|
||||
t('export_reservations.slots_number_hours_tickets'), t('export_reservations.payment_method')]
|
||||
sheet.add_row columns, :style => header
|
||||
|
||||
# data rows
|
||||
@reservations.each do |resrv|
|
||||
data = [
|
||||
resrv.user.id,
|
||||
resrv.user.profile.full_name,
|
||||
resrv.user.email,
|
||||
resrv.created_at.to_date,
|
||||
resrv.reservable_type,
|
||||
(resrv.reservable.nil? ? '' : resrv.reservable.name),
|
||||
resrv.slots.count,
|
||||
(resrv.stp_invoice_id.nil?)? t('export_reservations.local_payment') : t('export_reservations.online_payment')
|
||||
]
|
||||
styles = [nil, nil, nil, date, nil, nil, nil, nil]
|
||||
types = [:integer, :string, :string, :date, :string, :string, :integer, :string]
|
||||
|
||||
sheet.add_row data, :style => styles, :types => types
|
||||
end
|
||||
end
|
@ -1,26 +0,0 @@
|
||||
<table border="1">
|
||||
<tr>
|
||||
<th><%=t('export_subscriptions.id')%></th>
|
||||
<th><%=t('export_subscriptions.customer')%></th>
|
||||
<th><%=t('export_subscriptions.email')%></th>
|
||||
<th><%=t('export_subscriptions.subscription')%></th>
|
||||
<th><%=t('export_subscriptions.period')%></th>
|
||||
<th><%=t('export_subscriptions.start_date')%></th>
|
||||
<th><%=t('export_subscriptions.expiration_date')%></th>
|
||||
<th><%=t('export_subscriptions.amount')%></th>
|
||||
<th><%=t('export_subscriptions.payment_method')%></th>
|
||||
</tr>
|
||||
<% @datas.each do |data| %>
|
||||
<tr>
|
||||
<td><%= data.user.id %></td>
|
||||
<td><%= data.user.profile.full_name %></td>
|
||||
<td><%= data.user.email %></td>
|
||||
<td><%= data.plan.human_readable_name(group: true) %></td>
|
||||
<td><%= t("duration.#{data.plan.interval}", count: data.plan.interval_count) %></td>
|
||||
<td><%= data.created_at %></td>
|
||||
<td><%= data.expired_at %></td>
|
||||
<td><%= number_to_currency(data.plan.amount / 100) %></td>
|
||||
<td><%= (data.stp_subscription_id.nil?)? t('export_subscriptions.local_payment') : t('export_subscriptions.online_payment') %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
33
app/views/api/members/export_subscriptions.xlsx.axlsx
Normal file
33
app/views/api/members/export_subscriptions.xlsx.axlsx
Normal file
@ -0,0 +1,33 @@
|
||||
wb = xlsx_package.workbook
|
||||
|
||||
header = wb.styles.add_style :b => true, :bg_color => Stylesheet.primary.upcase.gsub('#', 'FF'), :fg_color => 'FFFFFFFF'
|
||||
date = wb.styles.add_style :format_code => Rails.application.secrets.excel_date_format
|
||||
|
||||
wb.add_worksheet(name: t('export_subscriptions.subscriptions')) do |sheet|
|
||||
|
||||
## data table
|
||||
# heading labels
|
||||
columns = [t('export_subscriptions.id'), t('export_subscriptions.customer'), t('export_subscriptions.email'),
|
||||
t('export_subscriptions.subscription'), t('export_subscriptions.period'), t('export_subscriptions.start_date'),
|
||||
t('export_subscriptions.expiration_date'), t('export_subscriptions.amount'), t('export_subscriptions.payment_method')]
|
||||
sheet.add_row columns, :style => header
|
||||
|
||||
# data rows
|
||||
@subscriptions.each do |sub|
|
||||
data = [
|
||||
sub.user.id,
|
||||
sub.user.profile.full_name,
|
||||
sub.user.email,
|
||||
sub.plan.human_readable_name(group: true),
|
||||
t("duration.#{sub.plan.interval}", count: sub.plan.interval_count),
|
||||
sub.created_at.to_date,
|
||||
sub.expired_at.to_date,
|
||||
number_to_currency(sub.plan.amount / 100),
|
||||
(sub.stp_subscription_id.nil?)? t('export_subscriptions.local_payment') : t('export_subscriptions.online_payment')
|
||||
]
|
||||
styles = [nil, nil, nil, nil, nil, date, date, nil, nil]
|
||||
types = [:integer, :string, :string, :string, :string, :date, :date, :string, :string]
|
||||
|
||||
sheet.add_row data, :style => styles, :types => types
|
||||
end
|
||||
end
|
79
app/views/api/statistics/export_current.xlsx.axlsx
Normal file
79
app/views/api/statistics/export_current.xlsx.axlsx
Normal file
@ -0,0 +1,79 @@
|
||||
wb = xlsx_package.workbook
|
||||
|
||||
bold = wb.styles.add_style :b => true
|
||||
header = wb.styles.add_style :b => true, :bg_color => Stylesheet.primary.upcase.gsub('#', 'FF'), :fg_color => 'FFFFFFFF'
|
||||
date = wb.styles.add_style :format_code => Rails.application.secrets.excel_date_format
|
||||
|
||||
wb.add_worksheet(name: @index.label) do |sheet|
|
||||
## heading stats for the current page
|
||||
sheet.add_row [t('export.entries'), @results['hits']['total']], :style => [bold, nil], :types => [:string, :integer]
|
||||
if @index.ca
|
||||
sheet.add_row [t('export.revenue'), @results['aggregations']['total_ca']['value']], :style => [bold, nil], :types => [:string, :float]
|
||||
end
|
||||
sheet.add_row [t('export.average_age'), @results['aggregations']['average_age']['value']], :style => [bold, nil], :types => [:string, :float]
|
||||
unless @type.simple
|
||||
sheet.add_row ["#{t('export.total')} #{@type.label}", @results['aggregations']['total_stat']['value']], :style => [bold, nil], :types => [:string, :integer]
|
||||
end
|
||||
sheet.add_row []
|
||||
|
||||
## data table
|
||||
# heading labels
|
||||
columns = [t('export.date'), t('export.user'), t('export.email'), t('export.phone'), t('export.gender'), t('export.age'), t('export.type')]
|
||||
columns.push @type.label unless @type.simple
|
||||
@fields.each do |f|
|
||||
columns.push f.label
|
||||
end
|
||||
columns.push t('export.revenue') if @index.ca
|
||||
sheet.add_row columns, :style => header
|
||||
|
||||
# data rows
|
||||
@results['hits']['hits'].each do |hit|
|
||||
user = get_item(@users, hit['_source']['userId'])
|
||||
subtype = get_item(@subtypes, hit['_source']['subType'], 'key')
|
||||
data = [
|
||||
Date::strptime(hit['_source']['date'],'%Y-%m-%d'),
|
||||
(user ? user.profile.full_name : "ID #{hit['_source']['userId']}"),
|
||||
(user ? user.email : ''),
|
||||
(user ? user.profile.phone : ''),
|
||||
t("export.#{hit['_source']['gender']}"),
|
||||
hit['_source']['age'],
|
||||
subtype.nil? ? "" : subtype.label
|
||||
]
|
||||
styles = [date, nil, nil, nil, nil, nil, nil]
|
||||
types = [:date, :string, :string, :string, :string, :integer, :string]
|
||||
unless @type.simple
|
||||
data.push hit['_source']['stat']
|
||||
styles.push nil
|
||||
types.push :string
|
||||
end
|
||||
@fields.each do |f|
|
||||
field_data = hit['_source'][f.key]
|
||||
case f.data_type
|
||||
when 'date'
|
||||
data.push Date::strptime(field_data, '%Y-%m-%d')
|
||||
styles.push date
|
||||
types.push :date
|
||||
when 'list'
|
||||
data.push field_data.map{|e| e['name'] }.join(', ')
|
||||
styles.push nil
|
||||
types.push :string
|
||||
when 'number'
|
||||
data.push field_data
|
||||
styles.push nil
|
||||
types.push :float
|
||||
else
|
||||
data.push field_data
|
||||
styles.push nil
|
||||
types.push :string
|
||||
end
|
||||
|
||||
end
|
||||
if @index.ca
|
||||
data.push hit['_source']['ca']
|
||||
styles.push nil
|
||||
types.push :float
|
||||
end
|
||||
|
||||
sheet.add_row data, :style => styles, :types => types
|
||||
end
|
||||
end
|
84
app/views/api/statistics/export_global.xlsx.axlsx
Normal file
84
app/views/api/statistics/export_global.xlsx.axlsx
Normal file
@ -0,0 +1,84 @@
|
||||
wb = xlsx_package.workbook
|
||||
|
||||
header = wb.styles.add_style :b => true, :bg_color => Stylesheet.primary.upcase.gsub('#', 'FF'), :fg_color => 'FFFFFFFF'
|
||||
date = wb.styles.add_style :format_code => Rails.application.secrets.excel_date_format
|
||||
|
||||
@indices.each do |index|
|
||||
if index.table
|
||||
index.statistic_types.each do |type|
|
||||
# see https://msdn.microsoft.com/fr-fr/library/c6bdca6y(v=vs.90).aspx for unauthorized character list
|
||||
sheet_name = "#{index.label} - #{type.label}".gsub(/[*|\\:"<>?\/]/,'').truncate(31)
|
||||
wb.add_worksheet(name: sheet_name) do |sheet|
|
||||
|
||||
## data table
|
||||
# heading labels
|
||||
columns = [t('export.date'), t('export.user'), t('export.email'), t('export.phone'), t('export.gender'), t('export.age'), t('export.type')]
|
||||
columns.push type.label unless type.simple
|
||||
index.statistic_fields.each do |f|
|
||||
columns.push f.label
|
||||
end
|
||||
columns.push t('export.revenue') if index.ca
|
||||
sheet.add_row columns, :style => header
|
||||
|
||||
# data rows
|
||||
@results['hits']['hits'].each do |hit|
|
||||
# check that the current result is for the given index and type
|
||||
if hit['_type'] == index.es_type_key and hit['_source']['type'] == type.key
|
||||
# get matching objects
|
||||
user = get_item(@users, hit['_source']['userId'])
|
||||
subtype = get_item(type.statistic_sub_types, hit['_source']['subType'], 'key')
|
||||
# start to fill data and associated styles and data-types
|
||||
data = [
|
||||
Date::strptime(hit['_source']['date'],'%Y-%m-%d'),
|
||||
(user ? user.profile.full_name : "ID #{hit['_source']['userId']}"),
|
||||
(user ? user.email : ''),
|
||||
(user ? user.profile.phone : ''),
|
||||
t("export.#{hit['_source']['gender']}"),
|
||||
hit['_source']['age'],
|
||||
subtype.nil? ? "" : subtype.label
|
||||
]
|
||||
styles = [date, nil, nil, nil, nil, nil, nil]
|
||||
types = [:date, :string, :string, :string, :string, :integer, :string]
|
||||
# do not proceed with the 'stat' field if the type is declared as 'simple'
|
||||
unless type.simple
|
||||
data.push hit['_source']['stat']
|
||||
styles.push nil
|
||||
types.push :string
|
||||
end
|
||||
# proceed additional fields
|
||||
index.statistic_fields.each do |f|
|
||||
field_data = hit['_source'][f.key]
|
||||
case f.data_type
|
||||
when 'date'
|
||||
data.push Date::strptime(field_data, '%Y-%m-%d')
|
||||
styles.push date
|
||||
types.push :date
|
||||
when 'list'
|
||||
data.push field_data.map{|e| e['name'] }.join(', ')
|
||||
styles.push nil
|
||||
types.push :string
|
||||
when 'number'
|
||||
data.push field_data
|
||||
styles.push nil
|
||||
types.push :float
|
||||
else
|
||||
data.push field_data
|
||||
styles.push nil
|
||||
types.push :string
|
||||
end
|
||||
|
||||
end
|
||||
# proceed teh 'ca' field if requested
|
||||
if index.ca
|
||||
data.push hit['_source']['ca']
|
||||
styles.push nil
|
||||
types.push :float
|
||||
end
|
||||
# finally, add the data row to the workbook's sheet
|
||||
sheet.add_row data, :style => styles, :types => types
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -47,6 +47,7 @@ TIME_ZONE: 'Paris'
|
||||
WEEK_STARTING_DAY: 'monday'
|
||||
D3_DATE_FORMAT: '%d/%m/%y'
|
||||
UIB_DATE_FORMAT: 'dd/MM/yyyy'
|
||||
EXCEL_DATE_FORMAT: 'dd/mm/yyyy'
|
||||
|
||||
OPENLAB_APP_SECRET:
|
||||
OPENLAB_APP_ID:
|
||||
|
@ -405,7 +405,10 @@ en:
|
||||
unknown: "Unknown"
|
||||
user_id: "User ID"
|
||||
display_more_results: "Display more results"
|
||||
|
||||
export_statistics_to_excel: "Export statistics to Excel"
|
||||
export_all_statistics: "Export all statistics"
|
||||
export_the_current_search_results: "Export the current search results"
|
||||
export: "Export"
|
||||
|
||||
stats_graphs:
|
||||
# statistics graphs
|
||||
|
@ -405,7 +405,10 @@ fr:
|
||||
unknown: "Inconnu"
|
||||
user_id: "ID Utilisateur"
|
||||
display_more_results: "Afficher plus de résultats"
|
||||
|
||||
export_statistics_to_excel: "Exporter les statistiques vers Excel"
|
||||
export_all_statistics: "Exporter toutes les statistiques"
|
||||
export_the_current_search_results: "Exporter les résultats de la recherche courante"
|
||||
export: "Exporter"
|
||||
|
||||
stats_graphs:
|
||||
# graphiques de statistiques
|
||||
|
@ -116,23 +116,36 @@ en:
|
||||
|
||||
export_members:
|
||||
# members list export to EXCEL format
|
||||
members: "Members"
|
||||
id: "ID"
|
||||
surname: "Surname"
|
||||
first_name: "First name"
|
||||
email: "E-mail"
|
||||
gender: "Gender"
|
||||
age: "Age"
|
||||
address: "Address"
|
||||
phone: "Phone"
|
||||
website: "Website"
|
||||
job: "Job"
|
||||
interests: "Interests"
|
||||
cad_software_mastered: "CAD Softwares mastered"
|
||||
group: "Group"
|
||||
subscription: "Subscription"
|
||||
subscription_end_date: "Subscription end date"
|
||||
validated_trainings: "Validated trainings"
|
||||
tags: "Tags"
|
||||
number_of_invoices: "Number of invoices"
|
||||
projects: "Projects"
|
||||
facebook: "Facebook"
|
||||
twitter: "Twitter"
|
||||
echo_sciences: "Echosciences"
|
||||
man: "Man"
|
||||
woman: "Woman"
|
||||
without_subscriptions: "Without subscriptions"
|
||||
|
||||
export_reservations:
|
||||
# machines/trainings/events reservations list to EXCEL format
|
||||
reservations: "Reservations"
|
||||
customer_id: "Customer ID"
|
||||
customer: "Customer"
|
||||
email: "E-mail"
|
||||
@ -146,6 +159,7 @@ en:
|
||||
|
||||
export_subscriptions:
|
||||
# subscriptions list export to EXCEL format
|
||||
subscriptions: "Subscriptions"
|
||||
id: "ID"
|
||||
customer: "Customer"
|
||||
email: "E-mail"
|
||||
@ -263,3 +277,20 @@ en:
|
||||
revenue: "Revenue"
|
||||
account_creation: "Account creation"
|
||||
project_publication: "Project publication"
|
||||
|
||||
export:
|
||||
# statistics exports to the excel file format
|
||||
entries: "Entries"
|
||||
revenue: "Revenue"
|
||||
average_age: "Average Age"
|
||||
total: "Total"
|
||||
date: "Date"
|
||||
user: "User"
|
||||
email: "Email"
|
||||
phone: "Phone"
|
||||
gender: "Gender"
|
||||
age: "Age"
|
||||
type: "Type"
|
||||
revenue: "Revenue"
|
||||
male: "Man"
|
||||
female: "Woman"
|
@ -116,23 +116,36 @@ fr:
|
||||
|
||||
export_members:
|
||||
# export de la liste des members au format EXCEL
|
||||
members: "Membres"
|
||||
id: "ID"
|
||||
surname: "Nom"
|
||||
first_name: "Prénom"
|
||||
email: "Courriel"
|
||||
gender: "Genre"
|
||||
age: "Âge"
|
||||
address: "Adresse"
|
||||
phone: "Tel."
|
||||
website: "Site web"
|
||||
job: "Profession"
|
||||
interests: "Centres d'intérêts"
|
||||
cad_software_mastered: "Logiciels de conception maîtrisés"
|
||||
group: "Groupe"
|
||||
subscription: "Abonnement"
|
||||
subscription_end_date: "Date de fin de l'abonnement"
|
||||
validated_trainings: "Formations validées"
|
||||
tags: "Étiquettes"
|
||||
number_of_invoices: "Nombre de factures"
|
||||
projects: "Projets"
|
||||
facebook: "Facebook"
|
||||
twitter: "Twitter"
|
||||
echo_sciences: "Echosciences"
|
||||
man: "Homme"
|
||||
woman: "Femme"
|
||||
without_subscriptions: "Sans Abonnement"
|
||||
|
||||
export_reservations:
|
||||
# export de la liste des réservations machines/formations/évènements au format EXCEL
|
||||
reservations: "Réservations"
|
||||
customer_id: "ID client"
|
||||
customer: "Client"
|
||||
email: "Courriel"
|
||||
@ -146,6 +159,7 @@ fr:
|
||||
|
||||
export_subscriptions:
|
||||
# export de la liste des abonnements au format EXCEL
|
||||
subscriptions: "Abonnements"
|
||||
id: "ID"
|
||||
customer: "Client"
|
||||
email: "Courriel"
|
||||
@ -263,3 +277,20 @@ fr:
|
||||
revenue: "Chiffre d'affaires"
|
||||
account_creation: "Création de compte"
|
||||
project_publication: "Publication de projet"
|
||||
|
||||
export:
|
||||
# export des statistiques au format excel
|
||||
entries: "Entrées"
|
||||
revenue: "Chiffre d'affaires"
|
||||
average_age: "Âge moyen"
|
||||
total: "Total"
|
||||
date: "Date"
|
||||
user: "Utilisateur"
|
||||
email: "Courriel"
|
||||
phone: "Téléphone"
|
||||
gender: "Genre"
|
||||
age: "Âge"
|
||||
type: "Type"
|
||||
revenue: "Chiffre d'affaires"
|
||||
male: "Homme"
|
||||
female: "Femme"
|
@ -137,7 +137,9 @@ Rails.application.routes.draw do
|
||||
|
||||
%w(account event machine project subscription training user).each do |path|
|
||||
post "/stats/#{path}/_search", to: "api/statistics##{path}"
|
||||
post "/stats/#{path}/export", to: "api/statistics#export_#{path}"
|
||||
end
|
||||
post '/stats/global/export', to: "api/statistics#export_global"
|
||||
post '_search/scroll', to: "api/statistics#scroll"
|
||||
|
||||
match '/project_collaborator/:valid_token', to: 'api/projects#collaborator_valid', via: :get
|
||||
|
@ -21,6 +21,7 @@ development:
|
||||
week_starting_day: <%= ENV["WEEK_STARTING_DAY"] %>
|
||||
d3_date_format: <%= ENV["D3_DATE_FORMAT"].dump %> # .dump is needed as the value may start by a '%', see https://github.com/tenderlove/psych/issues/75
|
||||
uib_date_format: <%= ENV["UIB_DATE_FORMAT"] %>
|
||||
excel_date_format: <%= ENV["EXCEL_DATE_FORMAT"]%>
|
||||
rails_locale: <%= ENV["RAILS_LOCALE"] %>
|
||||
moment_locale: <%= ENV["MOMENT_LOCALE"] %>
|
||||
summernote_locale: <%= ENV["SUMMERNOTE_LOCALE"] %>
|
||||
@ -46,6 +47,7 @@ test:
|
||||
week_starting_day: monday
|
||||
d3_date_format: '%d/%m/%y'
|
||||
uib_date_format: dd/MM/yyyy
|
||||
excel_date_format: dd/mm/yyyy
|
||||
rails_locale: en
|
||||
moment_locale: en
|
||||
summernote_locale: en-US
|
||||
@ -78,6 +80,7 @@ staging:
|
||||
week_starting_day: <%= ENV["WEEK_STARTING_DAY"] %>
|
||||
d3_date_format: <%= ENV["D3_DATE_FORMAT"].dump %>
|
||||
uib_date_format: <%= ENV["UIB_DATE_FORMAT"] %>
|
||||
excel_date_format: <%= ENV["EXCEL_DATE_FORMAT"]%>
|
||||
rails_locale: <%= ENV["RAILS_LOCALE"] %>
|
||||
moment_locale: <%= ENV["MOMENT_LOCALE"] %>
|
||||
summernote_locale: <%= ENV["SUMMERNOTE_LOCALE"] %>
|
||||
@ -112,6 +115,7 @@ production:
|
||||
week_starting_day: <%= ENV["WEEK_STARTING_DAY"] %>
|
||||
d3_date_format: <%= ENV["D3_DATE_FORMAT"].dump %>
|
||||
uib_date_format: <%= ENV["UIB_DATE_FORMAT"] %>
|
||||
excel_date_format: <%= ENV["EXCEL_DATE_FORMAT"]%>
|
||||
rails_locale: <%= ENV["RAILS_LOCALE"] %>
|
||||
moment_locale: <%= ENV["MOMENT_LOCALE"] %>
|
||||
summernote_locale: <%= ENV["SUMMERNOTE_LOCALE"] %>
|
||||
|
Loading…
x
Reference in New Issue
Block a user