1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-12-01 12:24:28 +01:00
This commit is contained in:
vincent 2022-04-01 17:48:32 +02:00
parent c16150d7cc
commit f25fdd4091
164 changed files with 4662 additions and 6718 deletions

View File

@ -1 +0,0 @@
defaults

View File

@ -13,9 +13,11 @@
"angular": true,
"Fablab": true,
"moment": true,
"_": true
"_": true,
"Humanize": true,
"GTM": true
},
"plugins": ["lint-erb"],
"plugins": ["html-erb"],
"overrides": [
{
"files": ["**/*.ts", "**/*.tsx"],

7
.gitignore vendored
View File

@ -65,3 +65,10 @@ yarn-error.log
/yarn-error.log
yarn-debug.log*
.yarn-integrity
/public/packs
/public/packs-test
/node_modules
/yarn-error.log
yarn-debug.log*
.yarn-integrity

View File

@ -1,8 +1,77 @@
# Changelog Fab-manager
- Updated Node to 16.13.2
- Updated eslint to v8 and eslint related packages to their latest versions
- Updated typescript to v4.6.3
- Webpack overlay will now report eslint issues
- Linted all code according to eslint rules
# v5.3.2 2022 January 19
## v5.3.7 2022 March 28
- Updated Spanish translations (thanks to [@altieriranedo](https://crowdin.com/profile/altieriranedo))
- Fix a security issue: updated minimist to 1.2.6 to fix [CVE-2021-44906](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44906)
- Fix a security issue: updated node-forge to 1.3.0 to fix [CVE-2022-24771](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24771), [CVE-2022-24772](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24772) and [CVE-2022-24773](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24773)
## v5.3.6 2022 March 24
- Support for Google Analytics V4
- OAuth2 scopes are now configurable from the interface
- Prepaid-packs purchases are exported to the accounting CSV file
- Updated environment documentation
- Updated react-i18next to 11.15.6
- Updated i18next to 21.6.13
- Updated i18next-icu to 2.0.3
- Updated sidekiq-unique-jobs to 7.1.15
- Updated @uirouter/angularjs to 1.0.30
- Updated bootstrap-sass to 3.4.3
- Removed unmaintained gem sidekiq-cron and replaced it with sidekiq-scheduler
- Removed unmaintained @rails/webpacker v5 and replaced it with shakapacker v6.2.0
- Removed dependency to auto-ngtemplate-loader
- Removed support for Universal Analytics
- Updated deprecated division operators in sass
- Fix a bug: prepaid-packs purchases are reported as subscriptions in the statistics
- Fix a bug: error Couldn't find the binary git during assets compilation
- Fix a bug: a sentence was not linked to a translation key
- Fix a bug: the version check may be scheduled at an invalid time
- Fix a bug: the moment-timezone relied on an outdated version of moment with a case-sensitive locale file
- Fix a bug: unable to delete an administrator who had closed an accounting period
- Fix a bug: captcha keys are not shown in the admin panel, once configured
- Fix a bug: help message in upgrade script has a bogus format
- Fix a security issue: removed message format in elasticsearch's log4j to fix [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-44228)
- Fix a security issue: updated image_processing to 1.12.2 to fix [CVE-2022-24720](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24720)
- Fix a security issue: updated url-parse to 1.5.10 to fix [CVE-2022-0686](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0686), [CVE-2022-0691](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0691), [CVE-2022-0639](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0639) and [CVE-2022-0512](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0512)
- Fix a security issue: updated rails to 5.2.6.3 to fix [CVE-2022-21831](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21831), [CVE-2022-23633](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23633)
- Fix a security issue: updated sidekiq to 6.4.1 to fix [CVE-2022-23837](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23837)
- Fix a security issue: updated nokogiri to 1.13.3 to fix [CVE-2021-30560](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-30560) and [CVE-2022-23308](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23308)
- Fix a security issue: updated puma to 4.3.11 to fix [CVE-2022-23634](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-23634)
- Fix a security issue: updated i18next-http-backend to 1.3.2 to fix [CVE-2022-0235](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0235)
- Fix a security issue: updated follow-redirects to 1.18.8 to fix [CVE-2022-0536](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0536)
- [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2021,07]`
- [TODO DEPLOY] `\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/scripts/cve-2021-44228.sh | bash`
- [TODO DEPLOY] update your oAuth2 provider configuration with the scopes previously defined in the OAUTH2_SCOPE environment variable
## v5.3.5 2022 March 02
- Added [an option](doc/environment.md#OPENLAB_SSL_VERIFY) to allow set verify ssl option for OpenLab
## v5.3.4 2022 March 01
- Fix line break on home events' cards
- Fix typo "projets" => "projects"
- Removes dead code about OpenAPI (open_api_calls_count_tracings)
- Fix a bug: unable to modify OpenLab url for production
## v5.3.3 2022 February 08
- Updated german translations
- Fix a bug: unable to rebuild the statistics
- Fix a bug/regresion: $sce.getTrustedHtml removes all dangerous html like iframe (youtube players, ect), replaced by $sce.trustAsHtml which trusts the content, it creates a security breach but all contents are created by users to we trust them
- Fix a bug: in SubscriptionPolicy#show?, was causing an error notice, making user think that the payment was not done, but it was
- Fix a bug: destroying a project was impossible
- Fix a bug: fix non-blocking js error when there was not payment gateway set
- [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2020,04]`
## v5.3.2 2022 January 19
- Add a test for statistics generation
- Fix a bug: missing the Other payment method
@ -14,7 +83,7 @@
- Fix a bug: prepaid-packs without expiration date do not work
- [TODO DEPLOY] `rails fablab:maintenance:regenerate_statistics[2020,04]`
# v5.3.1 2022 January 17
## v5.3.1 2022 January 17
- Definition of extended prices for spaces is now made in hours (previously in minutes)
- Support for JSONPath syntax in OAuth2 SSO fields mapping
@ -45,12 +114,12 @@
- Fix a security issue: updated follow-redirects to 1.14.7 to fix [CVE-2022-0155](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-0155)
- [TODO DEPLOY] `rails db:seed`
# v5.3.0 2021 December 29
## v5.3.0 2021 December 29
- Ability to configure multiple VAT rates, per kind of invoiced item
- Ability to export the collected VAT, by rates, to a CSV file
- Refactored the extended prices' frontend code to allow future customization
- Fix a bug: the amount label in not correctly shown in the extended prices modal
- Fix a bug: the amount label in not correctly shown in the extended prices modal
- Fix a bug: `extended_prices_in_same_day` apply the extended prices to each day
## v5.2.0 2021 December 23

View File

@ -9,6 +9,8 @@ RUN apk update && apk upgrade && \
curl \
nodejs \
yarn \
git \
openssh \
imagemagick \
supervisor \
tzdata \
@ -26,7 +28,6 @@ RUN apk update && apk upgrade && \
alpine-sdk \
build-base \
linux-headers \
git \
patch
RUN gem install bundler

View File

@ -7,8 +7,8 @@ gem 'rails', '~> 5.2.4'
# Used by rails 5.2 to reduce the app boot time by over 50%
gem 'bootsnap'
# Use Puma as web server
gem 'puma', '4.3.9'
gem 'webpacker', '~> 5.x'
gem 'puma', '4.3.11'
gem 'shakapacker', '6.2.0'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
@ -90,8 +90,8 @@ gem 'aasm'
# Background job processing
gem 'sidekiq', '>= 6.0.7'
# Recurring jobs for Sidekiq
gem 'sidekiq-cron'
gem 'sidekiq-unique-jobs', '~> 6.0.22'
gem 'sidekiq-scheduler'
gem 'sidekiq-unique-jobs', '~> 7.1.15'
gem 'stripe', '5.29.0'

View File

@ -4,46 +4,46 @@ GEM
Ascii85 (1.0.3)
aasm (5.0.8)
concurrent-ruby (~> 1.0)
actioncable (5.2.6)
actionpack (= 5.2.6)
actioncable (5.2.6.3)
actionpack (= 5.2.6.3)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailer (5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
actionmailer (5.2.6.3)
actionpack (= 5.2.6.3)
actionview (= 5.2.6.3)
activejob (= 5.2.6.3)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (5.2.6)
actionview (= 5.2.6)
activesupport (= 5.2.6)
actionpack (5.2.6.3)
actionview (= 5.2.6.3)
activesupport (= 5.2.6.3)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionpack-page_caching (1.2.2)
actionpack (>= 5.0.0)
actionview (5.2.6)
activesupport (= 5.2.6)
actionview (5.2.6.3)
activesupport (= 5.2.6.3)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_record_query_trace (1.7)
activejob (5.2.6)
activesupport (= 5.2.6)
activejob (5.2.6.3)
activesupport (= 5.2.6.3)
globalid (>= 0.3.6)
activemodel (5.2.6)
activesupport (= 5.2.6)
activerecord (5.2.6)
activemodel (= 5.2.6)
activesupport (= 5.2.6)
activemodel (5.2.6.3)
activesupport (= 5.2.6.3)
activerecord (5.2.6.3)
activemodel (= 5.2.6.3)
activesupport (= 5.2.6.3)
arel (>= 9.0)
activestorage (5.2.6)
actionpack (= 5.2.6)
activerecord (= 5.2.6)
activestorage (5.2.6.3)
actionpack (= 5.2.6.3)
activerecord (= 5.2.6.3)
marcel (~> 1.0.0)
activesupport (5.2.6)
activesupport (5.2.6.3)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -66,6 +66,9 @@ GEM
bindex (0.8.1)
bootsnap (1.4.6)
msgpack (~> 1.0)
brpoplpush-redis_script (0.1.2)
concurrent-ruby (~> 1.0, >= 1.0.5)
redis (>= 1.0, <= 5.0)
builder (3.2.4)
bullet (7.0.0)
activesupport (>= 3.0.0)
@ -91,7 +94,7 @@ GEM
cldr-plurals-runtime-rb (1.0.1)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
concurrent-ruby (1.1.8)
concurrent-ruby (1.1.9)
connection_pool (2.2.5)
coveralls_reborn (0.18.0)
simplecov (>= 0.18.1, < 0.20.0)
@ -115,6 +118,7 @@ GEM
dotenv-rails (2.7.5)
dotenv (= 2.7.5)
railties (>= 3.2, < 6.1)
e2mmap (0.1.0)
elasticsearch (5.0.5)
elasticsearch-api (= 5.0.5)
elasticsearch-transport (= 5.0.5)
@ -137,36 +141,36 @@ GEM
multi_json
equalizer (0.0.11)
erubi (1.10.0)
et-orbi (1.2.1)
et-orbi (1.2.7)
tzinfo
faker (2.10.2)
i18n (>= 1.6, < 2)
faraday (0.17.3)
multipart-post (>= 1.2, < 3)
ffi (1.15.4)
ffi (1.15.5)
foreman (0.87.0)
forgery (0.7.0)
friendly_id (5.1.0)
activerecord (>= 4.0.0)
fugit (1.3.1)
fugit (1.5.2)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.1)
globalid (0.4.2)
activesupport (>= 4.2.0)
raabro (~> 1.4)
globalid (1.0.0)
activesupport (>= 5.0)
hashdiff (1.0.1)
hashery (2.1.2)
hashie (4.1.0)
htmlentities (4.3.4)
httparty (0.18.1)
httparty (0.20.0)
mime-types (~> 3.0)
multi_xml (>= 0.5.2)
i18n (1.8.10)
i18n (1.10.0)
concurrent-ruby (~> 1.0)
icalendar (2.5.3)
ice_cube (~> 0.16)
ice_cube (0.16.3)
ice_nine (0.11.2)
image_processing (1.12.1)
image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
jaro_winkler (1.5.4)
@ -193,25 +197,25 @@ GEM
listen (3.0.8)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
loofah (2.9.1)
loofah (2.14.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mini_mime (>= 0.1.1)
marcel (1.0.1)
marcel (1.0.2)
message_format (0.0.6)
twitter_cldr (~> 5.0)
method_source (1.0.0)
mime-types (3.3.1)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0225)
mime-types-data (3.2022.0105)
mimemagic (0.4.3)
nokogiri (~> 1)
rake
mini_magick (4.10.1)
mini_mime (1.1.0)
mini_portile2 (2.6.1)
minitest (5.14.4)
mini_mime (1.1.2)
mini_portile2 (2.8.0)
minitest (5.15.0)
minitest-reporters (1.4.2)
ansi
builder
@ -222,8 +226,8 @@ GEM
multi_xml (0.6.0)
multipart-post (2.1.1)
nio4r (2.5.8)
nokogiri (1.12.5)
mini_portile2 (~> 2.6.1)
nokogiri (1.13.3)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
notify_with (0.0.2)
jbuilder (~> 2.0)
@ -245,8 +249,8 @@ GEM
omniauth-rails_csrf_protection (0.1.2)
actionpack (>= 4.2)
omniauth (>= 1.3.1)
openlab_ruby (0.0.5)
httparty (~> 0.13)
openlab_ruby (0.0.7)
httparty (~> 0.20)
orm_adapter (0.5.0)
parallel (1.19.1)
parser (2.7.0.4)
@ -269,35 +273,35 @@ GEM
prawn-table (0.2.2)
prawn (>= 1.3.0, < 3.0.0)
public_suffix (4.0.6)
puma (4.3.9)
puma (4.3.11)
nio4r (~> 2.0)
pundit (2.1.0)
activesupport (>= 3.0.0)
raabro (1.1.6)
racc (1.5.2)
raabro (1.4.0)
racc (1.6.0)
rack (2.2.3)
rack-proxy (0.6.5)
rack-proxy (0.7.2)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
railroady (1.5.3)
rails (5.2.6)
actioncable (= 5.2.6)
actionmailer (= 5.2.6)
actionpack (= 5.2.6)
actionview (= 5.2.6)
activejob (= 5.2.6)
activemodel (= 5.2.6)
activerecord (= 5.2.6)
activestorage (= 5.2.6)
activesupport (= 5.2.6)
rails (5.2.6.3)
actioncable (= 5.2.6.3)
actionmailer (= 5.2.6.3)
actionpack (= 5.2.6.3)
actionview (= 5.2.6.3)
activejob (= 5.2.6.3)
activemodel (= 5.2.6.3)
activerecord (= 5.2.6.3)
activestorage (= 5.2.6.3)
activesupport (= 5.2.6.3)
bundler (>= 1.3.0)
railties (= 5.2.6)
railties (= 5.2.6.3)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
rails-html-sanitizer (1.4.2)
loofah (~> 2.3)
rails-observers (0.1.5)
activemodel (>= 4.0)
@ -306,14 +310,14 @@ GEM
rails_stdout_logging
rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.5)
railties (5.2.6)
actionpack (= 5.2.6)
activesupport (= 5.2.6)
railties (5.2.6.3)
actionpack (= 5.2.6.3)
activesupport (= 5.2.6.3)
method_source
rake (>= 0.8.7)
thor (>= 0.19.0, < 2.0)
rainbow (3.0.0)
rake (13.0.3)
rake (13.0.6)
rb-fsevent (0.10.3)
rb-inotify (0.10.1)
ffi (~> 1.0)
@ -321,7 +325,7 @@ GEM
recurrence (1.3.0)
activesupport
i18n
redis (4.4.0)
redis (4.6.0)
repost (0.3.2)
responders (2.4.1)
actionpack (>= 4.2.0, < 6.0)
@ -337,31 +341,43 @@ GEM
unicode-display_width (~> 1.4.0)
ruby-progressbar (1.10.1)
ruby-rc4 (0.1.5)
ruby-vips (2.0.17)
ffi (~> 1.9)
ruby-vips (2.1.4)
ffi (~> 1.12)
rubyXL (3.4.14)
nokogiri (>= 1.10.8)
rubyzip (>= 1.3.0)
rubyzip (2.3.0)
rufus-scheduler (3.8.1)
fugit (~> 1.1, >= 1.1.6)
safe_yaml (1.0.5)
sassc (2.4.0)
ffi (~> 1.9)
seed_dump (3.3.1)
activerecord (>= 4)
activesupport (>= 4)
semantic_range (2.3.0)
semantic_range (3.0.0)
sha3 (1.0.1)
sidekiq (6.2.1)
shakapacker (6.2.0)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
sidekiq (6.4.1)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
sidekiq-cron (1.1.0)
fugit (~> 1.1)
sidekiq (>= 4.2.1)
sidekiq-unique-jobs (6.0.22)
sidekiq-scheduler (3.1.1)
e2mmap
redis (>= 3, < 5)
rufus-scheduler (~> 3.2)
sidekiq (>= 3)
thwait
tilt (>= 1.4.0)
sidekiq-unique-jobs (7.1.15)
brpoplpush-redis_script (> 0.1.1, <= 2.0.0)
concurrent-ruby (~> 1.0, >= 1.0.5)
sidekiq (>= 4.0, < 7.0)
thor (~> 0)
sidekiq (>= 5.0, < 8.0)
thor (>= 0.20, < 3.0)
simplecov (0.19.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
@ -371,12 +387,12 @@ GEM
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (4.0.2)
sprockets (4.0.3)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.2.2)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
ssrf_filter (1.0.7)
stripe (5.29.0)
@ -387,6 +403,9 @@ GEM
tins (~> 1.0)
thor (0.20.3)
thread_safe (0.3.6)
thwait (0.2.0)
e2mmap
tilt (2.0.10)
tins (1.25.0)
sync
ttfunk (1.5.1)
@ -417,12 +436,7 @@ GEM
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.2.1)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
websocket-driver (0.7.3)
websocket-driver (0.7.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
@ -475,7 +489,7 @@ DEPENDENCIES
pg_search
prawn
prawn-table
puma (= 4.3.9)
puma (= 4.3.11)
pundit
railroady
rails (~> 5.2.4)
@ -492,9 +506,10 @@ DEPENDENCIES
sassc
seed_dump
sha3
shakapacker (= 6.2.0)
sidekiq (>= 6.0.7)
sidekiq-cron
sidekiq-unique-jobs (~> 6.0.22)
sidekiq-scheduler
sidekiq-unique-jobs (~> 7.1.15)
spring
spring-watcher-listen (~> 2.0.0)
stripe (= 5.29.0)
@ -503,7 +518,6 @@ DEPENDENCIES
vcr (= 6.0.0)
web-console (>= 3.3.0)
webmock
webpacker (~> 5.x)
BUNDLED WITH
2.2.19
2.2.21

View File

@ -1,4 +1,3 @@
web: bundle exec rails server puma -p $PORT
worker: bundle exec sidekiq -C ./config/sidekiq.yml
wp-client: bin/webpack-dev-server
wp-server: SERVER_BUNDLE_ONLY=yes bin/webpack --watch
webpack: bin/webpacker-dev-server

View File

@ -83,7 +83,7 @@ class API::AuthProvidersController < API::ApiController
params.require(:auth_provider)
.permit(:name, :providable_type,
providable_attributes: [:id, :base_url, :token_endpoint, :authorization_endpoint, :logout_endpoint,
:profile_url, :client_id, :client_secret,
:profile_url, :client_id, :client_secret, :scopes,
o_auth2_mappings_attributes: [:id, :local_model, :local_field, :api_field,
:api_endpoint, :api_data_type, :_destroy,
transformation: [:type, :format, :true_value,

View File

@ -6,7 +6,7 @@ class API::OpenlabProjectsController < API::ApiController
before_action :init_openlab
def index
render json: @projets.search(params[:q], page: params[:page], per_page: params[:per_page]).response.body
render json: @projects.search(params[:q], page: params[:page], per_page: params[:per_page]).response.body
rescue StandardError
render json: { errors: ['service unavailable'] }
end
@ -15,6 +15,6 @@ class API::OpenlabProjectsController < API::ApiController
def init_openlab
client = Openlab::Client.new(app_secret: Setting.get('openlab_app_secret'))
@projets = Openlab::Projects.new(client)
@projects = Openlab::Projects.new(client)
end
end

View File

@ -4,7 +4,7 @@ import 'regenerator-runtime/runtime';
import 'jquery';
import {} from 'jquery-ujs';
import 'bootstrap-sass';
import '../src/javascript/lib/polyfill';
import 'src/javascript/lib/polyfill';
import 'angular';
<% unless Rails.application.secrets.angular_locale == 'en-us' %>
import 'angular-i18n/angular-locale_<%= Rails.application.secrets.angular_locale %>.js';
@ -31,16 +31,15 @@ import 'ngUpload';
import 'jasny-bootstrap/js/fileinput';
import 'holderjs';
import 'AngularDevise';
import '../src/javascript/lib/devise-modal';
import 'src/javascript/lib/devise-modal';
import 'angular-growl-v2';
import 'angular-xeditable';
import 'checklist-model/checklist-model';
import 'angular-unsavedchanges/lib/unsavedChanges';
import 'angular-loading-bar/src/loading-bar';
import 'angular-scroll/angular-scroll';
import 'angular-google-analytics/dist/angular-google-analytics';
import '../src/javascript/lib/dirDisqus';
import '../src/javascript/lib/humanize';
import 'src/javascript/lib/dirDisqus';
import 'src/javascript/lib/humanize';
import 'underscore/underscore';
import 'elasticsearch-browser/elasticsearch.angular';
import 'd3/d3';
@ -56,7 +55,7 @@ import 'summernote';
import 'summernote/lang/summernote-<%= Rails.application.secrets.summernote_locale %>.js';
<% end %>
import 'angular-summernote/dist/angular-summernote';
import '../src/javascript/lib/summernote-ext-nugget';
import 'src/javascript/lib/summernote-ext-nugget';
import '@claviska/jquery-minicolors/jquery.minicolors.js';
import 'angular-minicolors/angular-minicolors.js';
import 'angular-translate/dist/angular-translate';
@ -80,18 +79,18 @@ import 'angular-ui-tour/app/angular-ui-tour';
import '@fortawesome/fontawesome-free';
import '@fortawesome/fontawesome-free/js/v4-shims';
require('../src/javascript/app.js');
require('../src/javascript/router.js');
require('../src/javascript/plugins.js.erb');
require('src/javascript/app.js');
require('src/javascript/router.js');
require('src/javascript/plugins.js.erb');
function importAll (r) { r.keys().forEach(r); }
importAll(require.context('../src/javascript/components/', true, /.*/));
importAll(require.context('../src/javascript/controllers/', true, /.*/));
importAll(require.context('../src/javascript/services/', true, /.*/));
importAll(require.context('../src/javascript/directives/', true, /.*/));
importAll(require.context('../src/javascript/filters/', true, /.*/));
importAll(require.context('../src/javascript/typings/', true, /.*/));
importAll(require.context('src/javascript/components/', true, /.*/));
importAll(require.context('src/javascript/controllers/', true, /.*/));
importAll(require.context('src/javascript/services/', true, /.*/));
importAll(require.context('src/javascript/directives/', true, /.*/));
importAll(require.context('src/javascript/filters/', true, /.*/));
importAll(require.context('src/javascript/typings/', true, /.*/));
importAll(require.context('../images', true));
importAll(require.context('../templates', true));
importAll(require.context('images', true));
importAll(require.context('templates', true));

View File

@ -15,4 +15,4 @@
@import '~angular-aside/dist/css/angular-aside';
@import '~codemirror/lib/codemirror';
@import '../src/stylesheets/application.scss';
@import 'src/stylesheets/application.scss';

View File

@ -1,2 +0,0 @@
@import '../src/stylesheets/app.printer';

View File

@ -0,0 +1,2 @@
@import 'src/stylesheets/app.printer';

View File

@ -3,7 +3,7 @@ import { AxiosResponse } from 'axios';
import { Space } from '../models/space';
export default class SpaceAPI {
static async index (): Promise<Array<any>> {
static async index (): Promise<Array<Space>> {
const res: AxiosResponse<Array<Space>> = await apiClient.get('/api/spaces');
return res?.data;
}
@ -12,5 +12,4 @@ export default class SpaceAPI {
const res: AxiosResponse<Space> = await apiClient.get(`/api/spaces/${id}`);
return res?.data;
}
}

View File

@ -5,6 +5,7 @@
* creating namespaces and moduled for controllers, filters, services, and directives.
*/
// eslint-disable-next-line no-var -- Application is a global variable.
var Application = Application || {};
Application.Components = angular.module('application.components', []);
@ -17,22 +18,17 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
'ngUpload', 'duScroll', 'application.filters', 'application.services', 'application.directives',
'frapontillo.bootstrap-switch', 'application.controllers', 'application.router', 'application.components',
'ui.select', 'ui.calendar', 'angularMoment', 'Devise', 'angular-growl', 'xeditable',
'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch', 'angular-google-analytics',
'checklist-model', 'unsavedChanges', 'angular-loading-bar', 'ngTouch',
'angularUtils.directives.dirDisqus', 'summernote', 'elasticsearch', 'angular-medium-editor', 'naif.base64',
'minicolors', 'pascalprecht.translate', 'ngFitText', 'ngAside', 'ngCapsLock', 'vcRecaptcha', 'ui.codemirror',
'bm.uiTour'])
.config(['$httpProvider', 'AuthProvider', 'growlProvider', 'unsavedWarningsConfigProvider', 'AnalyticsProvider', 'uibDatepickerPopupConfig', '$provide', '$translateProvider', 'TourConfigProvider',
function ($httpProvider, AuthProvider, growlProvider, unsavedWarningsConfigProvider, AnalyticsProvider, uibDatepickerPopupConfig, $provide, $translateProvider, TourConfigProvider) {
.config(['$httpProvider', 'AuthProvider', 'growlProvider', 'unsavedWarningsConfigProvider', 'uibDatepickerPopupConfig', '$provide', '$translateProvider', 'TourConfigProvider', '$sceDelegateProvider',
function ($httpProvider, AuthProvider, growlProvider, unsavedWarningsConfigProvider, uibDatepickerPopupConfig, $provide, $translateProvider, TourConfigProvider, $sceDelegateProvider) {
// Google analytics
// first we check the user acceptance
const cookiesConsent = document.cookie.replace(/(?:(?:^|.*;\s*)fab-manager-cookies-consent\s*=\s*([^;]*).*$)|^.*$/, '$1');
if (cookiesConsent === 'accept') {
AnalyticsProvider.setAccount(Fablab.trackingId);
// track all routes (or not)
AnalyticsProvider.trackPages(true);
AnalyticsProvider.setDomainName(Fablab.baseHostUrl);
AnalyticsProvider.useAnalytics(true);
AnalyticsProvider.setPageEvent('$stateChangeSuccess');
GTM.enableAnalytics(Fablab.trackingId);
} else {
// if the cookies were not explicitly accepted, delete them
document.cookie = '_ga=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
@ -65,8 +61,10 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
$translateProvider.preferredLanguage(Fablab.locale);
// End the tour when the user clicks the forward or back buttons of the browser
TourConfigProvider.enableNavigationInterceptors();
}]).run(['$rootScope', '$log', 'Auth', 'amMoment', '$state', 'editableOptions', 'Analytics',
function ($rootScope, $log, Auth, amMoment, $state, editableOptions, Analytics) {
$sceDelegateProvider.resourceUrlWhitelist(['self']);
}]).run(['$rootScope', '$transitions', '$log', 'Auth', 'amMoment', '$state', 'editableOptions',
function ($rootScope, $transitions, $log, Auth, amMoment, $state, editableOptions) {
// Angular-moment (date-time manipulations library)
amMoment.changeLocale(Fablab.moment_locale);
@ -75,9 +73,12 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
// Alter the UI-Router's $state, registering into some information concerning the previous $state.
// This is used to allow the user to navigate to the previous state
$rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
$state.prevState = fromState;
$state.prevParams = fromParams;
$transitions.onSuccess({ }, function (trans) {
$state.prevState = trans.$from().name;
$state.prevParams = trans.$from().params;
const path = trans.router.stateService.href(trans.$to(), {}, { absolute: true });
GTM.trackPage(path, trans.$to().name);
});
// Global function to allow the user to navigate to the previous screen (ie. $state).
@ -85,7 +86,7 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
$rootScope.backPrevLocation = function (event) {
event.preventDefault();
event.stopPropagation();
if ($state.prevState.name === '') {
if ($state.prevState === '') {
$state.prevState = 'app.public.home';
}
$state.go($state.prevState, $state.prevParams);
@ -112,9 +113,9 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
// Prevent the usage of the application for members with incomplete profiles: they will be redirected to
// the 'profile completion' page. This is especially useful for user's accounts imported through SSO.
$rootScope.$on('$stateChangeStart', function (event, toState) {
$transitions.onStart({}, function (trans) {
Auth.currentUser().then(function (currentUser) {
if (currentUser.need_completion && toState.name !== 'app.logged.profileCompletion') {
if (currentUser.need_completion && trans.$to().name !== 'app.logged.profileCompletion') {
$state.go('app.logged.profileCompletion');
}
}).catch(() => {
@ -122,10 +123,6 @@ angular.module('application', ['ngCookies', 'ngResource', 'ngSanitize', 'ui.rout
});
});
// This code does nothing but it is here to remember to not remove the Analytics dependency,
// see https://github.com/revolunet/angular-google-analytics#automatic-page-view-tracking
Analytics.pageView();
/**
* This helper method builds and return an array containing every integers between
* the provided start and end.

View File

@ -1,5 +1,6 @@
import React, { ReactNode } from 'react';
import { FieldErrors, UseFormRegister, Validate } from 'react-hook-form';
import { FieldValues } from 'react-hook-form/dist/types/fields';
type inputType = string|number|readonly string [];
type ruleTypes = {
@ -9,12 +10,12 @@ type ruleTypes = {
maxLenght?: number,
min?: number,
max?: number,
validate?: Validate<any>;
validate?: Validate<FieldValues>;
};
interface RHFInputProps {
id: string,
register: UseFormRegister<any>,
register: UseFormRegister<FieldValues>,
label?: string,
tooltip?: string,
defaultValue?: inputType,

View File

@ -3,7 +3,7 @@ import { Node } from '@tiptap/core';
export interface IframeOptions {
allowFullscreen: boolean,
HTMLAttributes: {
[key: string]: any
[key: string]: string
},
}

View File

@ -14,6 +14,7 @@ import WalletAPI from '../../api/wallet';
import { Invoice } from '../../models/invoice';
import SettingAPI from '../../api/setting';
import { SettingName } from '../../models/setting';
import { GoogleTagManager } from '../../models/gtm';
import { ComputePriceResult } from '../../models/price';
import { Wallet } from '../../models/wallet';
import FormatLib from '../../lib/format';
@ -52,6 +53,8 @@ interface AbstractPaymentModalProps {
modalSize?: ModalSize,
}
declare const GTM: GoogleTagManager;
/**
* This component is an abstract modal that must be extended by each payment gateway to include its payment form.
*
@ -90,7 +93,9 @@ export const AbstractPaymentModal: React.FC<AbstractPaymentModalProps> = ({ isOp
CustomAssetAPI.get(CustomAssetName.CgvFile).then(asset => setCgv(asset));
SettingAPI.get(SettingName.PaymentGateway).then((setting) => {
// we capitalize the first letter of the name
setGateway(setting.value.replace(/^\w/, (c) => c.toUpperCase()));
if (setting.value) {
setGateway(setting.value.replace(/^\w/, (c) => c.toUpperCase()));
}
});
return () => { mounted.current = false; };
@ -154,6 +159,7 @@ export const AbstractPaymentModal: React.FC<AbstractPaymentModalProps> = ({ isOp
*/
const handleFormSuccess = async (result: Invoice|PaymentSchedule): Promise<void> => {
setSubmitState(false);
GTM.trackPurchase(result.id, result.total);
afterSuccess(result);
};

View File

@ -11,7 +11,7 @@ import { PaymentSchedule } from '../../../models/payment-schedule';
* A form component to collect the credit card details and to create the payment method on Stripe.
* The form validation button must be created elsewhere, using the attribute form={formId}.
*/
export const StripeForm: React.FC<GatewayFormProps> = ({ onSubmit, onSuccess, onError, children, className, paymentSchedule = false, cart, customer, operator, formId }) => {
export const StripeForm: React.FC<GatewayFormProps> = ({ onSubmit, onSuccess, onError, children, className, paymentSchedule = false, cart, formId }) => {
const { t } = useTranslation('shared');
const stripe = useStripe();

View File

@ -26,7 +26,6 @@ interface FreeExtendModalProps {
* Modal dialog shown to extend the current subscription of a customer, for free
*/
const FreeExtendModal: React.FC<FreeExtendModalProps> = ({ isOpen, toggleModal, subscription, customerId, onError, onSuccess }) => {
// we do not render the modal if the subscription was not provided
if (!subscription) return null;

View File

@ -318,8 +318,8 @@ Application.Controllers.controller('NewAuthenticationController', ['$scope', '$s
/**
* Page to edit an already added authentication provider
*/
Application.Controllers.controller('EditAuthenticationController', ['$scope', '$state', '$stateParams', '$rootScope', '$uibModal', 'dialogs', 'growl', 'providerPromise', 'mappingFieldsPromise', 'AuthProvider', '_t',
function ($scope, $state, $stateParams, $rootScope, $uibModal, dialogs, growl, providerPromise, mappingFieldsPromise, AuthProvider, _t) {
Application.Controllers.controller('EditAuthenticationController', ['$scope', '$state', '$rootScope', '$uibModal', 'dialogs', 'growl', 'providerPromise', 'mappingFieldsPromise', 'AuthProvider', '_t',
function ($scope, $state, $rootScope, $uibModal, dialogs, growl, providerPromise, mappingFieldsPromise, AuthProvider, _t) {
// parameters of the currently edited authentication provider
$scope.provider = providerPromise;

View File

@ -619,12 +619,12 @@ Application.Controllers.controller('NewEventController', ['$scope', '$state', 'C
/**
* Controller used in the events edition page
*/
Application.Controllers.controller('EditEventController', ['$scope', '$state', '$stateParams', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '$uibModal', 'growl', '_t',
function ($scope, $state, $stateParams, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, $uibModal, growl, _t) {
Application.Controllers.controller('EditEventController', ['$scope', '$state', '$transition$', 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '$uibModal', 'growl', '_t',
function ($scope, $state, $transition$, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, $uibModal, growl, _t) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/events/${$stateParams.id}`;
$scope.actionUrl = `/api/events/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';

View File

@ -4,7 +4,7 @@
no-undef,
no-unreachable,
no-unused-vars,
standard/no-callback-literal,
n/no-callback-literal,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
@ -17,8 +17,8 @@
*/
'use strict';
Application.Controllers.controller('GraphsController', ['$scope', '$state', '$rootScope', 'es', 'Statistics', '_t',
function ($scope, $state, $rootScope, es, Statistics, _t) {
Application.Controllers.controller('GraphsController', ['$scope', '$state', '$rootScope', '$transitions', 'es', 'Statistics', '_t',
function ($scope, $state, $rootScope, $transitions, es, Statistics, _t) {
/* PRIVATE STATIC CONSTANTS */
// height of the HTML/SVG charts elements in pixels
@ -167,8 +167,8 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
// workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected
// which will cause every tabs to reload, one by one, when the view is closed
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if ((fromState.name === 'app.admin.stats_graphs') && (Object.keys(fromParams).length === 0)) {
$transitions.onStart({ to: 'app.admin.stats_graphs' }, function (trans) {
if (Object.keys(trans.from().params).length === 0) {
return $scope.preventRefresh = true;
}
});
@ -179,7 +179,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param $event {Object} jQuery event object
* @param datePicker {Object} settings object of the concerned datepicker. Must have an 'opened' property
*/
var toggleDatePicker = function ($event, datePicker) {
const toggleDatePicker = function ($event, datePicker) {
$event.preventDefault();
$event.stopPropagation();
return datePicker.opened = !datePicker.opened;
@ -188,7 +188,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
/**
* Query elasticSearch according to the current parameters and update the chart
*/
var refreshChart = function () {
const refreshChart = function () {
if ($scope.selectedIndex && !$scope.preventRefresh) {
return query($scope.selectedIndex, function (aggregations, error) {
if (error) {
@ -239,7 +239,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* Format aggregations as retuned by elasticSearch to an understandable format for NVD3
* @param aggs {Object} as returned by elasticsearch
*/
var formatAggregations = function (aggs) {
const formatAggregations = function (aggs) {
const format = {};
angular.forEach(aggs, function (type, type_key) { // go through aggs[$TYPE] where $TYPE = month|year|hour|booking|...
@ -254,7 +254,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
const cur_subtype = cur_type.subtypes[it_st];
if (subgroup.key === cur_subtype.key) { // ... which match $SUBTYPE
// then we construct NVD3 dataSource according to these information
var dataSource = {
const dataSource = {
values: [],
key: cur_subtype.label,
total: 0,
@ -292,7 +292,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param limit {number} limit the number of stats in the bar chart
* @param typeKey {String} field name witch results are grouped by
*/
var formatRankingAggregations = function (aggs, limit, typeKey) {
const formatRankingAggregations = function (aggs, limit, typeKey) {
const format =
{ ranking: [] };
@ -325,7 +325,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param key {string} raw value of the label
* @param typeKey {string} name of the field the results are grouped by
*/
var getRankingLabel = function (key, typeKey) {
const getRankingLabel = function (key, typeKey) {
if ($scope.selectedIndex) {
if (typeKey === 'subType') {
for (const type of Array.from($scope.selectedIndex.types)) {
@ -356,7 +356,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param callback {function} function be to run after results were retrieved,
* it will receive two parameters : results {Array}, error {String} (if any)
*/
var query = function (index, callback) {
const query = function (index, callback) {
// invalid callback handeling
if (typeof (callback) !== 'function') {
console.error('[graphsController::query] Error: invalid callback provided');
@ -384,7 +384,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
let type_it = 0;
const results = {};
let error = '';
var recursiveCb = function () {
const recursiveCb = function () {
if (type_it < stat_types.length) {
return queryElasticStats(index.es_type_key, stat_types[type_it], function (prevResults, prevError) {
if (prevError) {
@ -418,7 +418,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param callback {function} function be to run after results were retrieved,
* it will receive two parameters : results {Array}, error {String} (if any)
*/
var queryElasticStats = function (esType, statType, callback) {
const queryElasticStats = function (esType, statType, callback) {
// handle invalid callback
if (typeof (callback) !== 'function') {
console.error('[graphsController::queryElasticStats] Error: invalid callback provided');
@ -457,7 +457,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param callback {function} function be to run after results were retrieved,
* it will receive two parameters : results {Array}, error {String} (if any)
*/
var queryElasticRanking = function (esType, groupKey, sortKey, callback) {
const queryElasticRanking = function (esType, groupKey, sortKey, callback) {
// handle invalid callback
if (typeof (callback) !== 'function') {
return console.error('[graphsController::queryElasticRanking] Error: invalid callback provided');
@ -497,15 +497,13 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param intervalBegin {moment} statitics interval beginning (moment.js type)
* @param intervalEnd {moment} statitics interval ending (moment.js type)
*/
var buildElasticAggregationsQuery = function (type, interval, intervalBegin, intervalEnd) {
const buildElasticAggregationsQuery = function (type, interval, intervalBegin, intervalEnd) {
const q = {
query: {
bool: {
must: [
{
match: {
type: type
}
match: { type }
},
{
range: {
@ -527,7 +525,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
intervals: {
date_histogram: {
field: 'date',
interval: interval,
interval,
min_doc_count: 0,
extended_bounds: {
min: intervalBegin.valueOf(),
@ -566,7 +564,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param intervalBegin {moment} statitics interval beginning (moment.js type)
* @param intervalEnd {moment} statitics interval ending (moment.js type)
*/
var buildElasticAggregationsRankingQuery = function (groupKey, sortKey, intervalBegin, intervalEnd) {
const buildElasticAggregationsRankingQuery = function (groupKey, sortKey, intervalBegin, intervalEnd) {
const q = {
query: {
bool: {
@ -635,7 +633,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param data {Array} array of NVD3 dataSources
* @param type {String} which chart to update (statistic type key)
*/
var updateChart = function (chart_type, data, type) {
const updateChart = function (chart_type, data, type) {
const id = `#chart-${type} svg`;
// clean old charts
@ -695,7 +693,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
/**
* Given an NVD3 line chart axis, scale it to display ordinated dates, according to the given arguments
*/
var setTimeScale = function (nvd3Axis, nvd3Scale, argsArray) {
const setTimeScale = function (nvd3Axis, nvd3Scale, argsArray) {
const scale = d3.time.scale();
nvd3Axis.scale(scale);
@ -710,7 +708,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
/**
* Translate line chart data in dates row to bar chart data, one bar per type.
*/
var prepareDataForBarChart = function (data, type) {
const prepareDataForBarChart = function (data, type) {
const newData = [{
key: type,
values: []
@ -738,7 +736,7 @@ Application.Controllers.controller('GraphsController', ['$scope', '$state', '$ro
* @param getValue {function} the callback which will return the value on which the sort will occurs
* @returns {Array}
*/
var stableSort = function (array, order, getValue) {
const stableSort = function (array, order, getValue) {
// prepare sorting
const keys_order = [];
const result = [];

View File

@ -55,13 +55,13 @@ Application.Controllers.controller('GroupsController', ['$scope', 'groupsPromise
$scope.saveGroup = function (data, id) {
if (id != null) {
return Group.update({ id }, { group: data }, response => growl.success(_t('app.admin.members.group_form.changes_successfully_saved'))
, error => growl.error(_t('app.admin.members.group_form.an_error_occurred_while_saving_changes')));
, () => growl.error(_t('app.admin.members.group_form.an_error_occurred_while_saving_changes')));
} else {
return Group.save({ group: data }, function (resp) {
growl.success(_t('app.admin.members.group_form.new_group_successfully_saved'));
return $scope.groups[$scope.groups.length - 1].id = resp.id;
}
, function (error) {
, function () {
growl.error(_t('app.admin.members.group_form.an_error_occurred_when_saving_the_new_group'));
return $scope.groups.splice($scope.groups.length - 1, 1);
});
@ -77,7 +77,7 @@ Application.Controllers.controller('GroupsController', ['$scope', 'groupsPromise
growl.success(_t('app.admin.members.group_form.group_successfully_deleted'));
return $scope.groups.splice(index, 1);
}
, error => growl.error(_t('app.admin.members.group_form.unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it')));
, () => growl.error(_t('app.admin.members.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
@ -92,7 +92,7 @@ Application.Controllers.controller('GroupsController', ['$scope', 'groupsPromise
$scope.groups[index] = response;
return growl.success(_t('app.admin.members.group_form.group_successfully_enabled_disabled', { STATUS: response.disabled }));
}
, error => growl.error(_t('app.admin.members.group_form.unable_to_enable_disable_group', { STATUS: !group.disabled })));
, () => growl.error(_t('app.admin.members.group_form.unable_to_enable_disable_group', { STATUS: !group.disabled })));
}
};
}

View File

@ -195,6 +195,14 @@ Application.Controllers.controller('InvoicesController', ['$scope', '$state', 'I
name: 'accounting_Space_label',
value: settings.accounting_Space_label
},
packCode: {
name: 'accounting_Pack_code',
value: settings.accounting_Pack_code
},
packLabel: {
name: 'accounting_Pack_label',
value: settings.accounting_Pack_label
},
errorCode: {
name: 'accounting_Error_code',
value: settings.accounting_Error_code
@ -1239,7 +1247,7 @@ Application.Controllers.controller('AvoirModalController', ['$scope', '$uibModal
function (avoir) { // success
$uibModalInstance.close({ avoir, invoice: $scope.invoice });
},
function (err) { // failed
function () { // failed
growl.error(_t('app.admin.invoices.unable_to_create_the_refund'));
}
);

View File

@ -650,12 +650,12 @@ Application.Controllers.controller('AdminMembersController', ['$scope', '$sce',
/**
* Controller used in the member edition page
*/
Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', 'settingsPromise',
function ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet, settingsPromise) {
Application.Controllers.controller('EditMemberController', ['$scope', '$state', '$transition$', 'Member', 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'activeProviderPromise', 'Wallet', 'settingsPromise',
function ($scope, $state, $transition$, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, activeProviderPromise, Wallet, settingsPromise) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/members/${$stateParams.id}`;
$scope.actionUrl = `/api/members/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'patch';
@ -922,8 +922,8 @@ Application.Controllers.controller('EditMemberController', ['$scope', '$state',
/**
* Controller used in the member's creation page (admin view)
*/
Application.Controllers.controller('NewMemberController', ['$scope', '$state', '$stateParams', 'Member', 'Training', 'Group', 'CSRF', 'settingsPromise',
function ($scope, $state, $stateParams, Member, Training, Group, CSRF, settingsPromise) {
Application.Controllers.controller('NewMemberController', ['$scope', '$state', 'Member', 'Training', 'Group', 'CSRF', 'settingsPromise',
function ($scope, $state, Member, Training, Group, CSRF, settingsPromise) {
CSRF.setMetaTags();
/* PUBLIC SCOPE */

View File

@ -224,8 +224,8 @@ Application.Controllers.controller('NewPlanController', ['$scope', '$uibModal',
/**
* Controller used in the plan edition form
*/
Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'spaces', 'prices', 'partners', 'CSRF', '$state', '$stateParams', 'growl', '$filter', '_t', 'Plan', 'planCategories',
function ($scope, groups, plans, planPromise, machines, spaces, prices, partners, CSRF, $state, $stateParams, growl, $filter, _t, Plan, planCategories) {
Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'spaces', 'prices', 'partners', 'CSRF', '$state', '$transition$', 'growl', '$filter', '_t', 'Plan', 'planCategories',
function ($scope, groups, plans, planPromise, machines, spaces, prices, partners, CSRF, $state, $transition$, growl, $filter, _t, Plan, planCategories) {
/* PUBLIC SCOPE */
// List of spaces
@ -254,7 +254,7 @@ Application.Controllers.controller('EditPlanController', ['$scope', 'groups', 'p
if ($scope.plan.disabled) { $scope.plan.disabled = 'true'; }
// API URL where the form will be posted
$scope.actionUrl = `/api/plans/${$stateParams.id}`;
$scope.actionUrl = `/api/plans/${$transition$.params().id}`;
// HTTP method for the rest API
$scope.method = 'PATCH';

View File

@ -403,7 +403,7 @@ Application.Controllers.controller('EditPricingController', ['$scope', '$state',
$scope.spaceCredits[$scope.spaceCredits.length - 1].id = resp.id;
return growl.success(_t('app.admin.pricing.credit_was_successfully_saved'));
}
, function (err) {
, function () {
$scope.spaceCredits.pop();
return growl.error(_t('app.admin.pricing.error_creating_credit'));
});

View File

@ -2,7 +2,7 @@
no-constant-condition,
no-return-assign,
no-undef,
standard/no-callback-literal,
n/no-callback-literal,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
@ -15,8 +15,8 @@
*/
'use strict';
Application.Controllers.controller('StatisticsController', ['$scope', '$state', '$rootScope', '$uibModal', 'es', 'Member', '_t', 'membersPromise', 'statisticsPromise', 'uiTourService', 'settingsPromise',
function ($scope, $state, $rootScope, $uibModal, es, Member, _t, membersPromise, statisticsPromise, uiTourService, settingsPromise) {
Application.Controllers.controller('StatisticsController', ['$scope', '$state', '$transitions', '$rootScope', '$uibModal', 'es', 'Member', '_t', 'membersPromise', 'statisticsPromise', 'uiTourService', 'settingsPromise',
function ($scope, $state, $transitions, $rootScope, $uibModal, es, Member, _t, membersPromise, statisticsPromise, uiTourService, settingsPromise) {
/* PRIVATE STATIC CONSTANTS */
// search window size
@ -407,8 +407,8 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
const initialize = function () {
// workaround for angular-bootstrap::tabs behavior: on tab deletion, another tab will be selected
// which will cause every tabs to reload, one by one, when the view is closed
$rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
if ((fromState.name === 'app.admin.statistics') && (Object.keys(fromParams).length === 0)) {
$transitions.onStart({ to: 'app.admin.statistics' }, function (trans) {
if (Object.keys(trans.from().params).length === 0) {
return $scope.preventRefresh = true;
}
});
@ -522,9 +522,7 @@ Application.Controllers.controller('StatisticsController', ['$scope', '$state',
bool: {
must: [
{
term: {
type: type
}
term: { type }
},
{
range: {

View File

@ -45,13 +45,13 @@ Application.Controllers.controller('TagsController', ['$scope', 'tagsPromise', '
$scope.saveTag = function (data, id) {
if (id != null) {
return Tag.update({ id }, { tag: data }, response => growl.success(_t('app.admin.members.tag_form.changes_successfully_saved'))
, error => growl.error(_t('app.admin.members.tag_form.an_error_occurred_while_saving_changes')));
, () => growl.error(_t('app.admin.members.tag_form.an_error_occurred_while_saving_changes')));
} else {
return Tag.save({ tag: data }, function (resp) {
growl.success(_t('app.admin.members.tag_form.new_tag_successfully_saved'));
return $scope.tags[$scope.tags.length - 1].id = resp.id;
}
, function (error) {
, function () {
growl.error(_t('app.admin.members.tag_form.an_error_occurred_while_saving_the_new_tag'));
return $scope.tags.splice($scope.tags.length - 1, 1);
});
@ -78,7 +78,7 @@ Application.Controllers.controller('TagsController', ['$scope', 'tagsPromise', '
growl.success(_t('app.admin.members.tag_form.tag_successfully_deleted'));
return $scope.tags.splice(index, 1);
}
, error => growl.error(_t('app.admin.members.tag_form.an_error_occurred_and_the_tag_deletion_failed')));
, () => growl.error(_t('app.admin.members.tag_form.an_error_occurred_and_the_tag_deletion_failed')));
});
}

View File

@ -114,15 +114,15 @@ Application.Controllers.controller('NewTrainingController', ['$scope', '$state',
/**
* Controller used in the training edition page (admin)
*/
Application.Controllers.controller('EditTrainingController', ['$scope', '$state', '$stateParams', 'trainingPromise', 'machinesPromise', 'CSRF',
function ($scope, $state, $stateParams, trainingPromise, machinesPromise, CSRF) {
Application.Controllers.controller('EditTrainingController', ['$scope', '$state', '$transition$', 'trainingPromise', 'machinesPromise', 'CSRF',
function ($scope, $state, $transition$, trainingPromise, machinesPromise, CSRF) {
/* PUBLIC SCOPE */
// Form action on the following URL
$scope.method = 'patch';
// API URL where the form will be posted
$scope.actionUrl = `/api/trainings/${$stateParams.id}`;
$scope.actionUrl = `/api/trainings/${$transition$.params().id}`;
// Details of the training to edit (id in URL)
$scope.training = trainingPromise;

View File

@ -12,8 +12,8 @@
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
Application.Controllers.controller('ApplicationController', ['$rootScope', '$scope', '$window', '$locale', '$timeout', 'Session', 'AuthService', 'Auth', '$uibModal', '$state', 'growl', 'Notification', '$interval', 'Setting', '_t', 'Version', 'Help',
function ($rootScope, $scope, $window, $locale, $timeout, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version, Help) {
Application.Controllers.controller('ApplicationController', ['$rootScope', '$scope', '$transitions', '$window', '$locale', '$timeout', 'Session', 'AuthService', 'Auth', '$uibModal', '$state', 'growl', 'Notification', '$interval', 'Setting', '_t', 'Version', 'Help',
function ($rootScope, $scope, $transitions, $window, $locale, $timeout, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version, Help) {
/* PRIVATE STATIC CONSTANTS */
// User's notifications will get refreshed every 30s
@ -325,19 +325,18 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
$rootScope.toCheckNotifications = false;
});
// bind to the $stateChangeStart event (AngularJS/UI-Router)
$rootScope.$on('$stateChangeStart', function (event, toState, toParams) {
if (!toState.data) { return; }
// bind to the $transitions.onStart event (UI-Router)
$transitions.onStart({}, function (trans) {
if (!trans.$to().data) { return; }
const { authorizedRoles } = toState.data;
const { authorizedRoles } = trans.$to().data;
if (!AuthService.isAuthorized(authorizedRoles)) {
event.preventDefault();
if (AuthService.isAuthenticated()) {
// user is not allowed
console.error('[ApplicationController::initialize] user is not allowed');
} else {
// user is not logged in
openLoginModal(toState, toParams);
openLoginModal(trans.$to().name, trans.$to().params);
}
}
});
@ -462,6 +461,7 @@ Application.Controllers.controller('ApplicationController', ['$rootScope', '$sco
// what to do when the modal is closed
// authentication succeeded, set the session, gather the notifications and redirect
GTM.trackLogin();
$scope.setCurrentUser(user);
if ((toState !== null) && (toParams !== null)) {

View File

@ -13,28 +13,20 @@ Application.Controllers.controller('CookiesController', ['$scope', '$cookies', '
// link pointed by "learn more"
$scope.learnMoreUrl = 'https://www.cookiesandyou.com/';
// current user wallet
// add a cookie to the browser, saving the user choice to refuse cookies
$scope.declineCookies = function () {
const expires = moment().add(13, 'months').toDate();
$cookies.put('fab-manager-cookies-consent', 'decline', { expires });
readCookie();
};
// current wallet transactions
// add a cookie to the browser, saving the user choice to accept cookies.
// Then enable the analytics
$scope.acceptCookies = function () {
const expires = moment().add(13, 'months').toDate();
$cookies.put('fab-manager-cookies-consent', 'accept', { expires });
readCookie();
// enable tracking using code provided by google analytics
/* eslint-disable */
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', Fablab.trackingId, 'auto');
ga('send', 'pageview');
/* eslint-enable */
GTM.enableAnalytics(Fablab.trackingId);
};
/* PRIVATE SCOPE */
@ -44,7 +36,7 @@ Application.Controllers.controller('CookiesController', ['$scope', '$cookies', '
*/
const initialize = function () {
readCookie();
// if the privacy policy was defined, redirect the user to it
// if the privacy policy was defined, redirect the user to it when clicking on "read more"
Setting.get({ name: 'privacy_body' }, data => {
if (data.setting.value) {
$scope.learnMoreUrl = '#!/privacy-policy';

View File

@ -126,8 +126,8 @@ Application.Controllers.controller('EventsController', ['$scope', '$state', 'Eve
}
]);
Application.Controllers.controller('ShowEventController', ['$scope', '$state', '$stateParams', '$rootScope', 'Event', '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'Slot', 'eventPromise', 'growl', '_t', 'Wallet', 'AuthService', 'helpers', 'dialogs', 'priceCategoriesPromise', 'settingsPromise', 'LocalPayment',
function ($scope, $state, $stateParams, $rootScope, Event, $uibModal, Member, Reservation, Price, CustomAsset, Slot, eventPromise, growl, _t, Wallet, AuthService, helpers, dialogs, priceCategoriesPromise, settingsPromise, LocalPayment) {
Application.Controllers.controller('ShowEventController', ['$scope', '$state', '$rootScope', 'Event', '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'Slot', 'eventPromise', 'growl', '_t', 'Wallet', 'AuthService', 'helpers', 'dialogs', 'priceCategoriesPromise', 'settingsPromise', 'LocalPayment',
function ($scope, $state,$rootScope, Event, $uibModal, Member, Reservation, Price, CustomAsset, Slot, eventPromise, growl, _t, Wallet, AuthService, helpers, dialogs, priceCategoriesPromise, settingsPromise, LocalPayment) {
/* PUBLIC SCOPE */
// reservations for the currently shown event

View File

@ -1,11 +1,11 @@
'use strict';
Application.Controllers.controller('HeaderController', ['$scope', '$rootScope', '$state', 'settingsPromise',
function ($scope, $rootScope, $state, settingsPromise) {
Application.Controllers.controller('HeaderController', ['$scope', '$transitions', '$state', 'settingsPromise',
function ($scope, $transitions, $state, settingsPromise) {
$scope.aboutPage = ($state.current.name === 'app.public.about');
$rootScope.$on('$stateChangeStart', function (event, toState) {
$scope.aboutPage = (toState.name === 'app.public.about');
$transitions.onStart({}, function (trans) {
$scope.aboutPage = (trans.$to().name === 'app.public.about');
});
/**

View File

@ -1,7 +1,7 @@
'use strict';
Application.Controllers.controller('HomeController', ['$scope', '$stateParams', '$translatePartialLoader', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', '_t',
function ($scope, $stateParams, $translatePartialLoader, AuthService, settingsPromise, Member, uiTourService, _t) {
Application.Controllers.controller('HomeController', ['$scope', '$transition$', '$translatePartialLoader', 'AuthService', 'settingsPromise', 'Member', 'uiTourService', '_t',
function ($scope, $transition$, $translatePartialLoader, AuthService, settingsPromise, Member, uiTourService, _t) {
/* PUBLIC SCOPE */
// Home page HTML content
@ -38,8 +38,8 @@ Application.Controllers.controller('HomeController', ['$scope', '$stateParams',
const initialize = function () {
// if we receive a token to reset the password as GET parameter, trigger the
// changePassword modal from the parent controller
if ($stateParams.reset_password_token) {
return $scope.$parent.editPassword($stateParams.reset_password_token);
if ($transition$.params().reset_password_token) {
return $scope.$parent.editPassword($transition$.params().reset_password_token);
}
// We set the home page content, with the directives replacing the placeholders

View File

@ -245,12 +245,12 @@ Application.Controllers.controller('NewMachineController', ['$scope', '$state',
/**
* Controller used in the machine edition page (admin)
*/
Application.Controllers.controller('EditMachineController', ['$scope', '$state', '$stateParams', 'machinePromise', 'CSRF',
function ($scope, $state, $stateParams, machinePromise, CSRF) {
Application.Controllers.controller('EditMachineController', ['$scope', '$state', '$transition$', 'machinePromise', 'CSRF',
function ($scope, $state, $transition$, machinePromise, CSRF) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/machines/${$stateParams.id}`;
$scope.actionUrl = `/api/machines/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';
@ -278,8 +278,8 @@ Application.Controllers.controller('EditMachineController', ['$scope', '$state',
/**
* Controller used in the machine details page (public)
*/
Application.Controllers.controller('ShowMachineController', ['$scope', '$state', '$uibModal', '$stateParams', '_t', 'Machine', 'growl', 'machinePromise', 'dialogs',
function ($scope, $state, $uibModal, $stateParams, _t, Machine, growl, machinePromise, dialogs) {
Application.Controllers.controller('ShowMachineController', ['$scope', '$state', '$uibModal', '_t', 'Machine', 'growl', 'machinePromise', 'dialogs',
function ($scope, $state, $uibModal, _t, Machine, growl, machinePromise, dialogs) {
// Retrieve the details for the machine id in the URL, if an error occurs redirect the user to the machines list
$scope.machine = machinePromise;
@ -357,8 +357,8 @@ Application.Controllers.controller('ShowMachineController', ['$scope', '$state',
* This controller workflow is pretty similar to the trainings reservation controller.
*/
Application.Controllers.controller('ReserveMachineController', ['$scope', '$stateParams', '_t', 'moment', 'Auth', '$timeout', 'Member', 'Availability', 'plansPromise', 'groupsPromise', 'machinePromise', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig', 'Reservation', 'growl',
function ($scope, $stateParams, _t, moment, Auth, $timeout, Member, Availability, plansPromise, groupsPromise, machinePromise, settingsPromise, uiCalendarConfig, CalendarConfig, Reservation, growl) {
Application.Controllers.controller('ReserveMachineController', ['$scope', '$transition$', '_t', 'moment', 'Auth', '$timeout', 'Member', 'Availability', 'plansPromise', 'groupsPromise', 'machinePromise', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig', 'Reservation', 'growl',
function ($scope, $transition$, _t, moment, Auth, $timeout, Member, Availability, plansPromise, groupsPromise, machinePromise, settingsPromise, uiCalendarConfig, CalendarConfig, Reservation, growl) {
/* PRIVATE STATIC CONSTANTS */
// Slot free to be booked
@ -660,7 +660,7 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat
const initialize = function () {
$scope.eventSources.push({
events: function (start, end, timezone, callback) {
Availability.machine({ machineId: $stateParams.id }, function (availabilities) {
Availability.machine({ machineId: $transition$.params().id }, function (availabilities) {
callback(availabilities);
});
},

View File

@ -323,7 +323,7 @@ Application.Controllers.controller('ShowProfileController', ['$scope', 'memberPr
* and return the filtered networks
* @return {Array}
*/
var filterNetworks = function () {
const filterNetworks = function () {
const networks = [];
for (const network of Array.from(SocialNetworks)) {
if ($scope.user.profile[network] && ($scope.user.profile[network].length > 0)) {

View File

@ -480,12 +480,12 @@ Application.Controllers.controller('NewProjectController', ['$rootScope', '$scop
/**
* Controller used in the project edition page
*/
Application.Controllers.controller('EditProjectController', ['$rootScope', '$scope', '$state', '$stateParams', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',
function ($rootScope, $scope, $state, $stateParams, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise, Diacritics, dialogs, allowedExtensions, _t) {
Application.Controllers.controller('EditProjectController', ['$rootScope', '$scope', '$state', '$transition$', 'Project', 'Machine', 'Member', 'Component', 'Theme', 'Licence', '$document', 'CSRF', 'projectPromise', 'Diacritics', 'dialogs', 'allowedExtensions', '_t',
function ($rootScope, $scope, $state, $transition$, Project, Machine, Member, Component, Theme, Licence, $document, CSRF, projectPromise, Diacritics, dialogs, allowedExtensions, _t) {
/* PUBLIC SCOPE */
// API URL where the form will be posted
$scope.actionUrl = `/api/projects/${$stateParams.id}`;
$scope.actionUrl = `/api/projects/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';
@ -618,7 +618,7 @@ Application.Controllers.controller('ShowProjectController', ['$scope', '$state',
growl.success(_t('app.public.projects_show.your_report_was_successful_thanks'));
return $uibModalInstance.close(res);
}
, function (error) {
, function () {
// creation failed...
growl.error(_t('app.public.projects_show.an_error_occured_while_sending_your_report'));
}

View File

@ -234,12 +234,12 @@ Application.Controllers.controller('NewSpaceController', ['$scope', '$state', 'C
/**
* Controller used in the space edition page (admin)
*/
Application.Controllers.controller('EditSpaceController', ['$scope', '$state', '$stateParams', 'spacePromise', 'CSRF',
function ($scope, $state, $stateParams, spacePromise, CSRF) {
Application.Controllers.controller('EditSpaceController', ['$scope', '$state', '$transition$', 'spacePromise', 'CSRF',
function ($scope, $state, $transition$, spacePromise, CSRF) {
CSRF.setMetaTags();
// API URL where the form will be posted
$scope.actionUrl = `/api/spaces/${$stateParams.id}`;
$scope.actionUrl = `/api/spaces/${$transition$.params().id}`;
// Form action on the above URL
$scope.method = 'put';
@ -307,8 +307,8 @@ Application.Controllers.controller('ShowSpaceController', ['$scope', '$state', '
* per slots.
*/
Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateParams', 'Auth', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $stateParams, Auth, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
Application.Controllers.controller('ReserveSpaceController', ['$scope', '$transition$', 'Auth', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'spacePromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $transition$, Auth, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, spacePromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
/* PRIVATE STATIC CONSTANTS */
// Color of the selected event backgound
@ -601,7 +601,7 @@ Application.Controllers.controller('ReserveSpaceController', ['$scope', '$stateP
// in the router because this allows to refetchEvents from fullCalendar API.
$scope.eventSources.push({
events: function (start, end, timezone, callback) {
Availability.spaces({ spaceId: $stateParams.id }, function (availabilities) {
Availability.spaces({ spaceId: $transition$.params().id }, function (availabilities) {
callback(availabilities);
});
},

View File

@ -91,8 +91,8 @@ Application.Controllers.controller('ShowTrainingController', ['$scope', '$state'
* training can be reserved during the reservation process (the shopping cart may contains only one training and a subscription).
*/
Application.Controllers.controller('ReserveTrainingController', ['$scope', '$stateParams', 'Auth', 'AuthService', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $stateParams, Auth, AuthService, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
Application.Controllers.controller('ReserveTrainingController', ['$scope', '$transition$', 'Auth', 'AuthService', '$timeout', 'Availability', 'Member', 'plansPromise', 'groupsPromise', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig', 'Reservation',
function ($scope, $transition$, Auth, AuthService, $timeout, Availability, Member, plansPromise, groupsPromise, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig, Reservation) {
/* PRIVATE STATIC CONSTANTS */
// Color of the selected event backgound
@ -144,7 +144,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
$scope.training = trainingPromise;
// 'all' OR training's slug
$scope.mode = $stateParams.id;
$scope.mode = $transition$.params().id;
// fullCalendar (v2) configuration
$scope.calendarConfig = CalendarConfig({
@ -279,7 +279,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
if ($scope.ctrl.member) {
Member.get({ id: $scope.ctrl.member.id }, function (member) {
$scope.ctrl.member = member;
const id = $stateParams.id === 'all' ? $stateParams.id : $scope.training.id;
const id = $transition$.params().id === 'all' ? $transition$.params().id : $scope.training.id;
return Availability.trainings({ trainingId: id, member_id: $scope.ctrl.member.id }, function (trainings) {
uiCalendarConfig.calendars.calendar.fullCalendar('removeEvents');
return $scope.eventSources.splice(0, 1, {
@ -391,7 +391,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
// in the router because this allows to refetchEvents from fullCalendar API.
$scope.eventSources.push({
events: function (start, end, timezone, callback) {
Availability.trainings({ trainingId: $stateParams.id }, function (availabilities) {
Availability.trainings({ trainingId: $transition$.params().id }, function (availabilities) {
callback(availabilities);
});
},
@ -408,7 +408,7 @@ Application.Controllers.controller('ReserveTrainingController', ['$scope', '$sta
*/
const calendarEventClickCb = function (event, jsEvent, view) {
$scope.selectedEvent = event;
if ($stateParams.id === 'all') {
if ($transition$.params().id === 'all') {
$scope.training = event.training;
}
return $scope.selectionTime = new Date();

View File

@ -4,9 +4,9 @@ Application.Directives.directive('bsJasnyFileinput', [function () {
return {
require: ['ngModel'],
link: function ($scope, elm, attrs, requiredCtrls) {
var ngModelCtrl = requiredCtrls[0];
var fileinput = elm.parents('[data-provides=fileinput]');
var filetypeRegex = attrs.bsJasnyFileinput;
const ngModelCtrl = requiredCtrls[0];
const fileinput = elm.parents('[data-provides=fileinput]');
const filetypeRegex = attrs.bsJasnyFileinput;
fileinput.on('clear.bs.fileinput', function (e) {
if (ngModelCtrl) {
ngModelCtrl.$setViewValue(null);

View File

@ -1,8 +1,3 @@
/* eslint-disable
no-undef,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
@ -135,7 +130,7 @@ Application.Filters.filter('projectsCollabored', [function () {
};
}]);
// depend on humanize.js lib in /vendor
// depend on app/frontend/src/javascript/lib/humanize.js
Application.Filters.filter('humanize', [function () {
return (element, param) => Humanize.truncate(element, param, null);
}]);
@ -157,6 +152,8 @@ Application.Filters.filter('breakFilter', [function () {
Application.Filters.filter('simpleText', [function () {
return function (text) {
if (text != null) {
// add a line break after specific closing tags
text = text.replace(/(<\/p>|<\/h4>|<\/h5>|<\/h6>|<\/pre>|<\/blockquote>)/g, '\n');
text = text.replace(/<br\s*\/?>/g, '\n');
return text.replace(/<\/?\w+[^>]*>/g, '');
} else {
@ -166,7 +163,7 @@ Application.Filters.filter('simpleText', [function () {
}]);
Application.Filters.filter('toTrusted', ['$sce', function ($sce) {
return text => $sce.getTrustedHtml(text);
return text => $sce.trustAsHtml(text);
}]);
Application.Filters.filter('planIntervalFilter', [function () {

View File

@ -11,7 +11,7 @@
'Auth',
'$rootScope',
function ($uibModal, $http, Auth, $rootScope) {
var promise = null;
let promise = null;
function reset () {
promise = null;
}

View File

@ -46,7 +46,7 @@ angular.module('angularUtils.directives.dirDisqus', [])
// get the remote Disqus script and insert it into the DOM, but only if it not already loaded (as that will cause warnings)
if (!$window.DISQUS) {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
const dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + scope.disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
} else {

View File

@ -9,7 +9,7 @@ export default class FormatLib {
*/
static date = (date: Date): string => {
return Intl.DateTimeFormat().format(moment(date).toDate());
}
};
/**
* Return the formatted localized time for the given date
@ -23,12 +23,12 @@ export default class FormatLib {
*/
static duration = (interval: unitOfTime.DurationConstructor, intervalCount: number): string => {
return moment.duration(intervalCount, interval).locale(Fablab.moment_locale).humanize();
}
};
/**
* Return the formatted localized amount for the given price (eg. 20.5 => "20,50 €")
*/
static price = (price: number): string => {
return new Intl.NumberFormat(Fablab.intl_locale, { style: 'currency', currency: Fablab.intl_currency }).format(price);
}
};
}

View File

@ -0,0 +1,43 @@
// this script loads the google tag manager, used by Google Analytics V4
(function () {
const GTM = {};
window.dataLayer = window.dataLayer || [];
function gtag () { window.dataLayer.push(arguments); }
GTM.enableAnalytics = function (trackingId) {
gtag('js', new Date());
gtag('config', trackingId);
const node = document.createElement('script');
const firstScript = document.getElementsByTagName('script')[0];
node.async = true;
node.src = `//www.googletagmanager.com/gtag/js?id=${trackingId}`;
firstScript.parentNode.insertBefore(node, firstScript);
};
GTM.trackPage = function (url, title) {
gtag('event', 'page_view', {
page_location: url,
page_title: title
});
};
GTM.trackLogin = function () {
gtag('event', 'login');
};
GTM.trackPurchase = function (transactionId, value) {
gtag('event', 'purchase', {
transaction_id: transactionId,
value,
currency: Fablab.intl_currency
});
};
this.GTM = GTM;
if (typeof module !== 'undefined' && module !== null) {
module.exports = GTM;
}
}).call(this);

View File

@ -1,23 +1,21 @@
(function () {
var Humanize, isArray, isFinite, isNaN, objectRef, timeFormats, toString;
const objectRef = new function () {}();
objectRef = new function () {}();
const toString = objectRef.toString;
toString = objectRef.toString;
isNaN = function (value) {
const isNaN = function (value) {
return Number.isNaN(value);
};
isFinite = function (value) {
const isFinite = function (value) {
return ((typeof window !== 'undefined' && window !== null ? window.isFinite : undefined) || global.isFinite)(value) && !isNaN(parseFloat(value));
};
isArray = function (value) {
const isArray = function (value) {
return toString.call(value) === '[object Array]';
};
timeFormats = [
const timeFormats = [
{
name: 'second',
value: 1e3
@ -36,7 +34,7 @@
}
];
Humanize = {};
const Humanize = {};
Humanize.intword = function (number, charWidth, decimals) {
if (decimals == null) {
@ -51,18 +49,18 @@
};
Humanize.compactInteger = function (input, decimals) {
var bigNumPrefixes, decimalIndex, decimalPart, decimalPartArray, length, number, numberLength, numberLengths, output, outputNumber, signString, unsignedNumber, unsignedNumberCharacterArray, unsignedNumberString, wholePart, wholePartArray, _i, _len, _length;
let decimalPart, length, output, outputNumber, unsignedNumberString, _i, _len, _length;
if (decimals == null) {
decimals = 0;
}
decimals = Math.max(decimals, 0);
number = parseInt(input, 10);
signString = number < 0 ? '-' : '';
unsignedNumber = Math.abs(number);
const number = parseInt(input, 10);
const signString = number < 0 ? '-' : '';
const unsignedNumber = Math.abs(number);
unsignedNumberString = '' + unsignedNumber;
numberLength = unsignedNumberString.length;
numberLengths = [13, 10, 7, 4];
bigNumPrefixes = ['T', 'B', 'M', 'k'];
const numberLength = unsignedNumberString.length;
const numberLengths = [13, 10, 7, 4];
const bigNumPrefixes = ['T', 'B', 'M', 'k'];
if (unsignedNumber < 1000) {
if (decimals > 0) {
unsignedNumberString += '.' + (Array(decimals + 1).join('0'));
@ -79,11 +77,11 @@
break;
}
}
decimalIndex = numberLength - length + 1;
unsignedNumberCharacterArray = unsignedNumberString.split('');
wholePartArray = unsignedNumberCharacterArray.slice(0, decimalIndex);
decimalPartArray = unsignedNumberCharacterArray.slice(decimalIndex, decimalIndex + decimals + 1);
wholePart = wholePartArray.join('');
const decimalIndex = numberLength - length + 1;
const unsignedNumberCharacterArray = unsignedNumberString.split('');
const wholePartArray = unsignedNumberCharacterArray.slice(0, decimalIndex);
const decimalPartArray = unsignedNumberCharacterArray.slice(decimalIndex, decimalIndex + decimals + 1);
const wholePart = wholePartArray.join('');
decimalPart = decimalPartArray.join('');
if (decimalPart.length < decimals) {
decimalPart += '' + (Array(decimals - decimalPart.length + 1).join('0'));
@ -105,7 +103,7 @@
};
Humanize.filesize = Humanize.fileSize = function (filesize) {
var sizeStr;
let sizeStr;
if (filesize >= 1073741824) {
sizeStr = Humanize.formatNumber(filesize / 1073741824, 2, '') + ' GB';
} else if (filesize >= 1048576) {
@ -119,7 +117,6 @@
};
Humanize.formatNumber = function (number, precision, thousand, decimal) {
var base; var commas; var decimals; var firstComma; var mod; var negative; var usePrecision;
if (precision == null) {
precision = 0;
}
@ -129,36 +126,35 @@
if (decimal == null) {
decimal = '.';
}
firstComma = function (number, thousand, position) {
const firstComma = function (number, thousand, position) {
if (position) {
return number.substr(0, position) + thousand;
} else {
return '';
}
};
commas = function (number, thousand, position) {
const commas = function (number, thousand, position) {
return number.substr(position).replace(/(\d{3})(?=\d)/g, '$1' + thousand);
};
decimals = function (number, decimal, usePrecision) {
const decimals = function (number, decimal, usePrecision) {
if (usePrecision) {
return decimal + Humanize.toFixed(Math.abs(number), usePrecision).split('.')[1];
} else {
return '';
}
};
usePrecision = Humanize.normalizePrecision(precision);
negative = number < 0 ? '-' : '';
base = parseInt(Humanize.toFixed(Math.abs(number || 0), usePrecision), 10) + '';
mod = base.length > 3 ? base.length % 3 : 0;
const usePrecision = Humanize.normalizePrecision(precision);
const negative = number < 0 ? '-' : '';
const base = parseInt(Humanize.toFixed(Math.abs(number || 0), usePrecision), 10) + '';
const mod = base.length > 3 ? base.length % 3 : 0;
return negative + firstComma(base, thousand, mod) + commas(base, thousand, mod) + decimals(number, decimal, usePrecision);
};
Humanize.toFixed = function (value, precision) {
var power;
if (precision == null) {
precision = Humanize.normalizePrecision(precision, 0);
}
power = Math.pow(10, precision);
const power = Math.pow(10, precision);
return (Math.round(value * power) / power).toFixed(precision);
};
@ -172,16 +168,16 @@
};
Humanize.ordinal = function (value) {
var end, leastSignificant, number, specialCase;
number = parseInt(value, 10);
let end;
const number = parseInt(value, 10);
if (number === 0) {
return value;
}
specialCase = number % 100;
const specialCase = number % 100;
if (specialCase === 11 || specialCase === 12 || specialCase === 13) {
return '' + number + 'th';
}
leastSignificant = number % 10;
const leastSignificant = number % 10;
switch (leastSignificant) {
case 1:
end = 'st';
@ -199,7 +195,7 @@
};
Humanize.times = function (value, overrides) {
var number, smallTimes, _ref;
let number, smallTimes, _ref;
if (overrides == null) {
overrides = {};
}
@ -243,8 +239,8 @@
};
Humanize.truncatewords = Humanize.truncateWords = function (string, length) {
var array, i, result;
array = string.split(' ');
let i, result;
const array = string.split(' ');
result = '';
i = 0;
while (i < length) {
@ -259,7 +255,7 @@
};
Humanize.truncatenumber = Humanize.boundedNumber = function (num, bound, ending) {
var result;
let result;
if (bound == null) {
bound = 100;
}
@ -276,8 +272,8 @@
};
Humanize.oxford = function (items, limit, limitStr) {
var extra, limitIndex, numItems;
numItems = items.length;
let extra, limitIndex;
const numItems = items.length;
if (numItems < 2) {
return '' + items;
} else if (numItems === 2) {
@ -296,7 +292,7 @@
};
Humanize.dictionary = function (object, joiner, separator) {
var defs, key, result, val;
let defs, key, result, val;
if (joiner == null) {
joiner = ' is ';
}
@ -316,12 +312,12 @@
};
Humanize.frequency = function (list, verb) {
var len, str, times;
let str;
if (!isArray(list)) {
return;
}
len = list.length;
times = Humanize.times(len);
const len = list.length;
const times = Humanize.times(len);
if (len === 0) {
str = '' + times + ' ' + verb;
} else {
@ -331,7 +327,7 @@
};
Humanize.pace = function (value, intervalMs, unit) {
var f, prefix, rate, relativePace, roundedPace, timeUnit, _i, _len;
let f, prefix, relativePace, timeUnit, _i, _len;
if (unit == null) {
unit = 'time';
}
@ -340,7 +336,7 @@
}
prefix = 'Approximately';
timeUnit = null;
rate = value / intervalMs;
const rate = value / intervalMs;
for (_i = 0, _len = timeFormats.length; _i < _len; _i++) {
f = timeFormats[_i];
relativePace = rate * f.value;
@ -354,7 +350,7 @@
relativePace = 1;
timeUnit = timeFormats[timeFormats.length - 1].name;
}
roundedPace = Math.round(relativePace);
const roundedPace = Math.round(relativePace);
unit = Humanize.pluralize(roundedPace, unit);
return '' + prefix + ' ' + roundedPace + ' ' + unit + ' per ' + timeUnit;
};
@ -387,21 +383,20 @@
};
Humanize.titlecase = Humanize.titleCase = function (string) {
var doTitleCase; var internalCaps; var smallWords; var splitOnHyphensRegex; var splitOnWhiteSpaceRegex;
smallWords = /\b(a|an|and|at|but|by|de|en|for|if|in|of|on|or|the|to|via|vs?\.?)\b/i;
internalCaps = /\S+[A-Z]+\S*/;
splitOnWhiteSpaceRegex = /\s+/;
splitOnHyphensRegex = /-/;
doTitleCase = function (_string, hyphenated, firstOrLast) {
var index, stringArray, titleCasedArray, word, _i, _len;
const smallWords = /\b(a|an|and|at|but|by|de|en|for|if|in|of|on|or|the|to|via|vs?\.?)\b/i;
const internalCaps = /\S+[A-Z]+\S*/;
const splitOnWhiteSpaceRegex = /\s+/;
const splitOnHyphensRegex = /-/;
const doTitleCase = function (_string, hyphenated, firstOrLast) {
let index, word, _i, _len;
if (hyphenated == null) {
hyphenated = false;
}
if (firstOrLast == null) {
firstOrLast = true;
}
titleCasedArray = [];
stringArray = _string.split(hyphenated ? splitOnHyphensRegex : splitOnWhiteSpaceRegex);
const titleCasedArray = [];
const stringArray = _string.split(hyphenated ? splitOnHyphensRegex : splitOnWhiteSpaceRegex);
for (index = _i = 0, _len = stringArray.length; _i < _len; index = ++_i) {
word = stringArray[index];
if (word.indexOf('-') !== -1) {

View File

@ -7,13 +7,13 @@ if (typeof Object.assign !== 'function') {
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
const to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
for (let index = 1; index < arguments.length; index++) {
const nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
for (const nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];

View File

@ -18,5 +18,5 @@ export default class UserLib {
}
return false;
}
};
}

View File

@ -16,5 +16,5 @@ export default class WalletLib {
} else {
return price - this.wallet.amount;
}
}
};
}

View File

@ -0,0 +1,6 @@
export interface GoogleTagManager {
enableAnalytics: (trackingId: string) => void,
trackPage: (url: string, title: string) => void,
trackLogin: () => void,
trackPurchase: (transactionId: number, value: number) => void,
}

View File

@ -1,14 +1,3 @@
/* eslint-disable
no-return-assign,
no-undef,
*/
// TODO: This file was created by bulk-decaffeinate.
// Fix any style issues and re-enable lint.
/*
* decaffeinate suggestions:
* DS102: Remove unnecessary code created because of implicit returns
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
angular.module('application.router', ['ui.router'])
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function ($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.hashPrefix('!');
@ -243,7 +232,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
memberPromise: ['$stateParams', 'Member', function ($stateParams, Member) { return Member.get({ id: $stateParams.id }).$promise; }]
memberPromise: ['$transition$', 'Member', function ($transition$, Member) { return Member.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.members', {
@ -297,7 +286,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
projectPromise: ['$stateParams', 'Project', function ($stateParams, Project) { return Project.get({ id: $stateParams.id }).$promise; }],
projectPromise: ['$transition$', 'Project', function ($transition$, Project) { return Project.get({ id: $transition$.params().id }).$promise; }],
shortnamePromise: ['Setting', function (Setting) { return Setting.get({ name: 'disqus_shortname' }).$promise; }]
}
})
@ -310,7 +299,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
projectPromise: ['$stateParams', 'Project', function ($stateParams, Project) { return Project.get({ id: $stateParams.id }).$promise; }],
projectPromise: ['$transition$', 'Project', function ($transition$, Project) { return Project.get({ id: $transition$.params().id }).$promise; }],
allowedExtensions: ['Setting', function (Setting) { return Setting.get({ name: 'allowed_cad_extensions' }).$promise; }]
}
})
@ -347,7 +336,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }]
machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.machines_reserve', {
@ -361,7 +350,7 @@ angular.module('application.router', ['ui.router'])
resolve: {
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],
machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }],
machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }],
settingsPromise: ['Setting', function (Setting) {
return Setting.query({
names: "['machine_explications_alert', 'booking_window_start', 'booking_window_end', 'booking_move_enable', " +
@ -380,7 +369,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
machinePromise: ['Machine', '$stateParams', function (Machine, $stateParams) { return Machine.get({ id: $stateParams.id }).$promise; }]
machinePromise: ['Machine', '$transition$', function (Machine, $transition$) { return Machine.get({ id: $transition$.params().id }).$promise; }]
}
})
@ -419,7 +408,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }]
spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.admin.space_edit', {
@ -432,7 +421,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }]
spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.space_reserve', {
@ -445,7 +434,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
spacePromise: ['Space', '$stateParams', function (Space, $stateParams) { return Space.get({ id: $stateParams.id }).$promise; }],
spacePromise: ['Space', '$transition$', function (Space, $transition$) { return Space.get({ id: $transition$.params().id }).$promise; }],
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],
settingsPromise: ['Setting', function (Setting) {
@ -482,7 +471,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) { return Training.get({ id: $stateParams.id }).$promise; }]
trainingPromise: ['Training', '$transition$', function (Training, $transition$) { return Training.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.logged.trainings_reserve', {
@ -498,8 +487,8 @@ angular.module('application.router', ['ui.router'])
explicationAlertPromise: ['Setting', function (Setting) { return Setting.get({ name: 'training_explications_alert' }).$promise; }],
plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }],
groupsPromise: ['Group', function (Group) { return Group.query().$promise; }],
trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) {
if ($stateParams.id !== 'all') { return Training.get({ id: $stateParams.id }).$promise; }
trainingPromise: ['Training', '$transition$', function (Training, $transition$) {
if ($transition$.params().id !== 'all') { return Training.get({ id: $transition$.params().id }).$promise; }
}],
settingsPromise: ['Setting', function (Setting) {
return Setting.query({
@ -563,7 +552,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }],
eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],
priceCategoriesPromise: ['PriceCategory', function (PriceCategory) { return PriceCategory.query().$promise; }],
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['booking_move_enable', 'booking_move_delay', 'booking_cancel_enable', 'booking_cancel_delay', 'event_explications_alert', 'online_payment_module']" }).$promise; }]
}
@ -694,7 +683,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
trainingPromise: ['Training', '$stateParams', function (Training, $stateParams) { return Training.get({ id: $stateParams.id }).$promise; }],
trainingPromise: ['Training', '$transition$', function (Training, $transition$) { return Training.get({ id: $transition$.params().id }).$promise; }],
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }]
}
})
@ -740,7 +729,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }],
eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],
categoriesPromise: ['Category', function (Category) { return Category.query().$promise; }],
themesPromise: ['EventTheme', function (EventTheme) { return EventTheme.query().$promise; }],
ageRangesPromise: ['AgeRange', function (AgeRange) { return AgeRange.query().$promise; }],
@ -756,8 +745,8 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
eventPromise: ['Event', '$stateParams', function (Event, $stateParams) { return Event.get({ id: $stateParams.id }).$promise; }],
reservationsPromise: ['Reservation', '$stateParams', function (Reservation, $stateParams) { return Reservation.query({ reservable_id: $stateParams.id, reservable_type: 'Event' }).$promise; }]
eventPromise: ['Event', '$transition$', function (Event, $transition$) { return Event.get({ id: $transition$.params().id }).$promise; }],
reservationsPromise: ['Reservation', '$transition$', function (Reservation, $transition$) { return Reservation.query({ reservable_id: $transition$.params().id, reservable_type: 'Event' }).$promise; }]
}
})
@ -820,7 +809,7 @@ angular.module('application.router', ['ui.router'])
spaces: ['Space', function (Space) { return Space.query().$promise; }],
machines: ['Machine', function (Machine) { return Machine.query().$promise; }],
plans: ['Plan', function (Plan) { return Plan.query().$promise; }],
planPromise: ['Plan', '$stateParams', function (Plan, $stateParams) { return Plan.get({ id: $stateParams.id }).$promise; }],
planPromise: ['Plan', '$transition$', function (Plan, $transition$) { return Plan.get({ id: $transition$.params().id }).$promise; }],
planCategories: ['PlanCategory', function (PlanCategory) { return PlanCategory.query().$promise; }]
}
})
@ -854,7 +843,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
couponPromise: ['Coupon', '$stateParams', function (Coupon, $stateParams) { return Coupon.get({ id: $stateParams.id }).$promise; }]
couponPromise: ['Coupon', '$transition$', function (Coupon, $transition$) { return Coupon.get({ id: $transition$.params().id }).$promise; }]
}
})
@ -879,7 +868,8 @@ angular.module('application.router', ['ui.router'])
"'accounting_Machine_code', 'accounting_Machine_label', 'accounting_Training_code', 'accounting_Training_label', " +
"'accounting_Event_code', 'accounting_Event_label', 'accounting_Space_code', 'accounting_Space_label', " +
"'payment_gateway', 'accounting_Error_code', 'accounting_Error_label', 'payment_schedule_prefix', " +
"'feature_tour_display', 'online_payment_module', 'stripe_public_key', 'stripe_currency', 'invoice_prefix']"
"'feature_tour_display', 'online_payment_module', 'stripe_public_key', 'stripe_currency', 'invoice_prefix', " +
"'accounting_Pack_code', 'accounting_Pack_label']"
}).$promise;
}],
stripeSecretKey: ['Setting', function (Setting) { return Setting.isPresent({ name: 'stripe_secret_key' }).$promise; }],
@ -958,7 +948,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
importItem: ['Import', '$stateParams', function (Import, $stateParams) { return Import.get({ id: $stateParams.id }).$promise; }]
importItem: ['Import', '$transition$', function (Import, $transition$) { return Import.get({ id: $transition$.params().id }).$promise; }]
}
})
.state('app.admin.members_edit', {
@ -970,9 +960,9 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
memberPromise: ['Member', '$stateParams', function (Member, $stateParams) { return Member.get({ id: $stateParams.id }).$promise; }],
memberPromise: ['Member', '$transition$', function (Member, $transition$) { return Member.get({ id: $transition$.params().id }).$promise; }],
activeProviderPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.active().$promise; }],
walletPromise: ['Wallet', '$stateParams', function (Wallet, $stateParams) { return Wallet.getWalletByUser({ user_id: $stateParams.id }).$promise; }],
walletPromise: ['Wallet', '$transition$', function (Wallet, $transition$) { return Wallet.getWalletByUser({ user_id: $transition$.params().id }).$promise; }],
transactionsPromise: ['Wallet', 'walletPromise', function (Wallet, walletPromise) { return Wallet.transactions({ id: walletPromise.id }).$promise; }],
tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }],
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['phone_required', 'address_required']" }).$promise; }]
@ -1027,7 +1017,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
providerPromise: ['AuthProvider', '$stateParams', function (AuthProvider, $stateParams) { return AuthProvider.get({ id: $stateParams.id }).$promise; }],
providerPromise: ['AuthProvider', '$transition$', function (AuthProvider, $transition$) { return AuthProvider.get({ id: $transition$.params().id }).$promise; }],
mappingFieldsPromise: ['AuthProvider', function (AuthProvider) { return AuthProvider.mapping_fields().$promise; }]
}
})
@ -1083,7 +1073,7 @@ angular.module('application.router', ['ui.router'])
"'display_name_enable', 'machines_sort_by', 'fab_analytics', 'statistics_module', 'address_required', " +
"'link_name', 'home_content', 'home_css', 'phone_required', 'upcoming_events_shown', 'public_agenda_module'," +
"'renew_pack_threshold', 'pack_only_for_subscription', 'overlapping_categories', 'public_registrations'," +
"'extended_prices_in_same_day']"
"'extended_prices_in_same_day', 'recaptcha_site_key', 'recaptcha_secret_key']"
}).$promise;
}],
privacyDraftsPromise: ['Setting', function (Setting) { return Setting.get({ name: 'privacy_draft', history: true }).$promise; }],

View File

@ -14,7 +14,7 @@ Application.Services.service('Diacritics', [
* @returns {string} without diacritics
*/
remove: function (str) {
var defaultDiacriticsRemovalap = [
const defaultDiacriticsRemovalap = [
{ base: 'A', letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F' },
{ base: 'AA', letters: '\uA732' },
{ base: 'AE', letters: '\u00C6\u01FC\u01E2' },
@ -103,10 +103,10 @@ Application.Services.service('Diacritics', [
{ base: 'z', letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763' }
];
var diacriticsMap = {};
for (var i = 0; i < defaultDiacriticsRemovalap.length; i++) {
var letters = defaultDiacriticsRemovalap[i].letters.split('');
for (var j = 0; j < letters.length; j++) {
const diacriticsMap = {};
for (let i = 0; i < defaultDiacriticsRemovalap.length; i++) {
const letters = defaultDiacriticsRemovalap[i].letters.split('');
for (let j = 0; j < letters.length; j++) {
diacriticsMap[letters[j]] = defaultDiacriticsRemovalap[i].base;
}
}

View File

@ -1,3 +1,5 @@
@use "sass:math";
// This is the default html and body font-size for the base rem value.
$rem-base: 10px !default;
@ -20,12 +22,12 @@ $modules: () !default;
// STRIP UNIT
// It strips the unit of measure and returns it
@function strip-unit($num) {
@return $num / ($num * 0 + 1);
@return math.div($num, $num * 0 + 1);
}
// CONVERT TO REM
@function convert-to-rem($value, $base-value: $rem-base) {
$value: strip-unit($value) / strip-unit($base-value) * 1rem;
$value: math.div(strip-unit($value), strip-unit($base-value)) * 1rem;
@if $value == 0rem {
$value: 0;

View File

@ -1,3 +1,5 @@
@use 'sass:math';
/*layout*/
.header,
.footer {
@ -286,8 +288,8 @@ body.container {
height: $header-md-height;
.navbar-form {
margin-top: floor(($header-md-height - 30) / 2);
margin-bottom: floor(($header-md-height - 30) / 2);
margin-top: floor(math.div($header-md-height - 30, 2));
margin-bottom: floor(math.div($header-md-height - 30, 2));
}
}
@ -689,7 +691,7 @@ body.container {
cursor: pointer;
& .Event-picture {opacity: 0.7;}
}
&-picture {
height: 250px;
background-color: #fff;
@ -701,7 +703,7 @@ body.container {
object-fit: cover;
}
}
&-desc {
position: relative;
padding: 15px;

View File

@ -1,3 +1,5 @@
@use 'sass:math';
/*primary nav*/
.navbar-header {
position: relative;
@ -42,7 +44,7 @@
.nav-primary {
li {
> a > i {
margin: floor(-($nav-primary-height - $line-height-computed) / 2) -10px;
margin: floor(math.div(-($nav-primary-height - $line-height-computed), 2)) -10px;
line-height: $nav-primary-height;
width: $nav-primary-height;
float: left;
@ -61,7 +63,7 @@
ul.nav {
> li {
> a {
padding: floor(($nav-primary-height - $line-height-computed) / 2) 15px;
padding: floor(math.div($nav-primary-height - $line-height-computed, 2)) 15px;
position: relative;
font-size: 14px;
@ -245,7 +247,7 @@
> .vbox > .header,
> .vbox > .footer {
padding: 0 floor(($nav-xs-width - 30px) / 2);
padding: 0 floor(math.div($nav-xs-width - 30px, 2));
}
.hidden-nav-xs {
@ -309,7 +311,7 @@
> li {
> a {
.header-md & {
padding: floor(($header-md-height - $line-height-computed) / 2 - 1);
padding: floor(math.div($header-md-height - $line-height-computed, 2) - 1);
}
}
}
@ -326,7 +328,7 @@
// + *{
// padding-top: 50px !important;
// }
}
.nav-bar-fixed-bottom {
@ -518,7 +520,7 @@
border-left: 3px solid;
// #870003;
}
}
}

View File

@ -1 +1,3 @@
@import "~fullcalendar/dist/fullcalendar.print";
@media print {
@import "~fullcalendar/dist/fullcalendar.print";
}

View File

@ -1,25 +1,28 @@
.cookies-consent {
display: flex;
position: fixed;
bottom: 3rem;
left: 3rem;
width: 40rem;
right: 0;
bottom: 0;
left: 0;
background-color: #f5f5f5;
padding: 3rem;
flex-direction: column;
z-index: 100;
-webkit-box-shadow: 0 4px 10px 2px rgba(224, 224, 224, 0.43);
-moz-box-shadow: 0 4px 10px 2px rgba(224, 224, 224, 0.43);
box-shadow: 0 4px 10px 2px rgba(224, 224, 224, 0.43);
-webkit-box-shadow: 0 4px 10px 2px rgba(0, 0, 0, 0.25);
-moz-box-shadow: 0 4px 10px 2px rgba(0, 0, 0, 0.25);
box-shadow: 0 4px 10px 2px rgba(0, 0, 0, 0.25);
.cookies-actions {
flex-wrap: wrap;
display: flex;
height: 45px;
justify-content: space-between;
gap: 1rem;
margin-top: 1rem;
button {
flex-basis: 50%;
@extend .fab-button;
flex: 1;
}
button.decline {
background-color: transparent;
border: 0;
@ -31,4 +34,10 @@
font-size: 17px;
}
}
@media (min-width: 480px) {
bottom: 3rem;
left: 3rem;
width: 40rem;
}
}

View File

@ -90,4 +90,15 @@
</div>
</div>
<div class="form-group" ng-class="{'has-error': providerForm['auth_provider[scopes]'].$dirty && providerForm['auth_provider[scopes]'].$invalid}">
<label for="provider_client_secret" class="col-sm-3 control-label" translate>{{ 'app.shared.oauth2.scopes' }}</label>
<div class="col-sm-9">
<input type="text"
ng-model="provider.providable_attributes.scopes"
class="form-control"
name="auth_provider[scopes]"
id="provider_scopes"
placeholder="profile,email...">
</div>
</div>
<ng-include src="'/admin/authentications/_oauth2_mapping.html'"></ng-include>

View File

@ -106,6 +106,16 @@
<input type="text" id="spaceLabel" ng-model="settings.spaceLabel.value" class="form-control" placeholder="{{ 'app.admin.invoices.general_space_label' | translate }}"/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label for="packCode" translate>{{ 'app.admin.invoices.accounting_Pack_code' }}</label>
<input type="text" id="packCode" ng-model="settings.packCode.value" class="form-control" placeholder="{{ 'app.admin.invoices.general_pack_code' | translate }}"/>
</div>
<div class="col-md-6">
<label for="packLabel" translate>{{ 'app.admin.invoices.accounting_Pack_label' }}</label>
<input type="text" id="packLabel" ng-model="settings.packLabel.value" class="form-control" placeholder="{{ 'app.admin.invoices.general_pack_label' | translate }}"/>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label for="spaceCode" translate>{{ 'app.admin.invoices.accounting_Error_code' }}</label>

View File

@ -42,7 +42,7 @@
<div class="form-group">
<div class="input-group">
<div class="input-group-addon"><i class="fa fa-search"></i></div>
<input type="search" class="form-control" placeholder="Mots-clés" ng-model="search.q"/>
<input type="search" class="form-control" placeholder="{{ 'app.public.projects_list.keywords' | translate }}" ng-model="search.q"/>
<div class="input-group-btn">
<button type="submit" class="btn btn-warning" translate>{{ 'app.public.projects_list.search' }}</button>
</div>

View File

@ -19,6 +19,8 @@ class AccountingPeriod < ApplicationRecord
validates_with PeriodOverlapValidator
validates_with PeriodIntegrityValidator
belongs_to :user, class_name: 'User', foreign_key: 'closed_by'
def delete
false
end
@ -79,13 +81,15 @@ class AccountingPeriod < ApplicationRecord
end
def compute_totals
period_invoices = invoices_with_vat(invoices.where(type: nil))
period_avoirs = invoices_with_vat(invoices.where(type: 'Avoir'))
period_invoices = invoices_with_vat(invoices.where(type: nil).includes([:invoice_items]))
period_avoirs = invoices_with_vat(invoices.where(type: 'Avoir').includes([:invoice_items]))
self.period_total = (period_invoices.map(&method(:price_without_taxe)).reduce(:+) || 0) -
(period_avoirs.map(&method(:price_without_taxe)).reduce(:+) || 0)
all_invoices = invoices_with_vat(Invoice.where('CAST(created_at AS DATE) <= :end_date AND type IS NULL', end_date: end_at))
all_avoirs = invoices_with_vat(Invoice.where("CAST(created_at AS DATE) <= :end_date AND type = 'Avoir'", end_date: end_at))
all_invoices = invoices_with_vat(Invoice.where('CAST(created_at AS DATE) <= :end_date AND type IS NULL', end_date: end_at)
.includes([:invoice_items]))
all_avoirs = invoices_with_vat(Invoice.where("CAST(created_at AS DATE) <= :end_date AND type = 'Avoir'", end_date: end_at)
.includes([:invoice_items]))
self.perpetual_total = (all_invoices.map(&method(:price_without_taxe)).reduce(:+) || 0) -
(all_avoirs.map(&method(:price_without_taxe)).reduce(:+) || 0)
self.footprint = compute_footprint

View File

@ -8,11 +8,6 @@ class InvoiceItem < Footprintable
has_one :payment_gateway_object, as: :item
belongs_to :object, polymorphic: true
belongs_to :reservation, foreign_type: 'Reservation', foreign_key: 'object_id'
belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'object_id'
belongs_to :wallet_transaction, foreign_type: 'WalletTransaction', foreign_key: 'object_id'
belongs_to :offer_day, foreign_type: 'OfferDay', foreign_key: 'object_id'
belongs_to :statistic_profile_prepaid_pack, foreign_type: 'StatisticProfilePrepaidPack', foreign_key: 'object_id'
after_create :chain_record
after_update :log_changes

View File

@ -1,4 +0,0 @@
class OpenAPI::CallsCountTracing < ApplicationRecord
belongs_to :projets, foreign_key: :open_api_client_id
validates :projets, :at, presence: true
end

View File

@ -2,8 +2,6 @@
# OpenAPI::Client keeps track of the authorized accesses to the 3-rd party API (aka. OpenAPI)
class OpenAPI::Client < ApplicationRecord
has_many :calls_count_tracings, foreign_key: :open_api_client_id, dependent: :destroy
validates :name, presence: true
validates_uniqueness_of :token

View File

@ -128,7 +128,9 @@ class Setting < ApplicationRecord
pack_only_for_subscription
overlapping_categories
extended_prices_in_same_day
public_registrations] }
public_registrations
accounting_Pack_code
accounting_Pack_label] }
# WARNING: when adding a new key, you may also want to add it in:
# - config/locales/en.yml#settings
# - app/frontend/src/javascript/models/setting.ts#SettingName
@ -195,4 +197,11 @@ class Setting < ApplicationRecord
setting = find_or_initialize_by(name: name)
setting.save && setting.history_values.create(invoicing_profile: user.invoicing_profile, value: value.to_s)
end
##
# Check if the given setting was set
##
def self.set?(name)
find_by(name: name)&.value.nil? ? false : true
end
end

View File

@ -49,6 +49,8 @@ class User < ApplicationRecord
has_one :payment_gateway_object, as: :item
has_many :accounting_periods, foreign_key: 'closed_by', dependent: :nullify
# fix for create admin user
before_save do
email&.downcase!

View File

@ -25,9 +25,9 @@ class PDF::Invoice < Prawn::Document
)
# logo
img_b64 = Setting.find_by(name: 'invoice_logo')
img_b64 = Setting.get('invoice_logo')
begin
image StringIO.new(Base64.decode64(img_b64.value)), fit: [415, 40]
image StringIO.new(Base64.decode64(img_b64)), fit: [415, 40]
rescue StandardError => e
puts "Unable to decode invoice logo from base64: #{e}"
end
@ -97,9 +97,9 @@ class PDF::Invoice < Prawn::Document
DATE: I18n.l(invoice.main_item.object.slots[0].start_at.to_date),
TIME: I18n.l(invoice.main_item.object.slots[0].start_at, format: :hour_minute))
invoice.invoice_items.each do |item|
next unless item.subscription
next unless item.object_type == Subscription.name
subscription = item.subscription
subscription = item.object
cancellation = invoice.is_a?(Avoir) ? I18n.t('invoices.cancellation') + ' - ' : ''
object = "\n- #{object}\n- #{cancellation + subscription_verbose(subscription, name)}"
break
@ -135,7 +135,7 @@ class PDF::Invoice < Prawn::Document
details = invoice.is_a?(Avoir) ? I18n.t('invoices.cancellation') + ' - ' : ''
if item.object_type == Subscription.name
subscription = item.subscription
subscription = item.object
if invoice.main_item.object_type == 'OfferDay'
details += I18n.t('invoices.subscription_extended_for_free_from_START_to_END',
START: I18n.l(invoice.main_item.object.start_at.to_date),

View File

@ -28,9 +28,9 @@ class PDF::PaymentSchedule < Prawn::Document
)
# logo
img_b64 = Setting.find_by(name: 'invoice_logo')
img_b64 = Setting.get('invoice_logo')
begin
image StringIO.new(Base64.decode64(img_b64.value)), fit: [415, 40]
image StringIO.new(Base64.decode64(img_b64)), fit: [415, 40]
rescue StandardError => e
puts "Unable to decode invoice logo from base64: #{e}"
end

View File

@ -20,6 +20,6 @@ class ProjectPolicy < ApplicationPolicy
end
def destroy?
user.admin? or record.author.user_id == user
user.admin? or record.author.user_id == user.id
end
end

View File

@ -3,7 +3,7 @@
# Check the access policies for API::SubscriptionsController
class SubscriptionPolicy < ApplicationPolicy
def show?
user.admin? or record.user_id == user.id
user.admin? || user.manager? || record.user.id == user.id
end
def payment_details?

View File

@ -69,6 +69,8 @@ class AccountingExportService
end
elsif invoice.main_item.object_type == 'WalletTransaction'
rows << "#{wallet_row(invoice)}\n"
elsif invoice.main_item.object_type == 'StatisticProfilePrepaidPack'
rows << "#{pack_row(invoice)}\n"
elsif invoice.main_item.object_type == 'Error'
items = invoice.invoice_items.reject { |ii| ii.object_type == 'Subscription' }
items.each do |item|
@ -131,6 +133,16 @@ class AccountingExportService
)
end
def pack_row(invoice)
row(
invoice,
account(invoice, :pack),
account(invoice, :pack, type: :label),
invoice.invoice_items.first.net_amount / 100.00,
line_label: label(invoice)
)
end
# Generate the "VAT" row, which contains the credit to the VAT account, with VAT amount only
def vat_row(invoice)
total = invoice.invoice_items.map(&:net_amount).sum
@ -195,29 +207,35 @@ class AccountingExportService
def account(invoice, account, type: :code, means: :other)
case account
when :projets
Setting.find_by(name: "accounting_#{means}_client_#{type}")&.value
Setting.get("accounting_#{means}_client_#{type}")
when :vat
Setting.find_by(name: "accounting_VAT_#{type}")&.value
Setting.get("accounting_VAT_#{type}")
when :subscription
if invoice.subscription_invoice?
Setting.find_by(name: "accounting_subscription_#{type}")&.value
Setting.get("accounting_subscription_#{type}")
else
puts "WARN: Invoice #{invoice.id} has no subscription"
end
when :reservation
if invoice.main_item.object_type == 'Reservation'
Setting.find_by(name: "accounting_#{invoice.main_item.object.reservable_type}_#{type}")&.value
Setting.get("accounting_#{invoice.main_item.object.reservable_type}_#{type}")
else
puts "WARN: Invoice #{invoice.id} has no reservation"
end
when :wallet
if invoice.main_item.object_type == 'WalletTransaction'
Setting.find_by(name: "accounting_wallet_#{type}")&.value
Setting.get("accounting_wallet_#{type}")
else
puts "WARN: Invoice #{invoice.id} is not a wallet credit"
end
when :pack
if invoice.main_item.object_type == 'StatisticProfilePrepaidPack'
Setting.get("accounting_Pack_#{type}")
else
puts "WARN: Invoice #{invoice.id} has no prepaid-pack"
end
when :error
Setting.find_by(name: "accounting_Error_#{type}")&.value
Setting.get("accounting_Error_#{type}")
else
puts "Unsupported account #{account}"
end || ''

View File

@ -46,7 +46,7 @@ class Members::MembersService
@member.update_statistic_profile
@member.generate_subscription_invoice(current_user.id)
@member.send_confirmation_instructions
UsersMailer.delay.notify_user_account_created(@member, @member.password)
UsersMailer.notify_user_account_created(@member, @member.password).deliver_later
true
else
false

View File

@ -126,13 +126,11 @@ class StatisticService
def subscriptions_list(options = default_options)
result = []
InvoiceItem.where('invoice_items.created_at >= :start_date AND invoice_items.created_at <= :end_date', options)
.eager_load(invoice: [:coupon], subscription: [:plan, statistic_profile: [:group]]).each do |i|
InvoiceItem.where("object_type = '#{Subscription.name}' AND invoice_items.created_at >= :start_date AND invoice_items.created_at <= :end_date", options)
.eager_load(invoice: [:coupon]).each do |i|
next if i.invoice.is_a?(Avoir)
sub = i.subscription
next unless sub
sub = i.object
ca = i.amount.to_i
cs = CouponService.new

View File

@ -46,7 +46,7 @@ class UserService
admin.send_confirmation_instructions
admin.add_role(:admin)
admin.remove_role(:member)
UsersMailer.delay.notify_user_account_created(admin, generated_password)
UsersMailer.notify_user_account_created(admin, generated_password).deliver_later
end
{ saved: saved, user: admin }
end
@ -61,7 +61,7 @@ class UserService
manager.send_confirmation_instructions
manager.add_role(:manager)
manager.remove_role(:member)
UsersMailer.delay.notify_user_account_created(manager, generated_password)
UsersMailer.notify_user_account_created(manager, generated_password).deliver_later
end
{ saved: saved, user: manager }
end

View File

@ -4,9 +4,9 @@ json.partial! 'api/auth_providers/auth_provider', auth_provider: @provider
if @provider.providable_type == OAuth2Provider.name
json.providable_attributes do
json.extract! @provider.providable, :id, :base_url, :token_endpoint, :authorization_endpoint, :profile_url, :client_id, :client_secret
json.extract! @provider.providable, :id, :base_url, :token_endpoint, :authorization_endpoint, :profile_url, :client_id, :client_secret, :scopes
json.o_auth2_mappings_attributes @provider.providable.o_auth2_mappings do |m|
json.extract! m, :id, :local_model, :local_field, :api_field, :api_endpoint, :api_data_type, :transformation
end
end
end
end

View File

@ -67,9 +67,7 @@
Fablab.sessionTours = [];
</script>
<%= stylesheet_packs_with_chunks_tag 'application', media: 'all' %>
<%= stylesheet_packs_with_chunks_tag 'plugins', media: 'all' %>
<%= stylesheet_packs_with_chunks_tag 'printer', media: 'print' %>
<%= stylesheet_pack_tag 'application', 'plugins', 'printer' %>
<% unless Stylesheet.theme.nil? %>
<link rel="stylesheet" media="all" href="<%= stylesheet_path(Stylesheet.theme.id) %>-<%= Stylesheet.theme.updated_at.to_i.to_s %>.css" />
<% end %>
@ -134,6 +132,6 @@
<span class="text-sm">Powered by <a href="http://www.fab-manager.com" target="_blank">Fab-manager</a></span>
</div>
<%= javascript_packs_with_chunks_tag 'application' %>
<%= javascript_pack_tag 'application' %>
</body>
</html>

View File

@ -1,10 +0,0 @@
class OpenAPITraceCallsCountWorker < Sidekiq::Workers
include Sidekiq::Worker
sidekiq_options queue: 'default', retry: true
def perform
OpenAPI::Client.find_each do |client|
OpenAPI::CallsCountTracing.create!(projets: client, calls_count: client.calls_count, at: DateTime.current)
end
end
end

View File

@ -7,7 +7,7 @@ class OpenlabWorker
def initialize
client = Openlab::Client.new(app_secret: Setting.get('openlab_app_secret'))
@projets = Openlab::Projects.new(client)
@projects = Openlab::Projects.new(client)
super
end
@ -17,12 +17,12 @@ class OpenlabWorker
case action.to_s
when /create/
project = Project.find(project_id)
response = @projets.create(project.openlab_attributes)
response = @projects.create(project.openlab_attributes)
when /update/
project = Project.find(project_id)
response = @projets.update(project_id, project.openlab_attributes)
response = @projects.update(project_id, project.openlab_attributes)
when /destroy/
response = @projets.destroy(project_id)
response = @projects.destroy(project_id)
else
raise NotImplementedError
end

View File

@ -1,3 +1,6 @@
# frozen_string_literal: true
# Send a reminder email to the user who has made a reservation
class ReservationReminderWorker
include Sidekiq::Worker
@ -5,25 +8,24 @@ class ReservationReminderWorker
DEFAULT_REMINDER_DELAY = 24.hours
def perform
enabled = Setting.find_by(name: 'reminder_enable').try(:value)
if enabled == 'true'
delay = Setting.find_by(name: 'reminder_delay').try(:value).try(:to_i).try(:hours) || DEFAULT_REMINDER_DELAY
return unless Setting.get('reminder_enable')
starting = DateTime.current.beginning_of_hour + delay
ending = starting + 1.hour
delay = Setting.find_by(name: 'reminder_delay').try(:value).try(:to_i).try(:hours) || DEFAULT_REMINDER_DELAY
Reservation.joins(:slots).where('slots.start_at >= ? AND slots.start_at <= ? AND slots.canceled_at IS NULL', starting, ending).each do |r|
already_sent = Notification.where(
attached_object_type: Reservation.name,
attached_object_id: r.id,
notification_type_id: NotificationType.find_by_name('notify_member_reservation_reminder')
).count
unless already_sent > 0
NotificationCenter.call type: 'notify_member_reservation_reminder',
receiver: r.user,
attached_object: r
end
end
starting = DateTime.current.beginning_of_hour + delay
ending = starting + 1.hour
Reservation.joins(:slots).where('slots.start_at >= ? AND slots.start_at <= ? AND slots.canceled_at IS NULL', starting, ending).each do |r|
already_sent = Notification.where(
attached_object_type: Reservation.name,
attached_object_id: r.id,
notification_type_id: NotificationType.find_by_name('notify_member_reservation_reminder')
).count
next if already_sent.positive?
NotificationCenter.call type: 'notify_member_reservation_reminder',
receiver: r.user,
attached_object: r
end
end
end
end

View File

@ -4,7 +4,6 @@ module.exports = function (api) {
const isDevelopmentEnv = api.env('development');
const isProductionEnv = api.env('production');
const isTestEnv = api.env('test');
const isWebpackDevServer = process.env.WEBPACK_DEV_SERVER;
if (!validEnv.includes(currentEnv)) {
throw new Error(
@ -16,39 +15,20 @@ module.exports = function (api) {
);
}
return {
const defaultConfigFunc = require('shakapacker/package/babel/preset.js');
const resultConfig = defaultConfigFunc(api);
const changesOnDefault = {
presets: [
isTestEnv && [
'@babel/preset-env',
{
targets: {
node: 'current'
},
modules: 'commonjs'
},
'@babel/preset-react'
],
(isProductionEnv || isDevelopmentEnv) && [
'@babel/preset-env',
{
forceAllTransforms: true,
useBuiltIns: 'entry',
corejs: 3,
modules: false,
exclude: ['transform-typeof-symbol']
}
],
[
'@babel/preset-react',
{
development: isDevelopmentEnv || isTestEnv,
useBuiltIns: true
}
],
['@babel/preset-typescript', { allExtensions: true, isTSX: true }]
]
].filter(Boolean),
plugins: [
isWebpackDevServer && 'react-refresh/babel',
'babel-plugin-macros',
'@babel/plugin-syntax-dynamic-import',
isTestEnv && 'babel-plugin-dynamic-import-node',
@ -56,7 +36,7 @@ module.exports = function (api) {
[
'@babel/plugin-proposal-class-properties',
{
loose: false
loose: true
}
],
[
@ -65,26 +45,28 @@ module.exports = function (api) {
useBuiltIns: true
}
],
[
'@babel/plugin-transform-runtime',
{
helpers: false,
regenerator: true,
corejs: false
}
],
[
'@babel/plugin-transform-regenerator',
{
async: false
}
],
isProductionEnv && [
'babel-plugin-transform-react-remove-prop-types',
isProductionEnv && ['babel-plugin-transform-react-remove-prop-types',
{
removeImport: true
}
],
process.env.WEBPACK_SERVE && [
'react-refresh/babel',
{
exclude: 'node_modules/**'
}
]
].filter(Boolean)
};
resultConfig.presets = [...resultConfig.presets, ...changesOnDefault.presets];
resultConfig.plugins = [...resultConfig.plugins, ...changesOnDefault.plugins];
return resultConfig;
};

15
bin/webpacker Executable file
View File

@ -0,0 +1,15 @@
#!/usr/bin/env ruby
require "pathname"
require "bundler/setup"
require "webpacker"
require "webpacker/webpack_runner"
ENV["RAILS_ENV"] ||= "development"
ENV["NODE_ENV"] ||= ENV["RAILS_ENV"]
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath)
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::WebpackRunner.run(ARGV)
end

18
bin/webpacker-dev-server Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/env ruby
ENV["RAILS_ENV"] ||= "development"
ENV["NODE_ENV"] ||= ENV["RAILS_ENV"]
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require "bundler/setup"
require "webpacker"
require "webpacker/dev_server_runner"
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::DevServerRunner.run(ARGV)
end

View File

@ -1,9 +1,16 @@
#!/usr/bin/env ruby
APP_ROOT = File.expand_path('..', __dir__)
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
begin
exec "yarnpkg", *ARGV
rescue Errno::ENOENT
yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
select { |dir| File.expand_path(dir) != __dir__ }.
product(["yarn", "yarnpkg", "yarn.cmd", "yarn.ps1"]).
map { |dir, file| File.expand_path(file, dir) }.
find { |file| File.executable?(file) }
if yarn
exec yarn, *ARGV
else
$stderr.puts "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1

View File

@ -1,10 +1,14 @@
# frozen_string_literal: true
# Be sure to restart your server when you modify this file.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Rails.application.config.content_security_policy do |policy|
Rails.application.config.content_security_policy do |policy| # # If you are using webpack-dev-server then specify webpack-dev-server host
policy.connect_src :self, :https, 'http://localhost:3035', 'ws://localhost:3035' if Rails.env.development?
# policy.default_src :self, :https
# policy.font_src :self, :https, :data
# policy.img_src :self, :https, :data
@ -14,7 +18,7 @@
# # Specify URI for violation reports
# # policy.report_uri "/csp-violation-report-endpoint"
# end
end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }

View File

@ -1,3 +1,5 @@
Openlab.configure do |config|
config.base_uri = Rails.application.secrets.openlab_base_uri unless Rails.env.production?
config.base_uri = Rails.application.secrets.openlab_base_uri if Rails.application.secrets.openlab_base_uri
config.httparty_verify = Rails.application.secrets.openlab_ssl_verify
config.httparty_verify_peer = Rails.application.secrets.openlab_ssl_verify_peer
end

View File

@ -1,25 +1,42 @@
# frozen_string_literal: true
require 'sidekiq'
require 'sidekiq-scheduler'
redis_host = ENV['REDIS_HOST'] || 'localhost'
redis_url = "redis://#{redis_host}:6379"
Sidekiq.configure_server do |config|
config.redis = { url: redis_url }
# load sidekiq-cron schedule config
schedule_file = 'config/schedule.yml'
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
if File.exist?(schedule_file)
rendered_schedule_file = ERB.new(File.read(schedule_file)).result
Sidekiq::Cron::Job.load_from_hash YAML.safe_load(rendered_schedule_file)
config.server_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Server
end
SidekiqUniqueJobs::Server.configure(config)
config.on(:startup) do
# load sidekiq-scheduler schedule config
schedule_file = 'config/schedule.yml'
if File.exist?(schedule_file)
rendered_schedule_file = ERB.new(File.read(schedule_file)).result
Sidekiq.schedule = YAML.safe_load(rendered_schedule_file)
SidekiqScheduler::Scheduler.instance.reload_schedule!
end
end
end
Sidekiq.configure_client do |config|
config.redis = { url: redis_url }
end
Sidekiq::Extensions.enable_delay!
config.client_middleware do |chain|
chain.add SidekiqUniqueJobs::Middleware::Client
end
end
# Quieting logging in the test environment
if Rails.env.test?

View File

@ -78,8 +78,8 @@ de:
slots_not_deleted: "Von {TOTAL} Slots {COUNT, plural, one {} =1{wurde einer wurde nicht gelöscht} other{wurden {COUNT} nicht gelöscht}}. Möglicherweise {COUNT, plural, =1{ist er} other{sind sie}} bereits reserviert."
you_should_select_at_least_a_machine: "Sie sollten mindestens eine Maschine auf diesem Slot auswählen."
inconsistent_times: "Fehler: das Ende der Verfügbarkeit liegt vor dem Beginn."
min_one_slot: "The availability must be split in one slot at least."
min_slot_duration: "You must specify a valid duration for the slots."
min_one_slot: "Die Verfügbarkeit muss auf mindestens einen Slot aufgeteilt werden."
min_slot_duration: "Sie müssen eine gültige Dauer für die Slots angeben."
export_is_running_you_ll_be_notified_when_its_ready: "Export wird ausgeführt. Sie werden nach Fertigstellung benachrichtigt."
actions: "Aktionen"
block_reservations: "Reservierungen blockieren"
@ -98,8 +98,8 @@ de:
delete_this_slot: "Nur diesen Slot"
delete_this_and_next: "Diesen Slot und die folgenden"
delete_all: "Alle Slots"
event_in_the_past: "Create a slot in the past"
confirm_create_event_in_the_past: "You are about to create a slot in the past. Are you sure you want to do this? Members will not be able to book this slot."
event_in_the_past: "Slot in der Vergangenheit erstellen"
confirm_create_event_in_the_past: "Sie erstellen einen Slot in der Vergangenheit. Sind Sie sicher? Mitglieder werden diesen Slot nicht buchen können."
edit_event: "Veranstaltung bearbeiten"
view_reservations: "Reservierungen anzeigen"
legend: "Legende"
@ -370,70 +370,70 @@ de:
status_disabled: "Deaktiviert"
status_all: "Alle"
spaces_pricing:
prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, <strong>without subscription</strong>."
prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.<br/><em>For example</em>, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged <strong>{PRICE}</strong>."
you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly."
extended_prices: "Moreover, you can define extended prices which will apply in priority over the hourly rate below. Extended prices allow you, for example, to set a favorable price for a booking of several hours."
spaces: "Spaces"
price_updated: "Price successfully updated"
prices_match_space_hours_rates_html: "Die unten aufgeführten Preise entsprechen einer Stunde Raumbelegung <strong>ohne Abonnement</strong>."
prices_calculated_on_hourly_rate_html: "Alle Preise werden automatisch nach dem hier definierten Stundensatz berechnet.<br/><em>Zum Beispiel</em> wird bei einem veranschlagten Stundensatz von {RATE} ein Slot von {DURATION} Minuten zum Preis von <strong>{PRICE}</strong> berechnet."
you_can_override: "Sie können diese Dauer für jede Verfügbarkeit überschreiben, die Sie in der Agenda erstellen. Der Preis wird dann entsprechend angepasst."
extended_prices: "Darüber hinaus können Sie erweiterte Preise festlegen, die vorrangig zum unten stehenden Stundensatz gelten. Mit erweiterten Preisen können Sie zum Beispiel einen günstigen Preis für eine Buchung über mehrere Stunden festlegen."
spaces: "Räume"
price_updated: "Preis erfolgreich aktualisiert"
machines_pricing:
prices_match_machine_hours_rates_html: "Die unten aufgeführten Preise entsprechen einer Stunde Maschinengebrauch, <strong>ohne Abonnement</strong>."
prices_calculated_on_hourly_rate_html: "Alle Preise werden automatisch nach dem hier definierten Stundensatz berechnet.<br/><em>Zum Beispiel</em> wird bei einem veranschlagten Stundensatz von {RATE} ein Slot von {DURATION} Minuten, zum Preis von <strong>{PRICE}</strong> berechnet."
you_can_override: "Sie können diese Dauer für jede Verfügbarkeit überschreiben, die Sie in der Agenda erstellen. Der Preis wird dann entsprechend angepasst."
machines: "Maschinen"
price_updated: "Price successfully updated"
price_updated: "Preis erfolgreich aktualisiert"
configure_packs_button:
packs: "Prepaid packs"
no_packs: "No packs for now"
pack_DURATION: "{DURATION} hours"
packs: "Vorausbezahlte Pakete"
no_packs: "Momentan keine Pakete"
pack_DURATION: "{DURATION} Stunden"
configure_extended_prices_button:
extended_prices: "Extended prices"
no_extended_prices: "No extended price for now"
extended_price_DURATION: "{DURATION} hours"
extended_prices: "Erweiterter Preis"
no_extended_prices: "Momentan kein erweiterter Preis"
extended_price_DURATION: "{DURATION} Stunden"
extended_price_form:
duration: "Duration (hours)"
amount: "Price"
duration: "Dauer (Stunden)"
amount: "Preis"
pack_form:
hours: "Hours"
amount: "Price"
disabled: "Disabled"
validity_count: "Maximum validity"
select_interval: "Interval..."
hours: "Stunden"
amount: "Preis"
disabled: "Deaktiviert"
validity_count: "Maximale Gültigkeit"
select_interval: "Zeitraum..."
intervals:
day: "{COUNT, plural, one{Day} other{Days}}"
week: "{COUNT, plural, one{Week} other{Weeks}}"
month: "{COUNT, plural, one{Month} other{Months}}"
year: "{COUNT, plural, one{Year} other{Years}}"
day: "{COUNT, plural, one {Tag} other {Tage}}"
week: "{COUNT, plural, one{Woche} other{Wochen}}"
month: "{COUNT, plural, one{Monat} other{Monate}}"
year: "{COUNT, plural, one {Jahr} other {Jahre}}"
create_pack:
new_pack: "New prepaid pack"
new_pack_info: "A prepaid pack allows users to buy {TYPE, select, Machine{machine} Space{space} other{}} hours before booking any slots. These packs can provide discounts on volumes purchases."
create_pack: "Create this pack"
pack_successfully_created: "The new prepaid pack was successfully created."
new_pack: "Neues vorausbezahltes Paket"
new_pack_info: "Ein vorausbezahltes Paket erlaubt den Kauf von {TYPE, select, Machine{Maschinen-} Space{Raum-} other{}}Stunden vor der Buchung eines Slots. Diese Pakete können Rabatte auf Volumenkäufe bieten."
create_pack: "Dieses Paket erstellen"
pack_successfully_created: "Das neue Vorausbezahlungs-Paket wurde erfolgreich erstellt."
delete_pack:
pack_deleted: "The prepaid pack was successfully deleted."
unable_to_delete: "Unable to delete the prepaid pack: "
delete_pack: "Delete the prepaid pack"
confirm_delete: "Delete"
delete_confirmation: "Are you sure you want to delete this prepaid pack? This won't be possible if the pack was already bought by users."
pack_deleted: "Das Vorausbezahlungs-Paket wurde erfolgreich gelöscht."
unable_to_delete: "Paket konnte nicht gelöscht werden: "
delete_pack: "Vorausbezahlungs-Paket löschen"
confirm_delete: "Löschen"
delete_confirmation: "Sind Sie sicher, dass Sie dieses Paket löschen möchten? Dies ist nicht möglich, wenn das Paket bereits von Benutzern gekauft wurde."
edit_pack:
edit_pack: "Edit the pack"
confirm_changes: "Confirm changes"
pack_successfully_updated: "The prepaid pack was successfully updated."
edit_pack: "Das Paket bearbeiten"
confirm_changes: "Änderungen bestätigen"
pack_successfully_updated: "Das Vorausbezahlungs-Paket wurde erfolgreich aktualisiert."
create_extended_price:
new_extended_price: "New extended price"
new_extended_price_info: "Extended prices allows you to define prices based on custom durations, instead of the default hourly rates."
create_extended_price: "Create extended price"
extended_price_successfully_created: "The new extended price was successfully created."
new_extended_price: "Neuer erweiterter Preis"
new_extended_price_info: "Erweiterte Preise erlauben Ihnen die Festlegung von Preisen basierend auf benutzerdefinierten Zeitdauern anstelle der Standard-Stundensätze."
create_extended_price: "Erweiterten Preis erstellen"
extended_price_successfully_created: "Der neue erweiterte Preis wurde erfolgreich erstellt."
delete_extended_price:
extended_price_deleted: "The extended price was successfully deleted."
unable_to_delete: "Unable to delete the extended price: "
delete_extended_price: "Delete the extended price"
confirm_delete: "Delete"
delete_confirmation: "Are you sure you want to delete this extended price?"
extended_price_deleted: "Der erweiterte Preis wurde erfolgreich gelöscht."
unable_to_delete: "Der erweiterte Preis konnte nicht gelöscht werden: "
delete_extended_price: "Erweiterten Preis löschen"
confirm_delete: "Löschen"
delete_confirmation: "Sind Sie sicher, dass Sie diesen erweiterten Preis löschen möchten?"
edit_extended_price:
edit_extended_price: "Edit the extended price"
confirm_changes: "Confirm changes"
extended_price_successfully_updated: "The extended price was successfully updated."
edit_extended_price: "Erweiterten Preis bearbeiten"
confirm_changes: "Änderungen bestätigen"
extended_price_successfully_updated: "Der erweiterte Preis wurde erfolgreich aktualisiert."
#ajouter un code promotionnel
coupons_new:
add_a_coupon: "Gutschein hinzufügen"
@ -496,7 +496,7 @@ de:
details: "Details"
amount: "Betrag"
machine_booking-3D_printer: "Maschinen-Buchung - 3D-Drucker"
training_booking-3D_print: "Training booking - initiation to 3d printing"
training_booking-3D_print: "Schulungsbuchung - Einstieg ins 3D-Drucken"
total_amount: "Gesamtbetrag"
total_including_all_taxes: "Gesamtpreis inkl. Steuern"
VAT_disabled: "MwSt. deaktiviert"
@ -553,15 +553,15 @@ de:
enable_VAT: "MwSt. aktivieren"
VAT_rate: "MwSt.-Satz"
VAT_history: "MwSt.-Sätze Historie"
VAT_notice: "This parameter configures the general case of the VAT rate and applies to everything sold by the Fablab. It is possible to override this parameter by setting a specific VAT rate for each object."
edit_multi_VAT_button: "More options"
multiVAT: "Advanced VAT"
multi_VAT_notice: "<strong>Please note</strong>: The current general rate is {RATE}%. Here you can define different VAT rates for each category.</br></br>For example, you can override this value, only for machine reservations, by filling in the corresponding field below. If no value is filled in, the general rate will apply."
VAT_rate_machine: "Machine reservation"
VAT_rate_space: "Space reservation"
VAT_rate_training: "Training reservation"
VAT_rate_event: "Event reservation"
VAT_rate_subscription: "Subscription"
VAT_notice: "Dieser Parameter legt den allgemeinen Fall des MwSt.-Satzes fest und gilt für alles, was der Fablab verkauft. Der Parameter kann überschreiben werden, indem ein spezieller Mehrwertsteuersatz für jedes Objekt festgelegt wird."
edit_multi_VAT_button: "Weitere Optionen"
multiVAT: "Erweiterte MwSt."
multi_VAT_notice: "<strong>Bitte beachten Sie</strong>: Der aktuelle allgemeine MwSt.-Satz beträgt {RATE}%. Hier können Sie unterschiedliche Mehrwertsteuersätze für jede Kategorie festlegen.</br></br>Zum Beispiel können Sie diesen Wert für Maschinenreservierungen überschreiben, indem Sie das entsprechende Feld unten ausfüllen. Wird kein Wert ausgefüllt, gilt der allgemeine Satz."
VAT_rate_machine: "Maschinenreservierung"
VAT_rate_space: "Raumreservierung"
VAT_rate_training: "Schulungsreservierung"
VAT_rate_event: "Veranstaltungsreservierung"
VAT_rate_subscription: "Abonnement"
changed_at: "Geändert am"
changed_by: "Von"
deleted_user: "Gelöschter Nutzer"
@ -603,9 +603,9 @@ de:
logo_successfully_saved: "Logo erfolgreich gespeichert."
an_error_occurred_while_saving_the_logo: "Beim Speichern des Logos ist ein Fehler aufgetreten."
filename: "Dateiname"
schedule_filename: "Schedule file name"
schedule_filename: "Dateiname des Zeitplans"
prefix_info: "Die Rechnungen werden als PDF-Dateien generiert, die mit dem folgenden Präfix benannt sind."
schedule_prefix_info: "The payment schedules will be generated as PDF files, named with the following prefix."
schedule_prefix_info: "Die Zahlungspläne werden als PDF-Dateien mit dem folgenden Prefix generiert."
prefix: "Präfix"
prefix_successfully_saved: "Dateipräfix erfolgreich gespeichert"
an_error_occurred_while_saving_the_prefix: "Beim Speichern des Dateipräfix ist ein Fehler aufgetreten"
@ -673,16 +673,20 @@ de:
general_space_code: "Abrechnungscode für alle Räume"
accounting_Space_label: "Raumbezeichnung"
general_space_label: "Abrechnungs-Label für alle Räume"
accounting_Error_code: "Errors code"
general_error_code: "Accounting code for erroneous invoices"
accounting_Error_label: "Errors label"
general_error_label: "Account label for erroneous invoices"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Fehlercode"
general_error_code: "Rechnungscode für fehlerhafte Rechnungen"
accounting_Error_label: "Fehlerbezeichnung"
general_error_label: "Kontobezeichnung für fehlerhafte Rechnungen"
codes_customization_success: "Anpassung der Abrechnungscodes erfolgreich gespeichert."
unexpected_error_occurred: "Beim Speichern der Codes ist ein unerwarteter Fehler aufgetreten. Bitte versuchen Sie es später erneut."
export_accounting_data: "Abrechnungsdaten exportieren"
export_what: "What do you want to export?"
export_VAT: "Export the collected VAT"
export_to_ACD: "Export all data to the accounting software ACD"
export_what: "Was möchten Sie exportieren?"
export_VAT: "Die gesammelte MwSt. exportieren"
export_to_ACD: "Alle Daten in die Buchhaltungssoftware ACD exportieren"
export_is_running: "Export wird ausgeführt. Sie werden nach Fertigstellung benachrichtigt."
export_form_date: "Exportieren ab"
export_to_date: "Exportieren bis"
@ -706,10 +710,10 @@ de:
debit_euro: "Soll in Euro"
credit_euro: "Guthaben in Euro"
lettering: "Beschriftung"
start_date: "Start date"
end_date: "End date"
vat_rate: "VAT rate"
amount: "Total amount"
start_date: "Startdatum"
end_date: "Enddatum"
vat_rate: "MwSt.-Satz"
amount: "Gesamtbetrag"
payment:
payment_settings: "Bezahlungseinstellungen"
online_payment: "Online-Bezahlung"
@ -722,53 +726,53 @@ de:
error_check_keys: "Fehler: Bitte überprüfen Sie Ihre Stripe-Schlüssel."
stripe_keys_saved: "Stripe-Schlüssel erfolgreich gespeichert."
error_saving_stripe_keys: "Die Stripe-Schlüssel konnten nicht gespeichert werden. Bitte versuchen Sie es später erneut."
payzen_keys_info_html: "<p>To be able to collect online payments, you must configure the <a href='https://payzen.eu' target='_blank'>PayZen</a> identifiers and keys.</p><p>Retrieve them from <a href='https://secure.payzen.eu/vads-merchant/' target='_blank'>your merchant back office</a>.</p>"
client_keys: "Client key"
api_keys: "API keys"
payzen_keys_info_html: "<p>Um Online-Zahlungen zu erhalten, müssen Sie die <a href='https://payzen.eu' target='_blank'>PayZen</a> Identifikatoren und Schlüssel konfigurieren.</p><p>Holen Sie sie aus <a href='https://secure.payzen.eu/vads-merchant/' target='_blank'>Ihrem Händler-Backend</a>.</p>"
client_keys: "Kundenschlüssel"
api_keys: "API-Schlüssel"
edit_keys: "Schlüssel bearbeiten"
currency: "Währung"
currency_info_html: "Bitte geben Sie unten die Währung an, die für Online-Bezahlung verwendet wird. Sie sollten einen ISO-Code mit drei Buchstaben aus der Liste <a href='https://stripe.com/docs/currencies' target='_blank'>Stripe unterstützter Währungen eingeben</a>."
currency_alert_html: "<strong>Warnung</strong>: Die Währung kann nicht mehr geändert werden, nachdem die erste Online-Zahlung eingegangen ist. Bitte nehmen Sie diese Einstellung sorgfältig vor, bevor Sie Fab-Manager für Mitglieder öffnen."
stripe_currency: "Stripe-Währung"
gateway_configuration_error: "An error occurred while configuring the payment gateway: "
gateway_configuration_error: "Fehler beim Konfigurieren des Zahlungs-Gateways: "
payzen:
payzen_keys: "PayZen keys"
payzen_keys: "PayZen-Schlüssel"
payzen_username: "Benutzername"
payzen_password: "Passwort"
payzen_endpoint: "REST API server name"
payzen_hmac: "HMAC-SHA-256 key"
payzen_public_key: "Client public key"
payzen_endpoint: "REST API Server Name"
payzen_hmac: "HMAC-SHA-256 Schlüssel"
payzen_public_key: "Öffentlicher Schlüssel des Kunden"
currency: "Währung"
payzen_currency: "PayZen Währung"
currency_info_html: "Bitte geben Sie unten die Währung an, die für Online-Bezahlung verwendet wird. Sie sollten einen ISO-Code mit drei Buchstaben aus der Liste <a href='https://payzen.io/de-DE/payment-file/ips/list-of-supported-currencies.html' target='_blank'>PayZen unterstützter Währungen eingeben</a>."
save: "Speichern"
currency_error: "The inputted value is not a valid currency"
error_while_saving: "An error occurred while saving the currency: "
currency_updated: "The PayZen currency was successfully updated to {CURRENCY}."
currency_error: "Der eingegebene Wert ist keine gültige Währung"
error_while_saving: "Beim Speichern der Währung ist ein Fehler aufgetreten: "
currency_updated: "Die PayZen-Währung wurde erfolgreich auf {CURRENCY} aktualisiert."
#select a payment gateway
gateway_modal:
select_gateway_title: "Select a payment gateway"
gateway_info: "To securely collect and process payments online, Fab-manager needs to use an third-party service authorized by the financial institutions, called a payment gateway."
select_gateway: "Please select an available gateway"
select_gateway_title: "Zahlungs-Gateway auswählen"
gateway_info: "Um Zahlungen sicher online zu sammeln und zu verarbeiten, muss Fab-Manager einen von Finanzinstituten autorisierten Drittanbieter nutzen, der als Zahlungsgateway bezeichnet wird."
select_gateway: "Bitte wählen Sie ein verfügbares Gateway"
stripe: "Stripe"
payzen: "PayZen"
confirm_button: "Validate the gateway"
confirm_button: "Gateway überprüfen"
payment_schedules:
filter_schedules: "Pläne filtern"
no_payment_schedules: "Keine Zahlungspläne zum Anzeigen"
load_more: "Mehr laden"
card_updated_success: "The user's card was successfully updated"
card_updated_success: "Die Karte des Nutzers wurde erfolgreich aktualisiert"
document_filters:
reference: "Referenz"
customer: "Kunde"
date: "Datum"
update_payment_mean_modal:
title: "Update the payment mean"
update_info: "Please specify below the new payment mean for this payment schedule to continue."
select_payment_mean: "Select a new payment mean"
method_Transfer: "By bank transfer"
method_Check: "By check"
confirm_button: "Update"
title: "Zahlungsmittel aktualisieren"
update_info: "Bitte geben Sie unten das neue Zahlungsmittel an, damit der Zahlungszeitplan fortgesetzt werden kann."
select_payment_mean: "Neues Zahlungsmittel auswählen"
method_Transfer: "Per Banküberweisung"
method_Check: "Per Scheck"
confirm_button: "Aktualisieren"
#management of users, labels, groups, and so on
members:
users_management: "Benutzer-Verwaltung"
@ -918,7 +922,7 @@ de:
expires_at: "Läuft ab am:"
price_: "Preis:"
offer_free_days: "Kostenlose Tage anbieten"
renew_subscription: "Renew the subscription"
renew_subscription: "Abonnement erneuern"
user_has_no_current_subscription: "Benutzer hat kein aktuelles Abonnement."
subscribe_to_a_plan: "Plan abonnieren"
trainings: "Schulungen"
@ -944,7 +948,7 @@ de:
a_problem_occurred_while_saving_the_date: "Beim Speichern des Datums ist ein Problem aufgetreten."
new_subscription: "Neues Abonnement"
you_are_about_to_purchase_a_subscription_to_NAME: "Sie sind dabei, ein Abonnement für {NAME} zu kaufen."
with_schedule: "Subscribe with a monthly payment schedule"
with_schedule: "Mit einem monatlichen Zahlungsplan abonnieren"
subscription_successfully_purchased: "Abonnement erfolgreich gekauft."
a_problem_occurred_while_taking_the_subscription: "Bei der Übernahme des Abonnements ist ein Problem aufgetreten"
wallet: "Guthabenkonto"
@ -953,37 +957,37 @@ de:
cannot_extend_own_subscription: "Sie können Ihr eigenes Abonnement nicht erweitern. Bitte fragen Sie einen anderen Manager oder einen Administrator."
#extend a subscription for free
free_extend_modal:
extend_subscription: "Extend the subscription"
offer_free_days_infos: "You are about to extend the user's subscription by offering him free additional days."
credits_will_remain_unchanged: "The balance of free credits (training / machines / spaces) of the user will remain unchanged."
current_expiration: "Current subscription will expire at:"
extend_subscription: "Abonnement verlängern"
offer_free_days_infos: "Sie sind dabei, das Abonnement des Benutzers zu verlängern, indem Sie ihm zusätzliche Tage kostenlos anbieten."
credits_will_remain_unchanged: "Der Saldo der freien Gutschriften (Schulungen / Maschinen / Räume) des Nutzers bleibt unverändert."
current_expiration: "Aktuelles Abonnement läuft ab um:"
DATE_TIME: "{DATE} {TIME}"
new_expiration_date: "New expiration date:"
number_of_free_days: "Number of free days:"
extend: "Extend"
extend_success: "The subscription was successfully extended for free"
new_expiration_date: "Neues Ablaufdatum:"
number_of_free_days: "Anzahl der freien Tage:"
extend: "Erweitern"
extend_success: "Das Abonnement wurde erfolgreich kostenlos erweitert"
#renew a subscription
renew_subscription_modal:
renew_subscription: "Renew the subscription"
renew_subscription_info: "You are about to renew the user's subscription by charging him again for his current subscription."
credits_will_be_reset: "The balance of free credits (training / machines / spaces) of the user will be reset, unused credits will be lost."
current_expiration: "Current subscription will expire at:"
new_start: "The new subscription will start at:"
new_expiration_date: "The new subscription will expire at:"
pay_in_one_go: "Pay in one go"
renew: "Renew"
renew_success: "The subscription was successfully renewed"
renew_subscription: "Abonnement erneuern"
renew_subscription_info: "Sie verlängern das Abonnement des Benutzers, indem Sie ihm sein aktuelles Abonnement erneut berechnen."
credits_will_be_reset: "Der Saldo der freien Credits (Schulung / Maschinen / Räume) des Benutzers wird zurückgesetzt, nicht genutzte Credits gehen verloren."
current_expiration: "Aktuelles Abonnement läuft ab um:"
new_start: "Das neue Abonnement beginnt am:"
new_expiration_date: "Das neue Abonnement läuft ab um:"
pay_in_one_go: "In einem Schritt bezahlen"
renew: "Erneuern"
renew_success: "Das Abonnement wurde erfolgreich verlängert"
#take a new subscription
subscribe_modal:
subscribe_USER: "Subscribe {USER}"
subscribe: "Subscribe"
select_plan: "Please select a plan"
pay_in_one_go: "Pay in one go"
subscribe_USER: "{USER} abonnieren"
subscribe: "Abonnieren"
select_plan: "Bitte wählen Sie einen Plan"
pay_in_one_go: "In einem Schritt bezahlen"
subscription_success: ""
#add a new administrator to the platform
admins_new:
add_an_administrator: "Administrator hinzufügen"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator erfolgreich erstellt. {GENDER, select, female{Sie} other{Er}} erhält {GENDER, select, female{ihre} other{seine}} Verbindungsanweisungen per E-Mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator erfolgreich erstellt. Er erhält seine Verbindungsanweisungen per E-Mail."
failed_to_create_admin: "Administrator konnte nicht erstellt werden:"
man: "Männlich"
woman: "Weiblich"
@ -1001,7 +1005,7 @@ de:
#add a new manager to the platform
manager_new:
add_a_manager: "Manager hinzufügen"
manager_successfully_created: "Manager erfolgreich erstellt. {GENDER, select, female{Sie} other{Er}} erhält {GENDER, select, female{ihre} other{seine}} Verbindungsanweisungen per E-Mail."
manager_successfully_created: "Manager erfolgreich erstellt. Er erhält seine Verbindungsanweisungen per E-Mail."
failed_to_create_manager: "Konnte den Manager nicht erstellen:"
man: "Männlich"
woman: "Weiblich"
@ -1032,7 +1036,7 @@ de:
oauth2_provider_successfully_added: "OAuth 2.0 Provider erfolgreich hinzugefügt."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Provider:"
provider: "Anbieter:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "Um diesen Provider hinzuzufügen, muss die Übereinstimmung zwischen User.uid und der API festgelegt werden."
provider_successfully_updated: "Anbieter erfolgreich aktualisiert."
an_error_occurred_unable_to_update_the_provider: "Ein Fehler ist aufgetreten: Der Anbieter konnte nicht aktualisiert werden."
@ -1228,9 +1232,9 @@ de:
error_SETTING_locked: "Die Einstellung konnte nicht aktualisiert werden: {SETTING} ist gesperrt. Bitte kontaktieren Sie Ihren Systemadministrator."
an_error_occurred_saving_the_setting: "Beim Speichern der Einstellung ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut."
book_overlapping_slots_info: "Erlauben / Verhindern der Reservierung von überlappenden Slots"
allow_booking: "Allow booking"
overlapping_categories: "Overlapping categories"
overlapping_categories_info: "Preventing booking on overlapping slots will be done by comparing the date and time of the following categories of reservations."
allow_booking: "Buchungen erlauben"
overlapping_categories: "Überlappende Kategorien"
overlapping_categories_info: "Die Buchung von überlappenden Zeitnischen wird durch einen Vergleich zwischen Datum und Uhrzeit der folgenden Buchungskategorien verhindert."
default_slot_duration: "Standarddauer für Slots"
duration_minutes: "Dauer (in Minuten)"
default_slot_duration_info: "Die Verfügbarkeit von Maschinen und Räumen ist in mehrere Slots dieser Dauer aufgeteilt. Dieser Wert kann je Verfügbarkeit überschrieben werden."
@ -1243,10 +1247,10 @@ de:
plans_info_html: "<p>Abonnements bieten eine Möglichkeit, Ihre Preise zu segmentieren und Vorteile für reguläre Benutzer zu bieten.</p><p><strong>Warnung:</strong> Es wird nicht empfohlen, die Abonnements zu deaktivieren, wenn mindestens ein Abonnement auf dem System aktiv ist.</p>"
enable_plans: "Pläne aktivieren"
plans_module: "Plan-Modul"
trainings: "Trainings"
trainings_info_html: "<p>Trainings are fully integrated into the Fab-manger's agenda. If enabled, your members will be able to book and pay trainings.</p><p>Trainings provides a way to prevent members to book some machines, if they do have not taken the prerequisite course.</p>"
enable_trainings: "Enable the trainings"
trainings_module: "trainings module"
trainings: "Schulungen"
trainings_info_html: "<p>Schulungen sind vollständig in die Agenda von Fab-Manger integriert. Wenn aktiviert, können Mitglieder Schulungen buchen und bezahlen.</p><p>Schulungen können Mitglieder daran hindern, Maschinen zu buchen, für die sie noch nicht den Grundkurs absolviert haben.</p>"
enable_trainings: "Schulungen aktivieren"
trainings_module: "Schulungs-Modul"
invoicing: "Rechnungsstellung"
invoicing_info_html: "<p>Sie können das Rechnungsmodul komplett deaktivieren.</p><p>Das ist nützlich, wenn Sie über Ihr eigenes Rechnungssystem verfügen und nicht wollen, dass Fab-Manager Rechnungen generiert und an Mitglieder sendet.</p><p><strong>Warnung:</strong> Auch wenn Sie das Rechnungsmodul deaktivieren, müssen Sie die Mehrwertsteuer konfigurieren, um Fehler in Rechnungslegung und Preisen zu vermeiden. Die Konfiguration erfolgt in der Sektion « Rechnungen > Einstellungen ».</p>"
enable_invoicing: "Rechnungsstellung aktivieren"
@ -1256,7 +1260,7 @@ de:
phone_is_required: "Telefonummer erforderlich"
phone_required_info: "Sie können festlegen, ob die Telefonnummer erforderlich sein soll, um einen neuen Benutzer auf Fab-Manager zu registrieren."
address: "Adresse"
address_required_info_html: "You can define if the address should be required to register a new user on Fab-manager.<br/><strong>Please note</strong> that, depending on your country, the regulations may requires addresses for the invoices to be valid."
address_required_info_html: "Sie können festlegen, ob eine Adresse für die Neuregistrierung eines Benutzers erforderlich sein soll.<br/><strong>Bitte beachten Sie</strong> dass in Abhängigkeit von Landesvorschriften Adressen für die Gültigkeit der Rechnungen erforderlich sein können."
address_is_required: "Adresse ist erforderlich"
captcha: "Captcha"
captcha_info_html: "Sie können einen Schutz gegen Roboter einrichten, um zu verhindern, dass diese Accounts erstellen. Dieser Schutz verwendet Google reCAPTCHA. Melden Sie sich für <a href='http://www.google.com/recaptcha/admin' target='_blank'>ein API-Schlüsselpaar</a> an, um reCaptcha zu verwenden."
@ -1278,24 +1282,24 @@ de:
confirmation_required_info: "Optional können Sie die Bestätigung der E-Mail-Adresse für Benutzer obligatorisch machen, bevor Sie Zugriff auf Fab-Manager bekommen."
confirmation_is_required: "Bestätigung erforderlich"
wallet_module: "Guthabenkonto-Modul"
public_agenda_module: "public agenda module"
public_agenda_module: "öffentliches Agenda-Modul"
statistics_module: "Statistik-Modul"
upcoming_events_shown: "Anzeigelimit für anstehende Termine"
display_invite_to_renew_pack: "Display the invite to renew prepaid-packs"
packs_threshold_info_html: "You can define under how many hours the user will be invited to buy a new prepaid-pack, if his stock of prepaid hours is under this threshold.<br/>You can set a <strong>number of hours</strong> (<em>eg. 5</em>) or a <strong>percentage</strong> of his current pack pack (<em>eg. 0.05 means 5%</em>)."
renew_pack_threshold: "threshold for packs renewal"
pack_only_for_subscription_info_html: "If this option is activated, the purchase and use of a prepaid pack is only possible for the user with a valid subscription."
pack_only_for_subscription: "Subscription valid for purchase and use of a prepaid pack"
pack_only_for_subscription_info: "Make subscription mandatory for prepaid packs"
extended_prices: "Extended prices"
extended_prices_info_html: "Spaces can have different prices depending on the cumulated duration of the booking. You can choose if this apply to all bookings or only to those starting within the same day."
extended_prices_in_same_day: "Extended prices in the same day"
public_registrations: "Public registrations"
display_invite_to_renew_pack: "Einladung zur Erneuerung der vorausbezahlten Pakete anzeigen"
packs_threshold_info_html: "Sie können festlegen, ab wievielen Reststunden der Benutzer auf den Kauf eines neuen Pakets an vorausbezahlten Stunden hingewiesen wird.<br/>Sie können eine <strong>Anzahl von Stunden</strong> (<em>z. B. 5</em>) oder einen <strong>Prozentsatz</strong> seines aktuellen Pakets (<em>z. B. 0,05 bedeutet 5%</em>) angeben."
renew_pack_threshold: "Schwellenwert für Paketverlängerung"
pack_only_for_subscription_info_html: "Wenn diese Option aktiviert ist, können nur Benutzer mit einem gültigen Abonnement vorausbezahlte Pakete kaufen und nutzen."
pack_only_for_subscription: "Abonnement gültig für Kauf und Nutzung eines vorausbezahlten Pakets"
pack_only_for_subscription_info: "Abonnement für vorausbezahlte Pakete obligatorisch machen"
extended_prices: "Erweiterter Preis"
extended_prices_info_html: "Räume können je nach Dauer der Buchung unterschiedliche Preise haben. Sie können wählen, ob dies für alle Buchungen oder nur für diejenigen gilt, die am selben Tag beginnen."
extended_prices_in_same_day: "Erweiterte Preise am selben Tag"
public_registrations: "Öffentliche Registrierungen"
overlapping_options:
training_reservations: "Trainings"
machine_reservations: "Machines"
space_reservations: "Spaces"
events_reservations: "Events"
training_reservations: "Schulungen"
machine_reservations: "Maschinen"
space_reservations: "Räume"
events_reservations: "Veranstaltungen"
general:
general: "Allgemein"
title: "Titel"
@ -1317,9 +1321,9 @@ de:
name: "Name"
created_at: "Erstellungsdatum"
updated_at: "Datum der letzten Aktualisierung"
public_registrations: "Public registrations"
public_registrations_info: "Allow everyone to register a new account on the platform. If disabled, only administrators and managers can create new accounts."
public_registrations_allowed: "Public registrations allowed"
public_registrations: "Öffentliche Registrierungen"
public_registrations_info: "Erlaube jedem, ein neues Konto auf der Plattform anzulegen. Wenn deaktiviert, können nur Administratoren und Manager neue Konten erstellen."
public_registrations_allowed: "Öffentliche Registrierungen erlaubt"
help: "Hilfe"
feature_tour: "Feature-Tour"
feature_tour_info_html: "<p>Wenn sich ein Administrator oder Manager anmeldet, wird beim jeweils ersten Besuch eines Abschnitts der Anwendung die Feature-Tour ausgelöst. Sie können dieses Verhalten auf einen der folgenden Werte ändern:</p><ul><li>« Einmal », um das Standardverhalten beizubehalten.</li><li>« Pro Sitzung », um die Tour jedes Mal anzuzeigen, wenn die Anwendung erneut geöffnet wird.</li><li>« Nur manuell », deaktiviert die automatische Anzeige der Touren. Es ist weiterhin möglich, sie durch Drücken der F1-Taste oder durch Klicken auf « Hilfe » im Benutzermenu zu starten.</li></ul>"
@ -1335,9 +1339,9 @@ de:
wallet: "Guthabenkonto"
wallet_info_html: "<p>Mit dem Guthabenkonto können Sie Benutzern eine Geldsumme zuweisen. Diese können es nach Belieben im Fab-Manager ausgeben.</p><p>Mitglieder können ihr Guthabenkonto nicht selbst aufladen, das können nur Manager und Administratoren.</p>"
enable_wallet: "Guthabenkonto aktivieren"
public_agenda: "Public agenda"
public_agenda_info_html: "<p>The public agenda offers to members and visitors a general overview of the Fablab's planning.</p><p>Please note that, even logged, users won't be able to book a reservation or modify anything from this agenda: this is a read-only page.</p>"
enable_public_agenda: "Enable public agenda"
public_agenda: "Öffentliche Agenda"
public_agenda_info_html: "<p>Die öffentliche Agenda bietet Mitgliedern und Besuchern eine allgemeine Übersicht über die Planung des Fablabs.</p><p>Bitte beachten Sie, dass selbst eingeloggte Benutzer keine Reservierung buchen oder die Agenda ändern können: Dies ist eine schreibgeschützte Seite.</p>"
enable_public_agenda: "Öffentliche Agenda aktivieren"
statistics: "Statistiken"
statistics_info_html: "<p>Aktivieren oder deaktivieren Sie das Statistik-Modul.</p><p>Wenn aktiviert, konsolidiert das Modul die Tagesdaten in der Datenbank einer leistungsstarken Analyse-Engine. Administratoren können im entsprechenden Abschnitt die erstellten Diagramme und Tabellen durchsuchen.</p>"
enable_statistics: "Statistik-Modul aktivieren"
@ -1381,7 +1385,7 @@ de:
online_payment: "Ist das Online-Zahlungsmodul aktiv?"
invoices: "Ist das Rechnungsmodul aktiv?"
openlab: "Ist das Projektteilungsmodul (OpenLab) aktiv?"
tracking_id_info_html: "<p>Um die statistische Analyse der Besuche mithilfe von Google Analytics zu ermöglichen, tragen Sie hier Ihre Tracking-ID in der Form UA-000000-0 ein. Besuchen Sie <a href='https://analytics.google.com/analytics/web/' target='_blank'>die Google Analytics Website</a>, um eine Tracking-ID zu erstellen.<br/><strong>Warnung:</strong> wenn Sie dieses Feature aktivieren, muss in Ihrer Datenschutzrichtlinie darauf hingewiesen werden.</p><p> Um Google Analytics verwenden zu können, benötigen Sie auch den Hostnamen. Klicken Sie auf die angrenzende Schaltfläche. Dieser letzte Parameter wird auch an anderen Stellen verwendet, bitte verwenden Sie ihn vorsichtig.</p>"
tracking_id_info_html: "Um die statistische Analyse der Besuche mithilfe von Google Analytics V4 zu ermöglichen, tragen Sie hier Ihre Tracking-ID in der Form G-XXXXXX ein. Besuchen Sie <a href='https://analytics.google.com/analytics/web/' target='_blank'>die Google Analytics Website</a>, um eine Tracking-ID zu erstellen.<br/><strong>Warnung:</strong> wenn Sie dieses Feature aktivieren, wird ein Cookie erstellt. Denken Sie daran, es oben in Ihrer Datenschutzrichtlinie darauf hingewiesen werden."
tracking_id: "Tracking-ID"
open_api_clients:
add_new_client: "Neuen API-Client erstellen"
@ -1395,7 +1399,7 @@ de:
client_name: "Kundenname"
confirmation_required: "Bestätigung erforderlich"
do_you_really_want_to_delete_this_open_api_client: "Möchten Sie diesen OpenAPI-Client wirklich löschen?"
do_you_really_want_to_revoke_this_open_api_access: "Möchten Sie diesen Zugriff wirklich widerrufen ? Er wird das aktuelle Token löschen und ersetzen."
do_you_really_want_to_revoke_this_open_api_access: "Möchten Sie diesen Zugriff wirklich widerrufen? Er wird das aktuelle Token löschen und ersetzen."
client_successfully_created: "Client erfolgreich erstellt."
client_successfully_updated: "Client erfolgreich aktualisiert."
client_successfully_deleted: "Client erfolgreich gelöscht."
@ -1422,50 +1426,50 @@ de:
report_removed: "Der Bericht wurde gelöscht"
failed_to_remove: "Ein Fehler ist aufgetreten, der Bericht konnte nicht gelöscht werden"
plans_categories:
manage_plans_categories: "Manage plans' categories"
manage_plans_categories: "Plan-Kategorien verwalten"
plan_categories_list:
categories_list: "List of the plan's categories"
categories_list: "Liste der Kategorien des Plans"
no_categories: "Keine Kategorien"
name: "Name"
significance: "Significance"
significance: "Signifikanz"
create_plan_category:
new_category: "New category"
new_category: "Neue Kategorie"
name: "Name"
significance: "Significance"
significance_info: "Categories will be shown ordered by signifiance. The higher you set the significance, the first the category will be shown."
confirm_create: "Create the category"
category_created: "The new category was successfully created"
unable_to_create: "Unable to create the category: "
significance: "Signifikanz"
significance_info: "Kategorien werden nach Signifikanz sortiert. Je höher die Signifikanz, desto weiter oben wird die Kategorie angezeigt."
confirm_create: "Kategorie erstellen"
category_created: "Die neue Kategorie wurde erfolgreich erstellt"
unable_to_create: "Die Kategorie konnte nicht erstellt werden: "
edit_plan_category:
edit_category: "Edit the category"
edit_category: "Kategorie bearbeiten"
name: "Name"
significance: "Significance"
confirm_edition: "Validate"
category_updated: "The category was successfully updated"
unable_to_update: "Unable to update the category: "
significance_info: "Categories will be shown ordered by signifiance. The higher you set the significance, the first the category will be shown."
significance: "Signifikanz"
confirm_edition: "Bestätigen"
category_updated: "Die Kategorie wurde erfolgreich aktualisiert"
unable_to_update: "Die Kategorie konnte nicht aktualisiert werden: "
significance_info: "Kategorien werden nach Signifikanz sortiert. Je höher die Signifikanz, desto weiter oben wird die Kategorie angezeigt."
delete_plan_category:
delete_category: "Delete a category"
confirm_delete: "Delete"
delete_confirmation: "Are you sure you want to delete this category? If you do, the plans associated with this category won't be sorted anymore."
category_deleted: "The category was successfully deleted"
unable_to_delete: "Unable to delete the category: "
delete_category: "Kategorie löschen"
confirm_delete: "Löschen"
delete_confirmation: "Sind Sie sicher, dass Sie diese Kategorie löschen möchten? Wenn Sie dies tun, werden die mit dieser Kategorie verbundenen Pläne nicht mehr sortiert."
category_deleted: "Die Kategorie wurde erfolgreich gelöscht"
unable_to_delete: "Die Kategorie konnte nicht gelöscht werden: "
local_payment:
validate_cart: "Validate my cart"
offline_payment: "Payment on site"
about_to_cash: "You're about to confirm the cashing by an external payment mean. Please do not click on the button below until you have fully cashed the requested payment."
about_to_confirm: "You're about to confirm your {ITEM, select, subscription{subscription} other{reservation}}."
payment_method: "Payment method"
method_card: "Online by card"
method_check: "By check"
method_transfer: "By bank transfer"
card_collection_info: "By validating, you'll be prompted for the member's card number. This card will be automatically charged at the deadlines."
check_collection_info: "By validating, you confirm that you have {DEADLINES} checks, allowing you to collect all the monthly payments."
transfer_collection_info: "<p>By validating, you confirm that you set up {DEADLINES} bank direct debits, allowing you to collect all the monthly payments.</p><p><strong>Please note:</strong> the bank transfers are not automatically handled by Fab-manager.</p>"
online_payment_disabled: "Online payment is not available. You cannot collect this payment schedule by online card."
validate_cart: "Bestätigen Sie den Warenkorb"
offline_payment: "Zahlung vor Ort"
about_to_cash: "Sie bestätigen die Zahlung über ein externes Zahlungsmittel. Bitte klicken Sie nicht auf die Schaltfläche unten, bis Sie die angeforderte Zahlung vollständig eingelöst haben."
about_to_confirm: "Sie bestätigen nun {ITEM, select, subscription{Ihr Abonnement} other{Ihre Reservierung}}"
payment_method: "Zahlungsmethode"
method_card: "Online per Karte"
method_check: "Per Scheck"
method_transfer: "Per Banküberweisung"
card_collection_info: "Nach der Validierung werden Sie nach der Kartennummer des Mitglieds gefragt. Diese Karte wird automatisch zu den Fristen belastet."
check_collection_info: "Durch die Validierung bestätigen Sie, dass Sie {DEADLINES} Schecks haben und so alle monatlichen Zahlungen abwickeln können."
transfer_collection_info: "<p>Durch die Validierung bestätigen Sie, dass Sie {DEADLINES} Bank-Lastschriften eingerichtet haben, so dass alle monatlichen Zahlungen eingezogen werden können.</p><p><strong>Bitte beachten Sie:</strong> Banküberweisungen werden nicht automatisch vom Fab-Manager bearbeitet.</p>"
online_payment_disabled: "Online-Zahlung ist nicht verfügbar. Sie können diesen Zahlungsplan nicht per Karte online abwickeln."
check_list_setting:
save: 'Save'
customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved."
save: 'Speichern'
customization_of_SETTING_successfully_saved: "Anpassung von {SETTING} erfolgreich gespeichert."
#feature tour
tour:
conclusion:
@ -1554,8 +1558,8 @@ de:
title: "Gutschrift"
content: "Ermöglicht die Erstellung einer Gutschrift für die Rechnung in dieser Zeile oder für ihre Unterelemente. <strong>Warnung:</strong> Nur das Rechnungsdokument wird generiert, die tatsächliche Gutschrift für den Benutzer wird immer in Ihrer Verantwortung liegen."
payment-schedules:
title: "Payment schedules"
content: "<p>Some subscription plans may be configured to allow the members to pay them with a monthly payment schedule.</p><p>Here you can view all existing payment schedules and manage their deadlines.</p><p>Click on [+] at the beginning of a row to display all deadlines associated with a payment schedule, and run some actions on them.</p>"
title: "Zahlungspläne"
content: "<p>Einige Abonnements können so konfiguriert werden, dass die Mitglieder sie mit einem monatlichen Zahlungsplan bezahlen können.</p><p>Hier können Sie alle bestehenden Zahlungspläne einsehen und deren Fristen verwalten.</p><p>Klicken Sie auf [+] am Anfang einer Reihe, um alle mit einem Zahlungsplan verbundenen Fristen anzuzeigen, und führen Sie Aktionen aus.</p>"
settings:
title: "Einstellungen"
content: "<p>Hier können Sie die Parameter für die Rechnungserstellung ändern. Klicken Sie auf das Element, das Sie bearbeiten wollen.</p><p>Insbesondere legen Sie hier fest, ob Sie der Mehrwertsteuer unterliegen und zu welchem Satz.</p>"

View File

@ -15,7 +15,7 @@ en:
trainings: "Trainings"
machines: "Machines"
spaces: "Spaces"
events: "Eventos"
events: "Events"
availabilities: "Availabilities"
availabilities_notice: "Export to an Excel workbook every slots available for reservation, and their occupancy rate."
info: "Info"
@ -24,7 +24,7 @@ en:
ongoing_reservations: "Ongoing reservations"
without_reservation: "Without reservation"
confirmation_required: "Confirmation required"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Do you really {GENDER, select, other {want}} to cancel the {USER}'s reservation, the {DATE} at {TIME}, concerning {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Do you really want to cancel {USER}'s reservation, the {DATE} at {TIME}, concerning {RESERVATION}?"
reservation_was_successfully_cancelled: "Reservation was successfully cancelled."
reservation_cancellation_failed: "Reservation cancellation failed."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Unable to remove the last machine of the slot. Delete the slot rather."
@ -184,7 +184,7 @@ en:
NUMBER_reservation: "{NUMBER} {NUMBER, plural, one{reservation} other{reservations}}"
none: "None"
training_validation: "Training validation"
training_of_the_DATE_TIME_html : "Training of the <strong>{DATE} - {TIME}</strong>"
training_of_the_DATE_TIME_html: "Training of the <strong>{DATE} - {TIME}</strong>"
you_can_validate_the_training_of_the_following_members: "You can validate the training of the following members:"
deleted_user: "Deleted user"
no_reservation: "No reservation"
@ -271,7 +271,7 @@ en:
events_edit:
edit_the_event: "Edit the event"
confirmation_required: "Confirmation required"
edit_recurring_event: "You're about to update a periodic event. What do you want to update ?"
edit_recurring_event: "You're about to update a periodic event. What do you want to update?"
edit_this_event: "Only this event"
edit_this_and_next: "This event and the following"
edit_all: "All events"
@ -322,10 +322,10 @@ en:
none: "None" #grammar concordance with training.
an_error_occurred_while_saving_the_number_of_credits: "An error occurred while saving the number of credits."
an_error_occurred_while_deleting_credit_with_the_TRAINING: "An error occurred while deleting credit with the {TRAINING}."
an_error_occurred_unable_to_find_the_credit_to_revoke: "An error occurred : unable to find the credit to revoke."
an_error_occurred_unable_to_find_the_credit_to_revoke: "An error occurred: unable to find the credit to revoke."
an_error_occurred_while_creating_credit_with_the_TRAINING: "An error occurred while creating credit with the {TRAINING}."
not_set: "Not set"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Error : a credit linking this machine with that subscription already exists."
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"
@ -365,7 +365,7 @@ en:
these_prices_match_space_hours_rates_html: "The prices below match one hour of space usage, <strong>without subscription</strong>."
add_a_space_credit: "Add a Space credit"
space: "Space"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Error : a credit linking this space with that subscription already exists."
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"
@ -511,7 +511,7 @@ en:
no_invoices_for_now: "No invoices for now."
payment_schedules_list: "Payment schedules"
invoicing_settings: "Invoicing settings"
warning_invoices_disabled: "Warning : invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
warning_invoices_disabled: "Warning: invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
change_logo: "Change logo"
john_smith: "John Smith"
john_smith_at_example_com: "jean.smith@example.com"
@ -702,6 +702,10 @@ en:
general_space_code: "Accounting code for all spaces"
accounting_Space_label: "Spaces label"
general_space_label: "Account label for all spaces"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Errors code"
general_error_code: "Accounting code for erroneous invoices"
accounting_Error_label: "Errors label"
@ -1012,7 +1016,7 @@ en:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Add an administrator"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator successfully created. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} connection directives by e-mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Successful creation. Connection directives were sent to the new administrator by e-mail."
failed_to_create_admin: "Unable to create the administrator:"
man: "Man"
woman: "Woman"
@ -1030,7 +1034,7 @@ en:
#add a new manager to the platform
manager_new:
add_a_manager: "Add a manager"
manager_successfully_created: "Manager successfully created. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} connection directives by e-mail."
manager_successfully_created: "Successful creation. Connection directives were sent to the new manager by e-mail."
failed_to_create_manager: "Unable to create the manager:"
man: "Man"
woman: "Woman"
@ -1061,7 +1065,7 @@ en:
oauth2_provider_successfully_added: "OAuth 2.0 provider successfully added."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Provider :"
provider: "Provider:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "It is required to set the matching between User.uid and the API to add this provider."
provider_successfully_updated: "Provider successfully updated."
an_error_occurred_unable_to_update_the_provider: "An error occurred: unable to update the provider."
@ -1351,7 +1355,7 @@ en:
public_registrations_allowed: "Public registrations allowed"
help: "Help"
feature_tour: "Feature tour"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_display_mode: "Feature tour display mode"
display_mode:
once: "Once"
@ -1410,7 +1414,7 @@ en:
online_payment: "Is the online payment module active?"
invoices: "Is the invoicing module active?"
openlab: "Is the project sharing module (OpenLab) active?"
tracking_id_info_html: "<p>To enable the statistical tracking of the visits using Google Analytics, set your tracking ID here. It is in the form UA-000000-2. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, remember to write it in your privacy policy, above.</p><p>The host name is also required to use Google Analytics. You can get it by clicking on the adjacent button. This last parameter is used elsewhere, please set it carefully.</p>"
tracking_id_info_html: "To enable the statistical tracking of the visits using Google Analytics V4, set your tracking ID here. It is in the form G-XXXXXX. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, a cookie will be created. Remember to write it down in your privacy policy, above."
tracking_id: "Tracking ID"
open_api_clients:
add_new_client: "Create new API client"
@ -1424,7 +1428,7 @@ en:
client_name: "Client's name"
confirmation_required: "Confirmation required"
do_you_really_want_to_delete_this_open_api_client: "Do you really want to delete this OpenAPI client?"
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access ? It will erase and replace the current token."
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access? It will erase and replace the current token."
client_successfully_created: "Client successfully created."
client_successfully_updated: "Client successfully updated."
client_successfully_deleted: "Client successfully deleted."

View File

@ -24,7 +24,7 @@ es:
ongoing_reservations: "Reservas en curso"
without_reservation: "Sin reserva"
confirmation_required: "Confirmación requerida"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Realmente quieres cancelar la reserva del {USER}, en {DATE} a las {TIME}, respecto {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "¿Realmente quieres cancelar la reserva del {USER}, en {DATE} a las {TIME}, respecto {RESERVATION}?"
reservation_was_successfully_cancelled: "La reserva fué cancelada con éxito."
reservation_cancellation_failed: "Fallo al cancelar la reserva."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "No se puede quitar la última máquina de la ranura. Eliminar la ranura en su lugar."
@ -271,7 +271,7 @@ es:
events_edit:
edit_the_event: "Editar el evento"
confirmation_required: "Confirmation required"
edit_recurring_event: "You're about to update a periodic event. What do you want to update ?"
edit_recurring_event: "You're about to update a periodic event. What do you want to update?"
edit_this_event: "Only this event"
edit_this_and_next: "This event and the following"
edit_all: "All events"
@ -482,7 +482,7 @@ es:
no_invoices_for_now: "Sin facturas por ahora."
payment_schedules_list: "Payment schedules"
invoicing_settings: "Configuración de facturación"
warning_invoices_disabled: "Warning : invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
warning_invoices_disabled: "Warning: invoices are not enabled. No invoices will be generated by Fab-manager. Nevertheless, you must correctly fill the information below, especially VAT."
change_logo: "Cambio de logotipo"
john_smith: "John Smith"
john_smith_at_example_com: "jean.smith@example.com"
@ -673,6 +673,10 @@ es:
general_space_code: "Accounting code for all spaces"
accounting_Space_label: "Spaces label"
general_space_label: "Account label for all spaces"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Errors code"
general_error_code: "Accounting code for erroneous invoices"
accounting_Error_label: "Errors label"
@ -838,7 +842,7 @@ es:
active: "Activo"
pending: "Pendiente"
previous_provider: "Proveedor anteriorr"
confirmation_required: "Delete the provider?"
confirmation_required: "¿Eliminar el proveedor?"
do_you_really_want_to_delete_the_TYPE_authentication_provider_NAME: "¿Realmente desea eliminar la {TYPE} proveedor de autenticación: {NAME}?"
authentication_provider_successfully_deleted: "El proveedor de autenticación se eliminó correctamente."
an_error_occurred_unable_to_delete_the_specified_provider: "Se ha producido un error: no se puede eliminar el proveedor especificado."
@ -983,7 +987,7 @@ es:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Agregar un administrador"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "administrador creado correctamente. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} directivas de conexión por e-mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Successful creation. Connection directives were sent to the new administrator by e-mail."
failed_to_create_admin: "No se puede crear el administrador :"
man: "Man"
woman: "Woman"
@ -1001,7 +1005,7 @@ es:
#add a new manager to the platform
manager_new:
add_a_manager: "Add a manager"
manager_successfully_created: "Manager successfully created. {GENDER, select, female{She} other{He}} receive {GENDER, select, female{her} other{his}} connection directives by e-mail."
manager_successfully_created: "Successful creation. Connection directives were sent to the new manager by e-mail."
failed_to_create_manager: "Unable to create the manager:"
man: "Man"
woman: "Woman"
@ -1032,7 +1036,7 @@ es:
oauth2_provider_successfully_added: "OAuth 2.0 proveedor agregado correctamente."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Proveedor :"
provider: "Proveedor:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "Es necesario establecer la coincidencia entre User.uid y la API para agregar este proveedor."
provider_successfully_updated: "Proveedor actualizado correctamente."
an_error_occurred_unable_to_update_the_provider: "Se ha producido un error: no se puede actualizar el proveedor."
@ -1322,7 +1326,7 @@ es:
public_registrations_allowed: "Public registrations allowed"
help: "Help"
feature_tour: "Feature tour"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_display_mode: "Feature tour display mode"
display_mode:
once: "Once"
@ -1381,7 +1385,7 @@ es:
online_payment: "Is the online payment module active?"
invoices: "Is the invoicing module active?"
openlab: "Is the project sharing module (OpenLab) active?"
tracking_id_info_html: "<p>To enable the statistical tracking of the visits using Google Analytics, set your tracking ID here. It is in the form UA-000000-2. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, remember to write it in your privacy policy, above.</p><p>The host name is also required to use Google Analytics. You can get it by clicking on the adjacent button. This last parameter is used elsewhere, please set it carefully.</p>"
tracking_id_info_html: "To enable the statistical tracking of the visits using Google Analytics V4, set your tracking ID here. It is in the form G-XXXXXX. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, a cookie will be created. Remember to write it down in your privacy policy, above."
tracking_id: "Tracking ID"
open_api_clients:
add_new_client: "Crear un nuevo cliente de API"
@ -1395,7 +1399,7 @@ es:
client_name: "Nombre del cliente"
confirmation_required: "Confirmation required"
do_you_really_want_to_delete_this_open_api_client: "¿Desea realmente eliminar este cliente OpenAPI?"
do_you_really_want_to_revoke_this_open_api_access: "¿Realmente desea revocar este acceso? Se borrará y reemplazará el token actual."
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access? It will erase and replace the current token."
client_successfully_created: "Cliente creado correctamente."
client_successfully_updated: "Cliente actualizado correctamente."
client_successfully_deleted: "Cliente borrado correctamente."

View File

@ -24,7 +24,7 @@ fr:
ongoing_reservations: "Réservations en cours"
without_reservation: "Sans réservation"
confirmation_required: "Confirmation requise"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Êtes-vous {GENDER, select, female{sûre} other{sûr}} de vouloir annuler la réservation de {USER}, le {DATE} à {TIME}, concernant {RESERVATION} ?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Voulez-vous vraiment annuler la réservation de {USER}, le {DATE} à {TIME}, concernant {RESERVATION} ?"
reservation_was_successfully_cancelled: "La réservation a bien été annulée."
reservation_cancellation_failed: "L'annulation de la réservation a échouée."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Impossible de supprimer la dernière machine du créneau. Supprimez plutôt le créneau."
@ -271,7 +271,7 @@ fr:
events_edit:
edit_the_event: "Éditer lévénement"
confirmation_required: "Confirmation requise"
edit_recurring_event: "Vous êtes sur le point de modifier un événement périodique. Que voulez-vous modifier ?"
edit_recurring_event: "Vous êtes sur le point de mettre à jour un événement périodique. Que voulez-vous mettre à jour ?"
edit_this_event: "Uniquement cet événement"
edit_this_and_next: "Cet événement et tous les suivants"
edit_all: "Tous les événements"
@ -673,6 +673,10 @@ fr:
general_space_code: "Code comptable pour tous les espaces"
accounting_Space_label: "Libellé espaces"
general_space_label: "Libellé du compte pour tous les espaces"
accounting_Pack_code: "Code pack prépayé"
general_pack_code: "Code comptable pour tous les packs prépayés"
accounting_Pack_label: "Libellé pack prépayé"
general_pack_label: "Libellé du compte pour tous les packs prépayés"
accounting_Error_code: "Code erreurs"
general_error_code: "Code comptable pour les factures en erreur"
accounting_Error_label: "Libellé erreurs"
@ -983,7 +987,7 @@ fr:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Ajouter un administrateur"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "L'administrateur a bien été créé. {GENDER, select, female{Elle} other{Il}} recevra ses instructions de connexion par email."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Création réussie. Les directives de connexion ont été envoyées à l'administrateur par e-mail."
failed_to_create_admin: "Impossible de créer l'administrateur :"
man: "Homme"
woman: "Femme"
@ -1001,7 +1005,7 @@ fr:
#add a new manager to the platform
manager_new:
add_a_manager: "Ajouter un gestionnaire"
manager_successfully_created: "Le gestionnaire a bien été créé. {GENDER, select, female{Elle} other{Il}} recevra ses instructions de connexion par courriel."
manager_successfully_created: "Création réussie. Les directives de connexion ont été envoyées au nouveau gestionnaire par e-mail."
failed_to_create_manager: "Impossible de créer le gestionnaire :"
man: "Homme"
woman: "Femme"
@ -1381,7 +1385,7 @@ fr:
online_payment: "Le module de paiement par carte bancaire est-il actif ?"
invoices: "Le module est facturation est-il actif ?"
openlab: "Le module de partage de projets (OpenLab) est-il actif ?"
tracking_id_info_html: "<p>Pour activer les suivi statistique des visites utilisant Google Analytics, définissez ici votre ID de suivi. Il se présente sous la forme UA-000000-2. Visitez <a href='https://analytics.google.com/analytics/web/' target='_blank'>le site web de Google Analytics</a> pour en obtenir un.<br/><strong>Attention :</strong> si vous activez cette fonctionnalité, pensez à l'indiquer dans votre politique de confidentialité, ci-dessus.</p><p>Le nom d'hôte est également requis pour pouvoir utiliser Google Analytics. Vous pouvez l'obtenir en cliquant sur le bouton adjacent. Ce dernier paramètre est utilisé ailleurs, veuillez le définir avec soin.</p>"
tracking_id_info_html: "Pour activer les suivi statistique des visites utilisant Google Analytics V4, définissez ici votre ID de suivi. Il se présente sous la forme G-XXXXXX. Visitez <a href='https://analytics.google.com/analytics/web/' target='_blank'>le site web de Google Analytics</a> pour en obtenir un.<br/><strong>Attention :</strong> si vous activez cette fonctionnalité, une cookie sera créé. Pensez à l'indiquer dans votre politique de confidentialité, ci-dessus."
tracking_id: "ID de suivi"
open_api_clients:
add_new_client: "Créer un compte client"

View File

@ -24,7 +24,7 @@
ongoing_reservations: "Pågående reservasjoner"
without_reservation: "Ikke reservert"
confirmation_required: "Bekreftelse nødvendig"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "{GENDER, select, other {Ønsker du å}} kansellere {USER} sin reservasjon {DATE}, {TIME} for {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Ønsker du å kansellere {USER} sin reservasjon {DATE}, {TIME} for {RESERVATION}?"
reservation_was_successfully_cancelled: "Kansellering av reservasjon er gjennomført."
reservation_cancellation_failed: "Det gikk ikke an å kansellere reservasjonen."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Kan ikke fjerne siste maskinen fra reservasjonen. Slett reservasjonen."
@ -325,7 +325,7 @@
an_error_occurred_unable_to_find_the_credit_to_revoke: "En feil oppstod: kunne ikke finne kreditten som skal tilbakekalles."
an_error_occurred_while_creating_credit_with_the_TRAINING: "Det oppstod en feil under oppretting av kreditt med {TRAINING}."
not_set: "Ikke angitt"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Feil : en kreditnota på denne maskinen med dette abonnementet finnes allerede."
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Feil: en kreditnota på denne maskinen med dette abonnementet finnes allerede."
changes_have_been_successfully_saved: "Endringene er lagret."
credit_was_successfully_saved: "Kreditten ble lagret."
error_creating_credit: "Kan ikke opprette kreditt, feil oppstod"
@ -365,7 +365,7 @@
these_prices_match_space_hours_rates_html: "Prisene under samsvarer med en time maskinbruk <strong>uten abonnement</strong>."
add_a_space_credit: "Legg til en plass/romkreditt"
space: "Plass/rom"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Feil : en kreditnota på denne maskinen med dette abonnementet finnes allerede."
error_a_credit_linking_this_space_with_that_subscription_already_exists: "Feil: en kreditnota på denne maskinen med dette abonnementet finnes allerede."
status_enabled: "Aktivert"
status_disabled: "Deaktivert"
status_all: "Alle"
@ -673,6 +673,10 @@
general_space_code: "Regnskapskode for plasser/rom"
accounting_Space_label: "Etikett, plasser/rom"
general_space_label: "Regnskapskode for alle plasser/rom"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Kode for feil"
general_error_code: "Regnskapskode for fakturafeil"
accounting_Error_label: "Etikett for feil"
@ -1295,7 +1299,7 @@
training_reservations: "Trainings"
machine_reservations: "Machines"
space_reservations: "Spaces"
events_reservations: "Events"
events_reservations: "Arrangementer"
general:
general: "Generelt"
title: "Tittel"
@ -1322,7 +1326,7 @@
public_registrations_allowed: "Public registrations allowed"
help: "Hjelp"
feature_tour: "Funksjonsgjennomgang"
feature_tour_info_html: "<p>When an administrator or a manager in logged-in, a feature tour will be triggered the first time he/she visits each section of the application. You can change this behavior to one of the following values:</p><ul><li>« Once » to keep the default behavior.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » to prevent displaying the tours automatically. It'll still be possible to trigger them by pressing the F1 key or by clicking on « Help » in the user's menu.</li></ul>"
feature_tour_info_html: "<p>Når en administrator eller en leder er innlogget En fremvisning utløses første gang han besøker hver del av applikasjonen. Du kan endre denne adferden til en av følgende verdier:</p><ul><li>« Once » for å beholde standardvirkemåten.</li><li>« By session » to display the tours each time you reopen the application.</li><li>« Manual trigger » for å forhindre at turene vises automatisk. Det vil fortsatt være mulig å utløse dem ved å trykke F1-tasten eller ved å klikke på « Hjelp » i brukermenyen.</li></ul>"
feature_tour_display_mode: "Modus for funksjonsgjennomgang"
display_mode:
once: "Én gang"
@ -1381,7 +1385,7 @@
online_payment: "Is the online payment module active?"
invoices: "Is the invoicing module active?"
openlab: "Is the project sharing module (OpenLab) active?"
tracking_id_info_html: "<p>To enable the statistical tracking of the visits using Google Analytics, set your tracking ID here. It is in the form UA-000000-2. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, remember to write it in your privacy policy, above.</p><p>The host name is also required to use Google Analytics. You can get it by clicking on the adjacent button. This last parameter is used elsewhere, please set it carefully.</p>"
tracking_id_info_html: "To enable the statistical tracking of the visits using Google Analytics V4, set your tracking ID here. It is in the form G-XXXXXX. Visit <a href='https://analytics.google.com/analytics/web/' target='_blank'>the Google Analytics website</a> to get one.<br/><strong>Warning:</strong> if you enable this feature, a cookie will be created. Remember to write it down in your privacy policy, above."
tracking_id: "Tracking ID"
open_api_clients:
add_new_client: "Lage ny API-klient"
@ -1395,7 +1399,7 @@
client_name: "Klientens navn"
confirmation_required: "Confirmation required"
do_you_really_want_to_delete_this_open_api_client: "Do you really want to delete this OpenAPI client?"
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access ? It will erase and replace the current token."
do_you_really_want_to_revoke_this_open_api_access: "Do you really want to revoke this access? It will erase and replace the current token."
client_successfully_created: "Client successfully created."
client_successfully_updated: "Client successfully updated."
client_successfully_deleted: "Client successfully deleted."
@ -1595,7 +1599,7 @@
content: "Create and manage promotional coupons allowing to offer punctual discounts to their holders."
events:
welcome:
title: "Events"
title: "Arrangementer"
content: "Create events, track their reservations and organize them from this page."
list:
title: "The events"

View File

@ -15,7 +15,7 @@ pt:
trainings: "Treinamentos"
machines: "Máquinas"
spaces: "Espaços"
events: "Eventos"
events: "Events"
availabilities: "Disponíveis"
availabilities_notice: "Exportar para Excel livro com todos os slots disponíveis para reserva, e suas ocupações."
info: "Informações"
@ -24,7 +24,7 @@ pt:
ongoing_reservations: "Reservas em curso"
without_reservation: "Sem reservas"
confirmation_required: "Confirmação Obrigatória"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Você realmente deseja cancelar a reserva do usuário {USER}, em {DATE} ás {TIME}, sobre {RESERVATION}?"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "Realmente deseja cancelar a reserva do usuário {USER}, em {DATE} ás {TIME}, sobre {RESERVATION}?"
reservation_was_successfully_cancelled: "A reserva foi cancelada com sucesso"
reservation_cancellation_failed: "Cancelamento da reserva falhou."
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "Não é possível remover a última máquina do slot. Delete o slot primeiramente."
@ -271,7 +271,7 @@ pt:
events_edit:
edit_the_event: "Editar evento"
confirmation_required: "Confirmação obrigatória"
edit_recurring_event: "Você está prestes a atualizar um evento periódico. O que você quer atualizar ?"
edit_recurring_event: "Você está prestes a atualizar um evento periódico. O que você quer atualizar?"
edit_this_event: "Apenas este evento"
edit_this_and_next: "Este evento e os seguintes"
edit_all: "Todos eventos"
@ -322,10 +322,10 @@ pt:
none: "Vazio" #grammar concordance with training.
an_error_occurred_while_saving_the_number_of_credits: "Um erro ocorreu enquanto era salvo o número de créditos."
an_error_occurred_while_deleting_credit_with_the_TRAINING: "Um erro ocorreu enquanto o crédito era deletado do {TRAINING}."
an_error_occurred_unable_to_find_the_credit_to_revoke: "Um erro ocorreu : incapaz de encontrar o crédito para revogar."
an_error_occurred_unable_to_find_the_credit_to_revoke: "An error occurred: unable to find the credit to revoke."
an_error_occurred_while_creating_credit_with_the_TRAINING: "Ocorreu um erro ao criar o crédito com o {TRAINING}."
not_set: "Não definido"
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."
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "Erro: uma conexão 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: "Não foi possível criar crédito, um erro ocorreu"
@ -673,6 +673,10 @@ pt:
general_space_code: "Código de contabilidade para todos os espaços"
accounting_Space_label: "Rótulo de espaços"
general_space_label: "Rótulo de conta para todos os espaços"
accounting_Pack_code: "Prepaid-pack code"
general_pack_code: "Accounting code for prepaid-packs"
accounting_Pack_label: "Prepaid-pack label"
general_pack_label: "Account label for prepaid-packs"
accounting_Error_code: "Código do erro"
general_error_code: "Código de contabilidade para faturas erradas"
accounting_Error_label: "Rótulo dos erros"
@ -983,7 +987,7 @@ pt:
#add a new administrator to the platform
admins_new:
add_an_administrator: "Adicionar administrador"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Administrator criado com sucesso. {GENDER, select, female{Ela} other{Ele}} receberá {GENDER, select, female{sua} other{seu}} diretivas de conexão por e-mail."
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "Successful creation. Connection directives were sent to the new administrator by e-mail."
failed_to_create_admin: "Não é possível criar administrador:"
man: "Homem"
woman: "Mulher"
@ -1001,7 +1005,7 @@ pt:
#add a new manager to the platform
manager_new:
add_a_manager: "Adicionar Gestor"
manager_successfully_created: "Gerente criado com sucesso. {GENDER, select, female{Ela} other{Ele}} receberá {GENDER, select, female{Suas diretrizes de conexão por e-mail} other{Suas diretrizes de conexão por e-mail}}"
manager_successfully_created: "Successful creation. Connection directives were sent to the new manager by e-mail."
failed_to_create_manager: "Não foi possível criar o gerente:"
man: "Homem"
woman: "Mulher"
@ -1032,7 +1036,7 @@ pt:
oauth2_provider_successfully_added: "Provedor OAuth 2.0 adicionado com sucesso."
#edit an authentication provider (SSO)
authentication_edit:
provider: "Provedor :"
provider: "Provedor:"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "É necessário definir a correspondência entre User.uid ea API para adicionar este fornecedor."
provider_successfully_updated: "Provedor modificado com sucesso."
an_error_occurred_unable_to_update_the_provider: "Um erro ocorreu: não é possível atualizar provedor."
@ -1322,7 +1326,7 @@ pt:
public_registrations_allowed: "Public registrations allowed"
help: "Ajuda"
feature_tour: "Tour de recursos"
feature_tour_info_html: "<p>Quando um administrador ou um gerente está logado, um tour de recurso será acionado na primeira vez que ele/ela visita cada seção do aplicativo. Você pode mudar esse comportamento para um dos seguintes valores:</p><ul><li>« Uma vez » para manter o comportamento padrão.</li><li>« Por sessão » para exibir os tours cada vez que você reabrir o aplicativo.</li><li>« Ativação manual » para evitar a exibição automática dos tours. Ainda será possível ativá-los pressionando a tecla F1 ou clicando em « Ajuda » no menu do usuário.</li></ul>"
feature_tour_info_html: "<p>Quando um administrador ou um gerente está logado, um tour de recurso será acionado na primeira vez que ele visita cada seção do aplicativo. Você pode mudar esse comportamento para um dos seguintes valores:</p><ul><li>« Uma vez » para manter o comportamento padrão.</li><li>« Por sessão » para exibir os tours cada vez que você reabrir o aplicativo.</li><li>« Ativação manual » para evitar a exibição automática dos tours. Ainda será possível ativá-los pressionando a tecla F1 ou clicando em « Ajuda » no menu do usuário.</li></ul>"
feature_tour_display_mode: "Modo de exibição de recursos do tour"
display_mode:
once: "Uma vez"
@ -1381,7 +1385,7 @@ pt:
online_payment: "O módulo de pagamento online está ativo?"
invoices: "O módulo de faturação está ativo?"
openlab: "O módulo de compartilhamento de projetos (OpenLab) está ativo?"
tracking_id_info_html: "<p>Para ativar o rastreamento estatístico das visitas usando o Google Analytics, defina seu ID de rastreamento aqui. Está na forma de UA-000000-2. Visite <a href='https://analytics.google.com/analytics/web/' target='_blank'>o site do Google Analytics</a> para obter um.<br/><strong>Aviso:</strong> se você ativar este recurso, lembre-se de escrevê-lo na sua política de privacidade.</p><p>O nome do host também é necessário para usar o Google Analytics. Você pode obtê-lo clicando no botão adjacente. Este último parâmetro é usado em outro lugar, por favor, defina-o com cuidado.</p>"
tracking_id_info_html: "Para ativar o rastreamento estatístico das visitas usando o Google Analytics, defina seu ID de rastreamento aqui. Está na forma de G-XXXXXX. Visite <a href='https://analytics.google.com/analytics/web/' target='_blank'>o site do Google Analytics</a> para obter um.<br/><strong>Aviso:</strong> se você ativar este recurso, um cookie será criado. Lembre-se de escrevê-lo na sua política de privacidade."
tracking_id: "ID de rastreamento"
open_api_clients:
add_new_client: "Criar novo cliente de API"

View File

@ -15,7 +15,7 @@ zu:
trainings: "crwdns6709:0crwdne6709:0"
machines: "crwdns6711:0crwdne6711:0"
spaces: "crwdns6713:0crwdne6713:0"
events: "crwdns6715:0crwdne6715:0"
events: "crwdns22406:0crwdne22406:0"
availabilities: "crwdns6717:0crwdne6717:0"
availabilities_notice: "crwdns6719:0crwdne6719:0"
info: "crwdns20468:0crwdne20468:0"
@ -24,7 +24,7 @@ zu:
ongoing_reservations: "crwdns6721:0crwdne6721:0"
without_reservation: "crwdns20326:0crwdne20326:0"
confirmation_required: "crwdns6725:0crwdne6725:0"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "crwdns20296:0GENDER={GENDER}crwdnd20296:0USER={USER}crwdnd20296:0DATE={DATE}crwdnd20296:0TIME={TIME}crwdnd20296:0RESERVATION={RESERVATION}crwdne20296:0"
do_you_really_want_to_cancel_the_USER_s_reservation_the_DATE_at_TIME_concerning_RESERVATION: "crwdns22408:0{USER}crwdnd22408:0{DATE}crwdnd22408:0{TIME}crwdnd22408:0{RESERVATION}crwdne22408:0"
reservation_was_successfully_cancelled: "crwdns6729:0crwdne6729:0"
reservation_cancellation_failed: "crwdns6731:0crwdne6731:0"
unable_to_remove_the_last_machine_of_the_slot_delete_the_slot_rather: "crwdns6733:0crwdne6733:0"
@ -271,7 +271,7 @@ zu:
events_edit:
edit_the_event: "crwdns7095:0crwdne7095:0"
confirmation_required: "crwdns19784:0crwdne19784:0"
edit_recurring_event: "crwdns19786:0crwdne19786:0"
edit_recurring_event: "crwdns22410:0crwdne22410:0"
edit_this_event: "crwdns19788:0crwdne19788:0"
edit_this_and_next: "crwdns19790:0crwdne19790:0"
edit_all: "crwdns19792:0crwdne19792:0"
@ -322,10 +322,10 @@ zu:
none: "crwdns19808:0crwdne19808:0" #grammar concordance with training.
an_error_occurred_while_saving_the_number_of_credits: "crwdns7173:0crwdne7173:0"
an_error_occurred_while_deleting_credit_with_the_TRAINING: "crwdns7175:0{TRAINING}crwdne7175:0"
an_error_occurred_unable_to_find_the_credit_to_revoke: "crwdns7177:0crwdne7177:0"
an_error_occurred_unable_to_find_the_credit_to_revoke: "crwdns22412:0crwdne22412:0"
an_error_occurred_while_creating_credit_with_the_TRAINING: "crwdns7179:0{TRAINING}crwdne7179:0"
not_set: "crwdns7181:0crwdne7181:0"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "crwdns7183:0crwdne7183:0"
error_a_credit_linking_this_machine_with_that_subscription_already_exists: "crwdns22414:0crwdne22414:0"
changes_have_been_successfully_saved: "crwdns7185:0crwdne7185:0"
credit_was_successfully_saved: "crwdns7187:0crwdne7187:0"
error_creating_credit: "crwdns7189:0crwdne7189:0"
@ -365,7 +365,7 @@ zu:
these_prices_match_space_hours_rates_html: "crwdns20480:0crwdne20480:0"
add_a_space_credit: "crwdns7259:0crwdne7259:0"
space: "crwdns7261:0crwdne7261:0"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "crwdns7263:0crwdne7263:0"
error_a_credit_linking_this_space_with_that_subscription_already_exists: "crwdns22416:0crwdne22416:0"
status_enabled: "crwdns7265:0crwdne7265:0"
status_disabled: "crwdns7267:0crwdne7267:0"
status_all: "crwdns7269:0crwdne7269:0"
@ -482,7 +482,7 @@ zu:
no_invoices_for_now: "crwdns7337:0crwdne7337:0"
payment_schedules_list: "crwdns21058:0crwdne21058:0"
invoicing_settings: "crwdns7339:0crwdne7339:0"
warning_invoices_disabled: "crwdns7341:0crwdne7341:0"
warning_invoices_disabled: "crwdns22418:0crwdne22418:0"
change_logo: "crwdns7343:0crwdne7343:0"
john_smith: "crwdns7345:0crwdne7345:0"
john_smith_at_example_com: "crwdns7347:0crwdne7347:0"
@ -673,6 +673,10 @@ zu:
general_space_code: "crwdns7677:0crwdne7677:0"
accounting_Space_label: "crwdns7679:0crwdne7679:0"
general_space_label: "crwdns7681:0crwdne7681:0"
accounting_Pack_code: "crwdns22446:0crwdne22446:0"
general_pack_code: "crwdns22448:0crwdne22448:0"
accounting_Pack_label: "crwdns22450:0crwdne22450:0"
general_pack_label: "crwdns22452:0crwdne22452:0"
accounting_Error_code: "crwdns21470:0crwdne21470:0"
general_error_code: "crwdns21472:0crwdne21472:0"
accounting_Error_label: "crwdns21474:0crwdne21474:0"
@ -983,7 +987,7 @@ zu:
#add a new administrator to the platform
admins_new:
add_an_administrator: "crwdns8027:0crwdne8027:0"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "crwdns8029:0GENDER={GENDER}crwdnd8029:0GENDER={GENDER}crwdne8029:0"
administrator_successfully_created_he_will_receive_his_connection_directives_by_email: "crwdns22420:0crwdne22420:0"
failed_to_create_admin: "crwdns8031:0crwdne8031:0"
man: "crwdns8033:0crwdne8033:0"
woman: "crwdns8035:0crwdne8035:0"
@ -1001,7 +1005,7 @@ zu:
#add a new manager to the platform
manager_new:
add_a_manager: "crwdns20348:0crwdne20348:0"
manager_successfully_created: "crwdns20350:0GENDER={GENDER}crwdnd20350:0GENDER={GENDER}crwdne20350:0"
manager_successfully_created: "crwdns22422:0crwdne22422:0"
failed_to_create_manager: "crwdns20352:0crwdne20352:0"
man: "crwdns20354:0crwdne20354:0"
woman: "crwdns20356:0crwdne20356:0"
@ -1032,7 +1036,7 @@ zu:
oauth2_provider_successfully_added: "crwdns8081:0crwdne8081:0"
#edit an authentication provider (SSO)
authentication_edit:
provider: "crwdns8083:0crwdne8083:0"
provider: "crwdns22424:0crwdne22424:0"
it_is_required_to_set_the_matching_between_User.uid_and_the_API_to_add_this_provider: "crwdns20208:0crwdne20208:0"
provider_successfully_updated: "crwdns20210:0crwdne20210:0"
an_error_occurred_unable_to_update_the_provider: "crwdns8089:0crwdne8089:0"
@ -1322,7 +1326,7 @@ zu:
public_registrations_allowed: "crwdns22283:0crwdne22283:0"
help: "crwdns20764:0crwdne20764:0"
feature_tour: "crwdns20766:0crwdne20766:0"
feature_tour_info_html: "crwdns20768:0crwdne20768:0"
feature_tour_info_html: "crwdns22426:0crwdne22426:0"
feature_tour_display_mode: "crwdns20770:0crwdne20770:0"
display_mode:
once: "crwdns20772:0crwdne20772:0"
@ -1381,7 +1385,7 @@ zu:
online_payment: "crwdns19892:0crwdne19892:0"
invoices: "crwdns19894:0crwdne19894:0"
openlab: "crwdns19896:0crwdne19896:0"
tracking_id_info_html: "crwdns20812:0crwdne20812:0"
tracking_id_info_html: "crwdns22442:0crwdne22442:0"
tracking_id: "crwdns20814:0crwdne20814:0"
open_api_clients:
add_new_client: "crwdns8443:0crwdne8443:0"
@ -1395,7 +1399,7 @@ zu:
client_name: "crwdns8459:0crwdne8459:0"
confirmation_required: "crwdns8461:0crwdne8461:0"
do_you_really_want_to_delete_this_open_api_client: "crwdns8463:0crwdne8463:0"
do_you_really_want_to_revoke_this_open_api_access: "crwdns8465:0crwdne8465:0"
do_you_really_want_to_revoke_this_open_api_access: "crwdns22428:0crwdne22428:0"
client_successfully_created: "crwdns8467:0crwdne8467:0"
client_successfully_updated: "crwdns8469:0crwdne8469:0"
client_successfully_deleted: "crwdns8471:0crwdne8471:0"

View File

@ -109,10 +109,10 @@ de:
your_previous_trainings: "Ihre vorigen Schulungen"
your_approved_trainings: "Ihre bestätigten Trainings"
no_trainings: "Keine Schulungen"
your_training_credits: "Your training credits"
subscribe_for_credits: "Subscribe to benefit from free trainings"
register_for_free: "Register for free to the following trainings:"
book_here: "Book here"
your_training_credits: "Dein Trainingsguthaben"
subscribe_for_credits: "Abonnement abschließen, um kostenlose Schulungen zu erhalten"
register_for_free: "Melden Sie sich kostenlos für folgende Schulungen an:"
book_here: "Hier buchen"
#dashboard: my events
events:
your_next_events: "Ihre nächsten Termine"
@ -132,7 +132,7 @@ de:
payment_schedules:
no_payment_schedules: "Keine Zahlungspläne zum Anzeigen"
load_more: "Mehr laden"
card_updated_success: "Your card was successfully updated"
card_updated_success: "Ihre Karte wurde erfolgreich aktualisiert"
#public profil of a member
members_show:
members_list: "Mitgliederliste"
@ -173,30 +173,30 @@ de:
DATE_TIME: "{DATE} {TIME}"
#modal telling users that they need to pass a training before booking a machine
required_training_modal:
to_book_MACHINE_requires_TRAINING_html: "To book the \"{MACHINE}\" you must have completed the training <strong>{TRAINING}</strong>."
training_or_training_html: "</strong> or the training <strong>"
to_book_MACHINE_requires_TRAINING_html: "Um \"{MACHINE}\" zu buchen, müssen Sie <strong>{TRAINING}</strong> abgeschlossen haben."
training_or_training_html: "</strong> oder die Schulung <strong>"
enroll_now: "Zur Schulung anmelden"
no_enroll_for_now: "Ich möchte mich jetzt nicht anmelden"
close: "Schließen"
propose_packs_modal:
available_packs: "Prepaid packs available"
packs_proposed: "You can buy a prepaid pack of hours for this machine. These packs allows you to benefit from volume discounts."
available_packs: "Prepaid-Pakete verfügbar"
packs_proposed: "Sie können ein Paket vorausbezahlter Stunden für diese Maschine kaufen. Über diese Pakete können Sie einen Mengenrabatt erhalten."
no_thanks: "Nein, danke"
pack_DURATION: "{DURATION} hours"
buy_this_pack: "Buy this pack"
pack_bought_success: "You have successfully bought this pack of prepaid-hours. Your invoice will ba available soon from your dashboard."
validity: "Usable for {COUNT} {PERIODS}"
pack_DURATION: "{DURATION} Stunden"
buy_this_pack: "Dieses Paket kaufen"
pack_bought_success: "Sie haben erfolgreich dieses Paket vorbezahlter Stunden gekauft. Ihre Rechnung wird bald in Ihrem Dashboard verfügbar sein."
validity: "Verwendbar für {COUNT} {PERIODS}"
period:
day: "{COUNT, plural, one{day} other{days}}"
week: "{COUNT, plural, one{week} other{weeks}}"
month: "{COUNT, plural, one{month} other{months}}"
year: "{COUNT, plural, one{year} other{years}}"
day: "{COUNT, plural, one {Tag} other {Tage}}"
week: "{COUNT, plural, one{Woche} other{Wochen}}"
month: "{COUNT, plural, one{Monat} other{Monate}}"
year: "{COUNT, plural, one {Jahr} other {Jahre}}"
packs_summary:
prepaid_hours: "Prepaid hours"
remaining_HOURS: "You have {HOURS} prepaid hours remaining for this {ITEM, select, Machine{machine} Space{space} other{}}."
no_hours: "You don't have any prepaid hours for this {ITEM, select, Machine{machine} Space{space} other{}}."
buy_a_new_pack: "Buy a new pack"
unable_to_use_pack_for_subsription_is_expired: "You must have a valid subscription to use your remaining hours."
prepaid_hours: "Vorausbezahlte Stunden"
remaining_HOURS: "Sie haben {HOURS} vorausbezahlte Stunden für {ITEM, select, Machine{diese Maschine} Space{diesen Raum} other{}} übrig."
no_hours: "Sie haben keine vorausbezahlte Nutzungsdauer für {ITEM, select, Machine{diese Maschine} Space{diesen Raum} other{}}."
buy_a_new_pack: "Ein neues Paket kaufen"
unable_to_use_pack_for_subsription_is_expired: "Sie benötigen für die verbleibenden Stunden ein gültiges Abonnement."
#book a training
trainings_reserve:
trainings_planning: "Schulungsplanung"

View File

@ -7,7 +7,7 @@ es:
you_ve_just_created_a_new_account_on_the_fablab_by_logging_from: "Acaba de crear una nueva cuenta en {GENDER, select, male{el} female{la} neutral{} other{las}} {NAME}, al iniciar sesión desde"
we_need_some_more_details: "Para finalizar la configuración de la plataforma, necesitamos algunos detalles más."
your_email_is_already_used_by_another_account_on_the_platform: "Parece que su dirección de correo electrónico ya está siendo utilizada por otro usuario. Compruebe su dirección de correo electrónico e ingrese debajo del código que le hemos enviado."
or: "or"
or: "o"
please_fill_the_following_form: "rellene el siguiente formulario, por favor"
some_data_may_have_already_been_provided_by_provider_and_cannot_be_modified: "Algunos datos pueden haber sido proporcionados ya por {NAME} y no pueden modificarse"
then_click_on_: "haz click en"
@ -25,20 +25,20 @@ es:
an_unexpected_error_occurred_check_your_authentication_code: "Ha ocurrido un error inesperado, por favor, revise su código de autentificación."
send_code_again: "Enviar el código de nuevo"
email_address_associated_with_your_account: "Email asociado con su cuenta"
email_is_required: "Email address is required"
email_is_required: "Se requiere una dirección de email"
email_format_is_incorrect: "El formato de email incorrecto"
code_successfully_sent_again: "El mail ha sido enviado otra vez con éxito"
used_for_statistics: "This data will be used for statistical purposes"
your_user_s_profile: "Your user's profile"
user_s_profile_is_required: "User's profile is required."
i_ve_read_and_i_accept_: "I've read and I accept"
_the_fablab_policy: "the FabLab policy"
change_my_data: "Change my data"
sync_my_profile: "Sync my profile"
once_your_data_are_up_to_date_: "Once your data are up to date,"
_click_on_the_synchronization_button_opposite_: "click on the synchronization button opposite"
_disconnect_then_reconnect_: "disconnect then reconnect"
_for_your_changes_to_take_effect: "for your changes to take effect."
used_for_statistics: "Estos datos se utilizarán para fines estadísticos"
your_user_s_profile: "Perfil de tu usuario"
user_s_profile_is_required: "Se requiere perfil de usuario."
i_ve_read_and_i_accept_: "He leído y acepto"
_the_fablab_policy: "la política de FabLab"
change_my_data: "Cambiar mis datos"
sync_my_profile: "Sincronizar mi perfil"
once_your_data_are_up_to_date_: "Una vez sus datos hayan sido actualizados,"
_click_on_the_synchronization_button_opposite_: "haga clic en el botón de sincronización"
_disconnect_then_reconnect_: "desconectar y volver a conectar"
_for_your_changes_to_take_effect: "para que los cambios surtan efecto."
dashboard:
#dashboard: public profile
profile:
@ -65,20 +65,20 @@ es:
edit_my_profile: "Editar mi perfil"
your_group_has_been_successfully_changed: "Su grupo ha sido cambiado con exito."
an_unexpected_error_prevented_your_group_from_being_changed: "Un error inesperado impidió que su grupo fuese cambiado."
confirmation_required: "Confirmation required"
confirmation_required: "Confirmación requerida"
confirm_delete_your_account: "¿Está seguro de querer eliminar su cuenta?"
all_data_will_be_lost: "All your data will be destroyed and won't be recoverable."
invoicing_data_kept: "According to regulation, all data related to your invoices will be kept separately for 10 years."
statistic_data_anonymized: "Some data (sex, date of birth, group) will be anonymized and kept for statistical purposes."
no_further_access_to_projects: "Your published projects will be anonymized and you won't get any further ability to edit them."
all_data_will_be_lost: "Todos tus datos serán destruidos y no serán recuperables."
invoicing_data_kept: "Según la regulación, todos los datos relacionados con sus facturas se mantendrán por separado durante 10 años."
statistic_data_anonymized: "Algunos datos (sexo, fecha de nacimiento, grupo) serán anonimizados y conservados con fines estadísticos."
no_further_access_to_projects: "Tus proyectos publicados serán anónimos y no tendrás más capacidad para editarlos."
your_user_account_has_been_successfully_deleted_goodbye: "Su cuenta ha sido eliminada con éxito. Adiós"
an_error_occured_preventing_your_account_from_being_deleted: "Un error inesperado impidió que su cuenta fuese eliminada."
used_for_statistics: "This data will be used for statistical purposes"
used_for_invoicing: "This data will be used for billing purposes"
used_for_reservation: "This data will be used in case of change on one of your bookings"
used_for_profile: "This data will only be displayed on your profile"
used_for_pricing_stats: "This data will be used to determine the prices to which you are entitled, and for statistical purposes"
public_profile: "You will have a public profile and other users will be able to associate you in their projects"
used_for_statistics: "Estos datos se utilizarán para fines estadísticos"
used_for_invoicing: "Estos datos se utilizarán para fines de facturación"
used_for_reservation: "Estos datos se utilizarán en caso de cambio en una de sus reservas"
used_for_profile: "Estos datos sólo se mostrarán en tu perfil"
used_for_pricing_stats: "Estos datos se utilizarán para determinar los precios a los que tiene derecho, y con fines estadísticos"
public_profile: "Tendrás un perfil público y otros usuarios podrán asociarte en sus proyectos"
trainings: "Cursos"
no_trainings: "Sin cursos"
subscription: "Suscripción"
@ -94,32 +94,32 @@ es:
#dashboard: my projects
projects:
you_dont_have_any_projects: "Aún no tiene proyectos."
add_a_project: "Add a project"
add_a_project: "Añadir un proyecto"
author: "Autor"
collaborator: "Colaborador"
rough_draft: "Draft"
description: "Description"
machines_and_materials: "Machines and materials"
machines: "Machines"
materials: "Materials"
collaborators: "Collaborators"
rough_draft: "Borrador"
description: "Descripción"
machines_and_materials: "Máquinas y materiales"
machines: "Máquinas"
materials: "Materiales"
collaborators: "Colaboradores"
#dashboard: my trainings
trainings:
your_next_trainings: "Sus próximos cursos"
your_previous_trainings: "Sus cursos anteriores"
your_approved_trainings: "Sus cursos aprobados"
no_trainings: "No trainings"
your_training_credits: "Your training credits"
subscribe_for_credits: "Subscribe to benefit from free trainings"
register_for_free: "Register for free to the following trainings:"
book_here: "Book here"
no_trainings: "Sin cursos"
your_training_credits: "Tus créditos de entrenamiento"
subscribe_for_credits: "Suscríbete para beneficiarte de entrenamientos gratuitos"
register_for_free: "Regístrate gratis en los siguientes entrenamientos:"
book_here: "Reservar aquí"
#dashboard: my events
events:
your_next_events: "Sus próximos eventos"
no_events_to_come: "No hay próximos eventos"
your_previous_events: "Sus eventos anteriores"
no_passed_events: "No passed events"
NUMBER_normal_places_reserved: "{NUMBER} {NUMBER, plural, =0{} =1{normal place reserved} other{normal places reserved}}"
no_passed_events: "Sin eventos anteriores"
NUMBER_normal_places_reserved: "¡{NUMBER} {NUMBER, plural, one {} =0{} =1{lugar normal reservado} other{lugares normales reservados}}"
NUMBER_of_NAME_places_reserved: "{NUMBER} {NUMBER, plural, =0{} =1{of {NAME} place reserved} other{of {NAME} places reserved}}"
#dashboard: my invoices
invoices:
@ -215,7 +215,7 @@ es:
notifications:
notifications_center: "Centro de notificaciones"
mark_all_as_read: "Marcar como leido"
date: "Date"
date: "Fecha"
notif_title: "Titulo"
no_new_notifications: "No hay notificaciones nuevas."
archives: "Archivos"

View File

@ -19,7 +19,7 @@ de:
my_trainings: "Meine Trainings"
my_events: "Meine Veranstaltungen"
my_invoices: "Meine Rechnungen"
my_payment_schedules: "My payment schedules"
my_payment_schedules: "Meine Zahlungspläne"
my_wallet: "Mein Guthaben"
#contextual help
help: "Hilfe"
@ -84,8 +84,8 @@ de:
birth_date_is_required: "Geburtsdatum ist erforderlich."
phone_number: "Telefonnummer"
phone_number_is_required: "Die Angabe der Telefonnummer ist erforderlich."
address: "Address"
address_is_required: "Address is required"
address: "Adresse"
address_is_required: "Adresse ist erforderlich"
i_authorize_Fablab_users_registered_on_the_site_to_contact_me: "Angemeldete Benutzer dürfen mich kontaktieren"
i_accept_to_receive_information_from_the_fablab: "Das Fablab darf mir Informationen schicken"
i_ve_read_and_i_accept_: "Ich habe gelesen und akzeptiere"
@ -165,6 +165,7 @@ de:
openlab_search_not_available_at_the_moment: "Suche über das gesamte Netzwerk ist derzeit nicht verfügbar. Sie können nach Projekten auf dieser Plattform suchen."
project_search_result_is_empty: "Leider haben wir keine Ergebnisse gefunden, die Ihren Suchkriterien entsprechen."
reset_all_filters: "Alle Filter zurücksetzen"
keywords: "Schlüsselwörter"
search: "Suche"
all_projects: "Alle Projekte"
my_projects: "Meine Projekte"
@ -211,7 +212,7 @@ de:
book: "Buchen"
_or_the_: " oder die "
machines_filters:
show_machines: "Show machines"
show_machines: "Maschinen anzeigen"
status_enabled: "Aktiviert"
status_disabled: "Deaktiviert"
status_all: "Alle"
@ -251,9 +252,9 @@ de:
no_plans: "Für Ihre Gruppe sind keine Pläne verfügbar"
AMOUNT_per_month: "{AMOUNT} / monate"
my_group: "Meine Gruppe"
his_group: "{GENDER, select, male{Seine} female{Ihre} other{Seine}} Gruppe"
he_wants_to_change_group: "{ROLE, select, member{Ich möchte} other{Der Benutzer möchte}} die Gruppe wechseln"
change_my_group: "Ändere {ROLE, select, member{meine} other{{GENDER, select, male{seine} female{ihre} other{seine}}}} Gruppe"
his_group: "User's group"
he_wants_to_change_group: "Change group"
change_my_group: "Validate group change"
summary: "Zusammenfassung"
your_subscription_has_expired_on_the_DATE: "Ihr Abonnement ist am {DATE} abgelaufen"
subscription_price: "Abonnementspreis"
@ -266,10 +267,10 @@ de:
an_error_prevented_to_change_the_user_s_group: "Fehler beim Ändern der Benutzergruppe."
plans_filter:
i_am: "Ich bin"
select_group: "select a group"
i_want_duration: "I want to subscribe for"
all_durations: "All durations"
select_duration: "select a duration"
select_group: "Wählen Sie eine Gruppe aus"
i_want_duration: "Ich möchte mich anmelden für"
all_durations: "Alle Laufzeiten"
select_duration: "Wählen Sie eine Laufzeit"
#Fablab's events list
events_list:
the_fablab_s_events: "Veranstaltungen des Fablabs"

Some files were not shown because too many files have changed in this diff Show More