diff --git a/.dockerignore b/.dockerignore index 0245e9501..9abd6e233 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ # Ignore bundler config. config/database.yml +config/auth_provider.yml # Ignore database files. postgresql diff --git a/.gitignore b/.gitignore index 27cdf7522..d5b342488 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ # Ignore application configurations /config/application.yml /config/database.yml +/config/auth_provider.yml .env *.DS_Store diff --git a/.nvmrc b/.nvmrc index 23d9c36a1..55bffd620 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16.13.2 +18.15.0 diff --git a/.rubocop.yml b/.rubocop.yml index 2c140dc27..961c45262 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,6 +6,8 @@ Layout/LineLength: Max: 145 Metrics/MethodLength: Max: 35 + Exclude: + - 'app/pdfs/pdf/*.rb' Metrics/CyclomaticComplexity: Max: 14 Metrics/PerceivedComplexity: @@ -19,6 +21,7 @@ Metrics/BlockLength: Exclude: - 'lib/tasks/**/*.rake' - 'config/routes.rb' + - 'config/environments/*.rb' - 'app/pdfs/pdf/*.rb' - 'test/**/*.rb' - '**/*_concern.rb' @@ -38,6 +41,8 @@ Rails/RedundantPresenceValidationOnBelongsTo: Enabled: false Style/DateTime: Enabled: true +Style/HashSyntax: + EnforcedShorthandSyntax: never Rails/TimeZone: Enabled: true Rails/UnknownEnv: diff --git a/.ruby-version b/.ruby-version index 7213b446a..72b3400f1 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-2.6.10 +ruby-3.2.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index f7e066533..0f928f5dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # Changelog Fab-manager +## v6.0.0 2023 April 03 + +- Updated ruby to 3.2 +- Updated rails to 7.0 +- Updated puma to 6.1 +- Updated responders to 3.0 +- Updated devise to 4.9 +- Updated sassc to 2.4 +- Updated sentry to 5.8 +- Updated web-console to 4.2 +- Updated shakapacker to 6.6 +- Updated bootsnap to 1.16 +- Updated pg to 1.4 +- Updated nodejs to 18.15 +- Updated oj to 3.14 +- Updated multi_json to 1.15 +- Updated spring to 4.0 +- Updated spring-watcher-listen to 2.1 +- Updated omniauth to 2.1 +- Updated omniauth-rails_csrf_protection to 1.0 +- Updated omniauth_openid_connect to 0.6 +- Updated the invoices chaining method with a more flexible model +- Fill the holes in the logical sequence of invoices references with nil invoices +- Use a cached configuration file to read the authentication provider settings +- Order numbers are now saved in database instead of generated on-the-fly +- OpenAPI availabilities endpoint +- Ability to filter OpenAPI reservations endpoint by availability_id +- Support for ARM64 CPU architecture +- Fix a bug: by default, invoices should be ordered by date descending +- Fix a bug: broken display after a plan category was deleted +- Fix a bug: unable to update recurring event +- Fix a security issue: updated json5 to 2.2.2 to fix [CVE-2022-46175](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-46175) +- Fix a security issue: updated terser to 5.16.8 to fix [CVE-2022-25858](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-25858) +- [TODO DEPLOY] `\curl -sSL https://raw.githubusercontent.com/sleede/fab-manager/master/scripts/mount-auth-provider.sh | bash` +- [TODO DEPLOY] `rails fablab:auth:write_provider` +- [TODO DEPLOY] `rails fablab:restore_order_number` THEN `rails fablab:fix_references` + ## v5.9.1 2023 March 22 - Fix a bug: logical sequence of invoices references has duplicates diff --git a/Dockerfile b/Dockerfile index 31a6369a4..51b22e744 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.6.10-alpine +FROM ruby:3.2.1-alpine MAINTAINER contact@fab-manager.com # Install upgrade system packages diff --git a/Gemfile b/Gemfile index 83325dfe2..822c4dd0b 100644 --- a/Gemfile +++ b/Gemfile @@ -3,12 +3,18 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 5.2.8' +gem 'rails', '~> 7.0' # 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.12' -gem 'shakapacker', '6.5.5' +gem 'puma', '6.1.0' +gem 'shakapacker', '6.6.0' + +# rails 6 compatibility with ruby 3 (may not be required after upgrade to rails 7) +gem 'matrix' +gem 'net-imap', require: false +gem 'net-pop', require: false +gem 'net-smtp', require: false # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder gem 'jbuilder', '~> 2.5' @@ -17,7 +23,7 @@ gem 'json', '>= 2.3.0' gem 'jsonpath' gem 'forgery' -gem 'responders', '~> 2.0' +gem 'responders', '~> 3.0' group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console @@ -33,26 +39,26 @@ group :development do gem 'bullet' gem 'coveralls_reborn', '~> 0.18.0', require: false gem 'foreman' - gem 'web-console', '>= 3.3.0' + gem 'web-console', '>= 4.2.0' # Preview mail in the browser gem 'listen', '~> 3.0.5' gem 'overcommit' + gem 'pry' gem 'rb-readline' # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring gem 'railroady' gem 'rubocop', '~> 1.31', require: false gem 'rubocop-rails', require: false - gem 'spring' - gem 'spring-watcher-listen', '~> 2.0.0' + gem 'spring', '~> 4' + gem 'spring-watcher-listen', '~> 2.1.0' end group :test do gem 'database_cleaner' gem 'faker' gem 'minitest-reporters' - gem 'pdf-reader' gem 'rubyXL' - gem 'vcr', '6.0.0' + gem 'vcr', '~> 6.1.0' gem 'webmock' end @@ -62,11 +68,11 @@ gem 'pg' gem 'pg_search' # authentication -gem 'devise', '>= 4.6.0' -gem 'omniauth', '~> 1.9.2' +gem 'devise', '>= 4.9' +gem 'omniauth', '~> 2.1' gem 'omniauth-oauth2' gem 'omniauth_openid_connect' -gem 'omniauth-rails_csrf_protection', '~> 0.1' +gem 'omniauth-rails_csrf_protection', '~> 1.0' gem 'rolify' @@ -95,6 +101,7 @@ gem 'stripe', '5.29.0' gem 'recurrence' # PDF +gem 'pdf-reader' gem 'prawn' gem 'prawn-table' @@ -107,9 +114,6 @@ gem 'pundit' gem 'oj' -gem 'actionpack-page_caching', '1.2.2' -gem 'rails-observers' - gem 'chroma' gem 'message_format' @@ -136,7 +140,7 @@ gem 'icalendar' gem 'tzinfo-data' # compilation of dynamic stylesheets (home page & theme) -gem 'sassc', '= 2.1.0' +gem 'sassc', '= 2.4.0' gem 'redis-session-store' diff --git a/Gemfile.lock b/Gemfile.lock index 43a951841..4adb800d5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,64 +1,85 @@ GEM remote: https://rubygems.org/ specs: - Ascii85 (1.0.3) + Ascii85 (1.1.0) aasm (5.0.8) concurrent-ruby (~> 1.0) - actioncable (5.2.8.1) - actionpack (= 5.2.8.1) + actioncable (7.0.4.3) + actionpack (= 7.0.4.3) + activesupport (= 7.0.4.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) + actionmailbox (7.0.4.3) + actionpack (= 7.0.4.3) + activejob (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.4.3) + actionpack (= 7.0.4.3) + actionview (= 7.0.4.3) + activejob (= 7.0.4.3) + activesupport (= 7.0.4.3) mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp rails-dom-testing (~> 2.0) - actionpack (5.2.8.1) - actionview (= 5.2.8.1) - activesupport (= 5.2.8.1) - rack (~> 2.0, >= 2.0.8) + actionpack (7.0.4.3) + actionview (= 7.0.4.3) + activesupport (= 7.0.4.3) + rack (~> 2.0, >= 2.2.0) 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.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.4.3) + actionpack (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.4.3) + activesupport (= 7.0.4.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.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + active_record_query_trace (1.8) + activejob (7.0.4.3) + activesupport (= 7.0.4.3) globalid (>= 0.3.6) - activemodel (5.2.8.1) - activesupport (= 5.2.8.1) - activerecord (5.2.8.1) - activemodel (= 5.2.8.1) - activesupport (= 5.2.8.1) - arel (>= 9.0) - activestorage (5.2.8.1) - actionpack (= 5.2.8.1) - activerecord (= 5.2.8.1) - marcel (~> 1.0.0) - activesupport (5.2.8.1) + activemodel (7.0.4.3) + activesupport (= 7.0.4.3) + activerecord (7.0.4.3) + activemodel (= 7.0.4.3) + activesupport (= 7.0.4.3) + activestorage (7.0.4.3) + actionpack (= 7.0.4.3) + activejob (= 7.0.4.3) + activerecord (= 7.0.4.3) + activesupport (= 7.0.4.3) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.4.3) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) acts_as_list (1.0.4) activerecord (>= 4.2) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) aes_key_wrap (1.1.0) afm (0.2.2) ansi (1.5.0) api-pagination (4.8.2) apipie-rails (0.5.17) rails (>= 4.1) - arel (9.0.0) ast (2.4.2) attr_required (1.0.1) awesome_print (1.8.0) @@ -66,11 +87,11 @@ GEM descendants_tracker (~> 0.0.4) ice_nine (~> 0.11.0) thread_safe (~> 0.3, >= 0.3.1) - bcrypt (3.1.13) - bindata (2.4.10) + bcrypt (3.1.18) + bindata (2.4.15) bindex (0.8.1) - bootsnap (1.4.6) - msgpack (~> 1.0) + bootsnap (1.16.0) + msgpack (~> 1.2) brpoplpush-redis_script (0.1.2) concurrent-ruby (~> 1.0, >= 1.0.5) redis (>= 1.0, <= 5.0) @@ -98,9 +119,10 @@ GEM childprocess (4.1.0) chroma (0.2.0) cldr-plurals-runtime-rb (1.0.1) + coderay (1.1.3) coercible (1.0.0) descendants_tracker (~> 0.0.1) - concurrent-ruby (1.1.10) + concurrent-ruby (1.2.2) connection_pool (2.2.5) coveralls_reborn (0.18.0) simplecov (>= 0.18.1, < 0.20.0) @@ -111,19 +133,20 @@ GEM safe_yaml (~> 1.0.0) crass (1.0.6) database_cleaner (1.8.3) + date (3.3.3) descendants_tracker (0.0.4) thread_safe (~> 0.3, >= 0.3.1) - devise (4.7.1) + devise (4.9.0) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) responders warden (~> 1.2.3) docile (1.3.2) - dotenv (2.7.5) - dotenv-rails (2.7.5) - dotenv (= 2.7.5) - railties (>= 3.2, < 6.1) + dotenv (2.8.1) + dotenv-rails (2.8.1) + dotenv (= 2.8.1) + railties (>= 3.2) elasticsearch (5.0.5) elasticsearch-api (= 5.0.5) elasticsearch-transport (= 5.0.5) @@ -145,7 +168,7 @@ GEM faraday multi_json equalizer (0.0.11) - erubi (1.10.0) + erubi (1.12.0) et-orbi (1.2.7) tzinfo faker (2.10.2) @@ -160,7 +183,7 @@ GEM fugit (1.5.3) et-orbi (~> 1, >= 1.2.7) raabro (~> 1.4) - globalid (1.0.1) + globalid (1.1.0) activesupport (>= 5.0) hashdiff (1.0.1) hashery (2.1.2) @@ -185,10 +208,11 @@ GEM jbuilder_cache_multi (0.1.0) jbuilder (>= 1.5.0, < 3) json (2.3.1) - json-jwt (1.13.0) + json-jwt (1.15.3) activesupport (>= 4.2) aes_key_wrap bindata + httpclient jsonpath (1.1.0) multi_json jwt (2.2.1) @@ -210,9 +234,13 @@ GEM loofah (2.19.1) crass (~> 1.0.2) nokogiri (>= 1.5.9) - mail (2.7.1) + mail (2.8.1) mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp marcel (1.0.2) + matrix (0.4.2) message_format (0.0.6) twitter_cldr (~> 5.0) method_source (1.0.0) @@ -221,20 +249,27 @@ GEM rake mini_magick (4.10.1) mini_mime (1.1.2) - mini_portile2 (2.8.0) - minitest (5.17.0) + minitest (5.18.0) minitest-reporters (1.4.2) ansi builder minitest (>= 5.0) ruby-progressbar - msgpack (1.3.3) - multi_json (1.14.1) + msgpack (1.6.1) + multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) + net-imap (0.3.4) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.1) + timeout + net-smtp (0.3.3) + net-protocol nio4r (2.5.8) - nokogiri (1.13.10) - mini_portile2 (~> 2.8.0) + nokogiri (1.14.2-x86_64-linux) racc (~> 1.4) oauth2 (1.4.4) faraday (>= 0.8, < 2.0) @@ -242,30 +277,31 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - oj (3.10.5) - omniauth (1.9.2) + oj (3.14.2) + omniauth (2.1.1) hashie (>= 3.4.6) - rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.6.0) - oauth2 (~> 1.1) - omniauth (~> 1.9) - omniauth-rails_csrf_protection (0.1.2) + rack (>= 2.2.3) + rack-protection + omniauth-oauth2 (1.8.0) + oauth2 (>= 1.4, < 3) + omniauth (~> 2.0) + omniauth-rails_csrf_protection (1.0.1) actionpack (>= 4.2) - omniauth (>= 1.3.1) - omniauth_openid_connect (0.4.0) - addressable (~> 2.5) + omniauth (~> 2.0) + omniauth_openid_connect (0.6.1) omniauth (>= 1.9, < 3) openid_connect (~> 1.1) - openid_connect (1.3.0) + openid_connect (1.4.2) activemodel attr_required (>= 1.0.0) - json-jwt (>= 1.5.0) - rack-oauth2 (>= 1.6.1) - swd (>= 1.0.0) + json-jwt (>= 1.15.0) + net-smtp + rack-oauth2 (~> 1.21) + swd (~> 1.3) tzinfo validate_email validate_url - webfinger (>= 1.0.1) + webfinger (~> 1.2) openlab_ruby (0.0.7) httparty (~> 0.20) orm_adapter (0.5.0) @@ -276,67 +312,72 @@ GEM parallel (1.19.1) parser (3.1.2.0) ast (~> 2.4.1) - pdf-core (0.7.0) - pdf-reader (2.4.0) - Ascii85 (~> 1.0.0) + pdf-core (0.9.0) + pdf-reader (2.11.0) + Ascii85 (~> 1.0) afm (~> 0.2.1) hashery (~> 2.0) ruby-rc4 ttfunk - pg (1.2.2) + pg (1.4.6) pg_search (2.3.2) activerecord (>= 5.2) activesupport (>= 5.2) - prawn (2.2.2) - pdf-core (~> 0.7.0) - ttfunk (~> 1.5) + prawn (2.4.0) + pdf-core (~> 0.9.0) + ttfunk (~> 1.7) prawn-table (0.2.2) prawn (>= 1.3.0, < 3.0.0) - public_suffix (4.0.6) - puma (4.3.12) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + public_suffix (5.0.1) + puma (6.1.0) nio4r (~> 2.0) pundit (2.1.0) activesupport (>= 3.0.0) raabro (1.4.0) - racc (1.6.1) + racc (1.6.2) rack (2.2.6.4) - rack-oauth2 (1.19.0) + rack-oauth2 (1.21.3) activesupport attr_required httpclient json-jwt (>= 1.11.0) rack (>= 2.1.0) + rack-protection (3.0.5) + rack rack-proxy (0.7.6) rack - rack-test (2.0.2) + rack-test (2.1.0) rack (>= 1.3) railroady (1.5.3) - rails (5.2.8.1) - actioncable (= 5.2.8.1) - actionmailer (= 5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) - activemodel (= 5.2.8.1) - activerecord (= 5.2.8.1) - activestorage (= 5.2.8.1) - activesupport (= 5.2.8.1) - bundler (>= 1.3.0) - railties (= 5.2.8.1) - sprockets-rails (>= 2.0.0) + rails (7.0.4.3) + actioncable (= 7.0.4.3) + actionmailbox (= 7.0.4.3) + actionmailer (= 7.0.4.3) + actionpack (= 7.0.4.3) + actiontext (= 7.0.4.3) + actionview (= 7.0.4.3) + activejob (= 7.0.4.3) + activemodel (= 7.0.4.3) + activerecord (= 7.0.4.3) + activestorage (= 7.0.4.3) + activesupport (= 7.0.4.3) + bundler (>= 1.15.0) + railties (= 7.0.4.3) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.4) + rails-html-sanitizer (1.5.0) loofah (~> 2.19, >= 2.19.1) - rails-observers (0.1.5) - activemodel (>= 4.0) - railties (5.2.8.1) - actionpack (= 5.2.8.1) - activesupport (= 5.2.8.1) + railties (7.0.4.3) + actionpack (= 7.0.4.3) + activesupport (= 7.0.4.3) method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) rainbow (3.0.0) rake (13.0.6) rb-fsevent (0.10.3) @@ -352,11 +393,11 @@ GEM redis (>= 3, < 5) regexp_parser (2.5.0) repost (0.3.2) - responders (2.4.1) - actionpack (>= 4.2.0, < 6.0) - railties (>= 4.2.0, < 6.0) + responders (3.1.0) + actionpack (>= 5.2) + railties (>= 5.2) rexml (3.2.5) - rolify (5.2.0) + rolify (5.3.0) rubocop (1.31.2) json (~> 2.3) parallel (~> 1.10) @@ -377,26 +418,26 @@ GEM ruby-rc4 (0.1.5) ruby-vips (2.1.4) ffi (~> 1.12) - rubyXL (3.4.14) + rubyXL (3.4.25) nokogiri (>= 1.10.8) rubyzip (>= 1.3.0) - rubyzip (2.3.0) + rubyzip (2.3.2) rufus-scheduler (3.8.1) fugit (~> 1.1, >= 1.1.6) safe_yaml (1.0.5) - sassc (2.1.0) + sassc (2.4.0) ffi (~> 1.9) seed_dump (3.3.1) activerecord (>= 4) activesupport (>= 4) semantic_range (3.0.0) - sentry-rails (5.7.0) + sentry-rails (5.8.0) railties (>= 5.0) - sentry-ruby (~> 5.7.0) - sentry-ruby (5.7.0) + sentry-ruby (~> 5.8.0) + sentry-ruby (5.8.0) concurrent-ruby (~> 1.0, >= 1.0.2) - sha3 (1.0.1) - shakapacker (6.5.5) + sha3 (1.0.5) + shakapacker (6.6.0) activesupport (>= 5.2) rack-proxy (>= 0.6.1) railties (>= 5.2) @@ -418,19 +459,11 @@ GEM simplecov (0.19.0) docile (~> 1.1) simplecov-html (~> 0.11) - simplecov-html (0.12.2) - spring (2.0.2) - activesupport (>= 4.2) - spring-watcher-listen (2.0.1) + simplecov-html (0.12.3) + spring (4.1.1) + spring-watcher-listen (2.1.0) listen (>= 2.7, < 4.0) - spring (>= 1.2, < 3.0) - sprockets (4.1.1) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) - sprockets (>= 3.0.0) + spring (>= 4) ssrf_filter (1.0.7) stripe (5.29.0) swd (1.3.0) @@ -438,22 +471,23 @@ GEM attr_required (>= 0.0.5) httpclient (>= 2.4) sync (0.5.0) - sys-filesystem (1.3.3) - ffi + sys-filesystem (1.4.3) + ffi (~> 1.1) term-ansicolor (1.7.1) tins (~> 1.0) thor (1.2.1) thread_safe (0.3.6) tilt (2.0.10) + timeout (0.3.2) tins (1.25.0) sync - ttfunk (1.5.1) + ttfunk (1.7.0) twitter_cldr (5.4.0) camertron-eprun cldr-plurals-runtime-rb (~> 1.0) tzinfo - tzinfo (1.2.10) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) tzinfo-data (1.2020.4) tzinfo (>= 1.0.0) unicode-display_width (1.4.1) @@ -461,22 +495,22 @@ GEM validate_email (0.1.6) activemodel (>= 3.0) mail (>= 2.2.5) - validate_url (1.0.13) + validate_url (1.0.15) activemodel (>= 3.0.0) public_suffix - vcr (6.0.0) + vcr (6.1.0) virtus (1.0.5) axiom-types (~> 0.1) coercible (~> 1.0) descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) - warden (1.2.8) - rack (>= 2.0.6) - web-console (3.7.0) - actionview (>= 5.0) - activemodel (>= 5.0) + warden (1.2.9) + rack (>= 2.0.9) + web-console (4.2.0) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) bindex (>= 0.4.0) - railties (>= 5.0) + railties (>= 6.0.0) webfinger (1.2.0) activesupport httpclient (>= 2.4) @@ -487,13 +521,13 @@ GEM websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) + zeitwerk (2.6.7) PLATFORMS - ruby + x86_64-linux DEPENDENCIES aasm - actionpack-page_caching (= 1.2.2) active_record_query_trace acts_as_list api-pagination @@ -507,7 +541,7 @@ DEPENDENCIES chroma coveralls_reborn (~> 0.18.0) database_cleaner - devise (>= 4.6.0) + devise (>= 4.9) dotenv-rails elasticsearch-model (~> 5) elasticsearch-persistence (~> 5) @@ -524,13 +558,17 @@ DEPENDENCIES jsonpath kaminari listen (~> 3.0.5) + matrix message_format mini_magick minitest-reporters + net-imap + net-pop + net-smtp oj - omniauth (~> 1.9.2) + omniauth (~> 2.1) omniauth-oauth2 - omniauth-rails_csrf_protection (~> 0.1) + omniauth-rails_csrf_protection (~> 1.0) omniauth_openid_connect openlab_ruby overcommit @@ -539,37 +577,37 @@ DEPENDENCIES pg_search prawn prawn-table - puma (= 4.3.12) + pry + puma (= 6.1.0) pundit railroady - rails (~> 5.2.8) - rails-observers + rails (~> 7.0) rb-readline recurrence redis-session-store repost - responders (~> 2.0) + responders (~> 3.0) rolify rubocop (~> 1.31) rubocop-rails rubyXL rubyzip (>= 1.3.0) - sassc (= 2.1.0) + sassc (= 2.4.0) seed_dump sentry-rails sentry-ruby sha3 - shakapacker (= 6.5.5) + shakapacker (= 6.6.0) sidekiq (>= 6.0.7) sidekiq-scheduler sidekiq-unique-jobs (~> 7.1.23) - spring - spring-watcher-listen (~> 2.0.0) + spring (~> 4) + spring-watcher-listen (~> 2.1.0) stripe (= 5.29.0) sys-filesystem tzinfo-data - vcr (= 6.0.0) - web-console (>= 3.3.0) + vcr (~> 6.1.0) + web-console (>= 4.2.0) webmock BUNDLED WITH diff --git a/Procfile b/Procfile index 64f020c5e..c32576a57 100644 --- a/Procfile +++ b/Procfile @@ -1,3 +1,3 @@ -web: bundle exec rails server puma -p $PORT +web: bundle exec rails server -u puma -p $PORT worker: bundle exec sidekiq -C ./config/sidekiq.yml webpack: bin/webpacker-dev-server diff --git a/app/controllers/api/abuses_controller.rb b/app/controllers/api/abuses_controller.rb index 9c93a2d35..9a2f983ac 100644 --- a/app/controllers/api/abuses_controller.rb +++ b/app/controllers/api/abuses_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Abuse. # Typical action is an user reporting an abuse on a project -class API::AbusesController < API::ApiController +class API::AbusesController < API::APIController before_action :authenticate_user!, except: :create before_action :set_abuse, only: %i[destroy] diff --git a/app/controllers/api/accounting_exports_controller.rb b/app/controllers/api/accounting_exports_controller.rb index 20dd342dd..41ddbd046 100644 --- a/app/controllers/api/accounting_exports_controller.rb +++ b/app/controllers/api/accounting_exports_controller.rb @@ -1,8 +1,7 @@ # frozen_string_literal: true # API Controller for exporting accounting data to external accounting softwares -class API::AccountingExportsController < API::ApiController - +class API::AccountingExportsController < API::APIController before_action :authenticate_user! def export @@ -27,7 +26,7 @@ class API::AccountingExportsController < API::ApiController render json: @export.errors, status: :unprocessable_entity end else - send_file File.join(Rails.root, export.file), + send_file Rails.root.join(export.file), type: 'text/csv', disposition: 'attachment' end diff --git a/app/controllers/api/accounting_periods_controller.rb b/app/controllers/api/accounting_periods_controller.rb index b9561dc94..8b31a50d7 100644 --- a/app/controllers/api/accounting_periods_controller.rb +++ b/app/controllers/api/accounting_periods_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of AccountingPeriod -class API::AccountingPeriodsController < API::ApiController +class API::AccountingPeriodsController < API::APIController before_action :authenticate_user! before_action :set_period, only: %i[show download_archive] diff --git a/app/controllers/api/admins_controller.rb b/app/controllers/api/admins_controller.rb index 31a5a285f..d5d82d679 100644 --- a/app/controllers/api/admins_controller.rb +++ b/app/controllers/api/admins_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type User with role 'admin'. -class API::AdminsController < API::ApiController +class API::AdminsController < API::APIController before_action :authenticate_user! def index diff --git a/app/controllers/api/age_ranges_controller.rb b/app/controllers/api/age_ranges_controller.rb index 169f4775b..8e938bc5a 100644 --- a/app/controllers/api/age_ranges_controller.rb +++ b/app/controllers/api/age_ranges_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type AgeRange # AgeRange are used in Events -class API::AgeRangesController < API::ApiController +class API::AgeRangesController < API::APIController before_action :authenticate_user!, except: [:index] before_action :set_age_range, only: %i[show update destroy] diff --git a/app/controllers/api/analytics_controller.rb b/app/controllers/api/analytics_controller.rb index 12128202f..e4a2171df 100644 --- a/app/controllers/api/analytics_controller.rb +++ b/app/controllers/api/analytics_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for fabAnalytics -class API::AnalyticsController < API::ApiController +class API::AnalyticsController < API::APIController before_action :authenticate_user! def data diff --git a/app/controllers/api/api_controller.rb b/app/controllers/api/api_controller.rb index 2315de63a..47bb5ed66 100644 --- a/app/controllers/api/api_controller.rb +++ b/app/controllers/api/api_controller.rb @@ -1,6 +1,4 @@ # frozen_string_literal: true -class API::ApiController < ApplicationController - - +class API::APIController < ApplicationController end diff --git a/app/controllers/api/auth_providers_controller.rb b/app/controllers/api/auth_providers_controller.rb index 71ea9d81b..97a5c0ceb 100644 --- a/app/controllers/api/auth_providers_controller.rb +++ b/app/controllers/api/auth_providers_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type AuthProvider # AuthProvider are used to connect users through single-sign on systems -class API::AuthProvidersController < API::ApiController +class API::AuthProvidersController < API::APIController before_action :set_provider, only: %i[show update destroy] def index @providers = policy_scope(AuthProvider) diff --git a/app/controllers/api/availabilities_controller.rb b/app/controllers/api/availabilities_controller.rb index 053142214..a1f3601a5 100644 --- a/app/controllers/api/availabilities_controller.rb +++ b/app/controllers/api/availabilities_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Availability -class API::AvailabilitiesController < API::ApiController +class API::AvailabilitiesController < API::APIController before_action :authenticate_user!, except: [:public] before_action :set_availability, only: %i[show update reservations lock] before_action :set_operator_role, only: %i[machine spaces trainings] diff --git a/app/controllers/api/cart_controller.rb b/app/controllers/api/cart_controller.rb index 1e461f8e9..22878c815 100644 --- a/app/controllers/api/cart_controller.rb +++ b/app/controllers/api/cart_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller to manage user's cart -class API::CartController < API::ApiController +class API::CartController < API::APIController include API::OrderConcern before_action :current_order, except: %i[create] @@ -17,7 +17,7 @@ class API::CartController < API::ApiController authorize @current_order, policy_class: CartPolicy service = Cart::CreateCartItemService.new(@current_order) @item = service.create(params) - if @item.save({ context: @current_order.order_items }) + if @item.save(**{ context: @current_order.order_items }) render 'api/orders/item', status: :created else render json: @item.errors.full_messages, status: :unprocessable_entity diff --git a/app/controllers/api/categories_controller.rb b/app/controllers/api/categories_controller.rb index fcc87117a..6ff53f176 100644 --- a/app/controllers/api/categories_controller.rb +++ b/app/controllers/api/categories_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Category # Categories are used to classify Events -class API::CategoriesController < API::ApiController +class API::CategoriesController < API::APIController before_action :authenticate_user!, except: [:index] before_action :set_category, only: %i[show update destroy] @@ -22,7 +22,6 @@ class API::CategoriesController < API::ApiController end end - def update authorize Category if @category.update(category_params) diff --git a/app/controllers/api/checkout_controller.rb b/app/controllers/api/checkout_controller.rb index 1cd0142d8..54f9c876a 100644 --- a/app/controllers/api/checkout_controller.rb +++ b/app/controllers/api/checkout_controller.rb @@ -4,7 +4,7 @@ require 'stripe/helper' require 'pay_zen/helper' # API Controller for cart checkout -class API::CheckoutController < API::ApiController +class API::CheckoutController < API::APIController include ::API::OrderConcern before_action :authenticate_user! before_action :current_order diff --git a/app/controllers/api/components_controller.rb b/app/controllers/api/components_controller.rb index 39a8f2b07..07274ee92 100644 --- a/app/controllers/api/components_controller.rb +++ b/app/controllers/api/components_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Component # Components are used in Projects -class API::ComponentsController < API::ApiController +class API::ComponentsController < API::APIController before_action :authenticate_user!, except: %i[index show] before_action :set_component, only: %i[show update destroy] diff --git a/app/controllers/api/coupons_controller.rb b/app/controllers/api/coupons_controller.rb index 616248c96..e7a0faa59 100644 --- a/app/controllers/api/coupons_controller.rb +++ b/app/controllers/api/coupons_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Coupon # Coupons are used in payments -class API::CouponsController < API::ApiController +class API::CouponsController < API::APIController include ApplicationHelper before_action :authenticate_user!, except: %i[validate] diff --git a/app/controllers/api/credits_controller.rb b/app/controllers/api/credits_controller.rb index e435f4881..73f547fcf 100644 --- a/app/controllers/api/credits_controller.rb +++ b/app/controllers/api/credits_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Credit # Credits are used to give free reservations to users -class API::CreditsController < API::ApiController +class API::CreditsController < API::APIController before_action :authenticate_user! before_action :set_credit, only: %i[show update destroy] @@ -15,6 +15,8 @@ class API::CreditsController < API::ApiController end end + def show; end + def create authorize Credit @credit = Credit.new(credit_params) diff --git a/app/controllers/api/custom_assets_controller.rb b/app/controllers/api/custom_assets_controller.rb index 44fd7c87c..6024fa25f 100644 --- a/app/controllers/api/custom_assets_controller.rb +++ b/app/controllers/api/custom_assets_controller.rb @@ -2,9 +2,9 @@ # API Controller for resources of type CustomAsset # CustomAssets are used in settings -class API::CustomAssetsController < API::ApiController - before_action :authenticate_user!, only: %i[index update create destroy] - before_action :set_custom_asset, only: %i[show update destroy] +class API::CustomAssetsController < API::APIController + before_action :authenticate_user!, only: %i[update create] + before_action :set_custom_asset, only: %i[show update] # PUT /api/custom_assets/1/ def update @@ -40,5 +40,4 @@ class API::CustomAssetsController < API::ApiController def custom_asset_params params.required(:custom_asset).permit(:name, custom_asset_file_attributes: [:attachment]) end - end diff --git a/app/controllers/api/event_themes_controller.rb b/app/controllers/api/event_themes_controller.rb index 91411508c..8db5d5299 100644 --- a/app/controllers/api/event_themes_controller.rb +++ b/app/controllers/api/event_themes_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type EventTheme # EventTheme are used to classify Events -class API::EventThemesController < API::ApiController +class API::EventThemesController < API::APIController before_action :authenticate_user!, except: [:index] before_action :set_event_theme, only: %i[show update destroy] @@ -22,7 +22,6 @@ class API::EventThemesController < API::ApiController end end - def update authorize EventTheme if @event_theme.update(event_theme_params) diff --git a/app/controllers/api/events_controller.rb b/app/controllers/api/events_controller.rb index d73fc5546..ce4b42bd9 100644 --- a/app/controllers/api/events_controller.rb +++ b/app/controllers/api/events_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Event -class API::EventsController < API::ApiController +class API::EventsController < API::APIController before_action :set_event, only: %i[show update destroy] def index diff --git a/app/controllers/api/exports_controller.rb b/app/controllers/api/exports_controller.rb index 55e0062a2..f75c8467f 100644 --- a/app/controllers/api/exports_controller.rb +++ b/app/controllers/api/exports_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Export # Export are used to download data tables in offline files -class API::ExportsController < API::ApiController +class API::ExportsController < API::APIController before_action :authenticate_user! before_action :set_export, only: [:download] diff --git a/app/controllers/api/files_controller.rb b/app/controllers/api/files_controller.rb index 70c274146..4f9367b34 100644 --- a/app/controllers/api/files_controller.rb +++ b/app/controllers/api/files_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for handling special actions on files -class API::FilesController < API::ApiController +class API::FilesController < API::APIController before_action :authenticate_user! # test the mime type of the uploaded file diff --git a/app/controllers/api/groups_controller.rb b/app/controllers/api/groups_controller.rb index 7276f54e7..07af9e5fc 100644 --- a/app/controllers/api/groups_controller.rb +++ b/app/controllers/api/groups_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Group # Groups are used for categorizing Users -class API::GroupsController < API::ApiController +class API::GroupsController < API::APIController before_action :authenticate_user!, except: :index def index diff --git a/app/controllers/api/i_calendar_controller.rb b/app/controllers/api/i_calendar_controller.rb index 76cd5beb1..f27389e75 100644 --- a/app/controllers/api/i_calendar_controller.rb +++ b/app/controllers/api/i_calendar_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type iCalendar -class API::ICalendarController < API::ApiController +class API::ICalendarController < API::APIController before_action :authenticate_user!, except: %i[index events] before_action :set_i_cal, only: [:destroy] respond_to :json diff --git a/app/controllers/api/imports_controller.rb b/app/controllers/api/imports_controller.rb index 40f131194..84e81eec3 100644 --- a/app/controllers/api/imports_controller.rb +++ b/app/controllers/api/imports_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Import -class API::ImportsController < API::ApiController +class API::ImportsController < API::APIController before_action :authenticate_user! def show diff --git a/app/controllers/api/invoices_controller.rb b/app/controllers/api/invoices_controller.rb index c03ac91e9..f1097dd96 100644 --- a/app/controllers/api/invoices_controller.rb +++ b/app/controllers/api/invoices_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of Invoice and Avoir -class API::InvoicesController < API::ApiController +class API::InvoicesController < API::APIController before_action :authenticate_user! before_action :set_invoice, only: %i[show download] diff --git a/app/controllers/api/licences_controller.rb b/app/controllers/api/licences_controller.rb index f32de94a6..632ccd869 100644 --- a/app/controllers/api/licences_controller.rb +++ b/app/controllers/api/licences_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Licence # Licenses are used in Projects -class API::LicencesController < API::ApiController +class API::LicencesController < API::APIController before_action :authenticate_user!, except: %i[index show] before_action :set_licence, only: %i[show update destroy] diff --git a/app/controllers/api/machine_categories_controller.rb b/app/controllers/api/machine_categories_controller.rb index ae9193a8e..178a85655 100644 --- a/app/controllers/api/machine_categories_controller.rb +++ b/app/controllers/api/machine_categories_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Machine Category # Categories are used to classify Machine -class API::MachineCategoriesController < API::ApiController +class API::MachineCategoriesController < API::APIController before_action :authenticate_user!, except: [:index] before_action :set_machine_category, only: %i[show update destroy] diff --git a/app/controllers/api/machines_controller.rb b/app/controllers/api/machines_controller.rb index 4084bfab7..678a60713 100644 --- a/app/controllers/api/machines_controller.rb +++ b/app/controllers/api/machines_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Machine -class API::MachinesController < API::ApiController +class API::MachinesController < API::APIController before_action :authenticate_user!, except: %i[index show] before_action :set_machine, only: %i[update destroy] respond_to :json diff --git a/app/controllers/api/members_controller.rb b/app/controllers/api/members_controller.rb index 4837dca32..c98edcc6e 100644 --- a/app/controllers/api/members_controller.rb +++ b/app/controllers/api/members_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type User with role 'member' -class API::MembersController < API::ApiController +class API::MembersController < API::APIController before_action :authenticate_user!, except: [:last_subscribed] before_action :set_member, only: %i[update destroy merge complete_tour update_role validate] before_action :set_operator, only: %i[show update create merge validate] diff --git a/app/controllers/api/notification_preferences_controller.rb b/app/controllers/api/notification_preferences_controller.rb index 0137726d5..e27967b75 100644 --- a/app/controllers/api/notification_preferences_controller.rb +++ b/app/controllers/api/notification_preferences_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Notification Preferences -class API::NotificationPreferencesController < API::ApiController +class API::NotificationPreferencesController < API::APIController before_action :authenticate_user! def index diff --git a/app/controllers/api/notification_types_controller.rb b/app/controllers/api/notification_types_controller.rb index e4fbcc102..6d4b8b3fd 100644 --- a/app/controllers/api/notification_types_controller.rb +++ b/app/controllers/api/notification_types_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Notification Types -class API::NotificationTypesController < API::ApiController +class API::NotificationTypesController < API::APIController before_action :authenticate_user! def index diff --git a/app/controllers/api/notifications_controller.rb b/app/controllers/api/notifications_controller.rb index 606cb4914..82fc87583 100644 --- a/app/controllers/api/notifications_controller.rb +++ b/app/controllers/api/notifications_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Notification # Notifications are scoped by user -class API::NotificationsController < API::ApiController +class API::NotificationsController < API::APIController before_action :authenticate_user! before_action :set_notification, only: :update diff --git a/app/controllers/api/open_api_clients_controller.rb b/app/controllers/api/open_api_clients_controller.rb index 27edc269f..1de54b1e7 100644 --- a/app/controllers/api/open_api_clients_controller.rb +++ b/app/controllers/api/open_api_clients_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type OpenAPI::Client # OpenAPI::Clients are used to allow access to the public API -class API::OpenAPIClientsController < API::ApiController +class API::OpenAPIClientsController < API::APIController before_action :authenticate_user! def index @@ -40,7 +40,7 @@ class API::OpenAPIClientsController < API::ApiController @client = OpenAPI::Client.find(params[:id]) authorize @client @client.destroy - head 204 + head :no_content end private diff --git a/app/controllers/api/openlab_projects_controller.rb b/app/controllers/api/openlab_projects_controller.rb index 1a19508e4..5522ce495 100644 --- a/app/controllers/api/openlab_projects_controller.rb +++ b/app/controllers/api/openlab_projects_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Openlab::Projects # Openlab::Projects are Projects shared between different instances -class API::OpenlabProjectsController < API::ApiController +class API::OpenlabProjectsController < API::APIController before_action :init_openlab def index diff --git a/app/controllers/api/orders_controller.rb b/app/controllers/api/orders_controller.rb index ff453e8df..6e77e397c 100644 --- a/app/controllers/api/orders_controller.rb +++ b/app/controllers/api/orders_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Order # Orders are used in store -class API::OrdersController < API::ApiController +class API::OrdersController < API::APIController before_action :authenticate_user!, except: %i[withdrawal_instructions] before_action :set_order, only: %i[show update destroy withdrawal_instructions] diff --git a/app/controllers/api/payment_schedules_controller.rb b/app/controllers/api/payment_schedules_controller.rb index 21968918c..ae5169f70 100644 --- a/app/controllers/api/payment_schedules_controller.rb +++ b/app/controllers/api/payment_schedules_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of PaymentSchedule -class API::PaymentSchedulesController < API::ApiController +class API::PaymentSchedulesController < API::APIController before_action :authenticate_user! before_action :set_payment_schedule, only: %i[download cancel update] before_action :set_payment_schedule_item, only: %i[show_item cash_check confirm_transfer refresh_item pay_item] diff --git a/app/controllers/api/payments_controller.rb b/app/controllers/api/payments_controller.rb index 7a878ee86..16e5c596a 100644 --- a/app/controllers/api/payments_controller.rb +++ b/app/controllers/api/payments_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Abstract API Controller to be extended by each payment gateway/mean, for handling the payments processes in the front-end -class API::PaymentsController < API::ApiController +class API::PaymentsController < API::APIController before_action :authenticate_user! # This method must be overridden by the the gateways controllers that inherits API::PaymentsControllers diff --git a/app/controllers/api/plan_categories_controller.rb b/app/controllers/api/plan_categories_controller.rb index 407bfd0e6..4c4dd6464 100644 --- a/app/controllers/api/plan_categories_controller.rb +++ b/app/controllers/api/plan_categories_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type PlanCategory # PlanCategory are used to sort plans -class API::PlanCategoriesController < API::ApiController +class API::PlanCategoriesController < API::APIController before_action :authenticate_user!, except: :index before_action :set_category, only: %i[show update destroy] diff --git a/app/controllers/api/plans_controller.rb b/app/controllers/api/plans_controller.rb index 52d786cd5..6c92a73bb 100644 --- a/app/controllers/api/plans_controller.rb +++ b/app/controllers/api/plans_controller.rb @@ -3,7 +3,7 @@ # API Controller for resources of type Plan and PartnerPlan. # Plan are used to define subscription's characteristics. # PartnerPlan is a special kind of plan which send notifications to an external user -class API::PlansController < API::ApiController +class API::PlansController < API::APIController include ApplicationHelper before_action :authenticate_user!, except: %i[index durations] diff --git a/app/controllers/api/prepaid_packs_controller.rb b/app/controllers/api/prepaid_packs_controller.rb index 8b02c6196..7ec8bb1a6 100644 --- a/app/controllers/api/prepaid_packs_controller.rb +++ b/app/controllers/api/prepaid_packs_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type PrepaidPack # PrepaidPacks are used to provide discounts to users that bought many hours at once -class API::PrepaidPacksController < API::ApiController +class API::PrepaidPacksController < API::APIController include ApplicationHelper before_action :authenticate_user!, except: :index diff --git a/app/controllers/api/price_categories_controller.rb b/app/controllers/api/price_categories_controller.rb index 9d91c4f53..96bb17102 100644 --- a/app/controllers/api/price_categories_controller.rb +++ b/app/controllers/api/price_categories_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type PriceCategory # PriceCategories are used in Events -class API::PriceCategoriesController < API::ApiController +class API::PriceCategoriesController < API::APIController before_action :authenticate_user!, only: %i[update show create destroy] before_action :set_price_category, only: %i[show update destroy] diff --git a/app/controllers/api/prices_controller.rb b/app/controllers/api/prices_controller.rb index 5c2d219e1..b77593ca9 100644 --- a/app/controllers/api/prices_controller.rb +++ b/app/controllers/api/prices_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Price # Prices are used in reservations (Machine, Space) -class API::PricesController < API::ApiController +class API::PricesController < API::APIController include ApplicationHelper before_action :authenticate_user! diff --git a/app/controllers/api/pricing_controller.rb b/app/controllers/api/pricing_controller.rb index 78b13bf61..522b553f6 100644 --- a/app/controllers/api/pricing_controller.rb +++ b/app/controllers/api/pricing_controller.rb @@ -3,7 +3,7 @@ # @deprecated # DEPRECATED: Please use API::PriceController instead. # API Controller for managing Plans prices -class API::PricingController < API::ApiController +class API::PricingController < API::APIController include ApplicationHelper before_action :authenticate_user!, except: %i[index update] diff --git a/app/controllers/api/product_categories_controller.rb b/app/controllers/api/product_categories_controller.rb index dc9ce614b..e3b2ec8d7 100644 --- a/app/controllers/api/product_categories_controller.rb +++ b/app/controllers/api/product_categories_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type ProductCategory # ProductCategories are used to group Products -class API::ProductCategoriesController < API::ApiController +class API::ProductCategoriesController < API::APIController before_action :authenticate_user!, except: :index before_action :set_product_category, only: %i[update destroy position] diff --git a/app/controllers/api/products_controller.rb b/app/controllers/api/products_controller.rb index ae8411993..b4f438352 100644 --- a/app/controllers/api/products_controller.rb +++ b/app/controllers/api/products_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Product # Products are used in store -class API::ProductsController < API::ApiController +class API::ProductsController < API::APIController before_action :authenticate_user!, except: %i[index show] before_action :set_product, only: %i[update clone destroy] diff --git a/app/controllers/api/profile_custom_fields_controller.rb b/app/controllers/api/profile_custom_fields_controller.rb index e0a902863..0e3326e40 100644 --- a/app/controllers/api/profile_custom_fields_controller.rb +++ b/app/controllers/api/profile_custom_fields_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type ProfileCustomField # ProfileCustomFields are fields configured by an admin, added to the user's profile -class API::ProfileCustomFieldsController < API::ApiController +class API::ProfileCustomFieldsController < API::APIController before_action :authenticate_user!, except: :index before_action :set_profile_custom_field, only: %i[show update destroy] diff --git a/app/controllers/api/projects_controller.rb b/app/controllers/api/projects_controller.rb index 15db7f801..dc1cf7699 100644 --- a/app/controllers/api/projects_controller.rb +++ b/app/controllers/api/projects_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Project -class API::ProjectsController < API::ApiController +class API::ProjectsController < API::APIController before_action :authenticate_user!, except: %i[index show last_published search] before_action :set_project, only: %i[update destroy] respond_to :json diff --git a/app/controllers/api/reservations_controller.rb b/app/controllers/api/reservations_controller.rb index 42cab8487..3bfe28d08 100644 --- a/app/controllers/api/reservations_controller.rb +++ b/app/controllers/api/reservations_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Reservation # Reservations are used for Training, Machine, Space and Event -class API::ReservationsController < API::ApiController +class API::ReservationsController < API::APIController before_action :authenticate_user! before_action :set_reservation, only: %i[show update] respond_to :json diff --git a/app/controllers/api/settings_controller.rb b/app/controllers/api/settings_controller.rb index 238b6960f..2640ea5b3 100644 --- a/app/controllers/api/settings_controller.rb +++ b/app/controllers/api/settings_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Setting -class API::SettingsController < API::ApiController +class API::SettingsController < API::APIController before_action :authenticate_user!, only: %i[update bulk_update reset] def index @@ -47,7 +47,7 @@ class API::SettingsController < API::ApiController end @settings.push db_setting - may_rollback(params[:transactional]) if db_setting.errors.keys.count.positive? + may_rollback(params[:transactional]) if db_setting.errors.attribute_names.count.positive? end end SettingService.run_after_update(updated_settings) @@ -93,9 +93,9 @@ class API::SettingsController < API::ApiController end # run the given block in a transaction if `should` is true. Just run it normally otherwise - def may_transaction(should, &block) + def may_transaction(should, &) if should == 'true' - ActiveRecord::Base.transaction(&block) + ActiveRecord::Base.transaction(&) else yield end diff --git a/app/controllers/api/slots_reservations_controller.rb b/app/controllers/api/slots_reservations_controller.rb index 9ee95cbca..2fcda5e83 100644 --- a/app/controllers/api/slots_reservations_controller.rb +++ b/app/controllers/api/slots_reservations_controller.rb @@ -3,7 +3,7 @@ # API Controller for resources of type Slot # Slots are used to cut Availabilities into reservable slots. The duration of these slots is configured per # availability by Availability.slot_duration, or otherwise globally by Setting.get('slot_duration') -class API::SlotsReservationsController < API::ApiController +class API::SlotsReservationsController < API::APIController before_action :authenticate_user! before_action :set_slots_reservation, only: %i[update cancel] respond_to :json diff --git a/app/controllers/api/spaces_controller.rb b/app/controllers/api/spaces_controller.rb index f155e1d81..5690b399d 100644 --- a/app/controllers/api/spaces_controller.rb +++ b/app/controllers/api/spaces_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Space -class API::SpacesController < API::ApiController +class API::SpacesController < API::APIController before_action :authenticate_user!, except: %i[index show] before_action :set_space, only: %i[update destroy] respond_to :json diff --git a/app/controllers/api/statistics_controller.rb b/app/controllers/api/statistics_controller.rb index ac2d2bd4a..1f8c96d56 100644 --- a/app/controllers/api/statistics_controller.rb +++ b/app/controllers/api/statistics_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for various statistical resources (gateway to elasticsearch DB) -class API::StatisticsController < API::ApiController +class API::StatisticsController < API::APIController before_action :authenticate_user! def index diff --git a/app/controllers/api/stylesheets_controller.rb b/app/controllers/api/stylesheets_controller.rb index acc8b0b03..22b4e1f9c 100644 --- a/app/controllers/api/stylesheets_controller.rb +++ b/app/controllers/api/stylesheets_controller.rb @@ -2,9 +2,7 @@ # API Controller for resources of type Stylesheet # Stylesheets are used to customize the appearance of Fab-manager -class API::StylesheetsController < API::ApiController - caches_page :show # magic happens here - +class API::StylesheetsController < API::APIController def show @stylesheet = Stylesheet.find(params[:id]) end diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb index 05cf0de53..07e4a0310 100644 --- a/app/controllers/api/subscriptions_controller.rb +++ b/app/controllers/api/subscriptions_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Subscription -class API::SubscriptionsController < API::ApiController +class API::SubscriptionsController < API::APIController before_action :set_subscription, only: %i[show payment_details cancel] before_action :authenticate_user! diff --git a/app/controllers/api/supporting_document_files_controller.rb b/app/controllers/api/supporting_document_files_controller.rb index c40d7ac69..34868aacb 100644 --- a/app/controllers/api/supporting_document_files_controller.rb +++ b/app/controllers/api/supporting_document_files_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type SupportingDocumentFile # SupportingDocumentFiles are used in settings -class API::SupportingDocumentFilesController < API::ApiController +class API::SupportingDocumentFilesController < API::APIController before_action :authenticate_user! before_action :set_supporting_document_file, only: %i[show update download] diff --git a/app/controllers/api/supporting_document_refusals_controller.rb b/app/controllers/api/supporting_document_refusals_controller.rb index a8aea3b7f..1da9cabe4 100644 --- a/app/controllers/api/supporting_document_refusals_controller.rb +++ b/app/controllers/api/supporting_document_refusals_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type SupportingDocumentRefusal # SupportingDocumentRefusal are used by admin refuse user's proof of identity file -class API::SupportingDocumentRefusalsController < API::ApiController +class API::SupportingDocumentRefusalsController < API::APIController before_action :authenticate_user! def index diff --git a/app/controllers/api/supporting_document_types_controller.rb b/app/controllers/api/supporting_document_types_controller.rb index c299f8a78..68a57569a 100644 --- a/app/controllers/api/supporting_document_types_controller.rb +++ b/app/controllers/api/supporting_document_types_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type SupportingDocumentType # ProofOfIdentityTypes are used to provide admin config proof of identity type by group -class API::SupportingDocumentTypesController < API::ApiController +class API::SupportingDocumentTypesController < API::APIController before_action :authenticate_user!, except: :index before_action :set_supporting_document_type, only: %i[show update destroy] diff --git a/app/controllers/api/tags_controller.rb b/app/controllers/api/tags_controller.rb index 24f1a4549..6beaa010a 100644 --- a/app/controllers/api/tags_controller.rb +++ b/app/controllers/api/tags_controller.rb @@ -2,8 +2,7 @@ # API Controller for resources of type Tag # Tags are used to restrict access to Availabilities -class API::TagsController < API::ApiController - +class API::TagsController < API::APIController before_action :authenticate_user!, except: %i[index show] before_action :set_tag, only: %i[show update destroy] diff --git a/app/controllers/api/themes_controller.rb b/app/controllers/api/themes_controller.rb index 1c1fa479f..66894b036 100644 --- a/app/controllers/api/themes_controller.rb +++ b/app/controllers/api/themes_controller.rb @@ -2,7 +2,7 @@ # API Controller for resources of type Theme # Themes are used in Projects -class API::ThemesController < API::ApiController +class API::ThemesController < API::APIController before_action :authenticate_user!, except: %i[index show] before_action :set_theme, only: %i[show update destroy] diff --git a/app/controllers/api/trainings_controller.rb b/app/controllers/api/trainings_controller.rb index 37d518c03..286ef7bf8 100644 --- a/app/controllers/api/trainings_controller.rb +++ b/app/controllers/api/trainings_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Training -class API::TrainingsController < API::ApiController +class API::TrainingsController < API::APIController include ApplicationHelper before_action :authenticate_user!, except: %i[index show] diff --git a/app/controllers/api/trainings_pricings_controller.rb b/app/controllers/api/trainings_pricings_controller.rb index 47f0e39f2..f0865a646 100644 --- a/app/controllers/api/trainings_pricings_controller.rb +++ b/app/controllers/api/trainings_pricings_controller.rb @@ -3,7 +3,7 @@ # @deprecated # DEPRECATED: Please use API::PriceController instead. # API Controller for managing Training prices -class API::TrainingsPricingsController < API::ApiController +class API::TrainingsPricingsController < API::APIController include ApplicationHelper before_action :authenticate_user! diff --git a/app/controllers/api/translations_controller.rb b/app/controllers/api/translations_controller.rb index cca3f47e4..dd74c167d 100644 --- a/app/controllers/api/translations_controller.rb +++ b/app/controllers/api/translations_controller.rb @@ -1,12 +1,12 @@ # frozen_string_literal: true # API Controller for managing front-end translations -class API::TranslationsController < API::ApiController +class API::TranslationsController < API::APIController before_action :set_locale def show translations = I18n.t params[:state] - if translations.class.name == String.name && translations.start_with?('translation missing') + if translations.instance_of?(String) && translations.start_with?('translation missing') render json: { error: translations }, status: :unprocessable_entity else path = params[:state] @@ -20,5 +20,4 @@ class API::TranslationsController < API::ApiController def set_locale I18n.locale = params[:locale] || I18n.default_locale end - end diff --git a/app/controllers/api/user_packs_controller.rb b/app/controllers/api/user_packs_controller.rb index 4c00014ef..0764347ad 100644 --- a/app/controllers/api/user_packs_controller.rb +++ b/app/controllers/api/user_packs_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type StatisticProfilePrepaidPack -class API::UserPacksController < API::ApiController +class API::UserPacksController < API::APIController before_action :authenticate_user! def index diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb index 0b1a61e67..6bd035f60 100644 --- a/app/controllers/api/users_controller.rb +++ b/app/controllers/api/users_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Users with role :partner or :manager -class API::UsersController < API::ApiController +class API::UsersController < API::APIController before_action :authenticate_user! before_action :set_user, only: %i[destroy] diff --git a/app/controllers/api/version_controller.rb b/app/controllers/api/version_controller.rb index 9c44c7c9c..ae2a71e64 100644 --- a/app/controllers/api/version_controller.rb +++ b/app/controllers/api/version_controller.rb @@ -3,7 +3,7 @@ require 'version' # API Controller to get the Fab-manager version -class API::VersionController < API::ApiController +class API::VersionController < API::APIController before_action :authenticate_user! def show diff --git a/app/controllers/api/wallet_controller.rb b/app/controllers/api/wallet_controller.rb index 19eedffea..a4f486db5 100644 --- a/app/controllers/api/wallet_controller.rb +++ b/app/controllers/api/wallet_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # API Controller for resources of type Wallet -class API::WalletController < API::ApiController +class API::WalletController < API::APIController before_action :authenticate_user! def by_user diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 5ee5c20fc..5ee62ae83 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -7,7 +7,6 @@ class ApplicationController < ActionController::Base # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception after_action :set_csrf_cookie - cache_sweeper :stylesheet_sweeper respond_to :html, :json @@ -42,7 +41,7 @@ class ApplicationController < ActionController::Base { profile_attributes: %i[phone last_name first_name interest software_mastered], invoicing_profile_attributes: [ - organization_attributes: [:name, address_attributes: [:address]], + organization_attributes: [:name, { address_attributes: [:address] }], user_profile_custom_fields_attributes: %i[profile_custom_field_id value], address_attributes: [:address] ], @@ -60,14 +59,14 @@ class ApplicationController < ActionController::Base end def permission_denied - head 403 + head :forbidden end # Set the configured locale for each action (API call) # @see https://guides.rubyonrails.org/i18n.html - def switch_locale(&action) + def switch_locale(&) locale = params[:locale] || Rails.application.secrets.rails_locale - I18n.with_locale(locale, &action) + I18n.with_locale(locale, &) end # @return [User] diff --git a/app/controllers/open_api/v1/accounting_controller.rb b/app/controllers/open_api/v1/accounting_controller.rb index 7690108ac..c92a654ce 100644 --- a/app/controllers/open_api/v1/accounting_controller.rb +++ b/app/controllers/open_api/v1/accounting_controller.rb @@ -4,9 +4,9 @@ require_relative 'concerns/accountings_filters_concern' # authorized 3rd party softwares can fetch the accounting lines through the OpenAPI class OpenAPI::V1::AccountingController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination - include AccountingsFiltersConcern + include OpenAPI::V1::Concerns::AccountingsFiltersConcern expose_doc def index diff --git a/app/controllers/open_api/v1/availabilities_controller.rb b/app/controllers/open_api/v1/availabilities_controller.rb new file mode 100644 index 000000000..9a5bedbdd --- /dev/null +++ b/app/controllers/open_api/v1/availabilities_controller.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require_relative 'concerns/reservations_filters_concern' + +# public API controller for resources of type Reservation +class OpenAPI::V1::AvailabilitiesController < OpenAPI::V1::BaseController + extend OpenAPI::APIDoc + include Rails::Pagination + include OpenAPI::V1::Concerns::AvailabilitiesFiltersConcern + expose_doc + + def index + @availabilities = Availability.order(start_at: :desc) + .includes(:slots) + + @availabilities = filter_by_after(@availabilities, params) + @availabilities = filter_by_before(@availabilities, params) + @availabilities = filter_by_id(@availabilities, params) + @availabilities = filter_by_available_type(@availabilities, params) + @availabilities = filter_by_available_id(@availabilities, params) + + @availabilities = @availabilities.page(page).per(per_page) + paginate @availabilities, per_page: per_page + end + + private + + def page + params[:page] || 1 + end + + def per_page + params[:per_page] || 20 + end +end diff --git a/app/controllers/open_api/v1/bookable_machines_controller.rb b/app/controllers/open_api/v1/bookable_machines_controller.rb index b8ed876eb..0ada7ac1a 100644 --- a/app/controllers/open_api/v1/bookable_machines_controller.rb +++ b/app/controllers/open_api/v1/bookable_machines_controller.rb @@ -2,7 +2,7 @@ # authorized 3rd party softwares can list the bookable machines through the OpenAPI class OpenAPI::V1::BookableMachinesController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc expose_doc def index diff --git a/app/controllers/open_api/v1/concerns/accountings_filters_concern.rb b/app/controllers/open_api/v1/concerns/accountings_filters_concern.rb index 2c5d4930b..3cafbc25c 100644 --- a/app/controllers/open_api/v1/concerns/accountings_filters_concern.rb +++ b/app/controllers/open_api/v1/concerns/accountings_filters_concern.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Filter the list of accounting lines by the given parameters -module AccountingsFiltersConcern +module OpenAPI::V1::Concerns::AccountingsFiltersConcern extend ActiveSupport::Concern included do diff --git a/app/controllers/open_api/v1/concerns/availabilities_filters_concern.rb b/app/controllers/open_api/v1/concerns/availabilities_filters_concern.rb new file mode 100644 index 000000000..717bc5c4b --- /dev/null +++ b/app/controllers/open_api/v1/concerns/availabilities_filters_concern.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +# Filter the list of availabilities by the given parameters +module OpenAPI::V1::Concerns::AvailabilitiesFiltersConcern + extend ActiveSupport::Concern + + included do + # @param availabilities [ActiveRecord::Relation] + # @param filters [ActionController::Parameters] + def filter_by_id(availabilities, filters) + return availabilities if filters[:id].blank? + + availabilities.where(id: may_array(filters[:id])) + end + + # @param availabilities [ActiveRecord::Relation] + # @param filters [ActionController::Parameters] + def filter_by_after(availabilities, filters) + return availabilities if filters[:after].blank? + + availabilities.where('availabilities.start_at >= ?', Time.zone.parse(filters[:after])) + end + + # @param availabilities [ActiveRecord::Relation] + # @param filters [ActionController::Parameters] + def filter_by_before(availabilities, filters) + return availabilities if filters[:before].blank? + + availabilities.where('availabilities.end_at <= ?', Time.zone.parse(filters[:before])) + end + + # @param availabilities [ActiveRecord::Relation] + # @param filters [ActionController::Parameters] + def filter_by_available_type(availabilities, filters) + return availabilities if filters[:available_type].blank? + + availabilities.where(available_type: format_type(filters[:available_type])) + end + + # @param availabilities [ActiveRecord::Relation] + # @param filters [ActionController::Parameters] + def filter_by_available_id(availabilities, filters) + return availabilities if filters[:available_id].blank? || filters[:available_type].blank? + + join_table = join_table(filters) + availabilities.joins(join_table).where(join_table => { where_clause(filters) => may_array(filters[:available_id]) }) + end + + # @param type [ActionController::Parameters] + # @return [String] + def format_type(type) + types = { + 'Machine' => 'machines', + 'Space' => 'space', + 'Training' => 'training', + 'Event' => 'event' + } + types[type] + end + + # @param filters [ActionController::Parameters] + # @return [Symbol] + def join_table(filters) + tables = { + 'Machine' => :machines_availabilities, + 'Space' => :spaces_availabilities, + 'Training' => :trainings_availabilities, + 'Event' => :event + } + tables[filters[:available_type]] + end + + # @param filters [ActionController::Parameters] + # @return [Symbol] + def where_clause(filters) + clauses = { + 'Machine' => :machine_id, + 'Space' => :space_id, + 'Training' => :training_id, + 'Event' => :id + } + clauses[filters[:available_type]] + end + end +end diff --git a/app/controllers/open_api/v1/concerns/reservations_filters_concern.rb b/app/controllers/open_api/v1/concerns/reservations_filters_concern.rb index f011aec0b..12f235d91 100644 --- a/app/controllers/open_api/v1/concerns/reservations_filters_concern.rb +++ b/app/controllers/open_api/v1/concerns/reservations_filters_concern.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Filter the list of reservations by the given parameters -module ReservationsFiltersConcern +module OpenAPI::V1::Concerns::ReservationsFiltersConcern extend ActiveSupport::Concern included do @@ -45,6 +45,15 @@ module ReservationsFiltersConcern reservations.where(reservable_id: may_array(filters[:reservable_id])) end + # @param reservations [ActiveRecord::Relation] + # @param filters [ActionController::Parameters] + def filter_by_availability_id(reservations, filters) + return reservations if filters[:availability_id].blank? + + reservations.joins(:slots_reservations, :slots) + .where(slots_reservations: { slots: { availability_id: may_array(filters[:availability_id]) } }) + end + # @param type [String] def format_type(type) type.singularize.classify diff --git a/app/controllers/open_api/v1/concerns/subscriptions_filters_concern.rb b/app/controllers/open_api/v1/concerns/subscriptions_filters_concern.rb index 56972f351..ba55144b8 100644 --- a/app/controllers/open_api/v1/concerns/subscriptions_filters_concern.rb +++ b/app/controllers/open_api/v1/concerns/subscriptions_filters_concern.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Filter the list of subscriptions by the given parameters -module SubscriptionsFiltersConcern +module OpenAPI::V1::Concerns::SubscriptionsFiltersConcern extend ActiveSupport::Concern included do diff --git a/app/controllers/open_api/v1/events_controller.rb b/app/controllers/open_api/v1/events_controller.rb index 3f4c61a12..85e32b697 100644 --- a/app/controllers/open_api/v1/events_controller.rb +++ b/app/controllers/open_api/v1/events_controller.rb @@ -2,7 +2,7 @@ # authorized 3rd party softwares can manage the events through the OpenAPI class OpenAPI::V1::EventsController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination expose_doc diff --git a/app/controllers/open_api/v1/invoices_controller.rb b/app/controllers/open_api/v1/invoices_controller.rb index e2adec7de..c7d77c2c2 100644 --- a/app/controllers/open_api/v1/invoices_controller.rb +++ b/app/controllers/open_api/v1/invoices_controller.rb @@ -2,7 +2,7 @@ # OpenAPI controller for the invoices class OpenAPI::V1::InvoicesController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination expose_doc diff --git a/app/controllers/open_api/v1/machines_controller.rb b/app/controllers/open_api/v1/machines_controller.rb index 9d11a01cb..b64dd5645 100644 --- a/app/controllers/open_api/v1/machines_controller.rb +++ b/app/controllers/open_api/v1/machines_controller.rb @@ -2,7 +2,7 @@ # authorized 3rd party softwares can manage the machines through the OpenAPI class OpenAPI::V1::MachinesController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc expose_doc before_action :set_machine, only: %i[show update destroy] diff --git a/app/controllers/open_api/v1/plan_categories_controller.rb b/app/controllers/open_api/v1/plan_categories_controller.rb index 1bd6ef554..186151c9c 100644 --- a/app/controllers/open_api/v1/plan_categories_controller.rb +++ b/app/controllers/open_api/v1/plan_categories_controller.rb @@ -2,7 +2,7 @@ # authorized 3rd party softwares can fetch data about plan categories through the OpenAPI class OpenAPI::V1::PlanCategoriesController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc expose_doc def index diff --git a/app/controllers/open_api/v1/plans_controller.rb b/app/controllers/open_api/v1/plans_controller.rb index fb915e0fa..afd4547c2 100644 --- a/app/controllers/open_api/v1/plans_controller.rb +++ b/app/controllers/open_api/v1/plans_controller.rb @@ -2,7 +2,7 @@ # authorized 3rd party softwares can fetch data about plans through the OpenAPI class OpenAPI::V1::PlansController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc expose_doc before_action :set_plan, only: %i[show] diff --git a/app/controllers/open_api/v1/prices_controller.rb b/app/controllers/open_api/v1/prices_controller.rb index b5652bb81..faa9ec944 100644 --- a/app/controllers/open_api/v1/prices_controller.rb +++ b/app/controllers/open_api/v1/prices_controller.rb @@ -2,7 +2,7 @@ # public API controller for resources of type Price class OpenAPI::V1::PricesController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination expose_doc diff --git a/app/controllers/open_api/v1/reservations_controller.rb b/app/controllers/open_api/v1/reservations_controller.rb index 14c8690c7..7d6fa160a 100644 --- a/app/controllers/open_api/v1/reservations_controller.rb +++ b/app/controllers/open_api/v1/reservations_controller.rb @@ -4,9 +4,9 @@ require_relative 'concerns/reservations_filters_concern' # public API controller for resources of type Reservation class OpenAPI::V1::ReservationsController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination - include ReservationsFiltersConcern + include OpenAPI::V1::Concerns::ReservationsFiltersConcern expose_doc def index @@ -19,6 +19,7 @@ class OpenAPI::V1::ReservationsController < OpenAPI::V1::BaseController @reservations = filter_by_user(@reservations, params) @reservations = filter_by_reservable_type(@reservations, params) @reservations = filter_by_reservable_id(@reservations, params) + @reservations = filter_by_availability_id(@reservations, params) @reservations = @reservations.page(page).per(per_page) paginate @reservations, per_page: per_page diff --git a/app/controllers/open_api/v1/spaces_controller.rb b/app/controllers/open_api/v1/spaces_controller.rb index 18dcf9dd8..86ac756ae 100644 --- a/app/controllers/open_api/v1/spaces_controller.rb +++ b/app/controllers/open_api/v1/spaces_controller.rb @@ -2,7 +2,7 @@ # authorized 3rd party softwares can fetch data about spaces through the OpenAPI class OpenAPI::V1::SpacesController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc expose_doc before_action :set_space, only: %i[show] diff --git a/app/controllers/open_api/v1/subscriptions_controller.rb b/app/controllers/open_api/v1/subscriptions_controller.rb index bc32d0259..72edfca8c 100644 --- a/app/controllers/open_api/v1/subscriptions_controller.rb +++ b/app/controllers/open_api/v1/subscriptions_controller.rb @@ -4,9 +4,9 @@ require_relative 'concerns/subscriptions_filters_concern' # authorized 3rd party softwares can fetch the subscriptions through the OpenAPI class OpenAPI::V1::SubscriptionsController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination - include SubscriptionsFiltersConcern + include OpenAPI::V1::Concerns::SubscriptionsFiltersConcern expose_doc def index diff --git a/app/controllers/open_api/v1/trainings_controller.rb b/app/controllers/open_api/v1/trainings_controller.rb index 277c99626..0b16a8449 100644 --- a/app/controllers/open_api/v1/trainings_controller.rb +++ b/app/controllers/open_api/v1/trainings_controller.rb @@ -2,7 +2,7 @@ # public API controller for resources of type Training class OpenAPI::V1::TrainingsController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc expose_doc def index diff --git a/app/controllers/open_api/v1/user_trainings_controller.rb b/app/controllers/open_api/v1/user_trainings_controller.rb index 902eea7d0..4b7287407 100644 --- a/app/controllers/open_api/v1/user_trainings_controller.rb +++ b/app/controllers/open_api/v1/user_trainings_controller.rb @@ -2,7 +2,7 @@ # public API controller for user's trainings class OpenAPI::V1::UserTrainingsController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination expose_doc diff --git a/app/controllers/open_api/v1/users_controller.rb b/app/controllers/open_api/v1/users_controller.rb index c52109dfc..91713096d 100644 --- a/app/controllers/open_api/v1/users_controller.rb +++ b/app/controllers/open_api/v1/users_controller.rb @@ -2,7 +2,7 @@ # public API controller for users class OpenAPI::V1::UsersController < OpenAPI::V1::BaseController - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc include Rails::Pagination expose_doc diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 05a2eb171..466bd5b09 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -2,13 +2,22 @@ # Devise controller for handling client sessions class SessionsController < Devise::SessionsController - def new - active_provider = AuthProvider.active - if active_provider.providable_type != DatabaseProvider.name - redirect_post "/users/auth/#{active_provider.strategy_name}", params: { authenticity_token: form_authenticity_token } - else + active_provider = Rails.configuration.auth_provider + if active_provider.providable_type == 'DatabaseProvider' super + else + redirect_post "/users/auth/#{active_provider.strategy_name}" end end + + # FIXME, Method DELETE is not allowed by Access-Control-Allow-Methods in preflight response. + # def destroy + # active_provider = Rails.configuration.auth_provider + # if active_provider.providable_type == 'OpenIdConnectProvider' + # redirect_to "/users/auth/#{active_provider.strategy_name}/logout" + # else + # super + # end + # end end diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index d01ae980f..2bcb14bb1 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -5,7 +5,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController require 'sso_logger' logger = SsoLogger.new - active_provider = AuthProvider.active + active_provider = Rails.configuration.auth_provider define_method active_provider.strategy_name do logger.info "[Users::OmniauthCallbacksController##{active_provider.strategy_name}] initiated" if request.env['omniauth.params'].blank? @@ -18,7 +18,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController logger.debug 'trying to create a new user' # If the username is mapped, we just check its uniqueness as it would break the postgresql # unique constraint otherwise. If the name is not unique, another unique is generated - if active_provider.sso_fields.include?('user.username') + if active_provider.db.sso_fields.include?('user.username') logger.debug 'the username was already in use, generating a new one' @user.username = generate_unique_username(@user.username) end @@ -26,7 +26,7 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController # unique random string, because: # - if it is the same user, his email will be filled from the SSO when he merge his accounts # - if it is not the same user, this will prevent the raise of PG::UniqueViolation - if active_provider.sso_fields.include?('user.email') && email_exists?(@user.email) + if active_provider.db.sso_fields.include?('user.email') && email_exists?(@user.email) logger.debug 'the email was already in use, marking it as duplicate' old_mail = @user.email @user.email = "<#{old_mail}>#{Devise.friendly_token}-duplicate" @@ -46,13 +46,14 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController @user.email = User.find(@user.id).email end end + # For users imported from the SSO, we consider the SSO as a source of trust so the email is automatically validated + @user.confirmed_at = Time.current if active_provider.db.sso_fields.include?('user.email') && !email_exists?(@user.email) - # We BYPASS THE VALIDATION because, in case of a new user, we want to save him anyway, we'll ask him later to complete his profile (on first login). + # We BYPASS THE VALIDATION because, in case of a new user, we want to save him anyway, + # we'll ask him later to complete his profile (on first login). # In case of an existing user, we trust the SSO validation as we want the SSO to have authority on users management and policy. logger.debug 'saving the user' - unless @user.save(validate: false) - logger.error "unable to save the user, an error occurred : #{@user.errors.full_messages.join(', ')}" - end + logger.error "unable to save the user, an error occurred : #{@user.errors.full_messages.join(', ')}" unless @user.save(validate: false) logger.debug 'signing-in the user and redirecting' sign_in_and_redirect @user, event: :authentication # this will throw if @user is not activated @@ -77,7 +78,6 @@ class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController raise e end end - end private diff --git a/app/doc/open_api/api_doc.rb b/app/doc/open_api/api_doc.rb index cb7dabe97..f08b3d1d0 100644 --- a/app/doc/open_api/api_doc.rb +++ b/app/doc/open_api/api_doc.rb @@ -4,11 +4,11 @@ # # Controller extension with common API documentation shortcuts # -module OpenAPI::ApiDoc +module OpenAPI::APIDoc # Apipie doesn't allow to append anything to esisting # description. It raises an error on double definition. # - def append_desc(desc = "") + def append_desc(desc = '') _apipie_dsl_data[:description] << desc << "\n" end @@ -20,7 +20,7 @@ module OpenAPI::ApiDoc # def to_markdown_code(code) code.split("\n").map do |line| - (" " * 4) + line + (' ' * 4) + line end.join("\n") end @@ -33,9 +33,8 @@ module OpenAPI::ApiDoc # @param schemas [Array] # def include_response_schema(*schemas) - root = Rails.root.join('app/doc/responses') _apipie_dsl_data[:description] = _apipie_dsl_data[:description].strip_heredoc - append_desc("## Response schema") + append_desc('## Response schema') schemas.each do |relative_path| append_desc MarkdownJsonSchema.read(relative_path) diff --git a/app/doc/open_api/application_doc.rb b/app/doc/open_api/application_doc.rb index ff21bd2a5..17958ce04 100644 --- a/app/doc/open_api/application_doc.rb +++ b/app/doc/open_api/application_doc.rb @@ -19,7 +19,7 @@ # end # class OpenAPI::ApplicationDoc - extend OpenAPI::ApiDoc + extend OpenAPI::APIDoc class << self # Stores provided resource description @@ -53,7 +53,7 @@ class OpenAPI::ApplicationDoc # @return [Hash] # def docs - @_docs ||= {} + @docs ||= {} end def define_param_group(param_group_name, &block) @@ -61,7 +61,7 @@ class OpenAPI::ApplicationDoc end def param_groups - @_param_groups ||= {} + @param_groups ||= {} end # Applies all defined DSL to provided controller class diff --git a/app/doc/open_api/v1/availabilities_doc.rb b/app/doc/open_api/v1/availabilities_doc.rb new file mode 100644 index 000000000..47d303671 --- /dev/null +++ b/app/doc/open_api/v1/availabilities_doc.rb @@ -0,0 +1,163 @@ +# frozen_string_literal: true + +# openAPI documentation for reservations endpoint +class OpenAPI::V1::AvailabilitiesDoc < OpenAPI::V1::BaseDoc + resource_description do + short 'Availabilities' + desc 'Slots availables for reservation' + formats FORMATS + api_version API_VERSION + end + + include OpenAPI::V1::Concerns::ParamGroups + + doc_for :index do + api :GET, "/#{API_VERSION}/availabilities", 'Availabilities index' + description 'Index of reservable availabilities and their slots, paginated. Ordered by *start_at* descendant.' + param_group :pagination + param :after, DateTime, optional: true, desc: 'Filter availabilities to those starting after the given date.' + param :before, DateTime, optional: true, desc: 'Filter availabilities to those ending before the given date.' + param :user_id, [Integer, Array], optional: true, desc: 'Scope the request to one or various users.' + param :available_type, %w[Event Machine Space Training], optional: true, desc: 'Scope the request to a specific type of reservable.' + param :available_id, [Integer, Array], optional: true, desc: 'Scope the request to one or various reservables.
' \ + 'WARNING: filtering by available_id is only available if ' \ + 'filter available_type is provided' + + example <<-AVAILABILITIES + # /open_api/v1/availabilities?available_type=Machine&page=1&per_page=3 + { + "availabilities": [ + { + "id": 5115, + "start_at": "2023-07-13T14:00:00.000+02:00", + "end_at": "2023-07-13T18:00:00.000+02:00", + "created_at": "2023-01-24T12:28:25.905+01:00", + "available_type": "Machine", + "available_ids": [ + 5, + 9, + 10, + 15, + 8, + 12, + 17, + 16, + 3, + 2, + 14, + 18 + ], + "slots": [ + { + "id": 17792, + "start_at": "2023-07-13T14:00:00.000+02:00", + "end_at": "2023-07-13T15:00:00.000+02:00" + }, + { + "id": 17793, + "start_at": "2023-07-13T15:00:00.000+02:00", + "end_at": "2023-07-13T16:00:00.000+02:00" + }, + { + "id": 17794, + "start_at": "2023-07-13T16:00:00.000+02:00", + "end_at": "2023-07-13T17:00:00.000+02:00" + }, + { + "id": 17795, + "start_at": "2023-07-13T17:00:00.000+02:00", + "end_at": "2023-07-13T18:00:00.000+02:00" + } + ] + }, + { + "id": 5112, + "start_at": "2023-07-07T14:00:00.000+02:00", + "end_at": "2023-07-07T18:00:00.000+02:00", + "created_at": "2023-01-24T12:26:45.997+01:00", + "available_type": "Machine", + "available_ids": [ + 5, + 9, + 10, + 15, + 8, + 12, + 17, + 16, + 3, + 2, + 14, + 18 + ], + "slots": [ + { + "id": 17786, + "start_at": "2023-07-07T14:00:00.000+02:00", + "end_at": "2023-07-07T15:00:00.000+02:00" + }, + { + "id": 17787, + "start_at": "2023-07-07T15:00:00.000+02:00", + "end_at": "2023-07-07T16:00:00.000+02:00" + }, + { + "id": 17788, + "start_at": "2023-07-07T16:00:00.000+02:00", + "end_at": "2023-07-07T17:00:00.000+02:00" + }, + { + "id": 17789, + "start_at": "2023-07-07T17:00:00.000+02:00", + "end_at": "2023-07-07T18:00:00.000+02:00" + } + ] + }, + { + "id": 5111, + "start_at": "2023-07-06T14:00:00.000+02:00", + "end_at": "2023-07-06T18:00:00.000+02:00", + "created_at": "2023-01-24T12:26:37.189+01:00", + "available_type": "Machine", + "available_ids": [ + 5, + 9, + 10, + 15, + 8, + 12, + 17, + 16, + 3, + 2, + 14, + 18 + ], + "slots": [ + { + "id": 17782, + "start_at": "2023-07-06T14:00:00.000+02:00", + "end_at": "2023-07-06T15:00:00.000+02:00" + }, + { + "id": 17783, + "start_at": "2023-07-06T15:00:00.000+02:00", + "end_at": "2023-07-06T16:00:00.000+02:00" + }, + { + "id": 17784, + "start_at": "2023-07-06T16:00:00.000+02:00", + "end_at": "2023-07-06T17:00:00.000+02:00" + }, + { + "id": 17785, + "start_at": "2023-07-06T17:00:00.000+02:00", + "end_at": "2023-07-06T18:00:00.000+02:00" + } + ] + } + ] + } + AVAILABILITIES + end +end diff --git a/app/doc/open_api/v1/reservations_doc.rb b/app/doc/open_api/v1/reservations_doc.rb index b6c4fecf1..cdbf2c4c5 100644 --- a/app/doc/open_api/v1/reservations_doc.rb +++ b/app/doc/open_api/v1/reservations_doc.rb @@ -20,6 +20,7 @@ class OpenAPI::V1::ReservationsDoc < OpenAPI::V1::BaseDoc param :user_id, [Integer, Array], optional: true, desc: 'Scope the request to one or various users.' param :reservable_type, %w[Event Machine Space Training], optional: true, desc: 'Scope the request to a specific type of reservable.' param :reservable_id, [Integer, Array], optional: true, desc: 'Scope the request to one or various reservables.' + param :availability_id, [Integer, Array], optional: true, desc: 'Scope the request to one or various availabilities.' example <<-RESERVATIONS # /open_api/v1/reservations?reservable_type=Event&page=1&per_page=3 @@ -48,6 +49,7 @@ class OpenAPI::V1::ReservationsDoc < OpenAPI::V1::BaseDoc "reserved_slots": [ { "canceled_at": "2016-05-20T09:40:12.201+01:00", + "availability_id": 5200, "start_at": "2016-06-03T14:00:00.000+01:00", "end_at": "2016-06-03T15:00:00.000+01:00" } @@ -76,6 +78,7 @@ class OpenAPI::V1::ReservationsDoc < OpenAPI::V1::BaseDoc "reserved_slots": [ { "canceled_at": null, + "availability_id": 5199, "start_at": "2016-06-02T16:00:00.000+01:00", "end_at": "2016-06-02T17:00:00.000+01:00" } @@ -104,6 +107,7 @@ class OpenAPI::V1::ReservationsDoc < OpenAPI::V1::BaseDoc "reserved_slots": [ { "canceled_at": null, + "availability_id": 5066, "start_at": "2016-06-03T14:00:00.000+01:00", "end_at": "2016-06-03T15:00:00.000+01:00" } diff --git a/app/frontend/src/javascript/api/member.ts b/app/frontend/src/javascript/api/member.ts index f1aeda857..bb6b5d54e 100644 --- a/app/frontend/src/javascript/api/member.ts +++ b/app/frontend/src/javascript/api/member.ts @@ -1,6 +1,6 @@ import apiClient from './clients/api-client'; import { AxiosResponse } from 'axios'; -import { serialize } from 'object-to-formdata'; +import { serialize } from 'object-to-formdata-tz'; import { User, MemberIndexFilter, UserRole } from '../models/user'; export default class MemberAPI { diff --git a/app/frontend/src/javascript/components/plans/plans-list.tsx b/app/frontend/src/javascript/components/plans/plans-list.tsx index f63fc014a..8973cd0ef 100644 --- a/app/frontend/src/javascript/components/plans/plans-list.tsx +++ b/app/frontend/src/javascript/components/plans/plans-list.tsx @@ -196,9 +196,9 @@ export const PlansList: React.FC = ({ onError, onPlanSelection, {Array.from(plans).sort(compareCategories).map(([categoryId, plansByCategory]) => { const category = findCategory(categoryId); const categoryPlans = plansByCategory.filter(filterPlan); - const isShown = !!categoryId && categoryPlans.length > 0; + const isShown = !!category && categoryPlans.length > 0; return ( -
+
{isShown &&

{ category.name }

} {isShown &&

} {renderPlans(categoryPlans)} diff --git a/app/frontend/src/javascript/lib/api.ts b/app/frontend/src/javascript/lib/api.ts index a0bae755a..1ef3b9b82 100644 --- a/app/frontend/src/javascript/lib/api.ts +++ b/app/frontend/src/javascript/lib/api.ts @@ -1,6 +1,6 @@ import _ from 'lodash'; import { ApiFilter } from '../models/api'; -import { serialize } from 'object-to-formdata'; +import { serialize } from 'object-to-formdata-tz'; export default class ApiLib { static filtersToQuery (filters?: ApiFilter, keepNullValues = true): string { diff --git a/app/frontend/src/javascript/router.js b/app/frontend/src/javascript/router.js index f2186e456..26ce00a93 100644 --- a/app/frontend/src/javascript/router.js +++ b/app/frontend/src/javascript/router.js @@ -979,7 +979,7 @@ angular.module('application.router', ['ui.router']) onlinePaymentStatus: ['Payment', function (Payment) { return Payment.onlinePaymentStatus().$promise; }], invoices: ['Invoice', function (Invoice) { return Invoice.list({ - query: { number: '', customer: '', date: null, order_by: '-reference', page: 1, size: 20 } + query: { number: '', customer: '', date: null, order_by: '-date', page: 1, size: 20 } }).$promise; }], closedPeriods: ['AccountingPeriod', function (AccountingPeriod) { return AccountingPeriod.query().$promise; }] diff --git a/app/models/advanced_accounting.rb b/app/models/advanced_accounting.rb index f68537b16..f475925f9 100644 --- a/app/models/advanced_accounting.rb +++ b/app/models/advanced_accounting.rb @@ -3,12 +3,12 @@ # AdvancedAccounting enables the various objects to have detailed accounting settings class AdvancedAccounting < ApplicationRecord belongs_to :accountable, polymorphic: true - belongs_to :machine, foreign_type: 'Machine', foreign_key: 'accountable_id', inverse_of: :advanced_accounting - belongs_to :training, foreign_type: 'Training', foreign_key: 'accountable_id', inverse_of: :advanced_accounting - belongs_to :space, foreign_type: 'Space', foreign_key: 'accountable_id', inverse_of: :advanced_accounting - belongs_to :event, foreign_type: 'Event', foreign_key: 'accountable_id', inverse_of: :advanced_accounting - belongs_to :product, foreign_type: 'Product', foreign_key: 'accountable_id', inverse_of: :advanced_accounting - belongs_to :plan, foreign_type: 'Plan', foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :machine, foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :training, foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :space, foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :event, foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :product, foreign_key: 'accountable_id', inverse_of: :advanced_accounting + belongs_to :plan, foreign_key: 'accountable_id', inverse_of: :advanced_accounting after_save :rebuild_accounting_lines diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 55c1abca5..077fb4ea2 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -15,7 +15,7 @@ class ApplicationRecord < ActiveRecord::Base def update_with_context(attributes, context) with_transaction_returning_status do assign_attributes(attributes) - save(context: context) + save(**{ context: context }) end end end diff --git a/app/models/auth_provider.rb b/app/models/auth_provider.rb index 126164938..8b21c58ae 100644 --- a/app/models/auth_provider.rb +++ b/app/models/auth_provider.rb @@ -11,6 +11,10 @@ class AuthProvider < ApplicationRecord def name 'DatabaseProvider::SimpleAuthProvider' end + + def strategy_name + 'database-simpleauthprovider' + end end PROVIDABLE_TYPES = %w[DatabaseProvider OAuth2Provider OpenIdConnectProvider].freeze @@ -26,6 +30,7 @@ class AuthProvider < ApplicationRecord validates_with UserUidMappedValidator, if: -> { %w[OAuth2Provider OpenIdConnectProvider].include?(providable_type) } before_create :set_initial_state + after_update :write_reload_config def build_providable(params) raise "Unknown providable_type: #{providable_type}" unless PROVIDABLE_TYPES.include?(providable_type) @@ -41,7 +46,7 @@ class AuthProvider < ApplicationRecord provider = find_by(status: 'active') return local if provider.nil? - provider + provider.reload rescue ActiveRecord::StatementInvalid # we fall here on database creation because the table "active_providers" still does not exists at the moment local @@ -110,4 +115,13 @@ class AuthProvider < ApplicationRecord # no providers in the database, he we will be 'active' (see seeds.rb) self.status = 'pending' unless AuthProvider.count.zero? end + + def write_reload_config + return unless status == 'active' + + ProviderConfig.write_active_provider + Rails.application.configure do + config.auth_provider = ProviderConfig.new + end + end end diff --git a/app/models/availability.rb b/app/models/availability.rb index e81f9c41e..6f28b240b 100644 --- a/app/models/availability.rb +++ b/app/models/availability.rb @@ -113,6 +113,22 @@ class Availability < ApplicationRecord end end + # @return [Array] + def available_ids + case available_type + when 'training' + training_ids + when 'machines' + machine_ids + when 'event' + [event&.id] + when 'space' + space_ids + else + [] + end + end + # check if the reservations are complete? # if a nb_total_places hasn't been defined, then places are unlimited # @return [Boolean] @@ -190,7 +206,7 @@ class Availability < ApplicationRecord duration = slot_duration || Setting.get('slot_duration').to_i return unless end_at < (start_at + duration.minutes) - errors.add(:end_at, I18n.t('availabilities.length_must_be_slot_multiple', MIN: duration)) + errors.add(:end_at, I18n.t('availabilities.length_must_be_slot_multiple', **{ MIN: duration })) end def should_be_associated diff --git a/app/models/cart_item/base_item.rb b/app/models/cart_item/base_item.rb index 4fc5952fa..6e62d55e9 100644 --- a/app/models/cart_item/base_item.rb +++ b/app/models/cart_item/base_item.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'cart_item' - # This is an abstract class implemented by classes that can be added to the shopping cart class CartItem::BaseItem < ApplicationRecord self.abstract_class = true diff --git a/app/models/cart_item/cart_item.rb b/app/models/cart_item/cart_item.rb deleted file mode 100644 index acfc5eb6a..000000000 --- a/app/models/cart_item/cart_item.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -# Items that can be added to the shopping cart -module CartItem; end diff --git a/app/models/cart_item/coupon.rb b/app/models/cart_item/coupon.rb index 858160b58..228959852 100644 --- a/app/models/cart_item/coupon.rb +++ b/app/models/cart_item/coupon.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'cart_item' - # A discount coupon applied to the whole shopping cart class CartItem::Coupon < ApplicationRecord self.table_name = 'cart_item_coupons' diff --git a/app/models/cart_item/event_reservation.rb b/app/models/cart_item/event_reservation.rb index c2dd29824..9ae7be11a 100644 --- a/app/models/cart_item/event_reservation.rb +++ b/app/models/cart_item/event_reservation.rb @@ -10,7 +10,7 @@ class CartItem::EventReservation < CartItem::Reservation accepts_nested_attributes_for :cart_item_event_reservation_tickets has_many :cart_item_reservation_slots, class_name: 'CartItem::ReservationSlot', dependent: :destroy, inverse_of: :cart_item, - foreign_key: 'cart_item_id', foreign_type: 'cart_item_type' + foreign_type: 'cart_item_type', as: :cart_item accepts_nested_attributes_for :cart_item_reservation_slots belongs_to :operator_profile, class_name: 'InvoicingProfile' @@ -22,6 +22,14 @@ class CartItem::EventReservation < CartItem::Reservation event end + def reservable_id + event_id + end + + def reservable_type + 'Event' + end + def price amount = reservable.amount * normal_tickets is_privileged = operator.privileged? && operator.id != customer.id diff --git a/app/models/cart_item/event_reservation_ticket.rb b/app/models/cart_item/event_reservation_ticket.rb index 94a921bad..c86a7189b 100644 --- a/app/models/cart_item/event_reservation_ticket.rb +++ b/app/models/cart_item/event_reservation_ticket.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'cart_item' - # A relation table between a pending event reservation and a special price for this event class CartItem::EventReservationTicket < ApplicationRecord self.table_name = 'cart_item_event_reservation_tickets' diff --git a/app/models/cart_item/free_extension.rb b/app/models/cart_item/free_extension.rb index ab2905b4b..8f4145a4f 100644 --- a/app/models/cart_item/free_extension.rb +++ b/app/models/cart_item/free_extension.rb @@ -25,7 +25,7 @@ class CartItem::FreeExtension < CartItem::BaseItem end def name - I18n.t('cart_items.free_extension', DATE: I18n.l(new_expiration_date)) + I18n.t('cart_items.free_extension', **{ DATE: I18n.l(new_expiration_date) }) end def to_object diff --git a/app/models/cart_item/machine_reservation.rb b/app/models/cart_item/machine_reservation.rb index 9fccf8911..6550dcee9 100644 --- a/app/models/cart_item/machine_reservation.rb +++ b/app/models/cart_item/machine_reservation.rb @@ -3,7 +3,7 @@ # A machine reservation added to the shopping cart class CartItem::MachineReservation < CartItem::Reservation has_many :cart_item_reservation_slots, class_name: 'CartItem::ReservationSlot', dependent: :destroy, inverse_of: :cart_item, - foreign_key: 'cart_item_id', foreign_type: 'cart_item_type' + foreign_type: 'cart_item_type', as: :cart_item accepts_nested_attributes_for :cart_item_reservation_slots belongs_to :operator_profile, class_name: 'InvoicingProfile' diff --git a/app/models/cart_item/payment_schedule.rb b/app/models/cart_item/payment_schedule.rb index bc989408f..fbcead696 100644 --- a/app/models/cart_item/payment_schedule.rb +++ b/app/models/cart_item/payment_schedule.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require_relative 'cart_item' - # A payment schedule applied to plan in the shopping cart class CartItem::PaymentSchedule < ApplicationRecord self.table_name = 'cart_item_payment_schedules' diff --git a/app/models/cart_item/prepaid_pack.rb b/app/models/cart_item/prepaid_pack.rb index aa57a666a..57bcebe03 100644 --- a/app/models/cart_item/prepaid_pack.rb +++ b/app/models/cart_item/prepaid_pack.rb @@ -41,7 +41,7 @@ class CartItem::PrepaidPack < CartItem::BaseItem return false end if pack.group_id != customer.group_id - errors.add(:group, I18n.t('cart_item_validation.pack_group', { GROUP: pack.group.name })) + errors.add(:group, I18n.t('cart_item_validation.pack_group', **{ GROUP: pack.group.name })) return false end true diff --git a/app/models/cart_item/reservation.rb b/app/models/cart_item/reservation.rb index f7f38455e..c70f67918 100644 --- a/app/models/cart_item/reservation.rb +++ b/app/models/cart_item/reservation.rb @@ -64,7 +64,7 @@ class CartItem::Reservation < CartItem::BaseItem plan = pending_subscription&.plan || customer&.subscribed_plan unless ReservationLimitService.authorized?(plan, customer, self, all_items) - errors.add(:reservation, I18n.t('cart_item_validation.limit_reached', { + errors.add(:reservation, I18n.t('cart_item_validation.limit_reached', **{ HOURS: ReservationLimitService.limit(plan, reservable).limit, RESERVABLE: reservable.name })) @@ -273,7 +273,7 @@ class CartItem::Reservation < CartItem::BaseItem end if slot.start_at < reservation_deadline_minutes.minutes.since && !operator.privileged? - errors.add(:slot, I18n.t('cart_item_validation.deadline', { MINUTES: reservation_deadline_minutes })) + errors.add(:slot, I18n.t('cart_item_validation.deadline', **{ MINUTES: reservation_deadline_minutes })) return false end diff --git a/app/models/cart_item/reservation_slot.rb b/app/models/cart_item/reservation_slot.rb index b1aa6a91d..147775334 100644 --- a/app/models/cart_item/reservation_slot.rb +++ b/app/models/cart_item/reservation_slot.rb @@ -1,20 +1,18 @@ # frozen_string_literal: true -require_relative 'cart_item' - # A relation table between a pending reservation and a slot class CartItem::ReservationSlot < ApplicationRecord self.table_name = 'cart_item_reservation_slots' belongs_to :cart_item, polymorphic: true - belongs_to :cart_item_machine_reservation, foreign_type: 'CartItem::MachineReservation', foreign_key: 'cart_item_id', - inverse_of: :cart_item_reservation_slots, class_name: 'CartItem::MachineReservation' - belongs_to :cart_item_space_reservation, foreign_type: 'CartItem::SpaceReservation', foreign_key: 'cart_item_id', - inverse_of: :cart_item_reservation_slots, class_name: 'CartItem::SpaceReservation' - belongs_to :cart_item_training_reservation, foreign_type: 'CartItem::TrainingReservation', foreign_key: 'cart_item_id', - inverse_of: :cart_item_reservation_slots, class_name: 'CartItem::TrainingReservation' - belongs_to :cart_item_event_reservation, foreign_type: 'CartItem::EventReservation', foreign_key: 'cart_item_id', - inverse_of: :cart_item_reservation_slots, class_name: 'CartItem::EventReservation' + belongs_to :cart_item_machine_reservation, foreign_key: 'cart_item_id', class_name: 'CartItem::MachineReservation', + inverse_of: :cart_item_reservation_slots + belongs_to :cart_item_space_reservation, foreign_key: 'cart_item_id', class_name: 'CartItem::SpaceReservation', + inverse_of: :cart_item_reservation_slots + belongs_to :cart_item_training_reservation, foreign_key: 'cart_item_id', class_name: 'CartItem::TrainingReservation', + inverse_of: :cart_item_reservation_slots + belongs_to :cart_item_event_reservation, foreign_key: 'cart_item_id', class_name: 'CartItem::EventReservation', + inverse_of: :cart_item_reservation_slots belongs_to :slot belongs_to :slots_reservation diff --git a/app/models/cart_item/space_reservation.rb b/app/models/cart_item/space_reservation.rb index aa513c3b8..138a4c17c 100644 --- a/app/models/cart_item/space_reservation.rb +++ b/app/models/cart_item/space_reservation.rb @@ -3,7 +3,7 @@ # A space reservation added to the shopping cart class CartItem::SpaceReservation < CartItem::Reservation has_many :cart_item_reservation_slots, class_name: 'CartItem::ReservationSlot', dependent: :destroy, inverse_of: :cart_item, - foreign_key: 'cart_item_id', foreign_type: 'cart_item_type' + foreign_type: 'cart_item_type', as: :cart_item accepts_nested_attributes_for :cart_item_reservation_slots belongs_to :operator_profile, class_name: 'InvoicingProfile' diff --git a/app/models/cart_item/subscription.rb b/app/models/cart_item/subscription.rb index 50b297e9e..845b8e024 100644 --- a/app/models/cart_item/subscription.rb +++ b/app/models/cart_item/subscription.rb @@ -38,7 +38,7 @@ class CartItem::Subscription < CartItem::BaseItem return false end if plan.group_id != customer.group_id - errors.add(:group, I18n.t('cart_item_validation.plan_group', { GROUP: plan.group.name })) + errors.add(:group, I18n.t('cart_item_validation.plan_group', **{ GROUP: plan.group.name })) return false end true diff --git a/app/models/cart_item/training_reservation.rb b/app/models/cart_item/training_reservation.rb index aff64b3a6..4dd19a2ef 100644 --- a/app/models/cart_item/training_reservation.rb +++ b/app/models/cart_item/training_reservation.rb @@ -3,7 +3,7 @@ # A training reservation added to the shopping cart class CartItem::TrainingReservation < CartItem::Reservation has_many :cart_item_reservation_slots, class_name: 'CartItem::ReservationSlot', dependent: :destroy, inverse_of: :cart_item, - foreign_key: 'cart_item_id', foreign_type: 'cart_item_type' + foreign_type: 'cart_item_type', as: :cart_item accepts_nested_attributes_for :cart_item_reservation_slots belongs_to :operator_profile, class_name: 'InvoicingProfile' diff --git a/app/models/chained_element.rb b/app/models/chained_element.rb new file mode 100644 index 000000000..44e76d689 --- /dev/null +++ b/app/models/chained_element.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +require 'integrity/checksum' +require 'json' + +# ChainedElement saves data about a securly footprinted chained element (like invoices) +class ChainedElement < ApplicationRecord + belongs_to :element, polymorphic: true + belongs_to :previous, class_name: 'ChainedElement' + has_one :next, class_name: 'ChainedElement', inverse_of: :previous, dependent: :restrict_with_exception + + before_create :set_content, :chain_record + + validates :element_id, :element_type, presence: true + + # @return [Boolean] + def corrupted? + comparable(FootprintService.chained_data(element, previous&.footprint, columns)) != comparable(content) || + footprint != Integrity::Checksum.text(comparable(content).to_json) + end + + # return ths list of columns in the saved JSON. This is used to do the comparison with the + # saved item, as it may have changed between (some columns may have been added) + # @return [Array] + def columns + %w[id].concat(content.keys.delete_if do |column| + %w[id previous].concat(element.class.columns_out_of_footprint).include?(column) + end.sort) + end + + private + + def set_content + self.content = FootprintService.chained_data(element, previous&.footprint) + end + + def chain_record + self.footprint = Integrity::Checksum.text(content.to_json) + end + + # @param item [Hash] + # @return [Hash] + def comparable(item) + item.sort.to_h.transform_values { |val| val.is_a?(Hash) ? val.sort.to_h : val } + end +end diff --git a/app/models/concerns/i_calendar_concern.rb b/app/models/concerns/i_calendar_concern.rb index aa0253853..1c10a2235 100644 --- a/app/models/concerns/i_calendar_concern.rb +++ b/app/models/concerns/i_calendar_concern.rb @@ -56,14 +56,14 @@ module ICalendarConcern def description(group_slots) case reservable_type when 'Machine', 'Space' - I18n.t('reservation_ics.description_slot', COUNT: group_slots.count, ITEM: reservable.name) + I18n.t('reservation_ics.description_slot', **{ COUNT: group_slots.count, ITEM: reservable.name }) when 'Training' - I18n.t('reservation_ics.description_training', TYPE: reservable.name) + I18n.t('reservation_ics.description_training', **{ TYPE: reservable.name }) when 'Event' - I18n.t('reservation_ics.description_event', NUMBER: nb_reserve_places + (tickets.map(&:booked).reduce(:+) || 0)) + I18n.t('reservation_ics.description_event', **{ NUMBER: nb_reserve_places + (tickets.map(&:booked).reduce(:+) || 0) }) else Rails.logger.warn "Unexpected reservable type #{reservable_type}" - I18n.t('reservation_ics.description_slot', COUNT: group_slots.count, ITEM: reservable_type) + I18n.t('reservation_ics.description_slot', **{ COUNT: group_slots.count, ITEM: reservable_type }) end end end diff --git a/app/models/concerns/single_sign_on_concern.rb b/app/models/concerns/single_sign_on_concern.rb index 1a78aa43d..a3804e332 100644 --- a/app/models/concerns/single_sign_on_concern.rb +++ b/app/models/concerns/single_sign_on_concern.rb @@ -7,8 +7,8 @@ module SingleSignOnConcern included do # enable OmniAuth authentication only if needed - devise :omniauthable, omniauth_providers: [AuthProvider.active.strategy_name.to_sym] unless - AuthProvider.active.providable_type == DatabaseProvider.name + devise :omniauthable, omniauth_providers: [Rails.configuration.auth_provider.strategy_name.to_sym] unless + Rails.configuration.auth_provider.providable_type == 'DatabaseProvider' ## Retrieve the requested data in the User and user's Profile tables ## @param sso_mapping {String} must be of form 'user._field_' or 'profile._field_'. Eg. 'user.email' @@ -39,7 +39,7 @@ module SingleSignOnConcern ## link the current user to the given provider (omniauth attributes hash) ## and remove the auth_token to mark his account as "migrated" def link_with_omniauth_provider(auth) - active_provider = AuthProvider.active + active_provider = Rails.configuration.auth_provider raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider if User.where(provider: auth.provider, uid: auth.uid).size.positive? @@ -104,7 +104,7 @@ module SingleSignOnConcern def from_omniauth(auth) logger = SsoLogger.new logger.debug "[User::from_omniauth] initiated with parameter #{auth}" - active_provider = AuthProvider.active + active_provider = Rails.configuration.auth_provider raise SecurityError, 'The identity provider does not match the activated one' if active_provider.strategy_name != auth.provider where(provider: auth.provider, uid: auth.uid).first_or_create.tap do |user| diff --git a/app/models/footprint_debug.rb b/app/models/footprint_debug.rb deleted file mode 100644 index 70d02aa4d..000000000 --- a/app/models/footprint_debug.rb +++ /dev/null @@ -1,33 +0,0 @@ -# frozen_string_literal: true - -# When a footprint is generated, the associated data is kept to allow further verifications -class FootprintDebug < ApplicationRecord - # We try to rebuild the data, column by column, from the db object - # If any datum oes not match, we print it as ERROR - def format_data(item_id) - item = klass.constantize.find(item_id) - columns = FootprintService.footprint_columns(klass.constantize) - - result = [] - index = 0 - columns.each do |column| - col_data = item[column] - end_idx = index + col_data.to_s.length - 1 - - if data[index..end_idx] == col_data.to_s - # if the item data for the current column matches, save it into the results and move forward teh cursor - result.push(col_data.to_s) - index = end_idx + 1 - else - # if the item data for the current column does not matches, mark it as an error, display the next chars, but do not move the cursor - datum = data[index..end_idx] - datum = data[index..index + 5] if datum&.empty? - result.push "ERROR (#{datum}...)" - end - end - # the remaining data is the previous record checksum - result.push(data[index..-1]) - - result - end -end diff --git a/app/models/footprintable.rb b/app/models/footprintable.rb index e5b09a3be..18f17d1e5 100644 --- a/app/models/footprintable.rb +++ b/app/models/footprintable.rb @@ -17,24 +17,29 @@ class Footprintable < ApplicationRecord end def check_footprint - footprint_children.map(&:check_footprint).all? && footprint == compute_footprint + return false unless persisted? + + reload + footprint_children.map(&:check_footprint).all? && !chained_element.corrupted? end + # @return [ChainedElement] def chain_record - self.footprint = compute_footprint - save! - FootprintDebug.create!( - footprint: footprint, - data: FootprintService.footprint_data(self.class, self), - klass: self.class.name + ChainedElement.create!( + element: self, + previous: previous_record&.chained_element ) end + # @return [Footprintable,NilClass] + def previous_record + self.class.where("#{sort_on_field} < ?", self[sort_on_field]) + .order("#{sort_on_field} DESC") + .limit(1) + .first + end + def debug_footprint FootprintService.debug_footprint(self.class, self) end - - def compute_footprint - FootprintService.compute_footprint(self.class, self) - end end diff --git a/app/models/history_value.rb b/app/models/history_value.rb index ca957e603..39bd30e9f 100644 --- a/app/models/history_value.rb +++ b/app/models/history_value.rb @@ -5,6 +5,8 @@ class HistoryValue < Footprintable belongs_to :setting belongs_to :invoicing_profile + has_one :chained_element, as: :element, dependent: :restrict_with_exception + delegate :footprint, to: :chained_element delegate :user, to: :invoicing_profile after_create :chain_record diff --git a/app/models/import.rb b/app/models/import.rb index a0cf83923..0cfb0a425 100644 --- a/app/models/import.rb +++ b/app/models/import.rb @@ -14,7 +14,7 @@ class Import < ApplicationRecord after_commit :proceed_import, on: [:create] def results_hash - YAML.safe_load(results, [Symbol]) if results + YAML.safe_load(results, permitted_classes: [Symbol]) if results end private diff --git a/app/models/invoice.rb b/app/models/invoice.rb index 75e7ad3f8..2365559d8 100644 --- a/app/models/invoice.rb +++ b/app/models/invoice.rb @@ -13,7 +13,8 @@ class Invoice < PaymentDocument belongs_to :wallet_transaction belongs_to :coupon - has_one :avoir, class_name: 'Invoice', dependent: :destroy, inverse_of: :avoir + has_one :chained_element, as: :element, dependent: :restrict_with_exception + has_one :avoir, class_name: 'Avoir', dependent: :destroy, inverse_of: :invoice has_one :payment_schedule_item, dependent: :restrict_with_error has_one :payment_gateway_object, as: :item, dependent: :destroy has_one :order, dependent: :restrict_with_error @@ -22,9 +23,10 @@ class Invoice < PaymentDocument has_many :accounting_lines, dependent: :destroy delegate :user, to: :invoicing_profile + delegate :footprint, to: :chained_element before_create :add_environment - after_create :update_reference, :chain_record + after_create :generate_order_number, :update_reference, :chain_record after_update :log_changes after_commit :generate_and_send_invoice, on: [:create], if: :persisted? @@ -49,17 +51,20 @@ class Invoice < PaymentDocument "#{prefix}-#{id}_#{created_at.strftime('%d%m%Y')}.pdf" end - def order_number - return order.reference unless order.nil? || order.reference.nil? + def generate_order_number + self.order_number = order.reference and return unless order.nil? || order.reference.nil? - return payment_schedule_item.payment_schedule.order_number if !payment_schedule_item.nil? && !payment_schedule_item.first? + if !payment_schedule_item.nil? && !payment_schedule_item.first? + self.order_number = payment_schedule_item.payment_schedule.order_number + return + end - PaymentDocumentService.generate_order_number(self) + super end # for debug & used by rake task "fablab:maintenance:regenerate_invoices" def regenerate_invoice_pdf - pdf = ::PDF::Invoice.new(self).render + pdf = ::Pdf::Invoice.new(self).render File.binwrite(file, pdf) end @@ -186,7 +191,7 @@ class Invoice < PaymentDocument end def paid_by_card? - !payment_gateway_object.nil? && payment_method == 'card' + payment_method == 'card' end def paid_by_wallet? diff --git a/app/models/invoice_item.rb b/app/models/invoice_item.rb index 526f0e3be..1cb37f6e2 100644 --- a/app/models/invoice_item.rb +++ b/app/models/invoice_item.rb @@ -7,11 +7,14 @@ class InvoiceItem < Footprintable has_one :invoice_item, dependent: :destroy # associates invoice_items of an invoice to invoice_items of an Avoir has_one :payment_gateway_object, as: :item, dependent: :destroy + has_one :chained_element, as: :element, dependent: :restrict_with_exception belongs_to :object, polymorphic: true after_create :chain_record after_update :log_changes + delegate :footprint, to: :chained_element + def amount_after_coupon # deduct coupon discount coupon_service = CouponService.new diff --git a/app/models/machine.rb b/app/models/machine.rb index a3f81cfa1..029ebfdfe 100644 --- a/app/models/machine.rb +++ b/app/models/machine.rb @@ -38,11 +38,11 @@ class Machine < ApplicationRecord accepts_nested_attributes_for :advanced_accounting, allow_destroy: true has_many :cart_item_machine_reservations, class_name: 'CartItem::MachineReservation', dependent: :destroy, inverse_of: :reservable, - foreign_type: 'reservable_type', foreign_key: 'reservable_id' + foreign_type: 'reservable_type', as: :reservable belongs_to :machine_category - has_many :plan_limitations, dependent: :destroy, inverse_of: :machine, foreign_type: 'limitable_type', foreign_key: 'limitable_id' + has_many :plan_limitations, dependent: :destroy, inverse_of: :machine, foreign_type: 'limitable_type', as: :limitable after_create :create_statistic_subtype after_create :create_machine_prices diff --git a/app/models/machine_category.rb b/app/models/machine_category.rb index 47c670640..9913844aa 100644 --- a/app/models/machine_category.rb +++ b/app/models/machine_category.rb @@ -4,5 +4,5 @@ class MachineCategory < ApplicationRecord has_many :machines, dependent: :nullify accepts_nested_attributes_for :machines, allow_destroy: true - has_many :plan_limitations, dependent: :destroy, inverse_of: :machine_category, foreign_type: 'limitable_type', foreign_key: 'limitable_id' + has_many :plan_limitations, dependent: :destroy, inverse_of: :machine_category, foreign_type: 'limitable_type', as: :limitable end diff --git a/app/models/open_id_connect_provider.rb b/app/models/open_id_connect_provider.rb index e91095edc..26989cc32 100644 --- a/app/models/open_id_connect_provider.rb +++ b/app/models/open_id_connect_provider.rb @@ -16,20 +16,4 @@ class OpenIdConnectProvider < ApplicationRecord validates :display, inclusion: { in: %w[page popup touch wap], allow_nil: true } validates :prompt, inclusion: { in: %w[none login consent select_account], allow_nil: true } validates :client_auth_method, inclusion: { in: %w[basic jwks] } - - def scope - self[:scope]&.join(' ') - end - - def config - OpenIdConnectProvider.columns.map(&:name).filter { |n| !n.start_with?('client__') && n != 'profile_url' }.map do |n| - [n, send(n)] - end.push(['client_options', client_config]).to_h - end - - def client_config - OpenIdConnectProvider.columns.map(&:name).filter { |n| n.start_with?('client__') }.to_h do |n| - [n.sub('client__', ''), send(n)] - end - end end diff --git a/app/models/order_item.rb b/app/models/order_item.rb index 6948bcbec..6609dccf1 100644 --- a/app/models/order_item.rb +++ b/app/models/order_item.rb @@ -4,7 +4,7 @@ class OrderItem < ApplicationRecord belongs_to :order belongs_to :orderable, polymorphic: true - belongs_to :product, foreign_type: 'Product', foreign_key: 'orderable_id', inverse_of: :order_items + belongs_to :product, foreign_key: 'orderable_id', inverse_of: :order_items validates :orderable, :order_id, :amount, presence: true end diff --git a/app/models/payment_document.rb b/app/models/payment_document.rb index 56016867e..683b7d535 100644 --- a/app/models/payment_document.rb +++ b/app/models/payment_document.rb @@ -8,8 +8,12 @@ class PaymentDocument < Footprintable self.reference = PaymentDocumentService.generate_reference(self, date: date) end + def generate_order_number + self.order_number = PaymentDocumentService.generate_order_number(self) + end + def update_reference - generate_reference + generate_reference if reference.blank? save end diff --git a/app/models/payment_gateway_object.rb b/app/models/payment_gateway_object.rb index 24862f031..cc9b812b1 100644 --- a/app/models/payment_gateway_object.rb +++ b/app/models/payment_gateway_object.rb @@ -5,17 +5,17 @@ require 'payment/item_builder' # A link between an object in the local database and another object in the remote payment gateway database class PaymentGatewayObject < ApplicationRecord belongs_to :item, polymorphic: true - belongs_to :invoice, foreign_type: 'Invoice', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :invoice_item, foreign_type: 'InvoiceItem', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :payment_schedule, foreign_type: 'PaymentSchedule', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :payment_schedule_item, foreign_type: 'PaymentScheduleItem', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :user, foreign_type: 'User', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :plan, foreign_type: 'Plan', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :machine, foreign_type: 'Machine', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :space, foreign_type: 'Space', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :training, foreign_type: 'Training', foreign_key: 'item_id', inverse_of: :payment_gateway_object - belongs_to :order, foreign_type: 'Order', foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :invoice, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :invoice_item, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :subscription, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :payment_schedule, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :payment_schedule_item, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :user, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :plan, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :machine, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :space, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :training, foreign_key: 'item_id', inverse_of: :payment_gateway_object + belongs_to :order, foreign_key: 'item_id', inverse_of: :payment_gateway_object belongs_to :payment_gateway_object # some objects may require a reference to another object for remote recovery diff --git a/app/models/payment_schedule.rb b/app/models/payment_schedule.rb index b6096fa80..54083962f 100644 --- a/app/models/payment_schedule.rb +++ b/app/models/payment_schedule.rb @@ -11,15 +11,18 @@ class PaymentSchedule < PaymentDocument belongs_to :statistic_profile belongs_to :operator_profile, class_name: 'InvoicingProfile' + has_one :chained_element, as: :element, dependent: :restrict_with_exception has_many :payment_schedule_items, dependent: :destroy has_many :payment_gateway_objects, as: :item, dependent: :destroy has_many :payment_schedule_objects, dependent: :destroy before_create :add_environment - after_create :update_reference, :chain_record + after_create :generate_order_number, :update_reference, :chain_record after_commit :generate_and_send_document, on: [:create], if: :persisted? after_commit :generate_initial_invoice, on: [:create], if: :persisted? + delegate :footprint, to: :chained_element + def file dir = "payment_schedules/#{invoicing_profile.id}" @@ -38,10 +41,6 @@ class PaymentSchedule < PaymentDocument "#{prefix}-#{id}_#{created_at.strftime('%d%m%Y')}.pdf" end - def order_number - ordered_items.first&.invoice&.order_number || PaymentDocumentService.generate_order_number(self) - end - ## # This is useful to check the first item because its amount may be different from the others ## @@ -69,7 +68,7 @@ class PaymentSchedule < PaymentDocument # for debug & used by rake task "fablab:maintenance:regenerate_schedules" def regenerate_pdf - pdf = ::PDF::PaymentSchedule.new(self).render + pdf = ::Pdf::PaymentSchedule.new(self).render File.binwrite(file, pdf) end diff --git a/app/models/payment_schedule_item.rb b/app/models/payment_schedule_item.rb index cbf1bc256..a8f921212 100644 --- a/app/models/payment_schedule_item.rb +++ b/app/models/payment_schedule_item.rb @@ -5,9 +5,12 @@ class PaymentScheduleItem < Footprintable belongs_to :payment_schedule belongs_to :invoice has_one :payment_gateway_object, as: :item, dependent: :destroy + has_one :chained_element, as: :element, dependent: :restrict_with_exception after_create :chain_record + delegate :footprint, to: :chained_element + def first? payment_schedule.ordered_items.first == self end diff --git a/app/models/payment_schedule_object.rb b/app/models/payment_schedule_object.rb index 9036897b1..d2fe1127a 100644 --- a/app/models/payment_schedule_object.rb +++ b/app/models/payment_schedule_object.rb @@ -3,11 +3,13 @@ # Links an object bought and a payment schedule used to pay this object class PaymentScheduleObject < Footprintable belongs_to :object, polymorphic: true - belongs_to :reservation, foreign_type: 'Reservation', foreign_key: 'object_id', inverse_of: :payment_schedule_object - belongs_to :subscription, foreign_type: 'Subscription', foreign_key: 'object_id', inverse_of: :payment_schedule_object - belongs_to :statistic_profile_prepaid_pack, foreign_type: 'StatisticProfilePrepaidPack', foreign_key: 'object_id', - inverse_of: :payment_schedule_object + belongs_to :reservation, foreign_key: 'object_id', inverse_of: :payment_schedule_object + belongs_to :subscription, foreign_key: 'object_id', inverse_of: :payment_schedule_object + belongs_to :statistic_profile_prepaid_pack, foreign_key: 'object_id', inverse_of: :payment_schedule_object belongs_to :payment_schedule + has_one :chained_element, as: :element, dependent: :restrict_with_exception after_create :chain_record + + delegate :footprint, to: :chained_element end diff --git a/app/models/plan.rb b/app/models/plan.rb index 0a508f8e2..a2aa4df3f 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -90,7 +90,7 @@ class Plan < ApplicationRecord def human_readable_duration i18n_key = "duration.#{interval}" - I18n.t(i18n_key, count: interval_count).to_s + I18n.t(i18n_key, **{ count: interval_count }).to_s end def human_readable_name(opts = {}) diff --git a/app/models/plan_limitation.rb b/app/models/plan_limitation.rb index 9bdabecbf..ae30ee215 100644 --- a/app/models/plan_limitation.rb +++ b/app/models/plan_limitation.rb @@ -5,8 +5,8 @@ class PlanLimitation < ApplicationRecord belongs_to :plan belongs_to :limitable, polymorphic: true - belongs_to :machine, foreign_type: 'Machine', foreign_key: 'limitable_id', inverse_of: :plan_limitations - belongs_to :machine_category, foreign_type: 'MachineCategory', foreign_key: 'limitable_id', inverse_of: :plan_limitations + belongs_to :machine, foreign_key: 'limitable_id', inverse_of: :plan_limitations + belongs_to :machine_category, foreign_key: 'limitable_id', inverse_of: :plan_limitations validates :limitable_id, :limitable_type, :limit, :plan_id, presence: true validates :limitable_id, uniqueness: { scope: %i[limitable_type plan_id] } diff --git a/app/models/prepaid_pack.rb b/app/models/prepaid_pack.rb index 16d752b36..88bf2d4e0 100644 --- a/app/models/prepaid_pack.rb +++ b/app/models/prepaid_pack.rb @@ -8,8 +8,8 @@ # The number of hours in a pack is stored in minutes. class PrepaidPack < ApplicationRecord belongs_to :priceable, polymorphic: true - belongs_to :machine, foreign_type: 'Machine', foreign_key: 'priceable_id', inverse_of: :prepaid_packs - belongs_to :space, foreign_type: 'Space', foreign_key: 'priceable_id', inverse_of: :prepaid_packs + belongs_to :machine, foreign_key: 'priceable_id', inverse_of: :prepaid_packs + belongs_to :space, foreign_key: 'priceable_id', inverse_of: :prepaid_packs belongs_to :group diff --git a/app/models/space.rb b/app/models/space.rb index 399b99d30..765eef8a0 100644 --- a/app/models/space.rb +++ b/app/models/space.rb @@ -32,7 +32,7 @@ class Space < ApplicationRecord accepts_nested_attributes_for :advanced_accounting, allow_destroy: true has_many :cart_item_space_reservations, class_name: 'CartItem::SpaceReservation', dependent: :destroy, inverse_of: :reservable, - foreign_type: 'reservable_type', foreign_key: 'reservable_id' + foreign_type: 'reservable_type', as: :reservable after_create :create_statistic_subtype after_create :create_space_prices diff --git a/app/models/training.rb b/app/models/training.rb index af34840c3..315e633db 100644 --- a/app/models/training.rb +++ b/app/models/training.rb @@ -33,7 +33,7 @@ class Training < ApplicationRecord accepts_nested_attributes_for :advanced_accounting, allow_destroy: true has_many :cart_item_training_reservations, class_name: 'CartItem::TrainingReservation', dependent: :destroy, inverse_of: :reservable, - foreign_type: 'reservable_type', foreign_key: 'reservable_id' + foreign_type: 'reservable_type', as: :reservable after_create :create_statistic_subtype after_create :create_trainings_pricings diff --git a/app/models/user.rb b/app/models/user.rb index 5f114ae6b..8568a444a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -176,15 +176,6 @@ class User < ApplicationRecord add_role(:member) if roles.blank? end - def cached_has_role?(role) - roles = Rails.cache.fetch( - roles_for: { object_id: object_id }, - expires_in: 1.day, - race_condition_ttl: 2.seconds - ) { roles.map(&:name) } - roles.include?(role.to_s) - end - def cgu_must_accept errors.add(:cgu, I18n.t('activerecord.errors.messages.empty')) if cgu == '0' end diff --git a/app/pdfs/pdf/invoice.rb b/app/pdfs/pdf/invoice.rb index 493346fdd..c7559eb78 100644 --- a/app/pdfs/pdf/invoice.rb +++ b/app/pdfs/pdf/invoice.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Generate a downloadable PDF file for the recorded invoice -class PDF::Invoice < Prawn::Document +class Pdf::Invoice < Prawn::Document require 'stringio' include ActionView::Helpers::NumberHelper include ApplicationHelper @@ -33,24 +33,18 @@ class PDF::Invoice < Prawn::Document Rails.logger.error "Unable to decode invoice logo from base64: #{e}" end move_down 20 - # the following line is a special comment to workaround RubyMine inspection problem - # noinspection RubyScope font('Open-Sans', size: 10) do # general information - if invoice.is_a?(Avoir) - text I18n.t('invoices.refund_invoice_reference', REF: invoice.reference), leading: 3 - else - text I18n.t('invoices.invoice_reference', REF: invoice.reference), leading: 3 - end - text I18n.t('invoices.code', CODE: Setting.get('invoice_code-value')), leading: 3 if Setting.get('invoice_code-active') + text I18n.t(invoice.is_a?(Avoir) ? 'invoices.refund_invoice_reference' : 'invoices.invoice_reference', + **{ REF: invoice.reference }), leading: 3 + text I18n.t('invoices.code', **{ CODE: Setting.get('invoice_code-value') }), leading: 3 if Setting.get('invoice_code-active') if invoice.main_item&.object_type != WalletTransaction.name - order_number = invoice.main_item&.object_type == OrderItem.name ? invoice.main_item&.object&.order&.reference : invoice.order_number - text I18n.t('invoices.order_number', NUMBER: order_number), leading: 3 + text I18n.t('invoices.order_number', **{ NUMBER: invoice.order_number }), leading: 3 end if invoice.is_a?(Avoir) - text I18n.t('invoices.refund_invoice_issued_on_DATE', DATE: I18n.l(invoice.avoir_date.to_date)) + text I18n.t('invoices.refund_invoice_issued_on_DATE', **{ DATE: I18n.l(invoice.avoir_date.to_date) }) else - text I18n.t('invoices.invoice_issued_on_DATE', DATE: I18n.l(invoice.created_at.to_date)) + text I18n.t('invoices.invoice_issued_on_DATE', **{ DATE: I18n.l(invoice.created_at.to_date) }) end # user/organization's information @@ -120,9 +114,9 @@ class PDF::Invoice < Prawn::Document data += [[I18n.t('invoices.total_including_all_taxes'), number_to_currency(total)]] vat_rate_group.each do |_type, rate| data += [[I18n.t('invoices.including_VAT_RATE', - RATE: rate[:vat_rate], - AMOUNT: number_to_currency(rate[:amount] / 100.00), - NAME: Setting.get('invoice_VAT-name')), + **{ RATE: rate[:vat_rate], + AMOUNT: number_to_currency(rate[:amount] / 100.00), + NAME: Setting.get('invoice_VAT-name') }), number_to_currency(rate[:total_vat] / 100.00)]] end data += [[I18n.t('invoices.including_total_excluding_taxes'), number_to_currency(total_ht / 100.00)]] diff --git a/app/pdfs/pdf/payment_schedule.rb b/app/pdfs/pdf/payment_schedule.rb index 3157da62f..a959e3af8 100644 --- a/app/pdfs/pdf/payment_schedule.rb +++ b/app/pdfs/pdf/payment_schedule.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Generate a downloadable PDF file for the recorded payment schedule -class PDF::PaymentSchedule < Prawn::Document +class Pdf::PaymentSchedule < Prawn::Document require 'stringio' include ActionView::Helpers::NumberHelper include ApplicationHelper @@ -37,8 +37,8 @@ class PDF::PaymentSchedule < Prawn::Document move_down 20 font('Open-Sans', size: 10) do # general information - text I18n.t('payment_schedules.schedule_reference', REF: payment_schedule.reference), leading: 3 - text I18n.t('payment_schedules.schedule_issued_on_DATE', DATE: I18n.l(payment_schedule.created_at.to_date)) + text I18n.t('payment_schedules.schedule_reference', **{ REF: payment_schedule.reference }), leading: 3 + text I18n.t('payment_schedules.schedule_issued_on_DATE', **{ DATE: I18n.l(payment_schedule.created_at.to_date) }) # user/organization's information if payment_schedule.invoicing_profile&.organization @@ -67,7 +67,7 @@ class PDF::PaymentSchedule < Prawn::Document # object move_down 25 - text I18n.t('payment_schedules.object', ITEM: subscription_verbose(subscription, name)) + text I18n.t('payment_schedules.object', **{ ITEM: subscription_verbose(subscription, name) }) # details table of the deadlines move_down 20 @@ -77,7 +77,6 @@ class PDF::PaymentSchedule < Prawn::Document # going through the payment_schedule_items payment_schedule.payment_schedule_items.each do |item| - price = item.amount.to_i / 100.00 date = I18n.l(item.due_date.to_date) @@ -101,7 +100,7 @@ class PDF::PaymentSchedule < Prawn::Document payment_verbose = _t('payment_schedules.settlement_by_METHOD', METHOD: payment_schedule.payment_method) if payment_schedule.wallet_amount payment_verbose += I18n.t('payment_schedules.settlement_by_wallet', - AMOUNT: number_to_currency(payment_schedule.wallet_amount / 100.00)) + **{ AMOUNT: number_to_currency(payment_schedule.wallet_amount / 100.00) }) end text payment_verbose @@ -112,7 +111,6 @@ class PDF::PaymentSchedule < Prawn::Document text line, style: :bold, inline_format: true end - # address and legals information move_down 40 txt = parse_html(Setting.get('invoice_legals')) @@ -126,7 +124,7 @@ class PDF::PaymentSchedule < Prawn::Document transparent(0.1) do rotate(45, origin: [0, 0]) do - image "#{Rails.root}/app/pdfs/data/watermark-#{I18n.default_locale}.png", at: [90, 150] + image Rails.root.join("app/pdfs/data/watermark-#{I18n.default_locale}.png"), at: [90, 150] end end end @@ -137,9 +135,9 @@ class PDF::PaymentSchedule < Prawn::Document subscription_start_at = subscription.expired_at - subscription.plan.duration duration_verbose = I18n.t("duration.#{subscription.plan.interval}", count: subscription.plan.interval_count) I18n.t('payment_schedules.subscription_of_NAME_for_DURATION_starting_from_DATE', - NAME: username, - DURATION: duration_verbose, - DATE: I18n.l(subscription_start_at.to_date)) + **{ NAME: username, + DURATION: duration_verbose, + DATE: I18n.l(subscription_start_at.to_date) }) end ## diff --git a/app/services/accounting/vat_export_service.rb b/app/services/accounting/vat_export_service.rb index 932f99733..43abfa281 100644 --- a/app/services/accounting/vat_export_service.rb +++ b/app/services/accounting/vat_export_service.rb @@ -43,7 +43,7 @@ class Accounting::VatExportService def header_row row = '' columns.each do |column| - row << I18n.t("vat_export.#{column}", NAME: @vat_name) << separator + row << I18n.t("vat_export.#{column}", **{ NAME: @vat_name }) << separator end "#{row}\n" end diff --git a/app/services/availabilities_export_service.rb b/app/services/availabilities_export_service.rb index 699ce2cb0..90ea3477b 100644 --- a/app/services/availabilities_export_service.rb +++ b/app/services/availabilities_export_service.rb @@ -10,23 +10,17 @@ require './app/helpers/application_helper' # Retrieve all availabilities and their related objects and write the result as a table in an excel file class AvailabilitiesExportService - # export all availabilities def export_index(export) @availabilities = Availability.all.includes(:machines, :trainings, :spaces, :event, :slots) - ActionController::Base.prepend_view_path './app/views/' - # place data in view_assigns - view_assigns = { availabilities: @availabilities } - av = ActionView::Base.new(ActionController::Base.view_paths, view_assigns) - av.class_eval do - # include any needed helpers (for the view) - include ApplicationHelper - end - - content = av.render template: 'exports/availabilities_index.xlsx.axlsx' + content = ApplicationController.render( + template: 'exports/availabilities_index', + locals: { availabilities: @availabilities }, + handlers: [:axlsx], + formats: [:xlsx] + ) # write content to file - File.open(export.file, 'w+b') { |f| f.write content } + File.binwrite(export.file, content) end - end diff --git a/app/services/event/update_event_service.rb b/app/services/event/update_event_service.rb index cbd3c749e..2eb42d67a 100644 --- a/app/services/event/update_event_service.rb +++ b/app/services/event/update_event_service.rb @@ -120,7 +120,7 @@ class Event::UpdateEventService def file_attributes(base_event, occurrence, event_params) ef_attributes = [] - event_params['event_files_attributes']&.each do |efa| + event_params['event_files_attributes']&.values&.each do |efa| if efa['id'].present? event_file = base_event.event_files.find(efa['id']) ef = occurrence.event_files.find_by(attachment: event_file.attachment.file.filename) diff --git a/app/services/footprint_service.rb b/app/services/footprint_service.rb index 16425494f..5c51ef3f3 100644 --- a/app/services/footprint_service.rb +++ b/app/services/footprint_service.rb @@ -1,77 +1,63 @@ # frozen_string_literal: true require 'integrity/checksum' +require 'json' # Provides helper methods to compute footprints class FootprintService class << self - # Compute the footprint - # @param klass {Class} a class inheriting from Footprintable - # @param item {Footprintable} an instance of the provided class - def compute_footprint(klass, item) - Integrity::Checksum.text(FootprintService.footprint_data(klass, item)) - end + # @param item [Footprintable] + # @param previous_footprint [String,NilClass] + # @param columns [Array] + # @return [HashString,Integer,Hash>] + def chained_data(item, previous_footprint = nil, columns = nil) + columns ||= footprint_columns(item.class) + res = {} + columns.each do |column| + next if column.blank? || item[column].blank? - # Return the original data string used to compute the footprint - # @param klass {Class} a class inheriting from Footprintable - # @param item {Footprintable} an instance of the provided class - # @param array {Boolean} if true, the result is return on the form of an array, otherwise a concatenated string is returned - def footprint_data(klass, item, array: false) - raise TypeError unless item.is_a? klass - - sort_on = item.sort_on_field - previous = klass.where("#{sort_on} < ?", item[sort_on]) - .order("#{sort_on} DESC") - .limit(1) - - columns = FootprintService.footprint_columns(klass) - columns = columns.map do |c| - comparable(item[c]) + res[column] = comparable(item[column]) rescue ActiveModel::MissingAttributeError - nil + res[column] = nil end - - res = columns.push(previous.first ? previous.first.footprint : '') - array ? res.map(&:to_s) : res.join.to_s + res['previous'] = previous_footprint + res.sort.to_h end # Return an ordered array of the columns used in the footprint computation - # @param klass {Class} a class inheriting from Footprintable + # @param klass [Class] a class inheriting from Footprintable def footprint_columns(klass) - %w[id].concat(klass.columns.map(&:name).delete_if { |c| %w[id footprint updated_at].concat(klass.columns_out_of_footprint).include? c }.sort) + %w[id].concat(klass.columns.map(&:name).delete_if do |column| + %w[id footprint updated_at].concat(klass.columns_out_of_footprint).include?(column) + end.sort) end # Logs a debugging message to help finding why a footprint is invalid - # @param klass {Class} a class inheriting from Footprintable - # @param item {Footprintable} an instance of the provided class + # @param klass [Class] a class inheriting from Footprintable + # @param item [Footprintable] an instance of the provided class def debug_footprint(klass, item) - columns = FootprintService.footprint_columns(klass) - current = FootprintService.footprint_data(klass, item, array: true) - saved = FootprintDebug.find_by(footprint: item.footprint, klass: klass.name) - return saved if Rails.env.test? + current = chained_data(item, item.chained_element.previous&.footprint, item.chained_element.columns) + saved = item.chained_element&.content&.sort&.to_h&.transform_values { |val| val.is_a?(Hash) ? val.sort.to_h : val } if saved.nil? - Rails.logger.debug { "Debug data not found for #{klass} [ id: #{item.id} ]" } + " #{klass} [ id: #{item.id} ] is not chained" else - Rails.logger.debug do - "Debug footprint for #{klass} [ id: #{item.id} ]\n" \ - "-----------------------------------------\ncolumns: [ #{columns.join(', ')} ]\n" \ - "current: #{current}\n saved: #{saved.format_data(item.id)}\n" \ - '-----------------------------------------' - end - item.footprint_children.map(&:debug_footprint) + "Debug footprint for #{klass} [ id: #{item.id} ]\n" \ + "-----------------------------------------\n" \ + "=== current ===\n#{JSON.pretty_generate(current)}\n\n=== saved ===\n#{JSON.pretty_generate(saved)}\n" \ + "-----------------------------------------\n" + + item.footprint_children.map(&:debug_footprint).join("\n\n") end - others = FootprintDebug.where('klass = ? AND data LIKE ? AND id != ?', klass, "#{item.id}%", saved&.id) - Rails.logger.debug { "other possible matches IDs: #{others.map(&:id)}\n-----------------------------------------" } end private # Return a comparable value for jsonb fields (with keys ordered alphabetically) def comparable(value) + return value.iso8601 if value.is_a? Time return value unless value.is_a? Hash - value.sort.to_h + value.sort.to_h.transform_values! { |v| comparable(v) } end end end diff --git a/app/services/invoices/item_label_service.rb b/app/services/invoices/item_label_service.rb index ce83dc4ed..daf5f7d1b 100644 --- a/app/services/invoices/item_label_service.rb +++ b/app/services/invoices/item_label_service.rb @@ -30,23 +30,23 @@ class Invoices::ItemLabelService subscription = item.object label = if invoice.main_item&.object_type == 'OfferDay' I18n.t('invoices.subscription_extended_for_free_from_START_to_END', - START: I18n.l(invoice.main_item&.object&.start_at&.to_date), - END: I18n.l(invoice.main_item&.object&.end_at&.to_date)) + **{ START: I18n.l(invoice.main_item&.object&.start_at&.to_date), + END: I18n.l(invoice.main_item&.object&.end_at&.to_date) }) else subscription_end_at = subscription.expiration_date subscription_start_at = subscription_end_at - subscription.plan.duration I18n.t('invoices.subscription_NAME_from_START_to_END', - NAME: item.description, - START: I18n.l(subscription_start_at.to_date), - END: I18n.l(subscription_end_at.to_date)) + **{ NAME: item.description, + START: I18n.l(subscription_start_at.to_date), + END: I18n.l(subscription_end_at.to_date) }) end unless invoice.payment_schedule_item.nil? dues = invoice.payment_schedule_item.payment_schedule.payment_schedule_items.order(:due_date) label += "\n #{I18n.t('invoices.from_payment_schedule', - NUMBER: dues.index(invoice.payment_schedule_item) + 1, - TOTAL: dues.count, - DATE: I18n.l(invoice.payment_schedule_item.due_date.to_date), - SCHEDULE: invoice.payment_schedule_item.payment_schedule.reference)}" + **{ NUMBER: dues.index(invoice.payment_schedule_item) + 1, + TOTAL: dues.count, + DATE: I18n.l(invoice.payment_schedule_item.due_date.to_date), + SCHEDULE: invoice.payment_schedule_item.payment_schedule.reference })}" end label end @@ -58,12 +58,12 @@ class Invoices::ItemLabelService case invoice.main_item&.object.try(:reservable_type) ### Machine reservation when 'Machine' - I18n.t('invoices.machine_reservation_DESCRIPTION', DESCRIPTION: item.description) + I18n.t('invoices.machine_reservation_DESCRIPTION', **{ DESCRIPTION: item.description }) when 'Space' - I18n.t('invoices.space_reservation_DESCRIPTION', DESCRIPTION: item.description) + I18n.t('invoices.space_reservation_DESCRIPTION', **{ DESCRIPTION: item.description }) ### Training reservation when 'Training' - I18n.t('invoices.training_reservation_DESCRIPTION', DESCRIPTION: item.description) + I18n.t('invoices.training_reservation_DESCRIPTION', **{ DESCRIPTION: item.description }) ### events reservation when 'Event' build_event_reservation_label(invoice, item) @@ -76,15 +76,15 @@ class Invoices::ItemLabelService # @param item [InvoiceItem] # @return [String] def build_event_reservation_label(invoice, item) - label = I18n.t('invoices.event_reservation_DESCRIPTION', DESCRIPTION: item.description) + label = I18n.t('invoices.event_reservation_DESCRIPTION', **{ DESCRIPTION: item.description }) # details of the number of tickets if invoice.main_item&.object&.nb_reserve_places&.positive? - label += "\n #{I18n.t('invoices.full_price_ticket', count: invoice.main_item&.object&.nb_reserve_places)}" + label += "\n #{I18n.t('invoices.full_price_ticket', **{ count: invoice.main_item&.object&.nb_reserve_places })}" end invoice.main_item&.object&.tickets&.each do |t| label += "\n #{I18n.t('invoices.other_rate_ticket', - count: t.booked, - NAME: t.event_price_category.price_category.name)}" + **{ count: t.booked, + NAME: t.event_price_category.price_category.name })}" end label end diff --git a/app/services/invoices/label_service.rb b/app/services/invoices/label_service.rb index b5a7ab01a..f9cd05268 100644 --- a/app/services/invoices/label_service.rb +++ b/app/services/invoices/label_service.rb @@ -21,7 +21,7 @@ class Invoices::LabelService when 'OfferDay' offer_day_label(invoice.main_item.object, username) when 'Error' - I18n.t('invoices.error_invoice') + invoice.main_item&.object_id&.zero? ? I18n.t('invoices.error_invoice') : invoice.main_item&.description when 'StatisticProfilePrepaidPack' I18n.t('invoices.prepaid_pack') when 'OrderItem' @@ -40,7 +40,7 @@ class Invoices::LabelService def avoir_label(invoice) return I18n.t('invoices.wallet_credit') if invoice.main_item&.object_type == WalletTransaction.name - I18n.t('invoices.cancellation_of_invoice_REF', REF: invoice.invoice.reference) + I18n.t('invoices.cancellation_of_invoice_REF', **{ REF: invoice.invoice.reference }) end # @param invoice [Invoice] @@ -48,9 +48,9 @@ class Invoices::LabelService # @return [String] def reservation_invoice_label(invoice, username) label = I18n.t('invoices.reservation_of_USER_on_DATE_at_TIME', - USER: username, - 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)) + **{ USER: username, + 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.object_type == Subscription.name @@ -67,11 +67,11 @@ class Invoices::LabelService # @return [String] def subscription_label(subscription, username) subscription_start_at = subscription.expired_at - subscription.plan.duration - duration_verbose = I18n.t("duration.#{subscription.plan.interval}", count: subscription.plan.interval_count) + duration_verbose = I18n.t("duration.#{subscription.plan.interval}", **{ count: subscription.plan.interval_count }) I18n.t('invoices.subscription_of_NAME_for_DURATION_starting_from_DATE', - NAME: username, - DURATION: duration_verbose, - DATE: I18n.l(subscription_start_at.to_date)) + **{ NAME: username, + DURATION: duration_verbose, + DATE: I18n.l(subscription_start_at.to_date) }) end # @param offer_day [OfferDay] @@ -79,9 +79,9 @@ class Invoices::LabelService # @return [String] def offer_day_label(offer_day, username) I18n.t('invoices.subscription_of_NAME_extended_starting_from_STARTDATE_until_ENDDATE', - NAME: username, - STARTDATE: I18n.l(offer_day.start_at.to_date), - ENDDATE: I18n.l(offer_day.end_at.to_date)) + **{ NAME: username, + STARTDATE: I18n.l(offer_day.start_at.to_date), + ENDDATE: I18n.l(offer_day.end_at.to_date) }) end end end diff --git a/app/services/invoices/number_service.rb b/app/services/invoices/number_service.rb index 63875cb1a..59ade6eaa 100644 --- a/app/services/invoices/number_service.rb +++ b/app/services/invoices/number_service.rb @@ -18,12 +18,39 @@ class Invoices::NumberService saved_number = setting == 'invoice_reference' ? document.reference : document.order_number return nil if saved_number.nil? - pattern = pattern(document, setting) - pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern) - start_idx = pattern.index(/n+|y+|m+|d+/) - end_idx = pattern.rindex(/n+|y+|m+|d+/) + indices = number_indices(document, setting) + saved_number[indices[0]..indices[1]]&.to_i + end - saved_number[start_idx..end_idx]&.to_i + # Search for any document matching the provided period and number + # @param number [Integer] the number to search + # @param date [Time] the date to search around, when using periodicity != 'global' + # @param setting [String] 'invoice_reference' | 'invoice_order-nb' + # @param klass [Class] Invoice | Order | PaymentSchedule + # @return [PaymentDocument,NilClass] + def find_by_number(number, date: Time.current, setting: 'invoice_reference', klass: Invoice) + raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting) + return nil if number.nil? + + pattern = pattern(date, setting) + pattern = pattern.gsub(/([SXR]\[[^\]]+\])+/, '%') + case pattern + when /n+/ + pattern = pattern.gsub(/[YMD]+/) { |match| '_' * match.to_s.length } + when /y+/ + pattern = pattern.gsub(/[MD]+/) { |match| '_' * match.to_s.length } + when /m+/ + pattern = pattern.gsub(/D+/) { |match| '_' * match.to_s.length } + end + pattern = PaymentDocumentService.send(:replace_date_pattern, pattern, date) + + pattern = pattern.gsub(/n+|y+|m+|d+/) do |match| + pad_and_truncate(number, match.to_s.length) + end + + field = setting == 'invoice_reference' ? 'reference' : 'order_number' + field = 'reference' if klass == Order + klass.where("#{field} LIKE '#{pattern}'").first end # @param document [PaymentDocument,NilClass] @@ -33,7 +60,7 @@ class Invoices::NumberService raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting) return nil if document.nil? - pattern = pattern(document, setting) + pattern = pattern(document.created_at, setting) pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern) return 'global' if pattern.match?(/n+/) @@ -44,19 +71,44 @@ class Invoices::NumberService nil end - # Get the pattern applicable to generate the number of the given invoice. - # @param document [PaymentDocument] + # Get the pattern applicable to generate the given number at the given date. + # @param date [Time] # @param setting [String] 'invoice_reference' | 'invoice_order-nb' # @return [String] - def pattern(document, setting = 'invoice_reference') + def pattern(date, setting = 'invoice_reference') raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting) - value = Setting.find_by(name: setting).value_at(document.created_at) - value || if document.created_at < Setting.find_by(name: setting).first_update + value = Setting.find_by(name: setting).value_at(date) + value || if date < Setting.find_by(name: setting).first_update Setting.find_by(name: setting).first_value else Setting.get(setting) end end + + private + + # Output the given integer with leading zeros. If the given value is longer than the given + # length, it will be truncated. + # @param value [Integer] the integer to pad + # @param length [Integer] the length of the resulting string. + def pad_and_truncate(value, length) + value.to_s.rjust(length, '0').gsub(/^.*(.{#{length},}?)$/m, '\1') + end + + # Return the indices of the number in the document's reference + # @param document [PaymentDocument,NilClass] + # @param setting [String] 'invoice_reference' | 'invoice_order-nb' + # @return [Array] + def number_indices(document, setting = 'invoice_reference') + raise TypeError, "invalid setting #{setting}" unless %w[invoice_order-nb invoice_reference].include?(setting) + return nil if document.nil? + + pattern = pattern(document.created_at, setting) + pattern = PaymentDocumentService.send(:replace_document_type_pattern, document, pattern) + start_idx = pattern.index(/n+|y+|m+|d+/) + end_idx = pattern.rindex(/n+|y+|m+|d+/) + [start_idx, end_idx] + end end end diff --git a/app/services/invoices/payment_details_service.rb b/app/services/invoices/payment_details_service.rb index 9d15c4d29..872cbd1bb 100644 --- a/app/services/invoices/payment_details_service.rb +++ b/app/services/invoices/payment_details_service.rb @@ -16,35 +16,25 @@ class Invoices::PaymentDetailsService build_avoir_details(invoice, total) else # subtract the wallet amount for this invoice from the total - if invoice.wallet_amount - wallet_amount = invoice.wallet_amount / 100.00 - total -= wallet_amount - else - wallet_amount = nil - end + wallet_amount = wallet_amount(invoice) + total -= wallet_amount unless wallet_amount.nil? + return '' if wallet_amount.nil? && total.zero? # payment method - payment_verbose = if invoice.paid_by_card? - I18n.t('invoices.settlement_by_debit_card') - else - I18n.t('invoices.settlement_done_at_the_reception') - end - - # if the invoice was 100% payed with the wallet ... - payment_verbose = I18n.t('invoices.settlement_by_wallet') if total.zero? && wallet_amount + payment_verbose = payment_mean(invoice, total, wallet_amount) payment_verbose += " #{I18n.t('invoices.on_DATE_at_TIME', - DATE: I18n.l(invoice.created_at.to_date), - TIME: I18n.l(invoice.created_at, format: :hour_minute))}" - if total.positive? || !invoice.wallet_amount - payment_verbose += " #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))}" + **{ DATE: I18n.l(invoice.created_at.to_date), + TIME: I18n.l(invoice.created_at, format: :hour_minute) })}" + if total.positive? || wallet_amount.nil? + payment_verbose += " #{I18n.t('invoices.for_an_amount_of_AMOUNT', **{ AMOUNT: number_to_currency(total) })}" end if invoice.wallet_amount payment_verbose += if total.positive? " #{I18n.t('invoices.and')} #{I18n.t('invoices.by_wallet')} " \ - "#{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))}" + "#{I18n.t('invoices.for_an_amount_of_AMOUNT', **{ AMOUNT: number_to_currency(wallet_amount) })}" else - " #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))}" + " #{I18n.t('invoices.for_an_amount_of_AMOUNT', **{ AMOUNT: number_to_currency(wallet_amount) })}" end end payment_verbose @@ -53,11 +43,35 @@ class Invoices::PaymentDetailsService private + # @param invoice [Invoice] + # @return [Float,NilClass] + def wallet_amount(invoice) + return invoice.wallet_amount / 100.00 if invoice.wallet_amount + + nil + end + + # @param invoice [Invoice] + # @param total [Float] + # @param wallet_amount [Float,NilClass] + # @return [String] + def payment_mean(invoice, total, wallet_amount) + # if the invoice was 100% payed with the wallet ... + return I18n.t('invoices.settlement_by_wallet') if total.zero? && !wallet_amount.nil? + + # else + if invoice.paid_by_card? + I18n.t('invoices.settlement_by_debit_card') + else + I18n.t('invoices.settlement_done_at_the_reception') + end + end + # @param invoice [Invoice] # @param total [Float] # @return [String] def build_avoir_details(invoice, total) - details = "#{I18n.t('invoices.refund_on_DATE', DATE: I18n.l(invoice.avoir_date.to_date))} " + details = "#{I18n.t('invoices.refund_on_DATE', **{ DATE: I18n.l(invoice.avoir_date.to_date) })} " case invoice.payment_method when 'stripe' details += I18n.t('invoices.by_card_online_payment') @@ -74,7 +88,7 @@ class Invoices::PaymentDetailsService else Rails.logger.error "specified refunding method (#{details}) is unknown" end - "#{details} #{I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))}" + "#{details} #{I18n.t('invoices.for_an_amount_of_AMOUNT', **{ AMOUNT: number_to_currency(total) })}" end end end diff --git a/app/services/invoices_service.rb b/app/services/invoices_service.rb index 47b96900b..ac63809e6 100644 --- a/app/services/invoices_service.rb +++ b/app/services/invoices_service.rb @@ -129,11 +129,11 @@ class InvoicesService "- #{I18n.l slot.end_at, format: :hour_minute}" else "#{I18n.t('events.from_STARTDATE_to_ENDDATE', - STARTDATE: I18n.l(slot.start_at.to_date, format: :long), - ENDDATE: I18n.l(slot.end_at.to_date, format: :long))} " \ + **{ STARTDATE: I18n.l(slot.start_at.to_date, format: :long), + ENDDATE: I18n.l(slot.end_at.to_date, format: :long) })} " \ "#{I18n.t('events.from_STARTTIME_to_ENDTIME', - STARTTIME: I18n.l(slot.start_at, format: :hour_minute), - ENDTIME: I18n.l(slot.end_at, format: :hour_minute))}" + **{ STARTTIME: I18n.l(slot.start_at, format: :hour_minute), + ENDTIME: I18n.l(slot.end_at, format: :hour_minute) })}" end price_slot = payment_details[:elements][:slots].detect { |p_slot| p_slot[:start_at].to_time.in_time_zone == slot[:start_at] } @@ -191,7 +191,7 @@ class InvoicesService invoice.invoice_items.push InvoiceItem.new( amount: payment_details[:elements][:pack], - description: I18n.t('invoices.pack_item', COUNT: pack.prepaid_pack.minutes / 60, ITEM: pack.prepaid_pack.priceable.name), + description: I18n.t('invoices.pack_item', **{ COUNT: pack.prepaid_pack.minutes / 60, ITEM: pack.prepaid_pack.priceable.name }), object: pack, main: main ) diff --git a/app/services/members/list_service.rb b/app/services/members/list_service.rb index e217d8240..6ed15eefd 100644 --- a/app/services/members/list_service.rb +++ b/app/services/members/list_service.rb @@ -100,7 +100,7 @@ class Members::ListService 'users.id' end - "#{order_key} #{direction}, users.id ASC LIMIT #{limit} OFFSET #{offset}" + Arel.sql("#{order_key} #{direction}, users.id ASC LIMIT #{limit} OFFSET #{offset}") end end end diff --git a/app/services/notification_center.rb b/app/services/notification_center.rb index dc9710763..adea6a3c3 100644 --- a/app/services/notification_center.rb +++ b/app/services/notification_center.rb @@ -2,18 +2,37 @@ # send notification to one or several receiver with a type, an attached object and an optional meta data class NotificationCenter - def self.call(type: nil, receiver: nil, attached_object: nil, meta_data: {}) - receiver = [receiver] unless receiver.respond_to?(:each) - notification_type = NotificationType.find_by(name: type) + class << self + def call(type: nil, receiver: nil, attached_object: nil, meta_data: {}) + return if prevent_notify?(type: type, attached_object: attached_object) - receiver.each do |user| - Notification.new( - meta_data: meta_data, - attached_object: attached_object, - receiver: user, - notification_type: notification_type - ) - .deliver_with_preferences(user, notification_type) + receiver = [receiver] unless receiver.respond_to?(:each) + notification_type = NotificationType.find_by(name: type) + + receiver.each do |user| + Notification.new( + meta_data: meta_data, + attached_object: attached_object, + receiver: user, + notification_type: notification_type + ) + .deliver_with_preferences(user, notification_type) + end + end + + private + + # In some very special cases, we do not want the notification to be created at all + # @param type [String] + # @param attached_object [ApplicationRecord] + # @return [Boolean] + def prevent_notify?(type: nil, attached_object: nil) + if type == 'notify_user_when_invoice_ready' + item = attached_object.main_item + return true if item.object_type == 'Error' && item.object_id == 1 + end + + false end end end diff --git a/app/services/payment_document_service.rb b/app/services/payment_document_service.rb index 5209f0b3d..cc30be4ff 100644 --- a/app/services/payment_document_service.rb +++ b/app/services/payment_document_service.rb @@ -7,7 +7,7 @@ class PaymentDocumentService # @param document [PaymentDocument] # @param date [Time] def generate_reference(document, date: Time.current) - pattern = Invoices::NumberService.pattern(document, 'invoice_reference') + pattern = Invoices::NumberService.pattern(document.created_at, 'invoice_reference') reference = replace_document_number_pattern(pattern, document) reference = replace_date_pattern(reference, date) @@ -16,7 +16,7 @@ class PaymentDocumentService # @param document [PaymentDocument] def generate_order_number(document) - pattern = Invoices::NumberService.pattern(document, 'invoice_order-nb') + pattern = Invoices::NumberService.pattern(document.created_at, 'invoice_order-nb') # global document number (nn..nn) reference = pattern.gsub(/n+(?![^\[]*\])/) do |match| @@ -27,6 +27,19 @@ class PaymentDocumentService replace_date_pattern(reference, document.created_at) end + # Generate a reference for the given document using the given document number + # @param number [Integer] + # @param document [PaymentDocument] + def generate_numbered_reference(number, document) + pattern = Invoices::NumberService.pattern(document.created_at, 'invoice_reference') + + reference = pattern.gsub(/n+|y+|m+|d+(?![^\[]*\])/) do |match| + pad_and_truncate(number, match.to_s.length) + end + reference = replace_date_pattern(reference, document.created_at) + replace_document_type_pattern(document, reference) + end + private # Output the given integer with leading zeros. If the given value is longer than the given @@ -55,6 +68,7 @@ class PaymentDocumentService # @param document [PaymentDocument] # @param periodicity [String] 'day' | 'month' | 'year' | 'global' + # @return [HashFootprintable,Number>] def previous_order(document, periodicity) start = periodicity == 'global' ? nil : document.created_at.send("beginning_of_#{periodicity}") ending = document.created_at @@ -67,11 +81,30 @@ class PaymentDocumentService .where('created_at < :end_date', end_date: db_time(ending)) invoices = invoices.where('created_at >= :start_date', start_date: db_time(start)) unless start.nil? - [ - orders.order(created_at: :desc).limit(1).first, - schedules.order(created_at: :desc).limit(1).first, - invoices.order(created_at: :desc).limit(1).first + last_with_number = [ + orders.where.not(reference: nil).order(created_at: :desc).limit(1).first, + schedules.where.not(order_number: nil).order(created_at: :desc).limit(1).first, + invoices.where.not(order_number: nil).order(created_at: :desc).limit(1).first ].filter(&:present?).max_by { |item| item&.created_at } + { + last_order: last_with_number, + unnumbered: orders_without_number(orders, schedules, invoices, last_with_number) + } + end + + def orders_without_number(orders, schedules, invoices, last_item_with_number = nil) + items_after(orders.where(reference: nil), last_item_with_number).count + + items_after(schedules.where(order_number: nil), last_item_with_number).count + + items_after(invoices.where(order_number: nil), last_item_with_number).count + end + + # @param items [ActiveRecord::Relation] + # @param previous_item [Footprintable,NilClass] + # @return [ActiveRecord::Relation] + def items_after(items, previous_item = nil) + return items if previous_item.nil? + + items.where('created_at > :date', date: previous_item&.created_at) end # @param document [PaymentDocument] invoice to exclude @@ -145,12 +178,12 @@ class PaymentDocumentService # @return [Integer] def order_number(document, periodicity) previous = previous_order(document, periodicity) - if Invoices::NumberService.number_periodicity(previous, 'invoice_order-nb') == periodicity - number = Invoices::NumberService.number(previous, 'invoice_order-nb') + if Invoices::NumberService.number_periodicity(previous[:last_order], 'invoice_order-nb') == periodicity + number = Invoices::NumberService.number(previous[:last_order], 'invoice_order-nb') end number ||= 0 - number + 1 + number + previous[:unnumbered] + 1 end # Replace the document number elements in the provided pattern with counts from the database diff --git a/app/services/payment_schedule_service.rb b/app/services/payment_schedule_service.rb index dea50390e..ad289d2f1 100644 --- a/app/services/payment_schedule_service.rb +++ b/app/services/payment_schedule_service.rb @@ -117,8 +117,8 @@ class PaymentScheduleService set_total_and_coupon(payment_schedule_item, invoice, user, coupon) # save the results + invoice.payment_schedule_item = payment_schedule_item invoice.save - payment_schedule_item.update(invoice_id: invoice.id) end # return a paginated list of PaymentSchedule, optionally filtered, with their associated PaymentScheduleItem diff --git a/app/services/payments/payment_concern.rb b/app/services/payments/payment_concern.rb index f2ff488df..2c67e83b5 100644 --- a/app/services/payments/payment_concern.rb +++ b/app/services/payments/payment_concern.rb @@ -60,7 +60,7 @@ module Payments::PaymentConcern ) invoice.wallet_amount = order.wallet_amount invoice.wallet_transaction_id = order.wallet_transaction_id + invoice.order = order invoice.save unless Setting.get('prevent_invoices_zero') && order.total.zero? - order.update(invoice_id: invoice.id) end end diff --git a/app/services/setting_service.rb b/app/services/setting_service.rb index 0e5bf728a..3f10899cb 100644 --- a/app/services/setting_service.rb +++ b/app/services/setting_service.rb @@ -114,7 +114,7 @@ class SettingService return unless (%w[openlab_app_id openlab_app_secret] & settings.map(&:name)).count.positive? && Setting.get('openlab_app_id').present? && Setting.get('openlab_app_secret').present? - Project.all.each(&:openlab_create) + Project.find_each(&:openlab_create) end # automatically validate the admins diff --git a/app/services/statistics_export_service.rb b/app/services/statistics_export_service.rb index 41d08e22f..cd00258b4 100644 --- a/app/services/statistics_export_service.rb +++ b/app/services/statistics_export_service.rb @@ -27,16 +27,12 @@ class StatisticsExportService @indices = StatisticIndex.all.includes(:statistic_fields, statistic_types: [:statistic_sub_types]) - ActionController::Base.prepend_view_path './app/views/' - # place data in view_assigns - view_assigns = { results: @results, users: @users, indices: @indices } - av = ActionView::Base.new(ActionController::Base.view_paths, view_assigns) - av.class_eval do - # include any needed helpers (for the view) - include ExcelHelper - end - - content = av.render template: 'exports/statistics_global.xlsx.axlsx' + content = ApplicationController.render( + template: 'exports/statistics_global', + locals: { results: @results, users: @users, indices: @indices }, + handlers: [:axlsx], + formats: [:xlsx] + ) # write content to file File.binwrite(export.file, content) end @@ -65,20 +61,16 @@ class StatisticsExportService @subtypes = @type.statistic_sub_types @fields = @index.statistic_fields - ActionController::Base.prepend_view_path './app/views/' - # place data in view_assigns - view_assigns = {results: @results, users: @users, index: @index, type: @type, subtypes: @subtypes, fields: @fields} - av = ActionView::Base.new(ActionController::Base.view_paths, view_assigns) - av.class_eval do - # include any needed helpers (for the view) - include ExcelHelper - end - - content = av.render template: 'exports/statistics_current.xlsx.axlsx' + content = ApplicationController.render( + template: 'exports/statistics_current', + locals: { results: @results, users: @users, index: @index, type: @type, subtypes: @subtypes, fields: @fields }, + handlers: [:axlsx], + formats: [:xlsx] + ) # write content to file File.binwrite(export.file, content) end - }, __FILE__, __LINE__ - 35 + }, __FILE__, __LINE__ - 31 end # rubocop:enable Style/DocumentDynamicEvalDefinition end diff --git a/app/services/users_export_service.rb b/app/services/users_export_service.rb index 13a96f595..5d84e7195 100644 --- a/app/services/users_export_service.rb +++ b/app/services/users_export_service.rb @@ -10,62 +10,48 @@ require './app/helpers/application_helper' # There routines will generate Excel files containing data dumped from database class UsersExportService - # export subscriptions def export_subscriptions(export) @subscriptions = Subscription.all.includes(:plan, statistic_profile: [user: [:profile]]) - ActionController::Base.prepend_view_path './app/views/' - # place data in view_assigns - view_assigns = { subscriptions: @subscriptions } - av = ActionView::Base.new(ActionController::Base.view_paths, view_assigns) - av.class_eval do - # include any needed helpers (for the view) - include ApplicationHelper - end - - content = av.render template: 'exports/users_subscriptions.xlsx.axlsx' + content = ApplicationController.render( + template: 'exports/users_subscriptions', + locals: { subscriptions: @subscriptions }, + handlers: [:axlsx], + formats: [:xlsx] + ) # write content to file - File.open(export.file, 'w+b') { |f| f.write content } + File.binwrite(export.file, content) end # export reservations def export_reservations(export) @reservations = Reservation.all.includes(:slots, :reservable, statistic_profile: [user: [:profile]]) - ActionController::Base.prepend_view_path './app/views/' - # place data in view_assigns - view_assigns = { reservations: @reservations } - av = ActionView::Base.new(ActionController::Base.view_paths, view_assigns) - av.class_eval do - # include any needed helpers (for the view) - include ApplicationHelper - end - - content = av.render template: 'exports/users_reservations.xlsx.axlsx' + content = ApplicationController.render( + template: 'exports/users_reservations', + locals: { reservations: @reservations }, + handlers: [:axlsx], + formats: [:xlsx] + ) # write content to file - File.open(export.file, 'w+b') { |f| f.write content } + File.binwrite(export.file, content) end # export members def export_members(export) @members = User.members .includes(:group, :tags, :projects, :profile, - invoicing_profile: [:invoices, :address, organization: [:address]], - statistic_profile: [:trainings, subscriptions: [:plan]]) + invoicing_profile: [:invoices, :address, { organization: [:address] }], + statistic_profile: [:trainings, { subscriptions: [:plan] }]) - ActionController::Base.prepend_view_path './app/views/' - # place data in view_assigns - view_assigns = { members: @members } - av = ActionView::Base.new(ActionController::Base.view_paths, view_assigns) - av.class_eval do - # include any needed helpers (for the view) - include ApplicationHelper - end - - content = av.render template: 'exports/users_members.xlsx.axlsx' + content = ApplicationController.render( + template: 'exports/users_members', + locals: { members: @members }, + handlers: [:axlsx], + formats: [:xlsx] + ) # write content to file - File.open(export.file, 'w+b') { |f| f.write content } + File.binwrite(export.file, content) end - end diff --git a/app/sweepers/stylesheet_sweeper.rb b/app/sweepers/stylesheet_sweeper.rb deleted file mode 100644 index 3a8c23fd6..000000000 --- a/app/sweepers/stylesheet_sweeper.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -# Build a cached version of the CSS stylesheet -class StylesheetSweeper < ActionController::Caching::Sweeper - observe Stylesheet - - def after_update(record) - expire_page(controller: 'stylesheets', action: 'show', id: record.id) if record.saved_change_to_contents? - end -end diff --git a/app/validators/closed_period_validator.rb b/app/validators/closed_period_validator.rb index 7a7a24bd2..d46ba4a18 100644 --- a/app/validators/closed_period_validator.rb +++ b/app/validators/closed_period_validator.rb @@ -9,7 +9,7 @@ class ClosedPeriodValidator < ActiveModel::Validator Time.current end - AccountingPeriod.all.each do |period| + AccountingPeriod.find_each do |period| record.errors.add(:date, I18n.t('errors.messages.in_closed_period')) if date >= period.start_at && date <= period.end_at end end diff --git a/app/validators/coupon_discount_validator.rb b/app/validators/coupon_discount_validator.rb index 60a674804..cd2d2f503 100644 --- a/app/validators/coupon_discount_validator.rb +++ b/app/validators/coupon_discount_validator.rb @@ -1,15 +1,14 @@ +# frozen_string_literal: true + +# Validates the validity of a new or updated coupon class CouponDiscountValidator < ActiveModel::Validator def validate(record) if !record.percent_off.nil? - unless (0..100).include? record.percent_off - record.errors[:percent_off] << I18n.t('errors.messages.percentage_out_of_range') - end + record.errors.add(:percent_off, I18n.t('errors.messages.percentage_out_of_range')) unless (0..100).include? record.percent_off elsif !record.amount_off.nil? - unless record.amount_off > 0 - record.errors[:amount_off] << I18n.t('errors.messages.greater_than_or_equal_to', count: 0) - end + record.errors.add(:amount_off, I18n.t('errors.messages.greater_than_or_equal_to', **{ count: 0 })) unless record.amount_off.positive? else - record.errors[:percent_off] << I18n.t('errors.messages.cannot_be_blank_at_same_time', field: 'amount_off') + record.errors.add(:percent_off, I18n.t('errors.messages.cannot_be_blank_at_same_time', **{ field: 'amount_off' })) end end -end \ No newline at end of file +end diff --git a/app/validators/database_provider_validator.rb b/app/validators/database_provider_validator.rb index d49de8b8d..af80c52c9 100644 --- a/app/validators/database_provider_validator.rb +++ b/app/validators/database_provider_validator.rb @@ -5,6 +5,6 @@ class DatabaseProviderValidator < ActiveModel::Validator def validate(record) return if DatabaseProvider.count.zero? - record.errors[:id] << I18n.t('authentication_providers.local_database_provider_already_exists') + record.errors.add(:id, I18n.t('authentication_providers.local_database_provider_already_exists')) end end diff --git a/app/validators/date_range_validator.rb b/app/validators/date_range_validator.rb index fccd59092..718de7e5f 100644 --- a/app/validators/date_range_validator.rb +++ b/app/validators/date_range_validator.rb @@ -7,6 +7,6 @@ class DateRangeValidator < ActiveModel::Validator the_start = record.start_at return if the_end.present? && the_end >= the_start - record.errors[:end_at] << I18n.t('errors.messages.end_before_start', START: the_start) + record.errors.add(:end_at, I18n.t('errors.messages.end_before_start', **{ START: the_start })) end end diff --git a/app/validators/duration_validator.rb b/app/validators/duration_validator.rb index 0fd4e8520..7ad5b8a8d 100644 --- a/app/validators/duration_validator.rb +++ b/app/validators/duration_validator.rb @@ -7,8 +7,8 @@ class DurationValidator < ActiveModel::Validator the_start = record.start_at diff = (the_end - the_start).to_i # 0.day means that (the_start == the_end), so it's a one day period - return if diff.days >= 0.day && diff.days <= 1.year + return if diff.days >= 0.days && diff.days <= 1.year - record.errors[:end_at] << I18n.t('errors.messages.invalid_duration', DAYS: diff) + record.errors.add(:end_at, I18n.t('errors.messages.invalid_duration', **{ DAYS: diff })) end end diff --git a/app/validators/past_period_validator.rb b/app/validators/past_period_validator.rb index 78ca9afe7..7216a55b1 100644 --- a/app/validators/past_period_validator.rb +++ b/app/validators/past_period_validator.rb @@ -5,8 +5,8 @@ class PastPeriodValidator < ActiveModel::Validator def validate(record) the_end = record.end_at - return if the_end.present? && the_end < Date.today + return if the_end.present? && the_end < Time.zone.today - record.errors[:end_at] << I18n.t('errors.messages.must_be_in_the_past') + record.errors.add(:end_at, I18n.t('errors.messages.must_be_in_the_past')) end end diff --git a/app/validators/period_integrity_validator.rb b/app/validators/period_integrity_validator.rb index 9f0d735f0..2bd41a28f 100644 --- a/app/validators/period_integrity_validator.rb +++ b/app/validators/period_integrity_validator.rb @@ -6,7 +6,7 @@ class PeriodIntegrityValidator < ActiveModel::Validator invoices = record.invoices.includes(:invoice_items) invoices.each do |i| - record.errors["invoice_#{i.reference}".to_sym] << I18n.t('errors.messages.invalid_footprint') unless i.check_footprint + record.errors.add("invoice_#{i.reference}".to_sym, I18n.t('errors.messages.invalid_footprint')) unless i.check_footprint end end end diff --git a/app/validators/period_overlap_validator.rb b/app/validators/period_overlap_validator.rb index 8d718c9a8..221f9259e 100644 --- a/app/validators/period_overlap_validator.rb +++ b/app/validators/period_overlap_validator.rb @@ -6,16 +6,10 @@ class PeriodOverlapValidator < ActiveModel::Validator the_end = record.end_at the_start = record.start_at - AccountingPeriod.all.each do |period| - if the_start >= period.start_at && the_start <= period.end_at - record.errors[:start_at] << I18n.t('errors.messages.cannot_overlap') - end - if the_end >= period.start_at && the_end <= period.end_at - record.errors[:end_at] << I18n.t('errors.messages.cannot_overlap') - end - if period.start_at >= the_start && period.end_at <= the_end - record.errors[:end_at] << I18n.t('errors.messages.cannot_encompass') - end + AccountingPeriod.find_each do |period| + record.errors.add(:start_at, I18n.t('errors.messages.cannot_overlap')) if the_start >= period.start_at && the_start <= period.end_at + record.errors.add(:end_at, I18n.t('errors.messages.cannot_overlap')) if the_end >= period.start_at && the_end <= period.end_at + record.errors.add(:end_at, I18n.t('errors.messages.cannot_encompass')) if period.start_at >= the_start && period.end_at <= the_end end end end diff --git a/app/validators/subscription_group_validator.rb b/app/validators/subscription_group_validator.rb index 7f04545e5..a793ff6fa 100644 --- a/app/validators/subscription_group_validator.rb +++ b/app/validators/subscription_group_validator.rb @@ -5,6 +5,6 @@ class SubscriptionGroupValidator < ActiveModel::Validator def validate(record) return if record.statistic_profile&.group_id == record.plan&.group_id - record.errors[:plan_id] << "This plan is not compatible with the current user's group" + record.errors.add(:plan_id, "This plan is not compatible with the current user's group") end end diff --git a/app/views/api/custom_assets/show.json.jbuilder b/app/views/api/custom_assets/show.json.jbuilder index 37012a046..182781ce9 100644 --- a/app/views/api/custom_assets/show.json.jbuilder +++ b/app/views/api/custom_assets/show.json.jbuilder @@ -1,12 +1,16 @@ +# frozen_string_literal: true + json.custom_asset do if @custom_asset json.extract! @custom_asset, :id, :name - json.custom_asset_file_attributes do - json.id @custom_asset.custom_asset_file.id - json.attachment @custom_asset.custom_asset_file.attachment_identifier - json.attachment_url @custom_asset.custom_asset_file.attachment_url - end if @custom_asset.custom_asset_file + if @custom_asset.custom_asset_file + json.custom_asset_file_attributes do + json.id @custom_asset.custom_asset_file.id + json.attachment @custom_asset.custom_asset_file.attachment_identifier + json.attachment_url @custom_asset.custom_asset_file.attachment_url + end + end else json.nil! end -end \ No newline at end of file +end diff --git a/app/views/api/stylesheets/show.css.erb b/app/views/api/stylesheets/show.css.erb index 02c72b437..69f10f41a 100644 --- a/app/views/api/stylesheets/show.css.erb +++ b/app/views/api/stylesheets/show.css.erb @@ -1 +1,3 @@ -<%= @stylesheet.contents.html_safe %> \ No newline at end of file +<% cache @stylesheet do %> + <%= @stylesheet.contents.html_safe %> +<% end %> diff --git a/app/views/auth_provider/provider.json.jbuilder b/app/views/auth_provider/provider.json.jbuilder new file mode 100644 index 000000000..135f082a5 --- /dev/null +++ b/app/views/auth_provider/provider.json.jbuilder @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +json.partial! 'api/auth_providers/auth_provider', auth_provider: provider + +# OAuth 2.0 + +if provider.providable_type == 'OAuth2Provider' + json.providable_attributes do + json.extract! provider.providable, :id, :base_url, :token_endpoint, :authorization_endpoint, :profile_url, :client_id, :client_secret, + :scopes + end +end + +if provider.providable_type == 'OpenIdConnectProvider' + json.providable_attributes do + json.extract! provider.providable, :id, :issuer, :discovery, :client_auth_method, :scope, :response_type, :response_mode, + :display, :prompt, :send_scope_to_token_endpoint, :client__identifier, :client__secret, :client__authorization_endpoint, + :client__token_endpoint, :client__userinfo_endpoint, :client__jwks_uri, :client__end_session_endpoint, :profile_url, + :post_logout_redirect_uri, :uid_field, :client__redirect_uri, :client__scheme, :client__host, :client__port + end +end + diff --git a/app/views/exports/availabilities_index.xlsx.axlsx b/app/views/exports/availabilities_index.xlsx.axlsx index 7952956df..1b61baf28 100644 --- a/app/views/exports/availabilities_index.xlsx.axlsx +++ b/app/views/exports/availabilities_index.xlsx.axlsx @@ -15,7 +15,7 @@ wb.add_worksheet(name: ExcelService.name_safe(t('export_availabilities.machines' sheet.add_row columns, style: header # data rows - @availabilities.where(available_type: 'machines').order(:start_at).each do |a| + availabilities.where(available_type: 'machines').order(:start_at).each do |a| slot_duration = a.slot_duration || Setting.get('slot_duration').to_i a.machines.each do |m| ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i| @@ -55,7 +55,7 @@ wb.add_worksheet(name: ExcelService.name_safe(t('export_availabilities.trainings sheet.add_row columns, style: header # data rows - @availabilities.where(available_type: 'training').order(:start_at).each do |a| + availabilities.where(available_type: 'training').order(:start_at).each do |a| data = [ a.start_at.to_date, I18n.l(a.start_at, format: '%A').capitalize, @@ -83,7 +83,7 @@ if Setting.get('spaces_module') sheet.add_row columns, style: header # data rows - @availabilities.where(available_type: 'space').order(:start_at).each do |a| + availabilities.where(available_type: 'space').order(:start_at).each do |a| slot_duration = a.slot_duration || Setting.get('slot_duration').to_i ((a.end_at - a.start_at) / slot_duration.minutes).to_i.times do |i| start_at = a.start_at + (i * slot_duration).minutes @@ -119,7 +119,7 @@ wb.add_worksheet(name: ExcelService.name_safe(t('export_availabilities.events')) sheet.add_row columns, :style => header # data rows - @availabilities.where(available_type: 'event').order(:start_at).each do |a| + availabilities.where(available_type: 'event').order(:start_at).each do |a| data = [ a.start_at.to_date, I18n.l(a.start_at, format: '%A').capitalize, diff --git a/app/views/exports/statistics_current.xlsx.axlsx b/app/views/exports/statistics_current.xlsx.axlsx index f009cab19..2a8d655a9 100644 --- a/app/views/exports/statistics_current.xlsx.axlsx +++ b/app/views/exports/statistics_current.xlsx.axlsx @@ -6,13 +6,13 @@ bold = wb.styles.add_style b: true header = wb.styles.add_style b: true, bg_color: Stylesheet.primary.upcase.gsub('#', 'FF'), fg_color: 'FFFFFFFF' date = wb.styles.add_style format_code: Rails.application.secrets.excel_date_format -wb.add_worksheet(name: ExcelService.name_safe(@index.label)) do |sheet| +wb.add_worksheet(name: ExcelService.name_safe(index.label)) do |sheet| ## heading stats for the current page - sheet.add_row [t('export.entries'), @results['hits']['total']], style: [bold, nil], types: %i[string integer] - sheet.add_row [t('export.revenue'), @results['aggregations']['total_ca']['value']], style: [bold, nil], types: %i[string float] if @index.ca - sheet.add_row [t('export.average_age'), @results['aggregations']['average_age']['value']], style: [bold, nil], types: %i[string float] - unless @type.simple - sheet.add_row ["#{t('export.total')} #{@type.label}", @results['aggregations']['total_stat']['value']], + sheet.add_row [t('export.entries'), results['hits']['total']], style: [bold, nil], types: %i[string integer] + sheet.add_row [t('export.revenue'), results['aggregations']['total_ca']['value']], style: [bold, nil], types: %i[string float] if index.ca + sheet.add_row [t('export.average_age'), results['aggregations']['average_age']['value']], style: [bold, nil], types: %i[string float] + unless type.simple + sheet.add_row ["#{t('export.total')} #{type.label}", results['aggregations']['total_stat']['value']], style: [bold, nil], types: %i[string integer] end @@ -22,22 +22,22 @@ wb.add_worksheet(name: ExcelService.name_safe(@index.label)) do |sheet| # heading labels columns = [t('export.date'), t('export.user'), t('export.email'), t('export.phone'), t('export.gender'), t('export.age'), t('export.type')] - columns.push @type.label unless @type.simple - @fields.each do |f| + columns.push type.label unless type.simple + fields.each do |f| columns.push f.label end - columns.push t('export.revenue') if @index.ca + columns.push t('export.revenue') if index.ca sheet.add_row columns, style: header # data rows - @results['hits']['hits'].each do |hit| - user = get_item(@users, hit['_source']['userId']) - subtype = get_item(@subtypes, hit['_source']['subType'], 'key') - data, styles, types = statistics_line(hit, user, @type, subtype, date) - @fields.each do |f| + results['hits']['hits'].each do |hit| + user = get_item(users, hit['_source']['userId']) + subtype = get_item(subtypes, hit['_source']['subType'], 'key') + data, styles, types = statistics_line(hit, user, type, subtype, date) + fields.each do |f| format_xlsx_cell(hit['_source'][f.key], data, styles, types, source_data_type: f.data_type, date_format: date) end - add_ca_cell(@index, hit, data, styles, types) + add_ca_cell(index, hit, data, styles, types) sheet.add_row data, style: styles, types: types end diff --git a/app/views/exports/statistics_global.xlsx.axlsx b/app/views/exports/statistics_global.xlsx.axlsx index b2ffc108c..3de6c4ed5 100644 --- a/app/views/exports/statistics_global.xlsx.axlsx +++ b/app/views/exports/statistics_global.xlsx.axlsx @@ -5,7 +5,7 @@ wb = xlsx_package.workbook header = wb.styles.add_style b: true, bg_color: Stylesheet.primary.upcase.gsub('#', 'FF'), fg_color: 'FFFFFFFF' date = wb.styles.add_style format_code: Rails.application.secrets.excel_date_format -@indices.each do |index| +indices.each do |index| next unless index.table index.statistic_types.each do |type| @@ -22,12 +22,12 @@ date = wb.styles.add_style format_code: Rails.application.secrets.excel_date_for sheet.add_row columns, style: header # data rows - @results['hits']['hits'].each do |hit| + results['hits']['hits'].each do |hit| # check that the current result is for the given index and type next unless hit['_type'] == index.es_type_key && hit['_source']['type'] == type.key # get matching objects - user = get_item(@users, hit['_source']['userId']) + user = get_item(users, hit['_source']['userId']) subtype = get_item(type.statistic_sub_types, hit['_source']['subType'], 'key') # start to fill data and associated styles and data-types data, styles, types = statistics_line(hit, user, type, subtype, date) diff --git a/app/views/exports/users_members.xlsx.axlsx b/app/views/exports/users_members.xlsx.axlsx index 877a8bf0b..f4866e267 100644 --- a/app/views/exports/users_members.xlsx.axlsx +++ b/app/views/exports/users_members.xlsx.axlsx @@ -39,7 +39,7 @@ wb.add_worksheet(name: ExcelService.name_safe(t('export_members.members'))) do | sheet.add_row columns, style: header # data rows - @members.each do |member| + members.each do |member| expiration = member&.subscription&.expired_at data = [ member.id, diff --git a/app/views/exports/users_reservations.xlsx.axlsx b/app/views/exports/users_reservations.xlsx.axlsx index ca2a11b07..6566704e0 100644 --- a/app/views/exports/users_reservations.xlsx.axlsx +++ b/app/views/exports/users_reservations.xlsx.axlsx @@ -15,7 +15,7 @@ wb.add_worksheet(name: ExcelService.name_safe(t('export_reservations.reservation sheet.add_row columns, style: header # data rows - @reservations.each do |resrv| + reservations.each do |resrv| invoice = resrv.original_invoice data = [ resrv.user&.id, diff --git a/app/views/exports/users_subscriptions.xlsx.axlsx b/app/views/exports/users_subscriptions.xlsx.axlsx index b8e43ac26..82273e1cb 100644 --- a/app/views/exports/users_subscriptions.xlsx.axlsx +++ b/app/views/exports/users_subscriptions.xlsx.axlsx @@ -15,7 +15,7 @@ wb.add_worksheet(name: ExcelService.name_safe(t('export_subscriptions.subscripti sheet.add_row columns, style: header # data rows - @subscriptions.each do |sub| + subscriptions.each do |sub| data = [ sub.user&.id, sub.user&.profile&.full_name || t('export_subscriptions.deleted_user'), diff --git a/app/views/open_api/v1/availabilities/index.json.jbuilder b/app/views/open_api/v1/availabilities/index.json.jbuilder new file mode 100644 index 000000000..8fe2c4090 --- /dev/null +++ b/app/views/open_api/v1/availabilities/index.json.jbuilder @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +json.availabilities @availabilities do |availability| + json.extract! availability, :id, :start_at, :end_at, :created_at + json.available_type availability.available_type.classify + json.available_ids availability.available_ids + + json.slots availability.slots do |slot| + json.extract! slot, :id, :start_at, :end_at + end +end diff --git a/app/views/open_api/v1/reservations/index.json.jbuilder b/app/views/open_api/v1/reservations/index.json.jbuilder index 6e25bf003..fd394eb76 100644 --- a/app/views/open_api/v1/reservations/index.json.jbuilder +++ b/app/views/open_api/v1/reservations/index.json.jbuilder @@ -25,6 +25,6 @@ json.reservations @reservations do |reservation| json.reserved_slots reservation.slots_reservations do |slot_reservation| json.extract! slot_reservation, :canceled_at - json.extract! slot_reservation.slot, :start_at, :end_at + json.extract! slot_reservation.slot, :availability_id, :start_at, :end_at end end diff --git a/app/workers/invoice_worker.rb b/app/workers/invoice_worker.rb index 25901d0f8..411f40677 100644 --- a/app/workers/invoice_worker.rb +++ b/app/workers/invoice_worker.rb @@ -7,7 +7,7 @@ class InvoiceWorker def perform(invoice_id) # generate a invoice invoice = Invoice.find invoice_id - pdf = ::PDF::Invoice.new(invoice).render + pdf = ::Pdf::Invoice.new(invoice).render # store invoice on drive File.binwrite(invoice.file, pdf) diff --git a/app/workers/payment_schedule_worker.rb b/app/workers/payment_schedule_worker.rb index 5b9f325bd..bbe9b9709 100644 --- a/app/workers/payment_schedule_worker.rb +++ b/app/workers/payment_schedule_worker.rb @@ -8,7 +8,7 @@ class PaymentScheduleWorker def perform(payment_schedule_id) # generate a payment schedule document ps = PaymentSchedule.find(payment_schedule_id) - pdf = ::PDF::PaymentSchedule.new(ps).render + pdf = ::Pdf::PaymentSchedule.new(ps).render # save the file on the disk File.binwrite(ps.file, pdf) diff --git a/bin/setup b/bin/setup index 94fd4d797..d6e019aca 100755 --- a/bin/setup +++ b/bin/setup @@ -1,6 +1,5 @@ #!/usr/bin/env ruby require 'fileutils' -include FileUtils # path to your application root. APP_ROOT = File.expand_path('..', __dir__) @@ -9,24 +8,22 @@ def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end -chdir APP_ROOT do - # This script is a starting point to setup your application. +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. # Add necessary setup steps to this file. puts '== Installing dependencies ==' system! 'gem install bundler --conservative' system('bundle check') || system!('bundle install') - # Install JavaScript dependencies if using Yarn - # system('bin/yarn') - # puts "\n== Copying sample files ==" - # unless File.exist?('config/database.yml') - # cp 'config/database.yml.sample', 'config/database.yml' + # unless File.exist?("config/database.yml") + # FileUtils.cp "config/database.yml.sample", "config/database.yml" # end puts "\n== Preparing database ==" - system! 'bin/rails db:setup' + system! 'bin/rails db:prepare' puts "\n== Removing old logs and tempfiles ==" system! 'bin/rails log:clear tmp:clear' diff --git a/config/application.rb b/config/application.rb index 1a3dfda9c..44874c4d5 100644 --- a/config/application.rb +++ b/config/application.rb @@ -19,69 +19,76 @@ require 'elasticsearch/persistence/model' # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) -module Fablab - class Application < Rails::Application - require 'fab_manager' +# module declaration +module FabManager; end - # Initialize configuration defaults for originally generated Rails version. - config.load_defaults 5.2 - # prevent this new behavior with rails >= 5.0 - # see https://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record-belongs-to-required-by-default-option - config.active_record.belongs_to_required_by_default = false +# Fab-Manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your +# administrative tasks and your marker's projects. +class FabManager::Application < Rails::Application + require 'fab_manager' - # Settings in config/environments/* take precedence over those specified here. - # Application configuration should go into files in config/initializers - # -- all .rb files in that directory are automatically loaded. + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 7.0 + config.active_support.cache_format_version = 6.1 + config.action_dispatch.cookies_serializer = :hybrid + config.active_record.verify_foreign_keys_for_fixtures = false + # prevent this new behavior with rails >= 5.0 + # see https://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record-belongs-to-required-by-default-option + config.active_record.belongs_to_required_by_default = false + config.active_record.schema_format = :sql - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. - # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. - config.time_zone = Rails.application.secrets.time_zone + config.active_record.yaml_column_permitted_classes = [Symbol, Date, Time] - config.to_prepare do - Devise::Mailer.layout 'notifications_mailer' - end + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. - config.active_job.queue_adapter = :sidekiq + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + config.time_zone = Rails.application.secrets.time_zone - config.generators do |g| - g.orm :active_record - g.test_framework :mini_test - end + config.to_prepare do + Devise::Mailer.layout 'notifications_mailer' + end - if Rails.env.development? - config.web_console.whitelisted_ips << '192.168.0.0/16' - config.web_console.whitelisted_ips << '192.168.99.0/16' # docker - config.web_console.whitelisted_ips << '10.0.2.2' # vagrant - end + config.active_job.queue_adapter = :sidekiq - # load locales for subdirectories - config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**/*.yml').to_s] + config.generators do |g| + g.orm :active_record + g.test_framework :mini_test + end - # enable the app to find locales in plugins locales directory - config.i18n.load_path += Dir["#{Rails.root}/plugins/*/config/locales/*.yml"] + # load locales for subdirectories + config.i18n.load_path += Dir[Rails.root.join('config/locales/**/*.yml').to_s] - # Enable locale fallbacks for I18n (makes lookups for any locale fall back to - # the I18n.default_locale when a translation cannot be found). - config.i18n.fallbacks = true + # enable the app to find locales in plugins locales directory + config.i18n.load_path += Dir[Rails.root.join('plugins/*/config/locales/*.yml').to_s] - # enable the app to find views in plugins views directory - Dir["#{Rails.root}/plugins/*/views"].each do |path| - Rails.application.config.paths['app/views'] << path - end + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = true - # disable ANSI color escape codes in active_record if NO_COLOR is defined. - config.colorize_logging = ENV['NO_COLOR'] ? false : true + # enable the app to find views in plugins views directory + Dir[Rails.root.join('plugins/*/views').to_s].each do |path| + Rails.application.config.paths['app/views'] << path + end - FabManager.activate_plugins! + # disable ANSI color escape codes in active_record if NO_COLOR is defined. + config.colorize_logging = ENV['NO_COLOR'] ? false : true - config.action_view.sanitized_allowed_tags = %w(a acronym hr pre table b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p image iframe style) + require 'provider_config' + config.auth_provider = ProviderConfig.new - config.after_initialize do - plugins = FabManager.plugins - plugins&.each(&:notify_after_initialize) + FabManager.activate_plugins! - require 'version' - Version.check - end + config.action_view.sanitized_allowed_tags = %w[a acronym hr pre table b strong i em li ul ol h1 h2 h3 h4 h5 h6 blockquote br cite sub sup ins p + image iframe style] + + config.after_initialize do + plugins = FabManager.plugins + plugins&.each(&:notify_after_initialize) + + require 'version' + Version.check end end diff --git a/config/environments/development.rb b/config/environments/development.rb index 2de9cb7eb..d303e9c9e 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,21 +1,12 @@ # frozen_string_literal: true -Rails.application.configure do - # https://github.com/flyerhzm/bullet - # In development, Bullet will find and report N+1 DB requests - config.after_initialize do - Bullet.enable = true - Bullet.alert = true - Bullet.bullet_logger = true - Bullet.console = true - Bullet.rails_logger = true - Bullet.add_footer = true - end +require 'active_support/core_ext/integer/time' +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # In the development environment your application's code is reloaded on - # every request. This slows down response time but is perfect for development + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false @@ -25,10 +16,14 @@ Rails.application.configure do # Show full error reports. config.consider_all_requests_local = true + # Enable server timing + config.server_timing = true + # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join('tmp', 'caching-dev.txt').exist? + if Rails.root.join('tmp/caching-dev.txt').exist? config.action_controller.perform_caching = true + config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store config.public_file_server.headers = { @@ -40,12 +35,7 @@ Rails.application.configure do config.cache_store = :null_store end - config.action_controller.default_url_options = { - host: Rails.application.secrets.default_host, - protocol: Rails.application.secrets.default_protocol - } - - # Store uploaded files on the local file system (see config/storage.yml for options) + # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Don't care if the mailer can't send. @@ -67,19 +57,48 @@ Rails.application.configure do # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true - # Raises error for missing translations - # config.action_view.raise_on_missing_translations = true + # Raises error for missing translations. + # config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker config.log_level = Rails.application.secrets.log_level || :debug -end + config.action_controller.default_url_options = { + host: Rails.application.secrets.default_host, + protocol: Rails.application.secrets.default_protocol + } + + # whitelist IP for web-console: local network, docker and vagrant + config.web_console.permissions = %w[192.168.0.0/16 192.168.99.0/16 10.0.2.2] + + config.hosts << ENV.fetch('DEFAULT_HOST', 'localhost') + + # https://github.com/flyerhzm/bullet + # In development, Bullet will find and report N+1 DB requests + config.after_initialize do + Bullet.enable = true + Bullet.alert = true + Bullet.bullet_logger = true + Bullet.console = true + Bullet.rails_logger = true + Bullet.add_footer = true + end +end diff --git a/config/environments/production.rb b/config/environments/production.rb index be0b081c2..ade01a168 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'active_support/core_ext/integer/time' + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -20,14 +22,13 @@ Rails.application.configure do # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). # config.require_master_key = true - config.action_controller.default_url_options = { - host: Rails.application.secrets.default_host, - protocol: Rails.application.secrets.default_protocol - } - - # Active serving static files from the `/public` folder by default + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. config.public_file_server.enabled = true + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.asset_host = "http://assets.example.com" + # Specifies the header that your server uses for sending files. # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX @@ -35,28 +36,22 @@ Rails.application.configure do # Store uploaded files on the local file system (see config/storage.yml for options) config.active_storage.service = :local - # Mount Action Cable outside main process or domain - # config.action_cable.mount_path = nil - # config.action_cable.url = 'wss://example.com/cable' - # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Use the lowest log level to ensure availability of diagnostic information - # when problems arise. - # config.log_level = :debug - config.log_level = ENV.fetch('LOG_LEVEL') { :debug }.to_sym + # Include generic and useful information about system operation, but avoid logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). + config.log_level = ENV.fetch('LOG_LEVEL', :info).to_sym # Prepend all log lines with the following tags. - # config.log_tags = [ :request_id ] + config.log_tags = [:request_id] # Use a different cache store in production. # config.cache_store = :mem_cache_store - # Use a real queuing backend for Active Job (and separate queues per environment) + # Use a real queuing backend for Active Job (and separate queues per environment). # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "fablab_#{Rails.env}" + # config.active_job.queue_name_prefix = "fab_manager_#{Rails.env}" config.action_mailer.perform_caching = false @@ -67,6 +62,7 @@ Rails.application.configure do # config.action_mailer.perform_deliveries = true # config.action_mailer.raise_delivery_errors = false # config.action_mailer.default :charset => "utf-8" + config.action_mailer.smtp_settings = { address: Rails.application.secrets.smtp_address, port: Rails.application.secrets.smtp_port, @@ -79,6 +75,7 @@ Rails.application.configure do ca_file: Rails.application.secrets.smtp_ca_file, ca_path: Rails.application.secrets.smtp_ca_path } + # use :smtp for switch prod config.action_mailer.delivery_method = Rails.application.secrets.delivery_method.to_sym @@ -86,8 +83,8 @@ Rails.application.configure do # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify + # Don't log any deprecations. + config.active_support.report_deprecations = false # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new @@ -97,11 +94,16 @@ Rails.application.configure do # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') if ENV['RAILS_LOG_TO_STDOUT'].present? - logger = ActiveSupport::Logger.new(STDOUT) + logger = ActiveSupport::Logger.new($stdout) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) end # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false + + config.action_controller.default_url_options = { + host: Rails.application.secrets.default_host, + protocol: Rails.application.secrets.default_protocol + } end diff --git a/config/environments/staging.rb b/config/environments/staging.rb index 72470851a..7115361f8 100644 --- a/config/environments/staging.rb +++ b/config/environments/staging.rb @@ -1,95 +1,3 @@ # frozen_string_literal: true -Rails.application.configure do - # Settings specified here will take precedence over those in config/application.rb. - - # Code is not reloaded between requests. - config.cache_classes = true - - # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both threaded web servers - # and those relying on copy on write to perform better. - # Rake tasks automatically ignore this option for performance. - config.eager_load = true - - # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false - config.action_controller.perform_caching = true - - config.action_controller.default_url_options = { - host: Rails.application.secrets.default_host, - protocol: Rails.application.secrets.default_protocol - } - - # Enable Rack::Cache to put a simple HTTP cache in front of your application - # Add `rack-cache` to your Gemfile before enabling this. - # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. - # config.action_dispatch.rack_cache = true - - - # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx - - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true - - # Set to :debug to see everything in the log. - config.log_level = Rails.application.secrets.log_level.blank? ? :debug : Rails.application.secrets.log_level - - # Prepend all log lines with the following tags. - # config.log_tags = [ :subdomain, :uuid ] - - # Use a different logger for distributed setups. - # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) - - # Use a different cache store in production. - # config.cache_store = :mem_cache_store - - # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = "http://assets.example.com" - - # Precompile additional assets. - # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. - # config.assets.precompile += %w( search.js ) - - # Ignore bad email addresses and do not raise email delivery errors. - # Set this to true and configure the email server for immediate delivery to raise delivery errors. - # config.action_mailer.raise_delivery_errors = false - - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify - - # Disable automatic flushing of the log to improve performance. - # config.autoflush_log = false - - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Active serving static files from the `/public` folder by default - config.public_file_server.enabled = true - - config.action_mailer.default_url_options = { - host: Rails.application.secrets.default_host, - protocol: Rails.application.secrets.default_protocol - } - # config.action_mailer.perform_deliveries = true - # config.action_mailer.raise_delivery_errors = false - # config.action_mailer.default :charset => "utf-8" - - config.action_mailer.smtp_settings = { - address: Rails.application.secrets.smtp_address, - port: Rails.application.secrets.smtp_port, - user_name: Rails.application.secrets.smtp_user_name, - password: Rails.application.secrets.smtp_password, - authentication: Rails.application.secrets.smtp_authentication, - enable_starttls_auto: Rails.application.secrets.smtp_enable_starttls_auto, - openssl_verify_mode: Rails.application.secrets.smtp_openssl_verify_mode, - tls: Rails.application.secrets.smtp_tls - } - - # use :smtp for switch prod - config.action_mailer.delivery_method = Rails.application.secrets.delivery_method.to_sym - -end - +require_relative './production' diff --git a/config/environments/test.rb b/config/environments/test.rb index 8216f4881..8243642ff 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,18 +1,22 @@ # frozen_string_literal: true +require 'active_support/core_ext/integer/time' + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # The test environment is used exclusively to run your application's - # test suite. You never need to work with it otherwise. Remember that - # your test database is "scratch space" for the test suite and is wiped - # and recreated between test runs. Don't rely on the data there! - config.cache_classes = true + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = false - # Do not eager load code on boot. This avoids loading your whole application - # just for the purpose of running a single test. If you are using a tool that - # preloads Rails for running tests, you may have to set it to true. - config.eager_load = false + # Eager loading loads your whole application. When running a single test locally, + # this probably isn't necessary. It's a good idea to do in a continuous integration + # system, or in some way before deploying your code. + config.eager_load = ENV['CI'].present? # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true @@ -23,11 +27,7 @@ Rails.application.configure do # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - - config.action_controller.default_url_options = { - host: Rails.application.secrets.default_host, - protocol: Rails.application.secrets.default_protocol - } + config.cache_store = :null_store # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false @@ -35,7 +35,7 @@ Rails.application.configure do # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false - # Store uploaded files on the local file system in a temporary directory + # Store uploaded files on the local file system in a temporary directory. config.active_storage.service = :test config.action_mailer.perform_caching = false @@ -48,11 +48,18 @@ Rails.application.configure do # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - # Raises error for missing translations - # config.action_view.raise_on_missing_translations = true + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] config.active_job.queue_adapter = :test config.active_support.test_order = :random - config.log_level = Rails.application.secrets.log_level.blank? ? :debug : Rails.application.secrets.log_level -end + config.log_level = ENV.fetch('LOG_LEVEL', :debug).to_sym + config.action_controller.default_url_options = { + host: Rails.application.secrets.default_host, + protocol: Rails.application.secrets.default_protocol + } +end diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index e5bd6c449..4bfa29400 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -2,18 +2,19 @@ # 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 +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header -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, :wss, 'http://localhost:3035', 'ws://localhost:3035' if Rails.env.development? +Rails.application.configure do + config.content_security_policy do |policy| + # If you are using webpack-dev-server then specify webpack-dev-server host + policy.connect_src :self, :https, :wss, 'http://localhost:3035', 'ws://localhost:3035' if Rails.env.development? + end + # # Generate session nonces for permitted importmap and inline scripts + # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } + # config.content_security_policy_nonce_directives = %w(script-src) + # + # # Report violations without enforcing the policy. + # # config.content_security_policy_report_only = true end - -# If you are using UJS then enable automatic nonce generation -# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } - -# Report CSP violations to a specified URI -# For further information see the following documentation: -# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only -# Rails.application.config.content_security_policy_report_only = true diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 0afb3b735..c2f2faceb 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -8,7 +8,7 @@ Devise.setup do |config| # confirmation, reset password and unlock tokens in the database. # Devise will use the `secret_key_base` on Rails 4+ applications as its `secret_key` # by default. You can change it below and use your own secret key. - # config.secret_key = 'f0ad7aadec8086b90c0427e734602262e5d211147f3d93b5b94b5263ffd245e9fd9fcd672dcadea1d9ee2b1bffbf2712cdb013883d66943ef5bed93a263fe11a' + # config.secret_key = 'f0ad7aadec8086b90c0427e734602262e5d211147f3d93b5b94b5263ffd245e9fd9fcd672dcadea1d9ee2b1bffbf2712cdb013883d66943ef5bed9' # ==> Mailer Configuration # Configure the class responsible to send e-mails. @@ -94,7 +94,7 @@ Devise.setup do |config| config.stretches = Rails.env.test? ? 1 : 10 # Setup a pepper to generate the encrypted password. - # config.pepper = 'af74f5ee4fe6f0156f5bbb843cdde2ce883df1cc97988ee7a88e9db28c07f7bb233d98e342e13151a2d2600ab1cd4ea405c1302dfced3d962739118c61225c80' + # config.pepper = 'af74f5ee4fe6f0156f5bbb843cdde2ce883df1cc97988ee7a88e9db28c07f7bb233d98e342e13151a2d2600ab1cd4ea405c1302dfced3d962739118c' # ==> Configuration for :confirmable # A period that the user is allowed to access the website even without @@ -227,17 +227,24 @@ Devise.setup do |config| # Add a new OmniAuth provider. Check the wiki for more information on setting # up on your models and hooks. # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' + active_provider = Rails.configuration.auth_provider + unless active_provider.nil? + # noinspection RubyCaseWithoutElseBlockInspection + case active_provider.providable_type + when 'OAuth2Provider' + require_relative '../../lib/omni_auth/oauth2' + config.omniauth active_provider.strategy_name.to_sym, + active_provider.providable.client_id, + active_provider.providable.client_secret, + strategy_class: OmniAuth::Strategies::SsoOauth2Provider - active_provider = AuthProvider.active - if active_provider.providable_type == OAuth2Provider.name - require_relative '../../lib/omni_auth/oauth2' - config.omniauth OmniAuth::Strategies::SsoOauth2Provider.name.to_sym, - active_provider.providable.client_id, - active_provider.providable.client_secret - elsif active_provider.providable_type == OpenIdConnectProvider.name - require_relative '../../lib/omni_auth/openid_connect' - config.omniauth OmniAuth::Strategies::SsoOpenidConnectProvider.name.to_sym, - active_provider.providable.config + when 'OpenIdConnectProvider' + require_relative '../../lib/omni_auth/openid_connect' + config.omniauth active_provider.strategy_name.to_sym, + active_provider.oidc_config.merge( + strategy_class: OmniAuth::Strategies::SsoOpenidConnectProvider + ) + end end # ==> Warden configuration diff --git a/config/initializers/devise_mailer.rb b/config/initializers/devise_mailer.rb index cd595d25b..b01e7deeb 100644 --- a/config/initializers/devise_mailer.rb +++ b/config/initializers/devise_mailer.rb @@ -1,3 +1,7 @@ -Devise::Mailer.class_eval do - helper :application -end \ No newline at end of file +# frozen_string_literal: true + +Rails.application.reloader.to_prepare do + Devise::Mailer.class_eval do + helper :application + end +end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 4a994e1e7..7a0c4b23f 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,4 +1,10 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. -# Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [:password] +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += %i[ + password passw secret token _key crypt salt certificate otp ssn +] diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb new file mode 100644 index 000000000..810aadeb9 --- /dev/null +++ b/config/initializers/permissions_policy.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# Define an application-wide HTTP permissions policy. For further +# information see https://developers.google.com/web/updates/2018/06/feature-policy +# +# Rails.application.config.permissions_policy do |f| +# f.camera :none +# f.gyroscope :none +# f.microphone :none +# f.usb :none +# f.fullscreen :self +# f.payment :self, "https://secure.example.com" +# end diff --git a/config/initializers/postgresql_database_tasks.rb b/config/initializers/postgresql_database_tasks.rb index 4616148e7..811dd88d3 100644 --- a/config/initializers/postgresql_database_tasks.rb +++ b/config/initializers/postgresql_database_tasks.rb @@ -1,21 +1,17 @@ # frozen_string_literal: true -module ActiveRecord - module Tasks - # The following magic allows to drop a PG database even if a connection exists - # @see https://stackoverflow.com/a/38710021 - class PostgreSQLDatabaseTasks - include ActiveRecord::Sanitization::ClassMethods +# The following magic allows to drop a PG database even if a connection exists +# @see https://stackoverflow.com/a/38710021 +class ActiveRecord::Tasks::PostgreSQLDatabaseTasks + include ActiveRecord::Sanitization::ClassMethods - def drop - establish_master_connection - q = sanitize_sql_array [ - "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname= ? AND state='idle';", - configuration['database'] - ] - connection.select_all q - connection.drop_database configuration['database'] - end - end + def drop + establish_master_connection + q = sanitize_sql_array [ + "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname= ? AND state='idle';", + configuration_hash[:database] + ] + connection.select_all q + connection.drop_database configuration_hash[:database] end end diff --git a/config/locales/app.admin.it.yml b/config/locales/app.admin.it.yml new file mode 100644 index 000000000..17b5c89d6 --- /dev/null +++ b/config/locales/app.admin.it.yml @@ -0,0 +1,2449 @@ +it: + app: + admin: + edit_destroy_buttons: + deleted: "Successfully deleted." + unable_to_delete: "Unable to delete: " + delete_item: "Delete the {TYPE}" + confirm_delete: "Delete" + delete_confirmation: "Are you sure you want to delete this {TYPE}?" + machines: + the_fablab_s_machines: "The FabLab's machines" + all_machines: "All machines" + add_a_machine: "Add a new machine" + manage_machines_categories: "Manage machines categories" + machines_settings: "Settings" + machines_settings: + title: "Settings" + generic_text_block: "Editorial text block" + generic_text_block_info: "Displays an editorial block above the list of machines visible to members." + generic_text_block_switch: "Display editorial block" + cta_switch: "Display a button" + cta_label: "Button label" + cta_url: "url" + save: "Save" + successfully_saved: "Your banner was successfully saved." + machine_categories_list: + machine_categories: "Machines categories" + add_a_machine_category: "Add a machine category" + name: "Name" + machines_number: "Number of machines" + machine_category: "Machine category" + machine_category_modal: + new_machine_category: "New category" + edit_machine_category: "Edit category" + successfully_created: "The new machine category has been successfully created." + unable_to_create: "Unable to delete the machine category: " + successfully_updated: "The machine category has been successfully updated." + unable_to_update: "Unable to modify the machine category: " + machine_category_form: + name: "Name of category" + assigning_machines: "Assign machines to this category" + save: "Save" + machine_form: + ACTION_title: "{ACTION, select, create{New} other{Update the}} machine" + watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions: "Watch out! When creating a new machine, its prices are initialized at 0 for all subscriptions." + consider_changing_them_before_creating_any_reservation_slot: "Consider changing them before creating any reservation slot." + description: "Description" + name: "Name" + illustration: "Visual" + technical_specifications: "Technical specifications" + category: "Category" + attachments: "Attachments" + attached_files_pdf: "Attached files (pdf)" + add_an_attachment: "Add an attachment" + settings: "Settings" + disable_machine: "Disable machine" + disabled_help: "When disabled, the machine won't be reservable and won't appear by default in the machines list." + reservable: "Can this machine be reserved?" + reservable_help: "When disabled, the machine will be shown in the default list of machines, but without the reservation button. If you already have created some availability slots for this machine, you may want to remove them: do it from the admin agenda." + save: "Save" + create_success: "The machine was created successfully" + update_success: "The machine was updated successfully" + training_form: + ACTION_title: "{ACTION, select, create{New} other{Update the}} training" + beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero." + dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training." + description: "Description" + name: "Name" + illustration: "Illustration" + add_a_new_training: "Add a new training" + validate_your_training: "Validate your training" + settings: "Settings" + associated_machines: "Associated machines" + associated_machines_help: "If you associate a machine to this training, the members will need to successfully pass this training before being able to reserve the machine." + default_seats: "Default number of seats" + public_page: "Show in training lists" + public_help: "When unchecked, this option will prevent the training from appearing in the trainings list." + disable_training: "Disable the training" + disabled_help: "When disabled, the training won't be reservable and won't appear by default in the trainings list." + automatic_cancellation: "Automatic cancellation" + automatic_cancellation_info: "If you edit specific conditions here, the general cancellation conditions will no longer be taken into account. You will be notified if a session is cancelled. Credit notes and refunds will be automatic if the wallet is enabled. Otherwise you will have to do it manually." + automatic_cancellation_switch: "Activate automatic cancellation for this training" + automatic_cancellation_threshold: "Minimum number of registrations to maintain a session" + automatic_cancellation_deadline: "Deadline, in hours, before automatic cancellation" + authorization_validity: "Authorisations validity period" + authorization_validity_info: "You can define a specific validity period in months for this training. The general conditions will no longer be taken into account." + authorization_validity_switch: "Activate an authorization validity period" + authorization_validity_period: "Validity period in months" + validation_rule: "Authorisations cancellation rule" + validation_rule_info: "Define a rule that cancel an authorisation if the machines associated with the training are not reserved for a specific period of time. This rule prevails over the authorisations validity period." + validation_rule_switch: "Activate the validation rule" + validation_rule_period: "Time limit in months" + save: "Save" + create_success: "The training was created successfully" + update_success: "The training was updated successfully" + space_form: + ACTION_title: "{ACTION, select, create{New} other{Update the}} space" + watch_out_when_creating_a_new_space_its_prices_are_initialized_at_0_for_all_subscriptions: "Watch out! When creating a new space, its prices are initialized at 0 for all subscriptions." + consider_changing_its_prices_before_creating_any_reservation_slot: "Consider changing its prices before creating any reservation slot." + name: "Name" + illustration: "Illustration" + description: "Description" + characteristics: "Characteristics" + attachments: "Attachments" + attached_files_pdf: "Attached files (pdf)" + add_an_attachment: "Add an attachment" + settings: "Settings" + default_seats: "Default number of seats" + disable_space: "Disable the space" + disabled_help: "When disabled, the space won't be reservable and won't appear by default in the spaces list." + save: "Save" + create_success: "The space was created successfully" + update_success: "The space was updated successfully" + event_form: + ACTION_title: "{ACTION, select, create{New} other{Update the}} event" + title: "Title" + matching_visual: "Matching visual" + description: "Description" + attachments: "Attachments" + attached_files_pdf: "Attached files (pdf)" + add_a_new_file: "Add a new file" + event_category: "Event category" + dates_and_opening_hours: "Dates and opening hours" + all_day: "All day" + all_day_help: "Will the event last all day or do you want to set times?" + start_date: "Start date" + end_date: "End date" + start_time: "Start time" + end_time: "End time" + recurrence: "Recurrence" + _and_ends_on: "and ends on" + prices_and_availabilities: "Prices and availabilities" + standard_rate: "Standard rate" + 0_equal_free: "0 = free" + fare_class: "Fare class" + price: "Price" + seats_available: "Seats available" + seats_help: "If you leave this field empty, this event will be available without reservations." + event_themes: "Event themes" + age_range: "Age range" + add_price: "Add a price" + save: "Save" + create_success: "The event was created successfully" + events_updated: "{COUNT, plural, =1{One event was} other{{COUNT} Events were}} successfully updated" + events_not_updated: "{TOTAL, plural, =1{The event was} other{On {TOTAL} events {COUNT, plural, =1{one was} other{{COUNT} were}}}} not updated." + error_deleting_reserved_price: "Unable to remove the requested price because it is associated with some existing reservations" + other_error: "An unexpected error occurred while updating the event" + recurring: + none: "None" + every_days: "Every days" + every_week: "Every week" + every_month: "Every month" + every_year: "Every year" + plan_form: + ACTION_title: "{ACTION, select, create{New} other{Update the}} plan" + tab_settings: "Settings" + tab_usage_limits: "Usage limits" + description: "Description" + general_settings: "General settings" + general_settings_info: "Determine to which group this subscription is dedicated. Also set its price and duration in periods." + activation_and_payment: "Subscription activation and payment" + name: "Name" + name_max_length: "Name length must be less than 24 characters." + group: "Group" + transversal: "Transversal plan" + transversal_help: "If this option is checked, a copy of this plan will be created for each currently enabled groups." + display: "Display" + category: "Category" + category_help: "Categories allow you to group the subscription plans, on the public view of the subscriptions." + number_of_periods: "Number of periods" + period: "Period" + year: "Year" + month: "Month" + week: "Week" + subscription_price: "Subscription price" + edit_amount_info: "Please note that if you change the price of this plan, the new price will only apply to new subscribers. Current subscriptions will stay unchanged, even those with a running payment schedule." + visual_prominence: "Visual prominence of the subscription" + visual_prominence_help: "On the subscriptions page, the most prominent subscriptions will be placed at the top of the list. An elevated number means a higher prominence." + rolling_subscription: "Rolling subscription?" + rolling_subscription_help: "A rolling subscription will begin the day of the first trainings. Otherwise, it will begin as soon as it is bought." + monthly_payment: "Monthly payment?" + monthly_payment_help: "If monthly payment is enabled, the members will be able to choose between a one-time payment or a payment schedule staged each months." + information_sheet: "Information sheet" + notified_partner: "Notified partner" + new_user: "New user" + alert_partner_notification: "As part of a partner subscription, some notifications may be sent to this user." + disabled: "Disable subscription" + disabled_help: "Beware: disabling this plan won't unsubscribe users having active subscriptions with it." + duration: "Duration" + partnership: "Partnership" + partner_plan: "Partner plan" + partner_plan_help: "You can sell subscriptions in partnership with another organization. By doing so, the other organization will be notified when a member subscribes to this subscription plan." + partner_created: "The partner was successfully created" + slots_visibility: "Slots visibility" + slots_visibility_help: "You can determine how far in advance subscribers can view and reserve machine slots. When this setting is set, it takes precedence over the general settings." + machines_visibility: "Visibility time limit, in hours (machines)" + visibility_minimum: "Visibility cannot be less than 7 hours" + save: "Save" + create_success: "Plan(s) successfully created. Don't forget to redefine prices." + update_success: "The plan was updated successfully" + plan_limit_form: + usage_limitation: "Limitation of use" + usage_limitation_info: "Define a maximum number of reservation hours per day and per machine category. Machine categories that have no parameters configured will not be subject to any limitation." + usage_limitation_switch: "Restrict machine reservations to a number of hours per day." + new_usage_limitation: "Add a limitation of use" + all_limitations: "All limitations" + by_category: "By machines category" + by_machine: "By machine" + category: "Machines category" + machine: "Machine name" + max_hours_per_day: "Max. hours/day" + ongoing_limitations: "Ongoing limitations" + saved_limitations: "Saved limitations" + cancel: "Cancel this limitation" + cancel_deletion: "Cancel" + ongoing_deletion: "Ongoing deletion" + plan_limit_modal: + title: "Manage limitation of use" + limit_reservations: "Limit reservations" + by_category: "By machines category" + by_machine: "By machine" + category: "Machines category" + machine: "Machine name" + categories_info: "If you select all machine categories, the limits will apply across the board." + machine_info: "Please note that if you have already created a limitation for the machines category including the selected machine, it will be permanently overwritten." + max_hours_per_day: "Maximum number of reservation hours per day" + confirm: "Confirm" + partner_modal: + title: "Create a new partner" + create_partner: "Create the partner" + first_name: "First name" + surname: "Last name" + email: "Email address" + plan_pricing_form: + prices: "Prices" + about_prices: "The prices defined here will apply to members subscribing to this plan, for machines and spaces. All prices are per hour." + copy_prices_from: "Copy prices from" + copy_prices_from_help: "This will replace all the prices of this plan with the prices of the selected plan" + machines: "Machines" + spaces: "Spaces" + update_recurrent_modal: + title: "Periodic event 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 followings" + edit_all: "All events" + date_wont_change: "Warning: you have changed the event date. This modification won't be propagated to other occurrences of the periodic event." + confirm: "Update the {MODE, select, single{event} other{events}}" + advanced_accounting_form: + title: "Advanced accounting parameters" + code: "Accounting code" + analytical_section: "Analytical section" + accounting_codes_settings: + code: "Accounting code" + label: "Account label" + journal_code: "Journal code" + sales_journal: "Sales journal" + financial: "Financial" + card: "Card payments" + wallet_debit: "Virtual wallet payments" + other: "Other payment means" + wallet_credit: "Virtual wallet credit" + VAT: "VAT" + sales: "Sales" + subscriptions: "Subscriptions" + machine: "Machine reservation" + training: "Training reservation" + event: "Event reservation" + space: "Space reservation" + prepaid_pack: "Pack of prepaid-hours" + product: "Product of the store" + error: "Erroneous invoices" + error_help: "As part of a maintenance operation, it may exceptionally happen that invoices, that have been generated by mistake due to a bug in the software, are discovered. As these invoices cannot be deleted, they will be exported to the account defined here. Please manually cancel these invoices." + advanced_accounting: "Advanced accounting" + enable_advanced: "Enable the advanced accounting" + enable_advanced_help: "This will enable the ability to have custom accounting codes per resources (machines, spaces, training ...). These codes can be modified on each resource edition form." + save: "Save" + update_success: "The accounting settings were successfully updated" + #add a new machine + machines_new: + declare_a_new_machine: "Declare a new machine" + #machine edition + machines_edit: + machine_edit: "Edit a machine" + #manage the trainings & machines slots + calendar: + calendar_management: "Calendar management" + trainings: "Trainings" + machines: "Machines" + spaces: "Spaces" + events: "Events" + availabilities: "Availabilities" + availabilities_notice: "Export to an Excel workbook every slots available for reservation, and their occupancy rate." + select_a_slot: "Please select a slot" + info: "Info" + tags: "Tags" + slot_duration: "Slot duration: {DURATION} minutes" + 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 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." + do_you_really_want_to_remove_MACHINE_from_this_slot: "Do you really want to remove \"{MACHINE}\" from this slot?" + this_will_prevent_any_new_reservation_on_this_slot_but_wont_cancel_those_existing: "This will prevent any new reservation on this slot but won't cancel those existing." + beware_this_cannot_be_reverted: "Beware: this cannot be reverted." + the_machine_was_successfully_removed_from_the_slot: "The machine was successfully removed from the slot." + deletion_failed: "Deletion failed." + do_you_really_want_to_remove_PLAN_from_this_slot: "Do you really want to remove \"{PLAN}\" from this slot?" + the_plan_was_successfully_removed_from_the_slot: "The plan was successfully removed from the slot." + DATE_slot: "{DATE} slot:" + what_kind_of_slot_do_you_want_to_create: "What kind of slot do you want to create?" + training: "Training" + machine: "Machine" + space: "Space" + next: "Next >" + previous: "< Previous" + select_some_machines: "Select some machines" + select_all: "All" + select_none: "None" + manage_machines: "Click here to add or remove machines." + manage_spaces: "Click here to add or remove spaces." + manage_trainings: "Click here to add or remove trainings." + number_of_tickets: "Number of tickets: " + adjust_the_opening_hours: "Adjust the opening hours" + to_time: "to" #e.g. from 18:00 to 21:00 + restrict_options: "Restriction options" + restrict_with_labels: "Restrict this slot with labels" + restrict_for_subscriptions: "Restrict this slot for subscription users" + select_some_plans: "Select some plans" + plans: "Plan(s):" + recurrence: "Recurrence" + enabled: "Enabled" + period: "Period" + week: "Week" + month: "Month" + number_of_periods: "Number of periods" + end_date: "End date" + summary: "Summary" + select_period: "Please select a period for the recurrence" + select_nb_period: "Please select a number of periods for the recurrence" + select_end_date: "Please select the date of the last occurrence" + about_to_create: "You are about to create the following {TYPE, select, machines{machine} training{training} space{space} other{other}} {NUMBER, plural, one{slot} other{slots}}:" + divided_in_slots: "{COUNT, plural, =1{This slot} other{These slots}} will be open for booking in {DURATION}-minutes increments." + reservable: "Reservable(s):" + labels: "Label(s):" + none: "None" + slot_successfully_deleted: "The slot {START} - {END} has been successfully deleted" + slots_deleted: "The slot of {START}, and {COUNT, plural, =1{one other} other{{COUNT} others}}, have been deleted" + unable_to_delete_the_slot: "Unable to delete the slot {START} - {END}, probably because it's already reserved by a member" + slots_not_deleted: "On {TOTAL} slots, {COUNT, plural, =1{one was not deleted} other{{COUNT} were not deleted}}. Some reservations may exist on {COUNT, plural, =1{it} other{them}}." + you_should_select_at_least_a_machine: "You should select at least one machine on this slot." + inconsistent_times: "Error: the end of the availability is before its beginning." + 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." + export_is_running_you_ll_be_notified_when_its_ready: "Export is running. You'll be notified when it's ready." + actions: "Actions" + block_reservations: "Block reservations" + do_you_really_want_to_block_this_slot: "Do you really want to block new reservations on this slot? It will become invisible to users." + locking_success: "Slot successfully locked, it won't appear any longer in the user calendar" + locking_failed: "An error occurred. Slot locking has failed" + allow_reservations: "Allow reservations" + do_you_really_want_to_allow_reservations: "Do you really want to allow booking again on this slot? It will become visible for the users." + unlocking_success: "Slot successfully unlocked, it will appear again in the user calendar" + unlocking_failed: "An error occurred. Slot unlocking has failed" + reservations_locked: "Booking is blocked" + unlockable_because_reservations: "Unable to block booking on this slot because some uncancelled reservations exist on it." + delete_slot: "Delete this slot" + do_you_really_want_to_delete_this_slot: "Do you really want to delete this slot?" + delete_recurring_slot: "You're about to delete a recurring slot. What do you want to do?" + delete_this_slot: "Only this slot" + delete_this_and_next: "This slot and the following" + delete_all: "All 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." + edit_event: "Edit the event" + view_reservations: "View reservations" + legend: "Legend" + and: "and" + external_sync: "Calendar synchronization" + divide_this_availability: "Divide this availability in" + slots: "slots" + slots_of: "of" + minutes: "minutes" + deleted_user: "Deleted user" + select_type: "Please select a type to continue" + no_modules_available: "No reservable module available. Please enable at least one module (machines, spaces or trainings) in the Customization section." + #import external iCal calendar + icalendar: + icalendar_import: "iCalendar import" + intro: "Fab-manager allows to automatically import calendar events, at RFC 5545 iCalendar format, from external URL. These URL are synchronized every hours and the events are shown in the public calendar. You can trigger a synchronisation too, by clicking on the corresponding button, in front of each import." + new_import: "New ICS import" + color: "Colour" + text_color: "Text colour" + url: "URL" + name: "Name" + example: "Example" + display: "Display" + hide_text: "Hide the text" + hidden: "Hidden" + shown: "Shown" + create_error: "Unable to create iCalendar import. Please try again later" + delete_failed: "Unable to delete the iCalendar import. Please try again later" + refresh: "Updating..." + sync_failed: "Unable to synchronize the URL. Please try again later" + confirmation_required: "Confirmation required" + confirm_delete_import: "Do you really want to delete this iCalendar import?" + delete_success: "iCalendar import successfully deleted" + #management of the projects' components & settings + projects: + name: "Name" + projects_settings: "Projects settings" + materials: "Materials" + add_a_material: "Add a material" + themes: "Themes" + add_a_new_theme: "Add a new theme" + licences: "Licences" + statuses: "Statuses" + description: "Description" + add_a_new_licence: "Add a new licence" + manage_abuses: "Manage the reports" + settings: + title: "Settings" + comments: "Comments" + disqus: "Disqus" + disqus_info: "If you want to enable your members and visitors to comment on projects, you can enable the Disqus forums by setting the following parameter. Visit the Disqus website for more information." + shortname: "Shortname" + cad_files: "CAD files" + validation: "Validation" + validation_info: "Users can upload CAD (Computer Aided Design) files with the documentation of their projects. You can specify which files types are allowed. Use the test input below to determine the MIME type of a file." + extensions: "Allowed extensions" + new_extension: "New extension" + new_ext_info_html: "

Specify a new file extension to allow these files to be uploaded.

Please consider that allowing file archives (eg. ZIP) or binary executable (eg. EXE) may result in a dangerous security issue and must be avoided in any cases.

" + mime_types: "Allowed MIME types" + new_mime_type: "New MIME type" + new_type_info_html: "

Specify a new MIME type to allow these files to be uploaded.

Please use the test input to determine the MIME type of a file. Please consider that allowing file archives (eg. application/zip) or binary executable (eg. application/exe) may result in a dangerous security issue and must be avoided in any cases.

" + test_file: "Test a file" + set_a_file: "Select a file" + file_is_TYPE: "MIME type of this file is {TYPE}" + projects_sharing: "Projects sharing" + open_lab_projects: "OpenLab Projects" + open_lab_info_html: "Enable OpenLab to share your projects with other Fab Labs and display a gallery of shared projects. Please send an email to contact@fab-manager.com to get your access credentials for free." + open_lab_app_id: "ID" + open_lab_app_secret: "Secret" + openlab_default_info_html: "In the projects gallery, visitors can switch between two views: all shared projets from the whole OpenLab network, or only the projects documented in your Fab Lab.
Here, you can choose which view is shown by default." + default_to_openlab: "Display OpenLab by default" + projects_setting: + add: "Add" + actions_controls: "Actions" + name: "Name" + projects_setting_option: + edit: "Edit" + delete_option: "Delete Option" + projects_setting_option_form: + name: "Name" + description: "Description" + name_cannot_be_blank: "Name cannot be blank." + save: "Save" + cancel: "Cancel" + status_settings: + option_create_success: "Status was successfully created." + option_delete_success: "Status was successfully deleted." + option_update_success: "Status was successfully updated." + #track and monitor the trainings + trainings: + trainings_monitoring: "Trainings monitoring" + all_trainings: "All trainings" + add_a_new_training: "Add a new training" + name: "Training name" + associated_machines: "Associated machines" + cancellation: "Cancellation (attendees | deadline)" + cancellation_minimum: "{ATTENDEES} minimum" + cancellation_deadline: "{DEADLINE} h" + capacity: "Capacity (max. attendees)" + authorisation: "Time-limited authorisation" + period_MONTH: "{MONTH} {MONTH, plural, one{month} other{months}}" + active_true: "Yes" + active_false: "No" + validation_rule: "Lapsed without reservation" + select_a_training: "Select a training" + training: "Training" + date: "Date" + year_NUMBER: "Year {NUMBER}" + month_of_NAME: "Month of {NAME}" + NUMBER_reservation: "{NUMBER} {NUMBER, plural, one{reservation} other{reservations}}" + none: "None" + training_validation: "Training validation" + training_of_the_DATE_TIME_html: "Training of the {DATE} - {TIME}" + 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" + validate_the_trainings: "Validate the trainings" + edition_of_the_description_tooltip: "Edition of the description tooltip" + describe_the_training_in_a_few_words: "Describe the training in a few words." + description_is_limited_to_255_characters: "Description is limited to 255 characters." + description_was_successfully_saved: "Description was successfully saved." + training_successfully_deleted: "Training successfully deleted." + unable_to_delete_the_training_because_some_users_already_booked_it: "Unable to delete the training because some users already booked it." + confirmation_required: "Confirmation required" + do_you_really_want_to_delete_this_training: "Do you really want to delete this training?" + filter_status: "Filter:" + status_enabled: "Enabled" + status_disabled: "Disabled" + status_all: "All" + trainings_settings: "Settings" + #create a new training + trainings_new: + add_a_new_training: "Add a new training" + trainings_settings: + title: "Settings" + automatic_cancellation: "Trainings automatic cancellation" + automatic_cancellation_info: "Minimum number of participants required to maintain a session. You will be notified if a session is cancelled. Credit notes and refunds will be automatic if the wallet is enabled. Otherwise you will have to do it manually." + automatic_cancellation_switch: "Activate automatic cancellation for all the trainings" + automatic_cancellation_threshold: "Minimum number of registrations to maintain a session" + must_be_positive: "You must specify a number above or equal to 0" + automatic_cancellation_deadline: "Deadline, in hours, before automatic cancellation" + must_be_above_zero: "You must specify a number above or equal to 1" + authorization_validity: "Authorisations validity period" + authorization_validity_info: "Define a validity period for all training authorisations. After this period, the authorisation will lapse" + authorization_validity_switch: "Activate an authorization validity period" + authorization_validity_period: "Validity period in months" + validation_rule: "Authorisations cancellation rule" + validation_rule_info: "Define a rule that cancel an authorisation if the machines associated with the training are not reserved for a specific period of time. This rule prevails over the authorisations validity period." + validation_rule_switch: "Activate the validation rule" + validation_rule_period: "Time limit in months" + generic_text_block: "Editorial text block" + generic_text_block_info: "Displays an editorial block above the list of trainings visible to members." + generic_text_block_switch: "Display editorial block" + cta_switch: "Display a button" + cta_label: "Button label" + cta_url: "url" + save: "Save" + update_success: "The trainings settings were successfully updated" + #events tracking and management + events: + settings: "Settings" + events_monitoring: "Events monitoring" + manage_filters: "Manage filters" + fablab_events: "Fablab events" + add_an_event: "Add an event" + all_events: "All events" + passed_events: "Passed events" + events_to_come: "Events to come" + events_to_come_asc: "Events to come | chronological order" + on_DATE: "on {DATE}" + from_DATE: "from {DATE}" + from_TIME: "from {TIME}" + to_date: "to" #e.g.: from 01/01 to 01/05 + to_time: "to" #e.g. from 18:00 to 21:00 + title: "Title" + dates: "Dates" + booking: "Booking" + sold_out: "Sold out" + cancelled: "Cancelled" + without_reservation: "Without reservation" + free_admission: "Free admission" + view_reservations: "View reservations" + load_the_next_events: "Load the next events..." + categories: "Categories" + add_a_category: "Add a category" + name: "Name" + themes: "Theme" + add_a_theme: "Add a theme" + age_ranges: "Age ranges" + add_a_range: "Add a range" + do_you_really_want_to_delete_this_ELEMENT: "Do you really want to delete this {ELEMENT, select, category{category} theme{theme} age_range{age range} other{element}}?" + unable_to_delete_ELEMENT_already_in_use_NUMBER_times: "Unable to delete this {ELEMENT, select, category{category} theme{theme} age_range{age range} other{element}} because it is already associated with {NUMBER, plural, =0{no events} one{one event} other{{NUMBER} events}}." + at_least_one_category_is_required: "At least one category is required." + unable_to_delete_the_last_one: "Unable to delete the last one." + unable_to_delete_an_error_occured: "Unable to delete: an error occurred." + manage_prices_categories: "Manage prices' categories" + prices_categories: "Prices' categories" + add_a_price_category: "Add a price's category" + usages_count: "Usages count" + price_category: "Price category" + category_name: "Category's name" + category_name_is_required: "Category's name is required." + enter_here_the_conditions_under_which_this_price_is_applicable: "Enter here the conditions under which this price is applicable" + conditions_are_required: "Conditions are required." + price_category_successfully_created: "Price category successfully created." + unable_to_add_the_price_category_check_name_already_used: "Unable to add the price category, check that the name is not already used." + unexpected_error_occurred_please_refresh: "An unexpected error occurred, please refresh the page." + price_category_successfully_updated: "Price category successfully updated." + unable_to_update_the_price_category: "Unable to update the price category." + unable_to_delete_this_price_category_because_it_is_already_used: "Unable to delete this price category because it is already used." + do_you_really_want_to_delete_this_price_category: "Do you really want to delete this price category?" + price_category_successfully_deleted: "Price category successfully deleted." + price_category_deletion_failed: "Price category deletion failed." + #add a new event + events_new: + add_an_event: "Add an event" + none: "None" + every_days: "Every days" + every_week: "Every week" + every_month: "Every month" + every_year: "Every year" + #edit an existing event + 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_this_event: "Only this event" + edit_this_and_next: "This event and the following" + edit_all: "All events" + date_wont_change: "Warning: you have changed the event date. This modification won't be propagated to other occurrences of the periodic event." + event_successfully_updated: "Event successfully updated." + events_updated: "The event, and {COUNT, plural, =1{one other} other{{COUNT} others}}, have been updated" + unable_to_update_the_event: "Unable to update the event" + events_not_updated: "On {TOTAL} events, {COUNT, plural, =1{one was not updated} other{{COUNT} were not deleted}}." + error_deleting_reserved_price: "Unable to delete the requested price because it is associated with some reservations" + other_error: "An unexpected error occurred while updating the event" + #event reservations list + event_reservations: + the_reservations: "Reservations:" + user: "User" + payment_date: "Payment date" + full_price_: "Full price:" + reserved_tickets: "Reserved tickets" + show_the_event: "Show the event" + no_reservations_for_now: "No reservation for now." + back_to_monitoring: "Back to monitoring" + canceled: "Canceled" + events_settings: + title: "Settings" + generic_text_block: "Editorial text block" + generic_text_block_info: "Displays an editorial block above the list of events visible to members." + generic_text_block_switch: "Display editorial block" + cta_switch: "Display a button" + cta_label: "Button label" + cta_url: "url" + save: "Save" + update_success: "The events settings were successfully updated" + #subscriptions, prices, credits and coupons management + pricing: + pricing_management: "Pricing management" + subscriptions: "Subscriptions" + trainings: "Trainings" + list_of_the_subscription_plans: "List of the subscription plans" + disabled_plans_info_html: "

Warning: the subscriptions are disabled on this application.

You can still create some, but they won't be available until the activation of the plans module, from the « Customization » section.

" + add_a_new_subscription_plan: "Add a new subscription plan" + name: "Name" + duration: "Duration" + group: "Group" + category: "Category" + prominence: "Prominence" + price: "Price" + machine_hours: "Machine slots" + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + machines: "Machines" + credits: "Credits" + subscription: "Subscription" + related_trainings: "Related trainings" + add_a_machine_credit: "Add a machine credit" + machine: "Machine" + hours: "Slots (default {DURATION} minutes)" + related_subscriptions: "Related subscriptions" + please_specify_a_number: "Please specify a number." + 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_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." + changes_have_been_successfully_saved: "Changes have been successfully saved." + credit_was_successfully_saved: "Credit was successfully saved." + error_creating_credit: "Unable to create credit, an error occurred" + do_you_really_want_to_delete_this_subscription_plan: "Do you really want to delete this subscription plan?" + subscription_plan_was_successfully_deleted: "Subscription plan was successfully deleted." + unable_to_delete_the_specified_subscription_an_error_occurred: "Unable to delete the specified subscription, an error occurred." + coupons: "Coupons" + list_of_the_coupons: "List of the coupons" + discount: "Discount" + nb_of_usages: "Number of usages" + status: "Status" + add_a_new_coupon: "Add a new coupon" + display_more_coupons: "Display the next coupons" + disabled: "Disabled" + expired: "Expired" + sold_out: "Sold out" + active: "Active" + all: "Display all" + confirmation_required: "Confirmation required" + do_you_really_want_to_delete_this_coupon: "Do you really want to delete this coupon?" + coupon_was_successfully_deleted: "Coupon was successfully deleted." + unable_to_delete_the_specified_coupon_already_in_use: "Unable to delete the specified coupon: it is already used with some invoices and/or some payment schedules." + unable_to_delete_the_specified_coupon_an_unexpected_error_occurred: "Unable to delete the specified coupon: an unexpected error occurred." + send_a_coupon: "Send a coupon" + coupon: "Coupon" + usages: "Usages" + unlimited: "Unlimited" + coupon_successfully_sent_to_USER: "Coupon successfully sent to {USER}" + an_error_occurred_unable_to_send_the_coupon: "An unexpected error prevent from sending the coupon." + code: "Code" + enabled: "Enabled" + validity_per_user: "Validity per user" + once: "Just once" + forever: "Each use" + valid_until: "Valid until (included)" + spaces: "Spaces" + these_prices_match_space_hours_rates_html: "The prices below match one hour of space usage, without subscription." + 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." + status_enabled: "Enabled" + status_disabled: "Disabled" + status_all: "All" + spaces_pricing: + prices_match_space_hours_rates_html: "The prices below match one hour of space reservation, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + 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" + machines_pricing: + prices_match_machine_hours_rates_html: "The prices below match one hour of machine usage, without subscription." + prices_calculated_on_hourly_rate_html: "All the prices will be automatically calculated based on the hourly rate defined here.
For example, if you define an hourly rate at {RATE}: a slot of {DURATION} minutes, will be charged {PRICE}." + you_can_override: "You can override this duration for each availability you create in the agenda. The price will then be adjusted accordingly." + machines: "Machines" + price_updated: "Price successfully updated" + configure_packs_button: + pack: "prepaid pack" + packs: "Prepaid packs" + no_packs: "No packs for now" + pack_DURATION: "{DURATION} hours" + 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." + edit_pack: "Edit the pack" + confirm_changes: "Confirm changes" + pack_successfully_updated: "The prepaid pack was successfully updated." + configure_extended_prices_button: + extended_prices: "Extended prices" + no_extended_prices: "No extended price for now" + extended_price_DURATION: "{DURATION} hours" + extended_price_form: + duration: "Duration (hours)" + amount: "Price" + pack_form: + hours: "Hours" + amount: "Price" + disabled: "Disabled" + validity_count: "Maximum validity" + select_interval: "Interval..." + 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}}" + 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." + 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." + 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?" + edit_extended_price: + edit_extended_price: "Edit the extended price" + confirm_changes: "Confirm changes" + extended_price_successfully_updated: "The extended price was successfully updated." + plans_categories: + manage_plans_categories: "Manage plans' categories" + plan_categories_list: + categories_list: "List of the plan's categories" + no_categories: "No categories" + name: "Name" + description: "Description" + significance: "Significance" + manage_plan_category: + create: "New category" + update: "Edit the category" + plan_category_form: + name: "Name" + description: "Description" + significance: "Significance" + info: "Categories will be shown ordered by signifiance. The higher you set the significance, the first the category will be shown." + create: + title: "New category" + cta: "Create the category" + success: "The new category was successfully created" + error: "Unable to create the category: " + update: + title: "Edit the category" + cta: "Validate" + success: "The category was successfully updated" + error: "Unable to update the category: " + delete_plan_category: + title: "Delete a category" + confirm: "Are you sure you want to delete this category? If you do, the plans associated with this category won't be sorted anymore." + cta: "Delete" + success: "The category was successfully deleted" + error: "Unable to delete the category: " + #ajouter un code promotionnel + coupons_new: + add_a_coupon: "Add a coupon" + unable_to_create_the_coupon_check_code_already_used: "Unable to create the coupon. Please check that the code is not already used." + #mettre à jour un code promotionnel + coupons_edit: + coupon: "Coupon:" + unable_to_update_the_coupon_an_error_occurred: "Unable to update the coupon: an error occurred." + plans: + #add a subscription plan on the platform + new: + add_a_subscription_plan: "Add a subscription plan" + #edit a subscription plan / machine slots prices + edit: + subscription_plan: "Subscription plan:" + #list of all invoices & invoicing parameters + invoices: + invoices: "Invoices" + accounting_periods: "Accounting periods" + invoices_list: "Invoices list" + filter_invoices: "Filter invoices" + operator_: "Operator:" + invoice_num_: "Invoice #:" + customer_: "Customer:" + date_: "Date:" + invoice_num: "Invoice #" + date: "Date" + price: "Price" + customer: "Customer" + download_the_invoice: "Download the invoice" + download_the_credit_note: "Download the credit note" + credit_note: "Credit note" + display_more_invoices: "Display more invoices..." + no_invoices_for_now: "No invoices for now." + payment_schedules: "Payment schedules" + invoicing_settings: "Invoicing settings" + edit_setting_info_html: "Information

Hover over the invoice elements below, all items that light up in yellow are editable.

" + 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" + invoice_reference_: "Invoice reference:" + code_: "Code:" + code_disabled: "Code disabled" + order_num: "Order #:" + invoice_issued_on_DATE_at_TIME: "Invoice issued on {DATE} at {TIME}" + object_reservation_of_john_smith_on_DATE_at_TIME: "Object: Reservation of John Smith on {DATE} at {TIME}" + order_summary: "Order summary:" + details: "Details" + amount: "Amount" + machine_booking-3D_printer: "Machine booking - 3D printer" + training_booking-3D_print: "Training booking - initiation to 3d printing" + total_amount: "Total amount" + total_including_all_taxes: "Total incl. all taxes" + VAT_disabled: "VAT disabled" + VAT_enabled: "VAT enabled" + including_VAT: "Including {NAME} {RATE}% of {AMOUNT}" + including_total_excluding_taxes: "Including Total excl. taxes" + including_amount_payed_on_ordering: "Including amount payed on ordering" + settlement_by_debit_card_on_DATE_at_TIME_for_an_amount_of_AMOUNT: "Settlement by debit card on {DATE} at {TIME}, for an amount of {AMOUNT}" + important_notes: "Important notes" + address_and_legal_information: "Address and legal information" + invoice_reference: "Invoice reference" + invoice_reference_is_required: "Invoice reference is required." + text: "text" + year: "Year" + month: "Month" + day: "Day" + num_of_invoice: "Num. of invoice" + online_sales: "Online sales" + wallet: "Wallet" + refund: "Refund" + payment_schedule: "Payment schedule" + model: "Model" + documentation: "Documentation" + 2_digits_year: "2 digits year (eg. 70)" + 4_digits_year: "4 digits year (eg. 1970)" + month_number: "Month number (eg. 1)" + 2_digits_month_number: "2 digits month number (eg. 01)" + 3_characters_month_name: "3 characters month name (eg. JAN)" + day_in_the_month: "Day in the month (eg. 1)" + 2_digits_day_in_the_month: "2 digits in the month (eg. 01)" + n_digits_daily_count_of_invoices: "(n) digits, daily count of invoices (eg. ddd => 002 : 2nd invoice of the day)" + n_digits_monthly_count_of_invoices: "(n) digits, monthly count of invoices (eg. mmmm => 0012 : 12th invoice of the month)" + n_digits_annual_amount_of_invoices: "(n) digits, annual count of invoices (ex. yyyyyy => 000008 : 8th invoice of this year)" + beware_if_the_number_exceed_the_specified_length_it_will_be_truncated_by_the_left: "Beware: if the number exceed the specified length, it will be truncated by the left." + n_digits_count_of_orders: "(n) digits, count of invoices (eg. nnnn => 0327 : 327th order)" + n_digits_daily_count_of_orders: "(n) digits, daily count of orders (eg. ddd => 002 : 2nd order of the day)" + n_digits_monthly_count_of_orders: "(n) digits, monthly count of orders (eg. mmmm => 0012 : 12th order of the month)" + n_digits_annual_amount_of_orders: "(n) digits, annual count of orders (ex. yyyyyy => 000008 : 8th order of this year)" + add_a_notice_regarding_the_online_sales_only_if_the_invoice_is_concerned: "Add a notice regarding the online sales, only if the invoice is concerned." + this_will_never_be_added_when_a_refund_notice_is_present: "This will never be added when a refund notice is present." + eg_XVL_will_add_VL_to_the_invoices_settled_by_card: '(eg. X[/VL] will add "/VL" to the invoices settled by online card)' + add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Add a notice regarding refunds, only if the invoice is concerned." + this_will_never_be_added_when_an_online_sales_notice_is_present: "This will never be added when an online sales notice is present." + eg_RA_will_add_A_to_the_refund_invoices: '(eg. R[/A] will add "/A" to the refund invoices)' + add_a_notice_regarding_payment_schedule: "Add a notice regarding the payment schedules, only for concerned documents." + this_will_never_be_added_with_other_notices: "This will never be added when any other notice is present." + eg_SE_to_schedules: '(eg. S[/E] will add "/E" to the payment schedules)' + code: "Code" + enable_the_code: "Enable the code" + enabled: "Enabled" + disabled: "Disabled" + order_number: "Order number" + elements: "Elements" + VAT: "VAT" + enable_VAT: "Enable VAT" + VAT_rate: "VAT rate" + VAT_history: "VAT rates history" + 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: "Please note: The current general rate is {RATE}%. Here you can define different VAT rates for each category.

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_rate_product: "Products (store)" + changed_at: "Changed at" + changed_by: "By" + deleted_user: "Deleted user" + refund_invoice_successfully_created: "Refund invoice successfully created." + create_a_refund_on_this_invoice: "Create a refund on this invoice" + refund_mode: "Refund mode:" + do_you_want_to_disable_the_user_s_subscription: "Do you want to disabled the user's subscription:" + elements_to_refund: "Elements to refund" + description: "Description" + description_optional: "Description (optional):" + will_appear_on_the_refund_invoice: "Will appear on the refund invoice." + none: "None" #grammar concordance with payment mean + by_cash: "By cash" + by_cheque: "By cheque" + by_transfer: "By transfer" + by_wallet: "By wallet" + you_must_select_at_least_one_element_to_create_a_refund: "You must select at least one element, to create a refund." + unable_to_create_the_refund: "Unable to create the refund" + invoice_reference_successfully_saved: "Invoice reference successfully saved." + an_error_occurred_while_saving_invoice_reference: "An error occurred while saving invoice reference." + invoicing_code_succesfully_saved: "Invoicing code successfully saved." + an_error_occurred_while_saving_the_invoicing_code: "An error occurred while saving the invoicing code." + code_successfully_activated: "Code successfully activated." + code_successfully_disabled: "Code successfully disabled." + an_error_occurred_while_activating_the_invoicing_code: "An error occurred while activating the invoicing code." + order_number_successfully_saved: "Order number successfully saved." + an_error_occurred_while_saving_the_order_number: "An error occurred while saving the order number." + VAT_rate_successfully_saved: "VAT rate successfully saved." + an_error_occurred_while_saving_the_VAT_rate: "An error occurred while saving the VAT rate." + VAT_successfully_activated: "VAT successfully activated." + VAT_successfully_disabled: "VAT successfully disabled." + an_error_occurred_while_activating_the_VAT: "An error occurred while activating the VAT." + text_successfully_saved: "Text successfully saved." + an_error_occurred_while_saving_the_text: "An error occurred while saving the text." + address_and_legal_information_successfully_saved: "Address and legal information successfully saved." + an_error_occurred_while_saving_the_address_and_the_legal_information: "An error occurred while saving the address and the legal information." + logo_successfully_saved: "Logo successfully saved." + an_error_occurred_while_saving_the_logo: "An error occurred while saving the logo." + filename: "File name" + schedule_filename: "Schedule file name" + prefix_info: "The invoices will be generated as PDF files, named with the following prefix." + schedule_prefix_info: "The payment schedules will be generated as PDF files, named with the following prefix." + prefix: "Prefix" + prefix_successfully_saved: "File prefix successfully saved" + an_error_occurred_while_saving_the_prefix: "An error occurred while saving the file prefix" + online_payment: "Online payment" + close_accounting_period: "Close an accounting period" + close_from_date: "Close from" + start_date_is_required: "Start date is required" + close_until_date: "Close until" + end_date_is_required: "End date is required" + previous_closings: "Previous closings" + start_date: "From" + end_date: "To" + closed_at: "Closed at" + closed_by: "By" + period_total: "Period total" + perpetual_total: "Perpetual total" + integrity: "Integrity check" + confirmation_required: "Confirmation required" + confirm_close_START_END: "Do you really want to close the accounting period between {START} and {END}? Any subsequent changes will be impossible." + period_must_match_fiscal_year: "A closing must occur at the end of a minimum annual period, or per financial year when it is not calendar-based." + this_may_take_a_while: "This operation will take some time to complete." + period_START_END_closed_success: "The accounting period from {START} to {END} has been successfully closed. Archive generation is running, you'll be notified when it's done." + failed_to_close_period: "An error occurred, unable to close the accounting period" + no_periods: "No closings for now" + accounting_codes: "Accounting codes" + export_accounting_data: "Export accounting data" + 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_is_running: "Export is running. You'll be notified when it's ready." + export_form_date: "Export from" + export_to_date: "Export until" + format: "File format" + encoding: "Encoding" + separator: "Separator" + dateFormat: "Date format" + labelMaxLength: "Label (max)" + decimalSeparator: "Decimal separator" + exportInvoicesAtZero: "Export invoices equal to 0" + columns: "Columns" + exportColumns: + journal_code: "Journal code" + date: "Entry date" + account_code: "Account code" + account_label: "Account label" + piece: "Document" + line_label: "Entry label" + debit_origin: "Origin debit" + credit_origin: "Origin credit" + debit_euro: "Euro debit" + credit_euro: "Euro credit" + lettering: "Lettering" + start_date: "Start date" + end_date: "End date" + vat_rate: "VAT rate" + amount: "Total amount" + payzen_keys_form: + payzen_keys_info_html: "

To be able to collect online payments, you must configure the PayZen identifiers and keys.

Retrieve them from your merchant back office.

" + client_keys: "Client key" + payzen_public_key: "Client public key" + api_keys: "API keys" + payzen_username: "Username" + payzen_password: "Password" + payzen_endpoint: "REST API server name" + payzen_hmac: "HMAC-SHA-256 key" + stripe_keys_form: + stripe_keys_info_html: "

To be able to collect online payments, you must configure the Stripe API keys.

Retrieve them from your dashboard.

Updating these keys will trigger a synchronization of all users on Stripe, this may take some time. You'll receive a notification when it's done.

" + public_key: "Public key" + secret_key: "Secret key" + payment: + payment_settings: "Payment settings" + online_payment: "Online payment" + online_payment_info_html: "You can enable your members to book directly online, paying by card. Alternatively, you can restrict the booking and payment processes for administrators and managers." + enable_online_payment: "Enable online payment" + stripe_keys: "Stripe keys" + public_key: "Public key" + secret_key: "Secret key" + error_check_keys: "Error: please check your Stripe keys." + stripe_keys_saved: "Stripe keys successfully saved." + error_saving_stripe_keys: "Unable to save the Stripe keys. Please try again later." + api_keys: "API keys" + edit_keys: "Edit keys" + currency: "Currency" + currency_info_html: "Please specify below the currency used for online payment. You should provide a three-letter ISO code, from the list of Stripe supported currencies." + currency_alert_html: "Warning: the currency cannot be changed after the first online payment was made. Please define this setting carefully before opening Fab-manager to your members." + stripe_currency: "Stripe currency" + gateway_configuration_error: "An error occurred while configuring the payment gateway: " + payzen_settings: + payzen_keys: "PayZen keys" + edit_keys: "Edit keys" + payzen_public_key: "Client public key" + payzen_username: "Username" + payzen_password: "Password" + payzen_endpoint: "REST API server name" + payzen_hmac: "HMAC-SHA-256 key" + currency: "Currency" + payzen_currency: "PayZen currency" + currency_info_html: "Please specify below the currency used for online payment. You should provide a three-letter ISO code, from the list of PayZen supported currencies." + save: "Save" + 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}." + #select a payment gateway + select_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" + stripe: "Stripe" + payzen: "PayZen" + confirm_button: "Validate the gateway" + payment_schedules_list: + filter_schedules: "Filter schedules" + no_payment_schedules: "No payment schedules to display" + load_more: "Load more" + card_updated_success: "The user's card was successfully updated" + document_filters: + reference: "Reference" + customer: "Customer" + date: "Date" + 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" + #management of users, labels, groups, and so on + members: + users_management: "Users management" + import: "Import members from a CSV file" + users: "Users" + members: "Members" + subscriptions: "Subscriptions" + search_for_an_user: "Search for an user" + add_a_new_member: "Add a new member" + reservations: "Reservations" + username: "Username" + surname: "Last name" + first_name: "First name" + email: "Email" + phone: "Phone" + user_type: "User type" + subscription: "Subscription" + display_more_users: "Display more users..." + administrators: "Administrators" + search_for_an_administrator: "Search for an administrator" + add_a_new_administrator: "Add a new administrator" + managers: "Managers" + managers_info: "A manager is a restricted administrator that cannot modify the settings of the application. However, he will be able to take reservations for any members and for all managers, including himself, and to process payments and refunds." + search_for_a_manager: "Search for a manager" + add_a_new_manager: "Add a new manager" + delete_this_manager: "Do you really want to delete this manager? This cannot be undone." + manager_successfully_deleted: "Manager successfully deleted." + unable_to_delete_the_manager: "Unable to delete the manager." + partners: "Partners" + partners_info: "A partner is a special user that can be associated with the «Partner» plans. These users won't be able to connect and will just receive notifications about subscriptions to their associated plan." + search_for_a_partner: "Search for a partner" + add_a_new_partner: "Add a new partner" + delete_this_partner: "Do you really want to delete this partner? This cannot be undone." + partner_successfully_deleted: "Partner successfully deleted." + unable_to_delete_the_partner: "Unable to delete the partner." + associated_plan: "Associated plan" + groups: "Groups" + tags: "Tags" + authentication: "Authentication" + confirmation_required: "Confirmation required" + confirm_delete_member: "Do you really want to delete this member? This cannot be undone." + member_successfully_deleted: "Member successfully deleted." + unable_to_delete_the_member: "Unable to delete the member." + do_you_really_want_to_delete_this_administrator_this_cannot_be_undone: "Do you really want to delete this administrator? This cannot be undone." + this_may_take_a_while_please_wait: "Warning: this may take a while, please be patient." + administrator_successfully_deleted: "Administrator successfully deleted." + unable_to_delete_the_administrator: "Unable to delete the administrator." + changes_successfully_saved: "Changes successfully saved." + an_error_occurred_while_saving_changes: "An error occurred when saving changes." + export_is_running_you_ll_be_notified_when_its_ready: "Export is running. You'll be notified when it's ready." + tag_form: + tags: "Tags" + add_a_tag: "Add a tag" + tag_name: "Tag name" + new_tag_successfully_saved: "New tag successfully saved." + an_error_occurred_while_saving_the_new_tag: "An error occurred while saving the new tag." + confirmation_required: "Delete this tag?" + confirm_delete_tag_html: "Do you really want to delete this tag?
Users and slots currently associated with this tag will be dissociated.
Warning: This cannot be undone!" + tag_successfully_deleted: "Tag successfully deleted." + an_error_occurred_and_the_tag_deletion_failed: "An error occurred and the tag deletion failed." + authentication_form: + search_for_an_authentication_provider: "Search for an authentication provider" + add_a_new_authentication_provider: "Add a new authentication provider" + name: "Name" + strategy_name: "Strategy's name" + type: "Type" + state: "State" + unknown: "Unknown: " + active: "Active" + pending: "Pending" + previous_provider: "Previous provider" + confirmation_required: "Delete the provider?" + do_you_really_want_to_delete_the_TYPE_authentication_provider_NAME: "Do you really want to delete the {TYPE} authentication provider: {NAME}?" + authentication_provider_successfully_deleted: "Authentication provider successfully deleted." + an_error_occurred_unable_to_delete_the_specified_provider: "An error occurred: unable to delete the specified provider." + local_database: "Local database" + o_auth2: "OAuth 2.0" + openid_connect: "OpenID Connect" + group_form: + add_a_group: "Add a group" + group_name: "Group name" + disable: "Disable" + enable: "Enable" + changes_successfully_saved: "Changes successfully saved." + an_error_occurred_while_saving_changes: "An error occurred when saving changes." + new_group_successfully_saved: "New group successfully saved." + an_error_occurred_when_saving_the_new_group: "An error occurred when saving the new group." + group_successfully_deleted: "Group successfully deleted." + unable_to_delete_group_because_some_users_and_or_groups_are_still_linked_to_it: "Unable to delete group because some users and/or groups are still linked to it." + group_successfully_enabled_disabled: "Group successfully {STATUS, select, true{disabled} other{enabled}}." + unable_to_enable_disable_group: "Unable to {STATUS, select, true{disable} other{enable}} group." + unable_to_disable_group_with_users: "Unable to disable group because it still contains {USERS} active {USERS, plural, =1{user} other{users}}." + status_enabled: "Enabled" + status_disabled: "Disabled" + status_all: "All" + member_filter_all: "All" + member_filter_not_confirmed: "Unconfirmed" + member_filter_inactive_for_3_years: "Inactive for 3 years" + #add a member + members_new: + add_a_member: "Add a member" + user_is_an_organization: "User is an organization" + create_success: "Member successfully created" + #members bulk import + members_import: + import_members: "Import members" + info: "You can upload a CSV file to create new members or update existing ones. Your file must user the identifiers below to specify the group, the trainings and the tags of the members." + required_fields: "Your file must contain, at least, the following information for each user to create: email, name, first name and group. If the password is empty, it will be generated. On updates, the empty fields will be kept as is." + about_example_html: "Please refer to the provided example file to generate a correct CSV file.
This example will:
  1. create a new member (Jean Dupont) with a generated password
  2. update the password of an existing membre (ID 43) using the new given password

Be careful to use Unicode UTF-8 encoding." + groups: "Groups" + group_name: "Group name" + group_identifier: "Identifier to use" + trainings: "Trainings" + training_name: "Training name" + training_identifier: "Identifier to use" + plans: "Plans" + plan_name: "Plan name" + plan_identifier: "Identifier to use" + tags: "Tags" + tag_name: "Tag name" + tag_identifier: "Identifier to use" + download_example: "Example file" + select_file: "Choose a file" + import: "Import" + update_field: "Reference field for users to update" + update_on_id: "ID" + update_on_username: "Username" + update_on_email: "Email address" + #import results + members_import_result: + import_results: "Import results" + import_details: "Import # {ID}, of {DATE}, initiated by {USER}" + results: "Results" + pending: "Pending..." + status_create: "Creating a new user" + status_update: "Updating user {ID}" + success: "Success" + failed: "Failed" + error_details: "Error's details:" + user_validation: + validate_member_success: "Member successfully validated" + invalidate_member_success: "Member successfully invalidated" + validate_member_error: "An unexpected error occurred: unable to validate this member." + invalidate_member_error: "An unexpected error occurred: unable to invalidate this member." + validate_account: "Validate the account" + supporting_documents_refusal_form: + refusal_comment: "Comment" + comment_placeholder: "Please type a comment here" + supporting_documents_refusal_modal: + title: "Refuse some supporting documents" + refusal_successfully_sent: "The refusal has been successfully sent." + unable_to_send: "Unable to refuse the supporting documents: " + confirm: "Confirm" + supporting_documents_validation: + title: "Supporting documents" + find_below_documents_files: "You will find below the supporting documents submitted by the member." + to_complete: "To complete" + refuse_documents: "Refusing the documents" + refuse_documents_info: "After verification, you may notify the member that the evidence submitted is not acceptable. You can specify the reasons for your refusal and indicate the actions to be taken. The member will be notified by e-mail." + change_role_modal: + change_role: "Change role" + warning_role_change: "

Warning: changing the role of a user is not a harmless operation.

  • Members can only book reservations for themselves, paying by card or wallet.
  • Managers can book reservations for themselves, paying by card or wallet, and for other members and managers, by collecting payments at the checkout.
  • Administrators as managers, they can book reservations for themselves and for others. Moreover, they can change every settings of the application.
" + new_role: "New role" + admin: "Administrator" + manager: "Manager" + member: "Member" + new_group: "New group" + new_group_help: "Users with a running subscription cannot be changed from their current group." + confirm: "Change role" + role_changed: "Role successfully changed from {OLD} to {NEW}." + error_while_changing_role: "An error occurred while changing the role. Please try again later." + #edit a member + members_edit: + subscription: "Subscription" + duration: "Duration:" + expires_at: "Expires at:" + price_: "Price:" + offer_free_days: "Offer free days" + renew_subscription: "Renew the subscription" + cancel_subscription: "Cancel the subscription" + user_has_no_current_subscription: "User has no current subscription." + subscribe_to_a_plan: "Subscribe to a plan" + trainings: "Trainings" + no_trainings: "No trainings" + next_trainings: "Next trainings" + passed_trainings: "Passed trainings" + validated_trainings: "Validated trainings" + events: "Events" + next_events: "Next events" + no_upcoming_events: "No upcoming events" + NUMBER_full_price_tickets_reserved: "{NUMBER, plural, =0{} one{1 full price ticket reserved} other{{NUMBER} full price tickets reserved}}" + NUMBER_NAME_tickets_reserved: "{NUMBER, plural, =0{} one{1 {NAME} ticket reserved} other{{NUMBER} {NAME} tickets reserved}}" + passed_events: "Passed events" + no_passed_events: "No passed events" + invoices: "Invoices" + invoice_num: "Invoice #" + date: "Date" + price: "Price" + download_the_invoice: "Download the invoice" + download_the_refund_invoice: "Download the refund invoice" + no_invoices_for_now: "No invoices for now." + you_successfully_changed_the_expiration_date_of_the_user_s_subscription: "You successfully changed the expiration date of the user's subscription" + a_problem_occurred_while_saving_the_date: "A problem occurred while saving the date." + new_subscription: "New subscription" + you_are_about_to_purchase_a_subscription_to_NAME: "You are about to purchase a subscription to {NAME}." + with_schedule: "Subscribe with a monthly payment schedule" + subscription_successfully_purchased: "Subscription successfully purchased." + a_problem_occurred_while_taking_the_subscription: "A problem occurred while taking the subscription" + wallet: "Wallet" + to_credit: 'Credit' + cannot_credit_own_wallet: "You cannot credit your own wallet. Please ask another manager or an administrator to credit your wallet." + cannot_extend_own_subscription: "You cannot extend your own subscription. Please ask another manager or an administrator to extend your subscription." + update_success: "Member's profile successfully updated" + my_documents: "My documents" + save: "Save" + confirm: "Confirm" + cancel: "Cancel" + validate_account: "Validate the account" + validate_member_success: "The member is validated" + invalidate_member_success: "The member is invalidated" + validate_member_error: "An error occurred: impossible to validate from this member." + invalidate_member_error: "An error occurred: impossible to invalidate from this member." + supporting_documents: "Supporting documents" + change_role: "Change role" + #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:" + 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" + #renew a subscription + renew_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" + DATE_TIME: "{DATE} {TIME}" + #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" + subscription_success: "Subscription successfully subscribed" + #cancel the current subscription + cancel_subscription_modal: + title: "Confirmation required" + confirmation_html: "You are about to cancel the subscription {NAME} of this user. From now, he won't be able to benefit from the advantages of this subscription, and all his unused credits will be lost. Are your sure?" + confirm: "Cancel this subscription" + subscription_canceled: "The subscription was successfully canceled." + #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: "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" + pseudonym: "Pseudonym" + pseudonym_is_required: "Pseudonym is required." + first_name: "First name" + first_name_is_required: "First name is required." + surname: "Last name" + surname_is_required: "Last name is required." + email_address: "Email address" + email_is_required: "Email address is required." + birth_date: "Date of birth" + address: "Address" + phone_number: "Phone number" + #add a new manager to the platform + manager_new: + add_a_manager: "Add a manager" + 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" + pseudonym: "Pseudonym" + pseudonym_is_required: "Pseudonym is required." + first_name: "First name" + first_name_is_required: "First name is required." + surname: "Last name" + surname_is_required: "Last name is required." + email_address: "Email address" + email_is_required: "Email address is required." + birth_date: "Date of birth" + address: "Address" + phone_number: "Phone number" + #authentication providers (SSO) components + authentication: + boolean_mapping_form: + mappings: "Mappings" + true_value: "True value" + false_value: "False value" + date_mapping_form: + input_format: "Input format" + date_format: "Date format" + integer_mapping_form: + mappings: "Mappings" + mapping_from: "From" + mapping_to: "To" + string_mapping_form: + mappings: "Mappings" + mapping_from: "From" + mapping_to: "To" + data_mapping_form: + define_the_fields_mapping: "Define the fields mapping" + add_a_match: "Add a match" + model: "Model" + field: "Field" + data_mapping: "Data mapping" + oauth2_data_mapping_form: + api_endpoint_url: "API endpoint or URL" + api_type: "API type" + api_field: "API field" + api_field_help_html: 'JsonPath syntax is supported.
If many fields are selected, the first one will be used.
Example: $.data[*].name' + openid_connect_data_mapping_form: + api_field: "Userinfo claim" + api_field_help_html: 'Set the field providing the corresponding data through the userinfo endpoint.
JsonPath syntax is supported. If many fields are selected, the first one will be used.
Example: $.data[*].name' + openid_standard_configuration: "Use the OpenID standard configuration" + type_mapping_modal: + data_mapping: "Data mapping" + TYPE_expected: "{TYPE} expected" + types: + integer: "integer" + string: "string" + text: "text" + date: "date" + boolean: "boolean" + oauth2_form: + authorization_callback_url: "Authorization callback URL" + common_url: "Server root URL" + authorization_endpoint: "Authorization endpoint" + token_acquisition_endpoint: "Token acquisition endpoint" + profile_edition_url: "Profil edition URL" + profile_edition_url_help: "The URL of the page where the user can edit his profile." + client_identifier: "Client identifier" + client_secret: "Client secret" + scopes: "Scopes" + openid_connect_form: + issuer: "Issuer" + issuer_help: "Root url for the authorization server." + discovery: "Discovery" + discovery_help: "Should OpenID discovery be used. This is recommended if the IDP provides a discovery endpoint." + discovery_unavailable: "Discovery is unavailable for the configured issuer." + discovery_enabled: "Enable discovery" + discovery_disabled: "Disable discovery" + client_auth_method: "Client authentication method" + client_auth_method_help: "Which authentication method to use to authenticate Fab-manager with the authorization server." + client_auth_method_basic: "Basic" + client_auth_method_jwks: "JWKS" + scope: "Scope" + scope_help_html: "Which OpenID scopes to include (openid is always required).
If Discovery is enabled, the available scopes will be automatically proposed." + prompt: "Prompt" + prompt_help_html: "Which OpenID pages the user will be shown.
None - no authentication or consent user interface pages are shown.
Login - the authorization server prompt the user for reauthentication.
Consent - the authorization server prompt the user for consent before returning information to Fab-manager.
Select account - the authorization server prompt the user to select a user account." + prompt_none: "None" + prompt_login: "Login" + prompt_consent: "Consent" + prompt_select_account: "Select account" + send_scope_to_token_endpoint: "Send scope to token endpoint?" + send_scope_to_token_endpoint_help: "Should the scope parameter be sent to the authorization token endpoint?" + send_scope_to_token_endpoint_false: "No" + send_scope_to_token_endpoint_true: "Yes" + profile_edition_url: "Profil edition URL" + profile_edition_url_help: "The URL of the page where the user can edit his profile." + client_options: "Client options" + client__identifier: "Identifier" + client__secret: "Secret" + client__authorization_endpoint: "Authorization endpoint" + client__token_endpoint: "Token endpoint" + client__userinfo_endpoint: "Userinfo endpoint" + client__jwks_uri: "JWKS URI" + client__end_session_endpoint: "End session endpoint" + client__end_session_endpoint_help: "The url to call to log the user out at the authorization server." + provider_form: + name: "Name" + authentication_type: "Authentication type" + save: "Save" + create_success: "Authentication provider created" + update_success: "Authentication provider updated" + methods: + local_database: "Local database" + oauth2: "OAuth 2.0" + openid_connect: "OpenID Connect" + #create a new authentication provider (SSO) + authentication_new: + add_a_new_authentication_provider: "Add a new authentication provider" + #edit an authentication provider (SSO) + authentication_edit: + provider: "Provider:" + #statistics tables + statistics: + statistics: "Statistics" + evolution: "Evolution" + age_filter: "Age filter" + from_age: "From" #e.g. from 8 to 40 years old + to_age: "to" #e.g. from 8 to 40 years old + start: "Start:" + end: "End:" + custom_filter: "Custom filter" + NO_: "NO" + criterion: "Criterion:" + value: "Value:" + exclude: "Exclude" + from_date: "From" #eg: from 01/01 to 01/05 + to_date: "to" #eg: from 01/01 to 01/05 + entries: "Entries:" + revenue_: "Revenue:" + average_age: "Average age:" + years_old: "years old" + total: "Total" + available_hours: "Hours available for booking:" + available_tickets: "Tickets available for booking:" + date: "Date" + reservation_date: "Reservation date" + user: "User" + gender: "Gender" + age: "Age" + type: "Type" + revenue: "Revenue" + unknown: "Unknown" + user_id: "User ID" + display_more_results: "Display more results" + export_statistics_to_excel: "Export statistics to Excel" + export_all_statistics: "Export all statistics" + export_the_current_search_results: "Export the current search results" + export: "Export" + deleted_user: "Deleted user" + man: "Man" + woman: "Woman" + export_is_running_you_ll_be_notified_when_its_ready: "Export is running. You'll be notified when it's ready." + create_plans_to_start: "Start by creating new subscription plans." + click_here: "Click here to create your first one." + average_cart: "Average cart:" + #statistics graphs + stats_graphs: + statistics: "Statistics" + data: "Data" + day: "Day" + week: "Week" + from_date: "From" #eg: from 01/01 to 01/05 + to_date: "to" #eg: from 01/01 to 01/05 + month: "Month" + start: "Start:" + end: "End:" + type: "Type" + revenue: "Revenue" + top_list_of: "Top list of" + number: "Number" + week_short: "Week" + week_of_START_to_END: "Week of {START} to {END}" + no_data_for_this_period: "No data for this period" + date: "Date" + boolean_setting: + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." + error_SETTING_locked: "Unable to update the setting: {SETTING} is locked. Please contact your system administrator." + an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." + save: "save" + #global application parameters and customization + settings: + customize_the_application: "Customize the application" + fablab_name: "FabLab name" + about: "About" + customize_information_messages: "Customize information messages" + message_of_the_machine_booking_page: "Message of the machine booking page:" + type_the_message_content: "Type the message content" + warning_message_of_the_training_booking_page: "Warning message of the training booking page:" + information_message_of_the_training_reservation_page: "Information message of the training reservation page:" + message_of_the_subscriptions_page: "Message of the subscriptions page:" + message_of_the_events_page: "Message of the events page:" + message_of_the_spaces_page: "Message of the spaces page:" + legal_documents: "Legal documents" + if_these_documents_are_not_filled_no_consent_about_them_will_be_asked_to_the_user: "If these documents are not filled, no consent about them will be asked." + general_terms_and_conditions: "General terms and conditions (T&C)" + terms_of_service: "Terms of service (TOS)" + customize_the_graphics: "Customize the graphics" + for_an_optimal_rendering_the_logo_image_must_be_at_the_PNG_format_with_a_transparent_background_and_with_an_aspect_ratio_3.5_times_wider_than_the_height: "For an optimal rendering, the logo image must be at the PNG format with a transparent background and an aspect ratio 3.5 wider than the height." + concerning_the_favicon_it_must_be_at_ICO_format_with_a_size_of_16x16_pixels: "Concerning the favicon, it must be at ICO format with a size of 16x16 pixels." + remember_to_refresh_the_page_for_the_changes_to_take_effect: "Remember to refresh the page for the changes to take effect." + logo_white_background: "Logo (white background)" + change_the_logo: "Change the logo" + logo_black_background: "Logo (black background)" + favicon: "Favicon" + change_the_favicon: "Change the favicon" + main_colour: "Main colour:" + primary: "Primary" + secondary_colour: "Secondary colour:" + secondary: "Secondary" + background_picture_of_the_profile_banner: "Background picture of the profile banner" + change_the_profile_banner: "Change the profile banner" + home_page: "Home page" + news_of_the_home_page: "News of the home page:" + type_your_news_here: "Type your news here" + leave_it_empty_to_not_bring_up_any_news_on_the_home_page: "Leave it empty to not bring up any news on the home page" + twitter_stream: "Twitter Stream:" + name_of_the_twitter_account: "Name of the Twitter account" + link: "Link" + link_to_about: 'Link title to the "About" page' + content: "Content" + title_of_the_about_page: "Title of the About page" + shift_enter_to_force_carriage_return: "SHIFT + ENTER to force carriage return" + input_the_main_content: "Input the main content" + drag_and_drop_to_insert_images: "Drag and drop to insert images" + input_the_fablab_contacts: "Input the FabLab contacts" + reservations: "Reservations" + reservations_parameters: "Reservations parameters" + confine_the_booking_agenda: "Confine the booking agenda" + opening_time: "Opening time" + closing_time: "Closing time" + max_visibility: "Maximum visibility (in months)" + visibility_for_yearly_members: "For currently running subscriptions, at least 1 year long" + visibility_for_other_members: "For all other members" + reservation_deadline: "Prevent last minute booking" + reservation_deadline_help: "If you increase the prior period, members won't be able to book a slot X minutes before its start." + machine_deadline_minutes: "Machine prior period (minutes)" + training_deadline_minutes: "Training prior period (minutes)" + event_deadline_minutes: "Event prior period (minutes)" + space_deadline_minutes: "Space prior period (minutes)" + ability_for_the_users_to_move_their_reservations: "Ability for the users to move their reservations" + reservations_shifting: "Reservations shifting" + prior_period_hours: "Prior period (hours)" + enabled: "Enabled" + disabled: "Disabled" + ability_for_the_users_to_cancel_their_reservations: "Ability for the users to cancel their reservations" + reservations_cancelling: "Reservations cancelling" + reservations_reminders: "Reservations reminders" + notification_sending_before_the_reservation_occurs: "Notification sending before the reservation occurs" + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." + file_successfully_updated: "File successfully updated." + name_genre: "title concordance" + machine_explications_alert: "explanation message on the machine reservation page" + training_explications_alert: "explanation message on the training reservation page" + training_information_message: "information message on the machine reservation page" + subscription_explications_alert: "explanation message on the subscription page" + event_explications_alert: "explanation message on the event reservation page" + space_explications_alert: "explanation message on the space reservation page" + main_color: "main colour" + secondary_color: "secondary colour" + customize_home_page: "Customize home page" + reset_home_page: "Reset the home page to its initial state" + confirmation_required: "Confirmation required" + confirm_reset_home_page: "Do you really want to reset the home page to its factory value?" + home_items: "Home page items" + item_news: "News" + item_projects: "Last projects" + item_twitter: "Last tweet" + item_members: "Last members" + item_events: "Next events" + home_content: "the home page" + home_content_reset: "Home page was successfully reset to its initial configuration." + home_css: "the stylesheet of the home page" + home_blogpost: "homepage's brief" + twitter_name: "Twitter feed name" + link_name: "link title to the \"About\" page" + about_title: "\"About\" page title" + about_body: "\"About\" page content" + about_contacts: "\"About\" page contacts" + about_follow_us: "Follow us" + about_networks: "Social networks" + privacy_draft: "privacy policy draft" + privacy_body: "privacy policy" + privacy_dpo: "data protection officer address" + booking_window_start: "opening time" + booking_window_end: "closing time" + booking_move_enable: "reservation moving enabling" + booking_move_delay: "preventive delay of moving" + booking_cancel_enable: "reservation canceling enabling" + booking_cancel_delay: "preventive delay of canceling" + reminder_enable: "reservation reminding enabling" + reminder_delay: "delay before sending the reminder" + default_value_is_24_hours: "If the field is leaved empty: 24 hours." + visibility_yearly: "maximum visibility for annual subscribers" + visibility_others: "maximum visibility for other members" + display: "Display" + display_name_info_html: "When enabled, connected members browsing the calendar or booking a resource will see the name of the members who has already booked some slots. When disabled, only administrators and managers will view the names.
Warning: if you enable this feature, please write it down in your privacy policy." + display_reservation_user_name: "Display the full name of the user(s) who booked a slots" + display_name: "Display the name" + display_name_enable: "name display" + events_in_the_calendar: "Display the events in the calendar" + events_in_calendar_info: "When enabled, the admin calendar will display the scheduled events, as read-only items." + show_event: "Show the events" + events_in_calendar: "events display in the calendar" + machines_sort_by: "machines display order" + fab_analytics: "Fab Analytics" + phone_required: "phone required" + address_required: "address required" + tracking_id: "tracking ID" + facebook_app_id: "Facebook App ID" + twitter_analytics: "Twitter analytics account" + book_overlapping_slots: "book overlapping slots" + slot_duration: "slots duration" + advanced: "Advanced settings" + customize_home_page_css: "Customise the stylesheet of the home page" + home_css_notice_html: "You can customize the stylesheet which will apply to the home page, using the SCSS syntax. These styles will be automatically subordinated to the .home-page selector to prevent any risk of breaking the application. Meanwhile please be careful, any changes in the home page editor at the top of the page may broke your styles, always refer to the HTML code." + error_SETTING_locked: "Unable to update the setting: {SETTING} is locked. Please contact your system administrator." + an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." + book_overlapping_slots_info: "Allow / prevent the reservation of overlapping 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." + default_slot_duration: "Default duration for slots" + duration_minutes: "Duration (in minutes)" + default_slot_duration_info: "Machine and space availabilities are divided in multiple slots of this duration. This value can be overridden per availability." + modules: "Modules" + machines: "Machines" + machines_info_html: "The module Reserve a machine module can be disabled." + enable_machines: "Enable the machines" + machines_module: "machines module" + spaces: "Spaces" + spaces_info_html: "

A space can be, for example, a woodshop or a meeting room. Their particularity is that they can be booked by several people at the same time.

Warning: It is not recommended to disable spaces if at least one space reservation was made on the system.

" + enable_spaces: "Enable the spaces" + spaces_module: "spaces module" + plans: "Plans" + plans_info_html: "

Subscriptions provide a way to segment your prices and provide benefits to regular users.

Warning: It is not recommended to disable plans if at least one subscription is active on the system.

" + enable_plans: "Enable the plans" + plans_module: "plans module" + trainings: "Trainings" + trainings_info_html: "

Trainings are fully integrated Fab-manager's agenda. If enabled, your members will be able to book and pay trainings.

Trainings provides a way to prevent members to book some machines, if they do have not taken the prerequisite course.

" + enable_trainings: "Enable the trainings" + trainings_module: "trainings module" + store: "Store" + store_info_html: "You can enable the store module that provides an easy way to sell various products and consumables to your members. This module also allows you to manage stocks and track orders." + enable_store: "Enable the store" + store_module: "store module" + invoicing: "Invoicing" + invoicing_info_html: "

You can fully disable the invoicing module.

This is useful if you have your own invoicing system, and you don't want Fab-manager generates and sends invoices to the members.

Warning: even if you disable the invoicing module, you must to configure the VAT to prevent errors in accounting and prices. Do it from the « Invoices > Invoicing settings » section.

" + enable_invoicing: "Enable invoicing" + invoicing_module: "invoicing module" + account_creation: "Account creation" + accounts_management: "Accounts management" + members_list: "Members list" + members_list_info: "You can customize the fields to display in the member management list" + phone: "Phone" + phone_is_required: "Phone required" + phone_required_info: "You can define if the phone number should be required to register a new user on Fab-manager." + address: "Address" + address_required_info_html: "You can define if the address should be required to register a new user on Fab-manager.
Please note that, depending on your country, the regulations may requires addresses for the invoices to be valid." + address_is_required: "Address is required" + external_id: "External identifier" + external_id_info_html: "You can set up an external identifier for your users, which cannot be modified by the user himself." + enable_external_id: "Enable the external ID" + captcha: "Captcha" + captcha_info_html: "You can setup a protection against robots, to prevent them creating members accounts. This protection is using Google reCAPTCHA. Sign up for an API key pair to start using the captcha." + site_key: "Site key" + secret_key: "Secret key" + recaptcha_site_key: "reCAPTCHA Site Key" + recaptcha_secret_key: "reCAPTCHA Secret Key" + feature_tour_display: "feature tour display" + email_from: "expeditor's address" + disqus_shortname: "Disqus shortname" + COUNT_items_removed: "{COUNT, plural, =1{One item} other{{COUNT} items}} removed" + item_added: "One item added" + openlab_app_id: "OpenLab ID" + openlab_app_secret: "OpenLab secret" + openlab_default: "default gallery view" + online_payment_module: "online payment module" + stripe_currency: "Stripe currency" + account_confirmation: "Account confirmation" + confirmation_required_info: "Optionally, you can force the users to confirm their email address before being able to access Fab-manager." + confirmation_is_required: "Confirmation required" + change_group: "Group change" + change_group_info: "After an user has created his account, you can restrict him from changing his group. In that case, only managers and administrators will be able to change the user's group." + allow_group_change: "Allow group change" + user_change_group: "users can change their group" + wallet_module: "wallet module" + public_agenda_module: "public agenda module" + statistics_module: "statistics module" + upcoming_events_shown: "display limit for upcoming events" + 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.
You can set a number of hours (eg. 5) or a percentage of his current pack pack (eg. 0.05 means 5%)." + 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" + show_username_in_admin_list: "Show the username in the list" + overlapping_options: + training_reservations: "Trainings" + machine_reservations: "Machines" + space_reservations: "Spaces" + events_reservations: "Events" + general: + general: "General" + title: "Title" + fablab_title: "FabLab title" + title_concordance: "Title concordance" + male: "Male." + female: "Female." + neutral: "Neutral." + eg: "eg:" + the_team: "The team of" + male_preposition: "the" + female_preposition: "the" + neutral_preposition: "" + elements_ordering: "Elements ordering" + machines_order: "Machines order" + display_machines_sorted_by: "Display machines sorted by" + sort_by: + default: "Default" + name: "Name" + created_at: "Creation date" + updated_at: "Last update date" + 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" + help: "Help" + feature_tour: "Feature tour" + feature_tour_info_html: "

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:

  • « Once » to keep the default behavior.
  • « By session » to display the tours each time you reopen the application.
  • « 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.
" + feature_tour_display_mode: "Feature tour display mode" + display_mode: + once: "Once" + session: "By session" + manual: "Manual trigger" + notifications: "Notifications" + email: "Email" + email_info: "The email address from which notifications will be sent. You can use a non-existing address (like noreply@...) or an existing address if you want to allow your members to reply to the notifications they receive." + email_from: "Expeditor's address" + wallet: "Wallet" + wallet_info_html: "

The virtual wallet allows you to allocate a sum of money to users. Then, can spend this money as they wish, in Fab-manager.

Members cannot credit their wallet themselves, it's a privilege of managers and administrators.

" + enable_wallet: "Enable wallet" + public_agenda: "Public agenda" + public_agenda_info_html: "

The public agenda offers to members and visitors a general overview of the Fablab's planning.

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.

" + enable_public_agenda: "Enable public agenda" + statistics: "Statistics" + statistics_info_html: "

Enable or disable the statistics module.

If enabled, every nights, the data of the day just passed will be consolidated in the database of a powerful analysis engine. Then, every administrators will be able to browse statistical charts and tables in the corresponding section.

" + enable_statistics: "Enable statistics" + account: + account: "Account" + customize_account_settings: "Customize account settings" + user_validation_required: "validation of accounts" + user_validation_required_title: "Validation of accounts" + user_validation_required_info: "By activating this option, only members whose account is validated by an administrator or a manager will be able to make reservations." + user_validation_setting: + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." + error_SETTING_locked: "Unable to update the setting: {SETTING} is locked. Please contact your system administrator." + an_error_occurred_saving_the_setting: "An error occurred while saving the setting. Please try again later." + user_validation_required_option_label: "Activate the account validation option" + user_validation_required_list_title: "Member account validation information message" + user_validation_required_list_info: "Your administrator must validate your account. Then, you will be able to access all the booking features." + user_validation_required_list_other_info: "The resources selected below will be subject to member account validation." + save: "Save" + user_validation_required_list: + subscription: "Subscriptions" + machine: "Machines" + event: "Events" + space: "Spaces" + training: "Trainings" + pack: "Prepaid pack" + confirm: "Confirm" + confirmation_required: "Confirmation required" + organization: "Organization" + organization_profile_custom_fields_info: "You can display additional fields for users who declare themselves to be an organization. You can also choose to make them mandatory at account creation." + organization_profile_custom_fields_alert: "Warning: the activated fields will be automatically displayed on the issued invoices. Once configured, please do not modify them." + supporting_documents_type_modal: + successfully_created: "The new supporting documents request has been created." + unable_to_create: "Unable to delete the supporting documents request: " + successfully_updated: "The supporting documents request has been updated." + unable_to_update: "Unable to modify the supporting documents request: " + new_type: "Create a supporting documents request" + edit_type: "Edit the supporting documents request" + create: "Create" + edit: "Edit" + supporting_documents_type_form: + type_form_info: "Please define the supporting documents request settings below" + select_group: "Choose one or many group(s)" + name: "Name" + supporting_documents_types_list: + add_supporting_documents_types: "Add supporting documents" + all_groups: 'All groups' + supporting_documents_type_info: "You can ask for supporting documents, according to the user's groups. This will ask your members to deposit those kind of documents in their personnal space. Each members will be informed that supporting documents are required to be provided in their personal space (My supporting documents tab). On your side, you'll be able to check the provided supporting documents and validate the member's account (if the Account Validation option is enabled)." + no_groups_info: "Supporting documents are necessarily applied to groups.
If you do not have any group yet, you can create one from the \"Users/Groups\" page (button on the right)." + create_groups: "Create groups" + supporting_documents_type_title: "Supporting documents requests" + add_type: "New supporting documents request" + group_name: "Group" + name: "Supporting documents" + no_types: "You do not have any supporting documents requests.
Make sure you have created at least one group in order to add a request." + delete_supporting_documents_type_modal: + confirmation_required: "Confirmation required" + confirm: "Confirm" + deleted: "The supporting documents request has been deleted." + unable_to_delete: "Unable to delete the supporting documents request: " + confirm_delete_supporting_documents_type: "Do you really want to remove this requested type of supporting documents?" + profile_custom_fields_list: + field_successfully_updated: "The organization field has been updated." + unable_to_update: "Impossible to modify the field : " + required: "Confirmation required" + actived: "Activate the field" + home: + show_upcoming_events: "Show upcoming events" + upcoming_events: + until_start: "Until they start" + 2h_before_end: "Until 2 hours before they end" + until_end: "Until they end" + privacy: + title: "Privacy" + privacy_policy: "Privacy policy" + input_the_dpo: "Data Protection Officer" + current_policy: "Current policy" + draft_from_USER_DATE: "Draft, saved by {USER}, on {DATE}" + save_or_publish: "Save or publish?" + save_or_publish_body: "Do you want to publish a new version of the privacy policy or save it as a draft?" + publish_will_notify: "Publish a new version will send a notification to every users." + publish: "Publish" + users_notified: "Platform users will be notified of the update." + about_analytics: "I agree to share anonymous data with the development team to help improve Fab-manager." + read_more: "Which data do we collect?" + statistics: "Statistics" + google_analytics: "Google Analytics" + facebook: "Facebook" + facebook_info_html: "To enable the statistical tracking of the shares on the Facebook social network, set your App ID here. Refer to this guide to get one." + app_id: "App ID" + twitter: "Twitter" + twitter_info_html: "To enable the statistical tracking of the shares on the Twitter social network, Twitter analytics, set the name of your Twitter account here." + twitter_analytics: "Twitter account" + analytics: + title: "Application improvement" + intro_analytics_html: "You'll find below a detailed view of all the data, Fab-manager will collect if permission is granted." + version: "Application version" + members: "Number of members" + admins: "Number of administrators" + managers: "Number of managers" + availabilities: "Number of availabilities of the last 7 days" + reservations: "Number of reservations during the last 7 days" + orders: "Number of store orders during the last 7 days" + plans: "Is the subscription module active?" + spaces: "Is the space management module active?" + online_payment: "Is the online payment module active?" + gateway: "The payment gateway used to collect online payments" + wallet: "Is the wallet module active?" + statistics: "Is the statistics module active?" + trainings: "Is the trainings module active?" + public_agenda: "Is the public agenda module active?" + machines: "Is the machines module active?" + store: "Is the store module active?" + invoices: "Is the invoicing module active?" + openlab: "Is the project sharing module (OpenLab) active?" + 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 the Google Analytics website to get one.
Warning: 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" + api_documentation: "API documentation" + open_api_clients: "OpenAPI clients" + name: "Name" + calls_count: "Calls count" + token: "Token" + created_at: "Creation date" + reset_token: "Revoke access" + 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." + client_successfully_created: "Client successfully created." + client_successfully_updated: "Client successfully updated." + client_successfully_deleted: "Client successfully deleted." + access_successfully_revoked: "Access successfully revoked." + #create a new space + space_new: + add_a_new_space: "Add a new space" + #modify an exiting space + space_edit: + edit_the_space_NAME: "Edit the space: {NAME}" + validate_the_changes: "Validate the changes" + #process and delete abuses reports + manage_abuses: + abuses_list: "Reports list" + no_reports: "No reports for now" + published_by: "published by" + at_date: "on" + has_reported: "made the following report:" + confirmation_required: "Confirm the processing of the report" + report_will_be_destroyed: "Once the report has been processed, it will be deleted. This can't be undone, continue?" + report_removed: "The report has been deleted" + failed_to_remove: "An error occurred, unable to delete the report" + local_payment_form: + 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} reservation{reservation} other{order}}." + 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: "

By validating, you confirm that you set up {DEADLINES} bank direct debits, allowing you to collect all the monthly payments.

Please note: the bank transfers are not automatically handled by Fab-manager.

" + online_payment_disabled: "Online payment is not available. You cannot collect this payment schedule by online card." + local_payment_modal: + validate_cart: "Validate my cart" + offline_payment: "Payment on site" + check_list_setting: + save: 'Save' + customization_of_SETTING_successfully_saved: "Customization of the {SETTING} successfully saved." + #feature tour + tour: + conclusion: + title: "Thank you for your attention" + content: "

If you want to restart this contextual help, press F1 at any time or click on [? Help] from the user's menu.

If you need additional help, you can check the user guide (only in French for now).

The Fab-manager's team also provides personalized support (help with getting started, help with installation, customization, etc.), contact-us for more info.

" + trainings: + welcome: + title: "Trainings" + content: "Here you can create, modify and delete trainings. It is also the place where you can validate the training courses followed by your members." + welcome_manager: + title: "Trainings" + content: "This is the place where you can view the trainings and their associations with the machines. It is also the place where you can validate the training courses followed by your members." + trainings: + title: "Manage trainings" + content: "

With each training, a default number of places is associated. However, the number of actual places may be modified for each session.

The training sessions are scheduled from the administrator tab « Calendar ».

Furthermore, a training may be associated with one or more machines. This makes it a prerequisite for the reservation of these machines.

" + filter: + title: "Filter" + content: "By default, only active courses are displayed here. Display the others by choosing another filter here." + tracking: + title: "Trainings monitoring" + content: "Once a training session is finished, you can validate the training for the members present from this screen. This validation is essential to allow them to use the associated machines, if applicable." + calendar: + welcome: + title: "Calendar" + content: "From this screen, you can plan the slots during which training, machines and spaces will be bookable by members." + agenda: + title: "The calendar" + content: "Click in the calendar to start creating a new availability range. You can directly select the entire time range desired by maintaining your click." + export: + title: "Export" + content: "Start generating an Excel file, listing all the availability slots created in the calendar." + import: + title: "Import external calendars" + content: "Allows you to import calendars from an external source in iCal format." + members: + welcome: + title: "Users" + content: "Here you can create, modify and delete members and administrators. You can also manage groups, labels, import / export with spreadsheet files and connect SSO software." + list: + title: "Members list" + content: "By default, this table lists all the members of your Fab-manager. You can sort the list in a different order by clicking on the header of each column." + search: + title: "Find a user" + content: "This input field allows you to search for any text on all of the columns in the table below." + filter: + title: "Filter the list" + content: "

Filter the list below to display only users who have not confirmed their email address or inactive accounts for more than 3 years.

Please notice that the GDPR requires that you delete any accounts inactive for more than 3 years.

" + actions: + title: "Members actions" + content: "

The buttons in this column allow you to display and modify all of the member's parameters, or to delete them irreversibly.

In the event of a deletion, the billing information will be kept for 10 years and statistical data will also be kept anonymously.

" + exports: + title: "Export" + content: "Each of these buttons starts the generation of an Excel file listing all the members, subscriptions or reservations, current and past." + import: + title: "Import members" + content: "Allows you to import a list of members to create in Fab-manager, from a CSV file." + admins: + title: "Manage administrators" + content: "In the same way as the members, manage the administrators of your Fab-manager here.
The administrators can take reservations for any member as well as modify all the parameters of the software." + groups: + title: "Manage groups" + content: "

Groups allow you to better segment your price list.

When you set up Fab-manager for the first time, it is recommended to start by defining the groups.

" + labels: + title: "Manage tags" + content: "The labels allow you to reserve certain slots for users associated with these same labels." + sso: + title: "Single Sign-On" + content: "Here you can set up and manage a single authentication system (SSO)." + invoices: + welcome: + title: "Invoices" + content: "

Here you will be able to download invoices and credit notes issued, as well as manage everything related to accounting and invoicing.

If you use third-party software to manage your invoices, it is possible to deactivate the billing module. For this, contact your system administrator.

" + welcome_manager: + title: "Invoices" + content: "Here you will be able to download invoices and create credit notes." + list: + title: "Invoices list" + content: "By default, this table lists all the invoices and credit notes issued by Fab-manager. You can sort the list in a different order by clicking on the header of each column." + chained: + title: "Chaining indicator" + content: "

This icon ensures the inalterability of the accounting data of the invoice on this line, in accordance with the French finance law of 2018 against VAT fraud.

If a red icon appears instead of this one , please contact technical support immediately.

" + download: + title: "Download" + content: "Click here to download the invoice in PDF format." + refund: + title: "Credit note" + content: "Allows you to generate a credit note for the invoice on this line or some of its sub-elements. Warning: This will only generate the accounting document, the actual refund of the user will always be your responsibility." + payment-schedules: + title: "Payment schedules" + content: "

Some subscription plans may be configured to allow the members to pay them with a monthly payment schedule.

Here you can view all existing payment schedules and manage their deadlines.

Click on [+] at the beginning of a row to display all deadlines associated with a payment schedule, and run some actions on them.

" + settings: + title: "Settings" + content: "

Here you can modify the parameters for invoices generation. Click on the item you are interested in to start editing.

In particular, this is where you can set if you are subject to VAT and the applicable rate.

" + codes: + title: "Accounting codes" + content: "Set the accounting codes here for all kinds of entries generated by the software. This setting is only required if you use the accounting export functionality." + export: + title: "Accounting export" + content: "Once the codes have been configured, click here to access the interface allowing you to export the entries to a third-party accounting software." + payment: + title: "Payment settings" + content: "If you want to allow your members to book directly online by paying by credit card, you can activate and configure this feature from this page." + periods: + title: "Close accounting periods" + content: "

The regulations of your country may require you to close your accounts regularly. The interface accessible from this button allows you to do this.

In France, if you are subject to VAT anti-fraud law BOI-TVA-DECLA-30-10-30-20160803, this closing is mandatory at least once a year.

As a reminder, if you have to use a certified software (take the test here), you are under the legal obligation to provide a certificate of compliance of the software. Contact-us to get it.

" + pricing: + welcome: + title: "Subscriptions & Prices" + content: "Manage subscription plans and prices for the various services you offer to your members." + new_plan: + title: "New subscription plan" + content: "Create subscription plans to offer preferential prices on machines and spaces to regular users." + trainings: + title: "Trainings" + content: "Define training prices here, by user group." + machines: + title: "Machines" + content: "Define here the prices of the machine slots, by user group. These prices will be applied to users who do not have subscriptions." + spaces: + title: "Spaces" + content: "In the same way, define here the prices of the spaces slots, for the users without subscriptions." + credits: + title: "Credits" + content: "

Credits allow you to give certain services for free to users who subscribe to a plan.

You can, for example, offer 2 hours of 3D printer for all annual subscriptions; or training of your choice for student subscribers, etc.

" + coupons: + title: "Coupons" + content: "Create and manage promotional coupons allowing to offer punctual discounts to their holders." + events: + welcome: + title: "Events" + content: "Create events, track their reservations and organize them from this page." + list: + title: "The events" + content: "This list displays all past or future events, as well as the number of reservations for each of them." + filter: + title: "Filter events" + content: "Only display upcoming events in the list below; or on the contrary, only those already passed." + categories: + title: "Categories" + content: "Categories help your users know what type of event it is. A category is required for each of the newly created events." + themes: + title: "Themes" + content: "

Themes are an additional (and optional) categorization of your events. They can group together different events of very different forms.

For example, a two-day course about marquetry and an evening workshop about the handling of the wood planer, can be found in the theme « carpentry ».

" + ages: + title: "Age groups" + content: "This other optional filter will help your users find events suited to their profile." + prices: + title: "Pricing categories" + content: "The price of events does not depend on groups or subscriptions, but on the categories you define on this page." + projects: + welcome: + title: "Projects" + content: "Here you can define all the elements that will be available for members to document the projects they carry out. You can also define various parameters related to the projects." + abuses: + title: "Manage reports" + content: "

Access here the management of reports.

Visitors can signal projects, for example for copyright infringement or for hate speech.

GDPR requires you to delete this reporting data once the required actions have been taken.

" + settings: + title: "Settings" + content: "

Comments, CAD files ... Manage project parameters here

You can also activate OpenLab projects, in order to display the projects shared by other Fab Labs in your gallery.

" + statistics: + welcome: + title: "Statistics" + content: "

From here, you will be able to access many statistics on your members and their uses within your Fab Lab.

In accordance with GDPR, users who have deleted their account continue to be reported in the statistics, but anonymously.

" + export: + title: "Export data" + content: "You can choose to export all or part of the statistical data to an Excel file." + trending: + title: "Evolution" + content: "Visualize the evolution over time of the main uses of your Fab Lab, thanks to graphs and curves." + settings: + welcome: + title: "Application customization" + content: "From here, you can configure the general settings of Fab-manager, enable or disable the optional modules and customize various elements of the interface." + general: + title: "General settings" + content: "A lot a settings can be customized from here. Take time to look all over this page, it will let you customize messages, documents, optional modules, registrations, visual aspect of Fab-manager, and much more." + home: + title: "Customize home page" + content: "

This WYSIWYG editor allows you to customize the appearance of the home page while using different components (last tweet, brief, etc.).

Warning: Keep in mind that any uncontrolled changes can break the appearance of the home page.

" + components: + title: "Insert a component" + content: "Click here to insert a pre-existing component into the home page." + codeview: + title: "Display HTML code" + content: "This button allows you to directly view and modify the code of the home page. This is the recommended way to proceed, but it requires prior knowledge of HTML." + reset: + title: "Go back" + content: "At any time, you can restore the original home page by clicking here." + css: + title: "Customize the style sheet" + content: "For advanced users, it is possible to define a custom style sheet (CSS) for the home page." + about: + title: "About" + content: "Fully personalize this page to present your activity." + privacy: + title: "Privacy policy" + content: "

Explain here how you use the data you collect about your members.

GDPR requires that a confidentiality policy is defined, as well as a data protection officer.

" + draft: + title: "Draft" + content: "Click here to view a privacy policy draft with holes, which you just need to read and complete." + reservations: + title: "Reservations" + content: "Opening hours, chance to cancel reservations... Each Fablab has its own reservation rules, which you can define on this page." + open_api: + welcome: + title: "OpenAPI" + content: "Fab-manager offers an open API allowing third-party software to deal simply with its data. This screen allows you to grant accesses to this API." + doc: + title: "Documentation" + content: "Click here to access the API online documentation." + store: + manage_the_store: "Manage the Store" + settings: "Settings" + all_products: "All products" + categories_of_store: "Store categories" + the_orders: "Orders" + back_to_list: "Back to list" + product_categories: + title: "All categories" + info: "Arrange categories with a drag and drop on a maximum of two levels. The order of the categories will be identical between the list below and the public view. Please note that you can delete a category or a sub-category even if they are associated with products. Those products will be left without categories. If you delete a category that contains sub-categories, the latter will also be deleted." + manage_product_category: + create: "Create a product category" + update: "Modify the product category" + delete: "Delete the product category" + product_category_modal: + new_product_category: "Create a category" + edit_product_category: "Modify a category" + product_category_form: + name: "Name of category" + slug: "URL" + select_parent_product_category: "Choose a parent category (N1)" + no_parent: "No parent" + create: + error: "Unable to create the category: " + success: "The new category has been created." + update: + error: "Unable to modify the category: " + success: "The category has been modified." + delete: + confirm: "Do you really want to delete {CATEGORY}?
If it has sub-categories, they will also be deleted." + save: "Delete" + error: "Unable to delete the category: " + success: "The category has been successfully deleted" + save: "Save" + required: "This field is required" + slug_pattern: "Only lowercase alphanumeric groups of characters separated by an hyphen" + categories_filter: + filter_categories: "By categories" + filter_apply: "Apply" + machines_filter: + filter_machines: "By machines" + filter_apply: "Apply" + keyword_filter: + filter_keywords_reference: "By keywords or reference" + filter_apply: "Apply" + stock_filter: + stock_internal: "Private stock" + stock_external: "Public stock" + filter_stock: "By stock status" + filter_stock_from: "From" + filter_stock_to: "to" + filter_apply: "Apply" + products: + unexpected_error_occurred: "An unexpected error occurred. Please try again later." + all_products: "All products" + create_a_product: "Create a product" + filter: "Filter" + filter_clear: "Clear all" + filter_apply: "Apply" + filter_categories: "By categories" + filter_machines: "By machines" + filter_keywords_reference: "By keywords or reference" + filter_stock: "By stock status" + stock_internal: "Private stock" + stock_external: "Public stock" + filter_stock_from: "From" + filter_stock_to: "to" + sort: + name_az: "A-Z" + name_za: "Z-A" + price_low: "Price: low to high" + price_high: "Price: high to low" + store_list_header: + result_count: "Result count:" + sort: "Sort:" + visible_only: "Visible products only" + product_item: + product: "product" + visible: "visible" + hidden: "hidden" + stock: + internal: "Private stock" + external: "Public stock" + unit: "unit" + new_product: + add_a_new_product: "Add a new product" + successfully_created: "The new product has been created." + edit_product: + successfully_updated: "The product has been updated." + successfully_cloned: "The product has been duplicated." + product_form: + product_parameters: "Product parameters" + stock_management: "Stock management" + description: "Description" + description_info: "The text will be presented in the product sheet. You have a few editorial styles at your disposal." + name: "Name of product" + sku: "Product reference (SKU)" + slug: "URL" + is_show_in_store: "Available in the store" + is_active_price: "Activate the price" + active_price_info: "Is this product visible by the members on the store?" + price_and_rule_of_selling_product: "Price and rule for selling the product" + price: "Price of product" + quantity_min: "Minimum number of items for the shopping cart" + linking_product_to_category: "Linking this product to an existing category" + assigning_category: "Assigning a category" + assigning_category_info: "You can only declare one category per product. If you assign this product to a sub-category, it will automatically be assigned to its parent category as well." + assigning_machines: "Assigning machines" + assigning_machines_info: "You can link one or more machines from your workshop to your product. This product will then be subject to the filters on the catalogue view. The selected machines will be linked to the product." + product_files: "Document" + product_files_info: "Add documents related to this product. They will be presented in the product sheet, in a separate block. You can only upload PDF documents." + add_product_file: "Add a document" + product_images: "Visuals of the product" + product_images_info: "We advise you to use a square format, JPG or PNG. For JPG, please use white for the background colour. The main visual will be the first presented in the product sheet." + add_product_image: "Add a visual" + save: "Save" + clone: "Duplicate" + product_stock_form: + stock_up_to_date: "Stock up to date" + date_time: "{DATE} - {TIME}" + ongoing_operations: "Ongoing stock operations" + save_reminder: "Don't forget to save your operations" + low_stock_threshold: "Define a low stock threshold" + stock_threshold_toggle: "Activate stock threshold" + stock_threshold_info: "Define a low stock threshold and receive a notification when it's reached. When the threshold is reached, the product quantity is labeled as low." + low_stock: "Low stock" + threshold_level: "Minimum threshold level" + threshold_alert: "Notify me when the threshold is reached" + events_history: "Events history" + event_type: "Events:" + reason: "Reason" + stocks: "Stock:" + internal: "Private stock" + external: "Public stock" + edit: "Edit" + all: "All types" + remaining_stock: "Remaining stock" + type_in: "Add" + type_out: "Remove" + cancel: "Cancel this operation" + product_stock_modal: + modal_title: "Manage stock" + internal: "Private stock" + external: "Public stock" + new_event: "New stock event" + addition: "Addition" + withdrawal: "Withdrawal" + update_stock: "Update stock" + reason_type: "Reason" + stocks: "Stock:" + quantity: "Quantity" + stock_movement_reason: + inward_stock: "Inward stock" + returned: "Returned by client" + cancelled: "Canceled by client" + inventory_fix: "Inventory fix" + sold: "Sold" + missing: "Missing in stock" + damaged: "Damaged product" + other_in: "Other (in)" + other_out: "Other (out)" + clone_product_modal: + clone_product: "Duplicate the product" + clone: "Duplicate" + name: "Name" + sku: "Product reference (SKU)" + is_show_in_store: "Available in the store" + active_price_info: "Is this product visible by the members on the store?" + orders: + heading: "Orders" + create_order: "Create an order" + filter: "Filter" + filter_clear: "Clear all" + filter_apply: "Apply" + filter_ref: "By reference" + filter_status: "By status" + filter_client: "By client" + filter_period: "By period" + filter_period_from: "From" + filter_period_to: "to" + state: + cart: 'Cart' + in_progress: 'Under preparation' + paid: "Paid" + payment_failed: "Payment error" + canceled: "Canceled" + ready: "Ready" + refunded: "Refunded" + delivered: "Delivered" + sort: + newest: "Newest first" + oldest: "Oldest first" + store_settings: + title: "Settings" + withdrawal_instructions: 'Product withdrawal instructions' + withdrawal_info: "This text is displayed on the checkout page to inform the client about the products withdrawal method" + store_hidden_title: "Store publicly available" + store_hidden_info: "You can hide the store to the eyes of the members and the visitors." + store_hidden: "Hide the store" + save: "Save" + update_success: "The settings were successfully updated" + invoices_settings_panel: + disable_invoices_zero: "Disable the invoices at 0" + disable_invoices_zero_label: "Do not generate invoices at {AMOUNT}" + filename: "Edit the file name" + filename_info: "Information

The invoices are generated as PDF files, named with the following prefix.

" + schedule_filename: "Edit the payment schedule file name" + schedule_filename_info: "Information

The payment shedules are generated as PDF files, named with the following prefix.

" + prefix: "Prefix" + example: "Example" + save: "Save" + update_success: "The settings were successfully updated" + vat_settings_modal: + title: "VAT settings" + update_success: "The VAT settings were successfully updated" + enable_VAT: "Enable VAT" + VAT_name: "VAT name" + VAT_name_help: "Some countries or regions may require that the VAT is named according to their specific local regulation" + VAT_rate: "VAT rate" + VAT_rate_help: "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." + advanced: "More rates" + hide_advanced: "Less rates" + show_history: "Show the changes history" + 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_rate_product: "Products (store)" + multi_VAT_notice: "Please note: The current general rate is {RATE}%. You can define different VAT rates for each category.

For example, you can override this value, only for machine reservations, by filling in the corresponding field beside. If you don't fill any value, the general rate will apply." + save: "Save" + setting_history_modal: + title: "Changes history" + no_history: "No changes for now." + setting: "Setting" + value: "Value" + date: "Changed at" + operator: "By" + editorial_block_form: + content: "Content" + content_is_required: "You must provide a content. If you wish to disable the banner, toggle the switch above this field." + label_is_required: "You must provide a label. If you wish to disable the button, toggle the switch above this field." + url_is_required: "You must provide a link for your button." + url_must_be_safe: "The button link should start with http://... or https://..." + title: "Banner" + switch: "Display the banner" + cta_switch: "Display a button" + cta_label: "Button label" + cta_url: "Button link" diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 3af29bcbb..c3b88f936 100644 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -2,82 +2,82 @@ pt: app: admin: edit_destroy_buttons: - deleted: "Successfully deleted." - unable_to_delete: "Unable to delete: " - delete_item: "Delete the {TYPE}" - confirm_delete: "Delete" - delete_confirmation: "Are you sure you want to delete this {TYPE}?" + deleted: "Excluído com êxito." + unable_to_delete: "Não foi possível excluir: " + delete_item: "Excluir o {TYPE}" + confirm_delete: "Deletar" + delete_confirmation: "Tem certeza que deseja excluir este {TYPE}?" machines: - the_fablab_s_machines: "The FabLab's machines" - all_machines: "All machines" - add_a_machine: "Add a new machine" - manage_machines_categories: "Manage machines categories" - machines_settings: "Settings" + the_fablab_s_machines: "As máquinas do FabLab" + all_machines: "Todas as máquinas" + add_a_machine: "Adicionar nova máquina" + manage_machines_categories: "Gerenciar categorias de máquinas" + machines_settings: "Configurações" machines_settings: - title: "Settings" - generic_text_block: "Editorial text block" - generic_text_block_info: "Displays an editorial block above the list of machines visible to members." - generic_text_block_switch: "Display editorial block" - cta_switch: "Display a button" - cta_label: "Button label" - cta_url: "url" - save: "Save" - successfully_saved: "Your banner was successfully saved." + title: "Configurações" + generic_text_block: "Bloco de texto editorial" + generic_text_block_info: "Exibe um bloco editorial acima da lista de máquinas visíveis aos membros." + generic_text_block_switch: "Exibir bloco editorial" + cta_switch: "Mostrar o Botão" + cta_label: "Rótulo do botão" + cta_url: "URL" + save: "Salvar" + successfully_saved: "Seu banner foi salvo com sucesso." machine_categories_list: - machine_categories: "Machines categories" - add_a_machine_category: "Add a machine category" - name: "Name" - machines_number: "Number of machines" - machine_category: "Machine category" + machine_categories: "Categorias das máquinas" + add_a_machine_category: "Adicionar uma categoria de máquina" + name: "Nome" + machines_number: "Número de máquinas" + machine_category: "Categoria de máquina" machine_category_modal: - new_machine_category: "New category" - edit_machine_category: "Edit category" - successfully_created: "The new machine category has been successfully created." - unable_to_create: "Unable to delete the machine category: " - successfully_updated: "The machine category has been successfully updated." - unable_to_update: "Unable to modify the machine category: " + new_machine_category: "Nova categoria" + edit_machine_category: "Editar categoria" + successfully_created: "A nova categoria de máquina foi criada com sucesso." + unable_to_create: "Não foi possível excluir a categoria da máquina: " + successfully_updated: "A categoria de máquina foi atualizada com sucesso." + unable_to_update: "Não foi possível modificar a categoria de máquina: " machine_category_form: - name: "Name of category" - assigning_machines: "Assign machines to this category" - save: "Save" + name: "Nome da categoria" + assigning_machines: "Atribuir máquinas a esta categoria" + save: "Salvar" machine_form: - ACTION_title: "{ACTION, select, create{New} other{Update the}} machine" - watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions: "Watch out! When creating a new machine, its prices are initialized at 0 for all subscriptions." + ACTION_title: "{ACTION, select, create{Nova} other{Atualize a}} máquina" + watch_out_when_creating_a_new_machine_its_prices_are_initialized_at_0_for_all_subscriptions: "Cuidado! Ao criar uma nova máquina, seus preços são inicializados em 0 para todas as assinaturas." consider_changing_them_before_creating_any_reservation_slot: "Consider changing them before creating any reservation slot." - description: "Description" - name: "Name" + description: "Descrição" + name: "Nome" illustration: "Visual" - technical_specifications: "Technical specifications" - category: "Category" - attachments: "Attachments" - attached_files_pdf: "Attached files (pdf)" - add_an_attachment: "Add an attachment" - settings: "Settings" - disable_machine: "Disable machine" - disabled_help: "When disabled, the machine won't be reservable and won't appear by default in the machines list." - reservable: "Can this machine be reserved?" + technical_specifications: "Especificações técnicas" + category: "Categoria" + attachments: "Anexos" + attached_files_pdf: "Arquivos anexados (pdf)" + add_an_attachment: "Adicionar um anexo" + settings: "Configurações" + disable_machine: "Desativar máquina" + disabled_help: "Quando desativada, a máquina não será reservável e não será exibida por padrão na lista de máquinas." + reservable: "Esta máquina pode ser reservada?" reservable_help: "When disabled, the machine will be shown in the default list of machines, but without the reservation button. If you already have created some availability slots for this machine, you may want to remove them: do it from the admin agenda." - save: "Save" + save: "Salvar" create_success: "The machine was created successfully" update_success: "The machine was updated successfully" training_form: ACTION_title: "{ACTION, select, create{New} other{Update the}} training" beware_when_creating_a_training_its_reservation_prices_are_initialized_to_zero: "Beware, when creating a training, its reservation prices are initialized at zero." dont_forget_to_change_them_before_creating_slots_for_this_training: "Don't forget to change them before creating slots for this training." - description: "Description" - name: "Name" - illustration: "Illustration" - add_a_new_training: "Add a new training" - validate_your_training: "Validate your training" - settings: "Settings" - associated_machines: "Associated machines" + description: "Descrição" + name: "Nome" + illustration: "Ilustração" + add_a_new_training: "Adicionar um novo treinamento" + validate_your_training: "Validar seu treinamento" + settings: "Confirgurações" + associated_machines: "Máquinas associadas" associated_machines_help: "If you associate a machine to this training, the members will need to successfully pass this training before being able to reserve the machine." default_seats: "Default number of seats" public_page: "Show in training lists" public_help: "When unchecked, this option will prevent the training from appearing in the trainings list." - disable_training: "Disable the training" + disable_training: "Desativar o treinamento" disabled_help: "When disabled, the training won't be reservable and won't appear by default in the trainings list." - automatic_cancellation: "Automatic cancellation" + automatic_cancellation: "Cancelamento automático" automatic_cancellation_info: "If you edit specific conditions here, the general cancellation conditions will no longer be taken into account. You will be notified if a session is cancelled. Credit notes and refunds will be automatic if the wallet is enabled. Otherwise you will have to do it manually." automatic_cancellation_switch: "Activate automatic cancellation for this training" automatic_cancellation_threshold: "Minimum number of registrations to maintain a session" @@ -118,35 +118,35 @@ pt: description: "Description" attachments: "Attachments" attached_files_pdf: "Attached files (pdf)" - add_a_new_file: "Add a new file" - event_category: "Event category" - dates_and_opening_hours: "Dates and opening hours" - all_day: "All day" - all_day_help: "Will the event last all day or do you want to set times?" - start_date: "Start date" - end_date: "End date" - start_time: "Start time" - end_time: "End time" - recurrence: "Recurrence" - _and_ends_on: "and ends on" - prices_and_availabilities: "Prices and availabilities" + add_a_new_file: "Adicionar um novo arquivo" + event_category: "Categoria do evento" + dates_and_opening_hours: "Datas e horário de funcionamento" + all_day: "O dia todo" + all_day_help: "O evento vai durar o dia inteiro ou você quer definir as horas?" + start_date: "Data de início" + end_date: "Data de término" + start_time: "Horário de início" + end_time: "Hora de término" + recurrence: "Recorrência" + _and_ends_on: "e termina em" + prices_and_availabilities: "Preços e disponibilidade" standard_rate: "Standard rate" - 0_equal_free: "0 = free" + 0_equal_free: "0 = grátis" fare_class: "Fare class" - price: "Price" - seats_available: "Seats available" - seats_help: "If you leave this field empty, this event will be available without reservations." - event_themes: "Event themes" - age_range: "Age range" - add_price: "Add a price" - save: "Save" - create_success: "The event was created successfully" - events_updated: "{COUNT, plural, =1{One event was} other{{COUNT} Events were}} successfully updated" - events_not_updated: "{TOTAL, plural, =1{The event was} other{On {TOTAL} events {COUNT, plural, =1{one was} other{{COUNT} were}}}} not updated." - error_deleting_reserved_price: "Unable to remove the requested price because it is associated with some existing reservations" - other_error: "An unexpected error occurred while updating the event" + price: "Preço" + seats_available: "Vagas disponíveis" + seats_help: "Se deixar este campo em branco, este evento estará disponível sem reservas." + event_themes: "Temas de eventos" + age_range: "Faixa etária" + add_price: "Adicionar um preço" + save: "Salvar" + create_success: "O evento foi criado com sucesso" + events_updated: "{COUNT, plural, =1{Um evento foi atualizado} other{{COUNT} eventos foram atualizados}} com sucesso" + events_not_updated: "{TOTAL, plural, =1{O evento não foi atualizado} other{Dos {TOTAL} eventos, {COUNT, plural, =1{um não foi atualizado} other{{COUNT} não foram atualizados}}}}." + error_deleting_reserved_price: "Não foi possível remover o preço solicitado porque ele está associado a algumas reservas existentes" + other_error: "Ocorreu um erro inesperado ao atualizar o evento" recurring: - none: "None" + none: "Nenhuma" every_days: "Every days" every_week: "Every week" every_month: "Every month" @@ -184,7 +184,7 @@ pt: notified_partner: "Notified partner" new_user: "New user" alert_partner_notification: "As part of a partner subscription, some notifications may be sent to this user." - disabled: "Disable subscription" + disabled: "Desativar a assinatura" disabled_help: "Beware: disabling this plan won't unsubscribe users having active subscriptions with it." duration: "Duration" partnership: "Partnership" @@ -195,19 +195,19 @@ pt: slots_visibility_help: "You can determine how far in advance subscribers can view and reserve machine slots. When this setting is set, it takes precedence over the general settings." machines_visibility: "Visibility time limit, in hours (machines)" visibility_minimum: "Visibility cannot be less than 7 hours" - save: "Save" + save: "Salvar" create_success: "Plan(s) successfully created. Don't forget to redefine prices." update_success: "The plan was updated successfully" plan_limit_form: usage_limitation: "Limitation of use" usage_limitation_info: "Define a maximum number of reservation hours per day and per machine category. Machine categories that have no parameters configured will not be subject to any limitation." usage_limitation_switch: "Restrict machine reservations to a number of hours per day." - new_usage_limitation: "Add a limitation of use" - all_limitations: "All limitations" - by_category: "By machines category" - by_machine: "By machine" - category: "Machines category" - machine: "Machine name" + new_usage_limitation: "Adicionar uma limitação de uso" + all_limitations: "Todas as limitações" + by_category: "Por categoria de máquinas" + by_machine: "Por máquina" + category: "Categoria de máquinas" + machine: "Nome da máquina" max_hours_per_day: "Max. hours/day" ongoing_limitations: "Ongoing limitations" saved_limitations: "Saved limitations" @@ -224,26 +224,26 @@ pt: categories_info: "If you select all machine categories, the limits will apply across the board." machine_info: "Please note that if you have already created a limitation for the machines category including the selected machine, it will be permanently overwritten." max_hours_per_day: "Maximum number of reservation hours per day" - confirm: "Confirm" + confirm: "Confirmar" partner_modal: title: "Create a new partner" create_partner: "Create the partner" - first_name: "First name" - surname: "Last name" - email: "Email address" + first_name: "Primeiro nome" + surname: "Último Nome" + email: "Endereço de e-mail" plan_pricing_form: - prices: "Prices" + prices: "Preços" about_prices: "The prices defined here will apply to members subscribing to this plan, for machines and spaces. All prices are per hour." - copy_prices_from: "Copy prices from" + copy_prices_from: "Copiar preços de" copy_prices_from_help: "This will replace all the prices of this plan with the prices of the selected plan" - machines: "Machines" - spaces: "Spaces" + machines: "Máquinas" + spaces: "Espaços" update_recurrent_modal: title: "Periodic event 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_event: "Apenas este evento" edit_this_and_next: "This event and the followings" - edit_all: "All events" + edit_all: "Todos os eventos" date_wont_change: "Warning: you have changed the event date. This modification won't be propagated to other occurrences of the periodic event." confirm: "Update the {MODE, select, single{event} other{events}}" advanced_accounting_form: @@ -1551,7 +1551,7 @@ pt: customization_of_SETTING_successfully_saved: "Personalização do {SETTING} salvo com êxito." error_SETTING_locked: "Não foi possível atualizar a configuração: {SETTING} está bloqueado. Por favor contate o administrador do sistema." an_error_occurred_saving_the_setting: "Ocorreu um erro ao salvar a configuração. Por favor, tente novamente mais tarde." - save: "salvar" + save: "Salvar" #global application parameters and customization settings: customize_the_application: "Customizar a aplicação" @@ -1608,10 +1608,10 @@ pt: visibility_for_other_members: "Para todos os outros membros" reservation_deadline: "Impedir a reserva da última hora" reservation_deadline_help: "Se você aumentar o período prévio, os membros não serão capazes de reservar um slot X minutos antes do seu início." - machine_deadline_minutes: "Machine prior period (minutes)" - training_deadline_minutes: "Training prior period (minutes)" - event_deadline_minutes: "Event prior period (minutes)" - space_deadline_minutes: "Space prior period (minutes)" + machine_deadline_minutes: "Período prévio das máquinas (minutos)" + training_deadline_minutes: "Período prévio dos treinamentos (minutos)" + event_deadline_minutes: "Período prévio dos eventos (minutos)" + space_deadline_minutes: "Período prévio dos espaços (minutos)" ability_for_the_users_to_move_their_reservations: "Habilidade para os usuários mover suas reservas" reservations_shifting: "Mudança de reservas" prior_period_hours: "Período anterior (horas)" @@ -1788,8 +1788,8 @@ pt: neutral: "Neutro." eg: "ex:" the_team: "A equipe" - male_preposition: "o" - female_preposition: "a" + male_preposition: "do" + female_preposition: "da" neutral_preposition: "" elements_ordering: "Ordenação de elementos" machines_order: "Ordem das máquinas" diff --git a/config/locales/app.logged.it.yml b/config/locales/app.logged.it.yml new file mode 100644 index 000000000..51a2099dd --- /dev/null +++ b/config/locales/app.logged.it.yml @@ -0,0 +1,324 @@ +it: + app: + logged: + #user's profile completion page when logging from an SSO provider + profile_completion: + confirm_your_new_account: "Confirm your new account" + or: "or" + do_you_already_have_an_account: "Do you already have an account?" + do_not_fill_the_form_beside_but_specify_here_the_code_you_ve_received_by_email_to_recover_your_access: "Do not fill the form beside but specify here the code you've received by email, to recover your access." + just_specify_code_here_to_recover_access: "Just specify here the code you've received by email to recover your access." + i_did_not_receive_the_code: "I didn't receive the code" + authentification_code: "Authentification code" + confirm_my_code: "Confirm my code" + an_unexpected_error_occurred_check_your_authentication_code: "An unexpected error occurred, please check your authentication code." + send_code_again: "Send the code again" + email_address_associated_with_your_account: "Email address associated with your account" + email_is_required: "Email address is required" + email_format_is_incorrect: "Email format is incorrect" + code_successfully_sent_again: "Code successfully sent again" + 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" + your_profile_has_been_successfully_updated: "Your profile has been successfully updated." + completion_header_info: + rules_changed: "Please fill the following form to update your profile and continue to use the platform." + sso_intro: "You've just created a new account on {GENDER, select, neutral{} other{the}} {NAME}, by logging from" + duplicate_email_info: "It looks like your email address is already used by another user. Check your email address and please input below the code you have received." + details_needed_info: "To finalize your account, we need some more details." + profile_form_option: + title: "New on this platform?" + please_fill: "Please fill in the following form to create your account." + disabled_data_from_sso: "Some data may have already been provided by {NAME} and cannot be modified." + confirm_instructions_html: "Once you are done, please click on Save to confirm your account and start using the application." + duplicate_email_html: "It looks like your email address ({EMAIL}) is already associated with another account. If this account is not yours, please click on the following button to change the email associated with your {PROVIDER} account." + edit_profile: "Change my data" + after_edition_info_html: "Once your data are up to date, click on the synchronization button below, or disconnect then reconnect for your changes to take effect." + sync_profile: "Sync my profile" + dashboard: + #dashboard: public profile + profile: + empty: '' + #dashboard: edit my profile + settings: + last_activity_on_: "Last activity on {DATE}" + i_want_to_change_group: "I want to change group!" + your_subscription_expires_on_: "Your subscription expires on" + no_subscriptions: "No subscriptions" + i_want_to_subscribe: "I want to subscribe!" + to_come: "to come" + approved: "approved" + projects: "Projects" + no_projects: "No projects" + labels: "Labels" + no_labels: "No labels" + cookies: "Cookies" + cookies_accepted: "You have accepted cookies" + cookies_declined: "You have refused cookies" + cookies_unset: "You have not chosen yet" + reset_cookies: "Change my choice" + delete_my_account: "Delete my account" + edit_my_profile: "Edit my profile" + your_group_has_been_successfully_changed: "Your group has been successfully changed." + an_unexpected_error_prevented_your_group_from_being_changed: "An unexpected error prevented your group from being changed." + confirmation_required: "Confirmation required" + confirm_delete_your_account: "Do you really want to delete your account?" + 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." + your_user_account_has_been_successfully_deleted_goodbye: "Your user account has been successfully deleted. Goodbye." + an_error_occured_preventing_your_account_from_being_deleted: "An error occurred, preventing your account from being deleted." + 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" + trainings: "Trainings" + no_trainings: "No trainings" + subscription: "Subscription" + group: "Group" + or: "or" + confirm_changes: "Confirm changes" + 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." + your_profile_has_been_successfully_updated: "Your profile has been successfully updated." + #dashboard: my projects + projects: + you_dont_have_any_projects: "You don't have any projects." + add_a_project: "Add a project" + author: "Author" + collaborator: "Collaborator" + rough_draft: "Draft" + description: "Description" + machines_and_materials: "Machines and materials" + machines: "Machines" + materials: "Materials" + collaborators: "Collaborators" + #dashboard: my trainings + trainings: + your_next_trainings: "Your next trainings" + your_previous_trainings: "Your previous trainings" + your_approved_trainings: "Your approved trainings" + 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" + canceled: "Canceled" + #dashboard: my events + events: + your_next_events: "Your next events" + no_events_to_come: "No events to come" + your_previous_events: "Your previous events" + no_passed_events: "No passed events" + NUMBER_normal_places_reserved: "{NUMBER} {NUMBER, plural, =0{} =1{normal place reserved} other{normal places reserved}}" + NUMBER_of_NAME_places_reserved: "{NUMBER} {NUMBER, plural, =0{} =1{of {NAME} place reserved} other{of {NAME} places reserved}}" + #dashboard: my invoices + invoices: + reference_number: "Reference number" + date: "Date" + price: "Price" + download_the_invoice: "Download the invoice" + download_the_credit_note: "Download the refund invoice" + no_invoices_for_now: "No invoices for now." + payment_schedules_dashboard: + no_payment_schedules: "No payment schedules to display" + load_more: "Load more" + card_updated_success: "Your card was successfully updated" + supporting_documents_files: + file_successfully_uploaded: "The supporting documents were sent." + unable_to_upload: "Unable to send the supporting documents: " + supporting_documents_files: "Supporting documents" + my_documents_info: "Due to your group declaration, some supporting documents are required. Once submitted, these documents will be verified by the administrator." + upload_limits_alert_html: "Warning!
You can submit your documents as PDF or images (JPEG, PNG). Maximum allowed size: {SIZE} Mb" + file_size_error: "The file size exceeds the limit ({SIZE} MB)" + save: "Save" + browse: "Browse" + edit: "Edit" + reservations_dashboard: + machine_section_title: "Machines reservations" + space_section_title: "Spaces reservations" + reservations_panel: + title: "My reservations" + upcoming: "Upcoming" + date: "Date" + history: "History" + no_reservation: "No reservation" + show_more: "Show more" + cancelled_slot: "Cancelled" + credits_panel: + title: "My credits" + info: "Your subscription comes with free credits you can use when reserving" + remaining_credits_html: "You can book {REMAINING} {REMAINING, plural, one{slot} other{slots}} for free." + used_credits_html: "You have already used {USED} {USED, plural, =0{credit} one{credit} other{credits}}." + no_credits: "You don't have any credits yet. Some subscriptions may allow you to book some slots for free." + prepaid_packs_panel: + title: "My prepaid packs" + name: "Prepaid pack name" + end: "Expiry date" + countdown: "Countdown" + history: "History" + consumed_hours: "{COUNT, plural, =1{1H consumed} other{{COUNT}H consumed}}" + cta_info: "You can buy prepaid hours packs to book machines and benefit from discounts. Choose a machine to buy a corresponding pack." + select_machine: "Select a machine" + cta_button: "Buy a pack" + no_packs: "No prepaid packs available for sale" + reserved_for_subscribers_html: 'The purchase of prepaid packs is reserved for subscribers.
Subscribe now to benefit.' + #public profil of a member + members_show: + members_list: "Members list" + #list of members accepting to be contacted + members: + the_fablab_members: "The Fab Lab members" + display_more_members: "Display more members..." + no_members_for_now: "No members for now" + avatar: "Avatar" + user: "User" + pseudonym: "Pseudonym" + email_address: "Email address" + #add a new project + projects_new: + add_a_new_project: "Add a new project" + #modify an existing project + projects_edit: + edit_the_project: "Edit the project" + rough_draft: "Draft" + publish: "Publish" + #book a machine + machines_reserve: + machine_planning: "Machine planning" + i_ve_reserved: "I've reserved" + not_available: "Not available" + i_reserve: "I reserve" + i_shift: "I shift" + i_change: "I change" + do_you_really_want_to_cancel_this_reservation: "Do you really want to cancel this reservation?" + reservation_was_cancelled_successfully: "Reservation was cancelled successfully." + cancellation_failed: "Cancellation failed." + a_problem_occured_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." + #modal telling users that they must wait for their training validation before booking a machine + pending_training_modal: + machine_reservation: "Machine reservation" + wait_for_validated: "You must wait for your training is being validated by the FabLab team to book this machine." + training_will_occur_DATE_html: "Your training will occur at {DATE}" + 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 {TRAINING}." + training_or_training_html: " or the training " + enroll_now: "Enroll to the training" + no_enroll_for_now: "I don't want to enroll now" + close: "Close" + 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." + no_thanks: "No, thanks" + 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}" + 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}}" + 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." + #book a training + trainings_reserve: + trainings_planning: "Trainings planning" + planning_of: "Planning of " #eg. Planning of 3d printer training + all_trainings: "All trainings" + cancel_my_selection: "Cancel my selection" + i_change: "I change" + i_shift: "I shift" + i_ve_reserved: "I've reserved" + #book a space + space_reserve: + planning_of_space_NAME: "Planning of the {NAME} space" + i_ve_reserved: "I've reserved" + i_shift: "I shift" + i_change: "I change" + notifications: + notifications_center: "Notifications center" + notifications_list: + notifications: "All notifications" + mark_all_as_read: "Mark all as read" + date: "Date" + notif_title: "Title" + no_new_notifications: "No new notifications." + archives: "Archives" + no_archived_notifications: "No archived notifications." + load_the_next_notifications: "Load the next notifications..." + notification_inline: + mark_as_read: "Mark as read" + notifications_center: + notifications_list: "All notifications" + notifications_settings: "My notifications preferences" + notifications_category: + enable_all: "Enable all" + disable_all: "Disable all" + notify_me_when: "I wish to be notified when" + users_accounts: "Concerning users notifications" + supporting_documents: "Concerning supporting documents notifications" + agenda: "Concerning agenda notifications" + subscriptions: "Concerning subscriptions notifications" + payments: "Concerning payment schedules notifications" + wallet: "Concerning wallet notifications" + shop: "Concerning shop notifications" + projects: "Concerning projects notifications" + accountings: "Concerning accounting notifications" + trainings: "Concerning trainings notifications" + app_management: "Concerning app management notifications" + notification_form: + notify_admin_when_user_is_created: "A user account has been created" + notify_admin_when_user_is_imported: "A user account has been imported" + notify_admin_profile_complete: "An imported account has completed its profile" + notify_admin_user_merged: "An imported account has been merged with an existing account" + notify_admins_role_update: "The role of a user has changed" + notify_admin_import_complete: "An import is done" + notify_admin_user_group_changed: "A user has changed his group" + notify_admin_user_supporting_document_refusal: "A supporting document has been rejected" + notify_admin_user_supporting_document_files_created: "A user has uploaded a supporting document" + notify_admin_user_supporting_document_files_updated: "A user has updated a supporting document" + notify_admin_member_create_reservation: "A member books a reservation" + notify_admin_slot_is_modified: "A reservation slot has been modified" + notify_admin_slot_is_canceled: "A reservation has been cancelled" + notify_admin_subscribed_plan: "A subscription has been purchased" + notify_admin_subscription_will_expire_in_7_days: "A member subscription expires in 7 days" + notify_admin_subscription_is_expired: "A member subscription has expired" + notify_admin_subscription_extended: "A subscription has been extended" + notify_admin_subscription_canceled: "A member subscription has been cancelled" + notify_admin_payment_schedule_failed: "Card debit failure" + notify_admin_payment_schedule_check_deadline: "A check has to be cashed" + notify_admin_payment_schedule_transfer_deadline: "A bank direct debit has to be confirmed" + notify_admin_payment_schedule_error: "An unexpected error occurred during the card debit" + notify_admin_refund_created: "A refund has been created" + notify_admin_user_wallet_is_credited: "The wallet of an user has been credited" + notify_user_order_is_ready: "Your command is ready" + notify_user_order_is_canceled: "Your command was canceled" + notify_user_order_is_refunded: "Your command was refunded" + notify_admin_low_stock_threshold: "The stock is low" + notify_admin_when_project_published: "A project has been published" + notify_admin_abuse_reported: "An abusive content has been reported" + notify_admin_close_period_reminder: "The fiscal year is coming to an end" + notify_admin_archive_complete: "An accounting archive is ready" + notify_admin_training_auto_cancelled: "A training was automatically cancelled" + notify_admin_export_complete: "An export is available" + notify_user_when_invoice_ready: "An invoice is available" + notify_admin_payment_schedule_gateway_canceled: "A payment schedule has been canceled by the payment gateway" + notify_project_collaborator_to_valid: "You are invited to collaborate on a project" + notify_project_author_when_collaborator_valid: "A collaborator has accepted your invitation to join your project" + notify_admin_order_is_paid: "A new order has been placed" diff --git a/config/locales/app.logged.pt.yml b/config/locales/app.logged.pt.yml index e89af82d5..d3b3be3b0 100644 --- a/config/locales/app.logged.pt.yml +++ b/config/locales/app.logged.pt.yml @@ -144,34 +144,34 @@ pt: browse: "Navegar" edit: "Editar" reservations_dashboard: - machine_section_title: "Machines reservations" - space_section_title: "Spaces reservations" + machine_section_title: "Reservas de máquinas" + space_section_title: "Reservas de espaços" reservations_panel: - title: "My reservations" - upcoming: "Upcoming" - date: "Date" - history: "History" - no_reservation: "No reservation" - show_more: "Show more" - cancelled_slot: "Cancelled" + title: "Minhas reservas" + upcoming: "Próximas" + date: "Data" + history: "Histórico" + no_reservation: "Nenhuma reserva" + show_more: "Exibir mais" + cancelled_slot: "Cancelado" credits_panel: - title: "My credits" - info: "Your subscription comes with free credits you can use when reserving" - remaining_credits_html: "You can book {REMAINING} {REMAINING, plural, one{slot} other{slots}} for free." - used_credits_html: "You have already used {USED} {USED, plural, =0{credit} one{credit} other{credits}}." - no_credits: "You don't have any credits yet. Some subscriptions may allow you to book some slots for free." + title: "Meus créditos" + info: "Sua assinatura vem com créditos gratuitos que você pode usar na reserva" + remaining_credits_html: "Você pode reservar {REMAINING} {REMAINING, plural, one{slot} other{slots}} de graça." + used_credits_html: "Você já usou {USED} {USED, plural, =0{crédito} one{crédito} other{créditos}}." + no_credits: "Você não tem nenhum crédito ainda. Algumas assinaturas podem permitir que você reserve alguns slots gratuitamente." prepaid_packs_panel: - title: "My prepaid packs" - name: "Prepaid pack name" - end: "Expiry date" + title: "Meus pacotes pré-pagos" + name: "Nome do pacote pré-pago" + end: "Data de validade" countdown: "Countdown" - history: "History" - consumed_hours: "{COUNT, plural, =1{1H consumed} other{{COUNT}H consumed}}" + history: "Histórico" + consumed_hours: "{COUNT, plural, =1{1H consumida} other{{COUNT}H consumidas}}" cta_info: "You can buy prepaid hours packs to book machines and benefit from discounts. Choose a machine to buy a corresponding pack." - select_machine: "Select a machine" - cta_button: "Buy a pack" - no_packs: "No prepaid packs available for sale" - reserved_for_subscribers_html: 'The purchase of prepaid packs is reserved for subscribers. Subscribe now to benefit.' + select_machine: "Selecione uma máquina" + cta_button: "Comprar um pacote" + no_packs: "Não há pacotes pré-pagos disponíveis para venda" + reserved_for_subscribers_html: 'A compra de pacotes pré-pagos é reservada para os inscritos. Inscreva-se agora para beneficiar.' #public profil of a member members_show: members_list: "Lista de membros" @@ -254,71 +254,71 @@ pt: notifications: notifications_center: "Centro de notificações" notifications_list: - notifications: "All notifications" - mark_all_as_read: "Mark all as read" - date: "Date" - notif_title: "Title" - no_new_notifications: "No new notifications." - archives: "Archives" - no_archived_notifications: "No archived notifications." - load_the_next_notifications: "Load the next notifications..." + notifications: "Todas as notificações" + mark_all_as_read: "Marcar todas como lidas" + date: "Data" + notif_title: "Título" + no_new_notifications: "Nenhuma nova notificação." + archives: "Arquivos" + no_archived_notifications: "Sem notificações arquivadas." + load_the_next_notifications: "Carregar próximas notificações..." notification_inline: - mark_as_read: "Mark as read" + mark_as_read: "Marcar como lida" notifications_center: - notifications_list: "All notifications" - notifications_settings: "My notifications preferences" + notifications_list: "Todas as notificações" + notifications_settings: "Minhas preferências de notificações" notifications_category: - enable_all: "Enable all" - disable_all: "Disable all" - notify_me_when: "I wish to be notified when" - users_accounts: "Concerning users notifications" - supporting_documents: "Concerning supporting documents notifications" - agenda: "Concerning agenda notifications" - subscriptions: "Concerning subscriptions notifications" - payments: "Concerning payment schedules notifications" - wallet: "Concerning wallet notifications" - shop: "Concerning shop notifications" - projects: "Concerning projects notifications" - accountings: "Concerning accounting notifications" - trainings: "Concerning trainings notifications" - app_management: "Concerning app management notifications" + enable_all: "Ativar tudo" + disable_all: "Desativar tudo" + notify_me_when: "Desejo ser notificado quando" + users_accounts: "Em relação às notificações dos usuários" + supporting_documents: "Em relação às notificações de documentos de apoio" + agenda: "Em relação às notificações da agenda" + subscriptions: "Em relação às notificações de assinaturas" + payments: "Em relação às notificações dos agendamentos de pagamentos" + wallet: "Em relação às notificações de carteiras" + shop: "Em relação às notificações da loja" + projects: "Em relação às notificações de projetos" + accountings: "Em relação às notificações contábeis" + trainings: "Em relação às notificações de treinamentos" + app_management: "Em relação às notificações do gerenciamento da aplicação" notification_form: - notify_admin_when_user_is_created: "A user account has been created" - notify_admin_when_user_is_imported: "A user account has been imported" - notify_admin_profile_complete: "An imported account has completed its profile" - notify_admin_user_merged: "An imported account has been merged with an existing account" - notify_admins_role_update: "The role of a user has changed" - notify_admin_import_complete: "An import is done" - notify_admin_user_group_changed: "A user has changed his group" - notify_admin_user_supporting_document_refusal: "A supporting document has been rejected" - notify_admin_user_supporting_document_files_created: "A user has uploaded a supporting document" - notify_admin_user_supporting_document_files_updated: "A user has updated a supporting document" - notify_admin_member_create_reservation: "A member books a reservation" - notify_admin_slot_is_modified: "A reservation slot has been modified" - notify_admin_slot_is_canceled: "A reservation has been cancelled" - notify_admin_subscribed_plan: "A subscription has been purchased" - notify_admin_subscription_will_expire_in_7_days: "A member subscription expires in 7 days" - notify_admin_subscription_is_expired: "A member subscription has expired" - notify_admin_subscription_extended: "A subscription has been extended" - notify_admin_subscription_canceled: "A member subscription has been cancelled" - notify_admin_payment_schedule_failed: "Card debit failure" - notify_admin_payment_schedule_check_deadline: "A check has to be cashed" + notify_admin_when_user_is_created: "Uma conta de usuário foi criada" + notify_admin_when_user_is_imported: "Uma conta de usuário foi importada" + notify_admin_profile_complete: "Uma conta importada completou seu perfil" + notify_admin_user_merged: "Uma conta importada foi mesclada com uma conta existente" + notify_admins_role_update: "O papel de um usuário foi alterado" + notify_admin_import_complete: "Uma importação foi concluída" + notify_admin_user_group_changed: "Um usuário mudou seu grupo" + notify_admin_user_supporting_document_refusal: "Um documento de apoio foi rejeitado" + notify_admin_user_supporting_document_files_created: "Um usuário enviou um documento de apoio" + notify_admin_user_supporting_document_files_updated: "Um usuário atualizou um documento de apoio" + notify_admin_member_create_reservation: "Um membro agendou uma reserva" + notify_admin_slot_is_modified: "Um slot de reserva foi modificado" + notify_admin_slot_is_canceled: "Uma reserva foi cancelada" + notify_admin_subscribed_plan: "Uma assinatura foi comprada" + notify_admin_subscription_will_expire_in_7_days: "A assinatura de um membro expira em 7 dias" + notify_admin_subscription_is_expired: "A assinatura de um membro expirou" + notify_admin_subscription_extended: "Uma assinatura foi estendida" + notify_admin_subscription_canceled: "Uma assinatura de um membro foi cancelada" + notify_admin_payment_schedule_failed: "Falha no débito do cartão" + notify_admin_payment_schedule_check_deadline: "Um cheque deve ser sacado" notify_admin_payment_schedule_transfer_deadline: "A bank direct debit has to be confirmed" - notify_admin_payment_schedule_error: "An unexpected error occurred during the card debit" - notify_admin_refund_created: "A refund has been created" - notify_admin_user_wallet_is_credited: "The wallet of an user has been credited" - notify_user_order_is_ready: "Your command is ready" - notify_user_order_is_canceled: "Your command was canceled" - notify_user_order_is_refunded: "Your command was refunded" - notify_admin_low_stock_threshold: "The stock is low" - notify_admin_when_project_published: "A project has been published" - notify_admin_abuse_reported: "An abusive content has been reported" - notify_admin_close_period_reminder: "The fiscal year is coming to an end" - notify_admin_archive_complete: "An accounting archive is ready" - notify_admin_training_auto_cancelled: "A training was automatically cancelled" - notify_admin_export_complete: "An export is available" - notify_user_when_invoice_ready: "An invoice is available" - notify_admin_payment_schedule_gateway_canceled: "A payment schedule has been canceled by the payment gateway" - notify_project_collaborator_to_valid: "You are invited to collaborate on a project" - notify_project_author_when_collaborator_valid: "A collaborator has accepted your invitation to join your project" - notify_admin_order_is_paid: "A new order has been placed" + notify_admin_payment_schedule_error: "Ocorreu um erro inesperado durante o débito do cartão" + notify_admin_refund_created: "Um reembolso foi criado" + notify_admin_user_wallet_is_credited: "A carteira de um usuário foi creditada" + notify_user_order_is_ready: "Seu pedido está pronto" + notify_user_order_is_canceled: "Seu pedido foi cancelado" + notify_user_order_is_refunded: "Seu pedido foi reembolsado" + notify_admin_low_stock_threshold: "O estoque está baixo" + notify_admin_when_project_published: "Um projeto foi publicado" + notify_admin_abuse_reported: "Um conteúdo abusivo foi reportado" + notify_admin_close_period_reminder: "O ano fiscal está chegando ao fim" + notify_admin_archive_complete: "Um arquivo contábil está pronto" + notify_admin_training_auto_cancelled: "Um treinamento foi automaticamente cancelado" + notify_admin_export_complete: "Uma exportação está disponível" + notify_user_when_invoice_ready: "Uma fatura está disponível" + notify_admin_payment_schedule_gateway_canceled: "Um agendamento de pagamento foi cancelado pelo gateway de pagamento" + notify_project_collaborator_to_valid: "Você está convidado a colaborar em um projeto" + notify_project_author_when_collaborator_valid: "Um colaborador aceitou seu convite para participar do seu projeto" + notify_admin_order_is_paid: "Um novo pedido foi feito" diff --git a/config/locales/app.public.it.yml b/config/locales/app.public.it.yml new file mode 100644 index 000000000..66149233e --- /dev/null +++ b/config/locales/app.public.it.yml @@ -0,0 +1,568 @@ +it: + app: + public: + #header and "about" page + common: + about_the_fablab: "About {GENDER, select, male{the} female{the} neutral{} other{the}} {NAME}" + return: "Return" + #cookies + cookies: + about_cookies: "This website uses cookies for audience measurement purposes." + learn_more: "Learn more" + accept: "Accept cookies" + decline: "Refuse" + #dashboard sections + dashboard: "Dashboard" + my_profile: "My Profile" + my_settings: "My Settings" + my_supporting_documents_files: "My supporting documents" + my_projects: "My Projects" + my_trainings: "My Trainings" + my_reservations: "My reservations" + my_events: "My Events" + my_invoices: "My Invoices" + my_payment_schedules: "My payment schedules" + my_orders: "My orders" + my_wallet: "My Wallet" + #contextual help + help: "Help" + #login/logout + sign_out: "Sign Out" + sign_up: "Sign Up" + sign_in: "Sign In" + #left menu + notifications: "Notifications" + admin: "Admin" + manager: "Manager" + reduce_panel: "Reduce panel" + #left menu (public) + home: "Home" + reserve_a_machine: "Reserve a Machine" + trainings_registrations: "Trainings registrations" + events_registrations: "Events registrations" + reserve_a_space: "Reserve a Space" + projects_gallery: "Projects gallery" + subscriptions: "Subscriptions" + public_calendar: "Calendar" + fablab_store: "Store" + #left menu (admin) + trainings_monitoring: "Trainings" + manage_the_calendar: "Calendar" + manage_the_users: "Users" + manage_the_invoices: "Invoices" + subscriptions_and_prices: "Subscriptions and Prices" + manage_the_events: "Events" + manage_the_machines: "Machines" + manage_the_store: "Store" + manage_the_spaces: "Spaces" + projects: "Projects" + statistics: "Statistics" + customization: "Customization" + open_api_clients: "OpenAPI clients" + #account creation modal + create_your_account: "Create your account" + man: "Man" + woman: "Woman" + gender_is_required: "Gender is required." + your_first_name: "Your first name" + first_name_is_required: "First name is required." + your_surname: "Your surname" + surname_is_required: "Surname is required." + your_pseudonym: "Your pseudonym" + pseudonym_is_required: "Pseudonym is required." + your_email_address: "Your e-mail address" + email_is_required: "E-mail address is required." + your_password: "Your password" + password_is_required: "Password is required." + password_is_too_short: "Password is too short (minimum 12 characters)" + password_is_too_weak: "Password is too weak:" + password_is_too_weak_explanations: "minimum 12 characters, at least one uppercase letter, one lowercase letter, one number and one special character" + type_your_password_again: "Type your password again" + password_confirmation_is_required: "Password confirmation is required." + password_does_not_match_with_confirmation: "Password does not match with confirmation." + i_am_an_organization: "I am an organization" + name_of_your_organization: "Name of your organization" + organization_name_is_required: "Organization name is required." + address_of_your_organization: "Address of your organization" + organization_address_is_required: "Organization address is required." + your_user_s_profile: "Your user's profile" + user_s_profile_is_required: "User's profile is required." + birth_date: "Birth date" + birth_date_is_required: "Birth date is required." + phone_number: "Phone number" + phone_number_is_required: "Phone number is required." + address: "Address" + address_is_required: "Address is required" + i_authorize_Fablab_users_registered_on_the_site_to_contact_me: "I authorize users, registered on the site, to contact me" + i_accept_to_receive_information_from_the_fablab: "I accept to receive information from the FabLab" + i_ve_read_and_i_accept_: "I've read and I accept" + _the_fablab_policy: "the terms of use" + field_required: "Field required" + profile_custom_field_is_required: "{FEILD} is required" + user_supporting_documents_required: "Warning!
You have declared to be \"{GROUP}\", supporting documents may be requested." + unexpected_error_occurred: "An unexpected error occurred. Please try again later." + 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" + public_profile: "You will have a public profile and other users will be able to associate you in their projects" + you_will_receive_confirmation_instructions_by_email_detailed: "If your e-mail address is valid, you will receive an email with instructions about how to confirm your account in a few minutes." + #password modification modal + change_your_password: "Change your password" + your_new_password: "Your new password" + your_password_was_successfully_changed: "Your password was successfully changed." + #connection modal + connection: "Connection" + password_forgotten: "Forgotten password?" + confirm_my_account: "Confirm my e-mail" + not_registered_to_the_fablab: "Not yet registered?" + create_an_account: "Create an account" + wrong_email_or_password: "Wrong e-mail or password." + caps_lock_is_on: "Caps lock key is on." + #confirmation modal + you_will_receive_confirmation_instructions_by_email: "You will receive confirmation instructions by email." + #forgotten password modal + you_will_receive_in_a_moment_an_email_with_instructions_to_reset_your_password: "If your e-mail address is valid, you will receive in a moment an e-mail with instructions to reset your password." + #Fab-manager's version + version: "Version:" + upgrade_fabmanager: "Upgrade Fab-manager" + current_version: "You are currently using version {VERSION} of Fab-manager." + upgrade_to: "A new release is available. You can upgrade up to version {VERSION}." + read_more: "View the details of this release" + security_version_html: "Your current version is vulnerable!
A later version, currently available, includes security fixes. Upgrade as soon as possible!" + how_to: "How to upgrade?" + #Notifications + and_NUMBER_other_notifications: "and {NUMBER, plural, =0{no other notifications} =1{one other notification} other{{NUMBER} other notifications}}..." + #about page + about: + read_the_fablab_policy: "Terms of use" + read_the_fablab_s_general_terms_and_conditions: "Read the general terms and conditions" + your_fablab_s_contacts: "Contact us" + privacy_policy: "Privacy policy" + #'privacy policy' page + privacy: + title: "Privacy policy" + dpo: "Data protection officer" + last_update: "Last update," + #home page + home: + latest_documented_projects: "The latest documented projects" + follow_us: "Follow us" + latest_tweets: "The latest tweets" + latest_registered_members: "Latest registered members" + create_an_account: "Create an account" + discover_members: "Discover members" + #next events summary on the home page + fablab_s_next_events: "Next events" + every_events: "Every events" + event_card: + on_the_date: "On the {DATE}" + from_date_to_date: "From {START} to {END}" + from_time_to_time: "From {START} to {END}" + all_day: "All day" + still_available: "Available place(s): " + event_full: "Event full" + without_reservation: "Without reservation" + free_admission: "Free admission" + full_price: "Full price: " + #projects gallery + projects_list: + the_fablab_projects: "The projects" + add_a_project: "Add a project" + network_search: "Fab-manager network" + tooltip_openlab_projects_switch: "The search over the whole network lets you search over the projects of every Fab-manager using this feature !" + openlab_search_not_available_at_the_moment: "Search over the whole network is not available at the moment. You still can search over the projects of this platform." + project_search_result_is_empty: "Sorry, we found no results matching your search criteria." + reset_all_filters: "Clear all" + keywords: "Keywords" + all_projects: "All projects" + my_projects: "My projects" + projects_to_whom_i_take_part_in: "Projects to whom I take part in" + all_machines: "All machines" + all_themes: "All themes" + all_materials: "All materials" + load_next_projects: "Load next projects" + rough_draft: "Rough draft" + status_filter: + all_statuses: "All statuses" + select_status: "Select a status" + #details of a projet + projects_show: + rough_draft: "Draft" + project_description: "Project description" + by_name: "By {NAME}" + step_N: "Step {INDEX}" + share_on_facebook: "Share on Facebook" + share_on_twitter: "Share on Twitter" + deleted_user: "Deleted user" + posted_on_: "Posted on" + CAD_file_to_download: "{COUNT, plural, =0{No CAD files} =1{CAD file to download} other{CAD files to download}}" + machines_and_materials: "Machines and materials" + collaborators: "Collaborators" + licence: "Licence" + confirmation_required: "Confirmation required" + report_an_abuse: "Report an abuse" + unauthorized_operation: "Unauthorized operation" + your_report_was_successful_thanks: "Your report was successful. Thank you." + an_error_occured_while_sending_your_report: "An error occurred while sending your report." + your_first_name: "Your first name" + your_first_name_is_required: "Your first name is required." + your_surname: "Your surname" + your_surname_is_required: "Your surname is required." + your_email_address: "Your email address" + your_email_address_is_required: "Your email address is required." + tell_us_why_this_looks_abusive: "Tell us why this looks abusive" + message_is_required: "Message is required." + report: "Report" + do_you_really_want_to_delete_this_project: "Do you really want to delete this project?" + status: "Status" + #list of machines + machines_list: + the_fablab_s_machines: "The machines" + add_a_machine: "Add a machine" + new_availability: "Open reservations" + book: "Book" + _or_the_: " or the " + store_ad: + title: "Discover our store" + buy: "Check out products from members' projects along with consumable related to the different machines and tools of the workshop." + sell: "If you also want to sell your creations, please let us know." + link: "To the store" + machines_filters: + show_machines: "Show machines:" + status_enabled: "Enabled" + status_disabled: "Disabled" + status_all: "All" + filter_by_machine_category: "Filter by category:" + all_machines: "All machines" + machine_card: + book: "Book" + consult: "Consult" + #details of a machine + machines_show: + book_this_machine: "Book this machine" + technical_specifications: "Technical specifications" + files_to_download: "Files to download" + projects_using_the_machine: "Projects using the machine" + _or_the_: " or the " + confirmation_required: "Confirmation required" + do_you_really_want_to_delete_this_machine: "Do you really want to delete this machine?" + unauthorized_operation: "Unauthorized operation" + the_machine_cant_be_deleted_because_it_is_already_reserved_by_some_users: "The machine can't be deleted because it's already reserved by some users." + #list of trainings + trainings_list: + book: "Book" + the_trainings: "The trainings" + #details of a training + training_show: + book_this_training: "Book this training" + do_you_really_want_to_delete_this_training: "Do you really want to delete this training?" + unauthorized_operation: "Unauthorized operation" + confirmation_required: "Confirmation required" + the_training_cant_be_deleted_because_it_is_already_reserved_by_some_users: "The training can't be deleted because it's already reserved by some users." + plan_card: + AMOUNT_per_month: "{AMOUNT} / month" + i_subscribe_online: "I subscribe online" + more_information: "More information" + i_choose_that_plan: "I choose that plan" + i_already_subscribed: "I already subscribed" + #summary of the subscriptions + plans: + subscriptions: "Subscriptions" + your_subscription_expires_on_the_DATE: "Your subscription expires on the {DATE}" + no_plans: "No plans are available for your group" + my_group: "My group" + his_group: "User's group" + he_wants_to_change_group: "Change group" + change_my_group: "Validate group change" + summary: "Summary" + your_subscription_has_expired_on_the_DATE: "Your subscription has expired on the {DATE}" + subscription_price: "Subscription price" + you_ve_just_payed_the_subscription_html: "You've just paid the subscription:" + thank_you_your_subscription_is_successful: "Thank you. Your subscription is successful!" + your_invoice_will_be_available_soon_from_your_dashboard: "Your invoice will be available soon from your dashboard" + your_group_was_successfully_changed: "Your group was successfully changed." + the_user_s_group_was_successfully_changed: "The user's group was successfully changed." + an_error_prevented_your_group_from_being_changed: "An error prevented your group from being changed." + an_error_prevented_to_change_the_user_s_group: "An error prevented to change the user's group." + plans_filter: + i_am: "I am" + select_group: "select a group" + i_want_duration: "I want to subscribe for" + all_durations: "All durations" + select_duration: "select a duration" + #Fablab's events list + events_list: + the_fablab_s_events: "The events" + all_categories: "All categories" + for_all: "For all" + sold_out: "Sold Out" + cancelled: "Cancelled" + free_admission: "Free admission" + still_available: "available place(s)" + without_reservation: "Without reservation" + add_an_event: "Add an event" + load_the_next_events: "Load the next events..." + full_price_: "Full price:" + to_date: "to" #e.g. from 01/01 to 01/05 + all_themes: "All themes" + #details and booking of an event + events_show: + event_description: "Event description" + downloadable_documents: "Downloadable documents" + information_and_booking: "Information and booking" + dates: "Dates" + beginning: "Beginning:" + ending: "Ending:" + opening_hours: "Opening hours:" + all_day: "All day" + from_time: "From" #e.g. from 18:00 to 21:00 + to_time: "to" #e.g. from 18:00 to 21:00 + full_price_: "Full price:" + tickets_still_availables: "Tickets still available:" + sold_out: "Sold out." + without_reservation: "Without reservation" + cancelled: "Cancelled" + ticket: "{NUMBER, plural, one{ticket} other{tickets}}" + make_a_gift_of_this_reservation: "Make a gift of this reservation" + thank_you_your_payment_has_been_successfully_registered: "Tank you. Your payment has been successfully registered!" + you_can_find_your_reservation_s_details_on_your_: "You can find your reservation's details on your" + dashboard: "dashboard" + you_booked_DATE: "You booked ({DATE}):" + canceled_reservation_SEATS: "Reservation canceled ({SEATS} seats)" + book: "Book" + confirm_and_pay: "Confirm and pay" + confirm_payment_of_html: "{ROLE, select, admin{Cash} other{Pay}}: {AMOUNT}" #(contexte : validate a payment of $20,00) + online_payment_disabled: "Payment by credit card is not available. Please contact us directly." + please_select_a_member_first: "Please select a member first" + change_the_reservation: "Change the reservation" + you_can_shift_this_reservation_on_the_following_slots: "You can shift this reservation on the following slots:" + confirmation_required: "Confirmation required" + do_you_really_want_to_delete_this_event: "Do you really want to delete this event?" + delete_recurring_event: "You're about to delete a periodic event. What do you want to do?" + delete_this_event: "Only this event" + delete_this_and_next: "This event and the following" + delete_all: "All events" + event_successfully_deleted: "Event successfully deleted." + events_deleted: "The event, and {COUNT, plural, =1{one other} other{{COUNT} others}}, have been deleted" + unable_to_delete_the_event: "Unable to delete the event, it may be booked by a member" + events_not_deleted: "On {TOTAL} events, {COUNT, plural, =1{one was not deleted} other{{COUNT} were not deleted}}. Some reservations may exists on {COUNT, plural, =1{it} other{them}}." + cancel_the_reservation: "Cancel the reservation" + do_you_really_want_to_cancel_this_reservation_this_apply_to_all_booked_tickets: "Do you really want to cancel this reservation? This apply to ALL booked tickets." + reservation_was_successfully_cancelled: "Reservation was successfully cancelled." + cancellation_failed: "Cancellation failed." + event_is_over: "The event is over." + thanks_for_coming: "Thanks for coming!" + view_event_list: "View events to come" + share_on_facebook: "Share on Facebook" + share_on_twitter: "Share on Twitter" + #public calendar + calendar: + calendar: "Calendar" + show_unavailables: "Show unavailable slots" + filter_calendar: "Filter calendar" + trainings: "Trainings" + machines: "Machines" + spaces: "Spaces" + events: "Events" + externals: "Other calendars" + choose_a_machine: "Choose a machine" + cancel: "Cancel" + #list of spaces + spaces_list: + the_spaces: "The spaces" + new_availability: "Open reservations" + add_a_space: "Add a space" + status_enabled: "Enabled" + status_disabled: "Disabled" + status_all: "All" + book: "Book" + #display the details of a space + space_show: + book_this_space: "Book this space" + unauthorized_operation: "Unauthorized operation" + confirmation_required: "Confirmation required" + do_you_really_want_to_delete_this_space: "Do you really want to delete this space?" + the_space_cant_be_deleted_because_it_is_already_reserved_by_some_users: "Unable to delete this space, because it is already reserved by some users." + characteristics: "Characteristics" + files_to_download: "Files to download" + projects_using_the_space: "Projects using the space" + #public store + store: + fablab_store: "Store" + unexpected_error_occurred: "An unexpected error occurred. Please try again later." + add_to_cart_success: "Product added to the cart." + products: + all_products: "All the products" + filter: "Filter" + filter_clear: "Clear all" + filter_apply: "Apply" + filter_categories: "Categories" + filter_machines: "By machines" + filter_keywords_reference: "By keywords or reference" + in_stock_only: "Available products only" + sort: + name_az: "A-Z" + name_za: "Z-A" + price_low: "Price: low to high" + price_high: "Price: high to low" + store_product: + ref: "ref: {REF}" + add_to_cart_success: "Product added to the cart." + unexpected_error_occurred: "An unexpected error occurred. Please try again later." + show_more: "Display more" + show_less: "Display less" + documentation: "Documentation" + minimum_purchase: "Minimum purchase: " + add_to_cart: "Add to cart" + stock_limit: "You have reached the current stock limit" + stock_status: + available: "Available" + limited_stock: "Limited stock" + out_of_stock: "Out of stock" + store_product_item: + minimum_purchase: "Minimum purchase: " + add: "Add" + add_to_cart: "Add to cart" + stock_limit: "You have reached the current stock limit" + product_price: + per_unit: "/ unit" + free: "Free" + cart: + my_cart: "My Cart" + cart_button: + my_cart: "My Cart" + store_cart: + checkout: "Checkout" + cart_is_empty: "Your cart is empty" + pickup: "Pickup your products" + checkout_header: "Total amount for your cart" + checkout_products_COUNT: "Your cart contains {COUNT} {COUNT, plural, =1{product} other{products}}" + checkout_products_total: "Products total" + checkout_gift_total: "Discount total" + checkout_coupon: "Coupon" + checkout_total: "Cart total" + checkout_error: "An unexpected error occurred. Please contact the administrator." + checkout_success: "Purchase confirmed. Thanks!" + select_user: "Please select a user before continuing." + abstract_item: + offer_product: "Offer the product" + total: "Total" + errors: + unauthorized_offering_product: "You can't offer anything to yourself" + cart_order_product: + reference_short: "ref:" + minimum_purchase: "Minimum purchase: " + stock_limit: "You have reached the current stock limit" + unit: "Unit" + update_item: "Update" + errors: + product_not_found: "This product is no longer available, please remove it from your cart." + out_of_stock: "This product is out of stock, please remove it from your cart." + stock_limit_QUANTITY: "Only {QUANTITY} {QUANTITY, plural, =1{unit} other{units}} left in stock, please adjust the quantity of items." + quantity_min_QUANTITY: "Minimum number of product was changed to {QUANTITY}, please adjust the quantity of items." + price_changed_PRICE: "The product price was modified to {PRICE}" + cart_order_reservation: + reservation: "Reservation" + offer_reservation: "Offer the reservation" + slot: "{DATE}: {START} - {END}" + offered: "offered" + orders_dashboard: + heading: "My orders" + sort: + newest: "Newest first" + oldest: "Oldest first" + member_select: + select_a_member: "Select a member" + start_typing: "Start typing..." + tour: + conclusion: + title: "Thank you for your attention" + content: "

If you want to restart this contextual help, press F1 at any time or click on « ? Help » from the user's menu.

If you need additional help, you can check the user guide (only in French for now).

The Fab-manager's team also provides personalized support (help with getting started, help with installation, customization, etc.), contact-us for more info.

" + welcome: + welcome: + title: "Welcome to Fab-manager" + content: "To help you get started with the application, we are going to take a quick tour of the features." + home: + title: "Home page" + content: "Clicking here will take you back to the home page where you are currently." + machines: + title: "Machines" + content: "

This page will allow you to consult the list of all machines and reserve a slot on behalf of a member.

A machine can be, for example, a 3D printer.

Members can also access this page and reserve a machine themselves, if credit card payment is enabled, or if some prices are equal to 0.

" + trainings: + title: "Trainings" + content: "

This page will allow you to consult the list of all training sessions and to register a member for a training session.

Trainings can be set as prerequisites before allowing reservation of certain machines.

Members can also access this page and register for a training session themselves, if credit card payment is enabled, or if some prices are equal to 0.

" + spaces: + title: "Spaces" + content: "

This page will allow you to consult the list of all available spaces and to reserve a place on a slot, on behalf of a member.

A space can be, for example, a woodshop or a meeting room.

Their particularity is that they can be booked by several people at the same time.

Members can also access this page and reserve a machine themselves, if credit card payment is enabled, or if some prices are equal to 0.

" + events: + title: "Events" + content: "

An open house evening or an internship to make your desk lamp? It's over here!

Events can be free or paid (with different prices), with or without reservation.

Again, members can access this page and book themselves places for free events, or paid events if credit card payment is enabled.

" + calendar: + title: "Agenda" + content: "Visualize at a glance everything that is scheduled for the next coming weeks (events, training, machines available, etc.)." + projects: + title: "Projects" + content: "

Document and share all your creations with the community.

If you use OpenLab, you will also be able to consult the projects of the entire Fab-manager network. Contact-us to get your access, it's free!

" + plans: + title: "Subscriptions" + content: "Subscriptions provide a way to segment your prices and provide benefits to regular users." + admin: + title: "{ROLE} section" + content: "

All of the elements below are only accessible to administrators and managers. They allow you to manage and configure Fab-manager.

At the end of this visit, click on one of them to find out more.

" + about: + title: "About" + content: "A page that you can fully customize, to present your activity and your structure." + notifications: + title: "Notifications center" + content: "

Every time something important happens (reservations, creation of accounts, activity of your members, etc.), you will be notified here.

Your members also receive notifications there.

" + profile: + title: "User's menu" + content: "

Find your personal information here as well as all your activity on Fab-manager.

This space is also available for all your members.

" + news: + title: "News" + content: "

This space allows you to display the latest news from your structure.

You can easily change its content from « Customization », « Home page ».

" + last_projects: + title: "Last projects" + content: "

This carousel scrolls through the latest projects documented by your members.

" + last_tweet: + title: "Last tweet" + content: "

The last tweet of your Tweeter feed can be shown here.

Configure it from « Customization », « Home page ».

" + last_members: + title: "Last members" + content: "The last registered members who have validated their address and agreed to be contacted will be shown here." + next_events: + title: "Upcoming events" + content: "The next three scheduled events are displayed in this space." + customize: + title: "Customize the home page" + content: "

This page can be fully personalized.

You can contact-us to make a tailored customization of the home page.

" + version: + title: "Application version" + content: "Hover your cursor over this icon to find out the version of Fab-manager. If you are not up to date, this will be reported here and you'll be able to get details by clicking on it." + machines: + welcome: + title: "Machines" + content: "

Machines are the tools available for your users. You must create here the machines which can then be reserved by the members.

You can also create entries for non-bookable or free access machines, then you just need to not associate availability slots with them.

" + welcome_manager: + title: "Machines" + content: "Machines are the tools available for the users to reserve." + view: + title: "View" + content: "To modify or delete a machine, click here first. You will not be able to delete a machine that has already been associated with availability slots, but you can deactivate it." + reserve: + title: "Reserve" + content: "Click here to access an agenda showing free slots. This will let you book this machine for an user and manage existing reservations." + spaces: + welcome: + title: "Spaces" + content: "

Spaces are places available for your users. For example, a meeting room or a woodshop. You must create here the spaces which can then be reserved by members.

The specificity of the spaces is that they can be reserved by several users at the same time.

" + welcome_manager: + title: "Spaces" + content: "

Spaces are places available to users, by reservation. For example, a meeting room or a woodshop.

The specificity of the spaces is that they can be reserved by several users at the same time.

" + view: + title: "View" + content: "To modify or delete a space, click here first. You will not be able to delete a space that has already been associated with availability slots, but you can deactivate it." + reserve: + title: "Reserve" + content: "Click here to access an agenda showing free slots. This will let you book this space for an user and manage existing reservations." diff --git a/config/locales/app.public.pt.yml b/config/locales/app.public.pt.yml index 7ba52c2c0..36d91c789 100644 --- a/config/locales/app.public.pt.yml +++ b/config/locales/app.public.pt.yml @@ -22,7 +22,7 @@ pt: my_events: "Meus Eventos" my_invoices: "Minhas Contas" my_payment_schedules: "Meus agendamentos de pagamento" - my_orders: "My orders" + my_orders: "Meus pedidos" my_wallet: "Minha Carteira" #contextual help help: "Ajuda" @@ -44,7 +44,7 @@ pt: projects_gallery: "Galeria de Projetos" subscriptions: "Assinaturas" public_calendar: "Calendário" - fablab_store: "Store" + fablab_store: "Loja" #left menu (admin) trainings_monitoring: "Treinamentos" manage_the_calendar: "Agenda" @@ -53,7 +53,7 @@ pt: subscriptions_and_prices: "Assinaturas e Preços" manage_the_events: "Eventos" manage_the_machines: "Máquinas" - manage_the_store: "Store" + manage_the_store: "Loja" manage_the_spaces: "Espaços" projects: "Projetos" statistics: "Estatísticas" @@ -93,10 +93,10 @@ pt: phone_number_is_required: "Número de telefone é obrigatório." address: "Endereço" address_is_required: "O endereço é necessário" - i_authorize_Fablab_users_registered_on_the_site_to_contact_me: "I authorize users, registered on the site, to contact me" + i_authorize_Fablab_users_registered_on_the_site_to_contact_me: "Eu autorizo usuários, registrados no site, a entrarem em contato comigo" i_accept_to_receive_information_from_the_fablab: "Eu aceito receber informações do FabLab" i_ve_read_and_i_accept_: "Eu li e aceito" - _the_fablab_policy: "the terms of use" + _the_fablab_policy: "os termos de uso" field_required: "Campo obrigatório" profile_custom_field_is_required: "{FEILD} é obrigatório" user_supporting_documents_required: "Atenção!
Você se declarou como \"{GROUP}\", é possível sejam solicitados documentos de comprovação." @@ -115,7 +115,7 @@ pt: connection: "Login" password_forgotten: "Esqueceu sua senha?" confirm_my_account: "Confirmar sua conta" - not_registered_to_the_fablab: "Not yet registered?" + not_registered_to_the_fablab: "Ainda não cadastrado?" create_an_account: "Criar conta" wrong_email_or_password: "E-mail ou senha incorretos." caps_lock_is_on: "A tecla Caps Lock está ativada." @@ -135,9 +135,9 @@ pt: and_NUMBER_other_notifications: "e {NUMBER, plural, =0{sem notificação} =1{uma notificação} other{{NUMBER} notificações}}..." #about page about: - read_the_fablab_policy: "Terms of use" - read_the_fablab_s_general_terms_and_conditions: "Read the general terms and conditions" - your_fablab_s_contacts: "Contact us" + read_the_fablab_policy: "Termos de uso" + read_the_fablab_s_general_terms_and_conditions: "Leia os termos e condições gerais" + your_fablab_s_contacts: "Entre em contato" privacy_policy: "Política de privacidade" #'privacy policy' page privacy: @@ -153,7 +153,7 @@ pt: create_an_account: "Criar uma conta" discover_members: "Ver membros" #next events summary on the home page - fablab_s_next_events: "Next events" + fablab_s_next_events: "Próximos eventos" every_events: "Todos Eventos" event_card: on_the_date: "Em {DATE}" @@ -167,9 +167,9 @@ pt: full_price: "Valor inteira: " #projects gallery projects_list: - the_fablab_projects: "The projects" + the_fablab_projects: "Os projetos" add_a_project: "Adicionar projeto" - network_search: "Fab-manager network" + network_search: "Rede Fab-manager" tooltip_openlab_projects_switch: "A busca em todos os FabLabs busca projetos em todos os FabLabs que usam o Fab-manager !" openlab_search_not_available_at_the_moment: "A busca em toda a rede de FabLabs não está disponível no momento. Você pode procurar por projetos nesta plataforma." project_search_result_is_empty: "Desculpe, nós não achamos nenhum resultado para sua pesquisa." @@ -184,8 +184,8 @@ pt: load_next_projects: "Carregar próximos projetos" rough_draft: "Rascunho" status_filter: - all_statuses: "All statuses" - select_status: "Select a status" + all_statuses: "Todos os status" + select_status: "Selecione um status" #details of a projet projects_show: rough_draft: "Rascunho" @@ -218,23 +218,23 @@ pt: status: "Status" #list of machines machines_list: - the_fablab_s_machines: "The machines" + the_fablab_s_machines: "As máquinas" add_a_machine: "Adicionar uma máquina" new_availability: "Reservas em aberto" book: "Reservar" _or_the_: " ou o " store_ad: - title: "Discover our store" - buy: "Check out products from members' projects along with consumable related to the different machines and tools of the workshop." - sell: "If you also want to sell your creations, please let us know." - link: "To the store" + title: "Confira a nossa loja" + buy: "Confira produtos de projetos dos membros, juntamente com o consumível relacionado com diferentes máquinas e ferramentas da oficina." + sell: "Se você também quer vender suas criações, por favor nos avise." + link: "Para a loja" machines_filters: show_machines: "Mostrar máquinas" status_enabled: "Ativadas" status_disabled: "Desabilitadas" status_all: "Todas" - filter_by_machine_category: "Filter by category:" - all_machines: "All machines" + filter_by_machine_category: "Filtrar por categoria:" + all_machines: "Todas as máquinas" machine_card: book: "Reservar" consult: "Consultar" @@ -293,7 +293,7 @@ pt: select_duration: "selecione uma duração" #Fablab's events list events_list: - the_fablab_s_events: "The events" + the_fablab_s_events: "Os eventos" all_categories: "Todas categorias" for_all: "Para todos" sold_out: "Esgotado." @@ -333,7 +333,7 @@ pt: book: "Reservar" confirm_and_pay: "Confirmar e pagar" confirm_payment_of_html: "{ROLE, select, admin{Pagamento pelo site} other{Pagamento}}: {AMOUNT}" #(contexte : validate a payment of $20,00) - online_payment_disabled: "Payment by credit card is not available. Please contact us directly." + online_payment_disabled: "Pagamento com cartão de crédito não está disponível. Por favor, entre em contato diretamente conosco." please_select_a_member_first: "Por favor, selecione um membro primeiro" change_the_reservation: "Alterar reserva" you_can_shift_this_reservation_on_the_following_slots: "Você pode alterar essa reserva nos campos a seguir:" @@ -366,8 +366,8 @@ pt: spaces: "Espaços" events: "Eventos" externals: "Outras agendas" - choose_a_machine: "Choose a machine" - cancel: "Cancel" + choose_a_machine: "Escolha uma máquina" + cancel: "Cancelar" #list of spaces spaces_list: the_spaces: "Os espaços" @@ -389,86 +389,86 @@ pt: projects_using_the_space: "Projetos usando espaço" #public store store: - fablab_store: "Store" - unexpected_error_occurred: "An unexpected error occurred. Please try again later." - add_to_cart_success: "Product added to the cart." + fablab_store: "Loja" + unexpected_error_occurred: "Ocorreu um erro inesperado. Tente novamente mais tarde." + add_to_cart_success: "Produto adicionado ao carrinho." products: - all_products: "All the products" - filter: "Filter" - filter_clear: "Clear all" - filter_apply: "Apply" - filter_categories: "Categories" - filter_machines: "By machines" - filter_keywords_reference: "By keywords or reference" - in_stock_only: "Available products only" + all_products: "Todos os produtos" + filter: "Filtro" + filter_clear: "Limpar tudo" + filter_apply: "Aplicar" + filter_categories: "Categorias" + filter_machines: "Por máquinas" + filter_keywords_reference: "Por palavras-chave ou referência" + in_stock_only: "Apenas produtos disponíveis" sort: name_az: "A-Z" name_za: "Z-A" - price_low: "Price: low to high" - price_high: "Price: high to low" + price_low: "Preço: menor para o maior" + price_high: "Preço: maior para o menor" store_product: ref: "ref: {REF}" - add_to_cart_success: "Product added to the cart." - unexpected_error_occurred: "An unexpected error occurred. Please try again later." - show_more: "Display more" - show_less: "Display less" - documentation: "Documentation" - minimum_purchase: "Minimum purchase: " - add_to_cart: "Add to cart" - stock_limit: "You have reached the current stock limit" + add_to_cart_success: "Produto adicionado ao carrinho." + unexpected_error_occurred: "Ocorreu um erro inesperado. Tente novamente mais tarde." + show_more: "Mostrar mais" + show_less: "Mostrar menos" + documentation: "Documentação" + minimum_purchase: "Compra mínima: " + add_to_cart: "Adicionar ao carrinho" + stock_limit: "Você atingiu o limite atual de estoque" stock_status: - available: "Available" - limited_stock: "Limited stock" - out_of_stock: "Out of stock" + available: "Disponível" + limited_stock: "Estoque limitado" + out_of_stock: "Indisponível" store_product_item: - minimum_purchase: "Minimum purchase: " - add: "Add" - add_to_cart: "Add to cart" - stock_limit: "You have reached the current stock limit" + minimum_purchase: "Compra mínima: " + add: "Adicionar" + add_to_cart: "Adicionar ao carrinho" + stock_limit: "Você atingiu o limite atual de estoque" product_price: - per_unit: "/ unit" - free: "Free" + per_unit: "/ unidade" + free: "Grátis" cart: - my_cart: "My Cart" + my_cart: "Meu Carrinho" cart_button: - my_cart: "My Cart" + my_cart: "Meu Carrinho" store_cart: - checkout: "Checkout" - cart_is_empty: "Your cart is empty" - pickup: "Pickup your products" - checkout_header: "Total amount for your cart" - checkout_products_COUNT: "Your cart contains {COUNT} {COUNT, plural, =1{product} other{products}}" - checkout_products_total: "Products total" - checkout_gift_total: "Discount total" + checkout: "Finalizar compra" + cart_is_empty: "Seu carrinho está vazio" + pickup: "Retirar seus produtos" + checkout_header: "Preço total do seu carrinho" + checkout_products_COUNT: "Seu carrinho contém {COUNT} {COUNT, plural, =1{produto} other{produtos}}" + checkout_products_total: "Total de produtos" + checkout_gift_total: "Total de desconto" checkout_coupon: "Cupom" checkout_total: "Total do carrinho" - checkout_error: "An unexpected error occurred. Please contact the administrator." - checkout_success: "Purchase confirmed. Thanks!" - select_user: "Please select a user before continuing." + checkout_error: "Ocorreu um erro inesperado. Por favor, contate o administrador." + checkout_success: "Compra confirmada. Obrigado!" + select_user: "Por favor, selecione um usuário antes de continuar." abstract_item: - offer_product: "Offer the product" + offer_product: "Ofereça o produto" total: "Total" errors: - unauthorized_offering_product: "You can't offer anything to yourself" + unauthorized_offering_product: "Você não pode oferecer nada para si mesmo" cart_order_product: reference_short: "ref:" - minimum_purchase: "Minimum purchase: " - stock_limit: "You have reached the current stock limit" - unit: "Unit" - update_item: "Update" + minimum_purchase: "Compra mínima: " + stock_limit: "Você atingiu o limite atual de estoque" + unit: "Unidade" + update_item: "Atualizar" errors: - product_not_found: "This product is no longer available, please remove it from your cart." - out_of_stock: "This product is out of stock, please remove it from your cart." - stock_limit_QUANTITY: "Only {QUANTITY} {QUANTITY, plural, =1{unit} other{units}} left in stock, please adjust the quantity of items." - quantity_min_QUANTITY: "Minimum number of product was changed to {QUANTITY}, please adjust the quantity of items." - price_changed_PRICE: "The product price was modified to {PRICE}" + product_not_found: "Este produto não está mais disponível, por favor, remova-o do seu carrinho." + out_of_stock: "Este produto está fora de estoque, por favor, remova-o do seu carrinho." + stock_limit_QUANTITY: "Apenas {QUANTITY} {QUANTITY, plural, =1{unidade} other{unidades}} sobrando em estoque, por favor, ajuste a quantidade de itens." + quantity_min_QUANTITY: "Quantidade mínima do produto foi alterada para {QUANTITY}, por favor, ajuste a quantidade de itens." + price_changed_PRICE: "O preço do produto foi modificado para {PRICE}" cart_order_reservation: - reservation: "Reservation" - offer_reservation: "Offer the reservation" + reservation: "Reserva" + offer_reservation: "Oferecer a reserva" slot: "{DATE}: {START} - {END}" - offered: "offered" + offered: "oferecido" orders_dashboard: - heading: "My orders" + heading: "Meus pedidos" sort: newest: "Mais recentes primeiro" oldest: "Mais antigos primeiro" diff --git a/config/locales/app.shared.it.yml b/config/locales/app.shared.it.yml new file mode 100644 index 000000000..d3fb7e114 --- /dev/null +++ b/config/locales/app.shared.it.yml @@ -0,0 +1,544 @@ +it: + app: + shared: + #translations of common buttons + buttons: + confirm_changes: "Confirm changes" + consult: "Consult" + edit: "Edit" + change: "Change" + delete: "Delete" + browse: "Browse" + cancel: "Cancel" + close: "Close" + clear: "Clear" + today: "Today" + confirm: "Confirm" + save: "Save" + "yes": "Yes" + "no": "No" + apply: "Apply" + messages: + you_will_lose_any_unsaved_modification_if_you_quit_this_page: "You will lose any unsaved modification if you quit this page" + you_will_lose_any_unsaved_modification_if_you_reload_this_page: "You will lose any unsaved modification if you reload this page" + payment_card_declined: "Your card was declined." + change_group: + title: "{OPERATOR, select, self{My group} other{User's group}}" + change: "Change {OPERATOR, select, self{my} other{his}} group" + cancel: "Cancel" + validate: "Validate group change" + success: "Group successfully changed" + stripe_form: + payment_card_error: "A problem occurred with your payment card:" + #text editor + text_editor: + fab_text_editor: + text_placeholder: "Type something…" + menu_bar: + link_placeholder: "Paste link…" + url_placeholder: "Paste url…" + new_tab: "Open in a new tab" + add_link: "Insert a link" + add_video: "Embed a video" + add_image: "Insert an image" + #modal dialog + fab_modal: + close: "Close" + fab_socials: + follow_us: "Follow us" + networks_update_success: "Social networks update successful" + networks_update_error: "Problem trying to update social networks" + url_placeholder: "Paste url…" + save: "Save" + website_invalid: "The website address is not a valid URL" + edit_socials: + url_placeholder: "Paste url…" + website_invalid: "The website address is not a valid URL" + #user edition form + avatar_input: + add_an_avatar: "Add an avatar" + change: "Change" + user_profile_form: + personal_data: "Personal" + account_data: "Account" + account_networks: "Social networks" + organization_data: "Organization" + profile_data: "Profile" + preferences_data: "Preferences" + declare_organization: "I declare to be an organization" + declare_organization_help: "If you declare to be an organization, your invoices will be issued in the name of the organization." + pseudonym: "Nickname" + external_id: "External identifier" + first_name: "First name" + surname: "Surname" + email_address: "Email address" + organization_name: "Organization name" + organization_address: "Organization address" + profile_custom_field_is_required: "{FEILD} is required" + date_of_birth: "Date of birth" + website: "Website" + website_invalid: "The website address is not a valid URL" + job: "Job" + interests: "Interests" + CAD_softwares_mastered: "CAD Softwares mastered" + birthday: "Date of birth" + birthday_is_required: "Date of birth is required." + address: "Address" + phone_number: "Phone number" + phone_number_invalid: "Phone number is invalid." + allow_public_profile: "I authorize users, registered on the site, to contact me" + allow_public_profile_help: "Your profile will be visible to other users and you'll be able to collaborate on projects." + allow_newsletter: "I accept to receive information from the FabLab" + allow_newsletter_help: "You may receive the newsletter." + 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" + group: "Group" + trainings: "Trainings" + tags: "Tags" + note: "Private note" + note_help: "This note is only visible to administrators and managers. The member cannot see it." + terms_and_conditions_html: "I've read and accept the terms and conditions" + must_accept_terms: "You must accept the terms and conditions" + save: "Save" + gender_input: + label: "Gender" + man: "Man" + woman: "Woman" + change_password: + change_my_password: "Change my password" + confirm_current: "Confirm your current password" + confirm: "OK" + wrong_password: "Wrong password" + password_input: + new_password: "New password" + confirm_password: "Confirm password" + help: "Your password must be minimum 12 characters long, have at least one uppercase letter, one lowercase letter, one number and one special character." + password_too_short: "Password is too short (must be at least 12 characters)" + confirmation_mismatch: "Confirmation mismatch with password." + password_strength: + not_in_requirements: "Your password doesn't meet the minimal requirements" + 0: "Very weak password" + 1: "Weak password" + 2: "Almost ok" + 3: "Good password" + 4: "Excellent password" + #project edition form + project: + name: "Name" + name_is_required: "Name is required." + illustration: "Visual" + add_an_illustration: "Add an illustration" + CAD_file: "CAD file" + allowed_extensions: "Allowed extensions:" + add_a_new_file: "Add a new file" + description: "Description" + description_is_required: "Description is required." + steps: "Steps" + step_N: "Step {INDEX}" + step_title: "Step title" + add_a_picture: "Add a picture" + change_the_picture: "Change the picture" + delete_the_step: "Delete the step" + confirmation_required: "Confirmation required" + do_you_really_want_to_delete_this_step: "Do you really want to delete this step?" + add_a_new_step: "Add a new step" + publish_your_project: "Publish your project" + or: "or" + employed_materials: "Employed materials" + employed_machines: "Employed machines" + collaborators: "Collaborators" + creative_commons_licences: "Creative Commons licences" + themes: "Themes" + tags: "Tags" + save_as_draft: "Save as draft" + status: "Status" + #button to book a machine reservation + reserve_button: + book_this_machine: "Book this machine" + #frame to select a plan to subscribe + plan_subscribe: + subscribe_online: "subscribe online" + do_not_subscribe: "do not subscribe" + #admin: choose a member to interact with + member_select: + select_a_member: "Select a member" + start_typing: "Start typing..." + member_not_validated: "Warning:
The member was not validated." + #payment modal + abstract_payment_modal: + online_payment: "Online payment" + i_have_read_and_accept_: "I have read, and accept " + _the_general_terms_and_conditions: "the general terms and conditions." + payment_schedule_html: "

You're about to subscribe to a payment schedule of {DEADLINES} months.

By paying this bill, you agree to send instructions to the financial institution that issue your card, to take payments from your card account, for the whole duration of this subscription. This imply that your card data are saved by {GATEWAY} and a series of payments will be initiated on your behalf, conforming to the payment schedule previously shown.

" + confirm_payment_of_: "Pay: {AMOUNT}" + validate: "Validate" + #dialog of on site payment for reservations + valid_reservation_modal: + booking_confirmation: "Booking confirmation" + here_is_the_summary_of_the_slots_to_book_for_the_current_user: "Here is the summary of the slots to book for the current user:" + subscription_confirmation: "Subscription confirmation" + here_is_the_subscription_summary: "Here is the subscription summary:" + payment_method: "Payment method" + method_card: "Online by card" + method_check: "By check" + 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." + #partial form to edit/create a user (admin view) + user_admin: + user: "User" + incomplete_profile: "Incomplete profile" + user_profile: "User profile" + warning_incomplete_user_profile_probably_imported_from_sso: "Warning: This user's profile is incomplete. As \"single sign-on\" (SSO) authentication is currently enabled, it may probably be an imported but non merged account. Do not modify it unless you know what your doing." + group: "Group" + group_is_required: "Group is required." + trainings: "Trainings" + tags: "Tags" + #machine/training slot modification modal + confirm_modify_slot_modal: + change_the_slot: "Change the slot" + do_you_want_to_change_your_booking_slot_initially_planned_at: "Do you want to change your booking slot, initially planned at:" + do_you_want_to_change_NAME_s_booking_slot_initially_planned_at: "Do you want to change {NAME}'s booking slot, initially planned at:" + cancel_this_reservation: "Cancel this reservation" + i_want_to_change_date: "I want to change date" + deleted_user: "deleted user" + #user public profile + public_profile: + last_activity_html: "Last activity
on {DATE}" + to_come: "to come" + approved: "approved" + projects: "Projects" + no_projects: "No projects" + author: "Author" + collaborator: "Collaborator" + private_profile: "Private profile" + interests: "Interests" + CAD_softwares_mastered: "CAD softwares mastered" + email_address: "Email address" + trainings: "Trainings" + no_trainings: "No trainings" + #wallet + wallet: + wallet: 'Wallet' + your_wallet_amount: 'Your amount available' + wallet_amount: 'Amount available' + no_transactions_for_now: 'No transactions for now' + date: "Date" + operation: 'Operation' + operator: 'Operator' + amount: 'Amount' + credit: 'Credit' + debit: 'Debit' + credit_title: 'Credit wallet' + credit_label: 'Set the amount to be credited' + confirm_credit_label: 'Confirm the amount to be credited' + generate_a_refund_invoice: "Generate a refund invoice" + description_optional: "Description (optional):" + will_appear_on_the_refund_invoice: "Will appear on the refund invoice." + to_credit: 'Credit' + wallet_credit_successfully: "Wallet of user is credited successfully." + a_problem_occurred_for_wallet_credit: "A problem is occurred while taking the credit of wallet." + amount_is_required: "The amount is required." + amount_minimum_1: "The amount minimum is 1" + amount_confirm_is_required: "The amount confirmation is required." + amount_confirm_does_not_match: "The amount confirmation does not match." + debit_subscription: "Pay for a subscription" + debit_reservation_training: "Pay for a training reservation" + debit_reservation_machine: "Pay for a machine reservation" + debit_reservation_event: "Pay for an event reservation" + warning_uneditable_credit: "Warning: once validated, the credited amount won't be editable anymore." + wallet_info: + you_have_AMOUNT_in_wallet: "You have {AMOUNT} on your wallet" + wallet_pay_ITEM: "You pay your {ITEM} directly." + item_reservation: "reservation" + item_subscription: "subscription" + item_first_deadline: "first deadline" + item_other: "purchase" + credit_AMOUNT_for_pay_ITEM: "You still have {AMOUNT} to pay to validate your {ITEM}." + client_have_AMOUNT_in_wallet: "The member has {AMOUNT} on his wallet" + client_wallet_pay_ITEM: "The member can directly pay his {ITEM}." + client_credit_AMOUNT_for_pay_ITEM: "{AMOUNT} are remaining to pay to validate the {ITEM}" + other_deadlines_no_wallet: "Warning: the remaining wallet balance cannot be used for the next deadlines." + #coupon (promotional) (creation/edition form) + coupon: + name: "Name" + name_is_required: "Name is required." + code: "Code" + code_is_required: "Code is required." + code_must_be_composed_of_capital_letters_digits_and_or_dashes: "The code must be composed of capital letters, digits and/or dashes." + kind_of_coupon: "Kind of coupon" + percentage: "Percentage" + amount: "Amount" + amount_off: "Amount off" + percent_off: "Percentage off" + percent_off_is_required: "Percentage off is required." + percentage_must_be_between_0_and_100: "Percentage must be between 0 and 100." + validity_per_user: "Validity per user" + once: "Just once" + forever: "Each use" + warn_validity_once: "Please note that when this coupon will be used with a payment schedule, the discount will be applied to the first deadline only." + warn_validity_forever: "Please note that when this coupon will be used with a payment schedule, the discount will be applied to each deadlines." + validity_per_user_is_required: "Validity per user is required." + valid_until: "Valid until (included)" + leave_empty_for_no_limit: "Do not specify any limit by leaving the field empty." + max_usages: "Maximum usages allowed" + max_usages_must_be_equal_or_greater_than_0: "The maximum usages allowed must be greater than 0." + enabled: "Active" + #coupon (input zone for users) + coupon_input: + i_have_a_coupon: "I have a coupon!" + code_: "Code:" + the_coupon_has_been_applied_you_get_PERCENT_discount: "The coupon has been applied. You get a {PERCENT}% discount." + the_coupon_has_been_applied_you_get_AMOUNT_CURRENCY: "The coupon has been applied. You get a discount of {AMOUNT} {CURRENCY}." + coupon_validity_once: "This coupon is valid only once. In case of payment schedule, only for the first deadline." + unable_to_apply_the_coupon_because_disabled: "Unable to apply the coupon: this code was disabled." + unable_to_apply_the_coupon_because_expired: "Unable to apply the coupon: this code has expired." + unable_to_apply_the_coupon_because_sold_out: "Unable to apply the coupon: this code reached its quota." + unable_to_apply_the_coupon_because_already_used: "Unable to apply the coupon: you have already used this code once before." + unable_to_apply_the_coupon_because_amount_exceeded: "Unable to apply the coupon: the discount exceed the total amount of this purchase." + unable_to_apply_the_coupon_because_undefined: "Unable to apply the coupon: an unexpected error occurred, please contact the Fablab's manager." + unable_to_apply_the_coupon_because_rejected: "This code does not exists." + payment_schedule_summary: + your_payment_schedule: "Your payment schedule" + NUMBER_monthly_payment_of_AMOUNT: "{NUMBER} monthly {NUMBER, plural, =1{payment} other{payments}} of {AMOUNT}" + first_debit: "First debit on the day of the order." + monthly_payment_NUMBER: "{NUMBER}{NUMBER, plural, =1{st} =2{nd} =3{rd} other{th}} monthly payment: " + debit: "Debit on the day of the order." + view_full_schedule: "View the complete payment schedule" + select_schedule: + monthly_payment: "Monthly payment" + #shopping cart module for reservations + cart: + summary: "Summary" + select_one_or_more_slots_in_the_calendar: "Select one {SINGLE, select, true{slot} other{or more slots}} in the calendar" + select_a_plan: "Select a plan here" + you_ve_just_selected_the_slot: "You've just selected the slot:" + datetime_to_time: "{START_DATETIME} to {END_TIME}" #eg: Thursday, September 4, 1986 8:30 PM to 10:00 PM + cost_of_TYPE: "Cost of the {TYPE, select, Machine{machine slot} Training{training} Space{space slot} other{element}}" + offer_this_slot: "Offer this slot" + confirm_this_slot: "Confirm this slot" + remove_this_slot: "Remove this slot" + to_benefit_from_attractive_prices: "To benefit from attractive prices" + view_our_subscriptions: "View our subscriptions" + or: "or" + cost_of_the_subscription: "Cost of the subscription" + subscription_price: "Subscription price" + you_ve_just_selected_a_subscription_html: "You've just selected a subscription:" + confirm_and_pay: "Confirm and pay" + you_have_settled_the_following_TYPE: "You have settled the following {TYPE, select, Machine{machine slots} Training{training} other{elements}}:" + you_have_settled_a_: "You have settled a" + total_: "TOTAL:" + thank_you_your_payment_has_been_successfully_registered: "Thank you. Your payment has been successfully registered !" + your_invoice_will_be_available_soon_from_your_: "Your invoice will be available soon form your" + dashboard: "Dashboard" + i_want_to_change_the_following_reservation: "I want to change the following reservation:" + cancel_my_modification: "Cancel my modification" + select_a_new_slot_in_the_calendar: "Select a new slot in the calendar" + cancel_my_selection: "Cancel my selection" + tags_of_the_original_slot: "Tags of the original slot:" + tags_of_the_destination_slot: "Tags of the destination slot:" + confirm_my_modification: "Confirm my modification" + your_booking_slot_was_successfully_moved_from_: "Your booking slot was successfully moved from" + to_date: "to" #eg. from 01 to 05 january. + please_select_a_member_first: "Please select a member first" + unable_to_select_plan_if_slots_in_the_past: "Unable to select a plan if any of the selected slots is in the past" + unable_to_change_the_reservation: "Unable to change the reservation" + confirmation_required: "Confirmation required" + do_you_really_want_to_cancel_this_reservation_html: "

Do you really want to cancel this reservation?

Warning: if this reservation was made free of charge, as part of a subscription, the credits used will not be re-credited.

" + reservation_was_cancelled_successfully: "Reservation was cancelled successfully." + cancellation_failed: "Cancellation failed." + confirm_payment_of_html: "{METHOD, select, card{Pay by card} other{Pay on site}}: {AMOUNT}" + a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." + none: "None" + online_payment_disabled: "Online payment is not available. Please contact the FabLab's reception directly." + slot_restrict_plans: "This slot is restricted for the plans below:" + slot_restrict_subscriptions_must_select_plan: "The slot is restricted for the subscribers. Please select a plan first." + slot_restrict_plans_of_others_groups: "The slot is restricted for the subscribers of others groups." + selected_plan_dont_match_slot: "Selected plan dont match this slot" + user_plan_dont_match_slot: "User subscribed plan dont match this slot" + no_plan_match_slot: "You dont have any matching plan for this slot" + slot_at_same_time: "Conflict with others reservations" + do_you_really_want_to_book_slot_at_same_time: "Do you really want to book this slot? Other bookings take place at the same time" + unable_to_book_slot_because_really_have_reservation_at_same_time: "Unable to book this slot because the following reservation occurs at the same time." + tags_mismatch: "Tags mismatch" + confirm_book_slot_tags_mismatch: "Do you really want to book this slot? {USER} does not have any of the required tags." + unable_to_book_slot_tags_mismatch: "Unable to book this slot because you don't have any of the required tags." + slot_tags: "Slot tags" + user_tags: "User tags" + no_tags: "No tags" + user_validation_required_alert: "Warning!
Your administrator must validate your account. Then, you'll then be able to access all the booking features." + #feature-tour modal + tour: + previous: "Previous" + next: "Next" + end: "End the tour" + #help modal + help: + title: "Help" + what_to_do: "What do you want to do?" + tour: "Start the feature tour" + guide: "Open the user's manual" + stripe_confirm_modal: + resolve_action: "Resolve the action" + ok_button: "OK" + #2nd factor authentication for card payments + stripe_confirm: + pending: "Pending for action..." + success: "Thank you, your card setup is complete. The payment will be proceeded shortly." + #the summary table of all payment schedules + payment_schedules_table: + schedule_num: "Schedule #" + date: "Date" + price: "Price" + customer: "Customer" + deadline: "Deadline" + amount: "Amount" + state: "State" + download: "Download" + state_new: "Not yet due" + state_pending_check: "Waiting for the cashing of the check" + state_pending_transfer: "Waiting for the tranfer confirmation" + state_requires_payment_method: "The credit card must be updated" + state_requires_action: "Action required" + state_paid: "Paid" + state_error: "Error" + state_gateway_canceled: "Canceled by the payment gateway" + state_canceled: "Canceled" + method_card: "by card" + method_check: "by check" + method_transfer: "by transfer" + payment_schedule_item_actions: + download: "Download" + cancel_subscription: "Cancel the subscription" + confirm_payment: "Confirm payment" + confirm_check: "Confirm cashing" + resolve_action: "Resolve the action" + update_card: "Update the card" + update_payment_mean: "Update the payment mean" + please_ask_reception: "For any questions, please contact the FabLab's reception." + confirm_button: "Confirm" + confirm_check_cashing: "Confirm the cashing of the check" + confirm_check_cashing_body: "You must cash a check of {AMOUNT} for the deadline of {DATE}. By confirming the cashing of the check, an invoice will be generated for this due date." + confirm_bank_transfer: "Confirm the bank transfer" + confirm_bank_transfer_body: "You must confirm the receipt of {AMOUNT} for the deadline of {DATE}. By confirming the bank transfer, an invoice will be generated for this due date." + confirm_cancel_subscription: "You're about to cancel this payment schedule and the related subscription. Are you sure?" + card_payment_modal: + online_payment_disabled: "Online payment is not available. Please contact the FabLab's reception directly." + unexpected_error: "An error occurred. Please report this issue to the Fab-Manager's team." + update_card_modal: + unexpected_error: "An error occurred. Please report this issue to the Fab-Manager's team." + stripe_card_update_modal: + update_card: "Update the card" + validate_button: "Validate the new card" + payzen_card_update_modal: + update_card: "Update the card" + validate_button: "Validate the new card" + form_multi_select: + create_label: "Add {VALUE}" + form_checklist: + select_all: "Select all" + unselect_all: "Unselect all" + form_file_upload: + browse: "Browse" + edit: "Edit" + form_image_upload: + browse: "Browse" + edit: "Edit" + main_image: "Main visual" + store: + order_item: + total: "Total" + client: "Client" + created_at: "Order creation" + last_update: "Last update" + state: + cart: 'Cart' + in_progress: 'Under preparation' + paid: "Paid" + payment_failed: "Payment error" + canceled: "Canceled" + ready: "Ready" + refunded: "Refunded" + delivered: "Delivered" + show_order: + back_to_list: "Back to list" + see_invoice: "See invoice" + tracking: "Order tracking" + client: "Client" + created_at: "Creation date" + last_update: "Last update" + cart: "Cart" + reference_short: "ref:" + unit: "Unit" + item_total: "Total" + payment_informations: "Payment informations" + amount: "Amount" + products_total: "Products total" + gift_total: "Discount total" + coupon: "Coupon" + cart_total: "Cart total" + pickup: "Pickup your products" + state: + cart: 'Cart' + in_progress: 'Under preparation' + paid: "Paid" + payment_failed: "Payment error" + canceled: "Canceled" + ready: "Ready" + refunded: "Refunded" + delivered: "Delivered" + payment: + by_wallet: "by wallet" + settlement_by_debit_card: "Settlement by debit card" + settlement_done_at_the_reception: "Settlement done at the reception" + settlement_by_wallet: "Settlement by wallet" + on_DATE_at_TIME: "on {DATE} at {TIME}," + for_an_amount_of_AMOUNT: "for an amount of {AMOUNT}" + and: 'and' + order_actions: + state: + cart: 'Cart' + in_progress: 'Under preparation' + paid: "Paid" + payment_failed: "Payment error" + canceled: "Canceled" + ready: "Ready" + refunded: "Refunded" + delivered: "Delivered" + confirm: 'Confirm' + confirmation_required: "Confirmation required" + confirm_order_in_progress_html: "Please confirm that this order in being prepared." + order_in_progress_success: "Order is under preparation" + confirm_order_ready_html: "Please confirm that this order is ready." + order_ready_note: 'You can leave a message to the customer about withdrawal instructions' + order_ready_success: "Order is ready" + confirm_order_delivered_html: "Please confirm that this order was delivered." + order_delivered_success: "Order was delivered" + confirm_order_canceled_html: "Do you really want to cancel this order?

If this impacts stock, please reflect the change in edit product > stock management. This won't be automatic.

" + order_canceled_success: "Order was canceled" + confirm_order_refunded_html: "Do you really want to refund this order?

If so, please refund the customer and generate the credit note from the Invoices tab.

If this affects stocks, please edit your product and reflect the change in the stock management tab.

These actions will not be automatic.

" + order_refunded_success: "Order was refunded" + unsaved_form_alert: + modal_title: "You have some unsaved changes" + confirmation_message: "If you leave this page, your changes will be lost. Are you sure you want to continue?" + confirmation_button: "Yes, don't save" + active_filters_tags: + keyword: "Keyword: {KEYWORD}" + stock_internal: "Private stock" + stock_external: "Public stock" + calendar: + calendar: "Calendar" + show_unavailables: "Show complete slots" + filter_calendar: "Filter calendar" + trainings: "Trainings" + machines: "Machines" + spaces: "Spaces" + events: "Events" + externals: "Other calendars" + show_reserved_uniq: "Show only slots with reservations" + machine: + machine_uncategorized: "Uncategorized machines" + form_unsaved_list: + save_reminder: "Do not forget to save your changes" + cancel: "Cancel" diff --git a/config/locales/app.shared.pt.yml b/config/locales/app.shared.pt.yml index b83bcad2c..0deea2e32 100644 --- a/config/locales/app.shared.pt.yml +++ b/config/locales/app.shared.pt.yml @@ -68,7 +68,7 @@ pt: declare_organization: "Declaro ser uma organização" declare_organization_help: "Se você declarar ser uma organização, suas faturas serão emitidas no nome da organização." pseudonym: "Usuário" - external_id: "External identifier" + external_id: "Identificador externo" first_name: "Primeiro nome" surname: "Sobrenome" email_address: "Endereço de e-mail" @@ -97,13 +97,13 @@ pt: group: "Grupo" trainings: "Treinamentos" tags: "Tags" - note: "Private note" - note_help: "This note is only visible to administrators and managers. The member cannot see it." + note: "Anotação privada" + note_help: "Esta anotação só é visível para administradores e gerentes. O membro não pode vê-la." terms_and_conditions_html: "Eu li e aceito
os termos e condições" must_accept_terms: "Você deve aceitar os termos e condições" save: "Salvar" gender_input: - label: "Gender" + label: "Gênero" man: "Homem" woman: "Mulher" change_password: @@ -114,16 +114,16 @@ pt: password_input: new_password: "Nova senha" confirm_password: "Confirmar a senha" - help: "Your password must be minimum 12 characters long, have at least one uppercase letter, one lowercase letter, one number and one special character." - password_too_short: "Password is too short (must be at least 12 characters)" + help: "Sua senha deve ter no mínimo 12 caracteres, ter pelo menos uma letra maiúscula, uma letra minúscula, um número e um caractere especial." + password_too_short: "Senha muito curta (mínimo de 12 caracteres)" confirmation_mismatch: "Confirmação de senha é diferente da senha." password_strength: - not_in_requirements: "Your password doesn't meet the minimal requirements" - 0: "Very weak password" - 1: "Weak password" - 2: "Almost ok" - 3: "Good password" - 4: "Excellent password" + not_in_requirements: "Sua senha não atende aos requisitos mínimos" + 0: "Senha muito fraca" + 1: "Senha fraca" + 2: "Quase boa" + 3: "Senha boa" + 4: "Senha excelente" #project edition form project: name: "Nome" @@ -437,14 +437,14 @@ pt: form_multi_select: create_label: "Adicionar {VALUE}" form_checklist: - select_all: "Select all" - unselect_all: "Unselect all" + select_all: "Selecionar todos" + unselect_all: "Remover seleção" form_file_upload: browse: "Browse" - edit: "Edit" + edit: "Editar" form_image_upload: browse: "Browse" - edit: "Edit" + edit: "Editar" main_image: "Main visual" store: order_item: @@ -453,7 +453,7 @@ pt: created_at: "Order creation" last_update: "Last update" state: - cart: 'Cart' + cart: 'Carrinho' in_progress: 'Under preparation' paid: "Paid" payment_failed: "Payment error" @@ -503,42 +503,42 @@ pt: paid: "Paid" payment_failed: "Payment error" canceled: "Canceled" - ready: "Ready" - refunded: "Refunded" - delivered: "Delivered" - confirm: 'Confirm' - confirmation_required: "Confirmation required" - confirm_order_in_progress_html: "Please confirm that this order in being prepared." - order_in_progress_success: "Order is under preparation" - confirm_order_ready_html: "Please confirm that this order is ready." - order_ready_note: 'You can leave a message to the customer about withdrawal instructions' - order_ready_success: "Order is ready" - confirm_order_delivered_html: "Please confirm that this order was delivered." - order_delivered_success: "Order was delivered" + ready: "Pronto" + refunded: "Reembolsado" + delivered: "Entregue" + confirm: 'Confirmar' + confirmation_required: "Confirmação necessária" + confirm_order_in_progress_html: "Por favor, confirme que este pedido está sendo preparado." + order_in_progress_success: "O pedido está em preparação" + confirm_order_ready_html: "Por favor, confirme que este pedido está pronto." + order_ready_note: 'Você pode deixar uma mensagem para o cliente sobre as instruções de retirada' + order_ready_success: "O pedido está pronto" + confirm_order_delivered_html: "Por favor, confirme que este pedido foi entregue." + order_delivered_success: "O pedido foi entregue" confirm_order_canceled_html: "Do you really want to cancel this order?

If this impacts stock, please reflect the change in edit product > stock management. This won't be automatic.

" order_canceled_success: "Order was canceled" confirm_order_refunded_html: "Do you really want to refund this order?

If so, please refund the customer and generate the credit note from the Invoices tab.

If this affects stocks, please edit your product and reflect the change in the stock management tab.

These actions will not be automatic.

" - order_refunded_success: "Order was refunded" + order_refunded_success: "O pedido foi reembolsado" unsaved_form_alert: - modal_title: "You have some unsaved changes" - confirmation_message: "If you leave this page, your changes will be lost. Are you sure you want to continue?" - confirmation_button: "Yes, don't save" + modal_title: "Você tem algumas alterações não salvas" + confirmation_message: "Se você sair desta página, suas alterações serão perdidas. Tem certeza de que deseja continuar?" + confirmation_button: "Sim, não salvar" active_filters_tags: keyword: "Keyword: {KEYWORD}" stock_internal: "Private stock" stock_external: "Public stock" calendar: - calendar: "Calendar" + calendar: "Agenda" show_unavailables: "Show complete slots" filter_calendar: "Filter calendar" - trainings: "Trainings" - machines: "Machines" - spaces: "Spaces" - events: "Events" - externals: "Other calendars" - show_reserved_uniq: "Show only slots with reservations" + trainings: "Treinamentos" + machines: "Máquinas" + spaces: "Espaços" + events: "Eventos" + externals: "Outras agendas" + show_reserved_uniq: "Mostrar apenas slots com reservas" machine: - machine_uncategorized: "Uncategorized machines" + machine_uncategorized: "Máquinas sem categoria" form_unsaved_list: - save_reminder: "Do not forget to save your changes" - cancel: "Cancel" + save_reminder: "Não se esqueça de salvar suas alterações" + cancel: "Cancelar" diff --git a/config/locales/de.yml b/config/locales/de.yml index b3f2de629..457299270 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -102,6 +102,7 @@ de: training_reservation_DESCRIPTION: "Trainingsreservierung - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Veranstaltungs-Reservierung - %{DESCRIPTION}" from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" + null_invoice: "Invoice at nil, billing jump following a malfunction of the Fab Manager software" full_price_ticket: one: "Ein Vollpreis-Ticket" other: "%{count} Vollpreis-Tickets" diff --git a/config/locales/devise.it.yml b/config/locales/devise.it.yml new file mode 100644 index 000000000..c86082d7e --- /dev/null +++ b/config/locales/devise.it.yml @@ -0,0 +1,63 @@ +#Additional translations at https://github.com/plataformatec/devise/wiki/I18n +it: + devise: + confirmations: + confirmed: "Your account was successfully confirmed." + send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." + send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes." + failure: + already_authenticated: "You are already signed in." + inactive: "Your account is not activated yet." + invalid: "Invalid email or password." + locked: "Your account is locked." + last_attempt: "You have one more attempt before your account will be locked." + not_found_in_database: "Invalid email or password." + timeout: "Your session expired. Please sign in again to continue." + unauthenticated: "You need to sign in or sign up before continuing." + unconfirmed: "You have to confirm your account before continuing. Please click on the link below the form." + mailer: + confirmation_instructions: + action: "Confirm my email address" + instruction: "You can finalize your registration by confirming your email address. Please click on the following link:" + subject: "Confirmation instructions" + reset_password_instructions: + action: "Change my password" + instruction: "Someone asked for a link to change your password. You can do it through the link below." + ignore_otherwise: "If you have not made this request, please ignore this message." + subject: "Reset password instructions" + unlock_instructions: + subject: "Unlock Instructions" + omniauth_callbacks: + failure: "Could not authenticate you from %{kind} because \"%{reason}\"." + success: "Successfully authenticated from %{kind} account." + passwords: + no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." + send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." + send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." + updated: "Your password was changed successfully. You are now signed in." + updated_not_active: "Your password was changed successfully." + registrations: + destroyed: "Bye! Your account was successfully cancelled. We hope to see you again soon." + signed_up: "Welcome! You have signed up successfully." + signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." + signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." + signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account." + update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address." + updated: "You updated your account successfully." + sessions: + signed_in: "Signed in successfully." + signed_out: "Signed out successfully." + unlocks: + send_instructions: "You will receive an email with instructions about how to unlock your account in a few minutes." + send_paranoid_instructions: "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes." + unlocked: "Your account has been unlocked successfully. Please sign in to continue." + errors: + messages: + already_confirmed: "This email was already confirmed, please try signing in." + confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" + expired: "has expired, please request a new one" + not_found: "This email was not found" + not_locked: "was not locked" + not_saved: + one: "1 error prohibited this %{resource} from being saved:" + other: "%{count} errors prohibited this %{resource} from being saved:" diff --git a/config/locales/en.yml b/config/locales/en.yml index 0ed2ff13f..3bd7aae37 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -102,6 +102,7 @@ en: training_reservation_DESCRIPTION: "Training reservation - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Event reservation - %{DESCRIPTION}" from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" + null_invoice: "Invoice at nil, billing jump following a malfunction of the Fab Manager software" full_price_ticket: one: "One full price ticket" other: "%{count} full price tickets" diff --git a/config/locales/es.yml b/config/locales/es.yml index 6998d5048..869b6de38 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -102,6 +102,7 @@ es: training_reservation_DESCRIPTION: "Reserva de curso - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Reserva de evento - %{DESCRIPTION}" from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" + null_invoice: "Invoice at nil, billing jump following a malfunction of the Fab Manager software" full_price_ticket: one: "Una entrada de precio completo" other: "%{count} entradas de precio completo" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 3f34fa9da..5331975c3 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -102,6 +102,7 @@ fr: training_reservation_DESCRIPTION: "Réservation Formation - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Réservation Événement - %{DESCRIPTION}" from_payment_schedule: "Échéance %{NUMBER} sur %{TOTAL}, du %{DATE}. Échéancier de paiement %{SCHEDULE}" + null_invoice: "Facture à néant, saut de facturation suite à un dysfonctionnement du logiciel Fab Manager" full_price_ticket: one: "Une place plein tarif" other: "%{count} places plein tarif" diff --git a/config/locales/it.yml b/config/locales/it.yml new file mode 100644 index 000000000..c1c584116 --- /dev/null +++ b/config/locales/it.yml @@ -0,0 +1,705 @@ +it: + #subscription plan duration + duration: + year: + one: 'one year' + other: '%{count} years' + month: + one: 'one month' + other: '%{count} months' + week: + one: 'one week' + other: '%{count} weeks' + activerecord: + attributes: + product: + amount: "The price" + slug: "URL" + errors: + #CarrierWave + messages: + carrierwave_processing_error: "failed to be processed" + carrierwave_integrity_error: "is not of an allowed file type" + carrierwave_download_error: "could not be downloaded" + extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}" + extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}" + content_type_whitelist_error: "You are not allowed to upload %{content_type} files, allowed types: %{allowed_types}" + rmagick_processing_error: "Failed to manipulate with rmagick, maybe it is not an image?" + mime_types_processing_error: "Failed to process file with MIME::Types, maybe not valid content-type?" + mini_magick_processing_error: "Failed to manipulate the file, maybe it is not an image?" + wrong_size: "is the wrong size (should be %{file_size})" + size_too_small: "is too small (should be at least %{file_size})" + size_too_big: "is too big (should be at most %{file_size})" + export_not_found: "Requested export was not found. It was probably deleted, please generate a new export." + percentage_out_of_range: "Percentage must be included between 0 and 100" + cannot_be_blank_at_same_time: "cannot be blank when %{field} is blank too" + cannot_be_in_the_past: "cannot be in the past" + cannot_be_before_previous_value: "cannot be before the previous value" + cannot_overlap: "can't overlap an existing accounting period" + cannot_encompass: "can't encompass an existing accounting period" + in_closed_period: "can't be within a closed accounting period" + invalid_footprint: "invoice's checksum is invalid" + end_before_start: "The end date can't be before the start date. Pick a date after %{START}" + invalid_duration: "The allowed duration must be between 1 day and 1 year. Your period is %{DAYS} days long." + must_be_in_the_past: "The period must be strictly prior to today's date." + registration_disabled: "Registration is disabled" + undefined_in_store: "must be defined to make the product available in the store" + gateway_error: "Payement gateway error: %{MESSAGE}" + gateway_amount_too_small: "Payments under %{AMOUNT} are not supported. Please order directly at the reception." + gateway_amount_too_large: "Payments above %{AMOUNT} are not supported. Please order directly at the reception." + product_in_use: "This product have already been ordered" + slug_already_used: "is already used" + coupon: + code_format_error: "only caps letters, numbers, and dashes are allowed" + apipie: + api_documentation: "API Documentation" + code: "HTTP code" + #error messages when importing an account from an SSO + omniauth: + email_already_linked_to_another_account_please_input_your_authentication_code: "E-mail address \"%{OLD_MAIL}\" is already linked to another account, please input your authentication code." + your_username_is_already_linked_to_another_account_unable_to_update_it: "Your username (%{USERNAME}) is already linked to another account, unable to update it." + your_email_address_is_already_linked_to_another_account_unable_to_update_it: "Your e-mail address (%{EMAIL}) is already linked to another account, unable to update it." + this_account_is_already_linked_to_an_user_of_the_platform: "This %{NAME} account is already linked to an user of the platform." + #availability slots in the calendar + availabilities: + not_available: "Not available" + reserving: "I'm reserving" + i_ve_reserved: "I've reserved" + length_must_be_slot_multiple: "must be at least %{MIN} minutes after the start date" + must_be_associated_with_at_least_1_machine: "must be associated with at least 1 machine" + deleted_user: "Deleted user" + #members management + members: + unable_to_change_the_group_while_a_subscription_is_running: "Unable to change the group while a subscription is running" + please_input_the_authentication_code_sent_to_the_address: "Please input the authentication code sent to the e-mail address %{EMAIL}" + your_authentication_code_is_not_valid: "Your authentication code is not valid." + current_authentication_method_no_code: "The current authentication method does not require any migration code" + requested_account_does_not_exists: "The requested account does not exist" + #SSO external authentication + authentication_providers: + local_database_provider_already_exists: 'A "Local Database" provider already exists. Unable to create another.' + matching_between_User_uid_and_API_required: "It is required to set the matching between User.uid and the API to add this provider." + #PDF invoices generation + invoices: + refund_invoice_reference: "Refund invoice reference: %{REF}" + invoice_reference: "Invoice reference: %{REF}" + code: "Code: %{CODE}" + order_number: "Order #: %{NUMBER}" + invoice_issued_on_DATE: "Invoice issued on %{DATE}" + refund_invoice_issued_on_DATE: "Refund invoice issued on %{DATE}" + wallet_credit: "Wallet credit" + cancellation_of_invoice_REF: "Cancellation of invoice %{REF}" + reservation_of_USER_on_DATE_at_TIME: "Reservation of %{USER} on %{DATE} at %{TIME}" + cancellation: "Cancellation" + object: "Object:" + order_summary: "Order summary:" + details: "Details" + amount: "Amount" + subscription_extended_for_free_from_START_to_END: "Subscription extended for free - From %{START} to %{END}" + subscription_NAME_from_START_to_END: "Subscription %{NAME} - From %{START} to %{END}" + machine_reservation_DESCRIPTION: "Machine reservation - %{DESCRIPTION}" + space_reservation_DESCRIPTION: "Space reservation - %{DESCRIPTION}" + training_reservation_DESCRIPTION: "Training reservation - %{DESCRIPTION}" + event_reservation_DESCRIPTION: "Event reservation - %{DESCRIPTION}" + from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" + null_invoice: "Invoice at nil, billing jump following a malfunction of the Fab Manager software" + full_price_ticket: + one: "One full price ticket" + other: "%{count} full price tickets" + other_rate_ticket: + one: "One %{NAME} ticket" + other: "%{count} %{NAME} tickets" + coupon_CODE_discount_of_DISCOUNT: "Coupon {CODE}: discount of {DISCOUNT}{TYPE, select, percent_off{%} other{}}" #messageFormat interpolation + total_including_all_taxes: "Total incl. all taxes" + VAT: "VAT" + including_VAT_RATE: "Including %{NAME} %{RATE}% of %{AMOUNT}" + including_total_excluding_taxes: "Including Total excl. taxes" + including_amount_payed_on_ordering: "Including amount payed on ordering" + total_amount: "Total amount" + refund_on_DATE: "Refund on %{DATE}" + by_card_online_payment: "by card (online payment)" + by_cheque: "by cheque" + by_transfer: "by transfer" + by_cash: "by cash" + by_wallet: "by wallet" + no_refund: "No refund" + settlement_by_debit_card: "Settlement by debit card" + settlement_done_at_the_reception: "Settlement done at the reception" + settlement_by_wallet: "Settlement by wallet" + on_DATE_at_TIME: "on %{DATE} at %{TIME}," + for_an_amount_of_AMOUNT: "for an amount of %{AMOUNT}" + on_DATE_from_START_to_END: "On %{DATE} from %{START} to %{END}" #eg: on feb. 7 from 7AM to 9AM + from_STARTDATE_to_ENDDATE_from_STARTTIME_to_ENDTIME: "From %{STARTDATE} to %{ENDDATE}, from %{STARTTIME} to %{ENDTIME}" #eg: from feb. 7 to feb. 10, from 6PM to 10PM + subscription_of_NAME_for_DURATION_starting_from_DATE: "Subscription of %{NAME} for %{DURATION} starting from %{DATE}" + subscription_of_NAME_extended_starting_from_STARTDATE_until_ENDDATE: "Subscription of %{NAME} extended (Free days) starting from %{STARTDATE} until %{ENDDATE}" + and: 'and' + invoice_text_example: "Our association is not subject to VAT" + error_invoice: "Erroneous invoice. The items below ware not booked. Please contact the FabLab for a refund." + prepaid_pack: "Prepaid pack of hours" + pack_item: "Pack of %{COUNT} hours for the %{ITEM}" + order: "Your order on the store" + unable_to_find_pdf: "We cannot find your invoice. If you ordered recently, it may have not been generated yet. Please retry in a moment." + #PDF payment schedule generation + payment_schedules: + schedule_reference: "Payment schedule reference: %{REF}" + schedule_issued_on_DATE: "Schedule issued on %{DATE}" + object: "Object: Payment schedule for %{ITEM}" + subscription_of_NAME_for_DURATION_starting_from_DATE: "the subscription of %{NAME} for %{DURATION} starting from %{DATE}" + deadlines: "Table of your deadlines" + deadline_date: "Payment date" + deadline_amount: "Amount including tax" + total_amount: "Total amount" + settlement_by_METHOD: "Debits will be made by {METHOD, select, card{card} transfer{bank transfer} other{check}} for each deadlines." + settlement_by_wallet: "%{AMOUNT} will be debited from your wallet to settle the first deadline." + #CVS accounting export (columns headers) + accounting_export: + journal_code: "Journal code" + date: "Entry date" + account_code: "Account code" + account_label: "Account label" + piece: "Document" + line_label: "Entry label" + debit_origin: "Origin debit" + credit_origin: "Origin credit" + debit_euro: "Euro debit" + credit_euro: "Euro credit" + lettering: "Lettering" + VAT: 'VAT' + accounting_summary: + subscription_abbreviation: "subscr." + Machine_reservation_abbreviation: "machine reserv." + Training_reservation_abbreviation: "training reserv." + Event_reservation_abbreviation: "event reserv." + Space_reservation_abbreviation: "space reserv." + wallet_abbreviation: "wallet" + shop_order_abbreviation: "shop order" + vat_export: + start_date: "Start date" + end_date: "End date" + vat_rate: "%{NAME} rate" + amount: "Total amount" + #training availabilities + trainings: + i_ve_reserved: "I've reserved" + completed: "Full" + refund_for_auto_cancel: "This training session was cancelled due to an insufficient number of participants." + #error messages when updating an event + events: + error_deleting_reserved_price: "Unable to delete the requested price because it is associated with some reservations" + other_error: "An unexpected error occurred while updating the event" + #event duration + from_STARTDATE_to_ENDDATE: "From %{STARTDATE} to %{ENDDATE}," + from_STARTTIME_to_ENDTIME: "from %{STARTTIME} to %{ENDTIME}" + #members list export to EXCEL format + export_members: + members: "Members" + id: "ID" + external_id: "External ID" + surname: "Surname" + first_name: "First name" + email: "E-mail" + newsletter: "Newsletter" + last_login: "Last login" + gender: "Gender" + age: "Age" + address: "Address" + phone: "Phone" + website: "Website" + job: "Job" + interests: "Interests" + cad_software_mastered: "CAD Softwares mastered" + group: "Group" + subscription: "Subscription" + subscription_end_date: "Subscription end date" + validated_trainings: "Validated trainings" + tags: "Tags" + number_of_invoices: "Number of invoices" + projects: "Projects" + facebook: "Facebook" + twitter: "Twitter" + echo_sciences: "Echosciences" + organization: "Organization" + organization_address: "Organization address" + note: "Note" + man: "Man" + woman: "Woman" + without_subscriptions: "Without subscriptions" + #machines/trainings/events reservations list to EXCEL format + export_reservations: + reservations: "Reservations" + customer_id: "Customer ID" + customer: "Customer" + email: "E-mail" + reservation_date: "Reservation date" + reservation_type: "Reservation type" + reservation_object: "Reservation object" + slots_number_hours_tickets: "Slots number (hours/tickets)" + payment_method: "Payment method" + local_payment: "Payment at the reception" + online_payment: "Online payment" + deleted_user: "Deleted user" + coupon: "Coupon used" + #subscriptions list export to EXCEL format + export_subscriptions: + subscriptions: "Subscriptions" + id: "ID" + customer: "Customer" + email: "E-mail" + subscription: "Subscription" + period: "Period" + start_date: "Start date" + expiration_date: "Expiration date" + amount: "Amount" + local_payment: "Payment at the reception" + online_payment: "Online payment" + deleted_user: "Deleted user" + #reservation slots export, by type, to EXCEL format + export_availabilities: + machines: "Machines" + trainings: "Trainings" + spaces: "Spaces" + events: "Events" + day_of_week: "Day of week" + date: "Date" + slot: "Slot" + machine: "Machine" + training: "Training" + space: "Space" + event: "Event" + reservations: "Reservations" + available_seats: "Available seats" + reservation_ics: + description_slot: "You have booked %{COUNT} slots of %{ITEM}" + description_training: "You have booked a %{TYPE} training" + description_event: "You have booked %{NUMBER} tickets for this event" + alarm_summary: "Remind your reservation" + roles: + member: "Member" + manager: "Manager" + admin: "Administrator" + api: + #internal app notifications + notifications: + deleted_user: "Deleted user" + notify_admin_abuse_reported: + an_abuse_was_reported_on_TYPE_ID_NAME_html: "An abuse was reported on %{TYPE} %{ID}: %{NAME}." + notify_admin_member_create_reservation: + a_RESERVABLE_reservation_was_made_by_USER_html: "A %{RESERVABLE} reservation was made by %{USER}." + notify_admin_profile_complete: + account_imported_from_PROVIDER_UID_has_completed_its_information_html: "Account imported from %{PROVIDER} (%{UID}) has completed its information." + notify_admin_slot_is_canceled: + USER_s_reservation_on_the_DATE_was_cancelled_remember_to_generate_a_refund_invoice_if_applicable_html: "%{USER}'s reservation, on the %{DATE}, was cancelled. Remember to generate a refund invoice if applicable." + notify_admin_slot_is_modified: + a_booking_slot_was_modified: "A booking slot was modified." + notify_admin_subscribed_plan: + subscription_PLAN_has_been_subscribed_by_USER_html: "Subscription %{PLAN} has been subscribed by %{USER}." + notify_admin_subscription_canceled: + USER_s_subscription_has_been_cancelled: "%{USER}'s subscription has been cancelled." + notify_admin_subscription_extended: + subscription_PLAN_of_the_member_USER_has_been_extended_FREE_until_DATE_html: "Subscription {PLAN} of the member {USER} has been extended {FREE, select, true{for free} other{}} until {DATE}." #messageFormat interpolation + notify_admin_subscription_is_expired: + USER_s_subscription_has_expired: "%{USER}'s subscription has expired." + notify_admin_subscription_will_expire_in_7_days: + USER_s_subscription_will_expire_in_7_days: "%{USER}'s subscription will expire in 7 days." + notify_admin_training_auto_cancelled: + auto_cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, has been automatically canceled due to an insufficient number of participants." + auto_refund: "The members were automatically refunded on their wallet." + manual_refund: "Please refund each members." + notify_admin_user_group_changed: + user_NAME_changed_his_group_html: "User {NAME} changed group." #messageFormat interpolation + notify_admin_user_merged: + user_NAME_has_merged_his_account_with_the_one_imported_from_PROVIDER_UID_html: "{NAME}'s account was merged with the one imported from {PROVIDER} ({%UID})." #messageFormat interpolation + notify_admin_when_project_published: + project_NAME_has_been_published_html: "Project
%{NAME} has been published." + notify_admin_when_user_is_created: + a_new_user_account_has_been_created_NAME_EMAIL_html: "A new user account has been created: %{NAME} <%{EMAIL}>." + notify_admin_when_user_is_imported: + a_new_user_account_has_been_imported_from_PROVIDER_UID_html: "A new user account has been imported from: %{PROVIDER} (%{UID})." + notify_member_create_reservation: + your_reservation_RESERVABLE_was_successfully_saved_html: "Your reservation %{RESERVABLE} was successfully saved." + notify_member_reservation_reminder: + reminder_you_have_a_reservation_RESERVABLE_to_be_held_on_DATE_html: "Reminder: You have a reservation %{RESERVABLE} to be held on %{DATE}" + notify_member_slot_is_canceled: + your_reservation_RESERVABLE_of_DATE_was_successfully_cancelled: "Your reservation %{RESERVABLE} of %{DATE} was successfully cancelled." + notify_member_slot_is_modified: + your_reservation_slot_was_successfully_changed: "Your reservation slot was successfully changed." + notify_member_subscribed_plan: + you_have_subscribed_to_PLAN_html: "You have subscribed to %{PLAN}." + notify_member_subscribed_plan_is_changed: + you_have_changed_your_subscription_to_PLAN_html: "You have changed your subscription to %{PLAN}." + notify_member_subscription_canceled: + your_subscription_PLAN_was_successfully_cancelled_html: "Your subscription %{PLAN} was successfully cancelled." + notify_member_subscription_extended: + your_subscription_PLAN_has_been_extended_FREE_until_DATE_html: "Your subscription {PLAN} has been extended {FREE, select, true{for free} other{}} until {DATE}." #messageFormat interpolation + notify_member_subscription_is_expired: + your_subscription_has_expired: "Your subscription has expired." + notify_member_subscription_will_expire_in_7_days: + your_subscription_will_expire_in_7_days: "Your subscription will expire in 7 days." + notify_member_training_authorization_expired: + training_authorization_revoked: "Your authorization to use %{MACHINES} has been revoked because it has expired." + notify_member_training_auto_cancelled: + auto_cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, has been canceled due to an insufficient number of participants." + auto_refund: "You were refunded on your wallet." + notify_member_training_invalidated: + invalidated: "Your authorization to use %{MACHINES} has been invalidated due to a lack of reservations." + notify_partner_subscribed_plan: + subscription_partner_PLAN_has_been_subscribed_by_USER_html: "Partner subscription %{PLAN} has been subscribed by %{USER}." + notify_project_author_when_collaborator_valid: + USER_became_collaborator_of_your_project: "%{USER} became collaborator of your project:" + notify_project_collaborator_to_valid: + you_are_invited_to_collaborate_on_the_project: "You are invited to collaborate on the project:" + notify_user_auth_migration: + your_account_was_migrated: "You account was successfully migrated to the new authentication system." + notify_user_profile_complete: + your_profile_was_completed: "Your profile was successfully completed, you now have access to the entire platform." + notify_user_training_valid: + your_TRAINING_was_validated_html: "Your training %{TRAINING} was successfully validated." + notify_user_user_group_changed: + your_group_has_changed: "Your group has changed." + notify_user_when_avoir_ready: + your_avoir_is_ready_html: "Your refund invoice #%{REFERENCE}, of %{AMOUNT}, is ready. Click here to download." + notify_user_when_invoice_ready: + your_invoice_is_ready_html: "Your invoice #%{REFERENCE}, of %{AMOUNT} is ready. Click here to download." + undefined_notification: + unknown_notification: "Unknown notification" + notification_ID_wrong_type_TYPE_unknown: "Notification %{ID} wrong (type %{TYPE} unknown)" + notify_user_wallet_is_credited: + your_wallet_is_credited: "Your wallet has been credited by administrator" + notify_admin_user_wallet_is_credited: + wallet_is_credited: "The wallet of member %{USER} has been credited %{AMOUNT}" + notify_admin_export_complete: + export: "The export" + statistics_global: "of all the statistics" + statistics_account: "of the registration statistics" + statistics_event: "of statistics about events" + statistics_machine: "of statistics about machine slots" + statistics_project: "of statistics about projects" + statistics_subscription: "of subscription statistics" + statistics_training: "of statistics about trainings" + statistics_space: "of statistics about spaces" + statistics_order: "of statistics about store orders" + users_members: "of the members' list" + users_subscriptions: "of the subscriptions' list" + users_reservations: "of the reservations' list" + availabilities_index: "of the reservations availabilities" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT" + is_over: "is over." + download_here: "Download here" + notify_admin_import_complete: + import_over: "%{CATEGORY} import is over. " + members: "Members" + view_results: "View results." + notify_admin_low_stock_threshold: + low_stock: "Low stock for %{PRODUCT}. " + view_product: "View the product." + notify_member_about_coupon: + enjoy_a_discount_of_PERCENT_with_code_CODE: "Enjoy a discount of %{PERCENT}% with code %{CODE}" + enjoy_a_discount_of_AMOUNT_with_code_CODE: "Enjoy a discount of %{AMOUNT} with code %{CODE}" + notify_admin_free_disk_space: + warning_free_disk_space: "Warning: the server's available disk space is now %{AVAILABLE} MiB" + notify_admin_close_period_reminder: + warning_last_closed_period_over_1_year: "Please remind to periodically close your accounting periods. Last closed period ended at %{LAST_END}" + warning_no_closed_periods: "Please remind to periodically close your accounting periods. You have to close periods from %{FIRST_DATE}" + notify_admin_archive_complete: + archive_complete: "Data archiving from %{START} to %{END} is done. click here to download. Remember to save it on an external secured media." + notify_privacy_policy_changed: + policy_updated: "Privacy policy updated." + click_to_show: "Click here to consult" + notify_admin_refund_created: + refund_created: "A refund of %{AMOUNT} has been created for user %{USER}" + notify_user_role_update: + your_role_is_ROLE: "Your role has been changed to %{ROLE}." + notify_admins_role_update: + user_NAME_changed_ROLE_html: "User %{NAME} is now %{ROLE}." + notify_admin_objects_stripe_sync: + all_objects_sync: "All data were successfully synchronized on Stripe." + notify_admin_order_is_paid: + order_paid_html: "A new order has been placed. View details." + notify_user_when_payment_schedule_ready: + your_schedule_is_ready_html: "Your payment schedule #%{REFERENCE}, of %{AMOUNT}, is ready. Click here to download." + notify_admin_payment_schedule_error: + schedule_error: "An error occurred for the card debit of the %{DATE} deadline, for schedule %{REFERENCE}" + notify_member_payment_schedule_error: + schedule_error: "An error occurred for the card debit of the %{DATE} deadline, for your schedule %{REFERENCE}" + notify_admin_payment_schedule_failed: + schedule_failed: "Failed card debit for the %{DATE} deadline, for schedule %{REFERENCE}" + notify_member_payment_schedule_failed: + schedule_failed: "Failed card debit for the %{DATE} deadline, for your schedule %{REFERENCE}" + notify_admin_payment_schedule_gateway_canceled: + schedule_canceled: "The payment schedule %{REFERENCE} was canceled by the gateway. An action is required." + notify_member_payment_schedule_gateway_canceled: + schedule_canceled: "Your payment schedule %{REFERENCE} was canceled by the gateway." + notify_admin_payment_schedule_check_deadline: + schedule_deadline: "You must cash the check for the %{DATE} deadline, for schedule %{REFERENCE}" + notify_admin_payment_schedule_transfer_deadline: + schedule_deadline: "You must confirm the bank direct debit for the %{DATE} deadline, for schedule %{REFERENCE}" + notify_member_reservation_limit_reached: + limit_reached: "For %{DATE}, you have reached your daily limit of %{HOURS} hours of %{ITEM} reservation." + notify_admin_user_supporting_document_files_created: + supporting_document_files_uploaded: "Supporting document uploaded by member %{NAME}." + notify_admin_user_supporting_document_files_updated: + supporting_document_files_uploaded: "Supporting document changed by member %{NAME}." + notify_user_is_validated: + account_validated: "Your account is valid." + notify_user_is_invalidated: + account_invalidated: "Your account is invalid." + notify_user_supporting_document_refusal: + refusal: "Your supporting documents were refused" + notify_admin_user_supporting_document_refusal: + refusal: "Member's supporting document %{NAME} was refused." + notify_user_order_is_ready: + order_ready: "Your command %{REFERENCE} is ready" + notify_user_order_is_canceled: + order_canceled: "Your command %{REFERENCE} is canceled" + notify_user_order_is_refunded: + order_refunded: "Your command %{REFERENCE} is refunded" + #statistics tools for admins + statistics: + subscriptions: "Subscriptions" + machines_hours: "Machines slots" + machine_dates: "Slots dates" + space_dates: "Slots dates" + spaces: "Spaces" + orders: "Orders" + trainings: "Trainings" + events: "Events" + registrations: "Registrations" + projects: "Projects" + users: "Users" + training_id: "Training ID" + training_date: "Training Date" + event_id: "Event ID" + event_date: "Event Date" + event_name: "Event Name" + event_theme: "Theme" + age_range: "Age Range" + themes: "Themes" + components: "Components" + machines: "Machines" + user_id: "User ID" + group: "Group" + bookings: "Bookings" + hours_number: "Hours number" + tickets_number: "Tickets number" + revenue: "Revenue" + account_creation: "Account creation" + project_publication: "Project publication" + duration: "Duration" + store: "Store" + paid-processed: "Paid and/or processed" + aborted: "Aborted" + #statistics exports to the Excel file format + export: + entries: "Entries" + revenue: "Revenue" + average_age: "Average Age" + total: "Total" + date: "Date" + user: "User" + email: "Email" + phone: "Phone" + gender: "Gender" + age: "Age" + type: "Type" + male: "Man" + female: "Woman" + deleted_user: "Deleted user" + #initial price's category for events, created to replace the old "reduced amount" property + price_category: + reduced_fare: "Reduced fare" + reduced_fare_if_you_are_under_25_student_or_unemployed: "Reduced fare if you are under 25, student or unemployed." + cart_items: + free_extension: "Free extension of a subscription, until %{DATE}" + must_be_after_expiration: "The new expiration date must be set after the current expiration date" + group_subscription_mismatch: "Your group mismatch with your subscription. Please report this error." + statistic_profile: + birthday_in_past: "The date of birth must be in the past" + order: + please_contact_FABLAB: "Please contact us for withdrawal instructions." + cart_item_validation: + slot: "The slot doesn't exist" + availability: "The availaility doesn't exist" + full: "The slot is already fully reserved" + deadline: "You can't reserve a slot %{MINUTES} minutes prior to its start" + limit_reached: "You have reached the booking limit of %{HOURS}H per day for the %{RESERVABLE}, for your current subscription. Please adjust your reservation." + restricted: "This availability is restricted for subscribers" + plan: "This subscription plan is disabled" + plan_group: "This subscription plan is reserved for members of group %{GROUP}" + reserved: "This slot is already reserved" + pack: "This prepaid pack is disabled" + pack_group: "This prepaid pack is reserved for members of group %{GROUP}" + space: "This space is disabled" + machine: "This machine is disabled" + reservable: "This machine is not reservable" + cart_validation: + select_user: "Please select a user before continuing" + settings: + locked_setting: "the setting is locked." + about_title: "\"About\" page title" + about_body: "\"About\" page content" + about_contacts: "\"About\" page contacts" + privacy_draft: "Privacy policy draft" + privacy_body: "Privacy policy" + privacy_dpo: "Data protection officer address" + twitter_name: "Twitter feed name" + home_blogpost: "Homepage's brief" + machine_explications_alert: "Explanation message on the machine reservation page" + training_explications_alert: "Explanation message on the training reservation page" + training_information_message: "Information message on the machine reservation page" + subscription_explications_alert: "Explanation message on the subscription page" + invoice_logo: "Invoices' logo" + invoice_reference: "Invoice's reference" + invoice_code-active: "Activation of the invoices' code" + invoice_code-value: "Invoices' code" + invoice_order-nb: "Invoice's order number" + invoice_VAT-active: "Activation of the VAT" + invoice_VAT-rate: "VAT rate" + invoice_VAT-rate_Product: "VAT rate for shop's product sales" + invoice_VAT-rate_Event: "VAT rate for event reservations" + invoice_VAT-rate_Machine: "VAT rate for machine reservations" + invoice_VAT-rate_Subscription: "VAT rate for subscriptions" + invoice_VAT-rate_Space: "VAT rate for space reservations" + invoice_VAT-rate_Training: "VAT rate for training reservations" + invoice_text: "Invoices' text" + invoice_legals: "Invoices' legal information" + booking_window_start: "Opening time" + booking_window_end: "Closing time" + booking_move_enable: "Activation of reservations moving" + booking_move_delay: "Preventive delay before any reservation move" + booking_cancel_enable: "Activation of reservations cancelling" + booking_cancel_delay: "Preventive delay before any reservation cancellation" + main_color: "Main colour" + secondary_color: "Secondary colour" + fablab_name: "Fablab's name" + name_genre: "Title concordance" + reminder_enable: "Activation of reservations reminding" + reminder_delay: "Delay before sending the reminder" + event_explications_alert: "Explanation message on the event reservation page" + space_explications_alert: "Explanation message on the space reservation page" + visibility_yearly: "Maximum visibility for annual subscribers" + visibility_others: "Maximum visibility for other members" + reservation_deadline: "Prevent reservation before it starts" + display_name_enable: "Display names in the calendar" + machines_sort_by: "Machines display order" + accounting_sales_journal_code: "Sales journal code" + accounting_payment_card_code: "Card payments code" + accounting_payment_card_label: "Card payments label" + accounting_payment_card_journal_code: "Card clients journal code" + accounting_payment_wallet_code: "Wallet payments code" + accounting_payment_wallet_label: "Wallet payments label" + accounting_payment_wallet_journal_code: "Wallet payments journal code" + accounting_payment_other_code: "Other payment means code" + accounting_payment_other_label: "Other payment means label" + accounting_payment_other_journal_code: "Other payment means journal code" + accounting_wallet_code: "Wallet credit code" + accounting_wallet_label: "Wallet credit label" + accounting_wallet_journal_code: "Wallet credit journal code" + accounting_VAT_code: "VAT code" + accounting_VAT_label: "VAT label" + accounting_VAT_journal_code: "VAT journal code" + accounting_subscription_code: "Subscriptions code" + accounting_subscription_label: "Subscriptions label" + accounting_Machine_code: "Machines code" + accounting_Machine_label: "Machines label" + accounting_Training_code: "Trainings code" + accounting_Training_label: "Trainings label" + accounting_Event_code: "Events code" + accounting_Event_label: "Events label" + accounting_Space_code: "Spaces code" + accounting_Space_label: "Spaces label" + accounting_Pack_code: "Prepaid-hours pack code" + accounting_Pack_label: "Prepaid-hours pack label" + accounting_Product_code: "Store products code" + accounting_Product_label: "Store products label" + hub_last_version: "Last Fab-manager's version" + hub_public_key: "Instance public key" + fab_analytics: "Fab Analytics" + link_name: "Link title to the \"About\" page" + home_content: "The home page" + home_css: "Stylesheet of the home page" + origin: "Instance URL" + uuid: "Instance ID" + phone_required: "Phone required?" + tracking_id: "Tracking ID" + book_overlapping_slots: "Book overlapping slots" + slot_duration: "Default duration of booking slots" + events_in_calendar: "Display events in the calendar" + spaces_module: "Spaces module" + plans_module: "Plans modules" + invoicing_module: "Invoicing module" + facebook_app_id: "Facebook App ID" + twitter_analytics: "Twitter analytics account" + recaptcha_site_key: "reCAPTCHA Site Key" + recaptcha_secret_key: "reCAPTCHA Secret Key" + feature_tour_display: "Feature tour display mode" + email_from: "Expeditor's address" + disqus_shortname: "Disqus shortname" + allowed_cad_extensions: "Allowed CAD files extensions" + allowed_cad_mime_types: "Allowed CAD files MIME types" + openlab_app_id: "OpenLab ID" + openlab_app_secret: "OpenLab secret" + openlab_default: "Default projects gallery view" + online_payment_module: "Online payments module" + stripe_public_key: "Stripe public key" + stripe_secret_key: "Stripe secret key" + stripe_currency: "Stripe currency" + invoice_prefix: "Invoices' files prefix" + confirmation_required: "Confirmation required" + wallet_module: "Wallet module" + statistics_module: "Statistics module" + upcoming_events_shown: "Display limit for upcoming events" + payment_schedule_prefix: "Payment schedule's files prefix" + trainings_module: "Trainings module" + address_required: "Address required" + accounting_Error_code: "Errors code" + accounting_Error_label: "Errors label" + payment_gateway: "Payment gateway" + payzen_username: "PayZen username" + payzen_password: "PayZen password" + payzen_endpoint: "PayZen API endpoint" + payzen_public_key: "PayZen client public key" + payzen_hmac: "PayZen HMAC-SHA-256 key" + payzen_currency: "PayZen currency" + public_agenda_module: "Public agenda module" + renew_pack_threshold: "Threshold for packs renewal" + pack_only_for_subscription: "Restrict packs for subscribers" + overlapping_categories: "Categories for overlapping booking prevention" + extended_prices_in_same_day: "Extended prices in the same day" + public_registrations: "Public registrations" + facebook: "facebook" + twitter: "twitter" + viadeo: "viadeo" + linkedin: "linkedin" + instagram: "instagram" + youtube: "youtube" + vimeo: "vimeo" + dailymotion: "dailymotion" + github: "github" + echosciences: "echosciences" + pinterest: "pinterest" + lastfm: "lastfm" + flickr: "flickr" + machines_module: "Machines module" + user_change_group: "Allow users to change their group" + show_username_in_admin_list: "Show the username in the admin's members list" + store_module: "Store module" + store_withdrawal_instructions: "Withdrawal instructions" + store_hidden: "Store hidden to the public" + advanced_accounting: "Advanced accounting" + external_id: "external identifier" + prevent_invoices_zero: "prevent building invoices at 0" + invoice_VAT-name: "VAT name" + trainings_auto_cancel: "Trainings automatic cancellation" + trainings_auto_cancel_threshold: "Minimum participants for automatic cancellation" + trainings_auto_cancel_deadline: "Automatic cancellation deadline" + trainings_authorization_validity: "Trainings validity period" + trainings_authorization_validity_duration: "Trainings validity period duration" + trainings_invalidation_rule: "Trainings automatic invalidation" + trainings_invalidation_rule_period: "Grace period before invalidating a training" + #statuses of projects + statuses: + new: "New" + pending: "Pending" + done: "Done" + abandoned: "Abandoned" diff --git a/config/locales/mails.de.yml b/config/locales/mails.de.yml index 1de187d70..e00ab59de 100644 --- a/config/locales/mails.de.yml +++ b/config/locales/mails.de.yml @@ -394,7 +394,7 @@ de: body: account_validated: "Your account was validated. Now, you have access to booking features." notify_user_is_invalidated: - subject: "Account invalidated" + subject: "Konto ungültig" body: account_invalidated: "Your account was invalidated. You won't be able to book anymore, until your account is validated again." notify_user_supporting_document_refusal: diff --git a/config/locales/mails.it.yml b/config/locales/mails.it.yml new file mode 100644 index 000000000..6dc6ad7d7 --- /dev/null +++ b/config/locales/mails.it.yml @@ -0,0 +1,422 @@ +it: + layouts: + notifications_mailer: + see_you_later: "See you soon on {GENDER, select, neutral{} other{the}}" #messageFormat interpolation + sincerely: "Sincerely," + signature: "The Fab Lab team." + do_not_reply: "Please do not reply to this email." + users_mailer: + notify_user_account_created: + subject: "Your FabLab account has been successfully created" + body: + hello: "Hello %{NAME}," + intro: "The FabLab team has just created an account for you, on {GENDER, select, neutral{} other{the}} {FABLAB} website:" #messageFormat interpolation + connection_parameters: "Here are your connection parameters:" + account_name: "Account name:" + password: "Password:" + temporary_password: "This is a temporary password, you can modify it in your «My account» screen." + keep_advantages: "With this account, you keep all the advantages linked to your Fab Lab user profile (trainings, subscriptions plans)." + to_use_platform: "To use the website, please" + logon_or_login: "create a new account or log in by clicking here." + token_if_link_problem: "If you experience issues with the link, you can enter the following code at your first connection attempt:" + notifications_mailer: + notify_user_user_group_changed: + subject: "You have changed group" + body: + warning: "You have changed group. Inspections can be conducted at the lab to verify the legitimacy of this change." + user_invalidated: "Your account was invalidated, please upload your new supporting documents to validate your account." + notify_admin_user_group_changed: + subject: "A member has changed group" + body: + user_changed_group_html: "User %{NAME} has changed group." + previous_group: "Previous group:" + new_group: "New group:" + user_invalidated: "The user's account was invalidated." + notify_admin_subscription_extended: + subject: "A subscription has been extended" + body: + subscription_extended_html: "Subscription {PLAN} for user {NAME} has been extended {FREE, select, true{for free} other{}} until {DATE}." #messageFormat interpolation + notify_member_subscription_extended: + subject: "Your subscription plan has been extended" + body: + your_plan: "Your subscription plan" + has_been_extended: "has been extended" + free: "for free" + until: "until" + notify_partner_subscribed_plan: + subject: "A subscription plan has been purchased" + body: + a_plan: "A subscription plan" + was_purchased_by_member: "has been purchased by user" + notify_admin_when_project_published: + subject: "A project has been published" + body: + new_project_published: "A new project has been published:" + notify_project_collaborator_to_valid: + subject: "Invitation to collaborate on a project" + body: + your_are_invited_to_take_part_in_a_project: "You are invited to join this project:" + to_accept_the_invitation_click_on_following_link: "To accept this invitation, please click on the following link:" + notify_project_author_when_collaborator_valid: + subject: "New collaborator in your project" + body: + the_member: "the user" + accepted_your_invitation_to_take_part_in_the_project: "has accepted your invitation to join your project:" + notify_user_training_valid: + subject: "Your training has been validated" + body: + your_training: "Your training" + has_been_validated: "has been validated" + notify_member_subscribed_plan: + subject: "Your subscription has been successfully purchased" + body: + plan_subscribed_html: "You have subscribed the plan: %{PLAN}." + rolling_subscription_stops_on: "Your subscription will end %{DURATION} after your first training. Otherwise, it will stop on %{DATE}." + subscription_stops_on: "Your subscription will end on %{DATE}." + notify_member_create_reservation: + subject: "Your reservation has been successfully saved" + body: + reservation_saved_html: "You reservation %{RESERVATION} has been successfully saved" + your_reserved_slots: "Your reserved slots are:" + notify_member_subscribed_plan_is_changed: + subject: "Your subscription has been updated" + body: + new_plan_html: "You have changed your plan to %{PLAN}." + notify_admin_member_create_reservation: + subject: "New reservation" + body: + member_reserved_html: "User %{NAME} has reserved %{RESERVABLE}." + reserved_slots: "Reserved slots are:" + notify_member_slot_is_modified: + subject: "Your reservation slot has been successfully changed" + body: + reservation_changed_to: "Your reservation slot has been changed to:" + previous_date: "Previous date:" + notify_admin_slot_is_modified: + subject: "A reservation slot has been modified" + body: + slot_modified: "User %{NAME} had modified his reservation slot" + new_date: "New slot" + old_date: "Previous slot" + notify_admin_when_user_is_created: + subject: "A user account has been created" + body: + new_account_created: "A new user account has been created on the website:" + user_of_group_html: "The user has registered in the group %{GROUP}" + account_for_organization: "This account manage an organization:" + notify_admin_subscribed_plan: + subject: "A subscription has been purchased" + body: + plan_subscribed_html: "A plan %{PLAN} has been subscribed by user %{NAME}." + notify_member_invoice_ready: + subject: "Your FabLab's invoice" + body: + please_find_attached_html: "Please find as attached file your invoice from {DATE}, with an amount of {AMOUNT} concerning your {TYPE, select, Reservation{reservation} OrderItem{order} other{subscription}}." #messageFormat interpolation + invoice_in_your_dashboard_html: "You can access your invoice in %{DASHBOARD} on the Fab Lab website." + your_dashboard: "your dashboard" + notify_member_reservation_reminder: + subject: "Reservation reminder" + body: + this_is_a_reminder_about_your_reservation_RESERVABLE_to_be_held_on_DATE_html: "This is a reminder about your reservation %{RESERVABLE} to be held on %{DATE}" + this_reservation_concerns_the_following_slots: "This reservation concerns the following slots:" + notify_member_avoir_ready: + subject: "Your FabLab's refund invoice" + body: + please_find_attached_html: "Please find as attached file your refund invoice from {DATE}, with an amount of {AMOUNT} concerning your {TYPE, select, Reservation{reservation} WalletTransaction{wallet credit} other{subscription}}." #messageFormat interpolation + invoice_in_your_dashboard_html: "You can access your refund invoice in %{DASHBOARD} on the Fab Lab website." + your_dashboard: "your dashboard" + notify_member_subscription_will_expire_in_7_days: + subject: "Your subscription expires in 7 days" + body: + your_plan: "you plan" + expires_in_7_days: "will expire in 7 days." + to_renew_your_plan_follow_the_link: "Please, follow this link to renew your plan" + notify_member_training_authorization_expired: + subject: "Your authorization was revoked" + body: + training_expired_html: "

You took the %{TRAINING} training, on %{DATE}.

Your authorization for this training, valid for %{PERIOD} months, has expired.

Please validate it again in order to be able to reserve the %{MACHINES}

." + notify_member_training_auto_cancelled: + subject: "Your training session was cancelled" + body: + cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, from %{START} to %{END} has been canceled due to an insufficient number of participants." + auto_refund: "You were refunded on your wallet and a credit note should be available." + notify_member_training_invalidated: + subject: "Your authorization was invalidated" + body: + training_invalidated_html: "

You took the %{TRAINING} training, on %{DATE} giving you access to the %{MACHINES}.

Due to the lack of reservations for one of these machines during the last %{PERIOD} months, your authorization has been invalidated.

Please validate the training again in order to continue reserving these machines.

." + notify_member_subscription_is_expired: + subject: "Your subscription has expired" + body: + your_plan: "You plan" + has_expired: "has expired." + you_can_go_to: "Please go to" + to_renew_your_plan: "to renew you plan" + notify_admin_subscription_will_expire_in_7_days: + subject: "A member subscription expires in 7 days" + body: + subscription_will_expire_html: "Subscription plan for user %{NAME} %{PLAN} will expire in 7 days." + notify_admin_training_auto_cancelled: + subject: "A training was automatically cancelled" + body: + cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, from %{START} to %{END} has been automatically canceled due to an insufficient number of participants." + auto_refund: "The members who have booked this training session were automatically refunded on their wallet and credit notes was generated." + manual_refund: "Please manually refund all members who have booked this training session and generate the credit notes." + notify_admin_subscription_is_expired: + subject: "A member subscription has expired" + body: + subscription_expired_html: "Subscription plan for user %{NAME} %{PLAN} is now expired." + notify_admin_subscription_canceled: + subject: "A member subscription has been cancelled" + body: + subscription_canceled_html: "Subscription %{PLAN} for user %{NAME} has been cancelled." + notify_member_subscription_canceled: + subject: "Your subscription has been cancelled" + body: + your_plan_was_canceled: "Your subscription plan has been cancelled." + your_plan: "your subscription plan" + end_at: "ends on" + notify_member_slot_is_canceled: + subject: "Your reservation has been canceled" + body: + reservation_canceled: "Your reservation for %{RESERVABLE} has been canceled" + notify_admin_slot_is_canceled: + subject: "A reservation has been cancelled" + body: + member_cancelled: "User %{NAME} has cancelled his reservation" + item_details: "%{START} - %{END}, concerning %{RESERVABLE}" + generate_refund: "Do not forget to generate a credit note or a refund for this cancellation." + notify_admin_when_user_is_imported: + subject: "A user account has been imported from the SSO" + body: + new_account_imported: "A new user account (ID: %{ID}) has been imported to the website via %{PROVIDER}." + provider_uid: "its provider ID is: " + known_information: "Here is what we know about this provider:" + address_already_used: "This address is already associated with another user" + no_more_info_available: "No other info about this user can be provided before he completes his profile." + notify_user_profile_complete: + subject: "You now have access to the whole website" + body: + message: "Your account informations has been correctly updated, you now have access to the whole website." + notify_user_auth_migration: + subject: "Important change to your FabLab account" + body: + the_platform: "the website" + is_changing_its_auth_system_and_will_now_use: "is actually changing its user identification system and will use" + instead_of: "instead of" + consequence_of_the_modification: "Because of this change you won't be able to login to the website with your actual usernames" + to_use_the_platform_thanks_for: "To keep on using the website, please" + create_an_account_on: "create an account on" + or_use_an_existing_account_clicking_here: "or use an existing account by clicking here" + in_case_of_problem_enter_the_following_code: "In case of problem with this link, you can enter the following code at your first connection attempt in order to migrate your actual account into the new authentification system:" + notify_admin_user_merged: + subject: "An imported account has been merged with an existing account" + body: + imported_account_merged: "A previously imported user account via %{PROVIDER) has been merged with the existing account %{NAME}" + provider_uid: "its provider ID is:" + notify_admin_profile_complete: + subject: "An imported account has completed its profile" + body: + account_completed: "An user account has completed its profile:" + imported_account_completed: "An user account, previously imported through %{PROVIDER}, has completed its profile:" + provider_id: "its provider ID is:" + notify_admin_abuse_reported: + subject: "An abusive content has been reported" + body: + intro: "A user has flagged a content as abusive" + signaled_content: "flagged content:" + signaled_by: "flagged by:" + signaled_on: "flagged on:" + message: "Message:" + visit_management_interface: "Refer to the Reporting Management Interface for more information." + notify_user_wallet_is_credited: + subject: "Your wallet has been credited" + body: + wallet_credit_html: "Your wallet has been credited %{AMOUNT} by administrator." + notify_admin_user_wallet_is_credited: + subject: "The wallet of an user has been credited" + body: + wallet_credit_html: "The wallet of member %{USER} has been credited %{AMOUNT} by administrator %{ADMIN}." + notify_admin_export_complete: + subject: "Export completed" + body: + you_asked_for_an_export: "You asked for an export" + statistics_global: "of all the statistics" + statistics_account: "of the registration statistics" + statistics_event: "of statistics about events" + statistics_machine: "of statistics about machine slots" + statistics_project: "of statistics about projects" + statistics_subscription: "of subscription statistics" + statistics_training: "of statistics about trainings" + statistics_space: "of statistics about spaces" + users_members: "of the members' list" + users_subscriptions: "of the subscriptions' list" + users_reservations: "of the reservations' list" + availabilities_index: "of the reservations availabilities" + accounting_acd: "of the accounting data to ACD" + accounting_vat: "of the collected VAT data" + click_to_download: "Excel file generated successfully. To download it, click" + here: "here" + file_type: + xlsx: "Excel" + csv: "CSV" + notify_admin_import_complete: + subject: "Import completed" + body: + you_made_an_import: "You have initiated an import %{CATEGORY}" + category_members: "of the members" + click_to_view_results: "Click here to view results" + notify_admin_low_stock_threshold: + subject: "Low stock alert" + body: + low_stock: "A new stock movement of %{PRODUCT} has exceeded the low stock threshold." + stocks_state_html: "Current stock status:
  • internal: %{INTERNAL}
  • external: %{EXTERNAL}
" + manage_stock: "Manage stocks for this product" + notify_member_about_coupon: + subject: "Coupon" + body: + enjoy_a_discount_of_PERCENT_with_code_CODE: "Enjoy a discount of %{PERCENT}% on the whole site with the code %{CODE}." + enjoy_a_discount_of_AMOUNT_with_code_CODE: "Enjoy a discount of %{AMOUNT} on the whole site with the code %{CODE}." + this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases: "This coupon is valid {USAGE, plural, =1{just once} other{many times}}: for all your purchases {TYPE, select, amount_off{at least equal to the amount of the coupon} other{}}, from now {DATE, select, NO-DATE{and without time limit} other{and until {DATE}}}." + notify_admin_free_disk_space: + subject: "Low disk space" + body: "Warning: available disk space on the server hosting Fab-manager is less than %{THRESHOLD} MiB. This can affect its operation and prevent saving some data. Currently, %{AVAILABLE} MiB of free disk space remains available on the mount point." + notify_admin_close_period_reminder: + subject: "Remind to close your accounting periods" + body: + warning_last_closed_period_over_1_year: "Please remind to periodically close your accounting periods. Last closed period ended at %{LAST_END}." + warning_no_closed_periods: "Please remind to periodically close your accounting periods. You have to close periods from %{FIRST_DATE}." + notify_admin_archive_complete: + subject: "Archiving completed" + body: + archive_complete: "You have closed the accounting period from %{START} to %{END}. Archiving of data is now complete." + click_to_download: "To download the ZIP archive, click" + here: "here." + save_on_secured: "Remember that you must save this archive on a secured external support, which may be requested by the tax authorities during a check." + notify_privacy_policy_changed: + subject: "Privacy policy updated" + body: + content_html: "

We wish to inform you that we have just updated our privacy policy.

We may change our privacy policy regularly. In accordance with the regulations, you will receive a notification for each update.

By accessing or using our services after the privacy policy update, we will consider that you agree its terms, updates included.

" + link_to_policy: "Click here to view the privacy policy." + notify_admin_refund_created: + subject: "A refund has been generated" + body: + refund_created: "A refund of %{AMOUNT} has been generated on invoice %{INVOICE} of user %{USER}" + wallet_refund_created: "A refund of %{AMOUNT} has been generated for the credit of the wallet of user %{USER}" + download: "Click here to download this refund invoice" + notify_admins_role_update: + subject: "The role of a user has changed" + body: + user_role_changed_html: "The role of the user %{NAME} has changed." + previous_role: "Previous role:" + new_role: "New role:" + notify_user_role_update: + subject: "Your role has changed" + body: + role_changed_html: "Your role at {GENDER, select, male{the} female{the} neutral{} other{the}} {NAME} has changed. You are now {ROLE}.
With great power comes great responsibility, use your new privileges fairly and respectfully." + notify_admin_objects_stripe_sync: + subject: "Stripe synchronization" + body: + objects_sync: "All members, coupons, machines, trainings, spaces and plans were successfully synchronized on Stripe." + notify_admin_order_is_paid: + subject: "New order" + body: + order_placed: "A new order (%{REFERENCE}) has been placed and paid by %{USER}." + view_details: "" + notify_member_payment_schedule_ready: + subject: "Your payment schedule" + body: + please_find_attached_html: "Please find attached your payment schedule, issued on {DATE}, with an amount of {AMOUNT} concerning your {TYPE, select, Reservation{reservation} other{subscription}}." #messageFormat interpolation + schedule_in_your_dashboard_html: "You can find this payment schedule at any time from %{DASHBOARD} on the Fab Lab's website." + your_dashboard: "your dashboard" + notify_admin_payment_schedule_error: + subject: "[URGENT] Card debit error" + body: + remember: "In accordance with the %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}." + error: "Unfortunately, an error occurred and this card debit was unable to complete successfully." + action: "Please then consult the %{GATEWAY} dashboard and contact the member as soon as possible to resolve the problem." + notify_member_payment_schedule_error: + subject: "[URGENT] Card debit error" + body: + remember: "In accordance with your %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}." + error: "Unfortunately, an error occurred and this card debit was unable to complete successfully." + action: "Please contact a manager as soon as possible to resolve the problem." + notify_admin_payment_schedule_failed: + subject: "[URGENT] Card debit failure" + body: + remember: "In accordance with the %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}." + error: "Unfortunately, this card debit was unable to complete successfully." + action: "Please contact the member as soon as possible, then go to the payment schedule management interface to resolve the problem. After a certain period of time, the card subscription could be cancelled." + notify_member_payment_schedule_failed: + subject: "[URGENT] Card debit failure" + body: + remember: "In accordance with your %{REFERENCE} payment schedule, a debit by card of %{AMOUNT} was scheduled on %{DATE}." + error: "Unfortunately, this card debit was unable to complete successfully." + action_html: "Please check %{DASHBOARD} or contact a manager quickly, otherwise your subscription may be interrupted." + your_dashboard: "your dashboard" + notify_admin_payment_schedule_gateway_canceled: + subject: "[URGENT] Payment schedule canceled by the payment gateway" + body: + error: "The payment schedule %{REFERENCE} was canceled by the payment gateway (%{GATEWAY}). No further debits will be made on this payment mean." + action: "Please consult the payment schedule management interface and contact the member as soon as possible to resolve the problem." + notify_member_payment_schedule_gateway_canceled: + subject: "[URGENT] Payment schedule canceled by the payment gateway" + body: + error: "Your payment schedule %{REFERENCE} was canceled by the payment gateway. No further debits will be made on this payment mean." + action: "Please contact a manager as soon as possible to resolve the problem." + notify_admin_payment_schedule_check_deadline: + subject: "Payment deadline" + body: + remember: "In accordance with the %{REFERENCE} payment schedule, %{AMOUNT} was due to be debited on %{DATE}." + date: "This is a reminder to cash the scheduled check as soon as possible." + confirm: "Do not forget to confirm the receipt in your payment schedule management interface, so that the corresponding invoice will be generated." + notify_member_payment_schedule_transfer_deadline: + subject: "Payment deadline" + body: + remember: "In accordance with your %{REFERENCE} payment schedule, %{AMOUNT} was due to be debited on %{DATE}." + date: "This is a reminder to verify that the direct bank debit was successfull." + confirm: "Please confirm the receipt of funds in your payment schedule management interface, so that the corresponding invoice will be generated." + notify_member_reservation_limit_reached: + subject: "Daily reservation limit reached" + body: + limit_reached: "For %{DATE}, you have reached your daily limit of %{HOURS} hours of %{ITEM} reservation." + notify_admin_user_supporting_document_files_created: + subject: "Supporting documents uploaded by a member" + body: + supporting_document_files_uploaded_below: "Member %{NAME} has uploaded the following supporting documents:" + validate_user: "Please validate this account" + notify_admin_user_supporting_document_files_updated: + subject: "Member's supporting documents have changed" + body: + user_update_supporting_document_file: "Member %{NAME} has modified the supporting documents below:" + validate_user: "Please validate this account" + notify_user_is_validated: + subject: "Account validated" + body: + account_validated: "Your account was validated. Now, you have access to booking features." + notify_user_is_invalidated: + subject: "Account invalidated" + body: + account_invalidated: "Your account was invalidated. You won't be able to book anymore, until your account is validated again." + notify_user_supporting_document_refusal: + subject: "Your supporting documents were refused" + body: + user_supporting_document_files_refusal: "Your supporting documents were refused:" + action: "Please re-upload some new supporting documents." + notify_admin_user_supporting_document_refusal: + subject: "A member's supporting documents were refused" + body: + user_supporting_document_files_refusal: "Member %{NAME}'s supporting documents were rejected by %{OPERATOR}:" + shared: + hello: "Hello %{user_name}" + notify_user_order_is_ready: + subject: "Your command is ready" + body: + notify_user_order_is_ready: "Your command %{REFERENCE} is ready:" + notify_user_order_is_canceled: + subject: "Your command was canceled" + body: + notify_user_order_is_canceled: "Your command %{REFERENCE} was canceled." + notify_user_order_is_refunded: + subject: "Your command was refunded" + body: + notify_user_order_is_refunded: "Your command %{REFERENCE} was refunded." diff --git a/config/locales/mails.pt.yml b/config/locales/mails.pt.yml index 2462370ec..99eb43143 100644 --- a/config/locales/mails.pt.yml +++ b/config/locales/mails.pt.yml @@ -111,7 +111,7 @@ pt: notify_member_invoice_ready: subject: "Fatura do seu FabLab" body: - please_find_attached_html: "Please find as attached file your invoice from {DATE}, with an amount of {AMOUNT} concerning your {TYPE, select, Reservation{reservation} OrderItem{order} other{subscription}}." #messageFormat interpolation + please_find_attached_html: "Por favor, encontre como arquivo anexado sua fatura a partir de {DATE}, com um valor de {AMOUNT} relativo {TYPE, select, Reservation{a sua reserva} OrderItem{ao seu pedido} other{a sua assinatura}}." #messageFormat interpolation invoice_in_your_dashboard_html: "Você pode acessar sua fatura em %{DASHBOARD} no site Fab Lab." your_dashboard: "seu dashboard" notify_member_reservation_reminder: @@ -132,18 +132,18 @@ pt: expires_in_7_days: "expira em 7 dias." to_renew_your_plan_follow_the_link: "Por favor, siga este link para renovar seu plano" notify_member_training_authorization_expired: - subject: "Your authorization was revoked" + subject: "Sua autorização foi revogada" body: - training_expired_html: "

You took the %{TRAINING} training, on %{DATE}.

Your authorization for this training, valid for %{PERIOD} months, has expired.

Please validate it again in order to be able to reserve the %{MACHINES}

." + training_expired_html: "

Você fez o treinamento %{TRAINING} em %{DATE}.

A sua autorização para este treinamento, válida por %{PERIOD} meses, expirou.

Por favor, valide novamente para poder reservar %{MACHINES}

." notify_member_training_auto_cancelled: - subject: "Your training session was cancelled" + subject: "Sua sessão de treinamento foi cancelada" body: - cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, from %{START} to %{END} has been canceled due to an insufficient number of participants." - auto_refund: "You were refunded on your wallet and a credit note should be available." + cancelled_training: "A sessão de treinamento %{TRAINING} agendada para %{DATE}, de %{START} a %{END} foi cancelada devido a um número insuficiente de participantes." + auto_refund: "Você foi reembolsado na sua carteira e uma nota de crédito deve estar disponível." notify_member_training_invalidated: - subject: "Your authorization was invalidated" + subject: "Sua autorização foi invalidada" body: - training_invalidated_html: "

You took the %{TRAINING} training, on %{DATE} giving you access to the %{MACHINES}.

Due to the lack of reservations for one of these machines during the last %{PERIOD} months, your authorization has been invalidated.

Please validate the training again in order to continue reserving these machines.

." + training_invalidated_html: "

Você realizou o treinamento %{TRAINING} em %{DATE} que dá acesso a %{MACHINES}.

Por falta de reservas para uma dessas máquinas nos últimos %{PERIOD} meses sua autorização foi invalidada.

Por favor, valide o treinamento novamente para continuar a reservar estas máquinas.

." notify_member_subscription_is_expired: subject: "Sua assinatura expirou" body: @@ -156,11 +156,11 @@ pt: body: subscription_will_expire_html: "O plano de assinatura do usuário %{NAME} %{PLAN} expirará em 7 dias." notify_admin_training_auto_cancelled: - subject: "A training was automatically cancelled" + subject: "Um treinamento foi automaticamente cancelado" body: - cancelled_training: "The %{TRAINING} training session scheduled for %{DATE}, from %{START} to %{END} has been automatically canceled due to an insufficient number of participants." - auto_refund: "The members who have booked this training session were automatically refunded on their wallet and credit notes was generated." - manual_refund: "Please manually refund all members who have booked this training session and generate the credit notes." + cancelled_training: "A sessão de treinamento %{TRAINING} agendada para %{DATE}, de %{START} a %{END} foi cancelada devido ao número insuficiente de participantes." + auto_refund: "Os membros que reservaram essa sessão de treinamento foram automaticamente reembolsados em suas carteiras e as notas de crédito foram geradas." + manual_refund: "Por favor, reembolse manualmente todos os membros que reservaram esta sessão de treinamento e gere as notas de créditos." notify_admin_subscription_is_expired: subject: "A assinatura de um membro expirou" body: @@ -266,11 +266,11 @@ pt: category_members: "dos membros" click_to_view_results: "Clique aqui para ver os resultados" notify_admin_low_stock_threshold: - subject: "Low stock alert" + subject: "Alerta de estoque baixo" body: - low_stock: "A new stock movement of %{PRODUCT} has exceeded the low stock threshold." - stocks_state_html: "Current stock status:
  • internal: %{INTERNAL}
  • external: %{EXTERNAL}
" - manage_stock: "Manage stocks for this product" + low_stock: "Um novo movimento de estoque de %{PRODUCT} excedeu o limite de estoque baixo." + stocks_state_html: "Status atual do estoque:
  • interno: %{INTERNAL}
  • externo: %{EXTERNAL}
" + manage_stock: "Gerenciar estoque para este produto" notify_member_about_coupon: subject: "Cupom" body: @@ -318,9 +318,9 @@ pt: body: objects_sync: "Todos os membros, cupons, máquinas, treinamentos, espaços e planos foram sincronizados com sucesso no Stripe." notify_admin_order_is_paid: - subject: "New order" + subject: "Novo pedido" body: - order_placed: "A new order (%{REFERENCE}) has been placed and paid by %{USER}." + order_placed: "Um novo pedido (%{REFERENCE}) foi realizado e pago por %{USER}." view_details: "" notify_member_payment_schedule_ready: subject: "Sua agenda de pagamentos" @@ -376,19 +376,19 @@ pt: date: "Este é um lembrete para verificar se o débito bancário foi bem sucedido." confirm: "Não se esqueça de confirmar o recibo na interface de gestão de pagamento, para que a fatura correspondente seja gerada." notify_member_reservation_limit_reached: - subject: "Daily reservation limit reached" + subject: "Limite diário de reservas atingido" body: - limit_reached: "For %{DATE}, you have reached your daily limit of %{HOURS} hours of %{ITEM} reservation." + limit_reached: "Para %{DATE}, você atingiu seu limite diário de %{HOURS} horas de reserva em %{ITEM}." notify_admin_user_supporting_document_files_created: - subject: "Supporting documents uploaded by a member" + subject: "Documentos de suporte enviados por um membro" body: - supporting_document_files_uploaded_below: "Member %{NAME} has uploaded the following supporting documents:" - validate_user: "Please validate this account" + supporting_document_files_uploaded_below: "O membro %{NAME} enviou os seguintes documentos de suporte:" + validate_user: "Por favor, valide esta conta" notify_admin_user_supporting_document_files_updated: - subject: "Member's supporting documents have changed" + subject: "Os documentos de apoio dos membros mudaram" body: - user_update_supporting_document_file: "Member %{NAME} has modified the supporting documents below:" - validate_user: "Please validate this account" + user_update_supporting_document_file: "O membro %{NAME} modificou os documentos de suporte abaixo:" + validate_user: "Por favor, valide esta conta" notify_user_is_validated: subject: "Conta validada" body: @@ -398,25 +398,25 @@ pt: body: account_invalidated: "Sua conta foi invalidada. Você não poderá mais reservar até que sua conta seja validada novamente." notify_user_supporting_document_refusal: - subject: "Your supporting documents were refused" + subject: "Seus documentos de apoio foram recusados" body: - user_supporting_document_files_refusal: "Your supporting documents were refused:" - action: "Please re-upload some new supporting documents." + user_supporting_document_files_refusal: "Os seus documentos de apoio foram recusados:" + action: "Por favor, recarregue novos documentos de apoio." notify_admin_user_supporting_document_refusal: - subject: "A member's supporting documents were refused" + subject: "Documentos de apoio de um membro foram recusados" body: - user_supporting_document_files_refusal: "Member %{NAME}'s supporting documents were rejected by %{OPERATOR}:" + user_supporting_document_files_refusal: "Os documentos de apoio do membro %{NAME} foram rejeitados por %{OPERATOR}:" shared: hello: "Olá %{user_name}" notify_user_order_is_ready: - subject: "Your command is ready" + subject: "Seu pedido está pronto" body: - notify_user_order_is_ready: "Your command %{REFERENCE} is ready:" + notify_user_order_is_ready: "Seu pedido %{REFERENCE} está pronto:" notify_user_order_is_canceled: - subject: "Your command was canceled" + subject: "Seu pedido foi cancelado" body: - notify_user_order_is_canceled: "Your command %{REFERENCE} was canceled." + notify_user_order_is_canceled: "Seu pedido %{REFERENCE} foi cancelado." notify_user_order_is_refunded: - subject: "Your command was refunded" + subject: "Seu pedido foi reembolsado" body: - notify_user_order_is_refunded: "Your command %{REFERENCE} was refunded." + notify_user_order_is_refunded: "Seu pedido %{REFERENCE} foi reembolsado." diff --git a/config/locales/no.yml b/config/locales/no.yml index 990c70005..17dd1da76 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -102,6 +102,7 @@ training_reservation_DESCRIPTION: "Bestilling, opplæring/kurs - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Arrangements-reservasjon - %{DESCRIPTION}" from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" + null_invoice: "Invoice at nil, billing jump following a malfunction of the Fab Manager software" full_price_ticket: one: "En fullprisbillett" other: "%{count} full price tickets" diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 8586f8c2c..08b3bf79b 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -13,7 +13,7 @@ pt: activerecord: attributes: product: - amount: "The price" + amount: "O preço" slug: "URL" errors: #CarrierWave @@ -43,12 +43,12 @@ pt: invalid_duration: "A duração permitida deve ter entre 1 dia e 1 ano. Sua menstruação tem %{DAYS} dias." must_be_in_the_past: "O período deve ser estritamente anterior à data de hoje." registration_disabled: "Registo está desabilitado" - undefined_in_store: "must be defined to make the product available in the store" - gateway_error: "Payement gateway error: %{MESSAGE}" + undefined_in_store: "deve ser definido para tornar o produto disponível na loja" + gateway_error: "Erro do gateway de pagamento: %{MESSAGE}" gateway_amount_too_small: "Payments under %{AMOUNT} are not supported. Please order directly at the reception." gateway_amount_too_large: "Payments above %{AMOUNT} are not supported. Please order directly at the reception." - product_in_use: "This product have already been ordered" - slug_already_used: "is already used" + product_in_use: "Este produto já foi comprado" + slug_already_used: "já está em uso" coupon: code_format_error: "only caps letters, numbers, and dashes are allowed" apipie: @@ -102,6 +102,7 @@ pt: training_reservation_DESCRIPTION: "Reserva de treinamneto - %{DESCRIPTION}" event_reservation_DESCRIPTION: "Reserva de evento - %{DESCRIPTION}" from_payment_schedule: "Due %{NUMBER} out of %{TOTAL}, from %{DATE}. Repayment schedule %{SCHEDULE}" + null_invoice: "Invoice at nil, billing jump following a malfunction of the Fab Manager software" full_price_ticket: one: "Um ticket de preço cheio" other: "%{count} tickets de preço cheio" @@ -510,29 +511,29 @@ pt: reduced_fare_if_you_are_under_25_student_or_unemployed: "Tarifa reduzida se tiver menos de 25 anos, estudante ou desempregado." cart_items: free_extension: "Extensão gratuita de uma assinatura, até %{DATE}" - must_be_after_expiration: "The new expiration date must be set after the current expiration date" - group_subscription_mismatch: "Your group mismatch with your subscription. Please report this error." + must_be_after_expiration: "A nova data de expiração deve ser definida após a data de expiração atual" + group_subscription_mismatch: "Seu grupo não coincide com sua assinatura. Por favor, reporte este erro." statistic_profile: birthday_in_past: "A data de nascimento deve estar no passado" order: - please_contact_FABLAB: "Please contact us for withdrawal instructions." + please_contact_FABLAB: "Por favor, entre em contato conosco para instruções de retirada." cart_item_validation: - slot: "The slot doesn't exist" - availability: "The availaility doesn't exist" - full: "The slot is already fully reserved" - deadline: "You can't reserve a slot %{MINUTES} minutes prior to its start" - limit_reached: "You have reached the booking limit of %{HOURS}H per day for the %{RESERVABLE}, for your current subscription. Please adjust your reservation." - restricted: "This availability is restricted for subscribers" - plan: "This subscription plan is disabled" - plan_group: "This subscription plan is reserved for members of group %{GROUP}" - reserved: "This slot is already reserved" - pack: "This prepaid pack is disabled" - pack_group: "This prepaid pack is reserved for members of group %{GROUP}" - space: "This space is disabled" - machine: "This machine is disabled" - reservable: "This machine is not reservable" + slot: "O slot não existe" + availability: "A disponibilidade não existe" + full: "O slot já está totalmente reservado" + deadline: "Você não pode reservar um slot %{MINUTES} minutos antes do seu início" + limit_reached: "Você atingiu o limite de reserva de %{HOURS}H por dia para %{RESERVABLE}, para sua assinatura atual. Por favor, ajuste sua reserva." + restricted: "Essa disponibilidade é restrita para assinantes" + plan: "Este plano de assinatura está desativado" + plan_group: "Este plano de assinatura é reservado para membros do grupo %{GROUP}" + reserved: "Este slot já está reservado" + pack: "Este pacote pré-pago está desativado" + pack_group: "Esse pacote pré-pago é reservado para membros do grupo %{GROUP}" + space: "Este espaço está desativado" + machine: "Esta máquina está desativada" + reservable: "Esta máquina não é reservável" cart_validation: - select_user: "Please select a user before continuing" + select_user: "Por favor, selecione um usuário antes de continuar" settings: locked_setting: "a configuração está bloqueada." about_title: "\"Sobre\" título da página" @@ -698,7 +699,7 @@ pt: trainings_invalidation_rule_period: "Grace period before invalidating a training" #statuses of projects statuses: - new: "New" - pending: "Pending" - done: "Done" - abandoned: "Abandoned" + new: "Novo" + pending: "Pendente" + done: "Concluído" + abandoned: "Abandonado" diff --git a/config/locales/zu.yml b/config/locales/zu.yml index 760884db6..ae7cc63dd 100644 --- a/config/locales/zu.yml +++ b/config/locales/zu.yml @@ -102,6 +102,7 @@ zu: training_reservation_DESCRIPTION: "crwdns3321:0%{DESCRIPTION}crwdne3321:0" event_reservation_DESCRIPTION: "crwdns3323:0%{DESCRIPTION}crwdne3323:0" from_payment_schedule: "crwdns36355:0%{NUMBER}crwdnd36355:0%{TOTAL}crwdnd36355:0%{DATE}crwdnd36355:0%{SCHEDULE}crwdne36355:0" + null_invoice: "crwdns37603:0crwdne37603:0" full_price_ticket: one: "crwdns3325:1crwdne3325:1" other: "crwdns3325:5%{count}crwdne3325:5" diff --git a/config/routes.rb b/config/routes.rb index 496db7a04..4f9872af2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,7 +4,7 @@ require 'sidekiq_unique_jobs/web' require 'sidekiq-scheduler/web' Rails.application.routes.draw do - if AuthProvider.active.providable_type == DatabaseProvider.name + if Rails.configuration.auth_provider.providable_type == 'DatabaseProvider' # with local authentication we do not use omniAuth so we must differentiate the config devise_for :users, controllers: { registrations: 'registrations', sessions: 'sessions', confirmations: 'confirmations', passwords: 'passwords' diff --git a/db/migrate/20170227104934_migrate_slots_reservations.rb b/db/migrate/20170227104934_migrate_slots_reservations.rb index 611972c19..4bd361075 100644 --- a/db/migrate/20170227104934_migrate_slots_reservations.rb +++ b/db/migrate/20170227104934_migrate_slots_reservations.rb @@ -1,15 +1,16 @@ # frozen_string_literal:true +# From this migration, we migrate all reservation-related data from Slot to SlotReservation class MigrateSlotsReservations < ActiveRecord::Migration[4.2] def up Slot.all.each do |slot| - SlotsReservation.create!({slot_id: slot.id, reservation_id: slot.reservation_id}) + SlotsReservation.create!({ slot_id: slot.id, reservation_id: slot.reservation_id }) end end def down SlotsReservation.all.each do |sr| - Slot.find(sr.slot_id).update_attributes(:reservation_id => sr.reservation_id) + Slot.find(sr.slot_id).update(reservation_id: sr.reservation_id) end end end diff --git a/db/migrate/20190521124609_migrate_profile_to_invoicing_profile.rb b/db/migrate/20190521124609_migrate_profile_to_invoicing_profile.rb index 08823dcab..4ca1c68bb 100644 --- a/db/migrate/20190521124609_migrate_profile_to_invoicing_profile.rb +++ b/db/migrate/20190521124609_migrate_profile_to_invoicing_profile.rb @@ -1,5 +1,7 @@ # frozen_string_literal:true +# From this migration, we split the user's profile into multiple tables: +# InvoicingProfile is intended to keep invoicing data about the user after his account was deleted class MigrateProfileToInvoicingProfile < ActiveRecord::Migration[4.2] def up User.all.each do |u| @@ -12,10 +14,10 @@ class MigrateProfileToInvoicingProfile < ActiveRecord::Migration[4.2] last_name: p.last_name, email: u.email ) - Address.find_by(placeable_id: p.id, placeable_type: 'Profile')&.update_attributes( + Address.find_by(placeable_id: p.id, placeable_type: 'Profile')&.update( placeable: ip ) - Organization.find_by(profile_id: p.id)&.update_attributes( + Organization.find_by(profile_id: p.id)&.update( invoicing_profile_id: ip.id ) end @@ -24,14 +26,14 @@ class MigrateProfileToInvoicingProfile < ActiveRecord::Migration[4.2] def down InvoicingProfile.all.each do |ip| profile = ip.user.profile - profile.update_attributes( + profile.update( first_name: ip.first_name, last_name: ip.last_name ) - Address.find_by(placeable_id: ip.id, placeable_type: 'InvoicingProfile')&.update_attributes( + Address.find_by(placeable_id: ip.id, placeable_type: 'InvoicingProfile')&.update( placeable: profile ) - Organization.find_by(invoicing_profile_id: ip.id)&.update_attributes( + Organization.find_by(invoicing_profile_id: ip.id)&.update( profile_id: profile.id ) end diff --git a/db/migrate/20190521151142_migrate_profile_to_statistic_profile.rb b/db/migrate/20190521151142_migrate_profile_to_statistic_profile.rb index 9a5205ed5..8621021f3 100644 --- a/db/migrate/20190521151142_migrate_profile_to_statistic_profile.rb +++ b/db/migrate/20190521151142_migrate_profile_to_statistic_profile.rb @@ -1,5 +1,7 @@ # frozen_string_literal:true +# From this migration, we split the user's profile into multiple tables: +# StatisticProfile is intended to keep anonymous statisttical data about the user after his account was deleted class MigrateProfileToStatisticProfile < ActiveRecord::Migration[4.2] def up User.all.each do |u| @@ -22,7 +24,7 @@ class MigrateProfileToStatisticProfile < ActiveRecord::Migration[4.2] p = sp.user.profile Rails.logger.warn "User #{sp.user_id} has no profile" and next unless p - p.update_attributes( + p.update( gender: sp.gender, birthday: sp.birthday ) diff --git a/db/migrate/20190523123916_migrate_wallet_to_invoicing_profile.rb b/db/migrate/20190523123916_migrate_wallet_to_invoicing_profile.rb index 0fa3ab7f4..f205e90a7 100644 --- a/db/migrate/20190523123916_migrate_wallet_to_invoicing_profile.rb +++ b/db/migrate/20190523123916_migrate_wallet_to_invoicing_profile.rb @@ -1,16 +1,17 @@ # frozen_string_literal:true +# Wallet data must be attached to InvoicingProfile because we must keep these data after the user has delete his account class MigrateWalletToInvoicingProfile < ActiveRecord::Migration[4.2] def up Wallet.all.each do |w| user = User.find(w.user_id) - w.update_attributes( + w.update( invoicing_profile_id: user.invoicing_profile.id ) end WalletTransaction.all.each do |wt| user = User.find(wt.user_id) - wt.update_attributes( + wt.update( invoicing_profile_id: user.invoicing_profile.id ) end @@ -19,13 +20,13 @@ class MigrateWalletToInvoicingProfile < ActiveRecord::Migration[4.2] def down Wallet.all.each do |w| invoicing_profile = User.find(w.invoicing_profile_id) - w.update_attributes( + w.update( user_id: invoicing_profile.user_id ) end WalletTransaction.all.each do |wt| invoicing_profile = User.find(wt.invoicing_profile_id) - wt.update_attributes( + wt.update( user_id: invoicing_profile.user_id ) end diff --git a/db/migrate/20190523140823_migrate_history_value_to_invoicing_profile.rb b/db/migrate/20190523140823_migrate_history_value_to_invoicing_profile.rb index 60e459d6b..99065d53e 100644 --- a/db/migrate/20190523140823_migrate_history_value_to_invoicing_profile.rb +++ b/db/migrate/20190523140823_migrate_history_value_to_invoicing_profile.rb @@ -1,10 +1,11 @@ # frozen_string_literal:true +# HistoryValue must be attached to InvoicingProfile because we want to be able to blame who was responsible for a change in accounting settings class MigrateHistoryValueToInvoicingProfile < ActiveRecord::Migration[4.2] def up HistoryValue.all.each do |hv| user = User.find_by(id: hv.user_id) - hv.update_attributes( + hv.update( invoicing_profile_id: user&.invoicing_profile&.id ) end @@ -13,7 +14,7 @@ class MigrateHistoryValueToInvoicingProfile < ActiveRecord::Migration[4.2] def down HistoryValue.all.each do |hv| invoicing_profile = User.find_by(id: hv.invoicing_profile_id) - hv.update_attributes( + hv.update( user_id: invoicing_profile&.user_id ) end diff --git a/db/migrate/20220328141618_create_open_id_connect_providers.rb b/db/migrate/20220328141618_create_open_id_connect_providers.rb index a7d7c34c7..de9c33757 100644 --- a/db/migrate/20220328141618_create_open_id_connect_providers.rb +++ b/db/migrate/20220328141618_create_open_id_connect_providers.rb @@ -9,7 +9,6 @@ class CreateOpenIdConnectProviders < ActiveRecord::Migration[5.2] t.string :client_auth_method t.string :scope t.string :response_type - t.string :response_type t.string :response_mode t.string :display t.string :prompt diff --git a/db/migrate/20230323085947_create_chained_elements.rb b/db/migrate/20230323085947_create_chained_elements.rb new file mode 100644 index 000000000..22fb495b2 --- /dev/null +++ b/db/migrate/20230323085947_create_chained_elements.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# From this migration, we save the chained elements in a separate table instead of adding footprints in their tables (like in invoices) +# This will allows more flexibility for the models +class CreateChainedElements < ActiveRecord::Migration[6.1] + def up + create_table :chained_elements do |t| + t.references :element, index: true, polymorphic: true, null: false + t.integer :previous_id + t.foreign_key :chained_elements, column: :previous_id, primary_key: :id + t.jsonb :content, null: false + t.string :footprint, null: false + + t.timestamps + end + + execute <<~SQL.squish + CREATE OR REPLACE RULE chained_elements_upd_protect AS ON UPDATE + TO chained_elements + WHERE ( + new.content <> old.content OR + new.footprint <> old.footprint OR + new.previous_id <> old.previous_id OR + new.element_id <> old.element_id OR + new.element_type <> old.element_type) + DO INSTEAD NOTHING; + SQL + end + + def down + execute <<~SQL.squish + DROP RULE IF EXISTS chained_elements_upd_protect ON chained_elements; + SQL + drop_table :chained_elements + end +end diff --git a/db/migrate/20230323104259_migrate_chaining_system.rb b/db/migrate/20230323104259_migrate_chaining_system.rb new file mode 100644 index 000000000..28c7aacfd --- /dev/null +++ b/db/migrate/20230323104259_migrate_chaining_system.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# From this migration, we migrate the chaining system to the new chained_elements table +class MigrateChainingSystem < ActiveRecord::Migration[6.1] + def up + [Invoice, InvoiceItem, HistoryValue, PaymentSchedule, PaymentScheduleItem, PaymentScheduleObject].each do |klass| + order = klass == HistoryValue ? :created_at : :id + previous = nil + klass.order(order).find_each do |item| + created = ChainedElement.create!( + element: item, + previous: previous + ) + previous = created + end + end + end + + def down + execute("TRUNCATE TABLE #{ChainedElement.arel_table.name}") + end +end diff --git a/db/migrate/20230323104727_drop_footprint_debugs.rb b/db/migrate/20230323104727_drop_footprint_debugs.rb new file mode 100644 index 000000000..28ba84b7a --- /dev/null +++ b/db/migrate/20230323104727_drop_footprint_debugs.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +# From this migration we delete the footprint_debugs table became useless +class DropFootprintDebugs < ActiveRecord::Migration[6.1] + def change + drop_table :footprint_debugs do |t| + t.string :footprint + t.string :data + t.string :klass + + t.timestamps + end + end +end diff --git a/db/migrate/20230324090312_drop_footprint_column.rb b/db/migrate/20230324090312_drop_footprint_column.rb new file mode 100644 index 000000000..042c8326c --- /dev/null +++ b/db/migrate/20230324090312_drop_footprint_column.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# We remove the footprint columns became useless +class DropFootprintColumn < ActiveRecord::Migration[6.1] + def change + remove_column :invoices, :footprint, :string + remove_column :invoice_items, :footprint, :string + remove_column :history_values, :footprint, :string + remove_column :payment_schedules, :footprint, :string + remove_column :payment_schedule_items, :footprint, :string + remove_column :payment_schedule_objects, :footprint, :string + end +end diff --git a/db/migrate/20230324095639_add_order_number.rb b/db/migrate/20230324095639_add_order_number.rb new file mode 100644 index 000000000..47eaa9ff9 --- /dev/null +++ b/db/migrate/20230324095639_add_order_number.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +# We now store the order number in DB, instead of generating it on every access +class AddOrderNumber < ActiveRecord::Migration[6.1] + def change + add_column :invoices, :order_number, :string + add_column :payment_schedules, :order_number, :string + end +end diff --git a/db/migrate/20230328094807_add_service_name_to_active_storage_blobs.active_storage.rb b/db/migrate/20230328094807_add_service_name_to_active_storage_blobs.active_storage.rb new file mode 100644 index 000000000..f6d94331c --- /dev/null +++ b/db/migrate/20230328094807_add_service_name_to_active_storage_blobs.active_storage.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +# This migration comes from active_storage (originally 20190112182829) +class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0] + def up + return unless table_exists?(:active_storage_blobs) + + unless column_exists?(:active_storage_blobs, :service_name) + add_column :active_storage_blobs, :service_name, :string + + if configured_service = ActiveStorage::Blob.service.name + ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) + end + + change_column :active_storage_blobs, :service_name, :string, null: false + end + end + + def down + return unless table_exists?(:active_storage_blobs) + + remove_column :active_storage_blobs, :service_name + end +end diff --git a/db/migrate/20230328094808_create_active_storage_variant_records.active_storage.rb b/db/migrate/20230328094808_create_active_storage_variant_records.active_storage.rb new file mode 100644 index 000000000..ca0e86245 --- /dev/null +++ b/db/migrate/20230328094808_create_active_storage_variant_records.active_storage.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +# This migration comes from active_storage (originally 20191206030411) +class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0] + def change + return unless table_exists?(:active_storage_blobs) + + # Use Active Record's configured type for primary key + create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t| + t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type + t.string :variation_digest, null: false + + t.index %i[blob_id variation_digest], name: 'index_active_storage_variant_records_uniqueness', unique: true + t.foreign_key :active_storage_blobs, column: :blob_id + end + end + + private + + def primary_key_type + config = Rails.configuration.generators + config.options[config.orm][:primary_key_type] || :primary_key + end + + def blobs_primary_key_type + pkey_name = connection.primary_key(:active_storage_blobs) + pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name } + pkey_column.bigint? ? :bigint : pkey_column.type + end +end diff --git a/db/migrate/20230328094809_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb b/db/migrate/20230328094809_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb new file mode 100644 index 000000000..6f3182210 --- /dev/null +++ b/db/migrate/20230328094809_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +# This migration comes from active_storage (originally 20211119233751) +class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0] + def change + return unless table_exists?(:active_storage_blobs) + + change_column_null(:active_storage_blobs, :checksum, true) + end +end diff --git a/db/schema.rb b/db/schema.rb index 629437c52..f167f4316 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,15 +2,15 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_03_15_095054) do +ActiveRecord::Schema[6.1].define(version: 2023_03_15_095054) do # These are extensions that must be enabled in order to support this database enable_extension "fuzzystrmatch" diff --git a/db/seeds.rb b/db/seeds.rb index 12dbac770..93ef4ab10 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -141,7 +141,7 @@ if Training.count.zero? } ]) - TrainingsPricing.all.each do |p| + TrainingsPricing.find_each do |p| p.update(amount: ((rand * 50) + 5).floor * 100) end end @@ -222,7 +222,7 @@ if Machine.count.zero? } ]) - Price.all.each do |p| + Price.find_each do |p| p.update(amount: ((rand * 50) + 5).floor * 100) end end @@ -249,6 +249,9 @@ unless DatabaseProvider.count.positive? provider.providable = db_provider provider.status = 'active' provider.save + + require 'provider_config' + ProviderConfig.write_active_provider end end diff --git a/db/structure.sql b/db/structure.sql new file mode 100644 index 000000000..0f648a913 --- /dev/null +++ b/db/structure.sql @@ -0,0 +1,8698 @@ +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +-- +-- Name: public; Type: SCHEMA; Schema: -; Owner: - +-- + +-- *not* creating schema, since initdb creates it + + +-- +-- Name: fuzzystrmatch; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS fuzzystrmatch WITH SCHEMA public; + + +-- +-- Name: EXTENSION fuzzystrmatch; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION fuzzystrmatch IS 'determine similarities and distance between strings'; + + +-- +-- Name: pg_trgm; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA public; + + +-- +-- Name: EXTENSION pg_trgm; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION pg_trgm IS 'text similarity measurement and index searching based on trigrams'; + + +-- +-- Name: unaccent; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS unaccent WITH SCHEMA public; + + +-- +-- Name: EXTENSION unaccent; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION unaccent IS 'text search dictionary that removes accents'; + + +-- +-- Name: f_unaccent(text); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.f_unaccent(text) RETURNS text + LANGUAGE sql IMMUTABLE + AS $_$ + SELECT public.unaccent('public.unaccent', $1) + $_$; + + +-- +-- Name: fill_search_vector_for_project(); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.fill_search_vector_for_project() RETURNS trigger + LANGUAGE plpgsql + AS $$ + declare + step_title record; + step_description record; + + begin + select title into step_title from project_steps where project_id = new.id; + select string_agg(description, ' ') as content into step_description from project_steps where project_id = new.id; + + new.search_vector := + setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(new.name, ''))), 'A') || + setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(new.tags, ''))), 'B') || + setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(new.description, ''))), 'D') || + setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(step_title.title, ''))), 'C') || + setweight(to_tsvector('pg_catalog.french', unaccent(coalesce(step_description.content, ''))), 'D'); + + return new; + end + $$; + + +-- +-- Name: pg_search_dmetaphone(text); Type: FUNCTION; Schema: public; Owner: - +-- + +CREATE FUNCTION public.pg_search_dmetaphone(text) RETURNS text + LANGUAGE sql IMMUTABLE STRICT + AS $_$ + SELECT array_to_string(ARRAY(SELECT dmetaphone(unnest(regexp_split_to_array($1, E'\\s+')))), ' ') +$_$; + + +SET default_tablespace = ''; + +-- +-- Name: abuses; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.abuses ( + id integer NOT NULL, + signaled_id integer, + signaled_type character varying, + first_name character varying, + last_name character varying, + email character varying, + message text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: abuses_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.abuses_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: abuses_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.abuses_id_seq OWNED BY public.abuses.id; + + +-- +-- Name: accounting_lines; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.accounting_lines ( + id bigint NOT NULL, + line_type character varying, + journal_code character varying, + date timestamp without time zone, + account_code character varying, + account_label character varying, + analytical_code character varying, + invoice_id bigint, + invoicing_profile_id bigint, + debit integer, + credit integer, + currency character varying, + summary character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: accounting_lines_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.accounting_lines_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: accounting_lines_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.accounting_lines_id_seq OWNED BY public.accounting_lines.id; + + +-- +-- Name: accounting_periods; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.accounting_periods ( + id integer NOT NULL, + start_at date, + end_at date, + closed_at timestamp without time zone, + closed_by integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + period_total integer, + perpetual_total integer, + footprint character varying +); + + +-- +-- Name: accounting_periods_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.accounting_periods_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: accounting_periods_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.accounting_periods_id_seq OWNED BY public.accounting_periods.id; + + +-- +-- Name: addresses; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.addresses ( + id integer NOT NULL, + address character varying, + street_number character varying, + route character varying, + locality character varying, + country character varying, + postal_code character varying, + placeable_id integer, + placeable_type character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: addresses_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.addresses_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: addresses_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.addresses_id_seq OWNED BY public.addresses.id; + + +-- +-- Name: advanced_accountings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.advanced_accountings ( + id bigint NOT NULL, + code character varying, + analytical_section character varying, + accountable_type character varying, + accountable_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: advanced_accountings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.advanced_accountings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: advanced_accountings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.advanced_accountings_id_seq OWNED BY public.advanced_accountings.id; + + +-- +-- Name: age_ranges; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.age_ranges ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + slug character varying +); + + +-- +-- Name: age_ranges_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.age_ranges_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: age_ranges_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.age_ranges_id_seq OWNED BY public.age_ranges.id; + + +-- +-- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.ar_internal_metadata ( + key character varying NOT NULL, + value character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: assets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.assets ( + id integer NOT NULL, + viewable_id integer, + viewable_type character varying, + attachment character varying, + type character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + is_main boolean +); + + +-- +-- Name: assets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.assets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: assets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.assets_id_seq OWNED BY public.assets.id; + + +-- +-- Name: auth_provider_mappings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.auth_provider_mappings ( + id integer NOT NULL, + local_field character varying, + api_field character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + local_model character varying, + api_endpoint character varying, + api_data_type character varying, + transformation jsonb, + auth_provider_id bigint +); + + +-- +-- Name: auth_provider_mappings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.auth_provider_mappings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: auth_provider_mappings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.auth_provider_mappings_id_seq OWNED BY public.auth_provider_mappings.id; + + +-- +-- Name: auth_providers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.auth_providers ( + id integer NOT NULL, + name character varying, + status character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + providable_type character varying, + providable_id integer +); + + +-- +-- Name: auth_providers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.auth_providers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: auth_providers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.auth_providers_id_seq OWNED BY public.auth_providers.id; + + +-- +-- Name: availabilities; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.availabilities ( + id integer NOT NULL, + start_at timestamp without time zone, + end_at timestamp without time zone, + available_type character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + nb_total_places integer, + destroying boolean DEFAULT false, + lock boolean DEFAULT false, + is_recurrent boolean, + occurrence_id integer, + period character varying, + nb_periods integer, + end_date timestamp without time zone, + slot_duration integer +); + + +-- +-- Name: availabilities_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.availabilities_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: availabilities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.availabilities_id_seq OWNED BY public.availabilities.id; + + +-- +-- Name: availability_tags; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.availability_tags ( + id integer NOT NULL, + availability_id integer, + tag_id integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: availability_tags_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.availability_tags_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: availability_tags_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.availability_tags_id_seq OWNED BY public.availability_tags.id; + + +-- +-- Name: cart_item_coupons; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_coupons ( + id bigint NOT NULL, + coupon_id bigint, + customer_profile_id bigint, + operator_profile_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_coupons_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_coupons_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_coupons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_coupons_id_seq OWNED BY public.cart_item_coupons.id; + + +-- +-- Name: cart_item_event_reservation_tickets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_event_reservation_tickets ( + id bigint NOT NULL, + booked integer, + event_price_category_id bigint, + cart_item_event_reservation_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_event_reservation_tickets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_event_reservation_tickets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_event_reservation_tickets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_event_reservation_tickets_id_seq OWNED BY public.cart_item_event_reservation_tickets.id; + + +-- +-- Name: cart_item_event_reservations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_event_reservations ( + id bigint NOT NULL, + normal_tickets integer, + event_id bigint, + operator_profile_id bigint, + customer_profile_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_event_reservations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_event_reservations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_event_reservations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_event_reservations_id_seq OWNED BY public.cart_item_event_reservations.id; + + +-- +-- Name: cart_item_free_extensions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_free_extensions ( + id bigint NOT NULL, + subscription_id bigint, + new_expiration_date timestamp without time zone, + customer_profile_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_free_extensions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_free_extensions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_free_extensions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_free_extensions_id_seq OWNED BY public.cart_item_free_extensions.id; + + +-- +-- Name: cart_item_payment_schedules; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_payment_schedules ( + id bigint NOT NULL, + plan_id bigint, + coupon_id bigint, + requested boolean, + start_at timestamp without time zone, + customer_profile_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_payment_schedules_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_payment_schedules_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_payment_schedules_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_payment_schedules_id_seq OWNED BY public.cart_item_payment_schedules.id; + + +-- +-- Name: cart_item_prepaid_packs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_prepaid_packs ( + id bigint NOT NULL, + prepaid_pack_id bigint, + customer_profile_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_prepaid_packs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_prepaid_packs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_prepaid_packs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_prepaid_packs_id_seq OWNED BY public.cart_item_prepaid_packs.id; + + +-- +-- Name: cart_item_reservation_slots; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_reservation_slots ( + id bigint NOT NULL, + cart_item_type character varying, + cart_item_id bigint, + slot_id bigint, + slots_reservation_id bigint, + offered boolean DEFAULT false, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_reservation_slots_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_reservation_slots_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_reservation_slots_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_reservation_slots_id_seq OWNED BY public.cart_item_reservation_slots.id; + + +-- +-- Name: cart_item_reservations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_reservations ( + id bigint NOT NULL, + reservable_type character varying, + reservable_id bigint, + plan_id bigint, + new_subscription boolean, + customer_profile_id bigint, + operator_profile_id bigint, + type character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_reservations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_reservations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_reservations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_reservations_id_seq OWNED BY public.cart_item_reservations.id; + + +-- +-- Name: cart_item_subscriptions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.cart_item_subscriptions ( + id bigint NOT NULL, + plan_id bigint, + start_at timestamp without time zone, + customer_profile_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: cart_item_subscriptions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.cart_item_subscriptions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: cart_item_subscriptions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.cart_item_subscriptions_id_seq OWNED BY public.cart_item_subscriptions.id; + + +-- +-- Name: categories; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.categories ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + slug character varying +); + + +-- +-- Name: categories_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.categories_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.categories_id_seq OWNED BY public.categories.id; + + +-- +-- Name: chained_elements; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.chained_elements ( + id bigint NOT NULL, + element_type character varying NOT NULL, + element_id bigint NOT NULL, + previous_id integer, + content jsonb NOT NULL, + footprint character varying NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: chained_elements_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.chained_elements_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: chained_elements_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.chained_elements_id_seq OWNED BY public.chained_elements.id; + + +-- +-- Name: components; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.components ( + id integer NOT NULL, + name character varying NOT NULL +); + + +-- +-- Name: components_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.components_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: components_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.components_id_seq OWNED BY public.components.id; + + +-- +-- Name: coupons; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.coupons ( + id integer NOT NULL, + name character varying, + code character varying, + percent_off integer, + valid_until timestamp without time zone, + max_usages integer, + active boolean, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + validity_per_user character varying, + amount_off integer +); + + +-- +-- Name: coupons_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.coupons_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: coupons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.coupons_id_seq OWNED BY public.coupons.id; + + +-- +-- Name: credits; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.credits ( + id integer NOT NULL, + creditable_id integer, + creditable_type character varying, + plan_id integer, + hours integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: credits_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.credits_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: credits_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.credits_id_seq OWNED BY public.credits.id; + + +-- +-- Name: custom_assets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.custom_assets ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: custom_assets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.custom_assets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: custom_assets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.custom_assets_id_seq OWNED BY public.custom_assets.id; + + +-- +-- Name: database_providers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.database_providers ( + id integer NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: database_providers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.database_providers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: database_providers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.database_providers_id_seq OWNED BY public.database_providers.id; + + +-- +-- Name: event_price_categories; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.event_price_categories ( + id integer NOT NULL, + event_id integer, + price_category_id integer, + amount integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: event_price_categories_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.event_price_categories_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: event_price_categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.event_price_categories_id_seq OWNED BY public.event_price_categories.id; + + +-- +-- Name: event_themes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.event_themes ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + slug character varying +); + + +-- +-- Name: event_themes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.event_themes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: event_themes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.event_themes_id_seq OWNED BY public.event_themes.id; + + +-- +-- Name: events; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.events ( + id integer NOT NULL, + title character varying, + description text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + availability_id integer, + amount integer, + nb_total_places integer, + nb_free_places integer, + recurrence_id integer, + age_range_id integer, + category_id integer, + deleted_at timestamp without time zone +); + + +-- +-- Name: events_event_themes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.events_event_themes ( + id integer NOT NULL, + event_id integer, + event_theme_id integer +); + + +-- +-- Name: events_event_themes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.events_event_themes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: events_event_themes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.events_event_themes_id_seq OWNED BY public.events_event_themes.id; + + +-- +-- Name: events_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.events_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: events_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.events_id_seq OWNED BY public.events.id; + + +-- +-- Name: exports; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.exports ( + id integer NOT NULL, + category character varying, + export_type character varying, + query character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + user_id integer, + key character varying, + extension character varying DEFAULT 'xlsx'::character varying +); + + +-- +-- Name: exports_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.exports_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: exports_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.exports_id_seq OWNED BY public.exports.id; + + +-- +-- Name: friendly_id_slugs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.friendly_id_slugs ( + id integer NOT NULL, + slug character varying NOT NULL, + sluggable_id integer NOT NULL, + sluggable_type character varying(50), + scope character varying, + created_at timestamp without time zone +); + + +-- +-- Name: friendly_id_slugs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.friendly_id_slugs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: friendly_id_slugs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.friendly_id_slugs_id_seq OWNED BY public.friendly_id_slugs.id; + + +-- +-- Name: groups; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.groups ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + slug character varying, + disabled boolean +); + + +-- +-- Name: groups_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.groups_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: groups_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.groups_id_seq OWNED BY public.groups.id; + + +-- +-- Name: history_values; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.history_values ( + id integer NOT NULL, + setting_id integer, + value character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + invoicing_profile_id integer +); + + +-- +-- Name: history_values_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.history_values_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: history_values_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.history_values_id_seq OWNED BY public.history_values.id; + + +-- +-- Name: i_calendar_events; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.i_calendar_events ( + id integer NOT NULL, + uid character varying, + dtstart timestamp without time zone, + dtend timestamp without time zone, + summary character varying, + description character varying, + attendee character varying, + i_calendar_id integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: i_calendar_events_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.i_calendar_events_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: i_calendar_events_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.i_calendar_events_id_seq OWNED BY public.i_calendar_events.id; + + +-- +-- Name: i_calendars; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.i_calendars ( + id integer NOT NULL, + url character varying, + name character varying, + color character varying, + text_color character varying, + text_hidden boolean, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: i_calendars_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.i_calendars_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: i_calendars_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.i_calendars_id_seq OWNED BY public.i_calendars.id; + + +-- +-- Name: imports; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.imports ( + id integer NOT NULL, + user_id integer, + attachment character varying, + update_field character varying, + category character varying, + results text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: imports_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.imports_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: imports_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.imports_id_seq OWNED BY public.imports.id; + + +-- +-- Name: invoice_items; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.invoice_items ( + id integer NOT NULL, + invoice_id integer, + amount integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + description text, + invoice_item_id integer, + object_type character varying NOT NULL, + object_id bigint NOT NULL, + main boolean +); + + +-- +-- Name: invoice_items_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.invoice_items_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: invoice_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.invoice_items_id_seq OWNED BY public.invoice_items.id; + + +-- +-- Name: invoices; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.invoices ( + id integer NOT NULL, + total integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + reference character varying, + payment_method character varying, + avoir_date timestamp without time zone, + invoice_id integer, + type character varying, + subscription_to_expire boolean, + description text, + wallet_amount integer, + wallet_transaction_id integer, + coupon_id integer, + environment character varying, + invoicing_profile_id integer, + operator_profile_id integer, + statistic_profile_id integer, + order_number character varying +); + + +-- +-- Name: invoices_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.invoices_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: invoices_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.invoices_id_seq OWNED BY public.invoices.id; + + +-- +-- Name: invoicing_profiles; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.invoicing_profiles ( + id integer NOT NULL, + user_id integer, + first_name character varying, + last_name character varying, + email character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + external_id character varying +); + + +-- +-- Name: invoicing_profiles_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.invoicing_profiles_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: invoicing_profiles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.invoicing_profiles_id_seq OWNED BY public.invoicing_profiles.id; + + +-- +-- Name: licences; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.licences ( + id integer NOT NULL, + name character varying NOT NULL, + description text +); + + +-- +-- Name: licences_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.licences_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: licences_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.licences_id_seq OWNED BY public.licences.id; + + +-- +-- Name: machine_categories; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.machine_categories ( + id bigint NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: machine_categories_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.machine_categories_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: machine_categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.machine_categories_id_seq OWNED BY public.machine_categories.id; + + +-- +-- Name: machines; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.machines ( + id integer NOT NULL, + name character varying NOT NULL, + description text, + spec text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + slug character varying, + disabled boolean, + deleted_at timestamp without time zone, + machine_category_id bigint, + reservable boolean DEFAULT true +); + + +-- +-- Name: machines_availabilities; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.machines_availabilities ( + id integer NOT NULL, + machine_id integer, + availability_id integer +); + + +-- +-- Name: machines_availabilities_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.machines_availabilities_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: machines_availabilities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.machines_availabilities_id_seq OWNED BY public.machines_availabilities.id; + + +-- +-- Name: machines_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.machines_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: machines_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.machines_id_seq OWNED BY public.machines.id; + + +-- +-- Name: machines_products; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.machines_products ( + product_id bigint NOT NULL, + machine_id bigint NOT NULL +); + + +-- +-- Name: notification_preferences; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.notification_preferences ( + id bigint NOT NULL, + user_id bigint NOT NULL, + notification_type_id bigint NOT NULL, + in_system boolean DEFAULT true, + email boolean DEFAULT true, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: notification_preferences_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.notification_preferences_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: notification_preferences_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.notification_preferences_id_seq OWNED BY public.notification_preferences.id; + + +-- +-- Name: notification_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.notification_types ( + id bigint NOT NULL, + name character varying NOT NULL, + category character varying NOT NULL, + is_configurable boolean NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: notification_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.notification_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: notification_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.notification_types_id_seq OWNED BY public.notification_types.id; + + +-- +-- Name: notifications; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.notifications ( + id integer NOT NULL, + receiver_id integer, + attached_object_id integer, + attached_object_type character varying, + notification_type_id integer, + is_read boolean DEFAULT false, + created_at timestamp without time zone, + updated_at timestamp without time zone, + receiver_type character varying, + is_send boolean DEFAULT false, + meta_data jsonb DEFAULT '{}'::jsonb +); + + +-- +-- Name: notifications_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.notifications_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: notifications_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.notifications_id_seq OWNED BY public.notifications.id; + + +-- +-- Name: o_auth2_providers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.o_auth2_providers ( + id integer NOT NULL, + base_url character varying, + token_endpoint character varying, + authorization_endpoint character varying, + client_id character varying, + client_secret character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + profile_url character varying, + scopes character varying +); + + +-- +-- Name: o_auth2_providers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.o_auth2_providers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: o_auth2_providers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.o_auth2_providers_id_seq OWNED BY public.o_auth2_providers.id; + + +-- +-- Name: offer_days; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.offer_days ( + id integer NOT NULL, + subscription_id integer, + start_at timestamp without time zone, + end_at timestamp without time zone, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: offer_days_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.offer_days_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: offer_days_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.offer_days_id_seq OWNED BY public.offer_days.id; + + +-- +-- Name: open_api_clients; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.open_api_clients ( + id integer NOT NULL, + name character varying, + calls_count integer DEFAULT 0, + token character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: open_api_clients_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.open_api_clients_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: open_api_clients_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.open_api_clients_id_seq OWNED BY public.open_api_clients.id; + + +-- +-- Name: open_id_connect_providers; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.open_id_connect_providers ( + id bigint NOT NULL, + issuer character varying, + discovery boolean, + client_auth_method character varying, + scope character varying[], + response_type character varying, + response_mode character varying, + display character varying, + prompt character varying, + send_scope_to_token_endpoint boolean, + post_logout_redirect_uri character varying, + uid_field character varying, + client__identifier character varying, + client__secret character varying, + client__redirect_uri character varying, + client__scheme character varying, + client__host character varying, + client__port character varying, + client__authorization_endpoint character varying, + client__token_endpoint character varying, + client__userinfo_endpoint character varying, + client__jwks_uri character varying, + client__end_session_endpoint character varying, + profile_url character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: open_id_connect_providers_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.open_id_connect_providers_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: open_id_connect_providers_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.open_id_connect_providers_id_seq OWNED BY public.open_id_connect_providers.id; + + +-- +-- Name: order_activities; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.order_activities ( + id bigint NOT NULL, + order_id bigint, + operator_profile_id bigint, + activity_type character varying, + note text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: order_activities_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.order_activities_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: order_activities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.order_activities_id_seq OWNED BY public.order_activities.id; + + +-- +-- Name: order_items; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.order_items ( + id bigint NOT NULL, + order_id bigint, + orderable_type character varying, + orderable_id bigint, + amount integer, + quantity integer, + is_offered boolean, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: order_items_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.order_items_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: order_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.order_items_id_seq OWNED BY public.order_items.id; + + +-- +-- Name: orders; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.orders ( + id bigint NOT NULL, + statistic_profile_id bigint, + operator_profile_id integer, + token character varying, + reference character varying, + state character varying, + total integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + wallet_amount integer, + wallet_transaction_id integer, + payment_method character varying, + footprint character varying, + environment character varying, + coupon_id bigint, + paid_total integer, + invoice_id bigint +); + + +-- +-- Name: orders_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.orders_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: orders_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.orders_id_seq OWNED BY public.orders.id; + + +-- +-- Name: organizations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.organizations ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + invoicing_profile_id integer +); + + +-- +-- Name: organizations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.organizations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: organizations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.organizations_id_seq OWNED BY public.organizations.id; + + +-- +-- Name: payment_gateway_objects; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.payment_gateway_objects ( + id bigint NOT NULL, + gateway_object_id character varying, + gateway_object_type character varying, + item_type character varying, + item_id bigint, + payment_gateway_object_id bigint +); + + +-- +-- Name: payment_gateway_objects_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.payment_gateway_objects_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: payment_gateway_objects_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.payment_gateway_objects_id_seq OWNED BY public.payment_gateway_objects.id; + + +-- +-- Name: payment_schedule_items; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.payment_schedule_items ( + id bigint NOT NULL, + amount integer, + due_date timestamp without time zone, + state character varying DEFAULT 'new'::character varying, + details jsonb DEFAULT '"{}"'::jsonb, + payment_method character varying, + client_secret character varying, + payment_schedule_id bigint, + invoice_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: payment_schedule_items_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.payment_schedule_items_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: payment_schedule_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.payment_schedule_items_id_seq OWNED BY public.payment_schedule_items.id; + + +-- +-- Name: payment_schedule_objects; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.payment_schedule_objects ( + id bigint NOT NULL, + object_type character varying, + object_id bigint, + payment_schedule_id bigint, + main boolean, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: payment_schedule_objects_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.payment_schedule_objects_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: payment_schedule_objects_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.payment_schedule_objects_id_seq OWNED BY public.payment_schedule_objects.id; + + +-- +-- Name: payment_schedules; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.payment_schedules ( + id bigint NOT NULL, + total integer, + reference character varying, + payment_method character varying, + wallet_amount integer, + wallet_transaction_id bigint, + coupon_id bigint, + environment character varying, + invoicing_profile_id bigint, + statistic_profile_id bigint, + operator_profile_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + start_at timestamp without time zone, + order_number character varying +); + + +-- +-- Name: payment_schedules_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.payment_schedules_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: payment_schedules_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.payment_schedules_id_seq OWNED BY public.payment_schedules.id; + + +-- +-- Name: plan_categories; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.plan_categories ( + id bigint NOT NULL, + name character varying, + weight integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + description text +); + + +-- +-- Name: plan_categories_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.plan_categories_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: plan_categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.plan_categories_id_seq OWNED BY public.plan_categories.id; + + +-- +-- Name: plan_limitations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.plan_limitations ( + id bigint NOT NULL, + plan_id bigint NOT NULL, + limitable_type character varying NOT NULL, + limitable_id bigint NOT NULL, + "limit" integer DEFAULT 0 NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: plan_limitations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.plan_limitations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: plan_limitations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.plan_limitations_id_seq OWNED BY public.plan_limitations.id; + + +-- +-- Name: plans; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.plans ( + id integer NOT NULL, + name character varying, + amount integer, + "interval" character varying, + group_id integer, + stp_plan_id character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + training_credit_nb integer DEFAULT 0, + is_rolling boolean, + description text, + type character varying, + base_name character varying, + ui_weight integer DEFAULT 0, + interval_count integer DEFAULT 1, + slug character varying, + disabled boolean, + monthly_payment boolean, + plan_category_id bigint, + limiting boolean, + machines_visibility integer +); + + +-- +-- Name: plans_availabilities; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.plans_availabilities ( + id integer NOT NULL, + plan_id integer, + availability_id integer +); + + +-- +-- Name: plans_availabilities_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.plans_availabilities_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: plans_availabilities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.plans_availabilities_id_seq OWNED BY public.plans_availabilities.id; + + +-- +-- Name: plans_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.plans_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: plans_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.plans_id_seq OWNED BY public.plans.id; + + +-- +-- Name: prepaid_pack_reservations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.prepaid_pack_reservations ( + id bigint NOT NULL, + statistic_profile_prepaid_pack_id bigint, + reservation_id bigint, + consumed_minutes integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: prepaid_pack_reservations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.prepaid_pack_reservations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: prepaid_pack_reservations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.prepaid_pack_reservations_id_seq OWNED BY public.prepaid_pack_reservations.id; + + +-- +-- Name: prepaid_packs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.prepaid_packs ( + id bigint NOT NULL, + priceable_type character varying, + priceable_id bigint, + group_id bigint, + amount integer, + minutes integer, + validity_interval character varying, + validity_count integer, + disabled boolean, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: prepaid_packs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.prepaid_packs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: prepaid_packs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.prepaid_packs_id_seq OWNED BY public.prepaid_packs.id; + + +-- +-- Name: price_categories; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.price_categories ( + id integer NOT NULL, + name character varying, + conditions text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: price_categories_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.price_categories_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: price_categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.price_categories_id_seq OWNED BY public.price_categories.id; + + +-- +-- Name: prices; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.prices ( + id integer NOT NULL, + group_id integer, + plan_id integer, + priceable_id integer, + priceable_type character varying, + amount integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + duration integer DEFAULT 60 +); + + +-- +-- Name: prices_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.prices_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: prices_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.prices_id_seq OWNED BY public.prices.id; + + +-- +-- Name: product_categories; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.product_categories ( + id bigint NOT NULL, + name character varying, + slug character varying, + parent_id integer, + "position" integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: product_categories_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.product_categories_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: product_categories_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.product_categories_id_seq OWNED BY public.product_categories.id; + + +-- +-- Name: product_stock_movements; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.product_stock_movements ( + id bigint NOT NULL, + product_id bigint, + quantity integer, + reason character varying, + stock_type character varying, + remaining_stock integer, + date timestamp without time zone, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + order_item_id integer +); + + +-- +-- Name: product_stock_movements_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.product_stock_movements_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: product_stock_movements_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.product_stock_movements_id_seq OWNED BY public.product_stock_movements.id; + + +-- +-- Name: products; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.products ( + id bigint NOT NULL, + name character varying, + slug character varying, + sku character varying, + description text, + is_active boolean DEFAULT false, + product_category_id bigint, + amount integer, + quantity_min integer, + stock jsonb DEFAULT '{"external": 0, "internal": 0}'::jsonb, + low_stock_alert boolean DEFAULT false, + low_stock_threshold integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: products_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.products_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: products_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.products_id_seq OWNED BY public.products.id; + + +-- +-- Name: profile_custom_fields; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.profile_custom_fields ( + id bigint NOT NULL, + label character varying, + required boolean DEFAULT false, + actived boolean DEFAULT false, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: profile_custom_fields_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.profile_custom_fields_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: profile_custom_fields_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.profile_custom_fields_id_seq OWNED BY public.profile_custom_fields.id; + + +-- +-- Name: profiles; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.profiles ( + id integer NOT NULL, + user_id integer, + first_name character varying, + last_name character varying, + phone character varying, + interest text, + software_mastered text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + facebook character varying, + twitter character varying, + google_plus character varying, + viadeo character varying, + linkedin character varying, + instagram character varying, + youtube character varying, + vimeo character varying, + dailymotion character varying, + github character varying, + echosciences character varying, + website character varying, + pinterest character varying, + lastfm character varying, + flickr character varying, + job character varying, + tours character varying, + note text +); + + +-- +-- Name: profiles_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.profiles_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: profiles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.profiles_id_seq OWNED BY public.profiles.id; + + +-- +-- Name: project_steps; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.project_steps ( + id integer NOT NULL, + description text, + project_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + title character varying, + step_nb integer +); + + +-- +-- Name: project_steps_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.project_steps_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_steps_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.project_steps_id_seq OWNED BY public.project_steps.id; + + +-- +-- Name: project_users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.project_users ( + id integer NOT NULL, + project_id integer, + user_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + is_valid boolean DEFAULT false, + valid_token character varying +); + + +-- +-- Name: project_users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.project_users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: project_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.project_users_id_seq OWNED BY public.project_users.id; + + +-- +-- Name: projects; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.projects ( + id integer NOT NULL, + name character varying, + description text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + tags text, + licence_id integer, + state character varying, + slug character varying, + published_at timestamp without time zone, + author_statistic_profile_id integer, + search_vector tsvector, + status_id bigint +); + + +-- +-- Name: projects_components; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.projects_components ( + id integer NOT NULL, + project_id integer, + component_id integer +); + + +-- +-- Name: projects_components_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.projects_components_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_components_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.projects_components_id_seq OWNED BY public.projects_components.id; + + +-- +-- Name: projects_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.projects_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.projects_id_seq OWNED BY public.projects.id; + + +-- +-- Name: projects_machines; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.projects_machines ( + id integer NOT NULL, + project_id integer, + machine_id integer +); + + +-- +-- Name: projects_machines_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.projects_machines_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_machines_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.projects_machines_id_seq OWNED BY public.projects_machines.id; + + +-- +-- Name: projects_spaces; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.projects_spaces ( + id integer NOT NULL, + project_id integer, + space_id integer +); + + +-- +-- Name: projects_spaces_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.projects_spaces_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_spaces_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.projects_spaces_id_seq OWNED BY public.projects_spaces.id; + + +-- +-- Name: projects_themes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.projects_themes ( + id integer NOT NULL, + project_id integer, + theme_id integer +); + + +-- +-- Name: projects_themes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.projects_themes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: projects_themes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.projects_themes_id_seq OWNED BY public.projects_themes.id; + + +-- +-- Name: reservations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.reservations ( + id integer NOT NULL, + message text, + created_at timestamp without time zone, + updated_at timestamp without time zone, + reservable_id integer, + reservable_type character varying, + nb_reserve_places integer, + statistic_profile_id integer +); + + +-- +-- Name: reservations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.reservations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: reservations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.reservations_id_seq OWNED BY public.reservations.id; + + +-- +-- Name: roles; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.roles ( + id integer NOT NULL, + name character varying, + resource_id integer, + resource_type character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: roles_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.roles_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: roles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.roles_id_seq OWNED BY public.roles.id; + + +-- +-- Name: schema_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.schema_migrations ( + version character varying NOT NULL +); + + +-- +-- Name: settings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.settings ( + id integer NOT NULL, + name character varying NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: settings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.settings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: settings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.settings_id_seq OWNED BY public.settings.id; + + +-- +-- Name: slots; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.slots ( + id integer NOT NULL, + start_at timestamp without time zone, + end_at timestamp without time zone, + created_at timestamp without time zone, + updated_at timestamp without time zone, + availability_id integer NOT NULL, + places jsonb DEFAULT '[]'::jsonb NOT NULL +); + + +-- +-- Name: slots_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.slots_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: slots_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.slots_id_seq OWNED BY public.slots.id; + + +-- +-- Name: slots_reservations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.slots_reservations ( + id integer NOT NULL, + slot_id integer NOT NULL, + reservation_id integer NOT NULL, + ex_start_at timestamp without time zone, + ex_end_at timestamp without time zone, + canceled_at timestamp without time zone, + offered boolean DEFAULT false +); + + +-- +-- Name: slots_reservations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.slots_reservations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: slots_reservations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.slots_reservations_id_seq OWNED BY public.slots_reservations.id; + + +-- +-- Name: spaces; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.spaces ( + id integer NOT NULL, + name character varying, + default_places integer, + description text, + slug character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + characteristics text, + disabled boolean, + deleted_at timestamp without time zone +); + + +-- +-- Name: spaces_availabilities; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.spaces_availabilities ( + id integer NOT NULL, + space_id integer, + availability_id integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: spaces_availabilities_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.spaces_availabilities_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: spaces_availabilities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.spaces_availabilities_id_seq OWNED BY public.spaces_availabilities.id; + + +-- +-- Name: spaces_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.spaces_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: spaces_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.spaces_id_seq OWNED BY public.spaces.id; + + +-- +-- Name: statistic_custom_aggregations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_custom_aggregations ( + id integer NOT NULL, + query text, + statistic_type_id integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + field character varying, + es_index character varying, + es_type character varying +); + + +-- +-- Name: statistic_custom_aggregations_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_custom_aggregations_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_custom_aggregations_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_custom_aggregations_id_seq OWNED BY public.statistic_custom_aggregations.id; + + +-- +-- Name: statistic_fields; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_fields ( + id integer NOT NULL, + statistic_index_id integer, + key character varying, + label character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + data_type character varying +); + + +-- +-- Name: statistic_fields_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_fields_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_fields_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_fields_id_seq OWNED BY public.statistic_fields.id; + + +-- +-- Name: statistic_graphs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_graphs ( + id integer NOT NULL, + statistic_index_id integer, + chart_type character varying, + "limit" integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: statistic_graphs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_graphs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_graphs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_graphs_id_seq OWNED BY public.statistic_graphs.id; + + +-- +-- Name: statistic_indices; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_indices ( + id integer NOT NULL, + es_type_key character varying, + label character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + "table" boolean DEFAULT true, + ca boolean DEFAULT true +); + + +-- +-- Name: statistic_indices_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_indices_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_indices_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_indices_id_seq OWNED BY public.statistic_indices.id; + + +-- +-- Name: statistic_profile_prepaid_packs; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_profile_prepaid_packs ( + id bigint NOT NULL, + prepaid_pack_id bigint, + statistic_profile_id bigint, + minutes_used integer DEFAULT 0, + expires_at timestamp without time zone, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: statistic_profile_prepaid_packs_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_profile_prepaid_packs_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_profile_prepaid_packs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_profile_prepaid_packs_id_seq OWNED BY public.statistic_profile_prepaid_packs.id; + + +-- +-- Name: statistic_profile_trainings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_profile_trainings ( + id integer NOT NULL, + statistic_profile_id integer, + training_id integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: statistic_profile_trainings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_profile_trainings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_profile_trainings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_profile_trainings_id_seq OWNED BY public.statistic_profile_trainings.id; + + +-- +-- Name: statistic_profiles; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_profiles ( + id integer NOT NULL, + gender boolean, + birthday date, + group_id integer, + user_id integer, + role_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: statistic_profiles_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_profiles_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_profiles_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_profiles_id_seq OWNED BY public.statistic_profiles.id; + + +-- +-- Name: statistic_sub_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_sub_types ( + id integer NOT NULL, + key character varying, + label character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: statistic_sub_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_sub_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_sub_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_sub_types_id_seq OWNED BY public.statistic_sub_types.id; + + +-- +-- Name: statistic_type_sub_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_type_sub_types ( + id integer NOT NULL, + statistic_type_id integer, + statistic_sub_type_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: statistic_type_sub_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_type_sub_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_type_sub_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_type_sub_types_id_seq OWNED BY public.statistic_type_sub_types.id; + + +-- +-- Name: statistic_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statistic_types ( + id integer NOT NULL, + statistic_index_id integer, + key character varying, + label character varying, + graph boolean, + created_at timestamp without time zone, + updated_at timestamp without time zone, + simple boolean +); + + +-- +-- Name: statistic_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statistic_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statistic_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statistic_types_id_seq OWNED BY public.statistic_types.id; + + +-- +-- Name: statuses; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.statuses ( + id bigint NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: statuses_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.statuses_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: statuses_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.statuses_id_seq OWNED BY public.statuses.id; + + +-- +-- Name: stylesheets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.stylesheets ( + id integer NOT NULL, + contents text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + name character varying +); + + +-- +-- Name: stylesheets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.stylesheets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: stylesheets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.stylesheets_id_seq OWNED BY public.stylesheets.id; + + +-- +-- Name: subscriptions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.subscriptions ( + id integer NOT NULL, + plan_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + expiration_date timestamp without time zone, + canceled_at timestamp without time zone, + statistic_profile_id integer, + start_at timestamp without time zone +); + + +-- +-- Name: subscriptions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.subscriptions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: subscriptions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.subscriptions_id_seq OWNED BY public.subscriptions.id; + + +-- +-- Name: supporting_document_files; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.supporting_document_files ( + id bigint NOT NULL, + supporting_document_type_id bigint, + user_id bigint, + attachment character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: supporting_document_files_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.supporting_document_files_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: supporting_document_files_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.supporting_document_files_id_seq OWNED BY public.supporting_document_files.id; + + +-- +-- Name: supporting_document_refusals; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.supporting_document_refusals ( + id bigint NOT NULL, + user_id bigint, + operator_id integer, + message text, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: supporting_document_refusals_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.supporting_document_refusals_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: supporting_document_refusals_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.supporting_document_refusals_id_seq OWNED BY public.supporting_document_refusals.id; + + +-- +-- Name: supporting_document_refusals_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.supporting_document_refusals_types ( + supporting_document_type_id bigint NOT NULL, + supporting_document_refusal_id bigint NOT NULL +); + + +-- +-- Name: supporting_document_types; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.supporting_document_types ( + id bigint NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: supporting_document_types_groups; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.supporting_document_types_groups ( + id bigint NOT NULL, + supporting_document_type_id bigint, + group_id bigint, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: supporting_document_types_groups_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.supporting_document_types_groups_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: supporting_document_types_groups_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.supporting_document_types_groups_id_seq OWNED BY public.supporting_document_types_groups.id; + + +-- +-- Name: supporting_document_types_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.supporting_document_types_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: supporting_document_types_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.supporting_document_types_id_seq OWNED BY public.supporting_document_types.id; + + +-- +-- Name: tags; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.tags ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: tags_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.tags_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: tags_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.tags_id_seq OWNED BY public.tags.id; + + +-- +-- Name: themes; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.themes ( + id integer NOT NULL, + name character varying NOT NULL +); + + +-- +-- Name: themes_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.themes_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: themes_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.themes_id_seq OWNED BY public.themes.id; + + +-- +-- Name: tickets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.tickets ( + id integer NOT NULL, + reservation_id integer, + event_price_category_id integer, + booked integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: tickets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.tickets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: tickets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.tickets_id_seq OWNED BY public.tickets.id; + + +-- +-- Name: trainings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.trainings ( + id integer NOT NULL, + name character varying, + created_at timestamp without time zone, + updated_at timestamp without time zone, + nb_total_places integer, + slug character varying, + description text, + public_page boolean DEFAULT true, + disabled boolean, + auto_cancel boolean, + auto_cancel_threshold integer, + auto_cancel_deadline integer, + "authorization" boolean, + authorization_period integer, + invalidation boolean, + invalidation_period integer +); + + +-- +-- Name: trainings_availabilities; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.trainings_availabilities ( + id integer NOT NULL, + training_id integer, + availability_id integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: trainings_availabilities_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.trainings_availabilities_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: trainings_availabilities_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.trainings_availabilities_id_seq OWNED BY public.trainings_availabilities.id; + + +-- +-- Name: trainings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.trainings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: trainings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.trainings_id_seq OWNED BY public.trainings.id; + + +-- +-- Name: trainings_machines; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.trainings_machines ( + id integer NOT NULL, + training_id integer, + machine_id integer +); + + +-- +-- Name: trainings_machines_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.trainings_machines_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: trainings_machines_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.trainings_machines_id_seq OWNED BY public.trainings_machines.id; + + +-- +-- Name: trainings_pricings; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.trainings_pricings ( + id integer NOT NULL, + group_id integer, + amount integer, + created_at timestamp without time zone, + updated_at timestamp without time zone, + training_id integer +); + + +-- +-- Name: trainings_pricings_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.trainings_pricings_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: trainings_pricings_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.trainings_pricings_id_seq OWNED BY public.trainings_pricings.id; + + +-- +-- Name: user_profile_custom_fields; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.user_profile_custom_fields ( + id bigint NOT NULL, + invoicing_profile_id bigint, + profile_custom_field_id bigint, + value character varying, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: user_profile_custom_fields_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.user_profile_custom_fields_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: user_profile_custom_fields_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.user_profile_custom_fields_id_seq OWNED BY public.user_profile_custom_fields.id; + + +-- +-- Name: user_tags; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.user_tags ( + id integer NOT NULL, + user_id integer, + tag_id integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: user_tags_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.user_tags_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: user_tags_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.user_tags_id_seq OWNED BY public.user_tags.id; + + +-- +-- Name: users; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.users ( + id integer NOT NULL, + email character varying DEFAULT ''::character varying NOT NULL, + encrypted_password character varying DEFAULT ''::character varying NOT NULL, + reset_password_token character varying, + reset_password_sent_at timestamp without time zone, + remember_created_at timestamp without time zone, + sign_in_count integer DEFAULT 0 NOT NULL, + current_sign_in_at timestamp without time zone, + last_sign_in_at timestamp without time zone, + confirmation_token character varying, + confirmed_at timestamp without time zone, + confirmation_sent_at timestamp without time zone, + unconfirmed_email character varying, + failed_attempts integer DEFAULT 0 NOT NULL, + unlock_token character varying, + locked_at timestamp without time zone, + created_at timestamp without time zone, + updated_at timestamp without time zone, + is_allow_contact boolean DEFAULT true, + group_id integer, + username character varying, + slug character varying, + is_active boolean DEFAULT true, + provider character varying, + uid character varying, + auth_token character varying, + merged_at timestamp without time zone, + is_allow_newsletter boolean, + current_sign_in_ip inet, + last_sign_in_ip inet, + mapped_from_sso character varying, + validated_at timestamp without time zone +); + + +-- +-- Name: users_credits; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.users_credits ( + id integer NOT NULL, + user_id integer, + credit_id integer, + hours_used integer, + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: users_credits_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.users_credits_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: users_credits_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.users_credits_id_seq OWNED BY public.users_credits.id; + + +-- +-- Name: users_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.users_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; + + +-- +-- Name: users_roles; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.users_roles ( + user_id integer, + role_id integer +); + + +-- +-- Name: wallet_transactions; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.wallet_transactions ( + id integer NOT NULL, + wallet_id integer, + transaction_type character varying, + amount integer, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + invoicing_profile_id integer +); + + +-- +-- Name: wallet_transactions_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.wallet_transactions_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: wallet_transactions_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.wallet_transactions_id_seq OWNED BY public.wallet_transactions.id; + + +-- +-- Name: wallets; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.wallets ( + id integer NOT NULL, + amount integer DEFAULT 0, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL, + invoicing_profile_id integer +); + + +-- +-- Name: wallets_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.wallets_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: wallets_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.wallets_id_seq OWNED BY public.wallets.id; + + +-- +-- Name: abuses id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.abuses ALTER COLUMN id SET DEFAULT nextval('public.abuses_id_seq'::regclass); + + +-- +-- Name: accounting_lines id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.accounting_lines ALTER COLUMN id SET DEFAULT nextval('public.accounting_lines_id_seq'::regclass); + + +-- +-- Name: accounting_periods id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.accounting_periods ALTER COLUMN id SET DEFAULT nextval('public.accounting_periods_id_seq'::regclass); + + +-- +-- Name: addresses id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.addresses ALTER COLUMN id SET DEFAULT nextval('public.addresses_id_seq'::regclass); + + +-- +-- Name: advanced_accountings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.advanced_accountings ALTER COLUMN id SET DEFAULT nextval('public.advanced_accountings_id_seq'::regclass); + + +-- +-- Name: age_ranges id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.age_ranges ALTER COLUMN id SET DEFAULT nextval('public.age_ranges_id_seq'::regclass); + + +-- +-- Name: assets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.assets ALTER COLUMN id SET DEFAULT nextval('public.assets_id_seq'::regclass); + + +-- +-- Name: auth_provider_mappings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.auth_provider_mappings ALTER COLUMN id SET DEFAULT nextval('public.auth_provider_mappings_id_seq'::regclass); + + +-- +-- Name: auth_providers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.auth_providers ALTER COLUMN id SET DEFAULT nextval('public.auth_providers_id_seq'::regclass); + + +-- +-- Name: availabilities id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.availabilities ALTER COLUMN id SET DEFAULT nextval('public.availabilities_id_seq'::regclass); + + +-- +-- Name: availability_tags id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.availability_tags ALTER COLUMN id SET DEFAULT nextval('public.availability_tags_id_seq'::regclass); + + +-- +-- Name: cart_item_coupons id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_coupons ALTER COLUMN id SET DEFAULT nextval('public.cart_item_coupons_id_seq'::regclass); + + +-- +-- Name: cart_item_event_reservation_tickets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservation_tickets ALTER COLUMN id SET DEFAULT nextval('public.cart_item_event_reservation_tickets_id_seq'::regclass); + + +-- +-- Name: cart_item_event_reservations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservations ALTER COLUMN id SET DEFAULT nextval('public.cart_item_event_reservations_id_seq'::regclass); + + +-- +-- Name: cart_item_free_extensions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_free_extensions ALTER COLUMN id SET DEFAULT nextval('public.cart_item_free_extensions_id_seq'::regclass); + + +-- +-- Name: cart_item_payment_schedules id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_payment_schedules ALTER COLUMN id SET DEFAULT nextval('public.cart_item_payment_schedules_id_seq'::regclass); + + +-- +-- Name: cart_item_prepaid_packs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_prepaid_packs ALTER COLUMN id SET DEFAULT nextval('public.cart_item_prepaid_packs_id_seq'::regclass); + + +-- +-- Name: cart_item_reservation_slots id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservation_slots ALTER COLUMN id SET DEFAULT nextval('public.cart_item_reservation_slots_id_seq'::regclass); + + +-- +-- Name: cart_item_reservations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservations ALTER COLUMN id SET DEFAULT nextval('public.cart_item_reservations_id_seq'::regclass); + + +-- +-- Name: cart_item_subscriptions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_subscriptions ALTER COLUMN id SET DEFAULT nextval('public.cart_item_subscriptions_id_seq'::regclass); + + +-- +-- Name: categories id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.categories ALTER COLUMN id SET DEFAULT nextval('public.categories_id_seq'::regclass); + + +-- +-- Name: chained_elements id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.chained_elements ALTER COLUMN id SET DEFAULT nextval('public.chained_elements_id_seq'::regclass); + + +-- +-- Name: components id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.components ALTER COLUMN id SET DEFAULT nextval('public.components_id_seq'::regclass); + + +-- +-- Name: coupons id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.coupons ALTER COLUMN id SET DEFAULT nextval('public.coupons_id_seq'::regclass); + + +-- +-- Name: credits id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.credits ALTER COLUMN id SET DEFAULT nextval('public.credits_id_seq'::regclass); + + +-- +-- Name: custom_assets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.custom_assets ALTER COLUMN id SET DEFAULT nextval('public.custom_assets_id_seq'::regclass); + + +-- +-- Name: database_providers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.database_providers ALTER COLUMN id SET DEFAULT nextval('public.database_providers_id_seq'::regclass); + + +-- +-- Name: event_price_categories id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_price_categories ALTER COLUMN id SET DEFAULT nextval('public.event_price_categories_id_seq'::regclass); + + +-- +-- Name: event_themes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_themes ALTER COLUMN id SET DEFAULT nextval('public.event_themes_id_seq'::regclass); + + +-- +-- Name: events id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.events ALTER COLUMN id SET DEFAULT nextval('public.events_id_seq'::regclass); + + +-- +-- Name: events_event_themes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.events_event_themes ALTER COLUMN id SET DEFAULT nextval('public.events_event_themes_id_seq'::regclass); + + +-- +-- Name: exports id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.exports ALTER COLUMN id SET DEFAULT nextval('public.exports_id_seq'::regclass); + + +-- +-- Name: friendly_id_slugs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.friendly_id_slugs ALTER COLUMN id SET DEFAULT nextval('public.friendly_id_slugs_id_seq'::regclass); + + +-- +-- Name: groups id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.groups ALTER COLUMN id SET DEFAULT nextval('public.groups_id_seq'::regclass); + + +-- +-- Name: history_values id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.history_values ALTER COLUMN id SET DEFAULT nextval('public.history_values_id_seq'::regclass); + + +-- +-- Name: i_calendar_events id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.i_calendar_events ALTER COLUMN id SET DEFAULT nextval('public.i_calendar_events_id_seq'::regclass); + + +-- +-- Name: i_calendars id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.i_calendars ALTER COLUMN id SET DEFAULT nextval('public.i_calendars_id_seq'::regclass); + + +-- +-- Name: imports id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.imports ALTER COLUMN id SET DEFAULT nextval('public.imports_id_seq'::regclass); + + +-- +-- Name: invoice_items id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoice_items ALTER COLUMN id SET DEFAULT nextval('public.invoice_items_id_seq'::regclass); + + +-- +-- Name: invoices id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoices ALTER COLUMN id SET DEFAULT nextval('public.invoices_id_seq'::regclass); + + +-- +-- Name: invoicing_profiles id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoicing_profiles ALTER COLUMN id SET DEFAULT nextval('public.invoicing_profiles_id_seq'::regclass); + + +-- +-- Name: licences id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.licences ALTER COLUMN id SET DEFAULT nextval('public.licences_id_seq'::regclass); + + +-- +-- Name: machine_categories id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.machine_categories ALTER COLUMN id SET DEFAULT nextval('public.machine_categories_id_seq'::regclass); + + +-- +-- Name: machines id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.machines ALTER COLUMN id SET DEFAULT nextval('public.machines_id_seq'::regclass); + + +-- +-- Name: machines_availabilities id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.machines_availabilities ALTER COLUMN id SET DEFAULT nextval('public.machines_availabilities_id_seq'::regclass); + + +-- +-- Name: notification_preferences id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notification_preferences ALTER COLUMN id SET DEFAULT nextval('public.notification_preferences_id_seq'::regclass); + + +-- +-- Name: notification_types id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notification_types ALTER COLUMN id SET DEFAULT nextval('public.notification_types_id_seq'::regclass); + + +-- +-- Name: notifications id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notifications ALTER COLUMN id SET DEFAULT nextval('public.notifications_id_seq'::regclass); + + +-- +-- Name: o_auth2_providers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.o_auth2_providers ALTER COLUMN id SET DEFAULT nextval('public.o_auth2_providers_id_seq'::regclass); + + +-- +-- Name: offer_days id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.offer_days ALTER COLUMN id SET DEFAULT nextval('public.offer_days_id_seq'::regclass); + + +-- +-- Name: open_api_clients id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.open_api_clients ALTER COLUMN id SET DEFAULT nextval('public.open_api_clients_id_seq'::regclass); + + +-- +-- Name: open_id_connect_providers id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.open_id_connect_providers ALTER COLUMN id SET DEFAULT nextval('public.open_id_connect_providers_id_seq'::regclass); + + +-- +-- Name: order_activities id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.order_activities ALTER COLUMN id SET DEFAULT nextval('public.order_activities_id_seq'::regclass); + + +-- +-- Name: order_items id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.order_items ALTER COLUMN id SET DEFAULT nextval('public.order_items_id_seq'::regclass); + + +-- +-- Name: orders id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.orders ALTER COLUMN id SET DEFAULT nextval('public.orders_id_seq'::regclass); + + +-- +-- Name: organizations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.organizations ALTER COLUMN id SET DEFAULT nextval('public.organizations_id_seq'::regclass); + + +-- +-- Name: payment_gateway_objects id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_gateway_objects ALTER COLUMN id SET DEFAULT nextval('public.payment_gateway_objects_id_seq'::regclass); + + +-- +-- Name: payment_schedule_items id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedule_items ALTER COLUMN id SET DEFAULT nextval('public.payment_schedule_items_id_seq'::regclass); + + +-- +-- Name: payment_schedule_objects id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedule_objects ALTER COLUMN id SET DEFAULT nextval('public.payment_schedule_objects_id_seq'::regclass); + + +-- +-- Name: payment_schedules id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedules ALTER COLUMN id SET DEFAULT nextval('public.payment_schedules_id_seq'::regclass); + + +-- +-- Name: plan_categories id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plan_categories ALTER COLUMN id SET DEFAULT nextval('public.plan_categories_id_seq'::regclass); + + +-- +-- Name: plan_limitations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plan_limitations ALTER COLUMN id SET DEFAULT nextval('public.plan_limitations_id_seq'::regclass); + + +-- +-- Name: plans id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plans ALTER COLUMN id SET DEFAULT nextval('public.plans_id_seq'::regclass); + + +-- +-- Name: plans_availabilities id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plans_availabilities ALTER COLUMN id SET DEFAULT nextval('public.plans_availabilities_id_seq'::regclass); + + +-- +-- Name: prepaid_pack_reservations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prepaid_pack_reservations ALTER COLUMN id SET DEFAULT nextval('public.prepaid_pack_reservations_id_seq'::regclass); + + +-- +-- Name: prepaid_packs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prepaid_packs ALTER COLUMN id SET DEFAULT nextval('public.prepaid_packs_id_seq'::regclass); + + +-- +-- Name: price_categories id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.price_categories ALTER COLUMN id SET DEFAULT nextval('public.price_categories_id_seq'::regclass); + + +-- +-- Name: prices id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prices ALTER COLUMN id SET DEFAULT nextval('public.prices_id_seq'::regclass); + + +-- +-- Name: product_categories id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.product_categories ALTER COLUMN id SET DEFAULT nextval('public.product_categories_id_seq'::regclass); + + +-- +-- Name: product_stock_movements id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.product_stock_movements ALTER COLUMN id SET DEFAULT nextval('public.product_stock_movements_id_seq'::regclass); + + +-- +-- Name: products id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.products ALTER COLUMN id SET DEFAULT nextval('public.products_id_seq'::regclass); + + +-- +-- Name: profile_custom_fields id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.profile_custom_fields ALTER COLUMN id SET DEFAULT nextval('public.profile_custom_fields_id_seq'::regclass); + + +-- +-- Name: profiles id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.profiles ALTER COLUMN id SET DEFAULT nextval('public.profiles_id_seq'::regclass); + + +-- +-- Name: project_steps id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_steps ALTER COLUMN id SET DEFAULT nextval('public.project_steps_id_seq'::regclass); + + +-- +-- Name: project_users id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_users ALTER COLUMN id SET DEFAULT nextval('public.project_users_id_seq'::regclass); + + +-- +-- Name: projects id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects ALTER COLUMN id SET DEFAULT nextval('public.projects_id_seq'::regclass); + + +-- +-- Name: projects_components id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_components ALTER COLUMN id SET DEFAULT nextval('public.projects_components_id_seq'::regclass); + + +-- +-- Name: projects_machines id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_machines ALTER COLUMN id SET DEFAULT nextval('public.projects_machines_id_seq'::regclass); + + +-- +-- Name: projects_spaces id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_spaces ALTER COLUMN id SET DEFAULT nextval('public.projects_spaces_id_seq'::regclass); + + +-- +-- Name: projects_themes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_themes ALTER COLUMN id SET DEFAULT nextval('public.projects_themes_id_seq'::regclass); + + +-- +-- Name: reservations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.reservations ALTER COLUMN id SET DEFAULT nextval('public.reservations_id_seq'::regclass); + + +-- +-- Name: roles id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.roles ALTER COLUMN id SET DEFAULT nextval('public.roles_id_seq'::regclass); + + +-- +-- Name: settings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.settings ALTER COLUMN id SET DEFAULT nextval('public.settings_id_seq'::regclass); + + +-- +-- Name: slots id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.slots ALTER COLUMN id SET DEFAULT nextval('public.slots_id_seq'::regclass); + + +-- +-- Name: slots_reservations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.slots_reservations ALTER COLUMN id SET DEFAULT nextval('public.slots_reservations_id_seq'::regclass); + + +-- +-- Name: spaces id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.spaces ALTER COLUMN id SET DEFAULT nextval('public.spaces_id_seq'::regclass); + + +-- +-- Name: spaces_availabilities id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.spaces_availabilities ALTER COLUMN id SET DEFAULT nextval('public.spaces_availabilities_id_seq'::regclass); + + +-- +-- Name: statistic_custom_aggregations id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_custom_aggregations ALTER COLUMN id SET DEFAULT nextval('public.statistic_custom_aggregations_id_seq'::regclass); + + +-- +-- Name: statistic_fields id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_fields ALTER COLUMN id SET DEFAULT nextval('public.statistic_fields_id_seq'::regclass); + + +-- +-- Name: statistic_graphs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_graphs ALTER COLUMN id SET DEFAULT nextval('public.statistic_graphs_id_seq'::regclass); + + +-- +-- Name: statistic_indices id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_indices ALTER COLUMN id SET DEFAULT nextval('public.statistic_indices_id_seq'::regclass); + + +-- +-- Name: statistic_profile_prepaid_packs id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_prepaid_packs ALTER COLUMN id SET DEFAULT nextval('public.statistic_profile_prepaid_packs_id_seq'::regclass); + + +-- +-- Name: statistic_profile_trainings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_trainings ALTER COLUMN id SET DEFAULT nextval('public.statistic_profile_trainings_id_seq'::regclass); + + +-- +-- Name: statistic_profiles id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profiles ALTER COLUMN id SET DEFAULT nextval('public.statistic_profiles_id_seq'::regclass); + + +-- +-- Name: statistic_sub_types id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_sub_types ALTER COLUMN id SET DEFAULT nextval('public.statistic_sub_types_id_seq'::regclass); + + +-- +-- Name: statistic_type_sub_types id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_type_sub_types ALTER COLUMN id SET DEFAULT nextval('public.statistic_type_sub_types_id_seq'::regclass); + + +-- +-- Name: statistic_types id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_types ALTER COLUMN id SET DEFAULT nextval('public.statistic_types_id_seq'::regclass); + + +-- +-- Name: statuses id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statuses ALTER COLUMN id SET DEFAULT nextval('public.statuses_id_seq'::regclass); + + +-- +-- Name: stylesheets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.stylesheets ALTER COLUMN id SET DEFAULT nextval('public.stylesheets_id_seq'::regclass); + + +-- +-- Name: subscriptions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.subscriptions ALTER COLUMN id SET DEFAULT nextval('public.subscriptions_id_seq'::regclass); + + +-- +-- Name: supporting_document_files id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_files ALTER COLUMN id SET DEFAULT nextval('public.supporting_document_files_id_seq'::regclass); + + +-- +-- Name: supporting_document_refusals id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_refusals ALTER COLUMN id SET DEFAULT nextval('public.supporting_document_refusals_id_seq'::regclass); + + +-- +-- Name: supporting_document_types id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_types ALTER COLUMN id SET DEFAULT nextval('public.supporting_document_types_id_seq'::regclass); + + +-- +-- Name: supporting_document_types_groups id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_types_groups ALTER COLUMN id SET DEFAULT nextval('public.supporting_document_types_groups_id_seq'::regclass); + + +-- +-- Name: tags id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.tags ALTER COLUMN id SET DEFAULT nextval('public.tags_id_seq'::regclass); + + +-- +-- Name: themes id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.themes ALTER COLUMN id SET DEFAULT nextval('public.themes_id_seq'::regclass); + + +-- +-- Name: tickets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.tickets ALTER COLUMN id SET DEFAULT nextval('public.tickets_id_seq'::regclass); + + +-- +-- Name: trainings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings ALTER COLUMN id SET DEFAULT nextval('public.trainings_id_seq'::regclass); + + +-- +-- Name: trainings_availabilities id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings_availabilities ALTER COLUMN id SET DEFAULT nextval('public.trainings_availabilities_id_seq'::regclass); + + +-- +-- Name: trainings_machines id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings_machines ALTER COLUMN id SET DEFAULT nextval('public.trainings_machines_id_seq'::regclass); + + +-- +-- Name: trainings_pricings id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings_pricings ALTER COLUMN id SET DEFAULT nextval('public.trainings_pricings_id_seq'::regclass); + + +-- +-- Name: user_profile_custom_fields id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_profile_custom_fields ALTER COLUMN id SET DEFAULT nextval('public.user_profile_custom_fields_id_seq'::regclass); + + +-- +-- Name: user_tags id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_tags ALTER COLUMN id SET DEFAULT nextval('public.user_tags_id_seq'::regclass); + + +-- +-- Name: users id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); + + +-- +-- Name: users_credits id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.users_credits ALTER COLUMN id SET DEFAULT nextval('public.users_credits_id_seq'::regclass); + + +-- +-- Name: wallet_transactions id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.wallet_transactions ALTER COLUMN id SET DEFAULT nextval('public.wallet_transactions_id_seq'::regclass); + + +-- +-- Name: wallets id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.wallets ALTER COLUMN id SET DEFAULT nextval('public.wallets_id_seq'::regclass); + + +-- +-- Name: abuses abuses_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.abuses + ADD CONSTRAINT abuses_pkey PRIMARY KEY (id); + + +-- +-- Name: accounting_lines accounting_lines_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.accounting_lines + ADD CONSTRAINT accounting_lines_pkey PRIMARY KEY (id); + + +-- +-- Name: accounting_periods accounting_periods_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.accounting_periods + ADD CONSTRAINT accounting_periods_pkey PRIMARY KEY (id); + + +-- +-- Name: addresses addresses_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.addresses + ADD CONSTRAINT addresses_pkey PRIMARY KEY (id); + + +-- +-- Name: advanced_accountings advanced_accountings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.advanced_accountings + ADD CONSTRAINT advanced_accountings_pkey PRIMARY KEY (id); + + +-- +-- Name: age_ranges age_ranges_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.age_ranges + ADD CONSTRAINT age_ranges_pkey PRIMARY KEY (id); + + +-- +-- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.ar_internal_metadata + ADD CONSTRAINT ar_internal_metadata_pkey PRIMARY KEY (key); + + +-- +-- Name: assets assets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.assets + ADD CONSTRAINT assets_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_provider_mappings auth_provider_mappings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.auth_provider_mappings + ADD CONSTRAINT auth_provider_mappings_pkey PRIMARY KEY (id); + + +-- +-- Name: auth_providers auth_providers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.auth_providers + ADD CONSTRAINT auth_providers_pkey PRIMARY KEY (id); + + +-- +-- Name: availabilities availabilities_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.availabilities + ADD CONSTRAINT availabilities_pkey PRIMARY KEY (id); + + +-- +-- Name: availability_tags availability_tags_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.availability_tags + ADD CONSTRAINT availability_tags_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_coupons cart_item_coupons_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_coupons + ADD CONSTRAINT cart_item_coupons_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_event_reservation_tickets cart_item_event_reservation_tickets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservation_tickets + ADD CONSTRAINT cart_item_event_reservation_tickets_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_event_reservations cart_item_event_reservations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservations + ADD CONSTRAINT cart_item_event_reservations_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_free_extensions cart_item_free_extensions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_free_extensions + ADD CONSTRAINT cart_item_free_extensions_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_payment_schedules cart_item_payment_schedules_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_payment_schedules + ADD CONSTRAINT cart_item_payment_schedules_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_prepaid_packs cart_item_prepaid_packs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_prepaid_packs + ADD CONSTRAINT cart_item_prepaid_packs_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_reservation_slots cart_item_reservation_slots_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservation_slots + ADD CONSTRAINT cart_item_reservation_slots_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_reservations cart_item_reservations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservations + ADD CONSTRAINT cart_item_reservations_pkey PRIMARY KEY (id); + + +-- +-- Name: cart_item_subscriptions cart_item_subscriptions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_subscriptions + ADD CONSTRAINT cart_item_subscriptions_pkey PRIMARY KEY (id); + + +-- +-- Name: categories categories_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.categories + ADD CONSTRAINT categories_pkey PRIMARY KEY (id); + + +-- +-- Name: chained_elements chained_elements_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.chained_elements + ADD CONSTRAINT chained_elements_pkey PRIMARY KEY (id); + + +-- +-- Name: components components_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.components + ADD CONSTRAINT components_pkey PRIMARY KEY (id); + + +-- +-- Name: coupons coupons_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.coupons + ADD CONSTRAINT coupons_pkey PRIMARY KEY (id); + + +-- +-- Name: credits credits_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.credits + ADD CONSTRAINT credits_pkey PRIMARY KEY (id); + + +-- +-- Name: custom_assets custom_assets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.custom_assets + ADD CONSTRAINT custom_assets_pkey PRIMARY KEY (id); + + +-- +-- Name: database_providers database_providers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.database_providers + ADD CONSTRAINT database_providers_pkey PRIMARY KEY (id); + + +-- +-- Name: event_price_categories event_price_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_price_categories + ADD CONSTRAINT event_price_categories_pkey PRIMARY KEY (id); + + +-- +-- Name: event_themes event_themes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_themes + ADD CONSTRAINT event_themes_pkey PRIMARY KEY (id); + + +-- +-- Name: events_event_themes events_event_themes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.events_event_themes + ADD CONSTRAINT events_event_themes_pkey PRIMARY KEY (id); + + +-- +-- Name: events events_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.events + ADD CONSTRAINT events_pkey PRIMARY KEY (id); + + +-- +-- Name: exports exports_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.exports + ADD CONSTRAINT exports_pkey PRIMARY KEY (id); + + +-- +-- Name: friendly_id_slugs friendly_id_slugs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.friendly_id_slugs + ADD CONSTRAINT friendly_id_slugs_pkey PRIMARY KEY (id); + + +-- +-- Name: groups groups_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.groups + ADD CONSTRAINT groups_pkey PRIMARY KEY (id); + + +-- +-- Name: history_values history_values_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.history_values + ADD CONSTRAINT history_values_pkey PRIMARY KEY (id); + + +-- +-- Name: i_calendar_events i_calendar_events_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.i_calendar_events + ADD CONSTRAINT i_calendar_events_pkey PRIMARY KEY (id); + + +-- +-- Name: i_calendars i_calendars_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.i_calendars + ADD CONSTRAINT i_calendars_pkey PRIMARY KEY (id); + + +-- +-- Name: imports imports_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.imports + ADD CONSTRAINT imports_pkey PRIMARY KEY (id); + + +-- +-- Name: invoice_items invoice_items_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoice_items + ADD CONSTRAINT invoice_items_pkey PRIMARY KEY (id); + + +-- +-- Name: invoices invoices_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoices + ADD CONSTRAINT invoices_pkey PRIMARY KEY (id); + + +-- +-- Name: invoicing_profiles invoicing_profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoicing_profiles + ADD CONSTRAINT invoicing_profiles_pkey PRIMARY KEY (id); + + +-- +-- Name: licences licences_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.licences + ADD CONSTRAINT licences_pkey PRIMARY KEY (id); + + +-- +-- Name: machine_categories machine_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.machine_categories + ADD CONSTRAINT machine_categories_pkey PRIMARY KEY (id); + + +-- +-- Name: machines_availabilities machines_availabilities_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.machines_availabilities + ADD CONSTRAINT machines_availabilities_pkey PRIMARY KEY (id); + + +-- +-- Name: machines machines_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.machines + ADD CONSTRAINT machines_pkey PRIMARY KEY (id); + + +-- +-- Name: notification_preferences notification_preferences_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notification_preferences + ADD CONSTRAINT notification_preferences_pkey PRIMARY KEY (id); + + +-- +-- Name: notification_types notification_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notification_types + ADD CONSTRAINT notification_types_pkey PRIMARY KEY (id); + + +-- +-- Name: notifications notifications_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notifications + ADD CONSTRAINT notifications_pkey PRIMARY KEY (id); + + +-- +-- Name: o_auth2_providers o_auth2_providers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.o_auth2_providers + ADD CONSTRAINT o_auth2_providers_pkey PRIMARY KEY (id); + + +-- +-- Name: offer_days offer_days_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.offer_days + ADD CONSTRAINT offer_days_pkey PRIMARY KEY (id); + + +-- +-- Name: open_api_clients open_api_clients_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.open_api_clients + ADD CONSTRAINT open_api_clients_pkey PRIMARY KEY (id); + + +-- +-- Name: open_id_connect_providers open_id_connect_providers_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.open_id_connect_providers + ADD CONSTRAINT open_id_connect_providers_pkey PRIMARY KEY (id); + + +-- +-- Name: order_activities order_activities_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.order_activities + ADD CONSTRAINT order_activities_pkey PRIMARY KEY (id); + + +-- +-- Name: order_items order_items_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.order_items + ADD CONSTRAINT order_items_pkey PRIMARY KEY (id); + + +-- +-- Name: orders orders_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.orders + ADD CONSTRAINT orders_pkey PRIMARY KEY (id); + + +-- +-- Name: organizations organizations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.organizations + ADD CONSTRAINT organizations_pkey PRIMARY KEY (id); + + +-- +-- Name: payment_gateway_objects payment_gateway_objects_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_gateway_objects + ADD CONSTRAINT payment_gateway_objects_pkey PRIMARY KEY (id); + + +-- +-- Name: payment_schedule_items payment_schedule_items_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedule_items + ADD CONSTRAINT payment_schedule_items_pkey PRIMARY KEY (id); + + +-- +-- Name: payment_schedule_objects payment_schedule_objects_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedule_objects + ADD CONSTRAINT payment_schedule_objects_pkey PRIMARY KEY (id); + + +-- +-- Name: payment_schedules payment_schedules_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedules + ADD CONSTRAINT payment_schedules_pkey PRIMARY KEY (id); + + +-- +-- Name: plan_categories plan_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plan_categories + ADD CONSTRAINT plan_categories_pkey PRIMARY KEY (id); + + +-- +-- Name: plan_limitations plan_limitations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plan_limitations + ADD CONSTRAINT plan_limitations_pkey PRIMARY KEY (id); + + +-- +-- Name: plans_availabilities plans_availabilities_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plans_availabilities + ADD CONSTRAINT plans_availabilities_pkey PRIMARY KEY (id); + + +-- +-- Name: plans plans_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plans + ADD CONSTRAINT plans_pkey PRIMARY KEY (id); + + +-- +-- Name: prepaid_pack_reservations prepaid_pack_reservations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prepaid_pack_reservations + ADD CONSTRAINT prepaid_pack_reservations_pkey PRIMARY KEY (id); + + +-- +-- Name: prepaid_packs prepaid_packs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prepaid_packs + ADD CONSTRAINT prepaid_packs_pkey PRIMARY KEY (id); + + +-- +-- Name: price_categories price_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.price_categories + ADD CONSTRAINT price_categories_pkey PRIMARY KEY (id); + + +-- +-- Name: prices prices_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prices + ADD CONSTRAINT prices_pkey PRIMARY KEY (id); + + +-- +-- Name: product_categories product_categories_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.product_categories + ADD CONSTRAINT product_categories_pkey PRIMARY KEY (id); + + +-- +-- Name: product_stock_movements product_stock_movements_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.product_stock_movements + ADD CONSTRAINT product_stock_movements_pkey PRIMARY KEY (id); + + +-- +-- Name: products products_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.products + ADD CONSTRAINT products_pkey PRIMARY KEY (id); + + +-- +-- Name: profile_custom_fields profile_custom_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.profile_custom_fields + ADD CONSTRAINT profile_custom_fields_pkey PRIMARY KEY (id); + + +-- +-- Name: profiles profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.profiles + ADD CONSTRAINT profiles_pkey PRIMARY KEY (id); + + +-- +-- Name: project_steps project_steps_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_steps + ADD CONSTRAINT project_steps_pkey PRIMARY KEY (id); + + +-- +-- Name: project_users project_users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_users + ADD CONSTRAINT project_users_pkey PRIMARY KEY (id); + + +-- +-- Name: projects_components projects_components_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_components + ADD CONSTRAINT projects_components_pkey PRIMARY KEY (id); + + +-- +-- Name: projects_machines projects_machines_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_machines + ADD CONSTRAINT projects_machines_pkey PRIMARY KEY (id); + + +-- +-- Name: projects projects_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects + ADD CONSTRAINT projects_pkey PRIMARY KEY (id); + + +-- +-- Name: projects_spaces projects_spaces_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_spaces + ADD CONSTRAINT projects_spaces_pkey PRIMARY KEY (id); + + +-- +-- Name: projects_themes projects_themes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_themes + ADD CONSTRAINT projects_themes_pkey PRIMARY KEY (id); + + +-- +-- Name: reservations reservations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.reservations + ADD CONSTRAINT reservations_pkey PRIMARY KEY (id); + + +-- +-- Name: roles roles_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.roles + ADD CONSTRAINT roles_pkey PRIMARY KEY (id); + + +-- +-- Name: settings settings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.settings + ADD CONSTRAINT settings_pkey PRIMARY KEY (id); + + +-- +-- Name: slots slots_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.slots + ADD CONSTRAINT slots_pkey PRIMARY KEY (id); + + +-- +-- Name: slots_reservations slots_reservations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.slots_reservations + ADD CONSTRAINT slots_reservations_pkey PRIMARY KEY (id); + + +-- +-- Name: spaces_availabilities spaces_availabilities_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.spaces_availabilities + ADD CONSTRAINT spaces_availabilities_pkey PRIMARY KEY (id); + + +-- +-- Name: spaces spaces_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.spaces + ADD CONSTRAINT spaces_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_custom_aggregations statistic_custom_aggregations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_custom_aggregations + ADD CONSTRAINT statistic_custom_aggregations_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_fields statistic_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_fields + ADD CONSTRAINT statistic_fields_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_graphs statistic_graphs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_graphs + ADD CONSTRAINT statistic_graphs_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_indices statistic_indices_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_indices + ADD CONSTRAINT statistic_indices_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_profile_prepaid_packs statistic_profile_prepaid_packs_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_prepaid_packs + ADD CONSTRAINT statistic_profile_prepaid_packs_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_profile_trainings statistic_profile_trainings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_trainings + ADD CONSTRAINT statistic_profile_trainings_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_profiles statistic_profiles_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profiles + ADD CONSTRAINT statistic_profiles_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_sub_types statistic_sub_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_sub_types + ADD CONSTRAINT statistic_sub_types_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_type_sub_types statistic_type_sub_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_type_sub_types + ADD CONSTRAINT statistic_type_sub_types_pkey PRIMARY KEY (id); + + +-- +-- Name: statistic_types statistic_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_types + ADD CONSTRAINT statistic_types_pkey PRIMARY KEY (id); + + +-- +-- Name: statuses statuses_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statuses + ADD CONSTRAINT statuses_pkey PRIMARY KEY (id); + + +-- +-- Name: stylesheets stylesheets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.stylesheets + ADD CONSTRAINT stylesheets_pkey PRIMARY KEY (id); + + +-- +-- Name: subscriptions subscriptions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.subscriptions + ADD CONSTRAINT subscriptions_pkey PRIMARY KEY (id); + + +-- +-- Name: supporting_document_files supporting_document_files_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_files + ADD CONSTRAINT supporting_document_files_pkey PRIMARY KEY (id); + + +-- +-- Name: supporting_document_refusals supporting_document_refusals_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_refusals + ADD CONSTRAINT supporting_document_refusals_pkey PRIMARY KEY (id); + + +-- +-- Name: supporting_document_types_groups supporting_document_types_groups_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_types_groups + ADD CONSTRAINT supporting_document_types_groups_pkey PRIMARY KEY (id); + + +-- +-- Name: supporting_document_types supporting_document_types_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_types + ADD CONSTRAINT supporting_document_types_pkey PRIMARY KEY (id); + + +-- +-- Name: tags tags_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.tags + ADD CONSTRAINT tags_pkey PRIMARY KEY (id); + + +-- +-- Name: themes themes_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.themes + ADD CONSTRAINT themes_pkey PRIMARY KEY (id); + + +-- +-- Name: tickets tickets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.tickets + ADD CONSTRAINT tickets_pkey PRIMARY KEY (id); + + +-- +-- Name: trainings_availabilities trainings_availabilities_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings_availabilities + ADD CONSTRAINT trainings_availabilities_pkey PRIMARY KEY (id); + + +-- +-- Name: trainings_machines trainings_machines_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings_machines + ADD CONSTRAINT trainings_machines_pkey PRIMARY KEY (id); + + +-- +-- Name: trainings trainings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings + ADD CONSTRAINT trainings_pkey PRIMARY KEY (id); + + +-- +-- Name: trainings_pricings trainings_pricings_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.trainings_pricings + ADD CONSTRAINT trainings_pricings_pkey PRIMARY KEY (id); + + +-- +-- Name: user_profile_custom_fields user_profile_custom_fields_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_profile_custom_fields + ADD CONSTRAINT user_profile_custom_fields_pkey PRIMARY KEY (id); + + +-- +-- Name: user_tags user_tags_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_tags + ADD CONSTRAINT user_tags_pkey PRIMARY KEY (id); + + +-- +-- Name: users_credits users_credits_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.users_credits + ADD CONSTRAINT users_credits_pkey PRIMARY KEY (id); + + +-- +-- Name: users users_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.users + ADD CONSTRAINT users_pkey PRIMARY KEY (id); + + +-- +-- Name: wallet_transactions wallet_transactions_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.wallet_transactions + ADD CONSTRAINT wallet_transactions_pkey PRIMARY KEY (id); + + +-- +-- Name: wallets wallets_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.wallets + ADD CONSTRAINT wallets_pkey PRIMARY KEY (id); + + +-- +-- Name: index_abuses_on_signaled_type_and_signaled_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_abuses_on_signaled_type_and_signaled_id ON public.abuses USING btree (signaled_type, signaled_id); + + +-- +-- Name: index_accounting_lines_on_invoice_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_accounting_lines_on_invoice_id ON public.accounting_lines USING btree (invoice_id); + + +-- +-- Name: index_accounting_lines_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_accounting_lines_on_invoicing_profile_id ON public.accounting_lines USING btree (invoicing_profile_id); + + +-- +-- Name: index_advanced_accountings_on_accountable; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_advanced_accountings_on_accountable ON public.advanced_accountings USING btree (accountable_type, accountable_id); + + +-- +-- Name: index_age_ranges_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_age_ranges_on_slug ON public.age_ranges USING btree (slug); + + +-- +-- Name: index_auth_provider_mappings_on_auth_provider_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_auth_provider_mappings_on_auth_provider_id ON public.auth_provider_mappings USING btree (auth_provider_id); + + +-- +-- Name: index_auth_providers_on_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_auth_providers_on_name ON public.auth_providers USING btree (name); + + +-- +-- Name: index_availability_tags_on_availability_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_availability_tags_on_availability_id ON public.availability_tags USING btree (availability_id); + + +-- +-- Name: index_availability_tags_on_tag_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_availability_tags_on_tag_id ON public.availability_tags USING btree (tag_id); + + +-- +-- Name: index_cart_item_coupons_on_coupon_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_coupons_on_coupon_id ON public.cart_item_coupons USING btree (coupon_id); + + +-- +-- Name: index_cart_item_coupons_on_customer_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_coupons_on_customer_profile_id ON public.cart_item_coupons USING btree (customer_profile_id); + + +-- +-- Name: index_cart_item_coupons_on_operator_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_coupons_on_operator_profile_id ON public.cart_item_coupons USING btree (operator_profile_id); + + +-- +-- Name: index_cart_item_event_reservations_on_customer_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_event_reservations_on_customer_profile_id ON public.cart_item_event_reservations USING btree (customer_profile_id); + + +-- +-- Name: index_cart_item_event_reservations_on_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_event_reservations_on_event_id ON public.cart_item_event_reservations USING btree (event_id); + + +-- +-- Name: index_cart_item_event_reservations_on_operator_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_event_reservations_on_operator_profile_id ON public.cart_item_event_reservations USING btree (operator_profile_id); + + +-- +-- Name: index_cart_item_free_extensions_on_customer_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_free_extensions_on_customer_profile_id ON public.cart_item_free_extensions USING btree (customer_profile_id); + + +-- +-- Name: index_cart_item_free_extensions_on_subscription_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_free_extensions_on_subscription_id ON public.cart_item_free_extensions USING btree (subscription_id); + + +-- +-- Name: index_cart_item_payment_schedules_on_coupon_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_payment_schedules_on_coupon_id ON public.cart_item_payment_schedules USING btree (coupon_id); + + +-- +-- Name: index_cart_item_payment_schedules_on_customer_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_payment_schedules_on_customer_profile_id ON public.cart_item_payment_schedules USING btree (customer_profile_id); + + +-- +-- Name: index_cart_item_payment_schedules_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_payment_schedules_on_plan_id ON public.cart_item_payment_schedules USING btree (plan_id); + + +-- +-- Name: index_cart_item_prepaid_packs_on_customer_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_prepaid_packs_on_customer_profile_id ON public.cart_item_prepaid_packs USING btree (customer_profile_id); + + +-- +-- Name: index_cart_item_prepaid_packs_on_prepaid_pack_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_prepaid_packs_on_prepaid_pack_id ON public.cart_item_prepaid_packs USING btree (prepaid_pack_id); + + +-- +-- Name: index_cart_item_reservation_slots_on_slot_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_reservation_slots_on_slot_id ON public.cart_item_reservation_slots USING btree (slot_id); + + +-- +-- Name: index_cart_item_reservation_slots_on_slots_reservation_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_reservation_slots_on_slots_reservation_id ON public.cart_item_reservation_slots USING btree (slots_reservation_id); + + +-- +-- Name: index_cart_item_reservations_on_customer_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_reservations_on_customer_profile_id ON public.cart_item_reservations USING btree (customer_profile_id); + + +-- +-- Name: index_cart_item_reservations_on_operator_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_reservations_on_operator_profile_id ON public.cart_item_reservations USING btree (operator_profile_id); + + +-- +-- Name: index_cart_item_reservations_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_reservations_on_plan_id ON public.cart_item_reservations USING btree (plan_id); + + +-- +-- Name: index_cart_item_reservations_on_reservable; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_reservations_on_reservable ON public.cart_item_reservations USING btree (reservable_type, reservable_id); + + +-- +-- Name: index_cart_item_slots_on_cart_item; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_slots_on_cart_item ON public.cart_item_reservation_slots USING btree (cart_item_type, cart_item_id); + + +-- +-- Name: index_cart_item_subscriptions_on_customer_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_subscriptions_on_customer_profile_id ON public.cart_item_subscriptions USING btree (customer_profile_id); + + +-- +-- Name: index_cart_item_subscriptions_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_subscriptions_on_plan_id ON public.cart_item_subscriptions USING btree (plan_id); + + +-- +-- Name: index_cart_item_tickets_on_cart_item_event_reservation; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_tickets_on_cart_item_event_reservation ON public.cart_item_event_reservation_tickets USING btree (cart_item_event_reservation_id); + + +-- +-- Name: index_cart_item_tickets_on_event_price_category; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_cart_item_tickets_on_event_price_category ON public.cart_item_event_reservation_tickets USING btree (event_price_category_id); + + +-- +-- Name: index_categories_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_categories_on_slug ON public.categories USING btree (slug); + + +-- +-- Name: index_chained_elements_on_element; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_chained_elements_on_element ON public.chained_elements USING btree (element_type, element_id); + + +-- +-- Name: index_coupons_on_code; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_coupons_on_code ON public.coupons USING btree (code); + + +-- +-- Name: index_credits_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_credits_on_plan_id ON public.credits USING btree (plan_id); + + +-- +-- Name: index_credits_on_plan_id_and_creditable_id_and_creditable_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_credits_on_plan_id_and_creditable_id_and_creditable_type ON public.credits USING btree (plan_id, creditable_id, creditable_type); + + +-- +-- Name: index_event_price_categories_on_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_price_categories_on_event_id ON public.event_price_categories USING btree (event_id); + + +-- +-- Name: index_event_price_categories_on_price_category_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_price_categories_on_price_category_id ON public.event_price_categories USING btree (price_category_id); + + +-- +-- Name: index_event_themes_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_event_themes_on_slug ON public.event_themes USING btree (slug); + + +-- +-- Name: index_events_event_themes_on_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_events_event_themes_on_event_id ON public.events_event_themes USING btree (event_id); + + +-- +-- Name: index_events_event_themes_on_event_theme_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_events_event_themes_on_event_theme_id ON public.events_event_themes USING btree (event_theme_id); + + +-- +-- Name: index_events_on_availability_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_events_on_availability_id ON public.events USING btree (availability_id); + + +-- +-- Name: index_events_on_category_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_events_on_category_id ON public.events USING btree (category_id); + + +-- +-- Name: index_events_on_deleted_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_events_on_deleted_at ON public.events USING btree (deleted_at); + + +-- +-- Name: index_events_on_recurrence_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_events_on_recurrence_id ON public.events USING btree (recurrence_id); + + +-- +-- Name: index_exports_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_exports_on_user_id ON public.exports USING btree (user_id); + + +-- +-- Name: index_friendly_id_slugs_on_slug_and_sluggable_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_friendly_id_slugs_on_slug_and_sluggable_type ON public.friendly_id_slugs USING btree (slug, sluggable_type); + + +-- +-- Name: index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_friendly_id_slugs_on_slug_and_sluggable_type_and_scope ON public.friendly_id_slugs USING btree (slug, sluggable_type, scope); + + +-- +-- Name: index_friendly_id_slugs_on_sluggable_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_friendly_id_slugs_on_sluggable_id ON public.friendly_id_slugs USING btree (sluggable_id); + + +-- +-- Name: index_friendly_id_slugs_on_sluggable_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_friendly_id_slugs_on_sluggable_type ON public.friendly_id_slugs USING btree (sluggable_type); + + +-- +-- Name: index_groups_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_groups_on_slug ON public.groups USING btree (slug); + + +-- +-- Name: index_history_values_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_history_values_on_invoicing_profile_id ON public.history_values USING btree (invoicing_profile_id); + + +-- +-- Name: index_history_values_on_setting_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_history_values_on_setting_id ON public.history_values USING btree (setting_id); + + +-- +-- Name: index_i_calendar_events_on_i_calendar_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_i_calendar_events_on_i_calendar_id ON public.i_calendar_events USING btree (i_calendar_id); + + +-- +-- Name: index_invoice_items_on_invoice_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoice_items_on_invoice_id ON public.invoice_items USING btree (invoice_id); + + +-- +-- Name: index_invoice_items_on_object_type_and_object_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoice_items_on_object_type_and_object_id ON public.invoice_items USING btree (object_type, object_id); + + +-- +-- Name: index_invoices_on_coupon_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoices_on_coupon_id ON public.invoices USING btree (coupon_id); + + +-- +-- Name: index_invoices_on_invoice_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoices_on_invoice_id ON public.invoices USING btree (invoice_id); + + +-- +-- Name: index_invoices_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoices_on_invoicing_profile_id ON public.invoices USING btree (invoicing_profile_id); + + +-- +-- Name: index_invoices_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoices_on_statistic_profile_id ON public.invoices USING btree (statistic_profile_id); + + +-- +-- Name: index_invoices_on_wallet_transaction_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoices_on_wallet_transaction_id ON public.invoices USING btree (wallet_transaction_id); + + +-- +-- Name: index_invoicing_profiles_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_invoicing_profiles_on_user_id ON public.invoicing_profiles USING btree (user_id); + + +-- +-- Name: index_machines_availabilities_on_availability_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_machines_availabilities_on_availability_id ON public.machines_availabilities USING btree (availability_id); + + +-- +-- Name: index_machines_availabilities_on_machine_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_machines_availabilities_on_machine_id ON public.machines_availabilities USING btree (machine_id); + + +-- +-- Name: index_machines_on_deleted_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_machines_on_deleted_at ON public.machines USING btree (deleted_at); + + +-- +-- Name: index_machines_on_machine_category_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_machines_on_machine_category_id ON public.machines USING btree (machine_category_id); + + +-- +-- Name: index_machines_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_machines_on_slug ON public.machines USING btree (slug); + + +-- +-- Name: index_notification_preferences_on_notification_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_notification_preferences_on_notification_type_id ON public.notification_preferences USING btree (notification_type_id); + + +-- +-- Name: index_notification_preferences_on_user_and_notification_type; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_notification_preferences_on_user_and_notification_type ON public.notification_preferences USING btree (user_id, notification_type_id); + + +-- +-- Name: index_notification_types_on_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_notification_types_on_name ON public.notification_types USING btree (name); + + +-- +-- Name: index_notifications_on_notification_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_notifications_on_notification_type_id ON public.notifications USING btree (notification_type_id); + + +-- +-- Name: index_notifications_on_receiver_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_notifications_on_receiver_id ON public.notifications USING btree (receiver_id); + + +-- +-- Name: index_offer_days_on_subscription_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_offer_days_on_subscription_id ON public.offer_days USING btree (subscription_id); + + +-- +-- Name: index_order_activities_on_operator_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_order_activities_on_operator_profile_id ON public.order_activities USING btree (operator_profile_id); + + +-- +-- Name: index_order_activities_on_order_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_order_activities_on_order_id ON public.order_activities USING btree (order_id); + + +-- +-- Name: index_order_items_on_order_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_order_items_on_order_id ON public.order_items USING btree (order_id); + + +-- +-- Name: index_order_items_on_orderable_type_and_orderable_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_order_items_on_orderable_type_and_orderable_id ON public.order_items USING btree (orderable_type, orderable_id); + + +-- +-- Name: index_orders_on_coupon_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_orders_on_coupon_id ON public.orders USING btree (coupon_id); + + +-- +-- Name: index_orders_on_invoice_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_orders_on_invoice_id ON public.orders USING btree (invoice_id); + + +-- +-- Name: index_orders_on_operator_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_orders_on_operator_profile_id ON public.orders USING btree (operator_profile_id); + + +-- +-- Name: index_orders_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_orders_on_statistic_profile_id ON public.orders USING btree (statistic_profile_id); + + +-- +-- Name: index_organizations_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_organizations_on_invoicing_profile_id ON public.organizations USING btree (invoicing_profile_id); + + +-- +-- Name: index_p_o_i_t_groups_on_group_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_p_o_i_t_groups_on_group_id ON public.supporting_document_types_groups USING btree (group_id); + + +-- +-- Name: index_p_o_i_t_groups_on_proof_of_identity_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_p_o_i_t_groups_on_proof_of_identity_type_id ON public.supporting_document_types_groups USING btree (supporting_document_type_id); + + +-- +-- Name: index_payment_gateway_objects_on_item_type_and_item_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_gateway_objects_on_item_type_and_item_id ON public.payment_gateway_objects USING btree (item_type, item_id); + + +-- +-- Name: index_payment_gateway_objects_on_payment_gateway_object_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_gateway_objects_on_payment_gateway_object_id ON public.payment_gateway_objects USING btree (payment_gateway_object_id); + + +-- +-- Name: index_payment_schedule_items_on_invoice_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedule_items_on_invoice_id ON public.payment_schedule_items USING btree (invoice_id); + + +-- +-- Name: index_payment_schedule_items_on_payment_schedule_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedule_items_on_payment_schedule_id ON public.payment_schedule_items USING btree (payment_schedule_id); + + +-- +-- Name: index_payment_schedule_objects_on_object_type_and_object_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedule_objects_on_object_type_and_object_id ON public.payment_schedule_objects USING btree (object_type, object_id); + + +-- +-- Name: index_payment_schedule_objects_on_payment_schedule_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedule_objects_on_payment_schedule_id ON public.payment_schedule_objects USING btree (payment_schedule_id); + + +-- +-- Name: index_payment_schedules_on_coupon_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedules_on_coupon_id ON public.payment_schedules USING btree (coupon_id); + + +-- +-- Name: index_payment_schedules_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedules_on_invoicing_profile_id ON public.payment_schedules USING btree (invoicing_profile_id); + + +-- +-- Name: index_payment_schedules_on_operator_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedules_on_operator_profile_id ON public.payment_schedules USING btree (operator_profile_id); + + +-- +-- Name: index_payment_schedules_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedules_on_statistic_profile_id ON public.payment_schedules USING btree (statistic_profile_id); + + +-- +-- Name: index_payment_schedules_on_wallet_transaction_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_payment_schedules_on_wallet_transaction_id ON public.payment_schedules USING btree (wallet_transaction_id); + + +-- +-- Name: index_plan_limitations_on_limitable_type_and_limitable_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_plan_limitations_on_limitable_type_and_limitable_id ON public.plan_limitations USING btree (limitable_type, limitable_id); + + +-- +-- Name: index_plan_limitations_on_plan_and_limitable; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_plan_limitations_on_plan_and_limitable ON public.plan_limitations USING btree (plan_id, limitable_id, limitable_type); + + +-- +-- Name: index_plan_limitations_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_plan_limitations_on_plan_id ON public.plan_limitations USING btree (plan_id); + + +-- +-- Name: index_plans_availabilities_on_availability_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_plans_availabilities_on_availability_id ON public.plans_availabilities USING btree (availability_id); + + +-- +-- Name: index_plans_availabilities_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_plans_availabilities_on_plan_id ON public.plans_availabilities USING btree (plan_id); + + +-- +-- Name: index_plans_on_group_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_plans_on_group_id ON public.plans USING btree (group_id); + + +-- +-- Name: index_plans_on_plan_category_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_plans_on_plan_category_id ON public.plans USING btree (plan_category_id); + + +-- +-- Name: index_prepaid_pack_reservations_on_reservation_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_prepaid_pack_reservations_on_reservation_id ON public.prepaid_pack_reservations USING btree (reservation_id); + + +-- +-- Name: index_prepaid_pack_reservations_on_sp_prepaid_pack_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_prepaid_pack_reservations_on_sp_prepaid_pack_id ON public.prepaid_pack_reservations USING btree (statistic_profile_prepaid_pack_id); + + +-- +-- Name: index_prepaid_packs_on_group_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_prepaid_packs_on_group_id ON public.prepaid_packs USING btree (group_id); + + +-- +-- Name: index_prepaid_packs_on_priceable_type_and_priceable_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_prepaid_packs_on_priceable_type_and_priceable_id ON public.prepaid_packs USING btree (priceable_type, priceable_id); + + +-- +-- Name: index_price_categories_on_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_price_categories_on_name ON public.price_categories USING btree (name); + + +-- +-- Name: index_prices_on_group_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_prices_on_group_id ON public.prices USING btree (group_id); + + +-- +-- Name: index_prices_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_prices_on_plan_id ON public.prices USING btree (plan_id); + + +-- +-- Name: index_prices_on_plan_priceable_group_and_duration; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_prices_on_plan_priceable_group_and_duration ON public.prices USING btree (plan_id, priceable_id, priceable_type, group_id, duration); + + +-- +-- Name: index_prices_on_priceable_type_and_priceable_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_prices_on_priceable_type_and_priceable_id ON public.prices USING btree (priceable_type, priceable_id); + + +-- +-- Name: index_product_categories_on_parent_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_product_categories_on_parent_id ON public.product_categories USING btree (parent_id); + + +-- +-- Name: index_product_categories_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_product_categories_on_slug ON public.product_categories USING btree (slug); + + +-- +-- Name: index_product_stock_movements_on_product_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_product_stock_movements_on_product_id ON public.product_stock_movements USING btree (product_id); + + +-- +-- Name: index_products_on_product_category_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_products_on_product_category_id ON public.products USING btree (product_category_id); + + +-- +-- Name: index_products_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_products_on_slug ON public.products USING btree (slug); + + +-- +-- Name: index_profiles_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_profiles_on_user_id ON public.profiles USING btree (user_id); + + +-- +-- Name: index_project_steps_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_project_steps_on_project_id ON public.project_steps USING btree (project_id); + + +-- +-- Name: index_project_users_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_project_users_on_project_id ON public.project_users USING btree (project_id); + + +-- +-- Name: index_project_users_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_project_users_on_user_id ON public.project_users USING btree (user_id); + + +-- +-- Name: index_projects_components_on_component_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_components_on_component_id ON public.projects_components USING btree (component_id); + + +-- +-- Name: index_projects_components_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_components_on_project_id ON public.projects_components USING btree (project_id); + + +-- +-- Name: index_projects_machines_on_machine_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_machines_on_machine_id ON public.projects_machines USING btree (machine_id); + + +-- +-- Name: index_projects_machines_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_machines_on_project_id ON public.projects_machines USING btree (project_id); + + +-- +-- Name: index_projects_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_projects_on_slug ON public.projects USING btree (slug); + + +-- +-- Name: index_projects_on_status_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_on_status_id ON public.projects USING btree (status_id); + + +-- +-- Name: index_projects_spaces_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_spaces_on_project_id ON public.projects_spaces USING btree (project_id); + + +-- +-- Name: index_projects_spaces_on_space_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_spaces_on_space_id ON public.projects_spaces USING btree (space_id); + + +-- +-- Name: index_projects_themes_on_project_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_themes_on_project_id ON public.projects_themes USING btree (project_id); + + +-- +-- Name: index_projects_themes_on_theme_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_projects_themes_on_theme_id ON public.projects_themes USING btree (theme_id); + + +-- +-- Name: index_reservations_on_reservable_type_and_reservable_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_reservations_on_reservable_type_and_reservable_id ON public.reservations USING btree (reservable_type, reservable_id); + + +-- +-- Name: index_reservations_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_reservations_on_statistic_profile_id ON public.reservations USING btree (statistic_profile_id); + + +-- +-- Name: index_roles_on_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_roles_on_name ON public.roles USING btree (name); + + +-- +-- Name: index_roles_on_name_and_resource_type_and_resource_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_roles_on_name_and_resource_type_and_resource_id ON public.roles USING btree (name, resource_type, resource_id); + + +-- +-- Name: index_settings_on_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_settings_on_name ON public.settings USING btree (name); + + +-- +-- Name: index_slots_on_availability_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_slots_on_availability_id ON public.slots USING btree (availability_id); + + +-- +-- Name: index_slots_on_places; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_slots_on_places ON public.slots USING gin (places); + + +-- +-- Name: index_slots_reservations_on_reservation_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_slots_reservations_on_reservation_id ON public.slots_reservations USING btree (reservation_id); + + +-- +-- Name: index_slots_reservations_on_slot_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_slots_reservations_on_slot_id ON public.slots_reservations USING btree (slot_id); + + +-- +-- Name: index_spaces_availabilities_on_availability_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_spaces_availabilities_on_availability_id ON public.spaces_availabilities USING btree (availability_id); + + +-- +-- Name: index_spaces_availabilities_on_space_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_spaces_availabilities_on_space_id ON public.spaces_availabilities USING btree (space_id); + + +-- +-- Name: index_spaces_on_deleted_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_spaces_on_deleted_at ON public.spaces USING btree (deleted_at); + + +-- +-- Name: index_statistic_custom_aggregations_on_statistic_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_custom_aggregations_on_statistic_type_id ON public.statistic_custom_aggregations USING btree (statistic_type_id); + + +-- +-- Name: index_statistic_fields_on_statistic_index_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_fields_on_statistic_index_id ON public.statistic_fields USING btree (statistic_index_id); + + +-- +-- Name: index_statistic_graphs_on_statistic_index_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_graphs_on_statistic_index_id ON public.statistic_graphs USING btree (statistic_index_id); + + +-- +-- Name: index_statistic_profile_prepaid_packs_on_prepaid_pack_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_profile_prepaid_packs_on_prepaid_pack_id ON public.statistic_profile_prepaid_packs USING btree (prepaid_pack_id); + + +-- +-- Name: index_statistic_profile_prepaid_packs_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_profile_prepaid_packs_on_statistic_profile_id ON public.statistic_profile_prepaid_packs USING btree (statistic_profile_id); + + +-- +-- Name: index_statistic_profile_trainings_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_profile_trainings_on_statistic_profile_id ON public.statistic_profile_trainings USING btree (statistic_profile_id); + + +-- +-- Name: index_statistic_profile_trainings_on_training_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_profile_trainings_on_training_id ON public.statistic_profile_trainings USING btree (training_id); + + +-- +-- Name: index_statistic_profiles_on_group_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_profiles_on_group_id ON public.statistic_profiles USING btree (group_id); + + +-- +-- Name: index_statistic_profiles_on_role_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_profiles_on_role_id ON public.statistic_profiles USING btree (role_id); + + +-- +-- Name: index_statistic_profiles_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_profiles_on_user_id ON public.statistic_profiles USING btree (user_id); + + +-- +-- Name: index_statistic_type_sub_types_on_statistic_sub_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_type_sub_types_on_statistic_sub_type_id ON public.statistic_type_sub_types USING btree (statistic_sub_type_id); + + +-- +-- Name: index_statistic_type_sub_types_on_statistic_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_type_sub_types_on_statistic_type_id ON public.statistic_type_sub_types USING btree (statistic_type_id); + + +-- +-- Name: index_statistic_types_on_statistic_index_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_statistic_types_on_statistic_index_id ON public.statistic_types USING btree (statistic_index_id); + + +-- +-- Name: index_subscriptions_on_plan_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_subscriptions_on_plan_id ON public.subscriptions USING btree (plan_id); + + +-- +-- Name: index_subscriptions_on_statistic_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_subscriptions_on_statistic_profile_id ON public.subscriptions USING btree (statistic_profile_id); + + +-- +-- Name: index_supporting_document_files_on_supporting_document_type_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_supporting_document_files_on_supporting_document_type_id ON public.supporting_document_files USING btree (supporting_document_type_id); + + +-- +-- Name: index_supporting_document_files_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_supporting_document_files_on_user_id ON public.supporting_document_files USING btree (user_id); + + +-- +-- Name: index_supporting_document_refusals_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_supporting_document_refusals_on_user_id ON public.supporting_document_refusals USING btree (user_id); + + +-- +-- Name: index_tags_on_name; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_tags_on_name ON public.tags USING btree (name); + + +-- +-- Name: index_tickets_on_event_price_category_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_tickets_on_event_price_category_id ON public.tickets USING btree (event_price_category_id); + + +-- +-- Name: index_tickets_on_reservation_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_tickets_on_reservation_id ON public.tickets USING btree (reservation_id); + + +-- +-- Name: index_trainings_availabilities_on_availability_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_trainings_availabilities_on_availability_id ON public.trainings_availabilities USING btree (availability_id); + + +-- +-- Name: index_trainings_availabilities_on_training_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_trainings_availabilities_on_training_id ON public.trainings_availabilities USING btree (training_id); + + +-- +-- Name: index_trainings_machines_on_machine_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_trainings_machines_on_machine_id ON public.trainings_machines USING btree (machine_id); + + +-- +-- Name: index_trainings_machines_on_training_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_trainings_machines_on_training_id ON public.trainings_machines USING btree (training_id); + + +-- +-- Name: index_trainings_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_trainings_on_slug ON public.trainings USING btree (slug); + + +-- +-- Name: index_trainings_pricings_on_group_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_trainings_pricings_on_group_id ON public.trainings_pricings USING btree (group_id); + + +-- +-- Name: index_trainings_pricings_on_training_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_trainings_pricings_on_training_id ON public.trainings_pricings USING btree (training_id); + + +-- +-- Name: index_user_profile_custom_fields_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_user_profile_custom_fields_on_invoicing_profile_id ON public.user_profile_custom_fields USING btree (invoicing_profile_id); + + +-- +-- Name: index_user_profile_custom_fields_on_profile_custom_field_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_user_profile_custom_fields_on_profile_custom_field_id ON public.user_profile_custom_fields USING btree (profile_custom_field_id); + + +-- +-- Name: index_user_tags_on_tag_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_user_tags_on_tag_id ON public.user_tags USING btree (tag_id); + + +-- +-- Name: index_user_tags_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_user_tags_on_user_id ON public.user_tags USING btree (user_id); + + +-- +-- Name: index_users_credits_on_credit_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_users_credits_on_credit_id ON public.users_credits USING btree (credit_id); + + +-- +-- Name: index_users_credits_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_users_credits_on_user_id ON public.users_credits USING btree (user_id); + + +-- +-- Name: index_users_on_auth_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_users_on_auth_token ON public.users USING btree (auth_token); + + +-- +-- Name: index_users_on_confirmation_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_confirmation_token ON public.users USING btree (confirmation_token); + + +-- +-- Name: index_users_on_email; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_email ON public.users USING btree (email); + + +-- +-- Name: index_users_on_group_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_users_on_group_id ON public.users USING btree (group_id); + + +-- +-- Name: index_users_on_provider; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_users_on_provider ON public.users USING btree (provider); + + +-- +-- Name: index_users_on_reset_password_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_reset_password_token ON public.users USING btree (reset_password_token); + + +-- +-- Name: index_users_on_slug; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_slug ON public.users USING btree (slug); + + +-- +-- Name: index_users_on_uid; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_users_on_uid ON public.users USING btree (uid); + + +-- +-- Name: index_users_on_unlock_token; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_unlock_token ON public.users USING btree (unlock_token); + + +-- +-- Name: index_users_on_username; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX index_users_on_username ON public.users USING btree (username); + + +-- +-- Name: index_users_roles_on_user_id_and_role_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_users_roles_on_user_id_and_role_id ON public.users_roles USING btree (user_id, role_id); + + +-- +-- Name: index_wallet_transactions_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_wallet_transactions_on_invoicing_profile_id ON public.wallet_transactions USING btree (invoicing_profile_id); + + +-- +-- Name: index_wallet_transactions_on_wallet_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_wallet_transactions_on_wallet_id ON public.wallet_transactions USING btree (wallet_id); + + +-- +-- Name: index_wallets_on_invoicing_profile_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_wallets_on_invoicing_profile_id ON public.wallets USING btree (invoicing_profile_id); + + +-- +-- Name: profiles_lower_unaccent_first_name_trgm_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX profiles_lower_unaccent_first_name_trgm_idx ON public.profiles USING gin (lower(public.f_unaccent((first_name)::text)) public.gin_trgm_ops); + + +-- +-- Name: profiles_lower_unaccent_last_name_trgm_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX profiles_lower_unaccent_last_name_trgm_idx ON public.profiles USING gin (lower(public.f_unaccent((last_name)::text)) public.gin_trgm_ops); + + +-- +-- Name: projects_search_vector_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX projects_search_vector_idx ON public.projects USING gin (search_vector); + + +-- +-- Name: proof_of_identity_type_id_and_proof_of_identity_refusal_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX proof_of_identity_type_id_and_proof_of_identity_refusal_id ON public.supporting_document_refusals_types USING btree (supporting_document_type_id, supporting_document_refusal_id); + + +-- +-- Name: unique_not_null_external_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX unique_not_null_external_id ON public.invoicing_profiles USING btree (external_id) WHERE (external_id IS NOT NULL); + + +-- +-- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: - +-- + +CREATE UNIQUE INDEX unique_schema_migrations ON public.schema_migrations USING btree (version); + + +-- +-- Name: accounting_periods accounting_periods_del_protect; Type: RULE; Schema: public; Owner: - +-- + +CREATE RULE accounting_periods_del_protect AS + ON DELETE TO public.accounting_periods DO INSTEAD NOTHING; + + +-- +-- Name: accounting_periods accounting_periods_upd_protect; Type: RULE; Schema: public; Owner: - +-- + +CREATE RULE accounting_periods_upd_protect AS + ON UPDATE TO public.accounting_periods + WHERE ((new.start_at <> old.start_at) OR (new.end_at <> old.end_at) OR (new.closed_at <> old.closed_at) OR (new.period_total <> old.period_total) OR (new.perpetual_total <> old.perpetual_total)) DO INSTEAD NOTHING; + + +-- +-- Name: chained_elements chained_elements_upd_protect; Type: RULE; Schema: public; Owner: - +-- + +CREATE RULE chained_elements_upd_protect AS + ON UPDATE TO public.chained_elements + WHERE ((new.content <> old.content) OR ((new.footprint)::text <> (old.footprint)::text) OR (new.previous_id <> old.previous_id) OR (new.element_id <> old.element_id) OR ((new.element_type)::text <> (old.element_type)::text)) DO INSTEAD NOTHING; + + +-- +-- Name: projects projects_search_content_trigger; Type: TRIGGER; Schema: public; Owner: - +-- + +CREATE TRIGGER projects_search_content_trigger BEFORE INSERT OR UPDATE ON public.projects FOR EACH ROW EXECUTE PROCEDURE public.fill_search_vector_for_project(); + + +-- +-- Name: payment_schedules fk_rails_00308dc223; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedules + ADD CONSTRAINT fk_rails_00308dc223 FOREIGN KEY (wallet_transaction_id) REFERENCES public.wallet_transactions(id); + + +-- +-- Name: cart_item_free_extensions fk_rails_0d11862969; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_free_extensions + ADD CONSTRAINT fk_rails_0d11862969 FOREIGN KEY (customer_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: tickets fk_rails_0efe03a510; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.tickets + ADD CONSTRAINT fk_rails_0efe03a510 FOREIGN KEY (event_price_category_id) REFERENCES public.event_price_categories(id); + + +-- +-- Name: invoicing_profiles fk_rails_122b1ddaf2; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoicing_profiles + ADD CONSTRAINT fk_rails_122b1ddaf2 FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: invoices fk_rails_13888eebf0; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoices + ADD CONSTRAINT fk_rails_13888eebf0 FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: wallet_transactions fk_rails_1548249e6b; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.wallet_transactions + ADD CONSTRAINT fk_rails_1548249e6b FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: cart_item_event_reservation_tickets fk_rails_17315e88ac; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservation_tickets + ADD CONSTRAINT fk_rails_17315e88ac FOREIGN KEY (event_price_category_id) REFERENCES public.event_price_categories(id); + + +-- +-- Name: statistic_custom_aggregations fk_rails_1742c38664; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_custom_aggregations + ADD CONSTRAINT fk_rails_1742c38664 FOREIGN KEY (statistic_type_id) REFERENCES public.statistic_types(id); + + +-- +-- Name: cart_item_coupons fk_rails_1a058c9deb; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_coupons + ADD CONSTRAINT fk_rails_1a058c9deb FOREIGN KEY (coupon_id) REFERENCES public.coupons(id); + + +-- +-- Name: project_users fk_rails_1bf16ed5d0; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_users + ADD CONSTRAINT fk_rails_1bf16ed5d0 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: history_values fk_rails_1c79bec847; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.history_values + ADD CONSTRAINT fk_rails_1c79bec847 FOREIGN KEY (setting_id) REFERENCES public.settings(id); + + +-- +-- Name: prepaid_pack_reservations fk_rails_1d1e8ca696; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prepaid_pack_reservations + ADD CONSTRAINT fk_rails_1d1e8ca696 FOREIGN KEY (reservation_id) REFERENCES public.reservations(id); + + +-- +-- Name: cart_item_reservations fk_rails_2384b7ab3d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservations + ADD CONSTRAINT fk_rails_2384b7ab3d FOREIGN KEY (customer_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: prices fk_rails_2385efc06e; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prices + ADD CONSTRAINT fk_rails_2385efc06e FOREIGN KEY (group_id) REFERENCES public.groups(id); + + +-- +-- Name: slots_reservations fk_rails_246639af41; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.slots_reservations + ADD CONSTRAINT fk_rails_246639af41 FOREIGN KEY (reservation_id) REFERENCES public.reservations(id); + + +-- +-- Name: i_calendar_events fk_rails_25e5a14f12; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.i_calendar_events + ADD CONSTRAINT fk_rails_25e5a14f12 FOREIGN KEY (i_calendar_id) REFERENCES public.i_calendars(id); + + +-- +-- Name: plan_limitations fk_rails_2673f3a894; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plan_limitations + ADD CONSTRAINT fk_rails_2673f3a894 FOREIGN KEY (plan_id) REFERENCES public.plans(id); + + +-- +-- Name: exports fk_rails_26b155474a; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.exports + ADD CONSTRAINT fk_rails_26b155474a FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: payment_schedules fk_rails_27cdd051f7; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedules + ADD CONSTRAINT fk_rails_27cdd051f7 FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: payment_gateway_objects fk_rails_2a54622221; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_gateway_objects + ADD CONSTRAINT fk_rails_2a54622221 FOREIGN KEY (payment_gateway_object_id) REFERENCES public.payment_gateway_objects(id); + + +-- +-- Name: accounting_lines fk_rails_2b624271e3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.accounting_lines + ADD CONSTRAINT fk_rails_2b624271e3 FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: statistic_profiles fk_rails_2c8874d1a1; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profiles + ADD CONSTRAINT fk_rails_2c8874d1a1 FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: invoices fk_rails_2f06166181; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoices + ADD CONSTRAINT fk_rails_2f06166181 FOREIGN KEY (wallet_transaction_id) REFERENCES public.wallet_transactions(id); + + +-- +-- Name: cart_item_event_reservations fk_rails_302f96c6bf; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservations + ADD CONSTRAINT fk_rails_302f96c6bf FOREIGN KEY (customer_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: cart_item_payment_schedules fk_rails_34a6d5887a; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_payment_schedules + ADD CONSTRAINT fk_rails_34a6d5887a FOREIGN KEY (customer_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: subscriptions fk_rails_358a71f738; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.subscriptions + ADD CONSTRAINT fk_rails_358a71f738 FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: invoices fk_rails_40d78f8cf6; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoices + ADD CONSTRAINT fk_rails_40d78f8cf6 FOREIGN KEY (operator_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: projects_spaces fk_rails_43999be339; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_spaces + ADD CONSTRAINT fk_rails_43999be339 FOREIGN KEY (space_id) REFERENCES public.spaces(id); + + +-- +-- Name: order_activities fk_rails_45d167c69d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.order_activities + ADD CONSTRAINT fk_rails_45d167c69d FOREIGN KEY (operator_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: spaces_availabilities fk_rails_4a1cac85d2; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.spaces_availabilities + ADD CONSTRAINT fk_rails_4a1cac85d2 FOREIGN KEY (availability_id) REFERENCES public.availabilities(id); + + +-- +-- Name: projects_components fk_rails_4d88badb91; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_components + ADD CONSTRAINT fk_rails_4d88badb91 FOREIGN KEY (component_id) REFERENCES public.components(id); + + +-- +-- Name: event_price_categories fk_rails_4dc2c47476; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_price_categories + ADD CONSTRAINT fk_rails_4dc2c47476 FOREIGN KEY (price_category_id) REFERENCES public.price_categories(id); + + +-- +-- Name: payment_schedule_items fk_rails_4e9d79c566; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedule_items + ADD CONSTRAINT fk_rails_4e9d79c566 FOREIGN KEY (invoice_id) REFERENCES public.invoices(id); + + +-- +-- Name: chained_elements fk_rails_4fad806cca; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.chained_elements + ADD CONSTRAINT fk_rails_4fad806cca FOREIGN KEY (previous_id) REFERENCES public.chained_elements(id); + + +-- +-- Name: cart_item_event_reservation_tickets fk_rails_5307e8aab8; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservation_tickets + ADD CONSTRAINT fk_rails_5307e8aab8 FOREIGN KEY (cart_item_event_reservation_id) REFERENCES public.cart_item_event_reservations(id); + + +-- +-- Name: payment_schedules fk_rails_552bc65163; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedules + ADD CONSTRAINT fk_rails_552bc65163 FOREIGN KEY (coupon_id) REFERENCES public.coupons(id); + + +-- +-- Name: payment_schedule_objects fk_rails_56f6b6d2d2; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedule_objects + ADD CONSTRAINT fk_rails_56f6b6d2d2 FOREIGN KEY (payment_schedule_id) REFERENCES public.payment_schedules(id); + + +-- +-- Name: cart_item_prepaid_packs fk_rails_58f52df420; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_prepaid_packs + ADD CONSTRAINT fk_rails_58f52df420 FOREIGN KEY (prepaid_pack_id) REFERENCES public.prepaid_packs(id); + + +-- +-- Name: cart_item_event_reservations fk_rails_59c5c16548; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservations + ADD CONSTRAINT fk_rails_59c5c16548 FOREIGN KEY (operator_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: statistic_profile_prepaid_packs fk_rails_5af0f4258a; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_prepaid_packs + ADD CONSTRAINT fk_rails_5af0f4258a FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: cart_item_payment_schedules fk_rails_5da9437a85; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_payment_schedules + ADD CONSTRAINT fk_rails_5da9437a85 FOREIGN KEY (coupon_id) REFERENCES public.coupons(id); + + +-- +-- Name: cart_item_free_extensions fk_rails_62ad5e8b18; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_free_extensions + ADD CONSTRAINT fk_rails_62ad5e8b18 FOREIGN KEY (subscription_id) REFERENCES public.subscriptions(id); + + +-- +-- Name: tickets fk_rails_65422fe751; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.tickets + ADD CONSTRAINT fk_rails_65422fe751 FOREIGN KEY (reservation_id) REFERENCES public.reservations(id); + + +-- +-- Name: cart_item_subscriptions fk_rails_674c95c433; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_subscriptions + ADD CONSTRAINT fk_rails_674c95c433 FOREIGN KEY (plan_id) REFERENCES public.plans(id); + + +-- +-- Name: prepaid_packs fk_rails_6ea2aaae74; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prepaid_packs + ADD CONSTRAINT fk_rails_6ea2aaae74 FOREIGN KEY (group_id) REFERENCES public.groups(id); + + +-- +-- Name: spaces_availabilities fk_rails_6f123023fd; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.spaces_availabilities + ADD CONSTRAINT fk_rails_6f123023fd FOREIGN KEY (space_id) REFERENCES public.spaces(id); + + +-- +-- Name: user_tags fk_rails_7156651ad8; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_tags + ADD CONSTRAINT fk_rails_7156651ad8 FOREIGN KEY (tag_id) REFERENCES public.tags(id); + + +-- +-- Name: events_event_themes fk_rails_725b0acd5b; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.events_event_themes + ADD CONSTRAINT fk_rails_725b0acd5b FOREIGN KEY (event_theme_id) REFERENCES public.event_themes(id); + + +-- +-- Name: notifications fk_rails_75cdc2096d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notifications + ADD CONSTRAINT fk_rails_75cdc2096d FOREIGN KEY (notification_type_id) REFERENCES public.notification_types(id); + + +-- +-- Name: wallets fk_rails_7bfc904eec; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.wallets + ADD CONSTRAINT fk_rails_7bfc904eec FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: statistic_profiles fk_rails_7cf6dfadf2; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profiles + ADD CONSTRAINT fk_rails_7cf6dfadf2 FOREIGN KEY (group_id) REFERENCES public.groups(id); + + +-- +-- Name: cart_item_prepaid_packs fk_rails_83291fbe82; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_prepaid_packs + ADD CONSTRAINT fk_rails_83291fbe82 FOREIGN KEY (customer_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: prepaid_pack_reservations fk_rails_85a17dcd7d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prepaid_pack_reservations + ADD CONSTRAINT fk_rails_85a17dcd7d FOREIGN KEY (statistic_profile_prepaid_pack_id) REFERENCES public.statistic_profile_prepaid_packs(id); + + +-- +-- Name: history_values fk_rails_860e5a38df; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.history_values + ADD CONSTRAINT fk_rails_860e5a38df FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: orders fk_rails_880df4b1ae; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.orders + ADD CONSTRAINT fk_rails_880df4b1ae FOREIGN KEY (operator_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: projects_machines fk_rails_88b280c24c; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_machines + ADD CONSTRAINT fk_rails_88b280c24c FOREIGN KEY (machine_id) REFERENCES public.machines(id); + + +-- +-- Name: payment_schedules fk_rails_8b73dd8d7d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedules + ADD CONSTRAINT fk_rails_8b73dd8d7d FOREIGN KEY (operator_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: cart_item_payment_schedules fk_rails_8c5ec85c7f; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_payment_schedules + ADD CONSTRAINT fk_rails_8c5ec85c7f FOREIGN KEY (plan_id) REFERENCES public.plans(id); + + +-- +-- Name: availability_tags fk_rails_8cb4e921f7; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.availability_tags + ADD CONSTRAINT fk_rails_8cb4e921f7 FOREIGN KEY (availability_id) REFERENCES public.availabilities(id); + + +-- +-- Name: organizations fk_rails_8d4871c330; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.organizations + ADD CONSTRAINT fk_rails_8d4871c330 FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: invoices fk_rails_8f2dfb47ee; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoices + ADD CONSTRAINT fk_rails_8f2dfb47ee FOREIGN KEY (coupon_id) REFERENCES public.coupons(id); + + +-- +-- Name: orders fk_rails_907a5e9f62; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.orders + ADD CONSTRAINT fk_rails_907a5e9f62 FOREIGN KEY (coupon_id) REFERENCES public.coupons(id); + + +-- +-- Name: orders fk_rails_9147ddb417; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.orders + ADD CONSTRAINT fk_rails_9147ddb417 FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: supporting_document_refusals fk_rails_91d424352e; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_refusals + ADD CONSTRAINT fk_rails_91d424352e FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: invoices fk_rails_94eb61be79; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.invoices + ADD CONSTRAINT fk_rails_94eb61be79 FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: notification_preferences fk_rails_9503aade25; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notification_preferences + ADD CONSTRAINT fk_rails_9503aade25 FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: cart_item_reservations fk_rails_951386f24e; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservations + ADD CONSTRAINT fk_rails_951386f24e FOREIGN KEY (operator_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: accounting_lines fk_rails_97c9798d44; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.accounting_lines + ADD CONSTRAINT fk_rails_97c9798d44 FOREIGN KEY (invoice_id) REFERENCES public.invoices(id); + + +-- +-- Name: project_users fk_rails_996d73fecd; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_users + ADD CONSTRAINT fk_rails_996d73fecd FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: auth_provider_mappings fk_rails_9b679de4cc; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.auth_provider_mappings + ADD CONSTRAINT fk_rails_9b679de4cc FOREIGN KEY (auth_provider_id) REFERENCES public.auth_providers(id); + + +-- +-- Name: machines fk_rails_9c12e5d709; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.machines + ADD CONSTRAINT fk_rails_9c12e5d709 FOREIGN KEY (machine_category_id) REFERENCES public.machine_categories(id); + + +-- +-- Name: prices fk_rails_9f0e94b0c3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.prices + ADD CONSTRAINT fk_rails_9f0e94b0c3 FOREIGN KEY (plan_id) REFERENCES public.plans(id); + + +-- +-- Name: projects_themes fk_rails_9fd58ae797; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_themes + ADD CONSTRAINT fk_rails_9fd58ae797 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: supporting_document_types_groups fk_rails_a1f5531605; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_types_groups + ADD CONSTRAINT fk_rails_a1f5531605 FOREIGN KEY (supporting_document_type_id) REFERENCES public.supporting_document_types(id); + + +-- +-- Name: notification_preferences fk_rails_a402db84f8; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.notification_preferences + ADD CONSTRAINT fk_rails_a402db84f8 FOREIGN KEY (notification_type_id) REFERENCES public.notification_types(id); + + +-- +-- Name: cart_item_coupons fk_rails_a44bac1e45; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_coupons + ADD CONSTRAINT fk_rails_a44bac1e45 FOREIGN KEY (operator_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: projects_themes fk_rails_b021a22658; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_themes + ADD CONSTRAINT fk_rails_b021a22658 FOREIGN KEY (theme_id) REFERENCES public.themes(id); + + +-- +-- Name: statistic_profile_prepaid_packs fk_rails_b0251cdfcf; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_prepaid_packs + ADD CONSTRAINT fk_rails_b0251cdfcf FOREIGN KEY (prepaid_pack_id) REFERENCES public.prepaid_packs(id); + + +-- +-- Name: orders fk_rails_b33ed6c672; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.orders + ADD CONSTRAINT fk_rails_b33ed6c672 FOREIGN KEY (invoice_id) REFERENCES public.invoices(id); + + +-- +-- Name: projects fk_rails_b4a83cd9b3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects + ADD CONSTRAINT fk_rails_b4a83cd9b3 FOREIGN KEY (status_id) REFERENCES public.statuses(id); + + +-- +-- Name: statistic_profiles fk_rails_bba64e5eb9; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profiles + ADD CONSTRAINT fk_rails_bba64e5eb9 FOREIGN KEY (role_id) REFERENCES public.roles(id); + + +-- +-- Name: events_event_themes fk_rails_bd1415f169; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.events_event_themes + ADD CONSTRAINT fk_rails_bd1415f169 FOREIGN KEY (event_id) REFERENCES public.events(id); + + +-- +-- Name: projects_machines fk_rails_c1427daf48; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_machines + ADD CONSTRAINT fk_rails_c1427daf48 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: plans fk_rails_c503ed4a8c; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.plans + ADD CONSTRAINT fk_rails_c503ed4a8c FOREIGN KEY (plan_category_id) REFERENCES public.plan_categories(id); + + +-- +-- Name: project_steps fk_rails_c6306005c3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.project_steps + ADD CONSTRAINT fk_rails_c6306005c3 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: projects_components fk_rails_c80c60ead3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_components + ADD CONSTRAINT fk_rails_c80c60ead3 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: user_profile_custom_fields fk_rails_c9a569c13e; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_profile_custom_fields + ADD CONSTRAINT fk_rails_c9a569c13e FOREIGN KEY (profile_custom_field_id) REFERENCES public.profile_custom_fields(id); + + +-- +-- Name: order_activities fk_rails_cabaff5432; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.order_activities + ADD CONSTRAINT fk_rails_cabaff5432 FOREIGN KEY (order_id) REFERENCES public.orders(id); + + +-- +-- Name: statistic_profile_trainings fk_rails_cb689a8d3d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_trainings + ADD CONSTRAINT fk_rails_cb689a8d3d FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: cart_item_subscriptions fk_rails_cb8daf6b0b; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_subscriptions + ADD CONSTRAINT fk_rails_cb8daf6b0b FOREIGN KEY (customer_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: accounting_periods fk_rails_cc9abff81f; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.accounting_periods + ADD CONSTRAINT fk_rails_cc9abff81f FOREIGN KEY (closed_by) REFERENCES public.users(id); + + +-- +-- Name: wallet_transactions fk_rails_d07bc24ce3; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.wallet_transactions + ADD CONSTRAINT fk_rails_d07bc24ce3 FOREIGN KEY (wallet_id) REFERENCES public.wallets(id); + + +-- +-- Name: cart_item_reservations fk_rails_d0bb98e5fa; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservations + ADD CONSTRAINT fk_rails_d0bb98e5fa FOREIGN KEY (plan_id) REFERENCES public.plans(id); + + +-- +-- Name: availability_tags fk_rails_d262715d11; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.availability_tags + ADD CONSTRAINT fk_rails_d262715d11 FOREIGN KEY (tag_id) REFERENCES public.tags(id); + + +-- +-- Name: payment_schedules fk_rails_d345f9b22a; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedules + ADD CONSTRAINT fk_rails_d345f9b22a FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: slots_reservations fk_rails_d4ced1b26d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.slots_reservations + ADD CONSTRAINT fk_rails_d4ced1b26d FOREIGN KEY (slot_id) REFERENCES public.slots(id); + + +-- +-- Name: payment_schedule_items fk_rails_d6030dd0e7; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.payment_schedule_items + ADD CONSTRAINT fk_rails_d6030dd0e7 FOREIGN KEY (payment_schedule_id) REFERENCES public.payment_schedules(id); + + +-- +-- Name: product_stock_movements fk_rails_dc802d5f48; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.product_stock_movements + ADD CONSTRAINT fk_rails_dc802d5f48 FOREIGN KEY (product_id) REFERENCES public.products(id); + + +-- +-- Name: event_price_categories fk_rails_dcd2787d07; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_price_categories + ADD CONSTRAINT fk_rails_dcd2787d07 FOREIGN KEY (event_id) REFERENCES public.events(id); + + +-- +-- Name: cart_item_coupons fk_rails_e1cb402fac; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_coupons + ADD CONSTRAINT fk_rails_e1cb402fac FOREIGN KEY (customer_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: supporting_document_types_groups fk_rails_e2f3e565b7; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.supporting_document_types_groups + ADD CONSTRAINT fk_rails_e2f3e565b7 FOREIGN KEY (group_id) REFERENCES public.groups(id); + + +-- +-- Name: order_items fk_rails_e3cb28f071; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.order_items + ADD CONSTRAINT fk_rails_e3cb28f071 FOREIGN KEY (order_id) REFERENCES public.orders(id); + + +-- +-- Name: reservations fk_rails_e409fe73aa; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.reservations + ADD CONSTRAINT fk_rails_e409fe73aa FOREIGN KEY (statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: statistic_profile_trainings fk_rails_e759406c68; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.statistic_profile_trainings + ADD CONSTRAINT fk_rails_e759406c68 FOREIGN KEY (training_id) REFERENCES public.trainings(id); + + +-- +-- Name: projects fk_rails_e812590204; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects + ADD CONSTRAINT fk_rails_e812590204 FOREIGN KEY (author_statistic_profile_id) REFERENCES public.statistic_profiles(id); + + +-- +-- Name: user_tags fk_rails_ea0382482a; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_tags + ADD CONSTRAINT fk_rails_ea0382482a FOREIGN KEY (user_id) REFERENCES public.users(id); + + +-- +-- Name: products fk_rails_efe167855e; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.products + ADD CONSTRAINT fk_rails_efe167855e FOREIGN KEY (product_category_id) REFERENCES public.product_categories(id); + + +-- +-- Name: user_profile_custom_fields fk_rails_f0faa9ed79; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.user_profile_custom_fields + ADD CONSTRAINT fk_rails_f0faa9ed79 FOREIGN KEY (invoicing_profile_id) REFERENCES public.invoicing_profiles(id); + + +-- +-- Name: projects_spaces fk_rails_f2103efed7; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.projects_spaces + ADD CONSTRAINT fk_rails_f2103efed7 FOREIGN KEY (project_id) REFERENCES public.projects(id); + + +-- +-- Name: events fk_rails_fd5598a81d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.events + ADD CONSTRAINT fk_rails_fd5598a81d FOREIGN KEY (category_id) REFERENCES public.categories(id); + + +-- +-- Name: cart_item_reservation_slots fk_rails_fd8092749c; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservation_slots + ADD CONSTRAINT fk_rails_fd8092749c FOREIGN KEY (slot_id) REFERENCES public.slots(id); + + +-- +-- Name: cart_item_reservation_slots fk_rails_fe07d12d9f; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_reservation_slots + ADD CONSTRAINT fk_rails_fe07d12d9f FOREIGN KEY (slots_reservation_id) REFERENCES public.slots_reservations(id); + + +-- +-- Name: cart_item_event_reservations fk_rails_fe95ba05e8; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.cart_item_event_reservations + ADD CONSTRAINT fk_rails_fe95ba05e8 FOREIGN KEY (event_id) REFERENCES public.events(id); + + +-- +-- PostgreSQL database dump complete +-- + +SET search_path TO "$user", public; + +INSERT INTO "schema_migrations" (version) VALUES +('20140409083104'), +('20140409083610'), +('20140409153915'), +('20140410101026'), +('20140410140516'), +('20140410162151'), +('20140411152729'), +('20140414141134'), +('20140415104151'), +('20140415123625'), +('20140416130838'), +('20140422085949'), +('20140422090412'), +('20140513152025'), +('20140516083543'), +('20140516083909'), +('20140516093335'), +('20140522115617'), +('20140522175539'), +('20140522175714'), +('20140522180032'), +('20140522180930'), +('20140522181011'), +('20140522181148'), +('20140523083230'), +('20140526144327'), +('20140527092045'), +('20140528134944'), +('20140528140257'), +('20140529145140'), +('20140603084413'), +('20140603085817'), +('20140603164215'), +('20140604094514'), +('20140604113611'), +('20140604113919'), +('20140604132045'), +('20140605125131'), +('20140605142133'), +('20140605151442'), +('20140606133116'), +('20140609092700'), +('20140609092827'), +('20140610153123'), +('20140610170446'), +('20140613150651'), +('20140620131525'), +('20140622121724'), +('20140622122944'), +('20140622145648'), +('20140623023557'), +('20140624123359'), +('20140624123814'), +('20140624124338'), +('20140703100457'), +('20140703231208'), +('20140703233420'), +('20140703233942'), +('20140703235739'), +('20140710144142'), +('20140710144427'), +('20140710144610'), +('20140711084809'), +('20140715095503'), +('20140717143735'), +('20140722162046'), +('20140722162309'), +('20140723075942'), +('20140723171547'), +('20140723172610'), +('20140724125605'), +('20140724131808'), +('20140724132655'), +('20140728110430'), +('20141002111736'), +('20141110131407'), +('20141215142044'), +('20141215153643'), +('20141217141648'), +('20141217172843'), +('20150107103903'), +('20150108082541'), +('20150112160349'), +('20150112160405'), +('20150112160425'), +('20150113112757'), +('20150114111132'), +('20150114111243'), +('20150114141926'), +('20150114142032'), +('20150115143750'), +('20150119082931'), +('20150119092557'), +('20150119093811'), +('20150119160758'), +('20150119161004'), +('20150127101521'), +('20150127155141'), +('20150127161235'), +('20150127172510'), +('20150128132219'), +('20150218154032'), +('20150428075148'), +('20150428091057'), +('20150506090921'), +('20150507075506'), +('20150507075620'), +('20150512123546'), +('20150520132030'), +('20150520133409'), +('20150526130729'), +('20150527153312'), +('20150529113555'), +('20150601125944'), +('20150603104502'), +('20150603104658'), +('20150603133050'), +('20150604081757'), +('20150604131525'), +('20150608142234'), +('20150609094336'), +('20150615135539'), +('20150617085623'), +('20150701090642'), +('20150702150754'), +('20150702151009'), +('20150706102547'), +('20150707135343'), +('20150713090542'), +('20150713151115'), +('20150715135751'), +('20150915144448'), +('20150915144939'), +('20150915152943'), +('20150916091131'), +('20150916093159'), +('20150921135557'), +('20150921135817'), +('20150922095921'), +('20150922100528'), +('20150924093917'), +('20150924094138'), +('20150924094427'), +('20150924141714'), +('20151005133841'), +('20151008152219'), +('20151105125623'), +('20151210113548'), +('20160119131623'), +('20160504085703'), +('20160504085905'), +('20160516090121'), +('20160516124056'), +('20160526095550'), +('20160526102307'), +('20160602075531'), +('20160613093842'), +('20160628092931'), +('20160628124538'), +('20160628131408'), +('20160628134211'), +('20160628134303'), +('20160629091649'), +('20160630083438'), +('20160630083556'), +('20160630083759'), +('20160630100137'), +('20160630140204'), +('20160704095606'), +('20160704165139'), +('20160714095018'), +('20160718165434'), +('20160720124355'), +('20160725131756'), +('20160725131950'), +('20160725135112'), +('20160726081931'), +('20160726111509'), +('20160726131152'), +('20160726144257'), +('20160728095026'), +('20160801145502'), +('20160801153454'), +('20160803085201'), +('20160803104701'), +('20160804073558'), +('20160808113850'), +('20160808113930'), +('20160824080717'), +('20160824084111'), +('20160825141326'), +('20160830154719'), +('20160831084443'), +('20160831084519'), +('20160905141858'), +('20160905142700'), +('20160906094739'), +('20160906094847'), +('20160906145713'), +('20160915105234'), +('20161123104604'), +('20170109085345'), +('20170213100744'), +('20170213101541'), +('20170213103438'), +('20170213142543'), +('20170227104736'), +('20170227104934'), +('20170227113718'), +('20170227114634'), +('20170906100906'), +('20171004135605'), +('20171005141522'), +('20171010143708'), +('20171011100640'), +('20171011125217'), +('20181210105917'), +('20181217103256'), +('20181217103441'), +('20181217110454'), +('20190107103632'), +('20190107111749'), +('20190110150532'), +('20190211124135'), +('20190211124726'), +('20190225101256'), +('20190225102847'), +('20190227143153'), +('20190314095931'), +('20190320091148'), +('20190521122429'), +('20190521123642'), +('20190521124609'), +('20190521151142'), +('20190522115230'), +('20190523123916'), +('20190523140823'), +('20190528140012'), +('20190604064929'), +('20190604065348'), +('20190604070903'), +('20190604075717'), +('20190605141322'), +('20190606074050'), +('20190606074801'), +('20190730085826'), +('20190910131825'), +('20190910141336'), +('20190917123631'), +('20190924140726'), +('20191113103352'), +('20191127153729'), +('20191202135507'), +('20200127111404'), +('20200206132857'), +('20200218092221'), +('20200408101654'), +('20200415141809'), +('20200511075933'), +('20200622135401'), +('20200623134900'), +('20200623141305'), +('20200629123011'), +('20200721162939'), +('20201027092149'), +('20201027100746'), +('20201027101809'), +('20201112092002'), +('20210416073410'), +('20210416083610'), +('20210521085710'), +('20210525134018'), +('20210525150942'), +('20210608082748'), +('20210621122103'), +('20210621123954'), +('20211014135151'), +('20211018121822'), +('20211220143400'), +('20220111134253'), +('20220118123741'), +('20220225143203'), +('20220316133304'), +('20220322135836'), +('20220328141618'), +('20220328144305'), +('20220328145017'), +('20220422090245'), +('20220422090709'), +('20220425095244'), +('20220426162334'), +('20220428123828'), +('20220428125751'), +('20220429164234'), +('20220506143526'), +('20220509105714'), +('20220517140916'), +('20220531160223'), +('20220620072750'), +('20220704084929'), +('20220705125232'), +('20220712153708'), +('20220712160137'), +('20220720135828'), +('20220803091913'), +('20220805083431'), +('20220808161314'), +('20220818160821'), +('20220822081222'), +('20220826074619'), +('20220826085923'), +('20220826090821'), +('20220826091819'), +('20220826093503'), +('20220826133518'), +('20220826140921'), +('20220826175129'), +('20220909131300'), +('20220914145334'), +('20220915133100'), +('20220920131912'), +('20221003133019'), +('20221110120338'), +('20221118092948'), +('20221122123557'), +('20221122123605'), +('20221206100225'), +('20221208123822'), +('20221212162655'), +('20221216090005'), +('20221220105939'), +('20221227141529'), +('20221228152719'), +('20221228152747'), +('20221228160449'), +('20221229085430'), +('20221229094334'), +('20221229100157'), +('20221229103407'), +('20221229105954'), +('20221229115757'), +('20221229120932'), +('20230106081943'), +('20230112151631'), +('20230113145632'), +('20230116142738'), +('20230119143245'), +('20230124094255'), +('20230126160900'), +('20230127091337'), +('20230127100506'), +('20230131104958'), +('20230213134954'), +('20230302120458'), +('20230307123611'), +('20230307123841'), +('20230309094535'), +('20230315095054'), +('20230323085947'), +('20230323104259'), +('20230323104727'), +('20230324090312'), +('20230324095639'), +('20230328094807'), +('20230328094808'), +('20230328094809'); + + diff --git a/doc/architecture.md b/doc/architecture.md index aaf9f65d0..34640f0d2 100644 --- a/doc/architecture.md +++ b/doc/architecture.md @@ -93,7 +93,6 @@ It also provides another REST-JSON API, open to the 3rd-party applications, and `  ╠═ pdfs/` PDF documents generation;
`  ╠═ policies/` Access policies for the API and OpenAPI endpoints;
`  ╠═ services/` Utilities arranged by data models;
-`  ╠═ sweepers/` Build cached version of some data;
`  ╠═ themes/` SASS files that overrides the frontend styles. We plan to move all styles here to build multiple themes;
`  ╠═ uploaders/` Handling of the uploaded files
`  ╠═ validators/` Custom data validation (before saving);
@@ -126,4 +125,4 @@ For now, the main application is still using Angular.js but it uses some React.j `    ║ ║ ╠═ plugins.js.erb` Entrypoint for embedding Fab-manager's plugins in the frontend application;
`    ║ ║ ╚═ router.js` Configuration for UI-Router (mapping between routes, controllers and templates)
`    ║ ╚═ stylesheets/` SASS source for the application style
-`    ╚═ templates/` Angular.js views (HTML) +`    ╚═ templates/` Angular.js views (HTML) diff --git a/doc/development_readme.md b/doc/development_readme.md index 6c09fdba5..918199ccd 100644 --- a/doc/development_readme.md +++ b/doc/development_readme.md @@ -125,13 +125,11 @@ This procedure is not easy to follow so if you don't need to write some code for ```bash # for dev - rails db:create - rails db:migrate + rails db:schema:load ADMIN_EMAIL='youradminemail' ADMIN_PASSWORD='youradminpassword' rails db:seed rails fablab:es:build_stats # for tests - RAILS_ENV=test rails db:create - RAILS_ENV=test rails db:migrate + RAILS_ENV=test rails db:schema:load ``` 14. Enable Overcommit diff --git a/doc/virtual-machine.md b/doc/virtual-machine.md index ca01359eb..4ccdb7b8b 100644 --- a/doc/virtual-machine.md +++ b/doc/virtual-machine.md @@ -50,14 +50,12 @@ the host can provide but will usually be much more slower than a production envi included in the migrations. Password minimal length is 8 characters): ```bash - rails db:create - rails db:migrate + rails db:schema:load # Be sure not to use the default values below in production ADMIN_EMAIL='admin@email' ADMIN_PASSWORD='adminpass' rails db:seed rails fablab:es:build_stats # for tests - RAILS_ENV=test rails db:create - RAILS_ENV=test rails db:migrate + RAILS_ENV=test rails db:schema:load ``` 8. Start the application and visit `localhost:3000` on your browser to check that it works: diff --git a/docker/supervisor.conf b/docker/supervisor.conf index 14d48b86b..85ee6d062 100644 --- a/docker/supervisor.conf +++ b/docker/supervisor.conf @@ -14,7 +14,7 @@ childlogdir=/var/log/supervisor/ ; where child log files will liv serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket [program:app] -command=bundle exec rails s puma -p 3000 -b 0.0.0.0 +command=bundle exec rails server -u puma -p 3000 -b 0.0.0.0 stderr_logfile=/var/log/supervisor/app-stderr.log stdout_logfile=/var/log/supervisor/app-stdout.log stdout_logfile_maxbytes=50MB diff --git a/lib/fab_manager.rb b/lib/fab_manager.rb index 56bbfba7e..9007be9e6 100644 --- a/lib/fab_manager.rb +++ b/lib/fab_manager.rb @@ -1,14 +1,15 @@ # frozen_string_literal: true -require_dependency 'plugin/instance' +load 'plugin/instance.rb' +# the FabManager application module FabManager class << self attr_reader :plugins end def self.activate_plugins! - all_plugins = Plugin::Instance.find_all("#{Rails.root}/plugins") + all_plugins = Plugin::Instance.find_all(Rails.root.join('plugins')) @plugins = [] all_plugins.each do |p| diff --git a/lib/integrity/archive_helper.rb b/lib/integrity/archive_helper.rb index a0b376982..8ae2fa315 100644 --- a/lib/integrity/archive_helper.rb +++ b/lib/integrity/archive_helper.rb @@ -6,7 +6,6 @@ module Integrity; end # Provides various helpers methods for interacting with accounting archives class Integrity::ArchiveHelper class << self - ## Checks the validity of all closed periods and raise an error otherwise def check_footprints if AccountingPeriod.count.positive? @@ -20,7 +19,7 @@ class Integrity::ArchiveHelper end else Rails.logger.info 'Checking all invoices footprints. This may take a while...' - Invoice.order(:id).all.each do |i| + Invoice.order(:id).find_each do |i| next if i.check_footprint i.debug_footprint @@ -48,7 +47,7 @@ class Integrity::ArchiveHelper ) end # 3. Delete periods from database - range_periods.each do |ap| + range_periods.each do |ap| # rubocop:disable Style/CombinableLoops execute("DELETE FROM accounting_periods WHERE ID=#{ap.id};") end periods diff --git a/lib/omni_auth/strategies/sso_oauth2_provider.rb b/lib/omni_auth/strategies/sso_oauth2_provider.rb index 150f23393..2fc3feb75 100644 --- a/lib/omni_auth/strategies/sso_oauth2_provider.rb +++ b/lib/omni_auth/strategies/sso_oauth2_provider.rb @@ -5,77 +5,74 @@ require 'jsonpath' require 'sso_logger' require_relative '../data_mapping/mapper' -module OmniAuth::Strategies - # Authentication strategy provided trough oAuth 2.0 - class SsoOauth2Provider < OmniAuth::Strategies::OAuth2 - include OmniAuth::DataMapping::Mapper +# Authentication strategy provided trough oAuth 2.0 +class OmniAuth::Strategies::SsoOauth2Provider < OmniAuth::Strategies::OAuth2 + include OmniAuth::DataMapping::Mapper - def self.active_provider - active_provider = AuthProvider.active - if active_provider.providable_type != OAuth2Provider.name - raise "Trying to instantiate the wrong provider: Expected OAuth2Provider, received #{active_provider.providable_type}" - end - - active_provider + def self.active_provider + active_provider = Rails.configuration.auth_provider + if active_provider.providable_type != 'OAuth2Provider' + raise "Trying to instantiate the wrong provider: Expected OAuth2Provider, received #{active_provider.providable_type}" end - # Strategy name. - option :name, active_provider.strategy_name + active_provider + end + # Strategy name. + option :name, active_provider.strategy_name - option :client_options, - site: active_provider.providable.base_url, - authorize_url: active_provider.providable.authorization_endpoint, - token_url: active_provider.providable.token_endpoint + option :client_options, + site: active_provider.providable.base_url, + authorize_url: active_provider.providable.authorization_endpoint, + token_url: active_provider.providable.token_endpoint - def authorize_params - super.tap do |params| - params[:scope] = OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.scopes - end - end - - def callback_url - url = Rails.application.config.action_controller.default_url_options - "#{url[:protocol]}://#{url[:host]}#{script_name}#{callback_path}" - end - - uid { parsed_info['user.uid'.to_sym] } - - info do - { - mapping: parsed_info - } - end - - extra do - { - raw_info: raw_info - } - end - - # retrieve data from various url, querying each only once - def raw_info - logger = SsoLogger.new - - @raw_info ||= {} - logger.debug "[raw_info] @raw_infos = #{@raw_info&.to_json}" - unless @raw_info.size.positive? - OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings.each do |mapping| - logger.debug "mapping = #{mapping&.to_json}" - next if @raw_info.key?(mapping.api_endpoint.to_sym) - - logger.debug "api_endpoint = #{mapping.api_endpoint.to_sym}" - logger.debug "access_token = #{access_token&.to_json}" - logger.debug "token get = #{access_token.get(mapping.api_endpoint)}" - logger.debug "parsed = #{access_token.get(mapping.api_endpoint).parsed}" - @raw_info[mapping.api_endpoint.to_sym] = access_token.get(mapping.api_endpoint).parsed - end - end - @raw_info - end - - def parsed_info - mapped_info(OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings, raw_info) + def authorize_params + super.tap do |params| + params[:scope] = OmniAuth::Strategies::SsoOauth2Provider.active_provider.providable.scopes end end + + def callback_url + url = Rails.application.config.action_controller.default_url_options + "#{url[:protocol]}://#{url[:host]}#{script_name}#{callback_path}" + end + + uid { parsed_info[:'user.uid'] } + + info do + { + mapping: parsed_info + } + end + + extra do + { + raw_info: raw_info + } + end + + # retrieve data from various url, querying each only once + def raw_info + logger = SsoLogger.new + + @raw_info ||= {} + logger.debug "[raw_info] @raw_infos = #{@raw_info&.to_json}" + unless @raw_info.size.positive? + OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings.each do |mapping| + logger.debug "mapping = #{mapping&.to_json}" + next if @raw_info.key?(mapping.api_endpoint.to_sym) + + logger.debug "api_endpoint = #{mapping.api_endpoint.to_sym}" + logger.debug "access_token = #{access_token&.to_json}" + logger.debug "token get = #{access_token.get(mapping.api_endpoint)}" + logger.debug "parsed = #{access_token.get(mapping.api_endpoint).parsed}" + @raw_info[mapping.api_endpoint.to_sym] = access_token.get(mapping.api_endpoint).parsed + end + end + @raw_info + end + + def parsed_info + mapped_info(OmniAuth::Strategies::SsoOauth2Provider.active_provider.auth_provider_mappings, raw_info) + end end diff --git a/lib/omni_auth/strategies/sso_openid_connect_provider.rb b/lib/omni_auth/strategies/sso_openid_connect_provider.rb index 5f6b0b3bf..aa3c2c2c2 100644 --- a/lib/omni_auth/strategies/sso_openid_connect_provider.rb +++ b/lib/omni_auth/strategies/sso_openid_connect_provider.rb @@ -3,34 +3,32 @@ require 'omniauth_openid_connect' require_relative '../data_mapping/mapper' -module OmniAuth::Strategies - # Authentication strategy provided trough OpenID Connect - class SsoOpenidConnectProvider < OmniAuth::Strategies::OpenIDConnect - include OmniAuth::DataMapping::Mapper +# Authentication strategy provided trough OpenID Connect +class OmniAuth::Strategies::SsoOpenidConnectProvider < OmniAuth::Strategies::OpenIDConnect + include OmniAuth::DataMapping::Mapper - def self.active_provider - active_provider = AuthProvider.active - if active_provider.providable_type != OpenIdConnectProvider.name - raise "Trying to instantiate the wrong provider: Expected OpenIdConnectProvider, received #{active_provider.providable_type}" - end - - active_provider + def self.active_provider + active_provider = Rails.configuration.auth_provider + if active_provider.providable_type != 'OpenIdConnectProvider' + raise "Trying to instantiate the wrong provider: Expected OpenIdConnectProvider, received #{active_provider.providable_type}" end - # Strategy name. - option :name, active_provider.strategy_name + active_provider + end - info do - { - mapping: parsed_info - } - end + # Strategy name. + option :name, active_provider.strategy_name - def parsed_info - mapped_info( - OmniAuth::Strategies::SsoOpenidConnectProvider.active_provider.auth_provider_mappings, - user_info: user_info.raw_attributes - ) - end + info do + { + mapping: parsed_info + } + end + + def parsed_info + mapped_info( + OmniAuth::Strategies::SsoOpenidConnectProvider.active_provider.auth_provider_mappings, + user_info: user_info.raw_attributes + ) end end diff --git a/lib/pay_zen/helper.rb b/lib/pay_zen/helper.rb index d4ec3a303..47115d44b 100644 --- a/lib/pay_zen/helper.rb +++ b/lib/pay_zen/helper.rb @@ -21,7 +21,7 @@ class PayZen::Helper < Payment::Helper end def human_error(error) - I18n.t('errors.messages.gateway_error', { MESSAGE: error.message }) + I18n.t('errors.messages.gateway_error', **{ MESSAGE: error.message }) end ## generate an unique string reference for the content of a cart diff --git a/lib/pay_zen/pci/charge.rb b/lib/pay_zen/pci/charge.rb index 5e20573da..22ff07e5c 100644 --- a/lib/pay_zen/pci/charge.rb +++ b/lib/pay_zen/pci/charge.rb @@ -32,6 +32,4 @@ class PayZen::PCI::Charge < PayZen::Client device: device, paymentForms: payment_forms) end - end - diff --git a/lib/provider_config.rb b/lib/provider_config.rb new file mode 100644 index 000000000..47bbf4285 --- /dev/null +++ b/lib/provider_config.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +# Deals with the yml file keeping the configuration of the current authentication provider +class ProviderConfig + def initialize + @config = if File.exist?('config/auth_provider.yml') + YAML.safe_load_file('config/auth_provider.yml').with_indifferent_access + else + { + providable_type: 'DatabaseProvider', + name: 'DatabaseProvider::SimpleAuthProvider', + strategy_name: 'database-simpleauthprovider' + } + end + end + + def db + AuthProvider.find(@config[:id]) + end + + def oidc_config + return nil unless @config[:providable_type] == 'OpenIdConnectProvider' + + (@config[:providable_attributes].keys.filter { |n| !n.start_with?('client__') && n != 'profile_url' }.map do |n| + val = @config[:providable_attributes][n] + val.join(' ') if n == 'scope' + [n, val] + end).push( + ['client_options', @config[:providable_attributes].keys.filter { |n| n.start_with?('client__') }.to_h do |n| + [n.sub('client__', ''), @config[:providable_attributes][n]] + end] + ).to_h + end + + def method_missing(method, *args) + return map_value(@config[method]) if @config.key?(method) + + return map_value(@config["#{method}_attributes"]) if @config.key?("#{method}_attributes") + + super + end + + def respond_to_missing?(name) + @config.key?(name) || @config.key("#{name}_attributes") + end + + def self.write_active_provider + data = ApplicationController.render( + template: 'auth_provider/provider', + locals: { provider: AuthProvider.active }, + handlers: [:jbuilder], + formats: [:json] + ) + file_path = Rails.root.join('config/auth_provider.yml') + File.open(file_path, File::WRONLY | File::CREAT) do |file| + file.truncate(0) + file.write(JSON.parse(data).to_yaml) + end + end + + private + + def map_value(item) + return Struct.new(*item.symbolize_keys.keys).new(*item.values) if item.is_a?(Hash) + + return item.map { |v| map_value(v) } if item.is_a?(Array) + + item + end +end diff --git a/lib/sidekiq/server_locale.rb b/lib/sidekiq/server_locale.rb index 7add106a4..ec968042a 100644 --- a/lib/sidekiq/server_locale.rb +++ b/lib/sidekiq/server_locale.rb @@ -1,12 +1,14 @@ -module FabManager - module Middleware - class ServerLocale - def call(worker_class, job, queue) - locale = job['locale'] || Rails.application.secrets.rails_locale - I18n.with_locale(locale) do - yield - end - end +# frozen_string_literal: true + +# module definition +module FabManager::Middleware; end + +# Provides localization in workers +class FabManager::Middleware::ServerLocale + def call(_worker_class, job, _queue) + locale = job['locale'] || Rails.application.secrets.rails_locale + I18n.with_locale(locale) do + yield end end -end \ No newline at end of file +end diff --git a/lib/sso_logger.rb b/lib/sso_logger.rb index ddcf49fc4..333383315 100644 --- a/lib/sso_logger.rb +++ b/lib/sso_logger.rb @@ -2,9 +2,9 @@ # This class provides logging functionalities for SSO authentication class SsoLogger - def initialize() - @logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT)) - @log_status = ENV.fetch('SSO_DEBUG') { false } + def initialize + @logger = ActiveSupport::TaggedLogging.new(Logger.new($stdout)) + @log_status = ENV.fetch('SSO_DEBUG', false) end def debug(message) diff --git a/lib/stripe/helper.rb b/lib/stripe/helper.rb index 507ba8ba7..d7cc83ca9 100644 --- a/lib/stripe/helper.rb +++ b/lib/stripe/helper.rb @@ -25,14 +25,14 @@ class Stripe::Helper < Payment::Helper case error.code when 'amount_too_small' message.match(/\d+\.\d+\s\w+/) do |res| - message = I18n.t('errors.messages.gateway_amount_too_small', { AMOUNT: res }) + message = I18n.t('errors.messages.gateway_amount_too_small', **{ AMOUNT: res }) end when 'amount_too_large' message.match(/\d+\.\d+\s\w+/) do |res| - message = I18n.t('errors.messages.gateway_amount_too_large', { AMOUNT: res }) + message = I18n.t('errors.messages.gateway_amount_too_large', **{ AMOUNT: res }) end else - message = I18n.t('errors.messages.gateway_error', { MESSAGE: message }) + message = I18n.t('errors.messages.gateway_error', **{ MESSAGE: message }) end message end diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index ab8be6329..d1f4053df 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -1,23 +1,26 @@ # frozen_string_literal: false namespace :db do + # Usage example: + # RAILS_ENV=test rails db:to_fixtures[chained_elements] desc 'Convert development DB to Rails test fixtures' task :to_fixtures, [:table] => :environment do |_task, args| - TABLES_TO_SKIP = %w[ar_internal_metadata delayed_jobs schema_info schema_migrations].freeze + tables_to_skip = %w[ar_internal_metadata delayed_jobs schema_info schema_migrations].freeze begin ActiveRecord::Base.establish_connection ActiveRecord::Base.connection.tables.each do |table_name| - next if TABLES_TO_SKIP.include?(table_name) + next if tables_to_skip.include?(table_name) next if args.table && args.table != table_name - conter = '000' - file_path = "#{Rails.root}/test/fixtures/test/#{table_name}.yml" - File.open(file_path, 'w') do |file| + counter = '000' + file_path = Rails.root.join("test/fixtures/#{table_name}.yml") + File.open(file_path, File::WRONLY | File::CREAT) do |file| rows = ActiveRecord::Base.connection.select_all("SELECT * FROM #{table_name}") data = rows.each_with_object({}) do |record, hash| - suffix = record['id'].blank? ? conter.succ! : record['id'] - hash["#{table_name.singularize}_#{suffix}"] = record + suffix = record['id'].presence || counter.succ! + # FIXME, this is broken with jsonb columns: it records a String but a Hash must be saved + hash["#{table_name.singularize}#{suffix}"] = yamlize(record, rows.column_types) end puts "Writing table '#{table_name}' to '#{file_path}'" file.write(data.to_yaml) @@ -27,4 +30,10 @@ namespace :db do ActiveRecord::Base.connection&.close end end + + def yamlize(record, column_types) + record.each_with_object({}) do |(key, value), hash| + hash[key] = column_types.include?(key) && column_types[key].type == :jsonb ? JSON.parse(value) : value + end + end end diff --git a/lib/tasks/fablab/auth.rake b/lib/tasks/fablab/auth.rake index 9269a6771..adb20cc99 100644 --- a/lib/tasks/fablab/auth.rake +++ b/lib/tasks/fablab/auth.rake @@ -3,7 +3,6 @@ # SSO and authentication relative tasks namespace :fablab do namespace :auth do - desc 'switch the active authentication provider' task :switch_provider, [:provider] => :environment do |_task, args| providers = AuthProvider.all.inject('') { |str, item| "#{str}#{item[:name]}, " } @@ -24,24 +23,28 @@ namespace :fablab do # disable previous provider prev_prev = AuthProvider.previous - prev_prev&.update_attribute(:status, 'pending') + prev_prev&.update(status: 'pending') - AuthProvider.active.update_attribute(:status, 'previous') unless AuthProvider.active.name == 'DatabaseProvider::SimpleAuthProvider' + AuthProvider.active.update(status: 'previous') unless AuthProvider.active.name == 'DatabaseProvider::SimpleAuthProvider' # enable given provider - AuthProvider.find_by(name: args.provider).update_attribute(:status, 'active') + AuthProvider.find_by(name: args.provider).update(status: 'active') # migrate the current users. if AuthProvider.active.providable_type == DatabaseProvider.name User.all.each do |user| # Concerns local database provider - user.update_attribute(:auth_token, nil) + user.update(auth_token: nil) end else # Concerns any providers except local database User.all.each(&:generate_auth_migration_token) end + # write the configuration to file + require 'provider_config' + ProviderConfig.write_active_provider + # ask the user to restart the application next if Rails.env.test? @@ -54,7 +57,6 @@ namespace :fablab do desc 'notify users that the auth provider has changed' task notify_changed: :environment do - I18n.locale = I18n.default_locale # notify every users if the provider is not local database provider @@ -73,5 +75,11 @@ namespace :fablab do task current: :environment do puts "Current active authentication provider: #{AuthProvider.active.name}" end + + desc 'write the provider config to a configuration file' + task write_provider: :environment do + require 'provider_config' + ProviderConfig.write_active_provider + end end end diff --git a/lib/tasks/fablab/chain.rake b/lib/tasks/fablab/chain.rake index 324ae3fe4..1f06b93eb 100644 --- a/lib/tasks/fablab/chain.rake +++ b/lib/tasks/fablab/chain.rake @@ -6,7 +6,7 @@ namespace :fablab do task :all, [:force] => :environment do |_task, args| if Invoice.where.not(footprint: nil).count.positive? && args.force != 'force' print 'All footprints will be regenerated. Are you sure? (y/n) ' - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end chain_invoices @@ -17,12 +17,11 @@ namespace :fablab do chain_payment_schedules_objects if ActiveRecord::Base.connection.table_exists? PaymentScheduleObject.arel_table end - desc 'assign all footprints to existing Invoice records' task invoices: :environment do if Invoice.where.not(footprint: nil).count.positive? print 'WARNING: Footprints were already generated. Regenerate? (y/n) ' - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end chain_invoices @@ -32,10 +31,10 @@ namespace :fablab do if AccountingPeriod.count.positive? last_period = AccountingPeriod.order(start_at: :desc).first puts "Regenerating from #{last_period.end_at}..." - Invoice.where('created_at > ?', last_period.end_at).order(:id).each(&:chain_record) + Invoice.where('created_at > ?', last_period.end_at).order(:id).find_each(&:chain_record) else puts '(Re)generating all footprint...' - Invoice.order(:id).all.each(&:chain_record) + Invoice.order(:id).find_each(&:chain_record) end end @@ -43,7 +42,7 @@ namespace :fablab do task invoices_items: :environment do if InvoiceItem.where.not(footprint: nil).count.positive? print 'WARNING: Footprints were already generated. Regenerate? (y/n) ' - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end chain_invoice_items @@ -53,10 +52,10 @@ namespace :fablab do if AccountingPeriod.count.positive? last_period = AccountingPeriod.order(start_at: :desc).first puts "Regenerating from #{last_period.end_at}..." - InvoiceItem.where('created_at > ?', last_period.end_at).order(:id).each(&:chain_record) + InvoiceItem.where('created_at > ?', last_period.end_at).order(:id).find_each(&:chain_record) else puts '(Re)generating all footprint...' - InvoiceItem.order(:id).all.each(&:chain_record) + InvoiceItem.order(:id).find_each(&:chain_record) end end @@ -64,21 +63,21 @@ namespace :fablab do task history_values: :environment do if HistoryValue.where.not(footprint: nil).count.positive? print 'WARNING: Footprints were already generated. Regenerate? (y/n) ' - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end chain_history_values end def chain_history_values - HistoryValue.order(:created_at).all.each(&:chain_record) + HistoryValue.order(:created_at).find_each(&:chain_record) end desc 'assign all footprints to existing PaymentSchedule records' task payment_schedule: :environment do if PaymentSchedule.where.not(footprint: nil).count.positive? print 'WARNING: Footprints were already generated. Regenerate? (y/n) ' - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end chain_payment_schedules @@ -88,10 +87,10 @@ namespace :fablab do if AccountingPeriod.count.positive? last_period = AccountingPeriod.order(start_at: :desc).first puts "Regenerating from #{last_period.end_at}..." - PaymentSchedule.where('created_at > ?', last_period.end_at).order(:id).each(&:chain_record) + PaymentSchedule.where('created_at > ?', last_period.end_at).order(:id).find_each(&:chain_record) else puts '(Re)generating all footprint...' - PaymentSchedule.order(:id).all.each(&:chain_record) + PaymentSchedule.order(:id).find_each(&:chain_record) end end @@ -99,7 +98,7 @@ namespace :fablab do task payment_schedule_item: :environment do if PaymentScheduleItem.where.not(footprint: nil).count.positive? print 'WARNING: Footprints were already generated. Regenerate? (y/n) ' - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end chain_payment_schedules_items @@ -109,10 +108,10 @@ namespace :fablab do if AccountingPeriod.count.positive? last_period = AccountingPeriod.order(start_at: :desc).first puts "Regenerating from #{last_period.end_at}..." - PaymentScheduleItem.where('created_at > ?', last_period.end_at).order(:id).each(&:chain_record) + PaymentScheduleItem.where('created_at > ?', last_period.end_at).order(:id).find_each(&:chain_record) else puts '(Re)generating all footprint...' - PaymentScheduleItem.order(:id).all.each(&:chain_record) + PaymentScheduleItem.order(:id).find_each(&:chain_record) end end @@ -120,7 +119,7 @@ namespace :fablab do task payment_schedule_object: :environment do if PaymentScheduleObject.where.not(footprint: nil).count.positive? print 'WARNING: Footprints were already generated. Regenerate? (y/n) ' - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end chain_payment_schedules_objects @@ -130,10 +129,10 @@ namespace :fablab do if AccountingPeriod.count.positive? last_period = AccountingPeriod.order(start_at: :desc).first puts "Regenerating from #{last_period.end_at}..." - PaymentScheduleObject.where('created_at > ?', last_period.end_at).order(:id).each(&:chain_record) + PaymentScheduleObject.where('created_at > ?', last_period.end_at).order(:id).find_each(&:chain_record) else puts '(Re)generating all footprint...' - PaymentScheduleObject.order(:id).all.each(&:chain_record) + PaymentScheduleObject.order(:id).find_each(&:chain_record) end end end diff --git a/lib/tasks/fablab/fix.rake b/lib/tasks/fablab/fix.rake index f80401da9..507f4ab56 100644 --- a/lib/tasks/fablab/fix.rake +++ b/lib/tasks/fablab/fix.rake @@ -291,7 +291,7 @@ namespace :fablab do InvoiceItem.where(object_type: 'Error').update_all(object_id: 0) # rubocop:disable Rails/SkipsModelValidations - Fablab::Application.load_tasks if Rake::Task.tasks.empty? + FabManager::Application.load_tasks if Rake::Task.tasks.empty? Rake::Task['fablab:chain:invoices_items'].invoke end diff --git a/lib/tasks/fablab/fix_references.rake b/lib/tasks/fablab/fix_references.rake new file mode 100644 index 000000000..1d598ae5d --- /dev/null +++ b/lib/tasks/fablab/fix_references.rake @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +namespace :fablab do + desc 'Fill the holes in the logical sequence of invoices references' + task fix_references: :environment do |_task, _args| + include ActionView::Helpers::NumberHelper + include DbHelper + + user = User.adminsys || User.admins.first + + ActiveRecord::Base.transaction do + missing_references = {} + + # browse invoices to list missing reference + puts 'Computing missing references...' + not_closed(Invoice).find_each do |invoice| + number = Invoices::NumberService.number(invoice) + next if number == 1 + + previous = Invoice.where('created_at < :date', date: db_time(invoice.created_at)) + .order(created_at: :desc) + .limit(1) + .first + previous_saved_number = Invoices::NumberService.number(previous) + previous_number = number - 1 + loop do + break if previous_number.zero? || previous_number == previous_saved_number + + previous_invoice = Invoices::NumberService.find_by_number(previous_number, date: invoice.created_at) + break if previous_invoice.present? + + missing_references[invoice.created_at] ||= [] + missing_references[invoice.created_at].push(previous_number) + + previous_number -= 1 + end + end + + # create placeholder invoices for found missing references + puts 'Creating missing invoices...' + total = missing_references.values.filter(&:present?).flatten.count + counter = 1 + missing_references.each_pair do |date, numbers| + numbers.each_with_index do |number, index| + print "#{counter} / #{total}\r" + invoice = Invoice.new( + total: 0, + invoicing_profile: user.invoicing_profile, + statistic_profile: user.statistic_profile, + operator_profile: user.invoicing_profile, + payment_method: '', + created_at: date - (index + 1).seconds, + invoice_items_attributes: [{ + amount: 0, + description: I18n.t('invoices.null_invoice'), + object_type: 'Error', + object_id: 1, + main: true + }] + ) + invoice.reference = PaymentDocumentService.generate_numbered_reference(number, invoice) + invoice.save! + counter += 1 + end + end + print "\n" + end + end + + # @param klass [Class] + # @return [ActiveRecord::Relation,Class] + def not_closed(klass) + if AccountingPeriod.count.positive? + last_period = AccountingPeriod.order(start_at: :desc).first + klass.where('created_at > ?', last_period.end_at) + else + klass + end + end +end diff --git a/lib/tasks/fablab/maintenance.rake b/lib/tasks/fablab/maintenance.rake index 7d1658fa9..23a6dc4f7 100644 --- a/lib/tasks/fablab/maintenance.rake +++ b/lib/tasks/fablab/maintenance.rake @@ -89,13 +89,17 @@ namespace :fablab do desc 'save the footprint original data' task save_footprint_data: :environment do - [Invoice, InvoiceItem, HistoryValue, PaymentSchedule, PaymentScheduleItem].each do |klass| - klass.all.each do |item| - FootprintDebug.create!( - footprint: item.footprint, - data: FootprintService.footprint_data(klass, item), - klass: klass + [Invoice, InvoiceItem, HistoryValue, PaymentSchedule, PaymentScheduleItem, PaymentScheduleObject].each do |klass| + next if klass == PaymentScheduleObject && !ActiveRecord::Base.connection.table_exists?(PaymentScheduleObject.arel_table) + + order = klass == HistoryValue ? :created_at : :id + previous = nil + klass.order(order).find_each do |item| + created = ChainedElement.create!( + element: item, + previous: previous ) + previous = created end end end diff --git a/lib/tasks/fablab/payzen.rake b/lib/tasks/fablab/payzen.rake index 89316adb3..92219fa00 100644 --- a/lib/tasks/fablab/payzen.rake +++ b/lib/tasks/fablab/payzen.rake @@ -3,7 +3,6 @@ # PayZen relative tasks namespace :fablab do namespace :payzen do - # example: rails fablab:payzen:replay_on_payment_success[54a35f3f6fdd729ac72b6da0,53,57,3,247] # to find the parameters, search the logs, example: # Started POST "/api/payzen/confirm_payment" for 93.27.29.108 at 2022-04-04 20:26:12 +0000 @@ -22,7 +21,7 @@ namespace :fablab do # ], "payment_method"=>"card"}, "order_id"=>"704cc55e23f00ac3d238d8de"}} desc 'replay PayzenController#on_payment_success for a given event' task :replay_on_payment_success, %i[gateway_item_id user_id event_id nb_reserve_places slot_id] => :environment do |_task, args| - ActiveRecord::Base.logger = Logger.new STDOUT + ActiveRecord::Base.logger = Logger.new $stdout gateway_item_type = 'PayZen::Order' diff --git a/lib/tasks/fablab/restore_order_number.rake b/lib/tasks/fablab/restore_order_number.rake new file mode 100644 index 000000000..fa785b00f --- /dev/null +++ b/lib/tasks/fablab/restore_order_number.rake @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +namespace :fablab do + desc 'Scans PDF files of invoices to find order numbers' + task restore_order_number: :environment do |_task, _args| + order_text = [ + I18n.t('invoices.order_number', **{ NUMBER: 'REPLACE' }).gsub('REPLACE', ''), + I18n.t('invoices.order_number', locale: 'en', **{ NUMBER: 'REPLACE' }).gsub('REPLACE', ''), + I18n.t('invoices.order_number', locale: 'fr', **{ NUMBER: 'REPLACE' }).gsub('REPLACE', '') + ] + max_id = ActiveRecord::Base.connection.execute('SELECT max(id) as max_id FROM invoices').first['max_id'] + Invoice.order(id: :asc).find_each do |invoice| + print "Processing: #{invoice.id} / #{max_id}\r" + next unless File.exist?(invoice.file) + + found = false + reader = PDF::Reader.new(invoice.file) + page = reader.pages.first + page.text.scan(/^.+/).each do |line| + next unless order_text.any? { |label| line.include? label } + break if found + + order_text.each do |label| + next unless line.include? label + + number = line.gsub(label, '').gsub(/\s{5,}.+$/, '').strip + invoice.update(order_number: number) + found = true + end + end + end + print "\nRestoring the store orders numbers...\n" + Order.where(reference: nil).order(id: :asc).find_each do |order| + order.update(reference: PaymentDocumentService.generate_order_number(order)) + end + puts 'Filling the gaps for invoices numbers...' + max = Invoice.where(order_number: nil).count + Invoice.where(order_number: nil).order(id: :asc).find_each.with_index do |invoice, index| + print "Processing: #{index} / #{max}\r" + next unless invoice.payment_schedule_item.nil? + + unless invoice.order.nil? + invoice.update(order_number: invoice.order.reference) + next + end + + invoice.update(order_number: PaymentDocumentService.generate_order_number(invoice)) + end + puts 'Restoring the payment schedules numbers...' + PaymentSchedule.order(id: :asc).find_each do |schedule| + schedule.update(order_number: PaymentDocumentService.generate_order_number(schedule)) + schedule.ordered_items.each do |item| + item.invoice&.update(order_number: schedule.order_number) + end + end + puts 'Restoring the refund invoices numbers...' + Avoir.where(order_number: nil).order(id: :asc).find_each do |refund| + next if refund.invoice.nil? + + # refunds are validated against their avoir_date for inclusion in closed periods, so we must bypass the validation + # (Invoices are validated on Time.current, so this was not necesseary above) + refund.update_attribute('order_number', refund.invoice.order_number) # rubocop:disable Rails/SkipsModelValidations + end + end +end diff --git a/lib/tasks/fablab/setup.rake b/lib/tasks/fablab/setup.rake index aac3c23e9..b685a284f 100644 --- a/lib/tasks/fablab/setup.rake +++ b/lib/tasks/fablab/setup.rake @@ -20,7 +20,7 @@ namespace :fablab do setting_id: setting.id, user_id: User.admins.first.id, value: 'false', - created_at: DateTime.parse(args.date) + created_at: Time.zone.parse(args.date) ) else setting = Setting.find_by(name: 'invoice_VAT-rate') @@ -28,7 +28,7 @@ namespace :fablab do setting_id: setting.id, user_id: User.admins.first.id, value: args.rate, - created_at: DateTime.parse(args.date) + created_at: Time.zone.parse(args.date) ) end end @@ -120,15 +120,15 @@ namespace :fablab do Group.find_by(slug: 'admins').destroy if Setting.get('user_validation_required') print "\e[91m::\e[0m \e[1mValidating the 'admins'...\e[0m\n" - User.admins.each { |admin| admin.update(validated_at: DateTime.current) if admin.validated_at.nil? } + User.admins.each { |admin| admin.update(validated_at: Time.current) if admin.validated_at.nil? } end print "\e[32m✅\e[0m \e[1mDone\e[0m\n" end desc 'generate acconting lines' task build_accounting_lines: :environment do - start_date = Invoice.order(created_at: :asc).first&.created_at || DateTime.current - end_date = DateTime.current + start_date = Invoice.order(created_at: :asc).first&.created_at || Time.current + end_date = Time.current AccountingLine.where(date: start_date..end_date).destroy_all Accounting::AccountingService.new.build(start_date&.beginning_of_day, end_date.end_of_day) puts '-> Done' diff --git a/lib/tasks/fablab/stripe.rake b/lib/tasks/fablab/stripe.rake index c8bba5466..b29c32b5c 100644 --- a/lib/tasks/fablab/stripe.rake +++ b/lib/tasks/fablab/stripe.rake @@ -3,7 +3,6 @@ # Stripe relative tasks namespace :fablab do namespace :stripe do - desc 'find any invoices with incoherent total between stripe and DB' task :find_incoherent_invoices, [:start_date] => :environment do |_task, args| puts 'DEPRECATION WARNING: Will not work for invoices created from version 4.1.0 and above' @@ -61,8 +60,9 @@ namespace :fablab do desc 'set stripe as the default payment gateway' task set_gateway: :environment do - if Setting.find_by(name: 'stripe_public_key').try(:value) && Setting.find_by(name: 'stripe_secret_key').try(:value) - Setting.set('payment_gateway', 'stripe') unless Setting.find_by(name: 'payment_gateway').try(:value) + if Setting.find_by(name: 'stripe_public_key').try(:value) && Setting.find_by(name: 'stripe_secret_key').try(:value) && + !Setting.find_by(name: 'payment_gateway').try(:value) + Setting.set('payment_gateway', 'stripe') end end @@ -72,7 +72,7 @@ namespace :fablab do task reset_cards: :environment do unless Rails.env.test? print "You're about to detach all payment cards from all customers. This was only made for test mode. Are you sure? (y/n) " - confirm = STDIN.gets.chomp + confirm = $stdin.gets.chomp next unless confirm == 'y' end User.all.each do |user| diff --git a/package.json b/package.json index 368690a3a..5baf878d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "5.9.1", + "version": "6.0.0", "description": "Fab-manager is the FabLab management solution. It provides a comprehensive, web-based, open-source tool to simplify your administrative tasks and your marker's projects.", "keywords": [ "fablab", @@ -151,8 +151,7 @@ "ngUpload": "0.5", "ngtemplate-loader": "^2.1.0", "nvd3": "1.8", - "object-to-formdata": "npm:object-to-formdata-tz@4.4.3", - "object-to-formdata-tz": "4.4.3", + "object-to-formdata-tz": "^4.4.3", "phosphor-react": "^1.4.0", "process": "^0.11.10", "prop-types": "^15.7.2", @@ -172,11 +171,12 @@ "resolve-url-loader": "^4.0.0", "sass": "^1.49.9", "sass-loader": "^12.6.0", - "shakapacker": "6.5.5", + "shakapacker": "6.6.0", "slugify": "^1.6.5", "sortablejs": "^1.15.0", "style-loader": "^3.3.1", "summernote": "0.8.18", + "terser": "^5.7.2", "terser-webpack-plugin": "5", "twitter-fetcher": "^18.0.2", "typescript": "^4.6.3", diff --git a/scripts/mount-auth-provider.sh b/scripts/mount-auth-provider.sh new file mode 100644 index 000000000..cb1b8dd67 --- /dev/null +++ b/scripts/mount-auth-provider.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +yq() { + docker run --rm -i -v "${PWD}:/workdir" --user "$UID" mikefarah/yq:4 "$@" +} + +config() +{ + echo -ne "Checking user... " + if [[ "$(whoami)" != "root" ]] && ! groups | grep docker + then + echo "Please add your current user to the docker group OR run this script as root." + echo "current user is not allowed to use docker, exiting..." + exit 1 + fi + SERVICE="$(yq eval '.services.*.image | select(. == "sleede/fab-manager*") | path | .[-2]' docker-compose.yml)" + echo -e "\n" +} + +add_mount() +{ + if [[ ! $(yq eval ".services.$SERVICE.volumes.[] | select (. == \"*auth_provider.yml\")" docker-compose.yml) ]]; then + # change docker-compose.yml permissions for fix yq can't modify file issue + chmod 666 docker-compose.yml + yq -i eval ".services.$SERVICE.volumes += [\"./config/auth_provider.yml:/usr/src/app/auth_provider.yml\"]" docker-compose.yml + chmod 644 docker-compose.yml + fi +} + +proceed() +{ + config + add_mount +} + +proceed "$@" diff --git a/scripts/tests.sh b/scripts/tests.sh index 836088631..981a635b2 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -5,6 +5,10 @@ stripe_public_key=$(RAILS_ENV='test' bin/rails runner "puts ENV['STRIPE_PUBLISHABLE_KEY']") stripe_secret_key=$(RAILS_ENV='test' bin/rails runner "puts ENV['STRIPE_API_KEY']") +oauth2_client_id=$(RAILS_ENV='test' bin/rails runner "puts ENV['OAUTH_CLIENT_ID']") +oauth2_client_secret=$(RAILS_ENV='test' bin/rails runner "puts ENV['OAUTH_CLIENT_SECRET']") +oidc_client_id=$(RAILS_ENV='test' bin/rails runner "puts ENV['OIDC_CLIENT_ID']") +oidc_client_secret=$(RAILS_ENV='test' bin/rails runner "puts ENV['OIDC_CLIENT_SECRET']") if [[ -z "$stripe_public_key" ]]; then read -rp "STRIPE_PUBLISHABLE_KEY is not set. Please input the public key now. > " stripe_public_key " stripe_secret_key " oauth2_client_id " oauth2_client_secret " oidc_client_id " oidc_client_secret 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: training created_at: 2016-04-04 15:24:01.517486000 Z updated_at: 2016-04-04 15:24:01.517486000 Z @@ -11,8 +11,8 @@ availability_1: availability_2: id: 2 - start_at: <%= (DateTime.current + 1.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: training created_at: 2016-04-04 15:24:09.169364000 Z updated_at: 2016-04-04 15:24:09.169364000 Z @@ -21,8 +21,8 @@ availability_2: availability_3: id: 3 - start_at: <%= DateTime.current.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:24:27.587583000 Z updated_at: 2016-04-04 15:24:27.587583000 Z @@ -31,8 +31,8 @@ availability_3: availability_4: id: 4 - start_at: <%= (DateTime.current + 1.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:24:44.044908000 Z updated_at: 2016-04-04 15:24:44.044908000 Z @@ -41,8 +41,8 @@ availability_4: availability_5: id: 5 - start_at: <%= (DateTime.current + 2.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:25:48.584444000 Z updated_at: 2016-04-04 15:25:48.584444000 Z @@ -51,8 +51,8 @@ availability_5: availability_6: id: 6 - start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:26:17.953216000 Z updated_at: 2016-04-04 15:26:17.953216000 Z @@ -61,8 +61,8 @@ availability_6: availability_7: id: 7 - start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:26:39.278627000 Z updated_at: 2016-04-04 15:26:39.278627000 Z @@ -71,8 +71,8 @@ availability_7: availability_8: id: 8 - start_at: <%= (DateTime.current + 2.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: training created_at: 2016-04-04 15:26:49.572724000 Z updated_at: 2016-04-04 15:26:49.572724000 Z @@ -132,8 +132,8 @@ availability_13: availability_14: id: 14 - start_at: <%= 20.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 20.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 20.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 20.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:44:04.023557000 Z updated_at: 2016-04-04 15:44:04.023557000 Z @@ -142,8 +142,8 @@ availability_14: availability_15: id: 15 - start_at: <%= 40.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 40.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 40.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 40.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:44:04.023557000 Z updated_at: 2016-04-04 15:44:04.023557000 Z @@ -152,8 +152,8 @@ availability_15: availability_16: id: 16 - start_at: <%= 80.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 80.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 80.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 80.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2016-04-04 15:44:04.023557000 Z updated_at: 2016-04-04 15:44:04.023557000 Z @@ -162,8 +162,8 @@ availability_16: availability_17: id: 17 - start_at: <%= 10.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 12.days.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 10.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 12.days.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: event created_at: 2016-04-04 15:44:04.023557000 Z updated_at: 2016-04-04 15:44:04.023557000 Z @@ -172,8 +172,8 @@ availability_17: availability_18: id: 18 - start_at: <%= 2.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 2.days.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 2.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 2.days.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: space created_at: 2017-02-15 15:53:35.154433000 Z updated_at: 2017-02-15 15:53:35.154433000 Z @@ -182,8 +182,8 @@ availability_18: availability_19: id: 19 - start_at: <%= 1.day.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: machines created_at: 2017-02-15 15:53:35.154433000 Z updated_at: 2017-02-15 15:53:35.154433000 Z @@ -192,8 +192,8 @@ availability_19: availability_20: id: 20 - start_at: <%= 10.days.ago.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 10.days.ago.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 10.days.ago.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 10.days.ago.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: training created_at: 2022-07-18 12:38:21.616510000 Z updated_at: 2022-07-18 12:38:21.616510000 Z @@ -202,8 +202,8 @@ availability_20: availability_21: id: 21 - start_at: <%= 10.minutes.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (10.minutes.from_now + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 10.minutes.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (10.minutes.from_now + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: space created_at: 2022-12-14 12:01:26.165110000 Z updated_at: 2022-12-14 12:01:26.165110000 Z @@ -212,8 +212,8 @@ availability_21: availability_22: id: 22 - start_at: <%= 1.hour.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 2.hours.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.hour.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 2.hours.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> available_type: training created_at: 2023-01-24 13:34:43.841240000 Z updated_at: 2023-01-24 13:34:43.841240000 Z diff --git a/test/fixtures/chained_elements.yml b/test/fixtures/chained_elements.yml new file mode 100644 index 000000000..1491e91fc --- /dev/null +++ b/test/fixtures/chained_elements.yml @@ -0,0 +1,3100 @@ +--- +chained_element1: + id: 1 + element_type: Invoice + element_id: 1 + previous_id: + content: + id: 1 + total: 10000 + previous: + reference: 1203001/VL + created_at: '2012-03-12T12:03:31+01:00' + environment: test + payment_method: card + operator_profile_id: 3 + invoicing_profile_id: 3 + statistic_profile_id: 3 + footprint: 66e347f8f85d25ab9ff93f3817ff08fe6cbff5fcdf2bb1687045aec79500aa36 + created_at: 2023-03-27 08:47:57.741808000 Z + updated_at: 2023-03-27 08:47:57.741808000 Z +chained_element2: + id: 2 + element_type: Invoice + element_id: 2 + previous_id: 1 + content: + id: 2 + total: 2000 + previous: 66e347f8f85d25ab9ff93f3817ff08fe6cbff5fcdf2bb1687045aec79500aa36 + reference: '1203002' + created_at: '2012-03-12T14:40:22+01:00' + environment: test + operator_profile_id: 1 + invoicing_profile_id: 4 + statistic_profile_id: 4 + footprint: 9fdd39efc9acb056dddf1e1da675d56ee905766dfae7227060223aff162adccd + created_at: 2023-03-27 08:47:57.745527000 Z + updated_at: 2023-03-27 08:47:57.745527000 Z +chained_element3: + id: 3 + element_type: Invoice + element_id: 3 + previous_id: 2 + content: + id: 3 + total: 3000 + previous: 9fdd39efc9acb056dddf1e1da675d56ee905766dfae7227060223aff162adccd + reference: '1203001' + created_at: '2015-06-10T13:20:01+02:00' + environment: test + operator_profile_id: 1 + invoicing_profile_id: 7 + statistic_profile_id: 7 + footprint: 2904154ead103b56e11b30988924a276c3dfab760ee1c817187828b58a7337d9 + created_at: 2023-03-27 08:47:57.747457000 Z + updated_at: 2023-03-27 08:47:57.747457000 Z +chained_element4: + id: 4 + element_type: Invoice + element_id: 4 + previous_id: 3 + content: + id: 4 + total: 0 + previous: 2904154ead103b56e11b30988924a276c3dfab760ee1c817187828b58a7337d9 + reference: '1604002' + created_at: '2016-04-05T10:35:52+02:00' + environment: test + operator_profile_id: 1 + invoicing_profile_id: 7 + statistic_profile_id: 7 + footprint: b1ceaaee9fc9477282a5963475c602e469e564207e7be3b1e3e35cac59d7ec2c + created_at: 2023-03-27 08:47:57.749415000 Z + updated_at: 2023-03-27 08:47:57.749415000 Z +chained_element5: + id: 5 + element_type: Invoice + element_id: 5 + previous_id: 4 + content: + id: 5 + total: 1500 + previous: b1ceaaee9fc9477282a5963475c602e469e564207e7be3b1e3e35cac59d7ec2c + reference: '1604031' + created_at: '2016-04-05T10:36:46+02:00' + environment: test + operator_profile_id: 1 + invoicing_profile_id: 3 + statistic_profile_id: 3 + footprint: 7b5314374cb1c58ce5c13d223b535ec0a1424c96c44dc03270a772b4adfd5f10 + created_at: 2023-03-27 08:47:57.751659000 Z + updated_at: 2023-03-27 08:47:57.751659000 Z +chained_element6: + id: 6 + element_type: Invoice + element_id: 6 + previous_id: 5 + content: + id: 6 + total: 3000 + previous: 7b5314374cb1c58ce5c13d223b535ec0a1424c96c44dc03270a772b4adfd5f10 + reference: '2101041' + created_at: '2021-01-04T15:51:21+01:00' + environment: test + operator_profile_id: 1 + invoicing_profile_id: 8 + statistic_profile_id: 8 + footprint: 928171b5571ccbd7dbe92d019fe226a97199cfe4a6f610a3cfd9cf03ca24a457 + created_at: 2023-03-27 08:47:57.754703000 Z + updated_at: 2023-03-27 08:47:57.754703000 Z +chained_element7: + id: 7 + element_type: Invoice + element_id: 5811 + previous_id: 6 + content: + id: 5811 + total: 4500 + previous: 928171b5571ccbd7dbe92d019fe226a97199cfe4a6f610a3cfd9cf03ca24a457 + reference: '2209002' + created_at: '2022-09-20T17:14:22+02:00' + environment: development + payment_method: local + operator_profile_id: 1 + invoicing_profile_id: 3 + statistic_profile_id: 3 + footprint: 20eaa314e9414f98ec88ec6de886e747129c8c57b85a59a5ec9ac78478ebdf9c + created_at: 2023-03-27 08:47:57.756663000 Z + updated_at: 2023-03-27 08:47:57.756663000 Z +chained_element8: + id: 8 + element_type: Invoice + element_id: 5812 + previous_id: 7 + content: + id: 5812 + total: 6000 + previous: 20eaa314e9414f98ec88ec6de886e747129c8c57b85a59a5ec9ac78478ebdf9c + reference: '2209004' + created_at: '2022-09-20T17:14:48+02:00' + environment: development + payment_method: local + operator_profile_id: 1 + invoicing_profile_id: 7 + statistic_profile_id: 7 + footprint: 19fdbb15449a4f78ab3287842149683bea77b2e54f78c7520b57015d01da65a6 + created_at: 2023-03-27 08:47:57.758392000 Z + updated_at: 2023-03-27 08:47:57.758392000 Z +chained_element9: + id: 9 + element_type: Invoice + element_id: 5816 + previous_id: 8 + content: + id: 5816 + total: 319 + previous: 19fdbb15449a4f78ab3287842149683bea77b2e54f78c7520b57015d01da65a6 + reference: 2210002/VL + created_at: '2022-10-04T14:36:03+02:00' + environment: development + payment_method: card + operator_profile_id: 4 + invoicing_profile_id: 4 + statistic_profile_id: 4 + footprint: 7e1490c32824a1ecae67837dbc3c6307f69466cb1b700df39c4e724260f16315 + created_at: 2023-03-27 08:47:57.760357000 Z + updated_at: 2023-03-27 08:47:57.760357000 Z +chained_element10: + id: 10 + element_type: Invoice + element_id: 5817 + previous_id: 9 + content: + id: 5817 + total: 1295 + previous: 7e1490c32824a1ecae67837dbc3c6307f69466cb1b700df39c4e724260f16315 + coupon_id: 30 + reference: 2210004/VL + created_at: '2022-10-04T15:54:42+02:00' + environment: development + payment_method: card + operator_profile_id: 4 + invoicing_profile_id: 4 + statistic_profile_id: 4 + footprint: 0e43498e4187741ca8f6aff257d976e2fec571cdfc8bc003cb94c087bcd359e7 + created_at: 2023-03-27 08:47:57.762274000 Z + updated_at: 2023-03-27 08:47:57.762274000 Z +chained_element11: + id: 11 + element_type: Invoice + element_id: 5818 + previous_id: 10 + content: + id: 5818 + total: 1000 + previous: 0e43498e4187741ca8f6aff257d976e2fec571cdfc8bc003cb94c087bcd359e7 + reference: 2210006/VL + created_at: '2022-10-04T16:04:12+02:00' + environment: development + payment_method: card + operator_profile_id: 4 + invoicing_profile_id: 4 + statistic_profile_id: 4 + footprint: cdf79c0c7ca29c1401fbb193e890c94db9b9b7ba37fd7a97b3b932b86dd6349a + created_at: 2023-03-27 08:47:57.764315000 Z + updated_at: 2023-03-27 08:47:57.764315000 Z +chained_element12: + id: 12 + element_type: Invoice + element_id: 5819 + previous_id: 11 + content: + id: 5819 + total: 4002 + previous: cdf79c0c7ca29c1401fbb193e890c94db9b9b7ba37fd7a97b3b932b86dd6349a + reference: 2210008/VL + created_at: '2022-10-04T16:17:52+02:00' + environment: development + payment_method: card + operator_profile_id: 4 + invoicing_profile_id: 4 + statistic_profile_id: 4 + footprint: 790973554a2c41c81fbf1af0d42ed8bae4211359b7b9ab047954b74ec547cadd + created_at: 2023-03-27 08:47:57.766298000 Z + updated_at: 2023-03-27 08:47:57.766298000 Z +chained_element13: + id: 13 + element_type: Invoice + element_id: 5820 + previous_id: 12 + content: + id: 5820 + total: 12000 + previous: 790973554a2c41c81fbf1af0d42ed8bae4211359b7b9ab047954b74ec547cadd + reference: '2210010' + created_at: '2022-10-04T16:25:37+02:00' + environment: development + payment_method: local + operator_profile_id: 1 + invoicing_profile_id: 3 + statistic_profile_id: 3 + footprint: 8c4d8f85ec92599bdf0560bbf381dadd455969f160dc7f67c59b438c9a2103fb + created_at: 2023-03-27 08:47:57.768271000 Z + updated_at: 2023-03-27 08:47:57.768271000 Z +chained_element14: + id: 14 + element_type: Invoice + element_id: 5821 + previous_id: 13 + content: + id: 5821 + total: 12000 + previous: 8c4d8f85ec92599bdf0560bbf381dadd455969f160dc7f67c59b438c9a2103fb + reference: '2210012' + created_at: '2022-10-04T16:32:28+02:00' + environment: development + payment_method: local + operator_profile_id: 1 + invoicing_profile_id: 2 + statistic_profile_id: 2 + footprint: 34805fb1cf4971a7c96d89a9b4a6e8d8dc149571b8424c8dbb2a9ae3eb688d97 + created_at: 2023-03-27 08:47:57.770153000 Z + updated_at: 2023-03-27 08:47:57.770153000 Z +chained_element15: + id: 15 + element_type: Invoice + element_id: 5822 + previous_id: 14 + content: + id: 5822 + total: 3000 + previous: 34805fb1cf4971a7c96d89a9b4a6e8d8dc149571b8424c8dbb2a9ae3eb688d97 + reference: '2210014' + created_at: '2022-10-04T16:35:40+02:00' + environment: development + payment_method: local + operator_profile_id: 1 + invoicing_profile_id: 2 + statistic_profile_id: 2 + footprint: 30d2688fa79772a085d676c5844186c22b0908bcc6aabd1ed17029dbbd525002 + created_at: 2023-03-27 08:47:57.772081000 Z + updated_at: 2023-03-27 08:47:57.772081000 Z +chained_element16: + id: 16 + element_type: InvoiceItem + element_id: 1 + previous_id: + content: + id: 1 + main: true + amount: 10000 + previous: + object_id: 1 + created_at: '2012-03-12T12:03:31+01:00' + invoice_id: 1 + description: Sleede - standard, association - month + object_type: Subscription + footprint: 1c5bb78cc1b313eb3d2e345addc0a9d003e467f3dc80e943a2242e7e91907aa6 + created_at: 2023-03-27 08:47:57.787430000 Z + updated_at: 2023-03-27 08:47:57.787430000 Z +chained_element69: + id: 69 + element_type: HistoryValue + element_id: 36 + previous_id: 68 + content: + id: 36 + value: t + previous: e1f821f197cbddd9615f86f7c2a4f7a6c36dddbfdfea8c80ecc03344e52fa581 + created_at: '2018-12-31T11:22:25+01:00' + setting_id: 36 + invoicing_profile_id: 1 + footprint: f2497547a5a6b3675a7aec9c3fe5d184f73593ecd11f7b75d8969060eab2baf5 + created_at: 2023-03-27 08:47:57.966420000 Z + updated_at: 2023-03-27 08:47:57.966420000 Z +chained_element17: + id: 17 + element_type: InvoiceItem + element_id: 2 + previous_id: 16 + content: + id: 2 + main: true + amount: 2000 + previous: 1c5bb78cc1b313eb3d2e345addc0a9d003e467f3dc80e943a2242e7e91907aa6 + object_id: 2 + created_at: '2012-03-12T14:40:22+01:00' + invoice_id: 2 + description: Mensuel tarif réduit - étudiant, - de 25 ans, enseignant, demandeur + d'emploi - month + object_type: Subscription + footprint: ecb764980922a08286217f135ed982f5f7cef61dd741700c969e2e157534c613 + created_at: 2023-03-27 08:47:57.789210000 Z + updated_at: 2023-03-27 08:47:57.789210000 Z +chained_element18: + id: 18 + element_type: InvoiceItem + element_id: 3 + previous_id: 17 + content: + id: 3 + main: true + amount: 3000 + previous: ecb764980922a08286217f135ed982f5f7cef61dd741700c969e2e157534c613 + object_id: 3 + created_at: '2015-06-10T13:20:01+02:00' + invoice_id: 3 + description: Mensuel - standard, association - month + object_type: Subscription + footprint: 92655ba1d2feeade0082ee1aae2d7a249f4f03a07f19a8f16c24dc9ae17c18ce + created_at: 2023-03-27 08:47:57.791085000 Z + updated_at: 2023-03-27 08:47:57.791085000 Z +chained_element19: + id: 19 + element_type: InvoiceItem + element_id: 4 + previous_id: 18 + content: + id: 4 + main: true + amount: 0 + previous: 92655ba1d2feeade0082ee1aae2d7a249f4f03a07f19a8f16c24dc9ae17c18ce + object_id: 1 + created_at: '2016-04-05T10:35:52+02:00' + invoice_id: 4 + description: Formation Laser / Vinyle April 11, 2012 08:00 - 12:00 PM + object_type: Reservation + footprint: 4d22858b15de3ccaff911ffbb937677500d82414418227ce029bb9c869d7da62 + created_at: 2023-03-27 08:47:57.792699000 Z + updated_at: 2023-03-27 08:47:57.792699000 Z +chained_element20: + id: 20 + element_type: InvoiceItem + element_id: 5 + previous_id: 19 + content: + id: 5 + main: true + amount: 1500 + previous: 4d22858b15de3ccaff911ffbb937677500d82414418227ce029bb9c869d7da62 + object_id: 2 + created_at: '2016-04-05T10:36:46+02:00' + invoice_id: 5 + description: Imprimante 3D June 15, 2015 12:00 - 01:00 PM + object_type: Reservation + footprint: 1cc37019ac4c5400074f2d62963506244848ef1e9db5301a8793c5d36031dd39 + created_at: 2023-03-27 08:47:57.794345000 Z + updated_at: 2023-03-27 08:47:57.794345000 Z +chained_element21: + id: 21 + element_type: InvoiceItem + element_id: 6 + previous_id: 20 + content: + id: 6 + main: true + amount: 3000 + previous: 1cc37019ac4c5400074f2d62963506244848ef1e9db5301a8793c5d36031dd39 + object_id: 4 + created_at: '2016-04-05T10:36:46+02:00' + invoice_id: 6 + description: Mensuel - standard, association - month + object_type: Subscription + footprint: 53bdf22e7779f9b81dd18b5aeb541e10b84f1e401e5d36723c5b89d56ae52fec + created_at: 2023-03-27 08:47:57.796263000 Z + updated_at: 2023-03-27 08:47:57.796263000 Z +chained_element22: + id: 22 + element_type: InvoiceItem + element_id: 11702 + previous_id: 21 + content: + id: 11702 + main: true + amount: 4000 + previous: 53bdf22e7779f9b81dd18b5aeb541e10b84f1e401e5d36723c5b89d56ae52fec + object_id: 1 + created_at: '2022-09-20T17:14:23+02:00' + invoice_id: 5811 + description: Tablette lamellé-collé x 1 + object_type: OrderItem + footprint: 8783b4e26652236378a2137153214c372931ba70cf7bb35d58491d719636da7f + created_at: 2023-03-27 08:47:57.798277000 Z + updated_at: 2023-03-27 08:47:57.798277000 Z +chained_element23: + id: 23 + element_type: InvoiceItem + element_id: 11703 + previous_id: 22 + content: + id: 11703 + amount: 500 + previous: 8783b4e26652236378a2137153214c372931ba70cf7bb35d58491d719636da7f + object_id: 2 + created_at: '2022-09-20T17:14:23+02:00' + invoice_id: 5811 + description: Panneaux de MDF x 1 + object_type: OrderItem + footprint: b48f466e15d7b43bd11baeab7be10e9d0bf0c42e72b4e87e6715072739469509 + created_at: 2023-03-27 08:47:57.800519000 Z + updated_at: 2023-03-27 08:47:57.800519000 Z +chained_element24: + id: 24 + element_type: InvoiceItem + element_id: 11704 + previous_id: 23 + content: + id: 11704 + main: true + amount: 6000 + previous: b48f466e15d7b43bd11baeab7be10e9d0bf0c42e72b4e87e6715072739469509 + object_id: 3 + created_at: '2022-09-20T17:14:48+02:00' + invoice_id: 5812 + description: Panneau de contre-plaqué x 4 + object_type: OrderItem + footprint: c462fd0f1ede1e8e99b30a5646b30a4d0db95ea6b170520230d4c6fd5174fa1b + created_at: 2023-03-27 08:47:57.802559000 Z + updated_at: 2023-03-27 08:47:57.802559000 Z +chained_element25: + id: 25 + element_type: InvoiceItem + element_id: 11712 + previous_id: 24 + content: + id: 11712 + main: true + amount: 119 + previous: c462fd0f1ede1e8e99b30a5646b30a4d0db95ea6b170520230d4c6fd5174fa1b + object_id: 16 + created_at: '2022-10-04T14:36:03+02:00' + invoice_id: 5816 + description: Filament PLA blanc x 1 + object_type: OrderItem + footprint: 7c57a97bd658873337e261d216f3602b4f08ea7aa401644c881a61093b299dee + created_at: 2023-03-27 08:47:57.805325000 Z + updated_at: 2023-03-27 08:47:57.805325000 Z +chained_element26: + id: 26 + element_type: InvoiceItem + element_id: 11713 + previous_id: 25 + content: + id: 11713 + amount: 200 + previous: 7c57a97bd658873337e261d216f3602b4f08ea7aa401644c881a61093b299dee + object_id: 17 + created_at: '2022-10-04T14:36:03+02:00' + invoice_id: 5816 + description: Filament PLA bleu x 1 + object_type: OrderItem + footprint: e303dd9cb1b43079a6a83cea2a0846e3446832e40e65cb07396eed56e65b6282 + created_at: 2023-03-27 08:47:57.808994000 Z + updated_at: 2023-03-27 08:47:57.808994000 Z +chained_element27: + id: 27 + element_type: InvoiceItem + element_id: 11714 + previous_id: 26 + content: + id: 11714 + main: true + amount: 119 + previous: e303dd9cb1b43079a6a83cea2a0846e3446832e40e65cb07396eed56e65b6282 + object_id: 18 + created_at: '2022-10-04T15:54:42+02:00' + invoice_id: 5817 + description: Filament PLA blanc x 1 + object_type: OrderItem + footprint: 2ed7ef9bcd93e79c5b8583dfae7fd786620795ae9821d32d7eabcbec317f2207 + created_at: 2023-03-27 08:47:57.812083000 Z + updated_at: 2023-03-27 08:47:57.812083000 Z +chained_element28: + id: 28 + element_type: InvoiceItem + element_id: 11715 + previous_id: 27 + content: + id: 11715 + amount: 1500 + previous: 2ed7ef9bcd93e79c5b8583dfae7fd786620795ae9821d32d7eabcbec317f2207 + object_id: 19 + created_at: '2022-10-04T15:54:43+02:00' + invoice_id: 5817 + description: Panneau de contre-plaqué x 1 + object_type: OrderItem + footprint: c0f2378855beedac05044ad77b6cdbaf20b54dc4e2b3c7bd6deb991155714a45 + created_at: 2023-03-27 08:47:57.815250000 Z + updated_at: 2023-03-27 08:47:57.815250000 Z +chained_element29: + id: 29 + element_type: InvoiceItem + element_id: 11716 + previous_id: 28 + content: + id: 11716 + main: true + amount: 1000 + previous: c0f2378855beedac05044ad77b6cdbaf20b54dc4e2b3c7bd6deb991155714a45 + object_id: 20 + created_at: '2022-10-04T16:04:12+02:00' + invoice_id: 5818 + description: Bulldozer x 1 + object_type: OrderItem + footprint: 845960aadf87ab3ccea1e18f09a5ddc12aa5c32bfce521535d380ebd4053175a + created_at: 2023-03-27 08:47:57.819673000 Z + updated_at: 2023-03-27 08:47:57.819673000 Z +chained_element30: + id: 30 + element_type: InvoiceItem + element_id: 11717 + previous_id: 29 + content: + id: 11717 + main: true + amount: 2 + previous: 845960aadf87ab3ccea1e18f09a5ddc12aa5c32bfce521535d380ebd4053175a + object_id: 21 + created_at: '2022-10-04T16:17:52+02:00' + invoice_id: 5819 + description: Sticker Hello x 2 + object_type: OrderItem + footprint: '09843a64142df0fcd04f078d38ef0c82c9bcd5d92ca57d2ac0cf2e9b160fea9d' + created_at: 2023-03-27 08:47:57.826052000 Z + updated_at: 2023-03-27 08:47:57.826052000 Z +chained_element31: + id: 31 + element_type: InvoiceItem + element_id: 11718 + previous_id: 30 + content: + id: 11718 + amount: 4000 + previous: '09843a64142df0fcd04f078d38ef0c82c9bcd5d92ca57d2ac0cf2e9b160fea9d' + object_id: 22 + created_at: '2022-10-04T16:17:52+02:00' + invoice_id: 5819 + description: Tablette lamellé-collé x 1 + object_type: OrderItem + footprint: 4d3db56e3c84458b92a80d0171212ee29e897a615353b4f3f34604d826348384 + created_at: 2023-03-27 08:47:57.828497000 Z + updated_at: 2023-03-27 08:47:57.828497000 Z +chained_element32: + id: 32 + element_type: InvoiceItem + element_id: 11719 + previous_id: 31 + content: + id: 11719 + main: true + amount: 12000 + previous: 4d3db56e3c84458b92a80d0171212ee29e897a615353b4f3f34604d826348384 + object_id: 11 + created_at: '2022-10-04T16:25:37+02:00' + invoice_id: 5820 + description: Tablette lamellé-collé x 3 + object_type: OrderItem + footprint: 44f6aaa53de181d96483280420058f0c9aee9ba648a47c4375e0e8a058b8c60b + created_at: 2023-03-27 08:47:57.830953000 Z + updated_at: 2023-03-27 08:47:57.830953000 Z +chained_element33: + id: 33 + element_type: InvoiceItem + element_id: 11720 + previous_id: 32 + content: + id: 11720 + main: true + amount: 12000 + previous: 44f6aaa53de181d96483280420058f0c9aee9ba648a47c4375e0e8a058b8c60b + object_id: 23 + created_at: '2022-10-04T16:32:28+02:00' + invoice_id: 5821 + description: Tablette lamellé-collé x 3 + object_type: OrderItem + footprint: 198e2bded4738b60186f49ab46e480b8dd6a4e3a3bf5480319f707ab2bc88cb2 + created_at: 2023-03-27 08:47:57.833559000 Z + updated_at: 2023-03-27 08:47:57.833559000 Z +chained_element34: + id: 34 + element_type: InvoiceItem + element_id: 11721 + previous_id: 33 + content: + id: 11721 + main: true + amount: 3000 + previous: 198e2bded4738b60186f49ab46e480b8dd6a4e3a3bf5480319f707ab2bc88cb2 + object_id: 24 + created_at: '2022-10-04T16:35:40+02:00' + invoice_id: 5822 + description: Panneau de 3 plis mélèze x 1 + object_type: OrderItem + footprint: 7021559a22497222ffa5b07053988435c954e8d21ccba39c06eecbf4630f8e6f + created_at: 2023-03-27 08:47:57.836155000 Z + updated_at: 2023-03-27 08:47:57.836155000 Z +chained_element35: + id: 35 + element_type: HistoryValue + element_id: 1 + previous_id: + content: + id: 1 + value: '

Fab-manager est + outil de gestion des atelier de fabrication numérique, permettant de réserver + des machines de découpe, des imprimantes 3D, etc. tout en gérant simplement + les aspect financier, comptable et statistiques de votre espace.

Fab-manager est un projet libre: ouvert à tous, il offre + la possibilité de contribuer soi-même au code, de télécharger le logiciel, de + l''étudier et de le redistribuer. Vous n''êtes pas technicien ? Vous pouvez + quand même participer à traduire + Fab-manager dans votre langue.

Fab-manager favorise le partage de + connaissances grâce au réseau OpenLab: les projets que vous documentez sont + partagés avec l''ensemble du réseau des Fab-managers.

' + previous: + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 1 + invoicing_profile_id: 1 + footprint: 3d7921439bced6a31e708bb9f34af0d8cc98f7355cb9400021ce8b9c54f604d6 + created_at: 2023-03-27 08:47:57.856077000 Z + updated_at: 2023-03-27 08:47:57.856077000 Z +chained_element36: + id: 36 + element_type: HistoryValue + element_id: 2 + previous_id: 35 + content: + id: 2 + value: Imaginer, Fabriquer,
Partager au Fab Lab
de La Casemate + previous: 3d7921439bced6a31e708bb9f34af0d8cc98f7355cb9400021ce8b9c54f604d6 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 2 + invoicing_profile_id: 1 + footprint: 4912ab26e346c7cc84439c1d60e63bd4189fd633af67ec76c7fb968e42b264ba + created_at: 2023-03-27 08:47:57.859182000 Z + updated_at: 2023-03-27 08:47:57.859182000 Z +chained_element37: + id: 37 + element_type: HistoryValue + element_id: 3 + previous_id: 36 + content: + id: 3 + value:
Contact commercial :
contact@fab-manager.com
Support + technique :
Forum
Feedback
GitHub


+

Visitez le site de Fab-manager

+ previous: 4912ab26e346c7cc84439c1d60e63bd4189fd633af67ec76c7fb968e42b264ba + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 3 + invoicing_profile_id: 1 + footprint: d51ed373f4aca669e13e0961d7abbfcc6ce1468989719922661e5f19d65eabeb + created_at: 2023-03-27 08:47:57.862052000 Z + updated_at: 2023-03-27 08:47:57.862052000 Z +chained_element38: + id: 38 + element_type: HistoryValue + element_id: 4 + previous_id: 37 + content: + id: 4 + value: fab_manager + previous: d51ed373f4aca669e13e0961d7abbfcc6ce1468989719922661e5f19d65eabeb + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 4 + invoicing_profile_id: 1 + footprint: 0b23f8a95dee83acc5e1e7bddf244c6555300699f61669493f423efb06aea2e3 + created_at: 2023-03-27 08:47:57.865255000 Z + updated_at: 2023-03-27 08:47:57.865255000 Z +chained_element39: + id: 39 + element_type: HistoryValue + element_id: 5 + previous_id: 38 + content: + id: 5 + value: Tout achat d'heure machine est définitif. Aucune annulation ne pourra être + effectuée, néanmoins au plus tard 24h avant le créneau fixé, vous pouvez en + modifier la date et l'horaire à votre convenance et en fonction du calendrier + proposé. Passé ce délais, aucun changement ne pourra être effectué. + previous: 0b23f8a95dee83acc5e1e7bddf244c6555300699f61669493f423efb06aea2e3 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 5 + invoicing_profile_id: 1 + footprint: c5976587bdc0cd5ad93a9b8ca03c3706e029e461f5f0a87df280ddd5070ec07d + created_at: 2023-03-27 08:47:57.867680000 Z + updated_at: 2023-03-27 08:47:57.867680000 Z +chained_element40: + id: 40 + element_type: HistoryValue + element_id: 6 + previous_id: 39 + content: + id: 6 + value: Toute réservation de formation est définitive. Aucune annulation ne pourra + être effectuée, néanmoins au plus tard 24h avant le créneau fixé, vous pouvez + en modifier la date et l'horaire à votre convenance et en fonction du calendrier + proposé. Passé ce délais, aucun changement ne pourra être effectué. + previous: c5976587bdc0cd5ad93a9b8ca03c3706e029e461f5f0a87df280ddd5070ec07d + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 6 + invoicing_profile_id: 1 + footprint: 98d44e27c7ef8ef5e8c6d3a8cafafb81b4cbdeeb24b8d9107e6d6f443b662f14 + created_at: 2023-03-27 08:47:57.870564000 Z + updated_at: 2023-03-27 08:47:57.870564000 Z +chained_element41: + id: 41 + element_type: HistoryValue + element_id: 7 + previous_id: 40 + content: + id: 7 + value: '

Règle sur la date de début des abonnements

  • Si vous êtes un nouvel utilisateur + - i.e aucune formation d''enregistrée sur le site - votre abonnement débutera + à la date de réservation de votre première formation.
  • Si vous avez déjà une formation + ou plus de validée, votre abonnement débutera à la date de votre achat d''abonnement.
  • +

Merci de bien prendre ses informations en compte, et merci de votre + compréhension. L''équipe du Fab Lab.

' + previous: 98d44e27c7ef8ef5e8c6d3a8cafafb81b4cbdeeb24b8d9107e6d6f443b662f14 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 7 + invoicing_profile_id: 1 + footprint: bc28c940bbc30438cb381434ac82fb04367d62f328f08f1bc91f1d1010efa86a + created_at: 2023-03-27 08:47:57.873981000 Z + updated_at: 2023-03-27 08:47:57.873981000 Z +chained_element42: + id: 42 + element_type: HistoryValue + element_id: 9 + previous_id: 41 + content: + id: 9 + value: iVBORw0KGgoAAAANSUhEUgAAAG0AAABZCAYAAAA0E6rtAAAACXBIWXMAAAsTAAALEwEAmpwYAAA57WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMzggNzkuMTU5ODI0LCAyMDE2LzA5LzE0LTAxOjA5OjAxICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNyAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTctMDEtMDNUMTE6MTg6MTgrMDE6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNy0wNi0wNlQxNTo1NjoxMiswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6TWV0YWRhdGFEYXRlPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3htcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDxwaG90b3Nob3A6Q29sb3JNb2RlPjM8L3Bob3Rvc2hvcDpDb2xvck1vZGU+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6MmYwMTE5MTMtODI5NS0zOTQ0LWJmZjYtMTY5ZTNhZTQ5OThlPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6ZGU3ZGE1MmYtNGFiZi0xMWU3LTljODAtYWJjY2ZlM2JkNzdmPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6YTE5NTAzOTAtOGQwOS0zMzQ3LWFkNGQtMzkyNDQ2YjRiNWJiPC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpIaXN0b3J5PgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+Y3JlYXRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOmExOTUwMzkwLThkMDktMzM0Ny1hZDRkLTM5MjQ0NmI0YjViYjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0wMS0wM1QxMToxODoxOCswMTowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDoyZjAxMTkxMy04Mjk1LTM5NDQtYmZmNi0xNjllM2FlNDk5OGU8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTA5PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjg5PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz7jSvdMAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAACL8SURBVHja7J15nB5Ftfe/VdXLsy8zk5lM9hASsrDKImgiuyCL7ILgq4KKu9flivuCiKjoFeWqCCoKQpTLIsiOrBqI5Bo2IQsJ2ZPJZPZn7ae7q94/+kkyQzIhExKSwVufT08mz3RX91Onzjm/86tTp4Vh+9oKYCFQA/YlThaHB+jlBmxuIcdyesmQQVAixELjYOPRSo25KDoJMdQ4mjTLKNFInBUENOGzEoc4vphEYnwVe4KNPdmgJoMeKxAjDSYnEAnABgSgo0cxZQNdINYJ9CqfcJmAxQaWpulZW0GZEI9RJHgcRYDmEKCIxQbKOLhoYF9COrDoJsQGRpNhPj20U+Xs+g0Ha712jKXpRhwdsrObhcAIQ61apeZ7xJXiQa+IxRvQNo5yWP/dABpDI8nRAn/mQcTfHmJN82GqTTjGECLw61fp+tn9ezObfhcIQAIKGwlIA2JlmRELfbz5LvajFeSTEJR0/ezh3qw3QmA1DApDDIFGjsnSOFMgjs/iHA/B2Co1DB4QIgDhOsjGHCqbRyQzyKYUoiEGjgVKQqjBCzBdFXRHCV3uRff1YDp60V5FAOMlanwM6wRD+kt98MxEggcM4pEqxblgSgEG+/+EtvUWYEigaMbZL0fiPQXEOQ5iH6gR0IfARubSqGlNWJP2wZk+HWvGOKzRLagRo5DZEchUGlSsrlEbm4awgi4VCHs7CNvbCFevI1i4Ev/FBfgvLyRc1AHdRWkIDk5iHSywLwlIPyHRs9OEd4Nsq9Qnyv8JDRAYAiRdJGaOJf4xkCeFeHlDDYRCjmoh/tYZuMcdQezQI7D2HovKtQDudt5BgkoiM0lkZiT22H3hYOA0AI+wux1/6XJq85/Ge+gf+P94kWDdOssEwTEK65gmsotq6D/a+L8PKS4zmH93oQkE4jBJ8uIa6mxFNaspI5wksbcfSuykY3CPOgJ3/0MRTnoX3N9F5ceiDhlL7JBZmA+WqS2aT23OfKoPPob3xP8SdHbto1DfypA6uwP1q4DwJkGpSw/Q5je50Mymn3arwP2YwP64xB9h6IV0lsQJx5M4+1RiJ5yIyo1+Q7+kcBK4+83E3W8myQs/iDdvDuU7/oJ359/xly6fYVA/s4m9O0bsexA+atD/HkKTCAycKkhfKggPgh6MZRM76ShSn7yQ+DEnIqzUbv/C0s0Qn/ku4jPfhf+J5yjdfAvl39+Jv/SV42ycQxXJHxjCnwSYavhmFppANKTJfUUgPwrVNBRxDtqX9Fc/TuKkM5CJhj3yy9uTDiD3jf1JnnsWpRtnU7zu1my4fv33KqQOzGB/thtvXfhGoLUhNvXt7TyxF+iox1rN2CgUVTzGkZoxntj1BnGBps9V2RiZL15E/r9/TOzQYxB2fA/3EALV2ErsmHfiHn8IplKg8vyiGSn0kXncuY3U2rfl5Txl0e0mUGbnAxmJAAFhEBDqEFtKloY1xI4yIhYumvCoEWR/1Y4/Bbpx9p1K/spvEj/xrGEbuBpdpfw/f6D30p/AgsWLIPFegXxGI9HKEE6OU7MCTBAgAoHZIKkJK3IObxAjskNQSeMjiJ8myNzVSW2KoJvE2Scw4sFbhrXAAISMkTz3w7Q8fhfOOafuU6Z0bwU9xcOmImwqCYdSyqGYcigmHTxpIcwbGy4MSWhhHR9Kkh80iFsExbShRObLn6LpltnYrfvwZmlqxCSabrmdkX/4r5FWxvzF0DFNoVGhxvLrR6CR5o2P7+RQBGYBY8mdHyN7vaHqGAHZy/+D/BVXIEWSN2NLXfAZmu/5w5TYhL2vC4OOFnwNYvdyKEMS2jhyZ7SQusGniHENuau/QvarlwMOb+YWm/luRj5229uzp59wDZWiFRaKaM+L7M5uEKD6Gv259C2PiJASeOSOtkjdEFJMQUj+qq+Q+dSX+HdpMtdM6pQTp1LodorPPfOwPXok0tiYDVWEkOwKAnNQ9PivbTAcCkGKJAHuZIV7hyCYoSmT+95nyX7lO/CmWOgYIgjrai/odUvfW3nuX/es/NS3CMsVZDy2i4LoQdbTzDaEFkawI6lwrxaEMzS9ZD73IbJfuYx/1yYbmpOmpprXfvVj+N2dWA2NoHcxGDED6WxLDs5yILHQxL4i4YSQLhJnHkfuh1fsqifDX72U2spX0NUyQu6BxK0UiESy1nPzbftUVjx/pJMbmzIm2NUWxxdKrreMtcRgSgYQSwbRMos4FvmTQ8QfoCdnHziREbfPxp64705/qtqaJXRefTWV+/9B2N0LYW23I7Stz2SBCUKjC9WSULKG2uX+QRhDKISpSOQC41X+685y1/1i8Vbva7BIjlTk74Dq4SJpaJz9MxKnnr/zp9GGlaz9wMUU7nsUiYtw3T3aVwoAx0I4kjd6CU4JWerwq+dZFTKvYjsMNgKX+MUQHG4okfrURbtEYAB9f76N4n1zUHYamYkzYCRej+wMr68fM4jENqaomNfoV2ylv9cp5MDo5EjLvcSyBtzHINAo4ocJ5Ec03TgHTiPzuc/vstkTrFqFEDYi4cBGdkEAAYR9JRiyzzAI6SKzMbAE1DS6t4LB385+DEI50QSS/QZaCkw5RJfLbE5R2s7nQYDlIJIOwtpxDRVA1egJVhp/0wchggCJjbrIEIwRlkvqSx/Hatlr1+m8bcOrQIephsikQ8Pn3os9ZgymUt1un4NjUZk3n/K9T2LKIDMxcp84HWevvTA1f/PEGOR64SjKT/2T4v3zEI5A1H2rKdawxjWQOe88VKYR43mDDq0xGlOrEvb14Le3E7zchr9gFUFvB9LNIlOxbT/Ha3gUayzlTf/rxaGN/CwXeXZIH/FTjyHx7tPfAGv9KpNYDRCNSRo++0mcsTOG3Fv3LddS/MsTaK+GlWim4Qufwd3rwO2+3rn/dor3zIMgjDLAtEFXa6jRjTR+8Quo1FBW3jVhqQdvwbMU7ryT7qtuRXcWkI2pHdY46UNd16IRU6iLNbVGmUqTvvgDqETT7nH3xmBK3g7CUVMfkACZTSAT+aEp/9ixqKwLFT3QP4UGM+RMBIlKNpA45BhaLvspY/7831gjmwg7SzuMkKVTZw5HAz0k9k/C8YYSsVPeRuydJw/PCNiYekCqUePzqHzj0JiI1mbU6Aw60FtahNfJ6qeOPYPmn38LmXTR5doOgST5QVKcS5KzSAHue0K8FmGniJ95GkLGGbbNENEDrQ1Id2g0k0ynsEa1RIBjFyy9ZM98D+kzj0FXylHi7VCF9i08vo/HZcTHS9RpITXcd+xP/Jhjhq28hGWB0Qgs7JZWhprlIe089qgJGMIdoKi253yX5CnHI6RAe0NPH5LLkaxE0Ik+XKL3FShi7zoW1Th2eKgTQb8jmrUmrGG0Bhys1h35HhJr1KhI04YotMI9f2Ltpy+m+MS92zwvtv8UrLEtmFow5Kez3o6giyRFnONCaqhxrbhHHjYsNKo8/3G6r7kWQT3HXwiEpfBeXooUNiQdrFE7lmNpj21EYDCBQQxBUUvz/sb6/76O8kOPM/7hydijJ2+9/9bx2A3NBCvWA0NzQ5ZNFRvVDMmjwMc+eCrufocMC6H5y1+m+7pbEFiR4DYGs3YMEUpUc6Lum7amowYqRVAWwtly0KwxLRBzMaEZElZQiTQ2ktqiDryXFg4qNJHOI7PpTdZhSEJbDxRxDncIJxlsYkcfinCzw8N3SRclsoikQiirP0mH7q4iGzKohtzWLw41tVULUblmrObxWw7MqBasxhxBW9+QfOJG3CKVA54/uAGWDiLnbERMQ4rZZBoLgTvTUBMym8I55G3DCHEIEDIyjf0PEbESVtMIVHqQvQKhj7fkecLezkHM11hUfgSEwet7vm3GojsYpy1B4MB0Q4ic0oi115hhBhWJOMJXH2hUtgGZ2HoqutEa75VFhIXurZugxjFYo0dgCIb+PPV/RWzwUMNoD9PjsSOBmowTHxPCFIHG2XsKVkvL8AnFwiph2EvY3UfY0UfY0YvuKNWZDIPM5hCxxNYvDgJqS1YQ9vYMRmZh792MQA/JdulKkRANeY01tnXQ84INqwg6NkSmd4hRhaVx9pKYyQaNPX06kBo2QnMmTiH/sXMQSFAKYSmCnh6qDz1LWOzBGjcCYW09tU8XCtReakMfVRgcQU6sx3hDCLDdyVPIHHcImXPPw52y/6DnVebNx1vyCiLmDvl7Wy5MNmiIuVgzxg0ryxg/6EhG//LIAZ95K55n9bMfwKxdgzWmedBrw+4NhGs60cXBVxDsMeMR0sEMIVbLn/8pcud/EoEaHPWuep7OS68GD2R+6Ns7LIE1CXxUYx61DXUeNi0UmFqIVAmsEYMTxUHXOsKuTvQ2SGmroRUh7aFBuyjxbWu6TfX5x+m+4Qb6fv8QYUcB1Zip85lD9GkCMRZCZDaP1Txq+AvNGEwYoNJZrOZt+ZR1BB3d6J6+wYU2ajQiaUN1Z/CPBl0pEXR1oSv1BdkdzOKSQItBIxJpZLaJN0ULfGQ6g9U4cnCF7OpGBx5h2+BCs8eNxhqXwXh6J6StKBJvPYWxv72TiU/fQeygqQTdxR0ipCWYHBhkPolIpIa/wCwbbJBjsqjGEYMLrVCK6pl0dhNt4NpaEJtBjWseEuwPC52EPavraRKD8I7T30brr3+APTJP2FvdIU1LAIjGGMKODSv5aK9E0LGaoGstQddadLWXYP0ajPaxxzUiM4MzO2FvoY4iu9F+aZCQK4EzYWI9v2T7Wu+t17PypLNo/+F3MbXBkWn8LUeSOvNoTFhlqE7NAhEDEDEbtoF49sRWnvswG778faRtRZBfSoK+AuGaEvZZYxFi8I0h4SvrolpN61ahC33Ihq2DFnfCZAwewmwfNK+tXkXfU09TeWYRqeOOJXHwrMEFd/hB9F5zJxgNQg1FaHVJKclwy80PO9dTmvt0P8I4ylMTMoHdOmob36eGsAQ2MUTOxlRqgw/Q1Imb+t2e4ZFuHIVCeDF0W8c2z7VbxiBsB2PMkDIPLKJ8sF2fj74rGCwVQ4k8Ir2ZMDYVD7BQmYZtUEiShku+SPYjFyESCVR+cJTpTBiNSibQpe30ayb6IdRrs8DCjYOREIaR6pjtFpqpgcFU/br81DCT3MDDhBqZsLBGDI6EhbSI7bP/9g1QcxPWyBaqS1cN/cFeaz+C3LEtUhIogcB0VjB+ZZjHaECgkQ1x1OiRO6VLlW/CbmzGUNuhmHGXAGSQXQKB7ipiSn2I3PCG/cYYZFMG2ZjfKf1JuxHV0Dj0FEVtQOvtsxQYjOdvaR6FQNhqiyUeaTBtIDH1am7DX9XAampCpXZWzS2J2qfOFG1HDo4QUTXLUJchvj1pBCIKE6s+eB54teio1jAVDxNuucfbAr0SFLq3G92+DsbvP9xlhtU4EpV+rdX3GuDVPUScbW0/t/ceHS0uB6+tOUGhBx/IHjWN2MFveQ34G2CqNexpeUZ89zOoZH5TurlwHfz2drp+dBP+whWI1OaQw5LoZQZB2N1LsKYN99BhKjABhAaBwR41EmFtS9NC2r/2DQqz78Ea10rTd79Mcuaxg57tjh2NwsaEr61quXe/l/gBh5A69l1YuW37VV0ro6mhGjOkTz0faQ806brSS99vH6ZWW4LoV1JRhuilIKHiESxYNbyNY2jAsVATm7d9Xq1Aae4c+pa9SOHxv1F7+ZVtx1Nj9kKS2a7Ug/ihR5E7+yNY+dfOAAg71gFBpMFbCbl0TxfGq2wRb0qbYLlBLjMI/IULgWGMIEODSMewWradBh5WC1AOcEhgJXLgl7eN1lonIFsymNeTL7KVVnn2JTSVwUMDIbaaZyI3UF4hYbFA4i9eTNCxfhgjR42Mx5CZbYMQXSyie3sQ2JggJOjr2bbQmpqxJzXCTqwDWXvlOUp3/Q2BM+RQTU5CU8EsAEW4uJ1g2Z5gIuvbLG33NRgRNXAiao1KZbBGtLyGeQwI+qL6yegQXShs+z5OEmevcdHmffH6N/CHpfW0X3oFtUUrkMSjPrcmOcup04sDTaelCYnh/x2cz+quIrWnnyJ26KzdDioMBl3qBHzC0paaIJNZwkpfXbxis3lMJBGuwphSfdfmwI5VMk/QthJT9BDKRuuQsHMDobceoRIY71VLJVIhbFBNjRijCUsdqEwTutT72hNPa0wQYmo1dM1Dd/ZQfWY+vbNvo/zos8hsGtPrY3RAWOpE2HF0uRjdNpFAFzfU/ejAiWL9BZiCN2c8saVV/EnVv84l/aFeRCy725RMJGxMxaf9a9/HyuejwHNAMArCtqitWIWI2wgZfShTDkHHBtq//H1UPD4Q7W0q328RtK0HbSNSCqldyg/PZ90HPgVSsWkDmu7nV6TAW7CEcH2J9k9/AxlLYvxgcI6pzi+bMMT4NUylTNhXIGzvJVjbhfE8VDYFjkIkIVjZTdvFlyDt2KZnFpYiLJXwV61GpAdaHCtBDB+7zYdHJPYk/58v4T03j9hbj9t9mmZL8DWle56sLyaqfghKbxoVYcWQ2XidUQijPRidvZTueqK+AaN+mTH9rosyk2UuAcIgqgJ/URu1hSuJygRsTAPffE8BEHMRCAq3PcLGoh1b8Zb1Y2Pypd4sSSEQMtprIGLxaOMjISQUus+jcOtjRF9gI5GqAYVMJxCuNQBdytMQHEIFg/+QxiVc1Yb3xNO736UpkLk4Mp2MvrAQUSFMqVC5JDIWxwQ+ulAl7OyDqo9wBbpSw2iDyidRDal6ERmDTCdRzVmEFcPoWn23igBHQCzafSMtB7slH2kBINMxrOY0uDamWsaYANWYQsZigEbGHVRTCpVPRkNtWch8GmEpIKgvGTmoXBLVlAIp0F4t2sDvgu4toTuLCEchU7E6KImWmGTMjfq15RbhgKWooIBWvLlrsV4w6P2q9z1M6sL3oZp2T0qdCTWmBo1ffB+pE4+jcO9f6fn1zdijR5K78HycGTPQxQK9N95M3y33k3nPiWTOPhNrZAvewkX0XHcz3rxFgMFqaSD7kbNIHPkORDZNsGIVfTffQuGORxGkaPz2R3An7EPxgfuIH3gQsbcehi6X6P3NDRRuepCwFC2bZC86jfQpJ6OamwnWt1G47S6Ktz8G5YCwXME9YC/yn76I2L77UfnH01Tm/4PUrOMJyxW6f3493qLF2M2t5D52LolZMxGOTfWZZ+j6xfXUFi8jMetwGj56IUF7O96SF0keeTS15a/Q9aPfYSoBwlWb8cjFwPuBS5Aso+WyVTSaFdYIU/jT9eaNaG3fucS8qBrMgmyrWdgw2ixsGG0WZFrMS26r6b3jZmOMMTr0THHuA6a67MUB1/qda03PX24wYblnwOeVF+aaxXtNM4vG7GUKj9+9xT21qZpVHzjPvOgkTe+9s+ufhgPPCQpm+QknmBfAdPzqB1v2oaum7VtfMC+SMC9Pnm7K/3py4N9DzxhjTFBoN0v2P8QscBpM7103bdFP+aW/mZdSObPi9FP7PZ9vjDGm957ZZkHDKLMg0WIWNtbHJj9qqbwWuAH4AxqDd6vEXW+CEpU77sLoym4EkGYzDycdkm99J+6E6QPNREMr2VP+HzI+EDTF9j2U2BHTSZ04k9Q7TgRgw/e+w8rz3k3QvhKBS8MnPow1Kk/YU+yHIPqHEyncQ6YSP3Bf8hd/CIDCPXew+sLzqMz7O0K4ZM46G2v8SHIfOpf4jCMA6P3z72m/8kuE3Z11VqOECTyyn76AzKnno70KHVddTvsVX0WXC8SnzST3yfcSdm/Y7BmrFbyXn6E8Z25k9tWr0OPGVSIbKFJ5rp3EXy3iF1TvfYrqw/cSP37PqElsdEDxgTsxlQqpk05HxiK/o8s99Mz+He4+00nOfOfmdbCmPKVbH2fFqccjx0q8p9bir15LbfkSrOZxWA2tqFQefL/eTx+9N96ASMfJnnM+wo7jjBlF39oS6z7wccj71J5dgvfMchJvfxvxQ2ci3RzutCm4hx0IgLfiGdZ9+At4nZ1YmVE0fPQ/wNdYTXlih0VEvL/iJYp/foCgdx2Zs84hNuUgEoe/BX/B8k0gputHP2LDN36CdJJRUZxXhWpW/zcbRXgpvFbgvkv39TQUrr0RZ9bRqNjur6vvL3mBdR/7AkZUmXjAATiT9gOg9Mj9rPjw5xhx8Xn9hGYgCPHXrSd58nFkLziT+E9mINwEwkS5/cb3Iwdfj86rzz7Nus99HXf6GFJHH4XVOgkcG699Bc7aKTSccSHuJftitzYjdKLeRw3pJlDJSNNrS14h7OzBQrKxDrvRGpXJYzdGfKiz9wFMePTBepAejb7Kj0Am6wVhhCFY04mhiointpqGYK2pbx2NQKZAUHrCkLxdkvxw9a4nqNxzF6mzPrjbhabDABlkMckYRg7kGyWgYukBdJbWJRq/fiEtl14V8Xxz51L913OkTj4Ru3X8wLUcAMug3AaUk4vQHRC2ryd19BGMf+g2BEn8dWsp/Plx3GlTiU3dd3OVcLHpxph62DCQp9x8n6B7A7VFi6M4zitjAijNfaKO9KNUD5Fyog1ocuslmaxyv3gjihA0IcHvbNxTTK04svCDXxI78lispt27cV4ohbAkRkqQ/TgfR/WPpqIhqgaopgSxww+KzNaSf7LqrHOorl3N5PmPR0Izr2LWpYpKKgm5SfuMXSVx4iEIkmivm7UfeT999zzM6F9fRWzqviAVulwiLEZZys6kvbAbRlHrWoNKJ+vPLQl7ewna26PJt2EVbZ/6JNVnFiHTaax9svgvtpM++YStyXjr8bvZHMCj69GFpjbHEP5GkKU273kKV/9096xnqn5JRsqKCCshELLfRNv4ez+mXNgWxtforohqslv3pvm/LmfSk38lftA76jRYBhx7E/4Qth3Fg0oibGcj6YUp1muHOVlyF32QcTf/htz7ImCicjnCzm4qf38qWneb+BbG3P5bxv3pt2TOOK8OFgRhZzelx54CDO7Uwxh1zXWM/NkVjP79dUx66lnSZ59C0N3Vb4Ja25ScTFKk/5GiRJICFoVrwJovSFK86kYqD9z2xquXEgPM1yYqyurHtjuy3/RjEwVkSgF9f7qH2urFyGSW3Lnvx5kwmcqzj0WnN2Sx9s5BGCFUHUSZvsZodFDZNDqF/3mY2pqXEEKSPfN9pM8+h6BtKRCiRo3A2ruVnl/MpvjQXwBIHvlOsud8AFnffC8sCcqh77e30fWbn2IIiB92BI2f/k8yZ5yFtLLInI1w+1kKodlWmpYlB5GoJFwdoC+H2A2mrzvZ/c3vYU2fjj122s52VltMKiElQkHxrnsI17eBBn/NKnSlAEFI9zW/xm4ehXAdKvOfQZHAe3YBXb+4EnRUR6T2wkoqj73Amr6LSZ04C5lK0XfbA4QdbSSPextGC4J1PfTedDve84uorVqFoYa/uo31l3wNK99A9fkF+AvXsPqci8icfzpWvpnSI4/jvfACyWOPQOYbML09+G0dtH3+y6ROuw+7cS+8Jc+SOvVUMieeC5aNdF3CoED7F6+k/Pd/kHjrW5HJDEHHGsqPPk35wXnY00ay4YqvoIOAytynkW5i8Km8fFvjiY2k4ccS+fmQDSTOO5kRN92MkImdJrP2y75ExzevQeWS0TKE2WwfTdmvE6jRYqBI2ogQdNVnY50qYSlEwsFUw6g0YD1HVDg2QkFYKEeEsqgv+BiF0VGgI90kRvsYv4IQDjKbxAQaXSxFjsJKIFMxdF+xXqPEQddq0S1EpPlSO8iWOA1f/TAEFrV/voxsTdP4+c9gt+5F5fk5rD75IoK1HQhHoatVhO0ilIXxPUxYQ8bTYAl0sRy5gLiDjDtbTcEzxiy3xmzTr4T4mMsqcGAvjcdU/vgAPWO/Sv6HV+00oSVmzUJlfkfQU0DlMnUAFQ0yrkRsrIcpRISSZVQSe2PRMpQAaRDOq/yaFdkRZdcZeQ3SsSKQEdZz/KWIci+0E91DgZAClU1u+jvKIHPJaEKEGpWOgZKYIARhMH0BamSK7PvOw87vPXDdrNxO19XX4q9uR2UTYAuUa0fPYwJEzEE6iQjWh0Swv27et5ozKaCmxX3i3a/BS6xD8VHi095L7s8dVKcYKuSu/CLZ//zmzrKPdP/6l3Rc9lNqK9fsoS81NggVR+biAwdTgKmEiEyczLknkjzhSNToFowf4C9+hcIf76Z875MQcxAxueML3yIyE77WNzeV+z6xXSP0fuCXZE/oIz3bo5jHgoZrvkn6Q5/bacNSXTSfwh13UV34L4wX1FeJ9wB5iWhtpzLn+XnBmsI6kbLsAT5YCvBCdLGETMdQTXlMEBKu78TUAmQiCTFrR7ONpTCEEK7ywuDBlkrlgZFBubxdw3I+cBOwlvx5htTskCImLsj//FtkLvzMTp7TIa9d1fmNZUEFkp5bbzp29Tnve8TKjxJbVOoUQCnE1MJ64BTBXJFS0drgDmaHGyEQgUEERVMJPEYbxYigun27LQ4EzgCWU/1XDbkiQfp0E/hU730U4h6xt82CnfTWWoHcww4BoK0pU64O17Svqzw1B/nq2iQCCCUiUJu2XQkUuGJIu2G2puVCgzA+gQ7JIEjqYOjvT+ui53cBfZ+QxEN8Q+8Xr6T761/GMMw3bwzmcbvX0/n1C38cdiyZH5t1OJpgtz/TkIS2cQHep/TLGuEFhnTFkKDv8p/Rcd578dsWvakE5j31MG1HH31lde5jl9gjWhAVb48w2tbQzRdoFJrSn1zEhpDMtYL8pNKf7sV/cRn5H3+b+DvPGN7a1bOW8s+uZv1Vv7r8X93dX1eZOC/MeBtedy+j3Qx5qfD17nuh8nb5tAPqPq2daNtCCguDZCSFZTXcRzRqmiAxMWxfR/Xuv6JLa7EOmIZMZIeVsExQpXzPbHo//Y2w+/d//LpXLX9nDVDxAiqdXZRKZZpiCZKWTfgq6L+puGv/5rJLfNoOCS2JhUGRpYZHot0jvFsgpCKxn6nW3MoTc/Ae+RuyycKeOAFh7dlVE4xfpPrEA/R8+7v0fvMXK/1liz9ZQf8yJHpVtKibJAE0OnESw11oVZJ46Iqi+JDAesngTFXER4ZrV1K5/SH8Bc8hRyaxx4ypF5Tfg8yg10d1zoP0XPoD+i79Od685x7zdPihPvwHXQwa6OwH4vUeIrSd9Ub5KKcDcaemMA9in5TkPkHg5yq3PkT1wXnETjqc5AVnEjv6eGRyxG5lN4K2pVQfeJDy7ffiPfY8YV93l4+62iCvFjidhvIebRl28hvuBVBba5Bf08i7DfJjhvzZqq+SqPzxPqp3P4kz6yDix78D97iZODPe8obV/g83rKA670m8R+bhPT4H/5ml6LCqDfZfbNyfpOl5fD0WNi57erN2TbcC4ClB8ekY1h/KJD8icU4QxVqmet/f8O5/EjVxNO7b98eddRj2/m/BmjoRKzuSjXkTr5fP1OV2guVr8RctwPvfp6k98jz+Sy+j+3rrX9v6myR5HRRvh7DkoJEMj2btOiMksNFhkupDCvNQgDzYJ/4+cE7XhgnmlXWEr6yicuNDkIlj7TcKe/J0nAOnYc0Yj9U6CjWiFZHMItwYwtroIDamWweYwIeahy72EHasJVi3jmDRaoIXFuMvWYi/YBV6bRHMxvjKqQpSj2iq14N3t8Kp6k0OZ/gUvrF29Q0MAgeNS+2fUP1nF8mfWYiZGuckTfxIi7BV95WozVlIbc6LlACZiqNGNCEzeUQsCVkXkXEQrh2tuYUaPB/dV4MeD+OVCPu6CDu7MX1lNuaVSxQGx2hiLxrCu4D7AorzJDVPYe006u1NJ7T+YAVCJHpZnuKyblI3xtETejFvl7gH28QOAPYP0E2yGBAW1xOwlmjT05av+RNsep1cffAjLbRJEKJWB+jnArz5DqW5Ls7fl1Hts4FcXVDD+WXP1u66sUGSpLC8jXB5EnWTpCh68MeOJLZ3F4mpFtbeCsYDLQKSIFyiTBEZrS4JH4xnoCgwayUsA/PyagqL4nhLxhFrW4HApUiCDAaFIOTN0P7/ANXjuuhKlYnHAAAAAElFTkSuQmCC + previous: bc28c940bbc30438cb381434ac82fb04367d62f328f08f1bc91f1d1010efa86a + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 9 + invoicing_profile_id: 1 + footprint: b65681052ca8c64ef072511c19485235b90e947076b89183c04ccc1c15ebef0d + created_at: 2023-03-27 08:47:57.877323000 Z + updated_at: 2023-03-27 08:47:57.877323000 Z +chained_element43: + id: 43 + element_type: HistoryValue + element_id: 10 + previous_id: 42 + content: + id: 10 + value: YYMMmmmX[/VL]R[/A] + previous: b65681052ca8c64ef072511c19485235b90e947076b89183c04ccc1c15ebef0d + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 10 + invoicing_profile_id: 1 + footprint: d6cb332331aea40406a321eeb303961dc788b56734e6eed740d5f0754bb6023a + created_at: 2023-03-27 08:47:57.889972000 Z + updated_at: 2023-03-27 08:47:57.889972000 Z +chained_element44: + id: 44 + element_type: HistoryValue + element_id: 11 + previous_id: 43 + content: + id: 11 + value: 'true' + previous: d6cb332331aea40406a321eeb303961dc788b56734e6eed740d5f0754bb6023a + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 11 + invoicing_profile_id: 1 + footprint: 1553310ba95c0ab76f19ffdf7a4d43c185775dce2b5a690d8e6b68facb9d8426 + created_at: 2023-03-27 08:47:57.892657000 Z + updated_at: 2023-03-27 08:47:57.892657000 Z +chained_element45: + id: 45 + element_type: HistoryValue + element_id: 12 + previous_id: 44 + content: + id: 12 + value: INMEDFABLAB + previous: 1553310ba95c0ab76f19ffdf7a4d43c185775dce2b5a690d8e6b68facb9d8426 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 12 + invoicing_profile_id: 1 + footprint: 4c3093471667bcfdbbc20a186cf3b79797f5e768358dffb1a0392f4fb5090195 + created_at: 2023-03-27 08:47:57.895626000 Z + updated_at: 2023-03-27 08:47:57.895626000 Z +chained_element46: + id: 46 + element_type: HistoryValue + element_id: 13 + previous_id: 45 + content: + id: 13 + value: nnnnnn-MM-YY + previous: 4c3093471667bcfdbbc20a186cf3b79797f5e768358dffb1a0392f4fb5090195 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 13 + invoicing_profile_id: 1 + footprint: f9b827e6f6dfbda56e4cd01e08f772e819c32a50e00848500eda4febae605597 + created_at: 2023-03-27 08:47:57.898067000 Z + updated_at: 2023-03-27 08:47:57.898067000 Z +chained_element47: + id: 47 + element_type: HistoryValue + element_id: 14 + previous_id: 46 + content: + id: 14 + value: 'false' + previous: f9b827e6f6dfbda56e4cd01e08f772e819c32a50e00848500eda4febae605597 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 14 + invoicing_profile_id: 1 + footprint: 7bcf08309d9a31cd8f190065b0489a0d4f74cae41b9deb2a661a8d80b382b520 + created_at: 2023-03-27 08:47:57.900479000 Z + updated_at: 2023-03-27 08:47:57.900479000 Z +chained_element48: + id: 48 + element_type: HistoryValue + element_id: 15 + previous_id: 47 + content: + id: 15 + value: '20.0' + previous: 7bcf08309d9a31cd8f190065b0489a0d4f74cae41b9deb2a661a8d80b382b520 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 15 + invoicing_profile_id: 1 + footprint: c55e576d150d1a432b03e5aa9d7121cca779856f479885fd41649c0bf13bb247 + created_at: 2023-03-27 08:47:57.903794000 Z + updated_at: 2023-03-27 08:47:57.903794000 Z +chained_element49: + id: 49 + element_type: HistoryValue + element_id: 16 + previous_id: 48 + content: + id: 16 + value: Notre association n'est pas assujettie à la TVA + previous: c55e576d150d1a432b03e5aa9d7121cca779856f479885fd41649c0bf13bb247 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 16 + invoicing_profile_id: 1 + footprint: f4d6b2d4137dd6ec2e12b0cc7446555b4afcfccf3d43da214577c7b7ffc49090 + created_at: 2023-03-27 08:47:57.906066000 Z + updated_at: 2023-03-27 08:47:57.906066000 Z +chained_element50: + id: 50 + element_type: HistoryValue + element_id: 17 + previous_id: 49 + content: + id: 17 + value: 'Fab-manager
41 rue du Colonel Moutarde, 21000 DIJON France
Tél.: + +33 1 23 45 67 98
Fax. : +33 1 23 45 67 98
SIRET : 237 082 474 00006 + - APE 913 E' + previous: f4d6b2d4137dd6ec2e12b0cc7446555b4afcfccf3d43da214577c7b7ffc49090 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 17 + invoicing_profile_id: 1 + footprint: '08caf95ab0044bd32c418d752f766ed94ec703b3b4a556f1c66a7b5c829cb1b8' + created_at: 2023-03-27 08:47:57.909734000 Z + updated_at: 2023-03-27 08:47:57.909734000 Z +chained_element51: + id: 51 + element_type: HistoryValue + element_id: 18 + previous_id: 50 + content: + id: 18 + value: '1970-01-01 08:00:00' + previous: '08caf95ab0044bd32c418d752f766ed94ec703b3b4a556f1c66a7b5c829cb1b8' + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 18 + invoicing_profile_id: 1 + footprint: ea0985c9f695154fa115f4221a666c12d0d1b23243b76aae396c7c62e757044c + created_at: 2023-03-27 08:47:57.912785000 Z + updated_at: 2023-03-27 08:47:57.912785000 Z +chained_element52: + id: 52 + element_type: HistoryValue + element_id: 19 + previous_id: 51 + content: + id: 19 + value: '1970-01-01 23:59:59' + previous: ea0985c9f695154fa115f4221a666c12d0d1b23243b76aae396c7c62e757044c + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 19 + invoicing_profile_id: 1 + footprint: af4f5a5d5a700521b1893fb3d6576ce868fb00d752672319d8ce8197592aa180 + created_at: 2023-03-27 08:47:57.915706000 Z + updated_at: 2023-03-27 08:47:57.915706000 Z +chained_element53: + id: 53 + element_type: HistoryValue + element_id: 20 + previous_id: 52 + content: + id: 20 + value: 'true' + previous: af4f5a5d5a700521b1893fb3d6576ce868fb00d752672319d8ce8197592aa180 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 20 + invoicing_profile_id: 1 + footprint: 29acba855268a8486182182a8e693483ed18345b6163da6fc9dc834539b290c5 + created_at: 2023-03-27 08:47:57.918671000 Z + updated_at: 2023-03-27 08:47:57.918671000 Z +chained_element54: + id: 54 + element_type: HistoryValue + element_id: 21 + previous_id: 53 + content: + id: 21 + value: '24' + previous: 29acba855268a8486182182a8e693483ed18345b6163da6fc9dc834539b290c5 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 21 + invoicing_profile_id: 1 + footprint: 497e03c5b51cb32ed07590b6da58e682899a38f55709cc2d7b344cd0b42993d2 + created_at: 2023-03-27 08:47:57.922949000 Z + updated_at: 2023-03-27 08:47:57.922949000 Z +chained_element55: + id: 55 + element_type: HistoryValue + element_id: 22 + previous_id: 54 + content: + id: 22 + value: 'false' + previous: 497e03c5b51cb32ed07590b6da58e682899a38f55709cc2d7b344cd0b42993d2 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 22 + invoicing_profile_id: 1 + footprint: 5f80a0274a2fb0f52a18e7b29bb6a0802631d9c025ccdc23cd90d45ca79164bc + created_at: 2023-03-27 08:47:57.926534000 Z + updated_at: 2023-03-27 08:47:57.926534000 Z +chained_element56: + id: 56 + element_type: HistoryValue + element_id: 23 + previous_id: 55 + content: + id: 23 + value: '24' + previous: 5f80a0274a2fb0f52a18e7b29bb6a0802631d9c025ccdc23cd90d45ca79164bc + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 23 + invoicing_profile_id: 1 + footprint: 9a9a4853fa37b1c189a5ecd27eee1427c84e82ca116b8d5a955de6785a5bb8fd + created_at: 2023-03-27 08:47:57.930959000 Z + updated_at: 2023-03-27 08:47:57.930959000 Z +chained_element57: + id: 57 + element_type: HistoryValue + element_id: 24 + previous_id: 56 + content: + id: 24 + value: "#cb1117" + previous: 9a9a4853fa37b1c189a5ecd27eee1427c84e82ca116b8d5a955de6785a5bb8fd + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 24 + invoicing_profile_id: 1 + footprint: 20ab553060b21c9b276f2934eeee46ba0c40dd413e2cece32af2b6c9ac46fb9a + created_at: 2023-03-27 08:47:57.934056000 Z + updated_at: 2023-03-27 08:47:57.934056000 Z +chained_element58: + id: 58 + element_type: HistoryValue + element_id: 25 + previous_id: 57 + content: + id: 25 + value: "#ffdd00" + previous: 20ab553060b21c9b276f2934eeee46ba0c40dd413e2cece32af2b6c9ac46fb9a + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 25 + invoicing_profile_id: 1 + footprint: aa162bc744ee16a4e5f2f351ec3ad321151a989b3a563007ea2b35f70bbd4de1 + created_at: 2023-03-27 08:47:57.936922000 Z + updated_at: 2023-03-27 08:47:57.936922000 Z +chained_element59: + id: 59 + element_type: HistoryValue + element_id: 26 + previous_id: 58 + content: + id: 26 + value: Avant de réserver une formation, nous vous conseillons de consulter nos + offres d'abonnement qui proposent des conditions avantageuses sur le prix des + formations et les créneaux machines. + previous: aa162bc744ee16a4e5f2f351ec3ad321151a989b3a563007ea2b35f70bbd4de1 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 26 + invoicing_profile_id: 1 + footprint: 354b43a0173ceda401066e929af3239047adab5eb496348cfed3fdd441ee1ce8 + created_at: 2023-03-27 08:47:57.940025000 Z + updated_at: 2023-03-27 08:47:57.940025000 Z +chained_element60: + id: 60 + element_type: HistoryValue + element_id: 27 + previous_id: 59 + content: + id: 27 + value: Fab Lab de La Casemate + previous: 354b43a0173ceda401066e929af3239047adab5eb496348cfed3fdd441ee1ce8 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 27 + invoicing_profile_id: 1 + footprint: 8df165ece350649f8b5911d947a920b3a7d61081e878474616b600d46ab308b2 + created_at: 2023-03-27 08:47:57.943046000 Z + updated_at: 2023-03-27 08:47:57.943046000 Z +chained_element61: + id: 61 + element_type: HistoryValue + element_id: 28 + previous_id: 60 + content: + id: 28 + value: male + previous: 8df165ece350649f8b5911d947a920b3a7d61081e878474616b600d46ab308b2 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 28 + invoicing_profile_id: 1 + footprint: 8b0a2fd62281de9a96414c245cdf032c7dd9a039638ad8abc6a28beaf4f512ea + created_at: 2023-03-27 08:47:57.946311000 Z + updated_at: 2023-03-27 08:47:57.946311000 Z +chained_element62: + id: 62 + element_type: HistoryValue + element_id: 29 + previous_id: 61 + content: + id: 29 + previous: 8b0a2fd62281de9a96414c245cdf032c7dd9a039638ad8abc6a28beaf4f512ea + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 29 + invoicing_profile_id: 1 + footprint: a24f0758c021216db2be4c5df434c4e6dfff9b8d9b645fdebe8fb3c011bcbb34 + created_at: 2023-03-27 08:47:57.949269000 Z + updated_at: 2023-03-27 08:47:57.949269000 Z +chained_element63: + id: 63 + element_type: HistoryValue + element_id: 30 + previous_id: 62 + content: + id: 30 + value: '3' + previous: a24f0758c021216db2be4c5df434c4e6dfff9b8d9b645fdebe8fb3c011bcbb34 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 30 + invoicing_profile_id: 1 + footprint: a08b873a23598227a6112ae29a58a65fddd738a6778259437bd18d92fb78ced0 + created_at: 2023-03-27 08:47:57.952399000 Z + updated_at: 2023-03-27 08:47:57.952399000 Z +chained_element64: + id: 64 + element_type: HistoryValue + element_id: 31 + previous_id: 63 + content: + id: 31 + value: '1' + previous: a08b873a23598227a6112ae29a58a65fddd738a6778259437bd18d92fb78ced0 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 31 + invoicing_profile_id: 1 + footprint: bd88948230f9a139b83c7ce1c36b70d02ad8b4a9f07679c2a40218f2b08e8552 + created_at: 2023-03-27 08:47:57.955259000 Z + updated_at: 2023-03-27 08:47:57.955259000 Z +chained_element65: + id: 65 + element_type: HistoryValue + element_id: 32 + previous_id: 64 + content: + id: 32 + value: f + previous: bd88948230f9a139b83c7ce1c36b70d02ad8b4a9f07679c2a40218f2b08e8552 + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 32 + invoicing_profile_id: 1 + footprint: 8b7809e5ccda15a81b8eb37c9609de59bc3905db3061c07132fad5c16de9ed6b + created_at: 2023-03-27 08:47:57.957427000 Z + updated_at: 2023-03-27 08:47:57.957427000 Z +chained_element66: + id: 66 + element_type: HistoryValue + element_id: 33 + previous_id: 65 + content: + id: 33 + value: default + previous: 8b7809e5ccda15a81b8eb37c9609de59bc3905db3061c07132fad5c16de9ed6b + created_at: '2018-12-17T12:23:01+01:00' + setting_id: 33 + invoicing_profile_id: 1 + footprint: 484b735f75567853c98c88e894f3fcf307be59848e3a758b2e2de071f010bbcd + created_at: 2023-03-27 08:47:57.959606000 Z + updated_at: 2023-03-27 08:47:57.959606000 Z +chained_element67: + id: 67 + element_type: HistoryValue + element_id: 34 + previous_id: 66 + content: + id: 34 + value: A propos de Fab-manager + previous: 484b735f75567853c98c88e894f3fcf307be59848e3a758b2e2de071f010bbcd + created_at: '2018-12-31T11:22:25+01:00' + setting_id: 34 + invoicing_profile_id: 1 + footprint: 2409cff9cd12cf005310cb4ca4bb81c6246dab84add691ae199495a6c1f6b2d7 + created_at: 2023-03-27 08:47:57.961940000 Z + updated_at: 2023-03-27 08:47:57.961940000 Z +chained_element68: + id: 68 + element_type: HistoryValue + element_id: 35 + previous_id: 67 + content: + id: 35 + value: "* Tarif réduit si vous avez moins de 25 ans, que vous êtes étudiant ou + demandeur d'emploi." + previous: 2409cff9cd12cf005310cb4ca4bb81c6246dab84add691ae199495a6c1f6b2d7 + created_at: '2018-12-31T11:22:25+01:00' + setting_id: 35 + invoicing_profile_id: 1 + footprint: e1f821f197cbddd9615f86f7c2a4f7a6c36dddbfdfea8c80ecc03344e52fa581 + created_at: 2023-03-27 08:47:57.964175000 Z + updated_at: 2023-03-27 08:47:57.964175000 Z +chained_element70: + id: 70 + element_type: HistoryValue + element_id: 37 + previous_id: 69 + content: + id: 37 + value: '24' + previous: f2497547a5a6b3675a7aec9c3fe5d184f73593ecd11f7b75d8969060eab2baf5 + created_at: '2018-12-31T11:22:25+01:00' + setting_id: 37 + invoicing_profile_id: 1 + footprint: e1140318243e78b2aa141808f1f9368da560bc7ec7f17b35842ccd87f9b704bd + created_at: 2023-03-27 08:47:57.968798000 Z + updated_at: 2023-03-27 08:47:57.968798000 Z +chained_element71: + id: 71 + element_type: HistoryValue + element_id: 38 + previous_id: 70 + content: + id: 38 + value: "

La présente politique de confidentialité définit et vous informe de + la manière dont _________ utilise et protège les informations que vous nous + transmettez, le cas échéant, lorsque vous utilisez le présent site accessible + à partir de l’URL suivante : _________ (ci-après le « Site »).

Veuillez + noter que cette politique de confidentialité est susceptible d’être modifiée + ou complétée à tout moment par _________, notamment en vue de se conformer à + toute évolution législative, réglementaire, jurisprudentielle ou technologique. + Dans un tel cas, la date de sa mise à jour sera clairement identifiée en tête + de la présente politique et l'Utilisateur sera informé par courriel. Ces modifications + engagent l’Utilisateur dès leur mise en ligne. Il convient par conséquent que + l’Utilisateur consulte régulièrement la présente politique de confidentialité + et d’utilisation des cookies afin de prendre connaissance de ses éventuelles + modifications.

" + previous: e1140318243e78b2aa141808f1f9368da560bc7ec7f17b35842ccd87f9b704bd + created_at: '2018-12-31T11:22:25+01:00' + setting_id: 38 + invoicing_profile_id: 1 + footprint: 9555d1255fa5e3d8d0988446f8fd8ac004f53af1f182d963e88c727cbe0fa662 + created_at: 2023-03-27 08:47:57.971220000 Z + updated_at: 2023-03-27 08:47:57.971220000 Z +chained_element72: + id: 72 + element_type: HistoryValue + element_id: 39 + previous_id: 71 + content: + id: 39 + value: '530' + previous: 9555d1255fa5e3d8d0988446f8fd8ac004f53af1f182d963e88c727cbe0fa662 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 39 + invoicing_profile_id: 1 + footprint: a05b5929bb28dd0738f2361c37252aca4fbf2931c7245f715b6f0f4796b021e7 + created_at: 2023-03-27 08:47:57.973907000 Z + updated_at: 2023-03-27 08:47:57.973907000 Z +chained_element73: + id: 73 + element_type: HistoryValue + element_id: 40 + previous_id: 72 + content: + id: 40 + value: '5801' + previous: a05b5929bb28dd0738f2361c37252aca4fbf2931c7245f715b6f0f4796b021e7 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 40 + invoicing_profile_id: 1 + footprint: b9f231e958b1c35895a6652d69d8b11f23b0f684c4a582622b7d071020925785 + created_at: 2023-03-27 08:47:57.976217000 Z + updated_at: 2023-03-27 08:47:57.976217000 Z +chained_element74: + id: 74 + element_type: HistoryValue + element_id: 41 + previous_id: 73 + content: + id: 41 + value: Payment by card + previous: b9f231e958b1c35895a6652d69d8b11f23b0f684c4a582622b7d071020925785 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 41 + invoicing_profile_id: 1 + footprint: e83706638143f32f79fc21886b03ddffede20b8d13086dd799f71a109a48d49b + created_at: 2023-03-27 08:47:57.978732000 Z + updated_at: 2023-03-27 08:47:57.978732000 Z +chained_element75: + id: 75 + element_type: HistoryValue + element_id: 42 + previous_id: 74 + content: + id: 42 + value: '5802' + previous: e83706638143f32f79fc21886b03ddffede20b8d13086dd799f71a109a48d49b + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 42 + invoicing_profile_id: 1 + footprint: '08a57b4d462179d59f89aec3454f20838795f4ecfcee0a08603ec6281c58aa43' + created_at: 2023-03-27 08:47:57.981364000 Z + updated_at: 2023-03-27 08:47:57.981364000 Z +chained_element76: + id: 76 + element_type: HistoryValue + element_id: 43 + previous_id: 75 + content: + id: 43 + value: Payment by wallet + previous: '08a57b4d462179d59f89aec3454f20838795f4ecfcee0a08603ec6281c58aa43' + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 43 + invoicing_profile_id: 1 + footprint: 96ab834c08316e888f49b232ea69652e3394e7d4fc05758858434c4c855e7984 + created_at: 2023-03-27 08:47:57.984122000 Z + updated_at: 2023-03-27 08:47:57.984122000 Z +chained_element77: + id: 77 + element_type: HistoryValue + element_id: 44 + previous_id: 76 + content: + id: 44 + value: '5803' + previous: 96ab834c08316e888f49b232ea69652e3394e7d4fc05758858434c4c855e7984 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 44 + invoicing_profile_id: 1 + footprint: 0a1153b549338be2129ac8740b9a69e306f1630eea597c544c40110d18de81aa + created_at: 2023-03-27 08:47:57.987022000 Z + updated_at: 2023-03-27 08:47:57.987022000 Z +chained_element78: + id: 78 + element_type: HistoryValue + element_id: 45 + previous_id: 77 + content: + id: 45 + value: Payment by other + previous: 0a1153b549338be2129ac8740b9a69e306f1630eea597c544c40110d18de81aa + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 45 + invoicing_profile_id: 1 + footprint: 1377d7b46e6227634561723da54b50188f975dd7604ebd9d56d845466a13143e + created_at: 2023-03-27 08:47:57.989540000 Z + updated_at: 2023-03-27 08:47:57.989540000 Z +chained_element79: + id: 79 + element_type: HistoryValue + element_id: 46 + previous_id: 78 + content: + id: 46 + value: '419100' + previous: 1377d7b46e6227634561723da54b50188f975dd7604ebd9d56d845466a13143e + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 46 + invoicing_profile_id: 1 + footprint: 793034b3eee84f60412d3a56b915a7bab19b24a8e728e89bbcdd80c9b0f5ff8b + created_at: 2023-03-27 08:47:58.014984000 Z + updated_at: 2023-03-27 08:47:58.014984000 Z +chained_element80: + id: 80 + element_type: HistoryValue + element_id: 47 + previous_id: 79 + content: + id: 47 + value: Wallet credit + previous: 793034b3eee84f60412d3a56b915a7bab19b24a8e728e89bbcdd80c9b0f5ff8b + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 47 + invoicing_profile_id: 1 + footprint: 56c673d94a613eea33c8987243526c517ece0304e89ba770697b0dbdfa67814c + created_at: 2023-03-27 08:47:58.017929000 Z + updated_at: 2023-03-27 08:47:58.017929000 Z +chained_element81: + id: 81 + element_type: HistoryValue + element_id: 48 + previous_id: 80 + content: + id: 48 + value: '4457' + previous: 56c673d94a613eea33c8987243526c517ece0304e89ba770697b0dbdfa67814c + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 48 + invoicing_profile_id: 1 + footprint: abced94f701723bd156697b65520b54a37de8d75f7bc7b63309fe5943d8e57f3 + created_at: 2023-03-27 08:47:58.020635000 Z + updated_at: 2023-03-27 08:47:58.020635000 Z +chained_element82: + id: 82 + element_type: HistoryValue + element_id: 49 + previous_id: 81 + content: + id: 49 + value: VAT + previous: abced94f701723bd156697b65520b54a37de8d75f7bc7b63309fe5943d8e57f3 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 49 + invoicing_profile_id: 1 + footprint: 31daf5f92e2111c540bcec45338d8e8dc115759709bee1d4dcc074fcc45302d3 + created_at: 2023-03-27 08:47:58.023451000 Z + updated_at: 2023-03-27 08:47:58.023451000 Z +chained_element83: + id: 83 + element_type: HistoryValue + element_id: 50 + previous_id: 82 + content: + id: 50 + value: '7061' + previous: 31daf5f92e2111c540bcec45338d8e8dc115759709bee1d4dcc074fcc45302d3 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 50 + invoicing_profile_id: 1 + footprint: e0951234463248ecec2ab8ca73d53deba490df387a8fc0cff06a86d191701542 + created_at: 2023-03-27 08:47:58.027454000 Z + updated_at: 2023-03-27 08:47:58.027454000 Z +chained_element84: + id: 84 + element_type: HistoryValue + element_id: 51 + previous_id: 83 + content: + id: 51 + value: Subscription + previous: e0951234463248ecec2ab8ca73d53deba490df387a8fc0cff06a86d191701542 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 51 + invoicing_profile_id: 1 + footprint: 1c1443a6ce9c7ff35882dbc63fb92278864b9699dd2e39a29bb54a90470f822c + created_at: 2023-03-27 08:47:58.029896000 Z + updated_at: 2023-03-27 08:47:58.029896000 Z +chained_element85: + id: 85 + element_type: HistoryValue + element_id: 52 + previous_id: 84 + content: + id: 52 + value: Machine reservation + previous: 1c1443a6ce9c7ff35882dbc63fb92278864b9699dd2e39a29bb54a90470f822c + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 52 + invoicing_profile_id: 1 + footprint: 02e34adbdbae0990cdeca88a5cbc41c55acdb1e790625a81b8c93a55b94344b0 + created_at: 2023-03-27 08:47:58.032975000 Z + updated_at: 2023-03-27 08:47:58.032975000 Z +chained_element86: + id: 86 + element_type: HistoryValue + element_id: 53 + previous_id: 85 + content: + id: 53 + value: '7062' + previous: 02e34adbdbae0990cdeca88a5cbc41c55acdb1e790625a81b8c93a55b94344b0 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 53 + invoicing_profile_id: 1 + footprint: c0d15cc477b7f1617ced24f93512ef0391a4a9ebd33f37a84c43c85e64b852b6 + created_at: 2023-03-27 08:47:58.035815000 Z + updated_at: 2023-03-27 08:47:58.035815000 Z +chained_element87: + id: 87 + element_type: HistoryValue + element_id: 54 + previous_id: 86 + content: + id: 54 + value: Training reservation + previous: c0d15cc477b7f1617ced24f93512ef0391a4a9ebd33f37a84c43c85e64b852b6 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 54 + invoicing_profile_id: 1 + footprint: ac6b2d9002359af614829300037655a59eeecd33b4576ee9a04cf28ad6a4f675 + created_at: 2023-03-27 08:47:58.038416000 Z + updated_at: 2023-03-27 08:47:58.038416000 Z +chained_element88: + id: 88 + element_type: HistoryValue + element_id: 55 + previous_id: 87 + content: + id: 55 + value: '7063' + previous: ac6b2d9002359af614829300037655a59eeecd33b4576ee9a04cf28ad6a4f675 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 55 + invoicing_profile_id: 1 + footprint: 8cf5c3dda9a5c970a63ce15e80ac9291374fa0b7032fd482cf608c4ccdeb93f6 + created_at: 2023-03-27 08:47:58.042193000 Z + updated_at: 2023-03-27 08:47:58.042193000 Z +chained_element89: + id: 89 + element_type: HistoryValue + element_id: 56 + previous_id: 88 + content: + id: 56 + value: Event reservation + previous: 8cf5c3dda9a5c970a63ce15e80ac9291374fa0b7032fd482cf608c4ccdeb93f6 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 56 + invoicing_profile_id: 1 + footprint: afa383e724c0b8e12ebe7efbee8f2315b764bf3cb8076eb47b8a2fd837e39dcf + created_at: 2023-03-27 08:47:58.044725000 Z + updated_at: 2023-03-27 08:47:58.044725000 Z +chained_element90: + id: 90 + element_type: HistoryValue + element_id: 57 + previous_id: 89 + content: + id: 57 + value: '7064' + previous: afa383e724c0b8e12ebe7efbee8f2315b764bf3cb8076eb47b8a2fd837e39dcf + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 57 + invoicing_profile_id: 1 + footprint: 877fb7b2322513f631d222956db89eb01bdadf50f603b070dd1b7138c0e4537d + created_at: 2023-03-27 08:47:58.047152000 Z + updated_at: 2023-03-27 08:47:58.047152000 Z +chained_element91: + id: 91 + element_type: HistoryValue + element_id: 58 + previous_id: 90 + content: + id: 58 + value: '7065' + previous: 877fb7b2322513f631d222956db89eb01bdadf50f603b070dd1b7138c0e4537d + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 58 + invoicing_profile_id: 1 + footprint: 01ee85aec13b492636abb82d4421b22b82aca2045a3d54bfa925c82f982cf837 + created_at: 2023-03-27 08:47:58.049583000 Z + updated_at: 2023-03-27 08:47:58.049583000 Z +chained_element92: + id: 92 + element_type: HistoryValue + element_id: 59 + previous_id: 91 + content: + id: 59 + value: Space reservation + previous: 01ee85aec13b492636abb82d4421b22b82aca2045a3d54bfa925c82f982cf837 + created_at: '2019-09-20T13:02:32+02:00' + setting_id: 59 + invoicing_profile_id: 1 + footprint: d48daab0a907149ebfdf2cf8fcf3e2ebcfbd858614444caad8f7cb8dffd9b3bd + created_at: 2023-03-27 08:47:58.052223000 Z + updated_at: 2023-03-27 08:47:58.052223000 Z +chained_element93: + id: 93 + element_type: HistoryValue + element_id: 60 + previous_id: 92 + content: + id: 60 + value: |- +
+
+
News
+
+
+
+
Projects
+
+
+
Last tweet
+
Last members
+
+
+
+
+
Next events
+
+
+
+ previous: d48daab0a907149ebfdf2cf8fcf3e2ebcfbd858614444caad8f7cb8dffd9b3bd + created_at: '2020-03-25T10:24:09+01:00' + setting_id: 60 + invoicing_profile_id: 1 + footprint: 40b57db3d5c6b3f43849d861f7ebe9961e3e279e8842785a6b8dc4b951e1c7bb + created_at: 2023-03-27 08:47:58.055719000 Z + updated_at: 2023-03-27 08:47:58.055719000 Z +chained_element94: + id: 94 + element_type: HistoryValue + element_id: 61 + previous_id: 93 + content: + id: 61 + value: '60' + previous: 40b57db3d5c6b3f43849d861f7ebe9961e3e279e8842785a6b8dc4b951e1c7bb + created_at: '2020-05-22T17:22:08+02:00' + setting_id: 61 + invoicing_profile_id: 1 + footprint: 4a8df51f2547472d2ca60675f498f146db3e6d889a2f8d2aa65a542b43b998ef + created_at: 2023-03-27 08:47:58.058830000 Z + updated_at: 2023-03-27 08:47:58.058830000 Z +chained_element95: + id: 95 + element_type: HistoryValue + element_id: 62 + previous_id: 94 + content: + id: 62 + value: 'true' + previous: 4a8df51f2547472d2ca60675f498f146db3e6d889a2f8d2aa65a542b43b998ef + created_at: '2020-06-01T13:12:21+02:00' + setting_id: 62 + invoicing_profile_id: 1 + footprint: 399ae14e656d48aa7f0cfb48a751677305d9a491d948f308d4d8b4475d76489f + created_at: 2023-03-27 08:47:58.061052000 Z + updated_at: 2023-03-27 08:47:58.061052000 Z +chained_element96: + id: 96 + element_type: HistoryValue + element_id: 63 + previous_id: 95 + content: + id: 63 + value: 'true' + previous: 399ae14e656d48aa7f0cfb48a751677305d9a491d948f308d4d8b4475d76489f + created_at: '2020-06-01T13:12:21+02:00' + setting_id: 63 + invoicing_profile_id: 1 + footprint: 317dc60fe067ef4dd9b595d8995f96d299c81b7475614e9ebbe4658b6bc81603 + created_at: 2023-03-27 08:47:58.064078000 Z + updated_at: 2023-03-27 08:47:58.064078000 Z +chained_element97: + id: 97 + element_type: HistoryValue + element_id: 64 + previous_id: 96 + content: + id: 64 + value: once + previous: 317dc60fe067ef4dd9b595d8995f96d299c81b7475614e9ebbe4658b6bc81603 + created_at: '2020-06-01T13:12:21+02:00' + setting_id: 64 + invoicing_profile_id: 1 + footprint: 6c6d35c98c9b5f29ac26fde96bd3bbb40f482fc670c37e35fee057622d787dd6 + created_at: 2023-03-27 08:47:58.066201000 Z + updated_at: 2023-03-27 08:47:58.066201000 Z +chained_element98: + id: 98 + element_type: HistoryValue + element_id: 65 + previous_id: 97 + content: + id: 65 + value: noreply@fab-manager.com + previous: 6c6d35c98c9b5f29ac26fde96bd3bbb40f482fc670c37e35fee057622d787dd6 + created_at: '2020-06-01T13:12:21+02:00' + setting_id: 65 + invoicing_profile_id: 1 + footprint: a297cdf8d1fef172ceae1142215a599177ce1b3b49449b34b7d44b89f9d6f328 + created_at: 2023-03-27 08:47:58.068328000 Z + updated_at: 2023-03-27 08:47:58.068328000 Z +chained_element99: + id: 99 + element_type: HistoryValue + element_id: 66 + previous_id: 98 + content: + id: 66 + value: 'true' + previous: a297cdf8d1fef172ceae1142215a599177ce1b3b49449b34b7d44b89f9d6f328 + created_at: '2020-06-08T19:12:16+02:00' + setting_id: 66 + invoicing_profile_id: 1 + footprint: ef7ee666cbdd6114861a14cbf6d883ac2cc8b342cd1ccb94565c6f8afb2019af + created_at: 2023-03-27 08:47:58.070587000 Z + updated_at: 2023-03-27 08:47:58.070587000 Z +chained_element100: + id: 100 + element_type: HistoryValue + element_id: 67 + previous_id: 99 + content: + id: 67 + value: pk_test_aScrMu3y4AocfCN5XLJjGzmQ + previous: ef7ee666cbdd6114861a14cbf6d883ac2cc8b342cd1ccb94565c6f8afb2019af + created_at: '2020-06-08T19:12:16+02:00' + setting_id: 67 + invoicing_profile_id: 1 + footprint: a1fbaba25ea8919330dc9b7bc3220aa6ace80d6c3ea5eccf03c08e0cf2f73f18 + created_at: 2023-03-27 08:47:58.073025000 Z + updated_at: 2023-03-27 08:47:58.073025000 Z +chained_element101: + id: 101 + element_type: HistoryValue + element_id: 68 + previous_id: 100 + content: + id: 68 + value: sk_test_mGokO9TGtrVxMOyK4yZiktBE + previous: a1fbaba25ea8919330dc9b7bc3220aa6ace80d6c3ea5eccf03c08e0cf2f73f18 + created_at: '2020-06-08T19:12:16+02:00' + setting_id: 68 + invoicing_profile_id: 1 + footprint: 8ce7e195c1aab7a3795d1cffae5816d6253c8f34157455000aa28764a585a1d1 + created_at: 2023-03-27 08:47:58.076269000 Z + updated_at: 2023-03-27 08:47:58.076269000 Z +chained_element102: + id: 102 + element_type: HistoryValue + element_id: 69 + previous_id: 101 + content: + id: 69 + value: usd + previous: 8ce7e195c1aab7a3795d1cffae5816d6253c8f34157455000aa28764a585a1d1 + created_at: '2020-06-08T19:12:16+02:00' + setting_id: 69 + invoicing_profile_id: 1 + footprint: 9b436ae3167c15669456f99ab20f44e25caf1bccb0a521e0e7318e42bfe42f09 + created_at: 2023-03-27 08:47:58.078677000 Z + updated_at: 2023-03-27 08:47:58.078677000 Z +chained_element103: + id: 103 + element_type: HistoryValue + element_id: 70 + previous_id: 102 + content: + id: 70 + value: FabManager_invoice + previous: 9b436ae3167c15669456f99ab20f44e25caf1bccb0a521e0e7318e42bfe42f09 + created_at: '2020-06-15T12:04:06+02:00' + setting_id: 70 + invoicing_profile_id: 1 + footprint: e1fdf5ddcce74be68ea146918db31dca07a0e2e3c9599a2ae83b3066602e3e06 + created_at: 2023-03-27 08:47:58.081906000 Z + updated_at: 2023-03-27 08:47:58.081906000 Z +chained_element104: + id: 104 + element_type: HistoryValue + element_id: 71 + previous_id: 103 + content: + id: 71 + value: 'false' + previous: e1fdf5ddcce74be68ea146918db31dca07a0e2e3c9599a2ae83b3066602e3e06 + created_at: '2020-06-15T12:04:06+02:00' + setting_id: 71 + invoicing_profile_id: 1 + footprint: e98d69989a8cc3d28226009a500dcc31d74477f8649890fa38f7733f4fe09e7e + created_at: 2023-03-27 08:47:58.085182000 Z + updated_at: 2023-03-27 08:47:58.085182000 Z +chained_element105: + id: 105 + element_type: HistoryValue + element_id: 72 + previous_id: 104 + content: + id: 72 + value: 'true' + previous: e98d69989a8cc3d28226009a500dcc31d74477f8649890fa38f7733f4fe09e7e + created_at: '2020-06-15T12:04:06+02:00' + setting_id: 72 + invoicing_profile_id: 1 + footprint: 4a9503e9388e7285d99d7fc6925c526aa6871ae69fb06dfbf42c4c31d206c1e0 + created_at: 2023-03-27 08:47:58.087749000 Z + updated_at: 2023-03-27 08:47:58.087749000 Z +chained_element106: + id: 106 + element_type: HistoryValue + element_id: 73 + previous_id: 105 + content: + id: 73 + value: 'true' + previous: 4a9503e9388e7285d99d7fc6925c526aa6871ae69fb06dfbf42c4c31d206c1e0 + created_at: '2020-06-17T12:48:19+02:00' + setting_id: 73 + invoicing_profile_id: 1 + footprint: 271cc66432b83306f6d98e672d4676190b4b2dac34d565f9a6061a9c4c44154b + created_at: 2023-03-27 08:47:58.090613000 Z + updated_at: 2023-03-27 08:47:58.090613000 Z +chained_element107: + id: 107 + element_type: HistoryValue + element_id: 74 + previous_id: 106 + content: + id: 74 + value: until_start + previous: 271cc66432b83306f6d98e672d4676190b4b2dac34d565f9a6061a9c4c44154b + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 74 + invoicing_profile_id: 1 + footprint: 655167fb99a1f6f50f72760010e018d92edce20320c486c2e703b5fd459c53f6 + created_at: 2023-03-27 08:47:58.093257000 Z + updated_at: 2023-03-27 08:47:58.093257000 Z +chained_element108: + id: 108 + element_type: HistoryValue + element_id: 75 + previous_id: 107 + content: + id: 75 + value: FabManager_paymentSchedule + previous: 655167fb99a1f6f50f72760010e018d92edce20320c486c2e703b5fd459c53f6 + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 75 + invoicing_profile_id: 1 + footprint: c2fdec09535ea86d8a27b8a0019be96a1aea30c0c0f657a5b36e265b88f14a98 + created_at: 2023-03-27 08:47:58.096527000 Z + updated_at: 2023-03-27 08:47:58.096527000 Z +chained_element109: + id: 109 + element_type: HistoryValue + element_id: 76 + previous_id: 108 + content: + id: 76 + value: 'true' + previous: c2fdec09535ea86d8a27b8a0019be96a1aea30c0c0f657a5b36e265b88f14a98 + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 76 + invoicing_profile_id: 1 + footprint: ff8f905802872aa72981d59e41615984c07798c662d92fa18b81fe8abd9ad285 + created_at: 2023-03-27 08:47:58.099510000 Z + updated_at: 2023-03-27 08:47:58.099510000 Z +chained_element110: + id: 110 + element_type: HistoryValue + element_id: 77 + previous_id: 109 + content: + id: 77 + value: 'false' + previous: ff8f905802872aa72981d59e41615984c07798c662d92fa18b81fe8abd9ad285 + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 77 + invoicing_profile_id: 1 + footprint: 787911a429fe5d05a0a8bda5280d877c98ca0493444ee8822d6652a857841962 + created_at: 2023-03-27 08:47:58.102658000 Z + updated_at: 2023-03-27 08:47:58.102658000 Z +chained_element111: + id: 111 + element_type: HistoryValue + element_id: 78 + previous_id: 110 + content: + id: 78 + value: stripe + previous: 787911a429fe5d05a0a8bda5280d877c98ca0493444ee8822d6652a857841962 + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 78 + invoicing_profile_id: 1 + footprint: a17582deb70542b7da337217b13a19e10a11835fee7a94c8f5e8faaeb543f440 + created_at: 2023-03-27 08:47:58.106468000 Z + updated_at: 2023-03-27 08:47:58.106468000 Z +chained_element112: + id: 112 + element_type: HistoryValue + element_id: 79 + previous_id: 111 + content: + id: 79 + value: '69876357' + previous: a17582deb70542b7da337217b13a19e10a11835fee7a94c8f5e8faaeb543f440 + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 79 + invoicing_profile_id: 1 + footprint: 7f8f4ba4f0c3654c34dcc21dbbde4bf63fa23fc80bf7a9551f2f92a8a447d285 + created_at: 2023-03-27 08:47:58.109212000 Z + updated_at: 2023-03-27 08:47:58.109212000 Z +chained_element113: + id: 113 + element_type: HistoryValue + element_id: 80 + previous_id: 112 + content: + id: 80 + value: testpassword_DEMOPRIVATEKEY23G4475zXZQ2UA5x7M + previous: 7f8f4ba4f0c3654c34dcc21dbbde4bf63fa23fc80bf7a9551f2f92a8a447d285 + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 80 + invoicing_profile_id: 1 + footprint: 844c62d72e713f73f95a2bc526ae63f6e02c98dd57df4e299173fbb6732989b0 + created_at: 2023-03-27 08:47:58.112443000 Z + updated_at: 2023-03-27 08:47:58.112443000 Z +chained_element114: + id: 114 + element_type: HistoryValue + element_id: 81 + previous_id: 113 + content: + id: 81 + value: https://api.payzen.eu + previous: 844c62d72e713f73f95a2bc526ae63f6e02c98dd57df4e299173fbb6732989b0 + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 81 + invoicing_profile_id: 1 + footprint: 89aec9e8497de9a7894b46c3c92f264d61c4941ab690476443ad062c44cc260f + created_at: 2023-03-27 08:47:58.116276000 Z + updated_at: 2023-03-27 08:47:58.116276000 Z +chained_element115: + id: 115 + element_type: HistoryValue + element_id: 82 + previous_id: 114 + content: + id: 82 + value: 69876357:testpublickey_DEMOPUBLICKEY95me92597fd28tGD4r5 + previous: 89aec9e8497de9a7894b46c3c92f264d61c4941ab690476443ad062c44cc260f + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 82 + invoicing_profile_id: 1 + footprint: c9001301e63f84afca55019b24d635a46b33252c8632d8f35dc524882fe85edb + created_at: 2023-03-27 08:47:58.119194000 Z + updated_at: 2023-03-27 08:47:58.119194000 Z +chained_element116: + id: 116 + element_type: HistoryValue + element_id: 83 + previous_id: 115 + content: + id: 83 + value: 83daf5e7b80d990f037407bab78dff9904aaf3c19 + previous: c9001301e63f84afca55019b24d635a46b33252c8632d8f35dc524882fe85edb + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 83 + invoicing_profile_id: 1 + footprint: a0beaaae3698630912e01e77705010a063337b5746845a46bdd791f22c3fbc5c + created_at: 2023-03-27 08:47:58.121815000 Z + updated_at: 2023-03-27 08:47:58.121815000 Z +chained_element117: + id: 117 + element_type: HistoryValue + element_id: 84 + previous_id: 116 + content: + id: 84 + value: EUR + previous: a0beaaae3698630912e01e77705010a063337b5746845a46bdd791f22c3fbc5c + created_at: '2020-04-15T16:38:40+02:00' + setting_id: 84 + invoicing_profile_id: 1 + footprint: 833e659b4804238d5c0e7832a4dd6f4c7a10bcc14caab37f9aec63acacdd8584 + created_at: 2023-03-27 08:47:58.124630000 Z + updated_at: 2023-03-27 08:47:58.124630000 Z +chained_element118: + id: 118 + element_type: HistoryValue + element_id: 85 + previous_id: 117 + content: + id: 85 + value: YYMMmmmX[/VL]R[/A]S[/E] + previous: 833e659b4804238d5c0e7832a4dd6f4c7a10bcc14caab37f9aec63acacdd8584 + created_at: '2020-12-14T15:37:35+01:00' + setting_id: 10 + invoicing_profile_id: 1 + footprint: 35d12a9a08a16b231a9604091f6c6cbd4b616c9c5adc4172fb7f6d84fae956c4 + created_at: 2023-03-27 08:47:58.128239000 Z + updated_at: 2023-03-27 08:47:58.128239000 Z +chained_element119: + id: 119 + element_type: HistoryValue + element_id: 86 + previous_id: 118 + content: + id: 86 + value: t + previous: 35d12a9a08a16b231a9604091f6c6cbd4b616c9c5adc4172fb7f6d84fae956c4 + created_at: '2021-06-15T14:05:21+02:00' + setting_id: 85 + invoicing_profile_id: 1 + footprint: 46f5175b8147ca831bf5ba7ab9e7526fb0fafc30b8633cbc900e73cb5bf9067a + created_at: 2023-03-27 08:47:58.130932000 Z + updated_at: 2023-03-27 08:47:58.130932000 Z +chained_element120: + id: 120 + element_type: HistoryValue + element_id: 87 + previous_id: 119 + content: + id: 87 + value: Prepaid pack + previous: 46f5175b8147ca831bf5ba7ab9e7526fb0fafc30b8633cbc900e73cb5bf9067a + created_at: '2022-10-26T14:46:16+02:00' + setting_id: 86 + invoicing_profile_id: 1 + footprint: b3a29ed1543d0e68b49760396a2cd91363adfbcae7b7aa35fe129a7570f6b7f2 + created_at: 2023-03-27 08:47:58.133141000 Z + updated_at: 2023-03-27 08:47:58.133141000 Z +chained_element121: + id: 121 + element_type: HistoryValue + element_id: 88 + previous_id: 120 + content: + id: 88 + value: '7066' + previous: b3a29ed1543d0e68b49760396a2cd91363adfbcae7b7aa35fe129a7570f6b7f2 + created_at: '2022-10-26T14:46:16+02:00' + setting_id: 87 + invoicing_profile_id: 1 + footprint: b31a034a0f564837cf0fb68f39ce8b8d88a6cc43aa2e87cdea965b1ccf49bd1d + created_at: 2023-03-27 08:47:58.135130000 Z + updated_at: 2023-03-27 08:47:58.135130000 Z +chained_element122: + id: 122 + element_type: HistoryValue + element_id: 89 + previous_id: 121 + content: + id: 89 + value: Shop order + previous: b31a034a0f564837cf0fb68f39ce8b8d88a6cc43aa2e87cdea965b1ccf49bd1d + created_at: '2022-10-26T14:46:16+02:00' + setting_id: 88 + invoicing_profile_id: 1 + footprint: bb6f8cabadf5327854a091779cfe372be41b03e3396ee32235af544437b0ba37 + created_at: 2023-03-27 08:47:58.137263000 Z + updated_at: 2023-03-27 08:47:58.137263000 Z +chained_element123: + id: 123 + element_type: HistoryValue + element_id: 90 + previous_id: 122 + content: + id: 90 + value: '7071' + previous: bb6f8cabadf5327854a091779cfe372be41b03e3396ee32235af544437b0ba37 + created_at: '2022-10-26T14:46:16+02:00' + setting_id: 89 + invoicing_profile_id: 1 + footprint: 5f96d70d9e1d0774106e15d6ce1d452d5272280b2543fdc1d4d854820d66febb + created_at: 2023-03-27 08:47:58.139454000 Z + updated_at: 2023-03-27 08:47:58.139454000 Z +chained_element124: + id: 124 + element_type: HistoryValue + element_id: 91 + previous_id: 123 + content: + id: 91 + value: CB01 + previous: 5f96d70d9e1d0774106e15d6ce1d452d5272280b2543fdc1d4d854820d66febb + created_at: '2022-12-09T15:00:14+01:00' + setting_id: 90 + invoicing_profile_id: 1 + footprint: 05a5531b5b1805655f167507c6920b7e7627a0f8534dbb29822ff86d3ae8a55f + created_at: 2023-03-27 08:47:58.141871000 Z + updated_at: 2023-03-27 08:47:58.141871000 Z +chained_element125: + id: 125 + element_type: HistoryValue + element_id: 92 + previous_id: 124 + content: + id: 92 + value: W001 + previous: 05a5531b5b1805655f167507c6920b7e7627a0f8534dbb29822ff86d3ae8a55f + created_at: '2022-12-09T15:00:14+01:00' + setting_id: 91 + invoicing_profile_id: 1 + footprint: 78829b4b170342317aa633c0acc3e62ff8bf3e41ee91d9545fbf75a096752f65 + created_at: 2023-03-27 08:47:58.144251000 Z + updated_at: 2023-03-27 08:47:58.144251000 Z +chained_element126: + id: 126 + element_type: HistoryValue + element_id: 93 + previous_id: 125 + content: + id: 93 + value: CA01 + previous: 78829b4b170342317aa633c0acc3e62ff8bf3e41ee91d9545fbf75a096752f65 + created_at: '2022-12-09T15:00:14+01:00' + setting_id: 92 + invoicing_profile_id: 1 + footprint: d9466cf10effc8ee734fbb52d5cd2d470d138d34bcddc822fd357721fea7a1f2 + created_at: 2023-03-27 08:47:58.147370000 Z + updated_at: 2023-03-27 08:47:58.147370000 Z +chained_element127: + id: 127 + element_type: HistoryValue + element_id: 94 + previous_id: 126 + content: + id: 94 + value: W002 + previous: d9466cf10effc8ee734fbb52d5cd2d470d138d34bcddc822fd357721fea7a1f2 + created_at: '2022-12-09T15:00:14+01:00' + setting_id: 93 + invoicing_profile_id: 1 + footprint: 3456a60825db8784543117072e8c5f62351fde5f395bff88810b4117cbf6f363 + created_at: 2023-03-27 08:47:58.149636000 Z + updated_at: 2023-03-27 08:47:58.149636000 Z +chained_element128: + id: 128 + element_type: HistoryValue + element_id: 95 + previous_id: 127 + content: + id: 95 + value: TVA1 + previous: 3456a60825db8784543117072e8c5f62351fde5f395bff88810b4117cbf6f363 + created_at: '2022-12-09T15:00:14+01:00' + setting_id: 94 + invoicing_profile_id: 1 + footprint: 0f01affefb4c5a18b3630c4b297e2824ac222865b3b2fd8db462f6c958c03eed + created_at: 2023-03-27 08:47:58.151882000 Z + updated_at: 2023-03-27 08:47:58.151882000 Z +chained_element129: + id: 129 + element_type: HistoryValue + element_id: 96 + previous_id: 128 + content: + id: 96 + value: 'false' + previous: 0f01affefb4c5a18b3630c4b297e2824ac222865b3b2fd8db462f6c958c03eed + created_at: '2022-12-22T15:45:07+01:00' + setting_id: 95 + invoicing_profile_id: 1 + footprint: 97f7539811e6407f069524ba8ef858c1b186d19441690853b9860e351d9d1468 + created_at: 2023-03-27 08:47:58.154392000 Z + updated_at: 2023-03-27 08:47:58.154392000 Z +chained_element130: + id: 130 + element_type: HistoryValue + element_id: 97 + previous_id: 129 + content: + id: 97 + value: '0' + previous: 97f7539811e6407f069524ba8ef858c1b186d19441690853b9860e351d9d1468 + created_at: '2022-11-29T22:02:47+01:00' + setting_id: 96 + invoicing_profile_id: 1 + footprint: 144944b95aef0545c30fcda4d5d8ef4ec3c0662d4ad6846398c8376b719ae806 + created_at: 2023-03-27 08:47:58.156431000 Z + updated_at: 2023-03-27 08:47:58.156431000 Z +chained_element131: + id: 131 + element_type: HistoryValue + element_id: 98 + previous_id: 130 + content: + id: 98 + value: TVA + previous: 144944b95aef0545c30fcda4d5d8ef4ec3c0662d4ad6846398c8376b719ae806 + created_at: '2022-12-23T15:39:12+01:00' + setting_id: 97 + invoicing_profile_id: 1 + footprint: 65226b3f9567b465c06805f27e87dd4171c86de5f8377c3341d18d170114e2db + created_at: 2023-03-27 08:47:58.158805000 Z + updated_at: 2023-03-27 08:47:58.158805000 Z +chained_element132: + id: 132 + element_type: HistoryValue + element_id: 99 + previous_id: 131 + content: + id: 99 + value: 'true' + previous: 65226b3f9567b465c06805f27e87dd4171c86de5f8377c3341d18d170114e2db + created_at: '2022-12-20T15:38:40+01:00' + setting_id: 98 + invoicing_profile_id: 1 + footprint: dcb161a8a9565434d60a124fe760838e9faae7e54a60bb0e10329b907067c58d + created_at: 2023-03-27 08:47:58.161331000 Z + updated_at: 2023-03-27 08:47:58.161331000 Z +chained_element133: + id: 133 + element_type: PaymentSchedule + element_id: 12 + previous_id: + content: + id: 12 + total: 180000 + previous: + reference: 2106309/E + created_at: '2021-06-14T14:24:45+02:00' + environment: development + operator_profile_id: 1 + invoicing_profile_id: 9 + statistic_profile_id: 9 + footprint: 6208cc7dc2a3d61d00c095adf5787c05f1c2966c3563868ee315c1afd8cec2b7 + created_at: 2023-03-27 08:47:58.185253000 Z + updated_at: 2023-03-27 08:47:58.185253000 Z +chained_element134: + id: 134 + element_type: PaymentSchedule + element_id: 13 + previous_id: 133 + content: + id: 13 + total: 180000 + previous: 6208cc7dc2a3d61d00c095adf5787c05f1c2966c3563868ee315c1afd8cec2b7 + reference: 2206310/E + created_at: '2022-06-27T10:43:14+02:00' + environment: development + operator_profile_id: 10 + invoicing_profile_id: 10 + statistic_profile_id: 10 + footprint: 103a5139d9fa51ee6578d30b6918b0884ef5dbf5c9a88a7300e2c8bd3f0b668c + created_at: 2023-03-27 08:47:58.187804000 Z + updated_at: 2023-03-27 08:47:58.187804000 Z +chained_element135: + id: 135 + element_type: PaymentScheduleItem + element_id: 105 + previous_id: + content: + id: 105 + amount: 9474 + details: + recurring: 9466 + adjustment: 8 + other_items: 0 + due_date: '2021-06-14T14:24:45+02:00' + previous: + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: b0857f06f4aaad1171d05c9296ccf8bf36b8423460014282f8f330da80907267 + created_at: 2023-03-27 08:47:58.212137000 Z + updated_at: 2023-03-27 08:47:58.212137000 Z +chained_element136: + id: 136 + element_type: PaymentScheduleItem + element_id: 106 + previous_id: 135 + content: + id: 106 + amount: 9466 + details: + recurring: 9466 + due_date: '2021-07-14T14:24:45+02:00' + previous: b0857f06f4aaad1171d05c9296ccf8bf36b8423460014282f8f330da80907267 + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 36daee5e084c88621220ef1d3361881575b37fe042c71ba541737a56a7379bb2 + created_at: 2023-03-27 08:47:58.214847000 Z + updated_at: 2023-03-27 08:47:58.214847000 Z +chained_element137: + id: 137 + element_type: PaymentScheduleItem + element_id: 107 + previous_id: 136 + content: + id: 107 + amount: 9466 + details: + recurring: 9466 + due_date: '2021-08-14T14:24:45+02:00' + previous: 36daee5e084c88621220ef1d3361881575b37fe042c71ba541737a56a7379bb2 + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 9978436ae627bf9d7b55b4ac3cba7d21d077659841a0e8bcc58301543a6818cf + created_at: 2023-03-27 08:47:58.217666000 Z + updated_at: 2023-03-27 08:47:58.217666000 Z +chained_element138: + id: 138 + element_type: PaymentScheduleItem + element_id: 108 + previous_id: 137 + content: + id: 108 + amount: 9466 + details: + recurring: 9466 + due_date: '2021-09-14T14:24:45+02:00' + previous: 9978436ae627bf9d7b55b4ac3cba7d21d077659841a0e8bcc58301543a6818cf + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 0ef34956375cc8ad53bc3209f10f88865b98ebe5a36a70d1c812f2ee0a6b343c + created_at: 2023-03-27 08:47:58.220508000 Z + updated_at: 2023-03-27 08:47:58.220508000 Z +chained_element139: + id: 139 + element_type: PaymentScheduleItem + element_id: 109 + previous_id: 138 + content: + id: 109 + amount: 9466 + details: + recurring: 9466 + due_date: '2021-10-14T14:24:45+02:00' + previous: 0ef34956375cc8ad53bc3209f10f88865b98ebe5a36a70d1c812f2ee0a6b343c + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 05f0ddda7ef2cb6954d9549a0b096685028f9d86655286e27a5411c7a02d1532 + created_at: 2023-03-27 08:47:58.225240000 Z + updated_at: 2023-03-27 08:47:58.225240000 Z +chained_element140: + id: 140 + element_type: PaymentScheduleItem + element_id: 110 + previous_id: 139 + content: + id: 110 + amount: 9466 + details: + recurring: 9466 + due_date: '2021-11-14T13:24:45+01:00' + previous: 05f0ddda7ef2cb6954d9549a0b096685028f9d86655286e27a5411c7a02d1532 + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 03f5d9185eb0c5b7f7f343cdb54acb348e845990141a02f981b93dcfd00932ec + created_at: 2023-03-27 08:47:58.230136000 Z + updated_at: 2023-03-27 08:47:58.230136000 Z +chained_element141: + id: 141 + element_type: PaymentScheduleItem + element_id: 111 + previous_id: 140 + content: + id: 111 + amount: 9466 + details: + recurring: 9466 + due_date: '2021-12-14T13:24:45+01:00' + previous: 03f5d9185eb0c5b7f7f343cdb54acb348e845990141a02f981b93dcfd00932ec + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 9fbbcf0b30545a1c59f675b74d17669e04a189ffce4af4c56c9eb6931233647a + created_at: 2023-03-27 08:47:58.232515000 Z + updated_at: 2023-03-27 08:47:58.232515000 Z +chained_element142: + id: 142 + element_type: PaymentScheduleItem + element_id: 112 + previous_id: 141 + content: + id: 112 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-01-14T13:24:45+01:00' + previous: 9fbbcf0b30545a1c59f675b74d17669e04a189ffce4af4c56c9eb6931233647a + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 6a46ace0416f252e7ba4655f5e6dcb9b01ad625e4ef5c222810ee7bc6d123e49 + created_at: 2023-03-27 08:47:58.234682000 Z + updated_at: 2023-03-27 08:47:58.234682000 Z +chained_element143: + id: 143 + element_type: PaymentScheduleItem + element_id: 113 + previous_id: 142 + content: + id: 113 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-02-14T13:24:45+01:00' + previous: 6a46ace0416f252e7ba4655f5e6dcb9b01ad625e4ef5c222810ee7bc6d123e49 + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 67672c6a1a8753432e6d67216863d01d71ce2c3a0501bf100fb09881d6195197 + created_at: 2023-03-27 08:47:58.236959000 Z + updated_at: 2023-03-27 08:47:58.236959000 Z +chained_element144: + id: 144 + element_type: PaymentScheduleItem + element_id: 114 + previous_id: 143 + content: + id: 114 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-03-14T13:24:45+01:00' + previous: 67672c6a1a8753432e6d67216863d01d71ce2c3a0501bf100fb09881d6195197 + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 4fb14e938f6a1c58b58f33374e34c02d900592fd25887e056102fc138b6757ff + created_at: 2023-03-27 08:47:58.239233000 Z + updated_at: 2023-03-27 08:47:58.239233000 Z +chained_element145: + id: 145 + element_type: PaymentScheduleItem + element_id: 115 + previous_id: 144 + content: + id: 115 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-04-14T14:24:45+02:00' + previous: 4fb14e938f6a1c58b58f33374e34c02d900592fd25887e056102fc138b6757ff + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 91eeff6cae5bb4e5a281d1f6ba6c9ddfbc33aaa2bacb654db86e206cab7cdef3 + created_at: 2023-03-27 08:47:58.241374000 Z + updated_at: 2023-03-27 08:47:58.241374000 Z +chained_element146: + id: 146 + element_type: PaymentScheduleItem + element_id: 116 + previous_id: 145 + content: + id: 116 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-05-14T14:24:45+02:00' + previous: 91eeff6cae5bb4e5a281d1f6ba6c9ddfbc33aaa2bacb654db86e206cab7cdef3 + created_at: '2021-06-14T14:24:45+02:00' + payment_schedule_id: 12 + footprint: 758ac7bdb397db943f018186467d94f80edcdb374093ac5a8b2a3c2ce91c25c2 + created_at: 2023-03-27 08:47:58.243774000 Z + updated_at: 2023-03-27 08:47:58.243774000 Z +chained_element147: + id: 147 + element_type: PaymentScheduleItem + element_id: 117 + previous_id: 146 + content: + id: 117 + amount: 9474 + details: + recurring: 9466 + adjustment: 8 + other_items: 0 + due_date: '2022-06-27T10:43:14+02:00' + previous: 758ac7bdb397db943f018186467d94f80edcdb374093ac5a8b2a3c2ce91c25c2 + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 0c15e8c79d1750c65616f6d49e85b8e754c0f66cd458b38e8eda658823540dfa + created_at: 2023-03-27 08:47:58.246299000 Z + updated_at: 2023-03-27 08:47:58.246299000 Z +chained_element148: + id: 148 + element_type: PaymentScheduleItem + element_id: 118 + previous_id: 147 + content: + id: 118 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-07-27T10:43:14+02:00' + previous: 0c15e8c79d1750c65616f6d49e85b8e754c0f66cd458b38e8eda658823540dfa + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 19dfe2c08a197773c02550dc806428abe055f79c2542b0427f26298d80eda7ef + created_at: 2023-03-27 08:47:58.248512000 Z + updated_at: 2023-03-27 08:47:58.248512000 Z +chained_element149: + id: 149 + element_type: PaymentScheduleItem + element_id: 119 + previous_id: 148 + content: + id: 119 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-08-27T10:43:14+02:00' + previous: 19dfe2c08a197773c02550dc806428abe055f79c2542b0427f26298d80eda7ef + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 0af9f0aa025b73dd25dfdd983cd64dc7d4152041235c7636d8c7775655a295f8 + created_at: 2023-03-27 08:47:58.250978000 Z + updated_at: 2023-03-27 08:47:58.250978000 Z +chained_element150: + id: 150 + element_type: PaymentScheduleItem + element_id: 120 + previous_id: 149 + content: + id: 120 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-09-27T10:43:14+02:00' + previous: 0af9f0aa025b73dd25dfdd983cd64dc7d4152041235c7636d8c7775655a295f8 + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 42b2dc2f8e987f0eecf93c3c3cebee8eafc179714ea92b8d26a3b73b96a020ca + created_at: 2023-03-27 08:47:58.253738000 Z + updated_at: 2023-03-27 08:47:58.253738000 Z +chained_element151: + id: 151 + element_type: PaymentScheduleItem + element_id: 121 + previous_id: 150 + content: + id: 121 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-10-27T10:43:14+02:00' + previous: 42b2dc2f8e987f0eecf93c3c3cebee8eafc179714ea92b8d26a3b73b96a020ca + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: efa228e492d52e98c13193fb235e57ebbf3f0532de58e9d02d6c95c2edd7633f + created_at: 2023-03-27 08:47:58.256597000 Z + updated_at: 2023-03-27 08:47:58.256597000 Z +chained_element152: + id: 152 + element_type: PaymentScheduleItem + element_id: 122 + previous_id: 151 + content: + id: 122 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-11-27T10:43:14+01:00' + previous: efa228e492d52e98c13193fb235e57ebbf3f0532de58e9d02d6c95c2edd7633f + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: acbf9b1f353dda77a82d4417a998cc71bf16f02b512c81c320dec0501a7bc975 + created_at: 2023-03-27 08:47:58.259346000 Z + updated_at: 2023-03-27 08:47:58.259346000 Z +chained_element153: + id: 153 + element_type: PaymentScheduleItem + element_id: 123 + previous_id: 152 + content: + id: 123 + amount: 9466 + details: + recurring: 9466 + due_date: '2022-12-27T10:43:14+01:00' + previous: acbf9b1f353dda77a82d4417a998cc71bf16f02b512c81c320dec0501a7bc975 + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: c5f84ec8469e0a1bcf3aec832380206b2b83a51d2ddd8ee534ec38ef97a1dafc + created_at: 2023-03-27 08:47:58.262313000 Z + updated_at: 2023-03-27 08:47:58.262313000 Z +chained_element154: + id: 154 + element_type: PaymentScheduleItem + element_id: 124 + previous_id: 153 + content: + id: 124 + amount: 9466 + details: + recurring: 9466 + due_date: '2023-01-27T10:43:14+01:00' + previous: c5f84ec8469e0a1bcf3aec832380206b2b83a51d2ddd8ee534ec38ef97a1dafc + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 625ebc4ba256dd8f292875b00cdcac96c489de3d6fd38d0d01114a94b6362b6f + created_at: 2023-03-27 08:47:58.265524000 Z + updated_at: 2023-03-27 08:47:58.265524000 Z +chained_element155: + id: 155 + element_type: PaymentScheduleItem + element_id: 125 + previous_id: 154 + content: + id: 125 + amount: 9466 + details: + recurring: 9466 + due_date: '2023-02-27T10:43:14+01:00' + previous: 625ebc4ba256dd8f292875b00cdcac96c489de3d6fd38d0d01114a94b6362b6f + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 24de79a63fd3ff50f73c9ba4094f16b4ee9686164b2dbc95200d349d1647c759 + created_at: 2023-03-27 08:47:58.268194000 Z + updated_at: 2023-03-27 08:47:58.268194000 Z +chained_element156: + id: 156 + element_type: PaymentScheduleItem + element_id: 126 + previous_id: 155 + content: + id: 126 + amount: 9466 + details: + recurring: 9466 + due_date: '2023-03-27T10:43:14+02:00' + previous: 24de79a63fd3ff50f73c9ba4094f16b4ee9686164b2dbc95200d349d1647c759 + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 16223a0b9842a706cdc3e4492bf46e5f975489f33630fabc81cf18c99839bceb + created_at: 2023-03-27 08:47:58.270756000 Z + updated_at: 2023-03-27 08:47:58.270756000 Z +chained_element157: + id: 157 + element_type: PaymentScheduleItem + element_id: 127 + previous_id: 156 + content: + id: 127 + amount: 9466 + details: + recurring: 9466 + due_date: '2023-04-27T10:43:14+02:00' + previous: 16223a0b9842a706cdc3e4492bf46e5f975489f33630fabc81cf18c99839bceb + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: e3dc793026b65339b8c26c07fe8d6aeea23927f3bcfd62e7383b9711633dfddf + created_at: 2023-03-27 08:47:58.273046000 Z + updated_at: 2023-03-27 08:47:58.273046000 Z +chained_element158: + id: 158 + element_type: PaymentScheduleItem + element_id: 128 + previous_id: 157 + content: + id: 128 + amount: 9466 + details: + recurring: 9466 + due_date: '2023-05-27T10:43:14+02:00' + previous: e3dc793026b65339b8c26c07fe8d6aeea23927f3bcfd62e7383b9711633dfddf + created_at: '2022-06-27T10:43:14+02:00' + payment_schedule_id: 13 + footprint: 5d2b2f4f73b05a201d84d11cee494929fbf138261e275a4731810f6c2bbdc699 + created_at: 2023-03-27 08:47:58.275274000 Z + updated_at: 2023-03-27 08:47:58.275274000 Z +chained_element159: + id: 159 + element_type: PaymentScheduleObject + element_id: 10 + previous_id: + content: + id: 10 + main: true + previous: + object_id: 5 + created_at: '2021-06-14T14:24:45+02:00' + object_type: Subscription + payment_schedule_id: 12 + footprint: db4ac0c877f57736d85e9ba455689d13ca976fcc5bb71e7584c554cb9aea686a + created_at: 2023-03-27 08:47:58.291918000 Z + updated_at: 2023-03-27 08:47:58.291918000 Z +chained_element160: + id: 160 + element_type: PaymentScheduleObject + element_id: 11 + previous_id: 159 + content: + id: 11 + main: true + previous: db4ac0c877f57736d85e9ba455689d13ca976fcc5bb71e7584c554cb9aea686a + object_id: 6 + created_at: '2022-06-27T10:43:14+02:00' + object_type: Subscription + payment_schedule_id: 13 + footprint: 1a96bddba094c580ae45a7efb6a1c971c30977add44c866c9716054db936de15 + created_at: 2023-03-27 08:47:58.294171000 Z + updated_at: 2023-03-27 08:47:58.294171000 Z +chained_element161: + id: 161 + element_type: InvoiceItem + element_id: 11722 + previous_id: 34 + content: + id: 11722 + main: true + amount: 0 + previous: 7021559a22497222ffa5b07053988435c954e8d21ccba39c06eecbf4630f8e6f + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5823 + description: facture à zéro + object_type: Error + footprint: b1a8c4e4d48d4df07f1b804c56ec21f85cfb19eb39ed388aab221c4e2f26e0d9 + created_at: 2023-03-27 08:48:26.075737000 Z + updated_at: 2023-03-27 08:48:26.075737000 Z +chained_element162: + id: 162 + element_type: Invoice + element_id: 5823 + previous_id: 15 + content: + id: 5823 + total: 0 + previous: 30d2688fa79772a085d676c5844186c22b0908bcc6aabd1ed17029dbbd525002 + reference: '2210013' + created_at: '2022-10-04T16:35:39+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005899-10-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 346d5c51785d0236016106bd6338a3d740b0cc04211c8638c0c99352f53a3a31 + created_at: 2023-03-27 08:48:26.167850000 Z + updated_at: 2023-03-27 08:48:26.167850000 Z +chained_element163: + id: 163 + element_type: InvoiceItem + element_id: 11723 + previous_id: 161 + content: + id: 11723 + main: true + amount: 0 + previous: b1a8c4e4d48d4df07f1b804c56ec21f85cfb19eb39ed388aab221c4e2f26e0d9 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5824 + description: facture à zéro + object_type: Error + footprint: 77994f7778f5bda652ccced08787fc905ac5810f6cb91b007e1e35bf46b8754f + created_at: 2023-03-27 08:48:26.174939000 Z + updated_at: 2023-03-27 08:48:26.174939000 Z +chained_element164: + id: 164 + element_type: Invoice + element_id: 5824 + previous_id: 162 + content: + id: 5824 + total: 0 + previous: 346d5c51785d0236016106bd6338a3d740b0cc04211c8638c0c99352f53a3a31 + reference: '2210011' + created_at: '2022-10-04T16:32:27+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005899-10-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 6f428e66964c00d254fd0139c55fc1325b853cbd20530823d7b6efdc2289b439 + created_at: 2023-03-27 08:48:26.211493000 Z + updated_at: 2023-03-27 08:48:26.211493000 Z +chained_element165: + id: 165 + element_type: InvoiceItem + element_id: 11724 + previous_id: 163 + content: + id: 11724 + main: true + amount: 0 + previous: 77994f7778f5bda652ccced08787fc905ac5810f6cb91b007e1e35bf46b8754f + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5825 + description: facture à zéro + object_type: Error + footprint: dfe5f411c60d0c940c9017eb85e111fd305416b20f2bb0e10f7bb267dbd66eb3 + created_at: 2023-03-27 08:48:26.219489000 Z + updated_at: 2023-03-27 08:48:26.219489000 Z +chained_element166: + id: 166 + element_type: Invoice + element_id: 5825 + previous_id: 164 + content: + id: 5825 + total: 0 + previous: 6f428e66964c00d254fd0139c55fc1325b853cbd20530823d7b6efdc2289b439 + reference: '2210009' + created_at: '2022-10-04T16:25:36+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005895-10-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 0eaab2aece8e1eed80d3be3cb75f1e6bd93520a0395d6ac043c7c841931ed4d6 + created_at: 2023-03-27 08:48:26.257758000 Z + updated_at: 2023-03-27 08:48:26.257758000 Z +chained_element167: + id: 167 + element_type: InvoiceItem + element_id: 11725 + previous_id: 165 + content: + id: 11725 + main: true + amount: 0 + previous: dfe5f411c60d0c940c9017eb85e111fd305416b20f2bb0e10f7bb267dbd66eb3 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5826 + description: facture à zéro + object_type: Error + footprint: 776e3f92c1b6fd3f1155221081f91c9d020993e4ffee197778ddb914656c80c2 + created_at: 2023-03-27 08:48:26.268252000 Z + updated_at: 2023-03-27 08:48:26.268252000 Z +chained_element168: + id: 168 + element_type: Invoice + element_id: 5826 + previous_id: 166 + content: + id: 5826 + total: 0 + previous: 0eaab2aece8e1eed80d3be3cb75f1e6bd93520a0395d6ac043c7c841931ed4d6 + reference: '2210007' + created_at: '2022-10-04T16:17:51+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005895-10-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 8f98ba4b214c450f5d4ef55b308b778523d77956eae050b39c77a3991104dd3d + created_at: 2023-03-27 08:48:26.302481000 Z + updated_at: 2023-03-27 08:48:26.302481000 Z +chained_element169: + id: 169 + element_type: InvoiceItem + element_id: 11726 + previous_id: 167 + content: + id: 11726 + main: true + amount: 0 + previous: 776e3f92c1b6fd3f1155221081f91c9d020993e4ffee197778ddb914656c80c2 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5827 + description: facture à zéro + object_type: Error + footprint: 8892dc19ee9e77034549108acaa1e371164ee0266524f362006515f4bf809cad + created_at: 2023-03-27 08:48:26.311696000 Z + updated_at: 2023-03-27 08:48:26.311696000 Z +chained_element170: + id: 170 + element_type: Invoice + element_id: 5827 + previous_id: 168 + content: + id: 5827 + total: 0 + previous: 8f98ba4b214c450f5d4ef55b308b778523d77956eae050b39c77a3991104dd3d + reference: '2210005' + created_at: '2022-10-04T16:04:11+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005893-10-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: b0b9b5b885609ecbf8efaee9f8595f131ef45016ddb921e8df9953ee8c367cda + created_at: 2023-03-27 08:48:26.354173000 Z + updated_at: 2023-03-27 08:48:26.354173000 Z +chained_element171: + id: 171 + element_type: InvoiceItem + element_id: 11727 + previous_id: 169 + content: + id: 11727 + main: true + amount: 0 + previous: 8892dc19ee9e77034549108acaa1e371164ee0266524f362006515f4bf809cad + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5828 + description: facture à zéro + object_type: Error + footprint: 531db87ae9dfcfaf35e6e56d89458bbb66e2a3411e0b4e63c24bccca15b5f914 + created_at: 2023-03-27 08:48:26.364331000 Z + updated_at: 2023-03-27 08:48:26.364331000 Z +chained_element172: + id: 172 + element_type: Invoice + element_id: 5828 + previous_id: 170 + content: + id: 5828 + total: 0 + previous: b0b9b5b885609ecbf8efaee9f8595f131ef45016ddb921e8df9953ee8c367cda + reference: '2210003' + created_at: '2022-10-04T15:54:41+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005891-10-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: db20e85028a3173367ad712379a42dac5494dcab733c1a3b4fb77899b9efd12f + created_at: 2023-03-27 08:48:26.392290000 Z + updated_at: 2023-03-27 08:48:26.392290000 Z +chained_element173: + id: 173 + element_type: InvoiceItem + element_id: 11728 + previous_id: 171 + content: + id: 11728 + main: true + amount: 0 + previous: 531db87ae9dfcfaf35e6e56d89458bbb66e2a3411e0b4e63c24bccca15b5f914 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5829 + description: facture à zéro + object_type: Error + footprint: dda2370370a7146ed7528f39972b953fc1d22cc59ae3f4c7edb58ee5791277d0 + created_at: 2023-03-27 08:48:26.399797000 Z + updated_at: 2023-03-27 08:48:26.399797000 Z +chained_element174: + id: 174 + element_type: Invoice + element_id: 5829 + previous_id: 172 + content: + id: 5829 + total: 0 + previous: db20e85028a3173367ad712379a42dac5494dcab733c1a3b4fb77899b9efd12f + reference: '2210001' + created_at: '2022-10-04T14:36:02+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005889-10-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 7cfbdfc32e1daee33e89bd49a70bf44813b213ee54c9d8e6cb714f9c16b228ad + created_at: 2023-03-27 08:48:26.426591000 Z + updated_at: 2023-03-27 08:48:26.426591000 Z +chained_element175: + id: 175 + element_type: InvoiceItem + element_id: 11729 + previous_id: 173 + content: + id: 11729 + main: true + amount: 0 + previous: dda2370370a7146ed7528f39972b953fc1d22cc59ae3f4c7edb58ee5791277d0 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5830 + description: facture à zéro + object_type: Error + footprint: 2022e0d73631cc76f77bbd9d08a3d6dc9309b5e756f179855159c3d61e4f3374 + created_at: 2023-03-27 08:48:26.435078000 Z + updated_at: 2023-03-27 08:48:26.435078000 Z +chained_element176: + id: 176 + element_type: Invoice + element_id: 5830 + previous_id: 174 + content: + id: 5830 + total: 0 + previous: 7cfbdfc32e1daee33e89bd49a70bf44813b213ee54c9d8e6cb714f9c16b228ad + reference: '2209003' + created_at: '2022-09-20T17:14:47+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '005878-09-22' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 25c2b0ca906a85cbca94d26946327f4f2578262bd193b3d86a3038b0ec1316d7 + created_at: 2023-03-27 08:48:26.469037000 Z + updated_at: 2023-03-27 08:48:26.469037000 Z +chained_element177: + id: 177 + element_type: InvoiceItem + element_id: 11730 + previous_id: 175 + content: + id: 11730 + main: true + amount: 0 + previous: 2022e0d73631cc76f77bbd9d08a3d6dc9309b5e756f179855159c3d61e4f3374 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5831 + description: facture à zéro + object_type: Error + footprint: e6c7c849e4d4438d9703ca879901bc7200cd44a00e49d6e12de762bca9ba96b6 + created_at: 2023-03-27 08:48:26.477527000 Z + updated_at: 2023-03-27 08:48:26.477527000 Z +chained_element178: + id: 178 + element_type: Invoice + element_id: 5831 + previous_id: 176 + content: + id: 5831 + total: 0 + previous: 25c2b0ca906a85cbca94d26946327f4f2578262bd193b3d86a3038b0ec1316d7 + reference: '2209001' + created_at: '2022-09-20T17:14:21+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: 000010-09-22 + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 230b42f62a80d4bddb2a1ca4fc8abaa61ff633b1febf99a15537840e17f1cdab + created_at: 2023-03-27 08:48:26.505738000 Z + updated_at: 2023-03-27 08:48:26.505738000 Z +chained_element179: + id: 179 + element_type: InvoiceItem + element_id: 11731 + previous_id: 177 + content: + id: 11731 + main: true + amount: 0 + previous: e6c7c849e4d4438d9703ca879901bc7200cd44a00e49d6e12de762bca9ba96b6 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5832 + description: facture à zéro + object_type: Error + footprint: 34ea62a2ec3034a33167a3ff4a5eebacd93f83acd3e5e78febce34bc442010ee + created_at: 2023-03-27 08:48:26.512600000 Z + updated_at: 2023-03-27 08:48:26.512600000 Z +chained_element180: + id: 180 + element_type: Invoice + element_id: 5832 + previous_id: 178 + content: + id: 5832 + total: 0 + previous: 230b42f62a80d4bddb2a1ca4fc8abaa61ff633b1febf99a15537840e17f1cdab + reference: '2101001' + created_at: '2021-01-04T15:51:20+01:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: 000020-01-21 + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: bf20da46826d72323221ad906bf8ca5395ff6b273d766f4fd5b0fc54a09b8c4a + created_at: 2023-03-27 08:48:26.551223000 Z + updated_at: 2023-03-27 08:48:26.551223000 Z +chained_element181: + id: 181 + element_type: InvoiceItem + element_id: 11732 + previous_id: 179 + content: + id: 11732 + main: true + amount: 0 + previous: 34ea62a2ec3034a33167a3ff4a5eebacd93f83acd3e5e78febce34bc442010ee + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5833 + description: facture à zéro + object_type: Error + footprint: c5d6e84569d61988017f7d5d830cb6b1c70a67ea111dfad7a6ab531d3705ac45 + created_at: 2023-03-27 08:48:26.559374000 Z + updated_at: 2023-03-27 08:48:26.559374000 Z +chained_element182: + id: 182 + element_type: Invoice + element_id: 5833 + previous_id: 180 + content: + id: 5833 + total: 0 + previous: bf20da46826d72323221ad906bf8ca5395ff6b273d766f4fd5b0fc54a09b8c4a + reference: '1604003' + created_at: '2016-04-05T10:36:45+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '000019-04-16' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: 43dd6179cd08bc4da01521a85c9d5bdf1305b51450bb9d867d479dc848246b14 + created_at: 2023-03-27 08:48:26.604421000 Z + updated_at: 2023-03-27 08:48:26.604421000 Z +chained_element183: + id: 183 + element_type: InvoiceItem + element_id: 11733 + previous_id: 181 + content: + id: 11733 + main: true + amount: 0 + previous: c5d6e84569d61988017f7d5d830cb6b1c70a67ea111dfad7a6ab531d3705ac45 + object_id: 1 + created_at: '2023-03-27T10:48:26+02:00' + invoice_id: 5834 + description: facture à zéro + object_type: Error + footprint: 837d77040d9846e98861b47d7ca56a462ee29e5c632b46e91d93949f140f6b6a + created_at: 2023-03-27 08:48:26.612167000 Z + updated_at: 2023-03-27 08:48:26.612167000 Z +chained_element184: + id: 184 + element_type: Invoice + element_id: 5834 + previous_id: 182 + content: + id: 5834 + total: 0 + previous: 43dd6179cd08bc4da01521a85c9d5bdf1305b51450bb9d867d479dc848246b14 + reference: '1604001' + created_at: '2016-04-05T10:35:51+02:00' + description: Facture à néant, saut de facturation suite à un dysfonctionnement + du logiciel Fab Manager + environment: test + order_number: '000018-04-16' + operator_profile_id: 1 + invoicing_profile_id: 1 + statistic_profile_id: 1 + footprint: bae54f976b2ff5fbad15445d66ea5f9934746bb2e114459d96cbb3d640431b5a + created_at: 2023-03-27 08:48:26.655573000 Z + updated_at: 2023-03-27 08:48:26.655573000 Z diff --git a/test/fixtures/coupons.yml b/test/fixtures/coupons.yml index b1f1409d2..11673d6c7 100644 --- a/test/fixtures/coupons.yml +++ b/test/fixtures/coupons.yml @@ -13,7 +13,7 @@ two: name: Summer discounts code: SUNNYFABLAB percent_off: 15 - valid_until: <%= 1.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + valid_until: <%= 1.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> max_usages: 10 active: true validity_per_user: always @@ -22,7 +22,7 @@ cash: name: Cash Code code: ZERG6H1R65H amount_off: 10000 - valid_until: <%= 1.year.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + valid_until: <%= 1.year.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> max_usages: 1 active: true validity_per_user: once @@ -31,7 +31,7 @@ cash2: name: Small Cash Code code: GIME3EUR amount_off: 300 - valid_until: <%= 1.year.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + valid_until: <%= 1.year.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> max_usages: active: true validity_per_user: once diff --git a/test/fixtures/footprint_debugs.yml b/test/fixtures/footprint_debugs.yml deleted file mode 100644 index 2969c0192..000000000 --- a/test/fixtures/footprint_debugs.yml +++ /dev/null @@ -1,1433 +0,0 @@ -footprint_debug_382: - id: 382 - footprint: e4edca90b74e7d1a6f59cd62a9434027ab8cec8f3f71737938123686afaa53f6 - data: 12012-03-12 12:03:31 +0100test33card1604001/VL310000 - klass: Invoice - created_at: '2021-05-31 15:00:35.371996' - updated_at: '2021-05-31 15:00:35.371996' -footprint_debug_383: - id: 383 - footprint: 52f5c2cb9e58d0ad421c93437f57fe2dd364ca412c85775cd59e7510031f1091 - data: 22012-03-12 14:40:22 +0100test41160400242000e4edca90b74e7d1a6f59cd62a9434027ab8cec8f3f71737938123686afaa53f6 - klass: Invoice - created_at: '2021-05-31 15:00:35.400618' - updated_at: '2021-05-31 15:00:35.400618' -footprint_debug_384: - id: 384 - footprint: 2396b77776092cf80e3b2c1effef36e655af63a52a781eb73f27d9f44e546bae - data: 32015-06-10 13:20:01 +0200test7112030017300052f5c2cb9e58d0ad421c93437f57fe2dd364ca412c85775cd59e7510031f1091 - klass: Invoice - created_at: '2021-05-31 15:00:35.417188' - updated_at: '2021-05-31 15:00:35.417188' -footprint_debug_385: - id: 385 - footprint: c0809383b304668ac5226fb502f92eb26c51701380ea9ba9526b80b0295b603d - data: 42016-04-05 10:35:52 +0200test711203002702396b77776092cf80e3b2c1effef36e655af63a52a781eb73f27d9f44e546bae - klass: Invoice - created_at: '2021-05-31 15:00:35.434524' - updated_at: '2021-05-31 15:00:35.434524' -footprint_debug_386: - id: 386 - footprint: f5d538feef1e83fd8f2b1431e7797e1d267f034e3612bdd9725a58e7ba947b27 - data: 52016-04-05 10:36:46 +0200test31150603131500c0809383b304668ac5226fb502f92eb26c51701380ea9ba9526b80b0295b603d - klass: Invoice - created_at: '2021-05-31 15:00:35.462102' - updated_at: '2021-05-31 15:00:35.462102' -footprint_debug_387: - id: 387 - footprint: eb22a99b5fec426dda0214bbaca3ea938fabe42c73bbf1f86712f67a5f61d236 - data: 62021-01-04 15:51:21 +0100test81210104183000f5d538feef1e83fd8f2b1431e7797e1d267f034e3612bdd9725a58e7ba947b27 - klass: Invoice - created_at: '2021-05-31 15:00:35.483844' - updated_at: '2021-05-31 15:00:35.483844' -footprint_debug_388: - id: 388 - footprint: d2b756f158d6332c32b7b262118f5bdcfd68221ab089c355e6776c1298d937b8 - data: 1100002012-03-12 12:03:31 +0100Sleede - standard, association - month1true1Subscription - klass: InvoiceItem - created_at: '2021-05-31 15:00:35.542725' - updated_at: '2021-05-31 15:00:35.542725' -footprint_debug_389: - id: 389 - footprint: f02559738cb3674e74021ac1894e512e1864eb9fc177e885283a214fa5e0dd74 - data: 220002012-03-12 14:40:22 +0100Mensuel tarif réduit - étudiant, - de 25 ans, - enseignant, demandeur d'emploi - month2true2Subscriptiond2b756f158d6332c32b7b262118f5bdcfd68221ab089c355e6776c1298d937b8 - klass: InvoiceItem - created_at: '2021-05-31 15:00:35.558807' - updated_at: '2021-05-31 15:00:35.558807' -footprint_debug_390: - id: 390 - footprint: e6141fbc1db017356f855ebc784cb2e084fbf82ed56a0dc295c8a39dcc2a0f92 - data: 330002015-06-10 13:20:01 +0200Mensuel - standard, association - month3true3Subscriptionf02559738cb3674e74021ac1894e512e1864eb9fc177e885283a214fa5e0dd74 - klass: InvoiceItem - created_at: '2021-05-31 15:00:35.575516' - updated_at: '2021-05-31 15:00:35.575516' -footprint_debug_391: - id: 391 - footprint: b66ade050a2ef9ebb18067ac1af2828fec2077037100d7068481e00097af4bc0 - data: 402016-04-05 10:35:52 +0200Formation Laser / Vinyle April 11, 2012 08:00 - - 12:00 PM4true1Reservatione6141fbc1db017356f855ebc784cb2e084fbf82ed56a0dc295c8a39dcc2a0f92 - klass: InvoiceItem - created_at: '2021-05-31 15:00:35.593044' - updated_at: '2021-05-31 15:00:35.593044' -footprint_debug_392: - id: 392 - footprint: a0f096de802df8d5708d4dcc23d7384ab95f246fb80e59564b2c3363db103b02 - data: 515002016-04-05 10:36:46 +0200Imprimante 3D June 15, 2015 12:00 - 01:00 PM5true2Reservationb66ade050a2ef9ebb18067ac1af2828fec2077037100d7068481e00097af4bc0 - klass: InvoiceItem - created_at: '2021-05-31 15:00:35.610419' - updated_at: '2021-05-31 15:00:35.610419' -footprint_debug_393: - id: 393 - footprint: 88e73e7d2f29fe8f029a646a54e5e8884ddf9cd9b207544e9f3d18c70d181749 - data: 630002016-04-05 10:36:46 +0200Mensuel - standard, association - month6true4Subscriptiona0f096de802df8d5708d4dcc23d7384ab95f246fb80e59564b2c3363db103b02 - klass: InvoiceItem - created_at: '2021-05-31 15:00:35.625981' - updated_at: '2021-05-31 15:00:35.625981' -footprint_debug_394: - id: 394 - footprint: fcc5700c917a25e79d5bb04b90531be52473b48cbe1e00009d412db88c9fc278 - data: '12018-12-17 12:23:01 +010011

Fab-manager - est outil de gestion des atelier de fabrication numérique, permettant de réserver - des machines de découpe, des imprimantes 3D, etc. tout en gérant simplement les - aspect financier, comptable et statistiques de votre espace.

Fab-manager est un projet libre: ouvert à tous, il offre la - possibilité de contribuer soi-même au code, de télécharger le logiciel, de l''étudier - et de le redistribuer. Vous n''êtes pas technicien ? Vous pouvez quand même participer - à traduire Fab-manager dans votre - langue.

Fab-manager favorise le partage de connaissances grâce au réseau - OpenLab: les projets que vous documentez sont partagés avec l''ensemble du réseau - des Fab-managers.

' - klass: HistoryValue - created_at: '2021-05-31 15:00:35.676183' - updated_at: '2021-05-31 15:00:35.676183' -footprint_debug_395: - id: 395 - footprint: d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - data: 22018-12-17 12:23:01 +010012Imaginer, Fabriquer,
Partager au Fab Lab
- de La Casematefcc5700c917a25e79d5bb04b90531be52473b48cbe1e00009d412db88c9fc278 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.692486' - updated_at: '2021-05-31 15:00:35.692486' -footprint_debug_396: - id: 396 - footprint: 33c39abf9e852b7f31d509d5cda12fe401160436a0b684fbbd8939320ac79159 - data: 32018-12-17 12:23:01 +010013
Contact commercial :
contact@fab-manager.com
-
Support technique :
Forum
-
Feedback
GitHub


-

Visitez le site de Fab-manager

d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.709213' - updated_at: '2021-05-31 15:00:35.709213' -footprint_debug_397: - id: 397 - footprint: bf38096a8a4223534da1b393c21866da6eabb951635b5575b9987f8a5983ae4b - data: 42018-12-17 12:23:01 +010014fab_manager5849b0af2169bb1f83a8f0a0ecf572a1adca4034097177fa08f91448bfdf427c - klass: HistoryValue - created_at: '2021-05-31 15:00:35.725992' - updated_at: '2021-05-31 15:00:35.725992' -footprint_debug_398: - id: 398 - footprint: 92120f18756df89476a3413456acc41a8bc2f169112f6e80b493d2daa1317b54 - data: 52018-12-17 12:23:01 +010015Tout achat d'heure machine est définitif. Aucune - annulation ne pourra être effectuée, néanmoins au plus tard 24h avant le créneau - fixé, vous pouvez en modifier la date et l'horaire à votre convenance et en fonction - du calendrier proposé. Passé ce délais, aucun changement ne pourra être effectué.d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.742737' - updated_at: '2021-05-31 15:00:35.742737' -footprint_debug_399: - id: 399 - footprint: aacaa245eb491bebb1768902f708c3397efca9f4db1adbf2e90a42a16831e986 - data: 62018-12-17 12:23:01 +010016Toute réservation de formation est définitive. - Aucune annulation ne pourra être effectuée, néanmoins au plus tard 24h avant le - créneau fixé, vous pouvez en modifier la date et l'horaire à votre convenance - et en fonction du calendrier proposé. Passé ce délais, aucun changement ne pourra - être effectué.d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.759306' - updated_at: '2021-05-31 15:00:35.759306' -footprint_debug_400: - id: 400 - footprint: 818f300cad937576887a0154584243803a0ddd25070e11f0d059f14b5ed291db - data: '72018-12-17 12:23:01 +010017

Règle sur la date de début des abonnements

  • - Si vous êtes un nouvel utilisateur - - i.e aucune formation d''enregistrée sur le site - votre abonnement débutera - à la date de réservation de votre première formation.
  • Si vous avez déjà une formation - ou plus de validée, votre abonnement débutera à la date de votre achat d''abonnement.
  • -

Merci de bien prendre ses informations en compte, et merci de votre compréhension. - L''équipe du Fab Lab.

bf38096a8a4223534da1b393c21866da6eabb951635b5575b9987f8a5983ae4b' - klass: HistoryValue - created_at: '2021-05-31 15:00:35.775879' - updated_at: '2021-05-31 15:00:35.775879' -footprint_debug_401: - id: 401 - footprint: eb5786adc7ce35b66489a84a3c5e1fadbe473f68161e6417d27d5df38ed12e69 - data: 92018-12-17 12:23:01 +010019iVBORw0KGgoAAAANSUhEUgAAAG0AAABZCAYAAAA0E6rtAAAACXBIWXMAAAsTAAALEwEAmpwYAAA57WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMzggNzkuMTU5ODI0LCAyMDE2LzA5LzE0LTAxOjA5OjAxICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNyAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTctMDEtMDNUMTE6MTg6MTgrMDE6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNy0wNi0wNlQxNTo1NjoxMiswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6TWV0YWRhdGFEYXRlPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3htcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDxwaG90b3Nob3A6Q29sb3JNb2RlPjM8L3Bob3Rvc2hvcDpDb2xvck1vZGU+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6MmYwMTE5MTMtODI5NS0zOTQ0LWJmZjYtMTY5ZTNhZTQ5OThlPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6ZGU3ZGE1MmYtNGFiZi0xMWU3LTljODAtYWJjY2ZlM2JkNzdmPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6YTE5NTAzOTAtOGQwOS0zMzQ3LWFkNGQtMzkyNDQ2YjRiNWJiPC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpIaXN0b3J5PgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+Y3JlYXRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOmExOTUwMzkwLThkMDktMzM0Ny1hZDRkLTM5MjQ0NmI0YjViYjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0wMS0wM1QxMToxODoxOCswMTowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDoyZjAxMTkxMy04Mjk1LTM5NDQtYmZmNi0xNjllM2FlNDk5OGU8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTA5PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjg5PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz7jSvdMAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAACL8SURBVHja7J15nB5Ftfe/VdXLsy8zk5lM9hASsrDKImgiuyCL7ILgq4KKu9flivuCiKjoFeWqCCoKQpTLIsiOrBqI5Bo2IQsJ2ZPJZPZn7ae7q94/+kkyQzIhExKSwVufT08mz3RX91Onzjm/86tTp4Vh+9oKYCFQA/YlThaHB+jlBmxuIcdyesmQQVAixELjYOPRSo25KDoJMdQ4mjTLKNFInBUENOGzEoc4vphEYnwVe4KNPdmgJoMeKxAjDSYnEAnABgSgo0cxZQNdINYJ9CqfcJmAxQaWpulZW0GZEI9RJHgcRYDmEKCIxQbKOLhoYF9COrDoJsQGRpNhPj20U+Xs+g0Ha712jKXpRhwdsrObhcAIQ61apeZ7xJXiQa+IxRvQNo5yWP/dABpDI8nRAn/mQcTfHmJN82GqTTjGECLw61fp+tn9ezObfhcIQAIKGwlIA2JlmRELfbz5LvajFeSTEJR0/ezh3qw3QmA1DApDDIFGjsnSOFMgjs/iHA/B2Co1DB4QIgDhOsjGHCqbRyQzyKYUoiEGjgVKQqjBCzBdFXRHCV3uRff1YDp60V5FAOMlanwM6wRD+kt98MxEggcM4pEqxblgSgEG+/+EtvUWYEigaMbZL0fiPQXEOQ5iH6gR0IfARubSqGlNWJP2wZk+HWvGOKzRLagRo5DZEchUGlSsrlEbm4awgi4VCHs7CNvbCFevI1i4Ev/FBfgvLyRc1AHdRWkIDk5iHSywLwlIPyHRs9OEd4Nsq9Qnyv8JDRAYAiRdJGaOJf4xkCeFeHlDDYRCjmoh/tYZuMcdQezQI7D2HovKtQDudt5BgkoiM0lkZiT22H3hYOA0AI+wux1/6XJq85/Ge+gf+P94kWDdOssEwTEK65gmsotq6D/a+L8PKS4zmH93oQkE4jBJ8uIa6mxFNaspI5wksbcfSuykY3CPOgJ3/0MRTnoX3N9F5ceiDhlL7JBZmA+WqS2aT23OfKoPPob3xP8SdHbto1DfypA6uwP1q4DwJkGpSw/Q5je50Mymn3arwP2YwP64xB9h6IV0lsQJx5M4+1RiJ5yIyo1+Q7+kcBK4+83E3W8myQs/iDdvDuU7/oJ359/xly6fYVA/s4m9O0bsexA+atD/HkKTCAycKkhfKggPgh6MZRM76ShSn7yQ+DEnIqzUbv/C0s0Qn/ku4jPfhf+J5yjdfAvl39+Jv/SV42ycQxXJHxjCnwSYavhmFppANKTJfUUgPwrVNBRxDtqX9Fc/TuKkM5CJhj3yy9uTDiD3jf1JnnsWpRtnU7zu1my4fv33KqQOzGB/thtvXfhGoLUhNvXt7TyxF+iox1rN2CgUVTzGkZoxntj1BnGBps9V2RiZL15E/r9/TOzQYxB2fA/3EALV2ErsmHfiHn8IplKg8vyiGSn0kXncuY3U2rfl5Txl0e0mUGbnAxmJAAFhEBDqEFtKloY1xI4yIhYumvCoEWR/1Y4/Bbpx9p1K/spvEj/xrGEbuBpdpfw/f6D30p/AgsWLIPFegXxGI9HKEE6OU7MCTBAgAoHZIKkJK3IObxAjskNQSeMjiJ8myNzVSW2KoJvE2Scw4sFbhrXAAISMkTz3w7Q8fhfOOafuU6Z0bwU9xcOmImwqCYdSyqGYcigmHTxpIcwbGy4MSWhhHR9Kkh80iFsExbShRObLn6LpltnYrfvwZmlqxCSabrmdkX/4r5FWxvzF0DFNoVGhxvLrR6CR5o2P7+RQBGYBY8mdHyN7vaHqGAHZy/+D/BVXIEWSN2NLXfAZmu/5w5TYhL2vC4OOFnwNYvdyKEMS2jhyZ7SQusGniHENuau/QvarlwMOb+YWm/luRj5229uzp59wDZWiFRaKaM+L7M5uEKD6Gv259C2PiJASeOSOtkjdEFJMQUj+qq+Q+dSX+HdpMtdM6pQTp1LodorPPfOwPXok0tiYDVWEkOwKAnNQ9PivbTAcCkGKJAHuZIV7hyCYoSmT+95nyX7lO/CmWOgYIgjrai/odUvfW3nuX/es/NS3CMsVZDy2i4LoQdbTzDaEFkawI6lwrxaEMzS9ZD73IbJfuYx/1yYbmpOmpprXfvVj+N2dWA2NoHcxGDED6WxLDs5yILHQxL4i4YSQLhJnHkfuh1fsqifDX72U2spX0NUyQu6BxK0UiESy1nPzbftUVjx/pJMbmzIm2NUWxxdKrreMtcRgSgYQSwbRMos4FvmTQ8QfoCdnHziREbfPxp64705/qtqaJXRefTWV+/9B2N0LYW23I7Stz2SBCUKjC9WSULKG2uX+QRhDKISpSOQC41X+685y1/1i8Vbva7BIjlTk74Dq4SJpaJz9MxKnnr/zp9GGlaz9wMUU7nsUiYtw3T3aVwoAx0I4kjd6CU4JWerwq+dZFTKvYjsMNgKX+MUQHG4okfrURbtEYAB9f76N4n1zUHYamYkzYCRej+wMr68fM4jENqaomNfoV2ylv9cp5MDo5EjLvcSyBtzHINAo4ocJ5Ec03TgHTiPzuc/vstkTrFqFEDYi4cBGdkEAAYR9JRiyzzAI6SKzMbAE1DS6t4LB385+DEI50QSS/QZaCkw5RJfLbE5R2s7nQYDlIJIOwtpxDRVA1egJVhp/0wchggCJjbrIEIwRlkvqSx/Hatlr1+m8bcOrQIephsikQ8Pn3os9ZgymUt1un4NjUZk3n/K9T2LKIDMxcp84HWevvTA1f/PEGOR64SjKT/2T4v3zEI5A1H2rKdawxjWQOe88VKYR43mDDq0xGlOrEvb14Le3E7zchr9gFUFvB9LNIlOxbT/Ha3gUayzlTf/rxaGN/CwXeXZIH/FTjyHx7tPfAGv9KpNYDRCNSRo++0mcsTOG3Fv3LddS/MsTaK+GlWim4Qufwd3rwO2+3rn/dor3zIMgjDLAtEFXa6jRjTR+8Quo1FBW3jVhqQdvwbMU7ryT7qtuRXcWkI2pHdY46UNd16IRU6iLNbVGmUqTvvgDqETT7nH3xmBK3g7CUVMfkACZTSAT+aEp/9ixqKwLFT3QP4UGM+RMBIlKNpA45BhaLvspY/7831gjmwg7SzuMkKVTZw5HAz0k9k/C8YYSsVPeRuydJw/PCNiYekCqUePzqHzj0JiI1mbU6Aw60FtahNfJ6qeOPYPmn38LmXTR5doOgST5QVKcS5KzSAHue0K8FmGniJ95GkLGGbbNENEDrQ1Id2g0k0ynsEa1RIBjFyy9ZM98D+kzj0FXylHi7VCF9i08vo/HZcTHS9RpITXcd+xP/Jhjhq28hGWB0Qgs7JZWhprlIe089qgJGMIdoKi253yX5CnHI6RAe0NPH5LLkaxE0Ik+XKL3FShi7zoW1Th2eKgTQb8jmrUmrGG0Bhys1h35HhJr1KhI04YotMI9f2Ltpy+m+MS92zwvtv8UrLEtmFow5Kez3o6giyRFnONCaqhxrbhHHjYsNKo8/3G6r7kWQT3HXwiEpfBeXooUNiQdrFE7lmNpj21EYDCBQQxBUUvz/sb6/76O8kOPM/7hydijJ2+9/9bx2A3NBCvWA0NzQ5ZNFRvVDMmjwMc+eCrufocMC6H5y1+m+7pbEFiR4DYGs3YMEUpUc6Lum7amowYqRVAWwtly0KwxLRBzMaEZElZQiTQ2ktqiDryXFg4qNJHOI7PpTdZhSEJbDxRxDncIJxlsYkcfinCzw8N3SRclsoikQiirP0mH7q4iGzKohtzWLw41tVULUblmrObxWw7MqBasxhxBW9+QfOJG3CKVA54/uAGWDiLnbERMQ4rZZBoLgTvTUBMym8I55G3DCHEIEDIyjf0PEbESVtMIVHqQvQKhj7fkecLezkHM11hUfgSEwet7vm3GojsYpy1B4MB0Q4ic0oi115hhBhWJOMJXH2hUtgGZ2HoqutEa75VFhIXurZugxjFYo0dgCIb+PPV/RWzwUMNoD9PjsSOBmowTHxPCFIHG2XsKVkvL8AnFwiph2EvY3UfY0UfY0YvuKNWZDIPM5hCxxNYvDgJqS1YQ9vYMRmZh792MQA/JdulKkRANeY01tnXQ84INqwg6NkSmd4hRhaVx9pKYyQaNPX06kBo2QnMmTiH/sXMQSFAKYSmCnh6qDz1LWOzBGjcCYW09tU8XCtReakMfVRgcQU6sx3hDCLDdyVPIHHcImXPPw52y/6DnVebNx1vyCiLmDvl7Wy5MNmiIuVgzxg0ryxg/6EhG//LIAZ95K55n9bMfwKxdgzWmedBrw+4NhGs60cXBVxDsMeMR0sEMIVbLn/8pcud/EoEaHPWuep7OS68GD2R+6Ns7LIE1CXxUYx61DXUeNi0UmFqIVAmsEYMTxUHXOsKuTvQ2SGmroRUh7aFBuyjxbWu6TfX5x+m+4Qb6fv8QYUcB1Zip85lD9GkCMRZCZDaP1Txq+AvNGEwYoNJZrOZt+ZR1BB3d6J6+wYU2ajQiaUN1Z/CPBl0pEXR1oSv1BdkdzOKSQItBIxJpZLaJN0ULfGQ6g9U4cnCF7OpGBx5h2+BCs8eNxhqXwXh6J6StKBJvPYWxv72TiU/fQeygqQTdxR0ipCWYHBhkPolIpIa/wCwbbJBjsqjGEYMLrVCK6pl0dhNt4NpaEJtBjWseEuwPC52EPavraRKD8I7T30brr3+APTJP2FvdIU1LAIjGGMKODSv5aK9E0LGaoGstQddadLWXYP0ajPaxxzUiM4MzO2FvoY4iu9F+aZCQK4EzYWI9v2T7Wu+t17PypLNo/+F3MbXBkWn8LUeSOvNoTFhlqE7NAhEDEDEbtoF49sRWnvswG778faRtRZBfSoK+AuGaEvZZYxFi8I0h4SvrolpN61ahC33Ihq2DFnfCZAwewmwfNK+tXkXfU09TeWYRqeOOJXHwrMEFd/hB9F5zJxgNQg1FaHVJKclwy80PO9dTmvt0P8I4ylMTMoHdOmob36eGsAQ2MUTOxlRqgw/Q1Imb+t2e4ZFuHIVCeDF0W8c2z7VbxiBsB2PMkDIPLKJ8sF2fj74rGCwVQ4k8Ir2ZMDYVD7BQmYZtUEiShku+SPYjFyESCVR+cJTpTBiNSibQpe30ayb6IdRrs8DCjYOREIaR6pjtFpqpgcFU/br81DCT3MDDhBqZsLBGDI6EhbSI7bP/9g1QcxPWyBaqS1cN/cFeaz+C3LEtUhIogcB0VjB+ZZjHaECgkQ1x1OiRO6VLlW/CbmzGUNuhmHGXAGSQXQKB7ipiSn2I3PCG/cYYZFMG2ZjfKf1JuxHV0Dj0FEVtQOvtsxQYjOdvaR6FQNhqiyUeaTBtIDH1am7DX9XAampCpXZWzS2J2qfOFG1HDo4QUTXLUJchvj1pBCIKE6s+eB54teio1jAVDxNuucfbAr0SFLq3G92+DsbvP9xlhtU4EpV+rdX3GuDVPUScbW0/t/ceHS0uB6+tOUGhBx/IHjWN2MFveQ34G2CqNexpeUZ89zOoZH5TurlwHfz2drp+dBP+whWI1OaQw5LoZQZB2N1LsKYN99BhKjABhAaBwR41EmFtS9NC2r/2DQqz78Ea10rTd79Mcuaxg57tjh2NwsaEr61quXe/l/gBh5A69l1YuW37VV0ro6mhGjOkTz0faQ806brSS99vH6ZWW4LoV1JRhuilIKHiESxYNbyNY2jAsVATm7d9Xq1Aae4c+pa9SOHxv1F7+ZVtx1Nj9kKS2a7Ug/ihR5E7+yNY+dfOAAg71gFBpMFbCbl0TxfGq2wRb0qbYLlBLjMI/IULgWGMIEODSMewWradBh5WC1AOcEhgJXLgl7eN1lonIFsymNeTL7KVVnn2JTSVwUMDIbaaZyI3UF4hYbFA4i9eTNCxfhgjR42Mx5CZbYMQXSyie3sQ2JggJOjr2bbQmpqxJzXCTqwDWXvlOUp3/Q2BM+RQTU5CU8EsAEW4uJ1g2Z5gIuvbLG33NRgRNXAiao1KZbBGtLyGeQwI+qL6yegQXShs+z5OEmevcdHmffH6N/CHpfW0X3oFtUUrkMSjPrcmOcup04sDTaelCYnh/x2cz+quIrWnnyJ26KzdDioMBl3qBHzC0paaIJNZwkpfXbxis3lMJBGuwphSfdfmwI5VMk/QthJT9BDKRuuQsHMDobceoRIY71VLJVIhbFBNjRijCUsdqEwTutT72hNPa0wQYmo1dM1Dd/ZQfWY+vbNvo/zos8hsGtPrY3RAWOpE2HF0uRjdNpFAFzfU/ejAiWL9BZiCN2c8saVV/EnVv84l/aFeRCy725RMJGxMxaf9a9/HyuejwHNAMArCtqitWIWI2wgZfShTDkHHBtq//H1UPD4Q7W0q328RtK0HbSNSCqldyg/PZ90HPgVSsWkDmu7nV6TAW7CEcH2J9k9/AxlLYvxgcI6pzi+bMMT4NUylTNhXIGzvJVjbhfE8VDYFjkIkIVjZTdvFlyDt2KZnFpYiLJXwV61GpAdaHCtBDB+7zYdHJPYk/58v4T03j9hbj9t9mmZL8DWle56sLyaqfghKbxoVYcWQ2XidUQijPRidvZTueqK+AaN+mTH9rosyk2UuAcIgqgJ/URu1hSuJygRsTAPffE8BEHMRCAq3PcLGoh1b8Zb1Y2Pypd4sSSEQMtprIGLxaOMjISQUus+jcOtjRF9gI5GqAYVMJxCuNQBdytMQHEIFg/+QxiVc1Yb3xNO736UpkLk4Mp2MvrAQUSFMqVC5JDIWxwQ+ulAl7OyDqo9wBbpSw2iDyidRDal6ERmDTCdRzVmEFcPoWn23igBHQCzafSMtB7slH2kBINMxrOY0uDamWsaYANWYQsZigEbGHVRTCpVPRkNtWch8GmEpIKgvGTmoXBLVlAIp0F4t2sDvgu4toTuLCEchU7E6KImWmGTMjfq15RbhgKWooIBWvLlrsV4w6P2q9z1M6sL3oZp2T0qdCTWmBo1ffB+pE4+jcO9f6fn1zdijR5K78HycGTPQxQK9N95M3y33k3nPiWTOPhNrZAvewkX0XHcz3rxFgMFqaSD7kbNIHPkORDZNsGIVfTffQuGORxGkaPz2R3An7EPxgfuIH3gQsbcehi6X6P3NDRRuepCwFC2bZC86jfQpJ6OamwnWt1G47S6Ktz8G5YCwXME9YC/yn76I2L77UfnH01Tm/4PUrOMJyxW6f3493qLF2M2t5D52LolZMxGOTfWZZ+j6xfXUFi8jMetwGj56IUF7O96SF0keeTS15a/Q9aPfYSoBwlWb8cjFwPuBS5Aso+WyVTSaFdYIU/jT9eaNaG3fucS8qBrMgmyrWdgw2ixsGG0WZFrMS26r6b3jZmOMMTr0THHuA6a67MUB1/qda03PX24wYblnwOeVF+aaxXtNM4vG7GUKj9+9xT21qZpVHzjPvOgkTe+9s+ufhgPPCQpm+QknmBfAdPzqB1v2oaum7VtfMC+SMC9Pnm7K/3py4N9DzxhjTFBoN0v2P8QscBpM7103bdFP+aW/mZdSObPi9FP7PZ9vjDGm957ZZkHDKLMg0WIWNtbHJj9qqbwWuAH4AxqDd6vEXW+CEpU77sLoym4EkGYzDycdkm99J+6E6QPNREMr2VP+HzI+EDTF9j2U2BHTSZ04k9Q7TgRgw/e+w8rz3k3QvhKBS8MnPow1Kk/YU+yHIPqHEyncQ6YSP3Bf8hd/CIDCPXew+sLzqMz7O0K4ZM46G2v8SHIfOpf4jCMA6P3z72m/8kuE3Z11VqOECTyyn76AzKnno70KHVddTvsVX0WXC8SnzST3yfcSdm/Y7BmrFbyXn6E8Z25k9tWr0OPGVSIbKFJ5rp3EXy3iF1TvfYrqw/cSP37PqElsdEDxgTsxlQqpk05HxiK/o8s99Mz+He4+00nOfOfmdbCmPKVbH2fFqccjx0q8p9bir15LbfkSrOZxWA2tqFQefL/eTx+9N96ASMfJnnM+wo7jjBlF39oS6z7wccj71J5dgvfMchJvfxvxQ2ci3RzutCm4hx0IgLfiGdZ9+At4nZ1YmVE0fPQ/wNdYTXlih0VEvL/iJYp/foCgdx2Zs84hNuUgEoe/BX/B8k0gputHP2LDN36CdJJRUZxXhWpW/zcbRXgpvFbgvkv39TQUrr0RZ9bRqNjur6vvL3mBdR/7AkZUmXjAATiT9gOg9Mj9rPjw5xhx8Xn9hGYgCPHXrSd58nFkLziT+E9mINwEwkS5/cb3Iwdfj86rzz7Nus99HXf6GFJHH4XVOgkcG699Bc7aKTSccSHuJftitzYjdKLeRw3pJlDJSNNrS14h7OzBQrKxDrvRGpXJYzdGfKiz9wFMePTBepAejb7Kj0Am6wVhhCFY04mhiointpqGYK2pbx2NQKZAUHrCkLxdkvxw9a4nqNxzF6mzPrjbhabDABlkMckYRg7kGyWgYukBdJbWJRq/fiEtl14V8Xxz51L913OkTj4Ru3X8wLUcAMug3AaUk4vQHRC2ryd19BGMf+g2BEn8dWsp/Plx3GlTiU3dd3OVcLHpxph62DCQp9x8n6B7A7VFi6M4zitjAijNfaKO9KNUD5Fyog1ocuslmaxyv3gjihA0IcHvbNxTTK04svCDXxI78lispt27cV4ohbAkRkqQ/TgfR/WPpqIhqgaopgSxww+KzNaSf7LqrHOorl3N5PmPR0Izr2LWpYpKKgm5SfuMXSVx4iEIkmivm7UfeT999zzM6F9fRWzqviAVulwiLEZZys6kvbAbRlHrWoNKJ+vPLQl7ewna26PJt2EVbZ/6JNVnFiHTaax9svgvtpM++YStyXjr8bvZHMCj69GFpjbHEP5GkKU273kKV/9096xnqn5JRsqKCCshELLfRNv4ez+mXNgWxtforohqslv3pvm/LmfSk38lftA76jRYBhx7E/4Qth3Fg0oibGcj6YUp1muHOVlyF32QcTf/htz7ImCicjnCzm4qf38qWneb+BbG3P5bxv3pt2TOOK8OFgRhZzelx54CDO7Uwxh1zXWM/NkVjP79dUx66lnSZ59C0N3Vb4Ja25ScTFKk/5GiRJICFoVrwJovSFK86kYqD9z2xquXEgPM1yYqyurHtjuy3/RjEwVkSgF9f7qH2urFyGSW3Lnvx5kwmcqzj0WnN2Sx9s5BGCFUHUSZvsZodFDZNDqF/3mY2pqXEEKSPfN9pM8+h6BtKRCiRo3A2ruVnl/MpvjQXwBIHvlOsud8AFnffC8sCcqh77e30fWbn2IIiB92BI2f/k8yZ5yFtLLInI1w+1kKodlWmpYlB5GoJFwdoC+H2A2mrzvZ/c3vYU2fjj122s52VltMKiElQkHxrnsI17eBBn/NKnSlAEFI9zW/xm4ehXAdKvOfQZHAe3YBXb+4EnRUR6T2wkoqj73Amr6LSZ04C5lK0XfbA4QdbSSPextGC4J1PfTedDve84uorVqFoYa/uo31l3wNK99A9fkF+AvXsPqci8icfzpWvpnSI4/jvfACyWOPQOYbML09+G0dtH3+y6ROuw+7cS+8Jc+SOvVUMieeC5aNdF3CoED7F6+k/Pd/kHjrW5HJDEHHGsqPPk35wXnY00ay4YqvoIOAytynkW5i8Km8fFvjiY2k4ccS+fmQDSTOO5kRN92MkImdJrP2y75ExzevQeWS0TKE2WwfTdmvE6jRYqBI2ogQdNVnY50qYSlEwsFUw6g0YD1HVDg2QkFYKEeEsqgv+BiF0VGgI90kRvsYv4IQDjKbxAQaXSxFjsJKIFMxdF+xXqPEQddq0S1EpPlSO8iWOA1f/TAEFrV/voxsTdP4+c9gt+5F5fk5rD75IoK1HQhHoatVhO0ilIXxPUxYQ8bTYAl0sRy5gLiDjDtbTcEzxiy3xmzTr4T4mMsqcGAvjcdU/vgAPWO/Sv6HV+00oSVmzUJlfkfQU0DlMnUAFQ0yrkRsrIcpRISSZVQSe2PRMpQAaRDOq/yaFdkRZdcZeQ3SsSKQEdZz/KWIci+0E91DgZAClU1u+jvKIHPJaEKEGpWOgZKYIARhMH0BamSK7PvOw87vPXDdrNxO19XX4q9uR2UTYAuUa0fPYwJEzEE6iQjWh0Swv27et5ozKaCmxX3i3a/BS6xD8VHi095L7s8dVKcYKuSu/CLZ//zmzrKPdP/6l3Rc9lNqK9fsoS81NggVR+biAwdTgKmEiEyczLknkjzhSNToFowf4C9+hcIf76Z875MQcxAxueML3yIyE77WNzeV+z6xXSP0fuCXZE/oIz3bo5jHgoZrvkn6Q5/bacNSXTSfwh13UV34L4wX1FeJ9wB5iWhtpzLn+XnBmsI6kbLsAT5YCvBCdLGETMdQTXlMEBKu78TUAmQiCTFrR7ONpTCEEK7ywuDBlkrlgZFBubxdw3I+cBOwlvx5htTskCImLsj//FtkLvzMTp7TIa9d1fmNZUEFkp5bbzp29Tnve8TKjxJbVOoUQCnE1MJ64BTBXJFS0drgDmaHGyEQgUEERVMJPEYbxYigun27LQ4EzgCWU/1XDbkiQfp0E/hU730U4h6xt82CnfTWWoHcww4BoK0pU64O17Svqzw1B/nq2iQCCCUiUJu2XQkUuGJIu2G2puVCgzA+gQ7JIEjqYOjvT+ui53cBfZ+QxEN8Q+8Xr6T761/GMMw3bwzmcbvX0/n1C38cdiyZH5t1OJpgtz/TkIS2cQHep/TLGuEFhnTFkKDv8p/Rcd578dsWvakE5j31MG1HH31lde5jl9gjWhAVb48w2tbQzRdoFJrSn1zEhpDMtYL8pNKf7sV/cRn5H3+b+DvPGN7a1bOW8s+uZv1Vv7r8X93dX1eZOC/MeBtedy+j3Qx5qfD17nuh8nb5tAPqPq2daNtCCguDZCSFZTXcRzRqmiAxMWxfR/Xuv6JLa7EOmIZMZIeVsExQpXzPbHo//Y2w+/d//LpXLX9nDVDxAiqdXZRKZZpiCZKWTfgq6L+puGv/5rJLfNoOCS2JhUGRpYZHot0jvFsgpCKxn6nW3MoTc/Ae+RuyycKeOAFh7dlVE4xfpPrEA/R8+7v0fvMXK/1liz9ZQf8yJHpVtKibJAE0OnESw11oVZJ46Iqi+JDAesngTFXER4ZrV1K5/SH8Bc8hRyaxx4ypF5Tfg8yg10d1zoP0XPoD+i79Od685x7zdPihPvwHXQwa6OwH4vUeIrSd9Ub5KKcDcaemMA9in5TkPkHg5yq3PkT1wXnETjqc5AVnEjv6eGRyxG5lN4K2pVQfeJDy7ffiPfY8YV93l4+62iCvFjidhvIebRl28hvuBVBba5Bf08i7DfJjhvzZqq+SqPzxPqp3P4kz6yDix78D97iZODPe8obV/g83rKA670m8R+bhPT4H/5ml6LCqDfZfbNyfpOl5fD0WNi57erN2TbcC4ClB8ekY1h/KJD8icU4QxVqmet/f8O5/EjVxNO7b98eddRj2/m/BmjoRKzuSjXkTr5fP1OV2guVr8RctwPvfp6k98jz+Sy+j+3rrX9v6myR5HRRvh7DkoJEMj2btOiMksNFhkupDCvNQgDzYJ/4+cE7XhgnmlXWEr6yicuNDkIlj7TcKe/J0nAOnYc0Yj9U6CjWiFZHMItwYwtroIDamWweYwIeahy72EHasJVi3jmDRaoIXFuMvWYi/YBV6bRHMxvjKqQpSj2iq14N3t8Kp6k0OZ/gUvrF29Q0MAgeNS+2fUP1nF8mfWYiZGuckTfxIi7BV95WozVlIbc6LlACZiqNGNCEzeUQsCVkXkXEQrh2tuYUaPB/dV4MeD+OVCPu6CDu7MX1lNuaVSxQGx2hiLxrCu4D7AorzJDVPYe006u1NJ7T+YAVCJHpZnuKyblI3xtETejFvl7gH28QOAPYP0E2yGBAW1xOwlmjT05av+RNsep1cffAjLbRJEKJWB+jnArz5DqW5Ls7fl1Hts4FcXVDD+WXP1u66sUGSpLC8jXB5EnWTpCh68MeOJLZ3F4mpFtbeCsYDLQKSIFyiTBEZrS4JH4xnoCgwayUsA/PyagqL4nhLxhFrW4HApUiCDAaFIOTN0P7/ANXjuuhKlYnHAAAAAElFTkSuQmCC818f300cad937576887a0154584243803a0ddd25070e11f0d059f14b5ed291db - klass: HistoryValue - created_at: '2021-05-31 15:00:35.792587' - updated_at: '2021-05-31 15:00:35.792587' -footprint_debug_402: - id: 402 - footprint: 415e133e7426ba4d442edc83b8091888c9c2a5350981e8c2be8fd84c3eb80e14 - data: 102018-12-17 12:23:01 +0100110YYMMmmmX[/VL]R[/A]eb5786adc7ce35b66489a84a3c5e1fadbe473f68161e6417d27d5df38ed12e69 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.809928' - updated_at: '2021-05-31 15:00:35.809928' -footprint_debug_403: - id: 403 - footprint: '06248f3ed99242d8b2588f97cbdc97732fa4e752912f601df70699f9f7a8919a' - data: 112018-12-17 12:23:01 +0100111true415e133e7426ba4d442edc83b8091888c9c2a5350981e8c2be8fd84c3eb80e14 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.825989' - updated_at: '2021-05-31 15:00:35.825989' -footprint_debug_404: - id: 404 - footprint: ea02f4452b07542799e576925ac9f9ee563cb5520de6e57861ba7be8a7cb3993 - data: 122018-12-17 12:23:01 +0100112INMEDFABLAB06248f3ed99242d8b2588f97cbdc97732fa4e752912f601df70699f9f7a8919a - klass: HistoryValue - created_at: '2021-05-31 15:00:35.912831' - updated_at: '2021-05-31 15:00:35.912831' -footprint_debug_405: - id: 405 - footprint: e090b8e07b36addc29f8d479b3d8e756aadbc12005cd6ad920175cbce1d37cf1 - data: 132018-12-17 12:23:01 +0100113nnnnnn-MM-YYea02f4452b07542799e576925ac9f9ee563cb5520de6e57861ba7be8a7cb3993 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.943550' - updated_at: '2021-05-31 15:00:35.943550' -footprint_debug_406: - id: 406 - footprint: a1681dc7ed8d92782d6ddba98ea6c80e726deff845bd40678b310b5bc63e0c58 - data: 142018-12-17 12:23:01 +0100114falsee090b8e07b36addc29f8d479b3d8e756aadbc12005cd6ad920175cbce1d37cf1 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.959276' - updated_at: '2021-05-31 15:00:35.959276' -footprint_debug_407: - id: 407 - footprint: 5f179582e43d783803d5f2ef2dce87253dd95341fa8bd2431cade4ca80200a46 - data: 152018-12-17 12:23:01 +010011520.0a1681dc7ed8d92782d6ddba98ea6c80e726deff845bd40678b310b5bc63e0c58 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.975968' - updated_at: '2021-05-31 15:00:35.975968' -footprint_debug_408: - id: 408 - footprint: 92b2e93fc98fe045de4d2d889068c162ee9806e1862e91c45e00e7184a73afe0 - data: 162018-12-17 12:23:01 +0100116Notre association n'est pas assujettie à la - TVA5f179582e43d783803d5f2ef2dce87253dd95341fa8bd2431cade4ca80200a46 - klass: HistoryValue - created_at: '2021-05-31 15:00:35.992950' - updated_at: '2021-05-31 15:00:35.992950' -footprint_debug_409: - id: 409 - footprint: c048d95a3acfa7543e4783cdaca27cbcea20c4b7277851a83a9aae2be2b182c3 - data: '172018-12-17 12:23:01 +0100117Fab-manager
41 rue du Colonel Moutarde, - 21000 DIJON France
Tél.: +33 1 23 45 67 98
Fax. : +33 1 23 45 67 98
- SIRET : 237 082 474 00006 - APE 913 Ed2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147' - klass: HistoryValue - created_at: '2021-05-31 15:00:36.009393' - updated_at: '2021-05-31 15:00:36.009393' -footprint_debug_410: - id: 410 - footprint: c69790b104c8c6eeac6f2a7a183f6fb9fbb6355b8338b91324cea23b5239d329 - data: 182018-12-17 12:23:01 +01001181970-01-01 08:00:0092b2e93fc98fe045de4d2d889068c162ee9806e1862e91c45e00e7184a73afe0 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.026151' - updated_at: '2021-05-31 15:00:36.026151' -footprint_debug_411: - id: 411 - footprint: 190dd6c99ee1fd3f63114837392903c8e7ca65398745df117cdfb7babd40fa7d - data: 192018-12-17 12:23:01 +01001191970-01-01 23:59:59c69790b104c8c6eeac6f2a7a183f6fb9fbb6355b8338b91324cea23b5239d329 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.042863' - updated_at: '2021-05-31 15:00:36.042863' -footprint_debug_412: - id: 412 - footprint: 7d58f294c401985c3bcb29e874b62f3a50ebdc5621489dde78ff51dc800e9415 - data: 202018-12-17 12:23:01 +0100120true190dd6c99ee1fd3f63114837392903c8e7ca65398745df117cdfb7babd40fa7d - klass: HistoryValue - created_at: '2021-05-31 15:00:36.060922' - updated_at: '2021-05-31 15:00:36.060922' -footprint_debug_413: - id: 413 - footprint: c5aa44060b1581338ef85a7245fc738471bcbb0b675b3cdda9ca30f9baef1a2e - data: 212018-12-17 12:23:01 +0100121247d58f294c401985c3bcb29e874b62f3a50ebdc5621489dde78ff51dc800e9415 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.076338' - updated_at: '2021-05-31 15:00:36.076338' -footprint_debug_414: - id: 414 - footprint: e92ac2440ede19347cd455d1f81414e3271549ee7ab9872c47adf920984bfdc7 - data: 222018-12-17 12:23:01 +0100122falsec5aa44060b1581338ef85a7245fc738471bcbb0b675b3cdda9ca30f9baef1a2e - klass: HistoryValue - created_at: '2021-05-31 15:00:36.092754' - updated_at: '2021-05-31 15:00:36.092754' -footprint_debug_415: - id: 415 - footprint: 83600acc4173c93e90a68bd38a9f747509ff6f987f90fec47eb6bf1434b305b0 - data: 232018-12-17 12:23:01 +010012324e92ac2440ede19347cd455d1f81414e3271549ee7ab9872c47adf920984bfdc7 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.109489' - updated_at: '2021-05-31 15:00:36.109489' -footprint_debug_416: - id: 416 - footprint: e158df6fcc48f10fd6797a823759d7780fdf7099ddbccad591bd221b9a30c3e6 - data: 242018-12-17 12:23:01 +0100124#cb111783600acc4173c93e90a68bd38a9f747509ff6f987f90fec47eb6bf1434b305b0 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.153002' - updated_at: '2021-05-31 15:00:36.153002' -footprint_debug_417: - id: 417 - footprint: 4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - data: 252018-12-17 12:23:01 +0100125#ffdd00e158df6fcc48f10fd6797a823759d7780fdf7099ddbccad591bd221b9a30c3e6 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.167821' - updated_at: '2021-05-31 15:00:36.167821' -footprint_debug_418: - id: 418 - footprint: f0b97bb9f3423c3528b712b3f06cacec1db36d4c208f8710fa398115a7f32156 - data: 262018-12-17 12:23:01 +0100126Avant de réserver une formation, nous vous conseillons - de consulter nos offres d'abonnement qui proposent des conditions avantageuses - sur le prix des formations et les créneaux machines.d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.184460' - updated_at: '2021-05-31 15:00:36.184460' -footprint_debug_419: - id: 419 - footprint: 76f95e6a1ae7ecb43aef2075ce20d6d63316f709fd74964aa18b17c71215196f - data: 272018-12-17 12:23:01 +0100127Fab Lab de La Casemate4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 15:00:36.211402' - updated_at: '2021-05-31 15:00:36.211402' -footprint_debug_420: - id: 420 - footprint: 590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - data: 282018-12-17 12:23:01 +0100128maleb227906223ad255fe9d5131046474ae24555c7cbeffc3b3e81c06e6a5297c72d - klass: HistoryValue - created_at: '2021-05-31 15:00:36.243279' - updated_at: '2021-05-31 15:00:36.243279' -footprint_debug_421: - id: 421 - footprint: c37769d58c7f9addfe4a06848a9018a979fb84d10b380dc49e8f8fe00cc120dc - data: 292018-12-17 12:23:01 +01001294d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 15:00:36.311365' - updated_at: '2021-05-31 15:00:36.311365' -footprint_debug_422: - id: 422 - footprint: fdee0b4c6408345ab1fc0fab7d11533fa519c181941804d02e51ce968146131c - data: 302018-12-17 12:23:01 +010013034d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 15:00:36.328766' - updated_at: '2021-05-31 15:00:36.328766' -footprint_debug_423: - id: 423 - footprint: b6277c53553c27bbd15a242adb1611fda19eb7d3dc049ff7b2c60cbb3e7662ba - data: 312018-12-17 12:23:01 +010013114d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 15:00:36.351232' - updated_at: '2021-05-31 15:00:36.351232' -footprint_debug_424: - id: 424 - footprint: 1b81675a112e1647267bde9452eb6aed2925f661b21c5319acb7b7a97dfbdafe - data: 322018-12-17 12:23:01 +0100132f4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 15:00:36.378063' - updated_at: '2021-05-31 15:00:36.378063' -footprint_debug_425: - id: 425 - footprint: 4dcbc36dbaeb6c62000aaa5affae1e19cbb8a207cfde546fd4e1f054afd9b69a - data: 332018-12-17 12:23:01 +0100133default4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 15:00:36.393016' - updated_at: '2021-05-31 15:00:36.393016' -footprint_debug_426: - id: 426 - footprint: 8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - data: 342018-12-31 11:22:25 +0100134A propos de Fab-manager590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.409384' - updated_at: '2021-05-31 15:00:36.409384' -footprint_debug_427: - id: 427 - footprint: 03f1e37492cd459b14143006941a3c6dd72a1d24f7367d46496da24a132f6b6d - data: 352018-12-31 11:22:25 +0100135* Tarif réduit si vous avez moins de 25 ans, - que vous êtes étudiant ou demandeur d'emploi.590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.426618' - updated_at: '2021-05-31 15:00:36.426618' -footprint_debug_428: - id: 428 - footprint: 1ced1c5fc617dac75fd3e1a94a8edc035470786c68b49da138cd9118723f8f0b - data: 362018-12-31 11:22:25 +0100136t590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.442835' - updated_at: '2021-05-31 15:00:36.442835' -footprint_debug_429: - id: 429 - footprint: bd8211c3a8a63d397085d48bb0121bdc51b40b2c7e5824d58fd23f6feb414204 - data: 372018-12-31 11:22:25 +010013724590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.459478' - updated_at: '2021-05-31 15:00:36.459478' -footprint_debug_430: - id: 430 - footprint: 1c5f2f5f596e7a735e2ce1085cc51e41e20c250051ff7591b3e4232bff9bf679 - data: '382018-12-31 11:22:25 +0100138

La présente politique de confidentialité - définit et vous informe de la manière dont _________ utilise et protège les informations - que vous nous transmettez, le cas échéant, lorsque vous utilisez le présent site - accessible à partir de l’URL suivante : _________ (ci-après le « Site »).

Veuillez - noter que cette politique de confidentialité est susceptible d’être modifiée ou - complétée à tout moment par _________, notamment en vue de se conformer à toute - évolution législative, réglementaire, jurisprudentielle ou technologique. Dans - un tel cas, la date de sa mise à jour sera clairement identifiée en tête de la - présente politique et l''Utilisateur sera informé par courriel. Ces modifications - engagent l’Utilisateur dès leur mise en ligne. Il convient par conséquent que - l’Utilisateur consulte régulièrement la présente politique de confidentialité - et d’utilisation des cookies afin de prendre connaissance de ses éventuelles modifications.

590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02' - klass: HistoryValue - created_at: '2021-05-31 15:00:36.476259' - updated_at: '2021-05-31 15:00:36.476259' -footprint_debug_431: - id: 431 - footprint: 6705cd67e864f65c5ed6c5e207a4d2267830b8ffb89a44f0a20ef02431342269 - data: 392019-09-20 13:02:32 +02001395308115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.492903' - updated_at: '2021-05-31 15:00:36.492903' -footprint_debug_432: - id: 432 - footprint: d53f5b5b4bb52d65d21ba105c71ae64f42d1193d49ba202c6dee6c672eefc15d - data: 402019-09-20 13:02:32 +020014058018115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.509931' - updated_at: '2021-05-31 15:00:36.509931' -footprint_debug_292: - id: 292 - footprint: fefee550d0b89fff624caa83e116137e776e6f2529393a7ae7d8a02289577d88 - data: 42016-04-05 10:35:52 +0200test7112030027055a339b3e10e0d5f1a1047898fa11b64a05088c9c1f0a2fd3108af4a03ac9330 - klass: Invoice - created_at: '2021-05-31 14:24:26.276430' - updated_at: '2021-05-31 14:24:26.276430' -footprint_debug_293: - id: 293 - footprint: 52ff4db137c1db67424a5c869307ab03c94cb357358cadaeb65667f04d173378 - data: 52016-04-05 10:36:46 +0200test31150603131500fefee550d0b89fff624caa83e116137e776e6f2529393a7ae7d8a02289577d88 - klass: Invoice - created_at: '2021-05-31 14:24:26.306074' - updated_at: '2021-05-31 14:24:26.306074' -footprint_debug_294: - id: 294 - footprint: aff284f918d75b27b2165404187843011a4115d1763a91e6c409a5d67db4a3c2 - data: 62021-01-04 15:51:21 +0100test8121010418300052ff4db137c1db67424a5c869307ab03c94cb357358cadaeb65667f04d173378 - klass: Invoice - created_at: '2021-05-31 14:24:26.322618' - updated_at: '2021-05-31 14:24:26.322618' -footprint_debug_295: - id: 295 - footprint: 364407aff754cab549374a99ccf12ab726c537765cc4f3358583335d4b9a589f - data: 402016-04-05 10:35:52 +0200Formation Laser / Vinyle April 11, 2012 08:00 - - 12:00 PM4true1Reservation036d18dd5a1d6340155d52a85d46074a7119e5e379430e4f1a26c9e7f0f05a97 - klass: InvoiceItem - created_at: '2021-05-31 14:24:26.381034' - updated_at: '2021-05-31 14:24:26.381034' -footprint_debug_296: - id: 296 - footprint: 9a6fdec124adc5662d4fd95c82e86c11853e2187c07138cde63f2f23159a0c9c - data: 515002016-04-05 10:36:46 +0200Imprimante 3D June 15, 2015 12:00 - 01:00 PM5true2Reservation364407aff754cab549374a99ccf12ab726c537765cc4f3358583335d4b9a589f - klass: InvoiceItem - created_at: '2021-05-31 14:24:26.397585' - updated_at: '2021-05-31 14:24:26.397585' -footprint_debug_297: - id: 297 - footprint: e9bd6492b7a0e8d19e7944dedabd9389964659cff02e7c450113104fe95ee7ba - data: 630002016-04-05 10:36:46 +0200Mensuel - standard, association - month6true4Subscription9a6fdec124adc5662d4fd95c82e86c11853e2187c07138cde63f2f23159a0c9c - klass: InvoiceItem - created_at: '2021-05-31 14:24:26.414279' - updated_at: '2021-05-31 14:24:26.414279' -footprint_debug_298: - id: 298 - footprint: fcc5700c917a25e79d5bb04b90531be52473b48cbe1e00009d412db88c9fc278 - data: '12018-12-17 12:23:01 +010011

Fab-manager - est outil de gestion des atelier de fabrication numérique, permettant de réserver - des machines de découpe, des imprimantes 3D, etc. tout en gérant simplement les - aspect financier, comptable et statistiques de votre espace.

Fab-manager est un projet libre: ouvert à tous, il offre la - possibilité de contribuer soi-même au code, de télécharger le logiciel, de l''étudier - et de le redistribuer. Vous n''êtes pas technicien ? Vous pouvez quand même participer - à traduire Fab-manager dans votre - langue.

Fab-manager favorise le partage de connaissances grâce au réseau - OpenLab: les projets que vous documentez sont partagés avec l''ensemble du réseau - des Fab-managers.

' - klass: HistoryValue - created_at: '2021-05-31 14:24:26.439340' - updated_at: '2021-05-31 14:24:26.439340' -footprint_debug_299: - id: 299 - footprint: d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - data: 22018-12-17 12:23:01 +010012Imaginer, Fabriquer,
Partager au Fab Lab
- de La Casematefcc5700c917a25e79d5bb04b90531be52473b48cbe1e00009d412db88c9fc278 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.456022' - updated_at: '2021-05-31 14:24:26.456022' -footprint_debug_300: - id: 300 - footprint: 33c39abf9e852b7f31d509d5cda12fe401160436a0b684fbbd8939320ac79159 - data: 32018-12-17 12:23:01 +010013
Contact commercial :
contact@fab-manager.com
-
Support technique :
Forum
-
Feedback
GitHub


-

Visitez le site de Fab-manager

d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.472700' - updated_at: '2021-05-31 14:24:26.472700' -footprint_debug_301: - id: 301 - footprint: bf38096a8a4223534da1b393c21866da6eabb951635b5575b9987f8a5983ae4b - data: 42018-12-17 12:23:01 +010014fab_manager5849b0af2169bb1f83a8f0a0ecf572a1adca4034097177fa08f91448bfdf427c - klass: HistoryValue - created_at: '2021-05-31 14:24:26.489417' - updated_at: '2021-05-31 14:24:26.489417' -footprint_debug_302: - id: 302 - footprint: 92120f18756df89476a3413456acc41a8bc2f169112f6e80b493d2daa1317b54 - data: 52018-12-17 12:23:01 +010015Tout achat d'heure machine est définitif. Aucune - annulation ne pourra être effectuée, néanmoins au plus tard 24h avant le créneau - fixé, vous pouvez en modifier la date et l'horaire à votre convenance et en fonction - du calendrier proposé. Passé ce délais, aucun changement ne pourra être effectué.d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.506771' - updated_at: '2021-05-31 14:24:26.506771' -footprint_debug_303: - id: 303 - footprint: aacaa245eb491bebb1768902f708c3397efca9f4db1adbf2e90a42a16831e986 - data: 62018-12-17 12:23:01 +010016Toute réservation de formation est définitive. - Aucune annulation ne pourra être effectuée, néanmoins au plus tard 24h avant le - créneau fixé, vous pouvez en modifier la date et l'horaire à votre convenance - et en fonction du calendrier proposé. Passé ce délais, aucun changement ne pourra - être effectué.d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.522944' - updated_at: '2021-05-31 14:24:26.522944' -footprint_debug_304: - id: 304 - footprint: 818f300cad937576887a0154584243803a0ddd25070e11f0d059f14b5ed291db - data: '72018-12-17 12:23:01 +010017

Règle sur la date de début des abonnements

  • - Si vous êtes un nouvel utilisateur - - i.e aucune formation d''enregistrée sur le site - votre abonnement débutera - à la date de réservation de votre première formation.
  • Si vous avez déjà une formation - ou plus de validée, votre abonnement débutera à la date de votre achat d''abonnement.
  • -

Merci de bien prendre ses informations en compte, et merci de votre compréhension. - L''équipe du Fab Lab.

bf38096a8a4223534da1b393c21866da6eabb951635b5575b9987f8a5983ae4b' - klass: HistoryValue - created_at: '2021-05-31 14:24:26.540163' - updated_at: '2021-05-31 14:24:26.540163' -footprint_debug_305: - id: 305 - footprint: eb5786adc7ce35b66489a84a3c5e1fadbe473f68161e6417d27d5df38ed12e69 - data: 92018-12-17 12:23:01 +010019iVBORw0KGgoAAAANSUhEUgAAAG0AAABZCAYAAAA0E6rtAAAACXBIWXMAAAsTAAALEwEAmpwYAAA57WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMzggNzkuMTU5ODI0LCAyMDE2LzA5LzE0LTAxOjA5OjAxICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNyAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTctMDEtMDNUMTE6MTg6MTgrMDE6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNy0wNi0wNlQxNTo1NjoxMiswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6TWV0YWRhdGFEYXRlPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3htcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDxwaG90b3Nob3A6Q29sb3JNb2RlPjM8L3Bob3Rvc2hvcDpDb2xvck1vZGU+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6MmYwMTE5MTMtODI5NS0zOTQ0LWJmZjYtMTY5ZTNhZTQ5OThlPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6ZGU3ZGE1MmYtNGFiZi0xMWU3LTljODAtYWJjY2ZlM2JkNzdmPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6YTE5NTAzOTAtOGQwOS0zMzQ3LWFkNGQtMzkyNDQ2YjRiNWJiPC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpIaXN0b3J5PgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+Y3JlYXRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOmExOTUwMzkwLThkMDktMzM0Ny1hZDRkLTM5MjQ0NmI0YjViYjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0wMS0wM1QxMToxODoxOCswMTowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDoyZjAxMTkxMy04Mjk1LTM5NDQtYmZmNi0xNjllM2FlNDk5OGU8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTA5PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjg5PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz7jSvdMAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAACL8SURBVHja7J15nB5Ftfe/VdXLsy8zk5lM9hASsrDKImgiuyCL7ILgq4KKu9flivuCiKjoFeWqCCoKQpTLIsiOrBqI5Bo2IQsJ2ZPJZPZn7ae7q94/+kkyQzIhExKSwVufT08mz3RX91Onzjm/86tTp4Vh+9oKYCFQA/YlThaHB+jlBmxuIcdyesmQQVAixELjYOPRSo25KDoJMdQ4mjTLKNFInBUENOGzEoc4vphEYnwVe4KNPdmgJoMeKxAjDSYnEAnABgSgo0cxZQNdINYJ9CqfcJmAxQaWpulZW0GZEI9RJHgcRYDmEKCIxQbKOLhoYF9COrDoJsQGRpNhPj20U+Xs+g0Ha712jKXpRhwdsrObhcAIQ61apeZ7xJXiQa+IxRvQNo5yWP/dABpDI8nRAn/mQcTfHmJN82GqTTjGECLw61fp+tn9ezObfhcIQAIKGwlIA2JlmRELfbz5LvajFeSTEJR0/ezh3qw3QmA1DApDDIFGjsnSOFMgjs/iHA/B2Co1DB4QIgDhOsjGHCqbRyQzyKYUoiEGjgVKQqjBCzBdFXRHCV3uRff1YDp60V5FAOMlanwM6wRD+kt98MxEggcM4pEqxblgSgEG+/+EtvUWYEigaMbZL0fiPQXEOQ5iH6gR0IfARubSqGlNWJP2wZk+HWvGOKzRLagRo5DZEchUGlSsrlEbm4awgi4VCHs7CNvbCFevI1i4Ev/FBfgvLyRc1AHdRWkIDk5iHSywLwlIPyHRs9OEd4Nsq9Qnyv8JDRAYAiRdJGaOJf4xkCeFeHlDDYRCjmoh/tYZuMcdQezQI7D2HovKtQDudt5BgkoiM0lkZiT22H3hYOA0AI+wux1/6XJq85/Ge+gf+P94kWDdOssEwTEK65gmsotq6D/a+L8PKS4zmH93oQkE4jBJ8uIa6mxFNaspI5wksbcfSuykY3CPOgJ3/0MRTnoX3N9F5ceiDhlL7JBZmA+WqS2aT23OfKoPPob3xP8SdHbto1DfypA6uwP1q4DwJkGpSw/Q5je50Mymn3arwP2YwP64xB9h6IV0lsQJx5M4+1RiJ5yIyo1+Q7+kcBK4+83E3W8myQs/iDdvDuU7/oJ359/xly6fYVA/s4m9O0bsexA+atD/HkKTCAycKkhfKggPgh6MZRM76ShSn7yQ+DEnIqzUbv/C0s0Qn/ku4jPfhf+J5yjdfAvl39+Jv/SV42ycQxXJHxjCnwSYavhmFppANKTJfUUgPwrVNBRxDtqX9Fc/TuKkM5CJhj3yy9uTDiD3jf1JnnsWpRtnU7zu1my4fv33KqQOzGB/thtvXfhGoLUhNvXt7TyxF+iox1rN2CgUVTzGkZoxntj1BnGBps9V2RiZL15E/r9/TOzQYxB2fA/3EALV2ErsmHfiHn8IplKg8vyiGSn0kXncuY3U2rfl5Txl0e0mUGbnAxmJAAFhEBDqEFtKloY1xI4yIhYumvCoEWR/1Y4/Bbpx9p1K/spvEj/xrGEbuBpdpfw/f6D30p/AgsWLIPFegXxGI9HKEE6OU7MCTBAgAoHZIKkJK3IObxAjskNQSeMjiJ8myNzVSW2KoJvE2Scw4sFbhrXAAISMkTz3w7Q8fhfOOafuU6Z0bwU9xcOmImwqCYdSyqGYcigmHTxpIcwbGy4MSWhhHR9Kkh80iFsExbShRObLn6LpltnYrfvwZmlqxCSabrmdkX/4r5FWxvzF0DFNoVGhxvLrR6CR5o2P7+RQBGYBY8mdHyN7vaHqGAHZy/+D/BVXIEWSN2NLXfAZmu/5w5TYhL2vC4OOFnwNYvdyKEMS2jhyZ7SQusGniHENuau/QvarlwMOb+YWm/luRj5229uzp59wDZWiFRaKaM+L7M5uEKD6Gv259C2PiJASeOSOtkjdEFJMQUj+qq+Q+dSX+HdpMtdM6pQTp1LodorPPfOwPXok0tiYDVWEkOwKAnNQ9PivbTAcCkGKJAHuZIV7hyCYoSmT+95nyX7lO/CmWOgYIgjrai/odUvfW3nuX/es/NS3CMsVZDy2i4LoQdbTzDaEFkawI6lwrxaEMzS9ZD73IbJfuYx/1yYbmpOmpprXfvVj+N2dWA2NoHcxGDED6WxLDs5yILHQxL4i4YSQLhJnHkfuh1fsqifDX72U2spX0NUyQu6BxK0UiESy1nPzbftUVjx/pJMbmzIm2NUWxxdKrreMtcRgSgYQSwbRMos4FvmTQ8QfoCdnHziREbfPxp64705/qtqaJXRefTWV+/9B2N0LYW23I7Stz2SBCUKjC9WSULKG2uX+QRhDKISpSOQC41X+685y1/1i8Vbva7BIjlTk74Dq4SJpaJz9MxKnnr/zp9GGlaz9wMUU7nsUiYtw3T3aVwoAx0I4kjd6CU4JWerwq+dZFTKvYjsMNgKX+MUQHG4okfrURbtEYAB9f76N4n1zUHYamYkzYCRej+wMr68fM4jENqaomNfoV2ylv9cp5MDo5EjLvcSyBtzHINAo4ocJ5Ec03TgHTiPzuc/vstkTrFqFEDYi4cBGdkEAAYR9JRiyzzAI6SKzMbAE1DS6t4LB385+DEI50QSS/QZaCkw5RJfLbE5R2s7nQYDlIJIOwtpxDRVA1egJVhp/0wchggCJjbrIEIwRlkvqSx/Hatlr1+m8bcOrQIephsikQ8Pn3os9ZgymUt1un4NjUZk3n/K9T2LKIDMxcp84HWevvTA1f/PEGOR64SjKT/2T4v3zEI5A1H2rKdawxjWQOe88VKYR43mDDq0xGlOrEvb14Le3E7zchr9gFUFvB9LNIlOxbT/Ha3gUayzlTf/rxaGN/CwXeXZIH/FTjyHx7tPfAGv9KpNYDRCNSRo++0mcsTOG3Fv3LddS/MsTaK+GlWim4Qufwd3rwO2+3rn/dor3zIMgjDLAtEFXa6jRjTR+8Quo1FBW3jVhqQdvwbMU7ryT7qtuRXcWkI2pHdY46UNd16IRU6iLNbVGmUqTvvgDqETT7nH3xmBK3g7CUVMfkACZTSAT+aEp/9ixqKwLFT3QP4UGM+RMBIlKNpA45BhaLvspY/7831gjmwg7SzuMkKVTZw5HAz0k9k/C8YYSsVPeRuydJw/PCNiYekCqUePzqHzj0JiI1mbU6Aw60FtahNfJ6qeOPYPmn38LmXTR5doOgST5QVKcS5KzSAHue0K8FmGniJ95GkLGGbbNENEDrQ1Id2g0k0ynsEa1RIBjFyy9ZM98D+kzj0FXylHi7VCF9i08vo/HZcTHS9RpITXcd+xP/Jhjhq28hGWB0Qgs7JZWhprlIe089qgJGMIdoKi253yX5CnHI6RAe0NPH5LLkaxE0Ik+XKL3FShi7zoW1Th2eKgTQb8jmrUmrGG0Bhys1h35HhJr1KhI04YotMI9f2Ltpy+m+MS92zwvtv8UrLEtmFow5Kez3o6giyRFnONCaqhxrbhHHjYsNKo8/3G6r7kWQT3HXwiEpfBeXooUNiQdrFE7lmNpj21EYDCBQQxBUUvz/sb6/76O8kOPM/7hydijJ2+9/9bx2A3NBCvWA0NzQ5ZNFRvVDMmjwMc+eCrufocMC6H5y1+m+7pbEFiR4DYGs3YMEUpUc6Lum7amowYqRVAWwtly0KwxLRBzMaEZElZQiTQ2ktqiDryXFg4qNJHOI7PpTdZhSEJbDxRxDncIJxlsYkcfinCzw8N3SRclsoikQiirP0mH7q4iGzKohtzWLw41tVULUblmrObxWw7MqBasxhxBW9+QfOJG3CKVA54/uAGWDiLnbERMQ4rZZBoLgTvTUBMym8I55G3DCHEIEDIyjf0PEbESVtMIVHqQvQKhj7fkecLezkHM11hUfgSEwet7vm3GojsYpy1B4MB0Q4ic0oi115hhBhWJOMJXH2hUtgGZ2HoqutEa75VFhIXurZugxjFYo0dgCIb+PPV/RWzwUMNoD9PjsSOBmowTHxPCFIHG2XsKVkvL8AnFwiph2EvY3UfY0UfY0YvuKNWZDIPM5hCxxNYvDgJqS1YQ9vYMRmZh792MQA/JdulKkRANeY01tnXQ84INqwg6NkSmd4hRhaVx9pKYyQaNPX06kBo2QnMmTiH/sXMQSFAKYSmCnh6qDz1LWOzBGjcCYW09tU8XCtReakMfVRgcQU6sx3hDCLDdyVPIHHcImXPPw52y/6DnVebNx1vyCiLmDvl7Wy5MNmiIuVgzxg0ryxg/6EhG//LIAZ95K55n9bMfwKxdgzWmedBrw+4NhGs60cXBVxDsMeMR0sEMIVbLn/8pcud/EoEaHPWuep7OS68GD2R+6Ns7LIE1CXxUYx61DXUeNi0UmFqIVAmsEYMTxUHXOsKuTvQ2SGmroRUh7aFBuyjxbWu6TfX5x+m+4Qb6fv8QYUcB1Zip85lD9GkCMRZCZDaP1Txq+AvNGEwYoNJZrOZt+ZR1BB3d6J6+wYU2ajQiaUN1Z/CPBl0pEXR1oSv1BdkdzOKSQItBIxJpZLaJN0ULfGQ6g9U4cnCF7OpGBx5h2+BCs8eNxhqXwXh6J6StKBJvPYWxv72TiU/fQeygqQTdxR0ipCWYHBhkPolIpIa/wCwbbJBjsqjGEYMLrVCK6pl0dhNt4NpaEJtBjWseEuwPC52EPavraRKD8I7T30brr3+APTJP2FvdIU1LAIjGGMKODSv5aK9E0LGaoGstQddadLWXYP0ajPaxxzUiM4MzO2FvoY4iu9F+aZCQK4EzYWI9v2T7Wu+t17PypLNo/+F3MbXBkWn8LUeSOvNoTFhlqE7NAhEDEDEbtoF49sRWnvswG778faRtRZBfSoK+AuGaEvZZYxFi8I0h4SvrolpN61ahC33Ihq2DFnfCZAwewmwfNK+tXkXfU09TeWYRqeOOJXHwrMEFd/hB9F5zJxgNQg1FaHVJKclwy80PO9dTmvt0P8I4ylMTMoHdOmob36eGsAQ2MUTOxlRqgw/Q1Imb+t2e4ZFuHIVCeDF0W8c2z7VbxiBsB2PMkDIPLKJ8sF2fj74rGCwVQ4k8Ir2ZMDYVD7BQmYZtUEiShku+SPYjFyESCVR+cJTpTBiNSibQpe30ayb6IdRrs8DCjYOREIaR6pjtFpqpgcFU/br81DCT3MDDhBqZsLBGDI6EhbSI7bP/9g1QcxPWyBaqS1cN/cFeaz+C3LEtUhIogcB0VjB+ZZjHaECgkQ1x1OiRO6VLlW/CbmzGUNuhmHGXAGSQXQKB7ipiSn2I3PCG/cYYZFMG2ZjfKf1JuxHV0Dj0FEVtQOvtsxQYjOdvaR6FQNhqiyUeaTBtIDH1am7DX9XAampCpXZWzS2J2qfOFG1HDo4QUTXLUJchvj1pBCIKE6s+eB54teio1jAVDxNuucfbAr0SFLq3G92+DsbvP9xlhtU4EpV+rdX3GuDVPUScbW0/t/ceHS0uB6+tOUGhBx/IHjWN2MFveQ34G2CqNexpeUZ89zOoZH5TurlwHfz2drp+dBP+whWI1OaQw5LoZQZB2N1LsKYN99BhKjABhAaBwR41EmFtS9NC2r/2DQqz78Ea10rTd79Mcuaxg57tjh2NwsaEr61quXe/l/gBh5A69l1YuW37VV0ro6mhGjOkTz0faQ806brSS99vH6ZWW4LoV1JRhuilIKHiESxYNbyNY2jAsVATm7d9Xq1Aae4c+pa9SOHxv1F7+ZVtx1Nj9kKS2a7Ug/ihR5E7+yNY+dfOAAg71gFBpMFbCbl0TxfGq2wRb0qbYLlBLjMI/IULgWGMIEODSMewWradBh5WC1AOcEhgJXLgl7eN1lonIFsymNeTL7KVVnn2JTSVwUMDIbaaZyI3UF4hYbFA4i9eTNCxfhgjR42Mx5CZbYMQXSyie3sQ2JggJOjr2bbQmpqxJzXCTqwDWXvlOUp3/Q2BM+RQTU5CU8EsAEW4uJ1g2Z5gIuvbLG33NRgRNXAiao1KZbBGtLyGeQwI+qL6yegQXShs+z5OEmevcdHmffH6N/CHpfW0X3oFtUUrkMSjPrcmOcup04sDTaelCYnh/x2cz+quIrWnnyJ26KzdDioMBl3qBHzC0paaIJNZwkpfXbxis3lMJBGuwphSfdfmwI5VMk/QthJT9BDKRuuQsHMDobceoRIY71VLJVIhbFBNjRijCUsdqEwTutT72hNPa0wQYmo1dM1Dd/ZQfWY+vbNvo/zos8hsGtPrY3RAWOpE2HF0uRjdNpFAFzfU/ejAiWL9BZiCN2c8saVV/EnVv84l/aFeRCy725RMJGxMxaf9a9/HyuejwHNAMArCtqitWIWI2wgZfShTDkHHBtq//H1UPD4Q7W0q328RtK0HbSNSCqldyg/PZ90HPgVSsWkDmu7nV6TAW7CEcH2J9k9/AxlLYvxgcI6pzi+bMMT4NUylTNhXIGzvJVjbhfE8VDYFjkIkIVjZTdvFlyDt2KZnFpYiLJXwV61GpAdaHCtBDB+7zYdHJPYk/58v4T03j9hbj9t9mmZL8DWle56sLyaqfghKbxoVYcWQ2XidUQijPRidvZTueqK+AaN+mTH9rosyk2UuAcIgqgJ/URu1hSuJygRsTAPffE8BEHMRCAq3PcLGoh1b8Zb1Y2Pypd4sSSEQMtprIGLxaOMjISQUus+jcOtjRF9gI5GqAYVMJxCuNQBdytMQHEIFg/+QxiVc1Yb3xNO736UpkLk4Mp2MvrAQUSFMqVC5JDIWxwQ+ulAl7OyDqo9wBbpSw2iDyidRDal6ERmDTCdRzVmEFcPoWn23igBHQCzafSMtB7slH2kBINMxrOY0uDamWsaYANWYQsZigEbGHVRTCpVPRkNtWch8GmEpIKgvGTmoXBLVlAIp0F4t2sDvgu4toTuLCEchU7E6KImWmGTMjfq15RbhgKWooIBWvLlrsV4w6P2q9z1M6sL3oZp2T0qdCTWmBo1ffB+pE4+jcO9f6fn1zdijR5K78HycGTPQxQK9N95M3y33k3nPiWTOPhNrZAvewkX0XHcz3rxFgMFqaSD7kbNIHPkORDZNsGIVfTffQuGORxGkaPz2R3An7EPxgfuIH3gQsbcehi6X6P3NDRRuepCwFC2bZC86jfQpJ6OamwnWt1G47S6Ktz8G5YCwXME9YC/yn76I2L77UfnH01Tm/4PUrOMJyxW6f3493qLF2M2t5D52LolZMxGOTfWZZ+j6xfXUFi8jMetwGj56IUF7O96SF0keeTS15a/Q9aPfYSoBwlWb8cjFwPuBS5Aso+WyVTSaFdYIU/jT9eaNaG3fucS8qBrMgmyrWdgw2ixsGG0WZFrMS26r6b3jZmOMMTr0THHuA6a67MUB1/qda03PX24wYblnwOeVF+aaxXtNM4vG7GUKj9+9xT21qZpVHzjPvOgkTe+9s+ufhgPPCQpm+QknmBfAdPzqB1v2oaum7VtfMC+SMC9Pnm7K/3py4N9DzxhjTFBoN0v2P8QscBpM7103bdFP+aW/mZdSObPi9FP7PZ9vjDGm957ZZkHDKLMg0WIWNtbHJj9qqbwWuAH4AxqDd6vEXW+CEpU77sLoym4EkGYzDycdkm99J+6E6QPNREMr2VP+HzI+EDTF9j2U2BHTSZ04k9Q7TgRgw/e+w8rz3k3QvhKBS8MnPow1Kk/YU+yHIPqHEyncQ6YSP3Bf8hd/CIDCPXew+sLzqMz7O0K4ZM46G2v8SHIfOpf4jCMA6P3z72m/8kuE3Z11VqOECTyyn76AzKnno70KHVddTvsVX0WXC8SnzST3yfcSdm/Y7BmrFbyXn6E8Z25k9tWr0OPGVSIbKFJ5rp3EXy3iF1TvfYrqw/cSP37PqElsdEDxgTsxlQqpk05HxiK/o8s99Mz+He4+00nOfOfmdbCmPKVbH2fFqccjx0q8p9bir15LbfkSrOZxWA2tqFQefL/eTx+9N96ASMfJnnM+wo7jjBlF39oS6z7wccj71J5dgvfMchJvfxvxQ2ci3RzutCm4hx0IgLfiGdZ9+At4nZ1YmVE0fPQ/wNdYTXlih0VEvL/iJYp/foCgdx2Zs84hNuUgEoe/BX/B8k0gputHP2LDN36CdJJRUZxXhWpW/zcbRXgpvFbgvkv39TQUrr0RZ9bRqNjur6vvL3mBdR/7AkZUmXjAATiT9gOg9Mj9rPjw5xhx8Xn9hGYgCPHXrSd58nFkLziT+E9mINwEwkS5/cb3Iwdfj86rzz7Nus99HXf6GFJHH4XVOgkcG699Bc7aKTSccSHuJftitzYjdKLeRw3pJlDJSNNrS14h7OzBQrKxDrvRGpXJYzdGfKiz9wFMePTBepAejb7Kj0Am6wVhhCFY04mhiointpqGYK2pbx2NQKZAUHrCkLxdkvxw9a4nqNxzF6mzPrjbhabDABlkMckYRg7kGyWgYukBdJbWJRq/fiEtl14V8Xxz51L913OkTj4Ru3X8wLUcAMug3AaUk4vQHRC2ryd19BGMf+g2BEn8dWsp/Plx3GlTiU3dd3OVcLHpxph62DCQp9x8n6B7A7VFi6M4zitjAijNfaKO9KNUD5Fyog1ocuslmaxyv3gjihA0IcHvbNxTTK04svCDXxI78lispt27cV4ohbAkRkqQ/TgfR/WPpqIhqgaopgSxww+KzNaSf7LqrHOorl3N5PmPR0Izr2LWpYpKKgm5SfuMXSVx4iEIkmivm7UfeT999zzM6F9fRWzqviAVulwiLEZZys6kvbAbRlHrWoNKJ+vPLQl7ewna26PJt2EVbZ/6JNVnFiHTaax9svgvtpM++YStyXjr8bvZHMCj69GFpjbHEP5GkKU273kKV/9096xnqn5JRsqKCCshELLfRNv4ez+mXNgWxtforohqslv3pvm/LmfSk38lftA76jRYBhx7E/4Qth3Fg0oibGcj6YUp1muHOVlyF32QcTf/htz7ImCicjnCzm4qf38qWneb+BbG3P5bxv3pt2TOOK8OFgRhZzelx54CDO7Uwxh1zXWM/NkVjP79dUx66lnSZ59C0N3Vb4Ja25ScTFKk/5GiRJICFoVrwJovSFK86kYqD9z2xquXEgPM1yYqyurHtjuy3/RjEwVkSgF9f7qH2urFyGSW3Lnvx5kwmcqzj0WnN2Sx9s5BGCFUHUSZvsZodFDZNDqF/3mY2pqXEEKSPfN9pM8+h6BtKRCiRo3A2ruVnl/MpvjQXwBIHvlOsud8AFnffC8sCcqh77e30fWbn2IIiB92BI2f/k8yZ5yFtLLInI1w+1kKodlWmpYlB5GoJFwdoC+H2A2mrzvZ/c3vYU2fjj122s52VltMKiElQkHxrnsI17eBBn/NKnSlAEFI9zW/xm4ehXAdKvOfQZHAe3YBXb+4EnRUR6T2wkoqj73Amr6LSZ04C5lK0XfbA4QdbSSPextGC4J1PfTedDve84uorVqFoYa/uo31l3wNK99A9fkF+AvXsPqci8icfzpWvpnSI4/jvfACyWOPQOYbML09+G0dtH3+y6ROuw+7cS+8Jc+SOvVUMieeC5aNdF3CoED7F6+k/Pd/kHjrW5HJDEHHGsqPPk35wXnY00ay4YqvoIOAytynkW5i8Km8fFvjiY2k4ccS+fmQDSTOO5kRN92MkImdJrP2y75ExzevQeWS0TKE2WwfTdmvE6jRYqBI2ogQdNVnY50qYSlEwsFUw6g0YD1HVDg2QkFYKEeEsqgv+BiF0VGgI90kRvsYv4IQDjKbxAQaXSxFjsJKIFMxdF+xXqPEQddq0S1EpPlSO8iWOA1f/TAEFrV/voxsTdP4+c9gt+5F5fk5rD75IoK1HQhHoatVhO0ilIXxPUxYQ8bTYAl0sRy5gLiDjDtbTcEzxiy3xmzTr4T4mMsqcGAvjcdU/vgAPWO/Sv6HV+00oSVmzUJlfkfQU0DlMnUAFQ0yrkRsrIcpRISSZVQSe2PRMpQAaRDOq/yaFdkRZdcZeQ3SsSKQEdZz/KWIci+0E91DgZAClU1u+jvKIHPJaEKEGpWOgZKYIARhMH0BamSK7PvOw87vPXDdrNxO19XX4q9uR2UTYAuUa0fPYwJEzEE6iQjWh0Swv27et5ozKaCmxX3i3a/BS6xD8VHi095L7s8dVKcYKuSu/CLZ//zmzrKPdP/6l3Rc9lNqK9fsoS81NggVR+biAwdTgKmEiEyczLknkjzhSNToFowf4C9+hcIf76Z875MQcxAxueML3yIyE77WNzeV+z6xXSP0fuCXZE/oIz3bo5jHgoZrvkn6Q5/bacNSXTSfwh13UV34L4wX1FeJ9wB5iWhtpzLn+XnBmsI6kbLsAT5YCvBCdLGETMdQTXlMEBKu78TUAmQiCTFrR7ONpTCEEK7ywuDBlkrlgZFBubxdw3I+cBOwlvx5htTskCImLsj//FtkLvzMTp7TIa9d1fmNZUEFkp5bbzp29Tnve8TKjxJbVOoUQCnE1MJ64BTBXJFS0drgDmaHGyEQgUEERVMJPEYbxYigun27LQ4EzgCWU/1XDbkiQfp0E/hU730U4h6xt82CnfTWWoHcww4BoK0pU64O17Svqzw1B/nq2iQCCCUiUJu2XQkUuGJIu2G2puVCgzA+gQ7JIEjqYOjvT+ui53cBfZ+QxEN8Q+8Xr6T761/GMMw3bwzmcbvX0/n1C38cdiyZH5t1OJpgtz/TkIS2cQHep/TLGuEFhnTFkKDv8p/Rcd578dsWvakE5j31MG1HH31lde5jl9gjWhAVb48w2tbQzRdoFJrSn1zEhpDMtYL8pNKf7sV/cRn5H3+b+DvPGN7a1bOW8s+uZv1Vv7r8X93dX1eZOC/MeBtedy+j3Qx5qfD17nuh8nb5tAPqPq2daNtCCguDZCSFZTXcRzRqmiAxMWxfR/Xuv6JLa7EOmIZMZIeVsExQpXzPbHo//Y2w+/d//LpXLX9nDVDxAiqdXZRKZZpiCZKWTfgq6L+puGv/5rJLfNoOCS2JhUGRpYZHot0jvFsgpCKxn6nW3MoTc/Ae+RuyycKeOAFh7dlVE4xfpPrEA/R8+7v0fvMXK/1liz9ZQf8yJHpVtKibJAE0OnESw11oVZJ46Iqi+JDAesngTFXER4ZrV1K5/SH8Bc8hRyaxx4ypF5Tfg8yg10d1zoP0XPoD+i79Od685x7zdPihPvwHXQwa6OwH4vUeIrSd9Ub5KKcDcaemMA9in5TkPkHg5yq3PkT1wXnETjqc5AVnEjv6eGRyxG5lN4K2pVQfeJDy7ffiPfY8YV93l4+62iCvFjidhvIebRl28hvuBVBba5Bf08i7DfJjhvzZqq+SqPzxPqp3P4kz6yDix78D97iZODPe8obV/g83rKA670m8R+bhPT4H/5ml6LCqDfZfbNyfpOl5fD0WNi57erN2TbcC4ClB8ekY1h/KJD8icU4QxVqmet/f8O5/EjVxNO7b98eddRj2/m/BmjoRKzuSjXkTr5fP1OV2guVr8RctwPvfp6k98jz+Sy+j+3rrX9v6myR5HRRvh7DkoJEMj2btOiMksNFhkupDCvNQgDzYJ/4+cE7XhgnmlXWEr6yicuNDkIlj7TcKe/J0nAOnYc0Yj9U6CjWiFZHMItwYwtroIDamWweYwIeahy72EHasJVi3jmDRaoIXFuMvWYi/YBV6bRHMxvjKqQpSj2iq14N3t8Kp6k0OZ/gUvrF29Q0MAgeNS+2fUP1nF8mfWYiZGuckTfxIi7BV95WozVlIbc6LlACZiqNGNCEzeUQsCVkXkXEQrh2tuYUaPB/dV4MeD+OVCPu6CDu7MX1lNuaVSxQGx2hiLxrCu4D7AorzJDVPYe006u1NJ7T+YAVCJHpZnuKyblI3xtETejFvl7gH28QOAPYP0E2yGBAW1xOwlmjT05av+RNsep1cffAjLbRJEKJWB+jnArz5DqW5Ls7fl1Hts4FcXVDD+WXP1u66sUGSpLC8jXB5EnWTpCh68MeOJLZ3F4mpFtbeCsYDLQKSIFyiTBEZrS4JH4xnoCgwayUsA/PyagqL4nhLxhFrW4HApUiCDAaFIOTN0P7/ANXjuuhKlYnHAAAAAElFTkSuQmCC818f300cad937576887a0154584243803a0ddd25070e11f0d059f14b5ed291db - klass: HistoryValue - created_at: '2021-05-31 14:24:26.557925' - updated_at: '2021-05-31 14:24:26.557925' -footprint_debug_306: - id: 306 - footprint: 415e133e7426ba4d442edc83b8091888c9c2a5350981e8c2be8fd84c3eb80e14 - data: 102018-12-17 12:23:01 +0100110YYMMmmmX[/VL]R[/A]eb5786adc7ce35b66489a84a3c5e1fadbe473f68161e6417d27d5df38ed12e69 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.573269' - updated_at: '2021-05-31 14:24:26.573269' -footprint_debug_307: - id: 307 - footprint: '06248f3ed99242d8b2588f97cbdc97732fa4e752912f601df70699f9f7a8919a' - data: 112018-12-17 12:23:01 +0100111true415e133e7426ba4d442edc83b8091888c9c2a5350981e8c2be8fd84c3eb80e14 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.589787' - updated_at: '2021-05-31 14:24:26.589787' -footprint_debug_308: - id: 308 - footprint: ea02f4452b07542799e576925ac9f9ee563cb5520de6e57861ba7be8a7cb3993 - data: 122018-12-17 12:23:01 +0100112INMEDFABLAB06248f3ed99242d8b2588f97cbdc97732fa4e752912f601df70699f9f7a8919a - klass: HistoryValue - created_at: '2021-05-31 14:24:26.606352' - updated_at: '2021-05-31 14:24:26.606352' -footprint_debug_309: - id: 309 - footprint: e090b8e07b36addc29f8d479b3d8e756aadbc12005cd6ad920175cbce1d37cf1 - data: 132018-12-17 12:23:01 +0100113nnnnnn-MM-YYea02f4452b07542799e576925ac9f9ee563cb5520de6e57861ba7be8a7cb3993 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.623115' - updated_at: '2021-05-31 14:24:26.623115' -footprint_debug_310: - id: 310 - footprint: a1681dc7ed8d92782d6ddba98ea6c80e726deff845bd40678b310b5bc63e0c58 - data: 142018-12-17 12:23:01 +0100114falsee090b8e07b36addc29f8d479b3d8e756aadbc12005cd6ad920175cbce1d37cf1 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.641727' - updated_at: '2021-05-31 14:24:26.641727' -footprint_debug_311: - id: 311 - footprint: 5f179582e43d783803d5f2ef2dce87253dd95341fa8bd2431cade4ca80200a46 - data: 152018-12-17 12:23:01 +010011520.0a1681dc7ed8d92782d6ddba98ea6c80e726deff845bd40678b310b5bc63e0c58 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.658269' - updated_at: '2021-05-31 14:24:26.658269' -footprint_debug_312: - id: 312 - footprint: 92b2e93fc98fe045de4d2d889068c162ee9806e1862e91c45e00e7184a73afe0 - data: 162018-12-17 12:23:01 +0100116Notre association n'est pas assujettie à la - TVA5f179582e43d783803d5f2ef2dce87253dd95341fa8bd2431cade4ca80200a46 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.681487' - updated_at: '2021-05-31 14:24:26.681487' -footprint_debug_313: - id: 313 - footprint: c048d95a3acfa7543e4783cdaca27cbcea20c4b7277851a83a9aae2be2b182c3 - data: '172018-12-17 12:23:01 +0100117Fab-manager
41 rue du Colonel Moutarde, - 21000 DIJON France
Tél.: +33 1 23 45 67 98
Fax. : +33 1 23 45 67 98
- SIRET : 237 082 474 00006 - APE 913 Ed2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147' - klass: HistoryValue - created_at: '2021-05-31 14:24:26.700565' - updated_at: '2021-05-31 14:24:26.700565' -footprint_debug_314: - id: 314 - footprint: c69790b104c8c6eeac6f2a7a183f6fb9fbb6355b8338b91324cea23b5239d329 - data: 182018-12-17 12:23:01 +01001181970-01-01 08:00:0092b2e93fc98fe045de4d2d889068c162ee9806e1862e91c45e00e7184a73afe0 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.714751' - updated_at: '2021-05-31 14:24:26.714751' -footprint_debug_315: - id: 315 - footprint: 190dd6c99ee1fd3f63114837392903c8e7ca65398745df117cdfb7babd40fa7d - data: 192018-12-17 12:23:01 +01001191970-01-01 23:59:59c69790b104c8c6eeac6f2a7a183f6fb9fbb6355b8338b91324cea23b5239d329 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.733361' - updated_at: '2021-05-31 14:24:26.733361' -footprint_debug_316: - id: 316 - footprint: 7d58f294c401985c3bcb29e874b62f3a50ebdc5621489dde78ff51dc800e9415 - data: 202018-12-17 12:23:01 +0100120true190dd6c99ee1fd3f63114837392903c8e7ca65398745df117cdfb7babd40fa7d - klass: HistoryValue - created_at: '2021-05-31 14:24:26.748202' - updated_at: '2021-05-31 14:24:26.748202' -footprint_debug_317: - id: 317 - footprint: c5aa44060b1581338ef85a7245fc738471bcbb0b675b3cdda9ca30f9baef1a2e - data: 212018-12-17 12:23:01 +0100121247d58f294c401985c3bcb29e874b62f3a50ebdc5621489dde78ff51dc800e9415 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.764897' - updated_at: '2021-05-31 14:24:26.764897' -footprint_debug_318: - id: 318 - footprint: e92ac2440ede19347cd455d1f81414e3271549ee7ab9872c47adf920984bfdc7 - data: 222018-12-17 12:23:01 +0100122falsec5aa44060b1581338ef85a7245fc738471bcbb0b675b3cdda9ca30f9baef1a2e - klass: HistoryValue - created_at: '2021-05-31 14:24:26.781471' - updated_at: '2021-05-31 14:24:26.781471' -footprint_debug_319: - id: 319 - footprint: 83600acc4173c93e90a68bd38a9f747509ff6f987f90fec47eb6bf1434b305b0 - data: 232018-12-17 12:23:01 +010012324e92ac2440ede19347cd455d1f81414e3271549ee7ab9872c47adf920984bfdc7 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.798088' - updated_at: '2021-05-31 14:24:26.798088' -footprint_debug_320: - id: 320 - footprint: e158df6fcc48f10fd6797a823759d7780fdf7099ddbccad591bd221b9a30c3e6 - data: 242018-12-17 12:23:01 +0100124#cb111783600acc4173c93e90a68bd38a9f747509ff6f987f90fec47eb6bf1434b305b0 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.816447' - updated_at: '2021-05-31 14:24:26.816447' -footprint_debug_321: - id: 321 - footprint: 4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - data: 252018-12-17 12:23:01 +0100125#ffdd00e158df6fcc48f10fd6797a823759d7780fdf7099ddbccad591bd221b9a30c3e6 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.834439' - updated_at: '2021-05-31 14:24:26.834439' -footprint_debug_322: - id: 322 - footprint: f0b97bb9f3423c3528b712b3f06cacec1db36d4c208f8710fa398115a7f32156 - data: 262018-12-17 12:23:01 +0100126Avant de réserver une formation, nous vous conseillons - de consulter nos offres d'abonnement qui proposent des conditions avantageuses - sur le prix des formations et les créneaux machines.d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 - klass: HistoryValue - created_at: '2021-05-31 14:24:26.867893' - updated_at: '2021-05-31 14:24:26.867893' -footprint_debug_323: - id: 323 - footprint: 76f95e6a1ae7ecb43aef2075ce20d6d63316f709fd74964aa18b17c71215196f - data: 272018-12-17 12:23:01 +0100127Fab Lab de La Casemate4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 14:24:26.948633' - updated_at: '2021-05-31 14:24:26.948633' -footprint_debug_324: - id: 324 - footprint: 590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - data: 282018-12-17 12:23:01 +0100128maleb227906223ad255fe9d5131046474ae24555c7cbeffc3b3e81c06e6a5297c72d - klass: HistoryValue - created_at: '2021-05-31 14:24:26.966103' - updated_at: '2021-05-31 14:24:26.966103' -footprint_debug_325: - id: 325 - footprint: c37769d58c7f9addfe4a06848a9018a979fb84d10b380dc49e8f8fe00cc120dc - data: 292018-12-17 12:23:01 +01001294d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 14:24:26.981562' - updated_at: '2021-05-31 14:24:26.981562' -footprint_debug_326: - id: 326 - footprint: fdee0b4c6408345ab1fc0fab7d11533fa519c181941804d02e51ce968146131c - data: 302018-12-17 12:23:01 +010013034d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 14:24:26.998331' - updated_at: '2021-05-31 14:24:26.998331' -footprint_debug_327: - id: 327 - footprint: b6277c53553c27bbd15a242adb1611fda19eb7d3dc049ff7b2c60cbb3e7662ba - data: 312018-12-17 12:23:01 +010013114d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 14:24:27.014949' - updated_at: '2021-05-31 14:24:27.014949' -footprint_debug_328: - id: 328 - footprint: 1b81675a112e1647267bde9452eb6aed2925f661b21c5319acb7b7a97dfbdafe - data: 322018-12-17 12:23:01 +0100132f4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 14:24:27.031966' - updated_at: '2021-05-31 14:24:27.031966' -footprint_debug_329: - id: 329 - footprint: 4dcbc36dbaeb6c62000aaa5affae1e19cbb8a207cfde546fd4e1f054afd9b69a - data: 332018-12-17 12:23:01 +0100133default4d7d4f2319f1f784adf5453558c1d4bd1c019eece27d3379df8e2192654634cc - klass: HistoryValue - created_at: '2021-05-31 14:24:27.048396' - updated_at: '2021-05-31 14:24:27.048396' -footprint_debug_330: - id: 330 - footprint: 8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - data: 342018-12-31 11:22:25 +0100134A propos de Fab-manager590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.065055' - updated_at: '2021-05-31 14:24:27.065055' -footprint_debug_331: - id: 331 - footprint: 03f1e37492cd459b14143006941a3c6dd72a1d24f7367d46496da24a132f6b6d - data: 352018-12-31 11:22:25 +0100135* Tarif réduit si vous avez moins de 25 ans, - que vous êtes étudiant ou demandeur d'emploi.590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.081618' - updated_at: '2021-05-31 14:24:27.081618' -footprint_debug_332: - id: 332 - footprint: 1ced1c5fc617dac75fd3e1a94a8edc035470786c68b49da138cd9118723f8f0b - data: 362018-12-31 11:22:25 +0100136t590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.098666' - updated_at: '2021-05-31 14:24:27.098666' -footprint_debug_333: - id: 333 - footprint: bd8211c3a8a63d397085d48bb0121bdc51b40b2c7e5824d58fd23f6feb414204 - data: 372018-12-31 11:22:25 +010013724590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.114890' - updated_at: '2021-05-31 14:24:27.114890' -footprint_debug_334: - id: 334 - footprint: 1c5f2f5f596e7a735e2ce1085cc51e41e20c250051ff7591b3e4232bff9bf679 - data: '382018-12-31 11:22:25 +0100138

La présente politique de confidentialité - définit et vous informe de la manière dont _________ utilise et protège les informations - que vous nous transmettez, le cas échéant, lorsque vous utilisez le présent site - accessible à partir de l’URL suivante : _________ (ci-après le « Site »).

Veuillez - noter que cette politique de confidentialité est susceptible d’être modifiée ou - complétée à tout moment par _________, notamment en vue de se conformer à toute - évolution législative, réglementaire, jurisprudentielle ou technologique. Dans - un tel cas, la date de sa mise à jour sera clairement identifiée en tête de la - présente politique et l''Utilisateur sera informé par courriel. Ces modifications - engagent l’Utilisateur dès leur mise en ligne. Il convient par conséquent que - l’Utilisateur consulte régulièrement la présente politique de confidentialité - et d’utilisation des cookies afin de prendre connaissance de ses éventuelles modifications.

590ffe38616993f19972b90be909845e99a49c45a252c039168c000e1395bd02' - klass: HistoryValue - created_at: '2021-05-31 14:24:27.131658' - updated_at: '2021-05-31 14:24:27.131658' -footprint_debug_335: - id: 335 - footprint: 6705cd67e864f65c5ed6c5e207a4d2267830b8ffb89a44f0a20ef02431342269 - data: 392019-09-20 13:02:32 +02001395308115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.148369' - updated_at: '2021-05-31 14:24:27.148369' -footprint_debug_336: - id: 336 - footprint: d53f5b5b4bb52d65d21ba105c71ae64f42d1193d49ba202c6dee6c672eefc15d - data: 402019-09-20 13:02:32 +020014058018115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.165064' - updated_at: '2021-05-31 14:24:27.165064' -footprint_debug_337: - id: 337 - footprint: 371ade05448e6ba0d45288152cd8f04520203570a5b503072fe0fd98becd6274 - data: 412019-09-20 13:02:32 +0200141Client card8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.181733' - updated_at: '2021-05-31 14:24:27.181733' -footprint_debug_433: - id: 433 - footprint: 371ade05448e6ba0d45288152cd8f04520203570a5b503072fe0fd98becd6274 - data: 412019-09-20 13:02:32 +0200141Client card8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.526446' - updated_at: '2021-05-31 15:00:36.526446' -footprint_debug_434: - id: 434 - footprint: 9e9627351496aa3b81fcf9a2a186a1a244aa018c66690147dc77cb13110f0d17 - data: 422019-09-20 13:02:32 +020014258028115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.543068' - updated_at: '2021-05-31 15:00:36.543068' -footprint_debug_338: - id: 338 - footprint: 9e9627351496aa3b81fcf9a2a186a1a244aa018c66690147dc77cb13110f0d17 - data: 422019-09-20 13:02:32 +020014258028115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.198443' - updated_at: '2021-05-31 14:24:27.198443' -footprint_debug_339: - id: 339 - footprint: ab8e9b3ded4bed5ac11f14e5d794519877e4887ac2f1c7e609406cf06f29f553 - data: 432019-09-20 13:02:32 +0200143Client wallet8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.215165' - updated_at: '2021-05-31 14:24:27.215165' -footprint_debug_340: - id: 340 - footprint: 3fc58d50393f9d178200abe5adfd2df72e312dc91339985b1d94edcf17a1804d - data: 442019-09-20 13:02:32 +020014458038115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.231964' - updated_at: '2021-05-31 14:24:27.231964' -footprint_debug_341: - id: 341 - footprint: 76ec5b696c4537fd5af2d0906376479d56598b0f515d2c13397c7205c43b9793 - data: 452019-09-20 13:02:32 +0200145Client other8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.248582' - updated_at: '2021-05-31 14:24:27.248582' -footprint_debug_342: - id: 342 - footprint: 1dad73d081d3df136530a6f45833d645c6185dfe3190a724c8f6d0fed88704cc - data: 462019-09-20 13:02:32 +020014640918115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.265194' - updated_at: '2021-05-31 14:24:27.265194' -footprint_debug_343: - id: 343 - footprint: 3b55f0c50e8cd6728340ab6e146818ba800d4dd29aa5a6e95d5da2d984ebb377 - data: 472019-09-20 13:02:32 +0200147Wallet credit8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.281829' - updated_at: '2021-05-31 14:24:27.281829' -footprint_debug_344: - id: 344 - footprint: 3e10fbcf4fe7cf5eb112a1056865931bf46f24ac21da6313cb4400cb4b2dc391 - data: 482019-09-20 13:02:32 +02001484458115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.298579' - updated_at: '2021-05-31 14:24:27.298579' -footprint_debug_345: - id: 345 - footprint: 63a66401804d8a4fbf3177a4eb426623c15608af7f9b09e80e0bbed9b1e1e3b2 - data: 492019-09-20 13:02:32 +0200149VAT8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.315243' - updated_at: '2021-05-31 14:24:27.315243' -footprint_debug_346: - id: 346 - footprint: 89e852942f9b44775ee0c3b0e561c2d886b9dfc9ddb95b18c5a6137722d868e4 - data: 502019-09-20 13:02:32 +020015070618115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.331849' - updated_at: '2021-05-31 14:24:27.331849' -footprint_debug_347: - id: 347 - footprint: 169403ba2131226cf53b2c06ef2cef29570c22eb955bc263af6112d051f06617 - data: 512019-09-20 13:02:32 +0200151Subscription8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.373528' - updated_at: '2021-05-31 14:24:27.373528' -footprint_debug_348: - id: 348 - footprint: 9612c3c2b51c32d8827f03dbf76211f1595ca940b92837cad1ecde00c35543a6 - data: 522019-09-20 13:02:32 +020015270628115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.390238' - updated_at: '2021-05-31 14:24:27.390238' -footprint_debug_349: - id: 349 - footprint: 36dc3394e404aa37bb974a4c97945c6ba26a1721dbf12d269a48c7a94dc0490d - data: 532019-09-20 13:02:32 +0200153Machine reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.407671' - updated_at: '2021-05-31 14:24:27.407671' -footprint_debug_350: - id: 350 - footprint: 963edffba941ff733926b4cb6c5f439d9c348463fb4391bb6f0081f246eaa9bc - data: 542019-09-20 13:02:32 +020015470638115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.423425' - updated_at: '2021-05-31 14:24:27.423425' -footprint_debug_351: - id: 351 - footprint: f6fc678562339ce277e855f3e83ab624fc3d8ed36097323417dc460728b7efdc - data: 552019-09-20 13:02:32 +0200155Training reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.440020' - updated_at: '2021-05-31 14:24:27.440020' -footprint_debug_352: - id: 352 - footprint: e26264ccf8cb9d99b4cda6df9924a73af3f85889b48b63e5c1571e4c3590985b - data: 562019-09-20 13:02:32 +020015670648115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.458013' - updated_at: '2021-05-31 14:24:27.458013' -footprint_debug_353: - id: 353 - footprint: 8b59de6703a1c44be6016b465db5c62c0b879884c57d2abc467f0615240c1121 - data: 572019-09-20 13:02:32 +0200157Event reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.474546' - updated_at: '2021-05-31 14:24:27.474546' -footprint_debug_354: - id: 354 - footprint: bd46083a2bcc46ce9a417bb25354df0cb137822a426c0c9ca20705d61bce8457 - data: 582019-09-20 13:02:32 +020015870658115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.490153' - updated_at: '2021-05-31 14:24:27.490153' -footprint_debug_355: - id: 355 - footprint: 236ec67c6b4ff1272e3c4a6dbbdc12a900c9ca62e9f408beb51814587b1f88ea - data: 592019-09-20 13:02:32 +0200159Space reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.506828' - updated_at: '2021-05-31 14:24:27.506828' -footprint_debug_356: - id: 356 - footprint: 9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - data: |- - 602020-03-25 10:24:09 +0100160
-
-
News
-
-
-
-
Projects
-
-
-
Last tweet
-
Last members
-
-
-
-
-
Next events
-
-
-
6705cd67e864f65c5ed6c5e207a4d2267830b8ffb89a44f0a20ef02431342269 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.523676' - updated_at: '2021-05-31 14:24:27.523676' -footprint_debug_357: - id: 357 - footprint: 675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - data: 612020-05-22 17:22:08 +02001616073ebbb9d581850b5a82fcca49ce45e29c1d2c9813661f3079a14227c78f5b563 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.540466' - updated_at: '2021-05-31 14:24:27.540466' -footprint_debug_358: - id: 358 - footprint: 804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - data: 622020-06-01 13:12:21 +0200162true675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.557152' - updated_at: '2021-05-31 14:24:27.557152' -footprint_debug_359: - id: 359 - footprint: ff6251e103143d45bf911e444a1b084701d5f631389cf3cc855d228e245be390 - data: 632020-06-01 13:12:21 +0200163true675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.643167' - updated_at: '2021-05-31 14:24:27.643167' -footprint_debug_360: - id: 360 - footprint: 93d86a4c99b9a33304e9b39266d96d2d048badd537bd443b92b9cfd6f03548a7 - data: 642020-06-01 13:12:21 +0200164once675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.668871' - updated_at: '2021-05-31 14:24:27.668871' -footprint_debug_361: - id: 361 - footprint: 39b0af95095e06459166e6327f0a170698918f1b53aecbcb6960a599e9d6701d - data: 652020-06-01 13:12:21 +0200165noreply@fab-manager.com675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.690243' - updated_at: '2021-05-31 14:24:27.690243' -footprint_debug_362: - id: 362 - footprint: 87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - data: 662020-06-08 19:12:16 +0200166true804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.706977' - updated_at: '2021-05-31 14:24:27.706977' -footprint_debug_363: - id: 363 - footprint: da7ee4f56775d9127303cf3b6867aeb90a663e85d0b607ff1e3738f12c72d01e - data: 672020-06-08 19:12:16 +0200167pk_test_aScrMu3y4AocfCN5XLJjGzmQ804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.828839' - updated_at: '2021-05-31 14:24:27.828839' -footprint_debug_364: - id: 364 - footprint: 394d64c697b4025410eb7c60286badf50e76b54c461a5734a41b65bd0734ec08 - data: 682020-06-08 19:12:16 +0200168sk_test_mGokO9TGtrVxMOyK4yZiktBE804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.857123' - updated_at: '2021-05-31 14:24:27.857123' -footprint_debug_365: - id: 365 - footprint: 7e721af60be5ca521dcc21dd1f687062deabbf90e5adc14158872da3b4b58bbe - data: 692020-06-08 19:12:16 +0200169usd804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 14:24:27.885679' - updated_at: '2021-05-31 14:24:27.885679' -footprint_debug_366: - id: 366 - footprint: 6da5b0623d0f4cc091e09ffb0af687e5693103069783de400d14fa7afc0b40ba - data: 702020-06-15 12:04:06 +0200170FabManager_invoice87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - klass: HistoryValue - created_at: '2021-05-31 14:24:27.910556' - updated_at: '2021-05-31 14:24:27.910556' -footprint_debug_367: - id: 367 - footprint: 903b26f65fe1b3180dd0d8b29c2c59eb04e569c0f8140d5e0f28d90cf3a47fe3 - data: 712020-06-15 12:04:06 +0200171false87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - klass: HistoryValue - created_at: '2021-05-31 14:24:27.965789' - updated_at: '2021-05-31 14:24:27.965789' -footprint_debug_368: - id: 368 - footprint: 11da784cad45332300eb73c815c1d8d677835e5615eab8e8ad6ded065a2a8309 - data: 722020-06-15 12:04:06 +0200172true87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - klass: HistoryValue - created_at: '2021-05-31 14:24:27.982198' - updated_at: '2021-05-31 14:24:27.982198' -footprint_debug_369: - id: 369 - footprint: e6359c30093db9ba8aeee8e6ca0b248b2de626e3e3f9feb87a41eda483f2a320 - data: 732020-06-17 12:48:19 +0200173true6da5b0623d0f4cc091e09ffb0af687e5693103069783de400d14fa7afc0b40ba - klass: HistoryValue - created_at: '2021-05-31 14:24:27.999424' - updated_at: '2021-05-31 14:24:27.999424' -footprint_debug_370: - id: 370 - footprint: 6acf15ed45264b89f24f2ae69083cb15267b39999333d3ead5e47eb6bf43d2a8 - data: 742020-04-15 16:38:40 +0200174until_start9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.015476' - updated_at: '2021-05-31 14:24:28.015476' -footprint_debug_371: - id: 371 - footprint: 14acebf5826eeacbbdc909b6493cfa6d3c54eec353a3afb6d3464763ad825235 - data: 752020-04-15 16:38:40 +0200175FabManager_paymentSchedule9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.032407' - updated_at: '2021-05-31 14:24:28.032407' -footprint_debug_372: - id: 372 - footprint: 632ccda80572b2007a58348687c9c039c886fc546410b9d2ed42b88b67cc14d0 - data: 762020-04-15 16:38:40 +0200176true9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.057224' - updated_at: '2021-05-31 14:24:28.057224' -footprint_debug_373: - id: 373 - footprint: e20b25798f378ede57e81575f4e49a72381a02d7fb6704914e9eec4f2c4dc694 - data: 772020-04-15 16:38:40 +0200177false9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.073729' - updated_at: '2021-05-31 14:24:28.073729' -footprint_debug_374: - id: 374 - footprint: 5b41d5f35a871e35554b236ac7ea4257c104d18a33ae69e840fb5f4f60fe4907 - data: 782020-04-15 16:38:40 +0200178stripe9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.090489' - updated_at: '2021-05-31 14:24:28.090489' -footprint_debug_375: - id: 375 - footprint: 6bce8d94ae14b39a89f220d8c73f4daf44a795888ca011bf1a11da3a35eaf171 - data: 792020-04-15 16:38:40 +02001799f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.107155' - updated_at: '2021-05-31 14:24:28.107155' -footprint_debug_376: - id: 376 - footprint: b1b314da439b81e95281909992e79f4d118e08633607010f777d6ef40ad28d8e - data: 802020-04-15 16:38:40 +02001809f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.124089' - updated_at: '2021-05-31 14:24:28.124089' -footprint_debug_377: - id: 377 - footprint: 57dac418c605a111ab2a9c253704f9d9b182dfbb74068fc6596f3d20c611fb42 - data: 812020-04-15 16:38:40 +02001819f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.140649' - updated_at: '2021-05-31 14:24:28.140649' -footprint_debug_378: - id: 378 - footprint: 68a9d660f03f0e1408ee406ccf7df781147f3a7a2e5ac158a8d3ee4aaaca655a - data: 822020-04-15 16:38:40 +02001829f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.157278' - updated_at: '2021-05-31 14:24:28.157278' -footprint_debug_379: - id: 379 - footprint: 5a984dc2686c93d0380e04c017ce8ec05d18cb3c4c0fec8d4154605986078903 - data: 832020-04-15 16:38:40 +02001839f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.176823' - updated_at: '2021-05-31 14:24:28.176823' -footprint_debug_380: - id: 380 - footprint: bdf31d00b03e511c0a2a1bf18f628462655f32834b6ee6822d1a883055a191f4 - data: 842020-04-15 16:38:40 +02001849f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.198942' - updated_at: '2021-05-31 14:24:28.198942' -footprint_debug_381: - id: 381 - footprint: f67be79a6558146d67c1e14c7f7db4c248a2cb8effa7de41952dc3f92aa2bd8b - data: 852020-12-14 15:37:35 +0100110YYMMmmmX[/VL]R[/A]S[/E]e6359c30093db9ba8aeee8e6ca0b248b2de626e3e3f9feb87a41eda483f2a320 - klass: HistoryValue - created_at: '2021-05-31 14:24:28.215440' - updated_at: '2021-05-31 14:24:28.215440' -footprint_debug_435: - id: 435 - footprint: ab8e9b3ded4bed5ac11f14e5d794519877e4887ac2f1c7e609406cf06f29f553 - data: 432019-09-20 13:02:32 +0200143Client wallet8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.568624' - updated_at: '2021-05-31 15:00:36.568624' -footprint_debug_436: - id: 436 - footprint: 3fc58d50393f9d178200abe5adfd2df72e312dc91339985b1d94edcf17a1804d - data: 442019-09-20 13:02:32 +020014458038115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.584707' - updated_at: '2021-05-31 15:00:36.584707' -footprint_debug_437: - id: 437 - footprint: 76ec5b696c4537fd5af2d0906376479d56598b0f515d2c13397c7205c43b9793 - data: 452019-09-20 13:02:32 +0200145Client other8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.601951' - updated_at: '2021-05-31 15:00:36.601951' -footprint_debug_438: - id: 438 - footprint: 1dad73d081d3df136530a6f45833d645c6185dfe3190a724c8f6d0fed88704cc - data: 462019-09-20 13:02:32 +020014640918115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.684745' - updated_at: '2021-05-31 15:00:36.684745' -footprint_debug_439: - id: 439 - footprint: 3b55f0c50e8cd6728340ab6e146818ba800d4dd29aa5a6e95d5da2d984ebb377 - data: 472019-09-20 13:02:32 +0200147Wallet credit8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.702004' - updated_at: '2021-05-31 15:00:36.702004' -footprint_debug_440: - id: 440 - footprint: 3e10fbcf4fe7cf5eb112a1056865931bf46f24ac21da6313cb4400cb4b2dc391 - data: 482019-09-20 13:02:32 +02001484458115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.718198' - updated_at: '2021-05-31 15:00:36.718198' -footprint_debug_441: - id: 441 - footprint: 63a66401804d8a4fbf3177a4eb426623c15608af7f9b09e80e0bbed9b1e1e3b2 - data: 492019-09-20 13:02:32 +0200149VAT8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.736615' - updated_at: '2021-05-31 15:00:36.736615' -footprint_debug_442: - id: 442 - footprint: 89e852942f9b44775ee0c3b0e561c2d886b9dfc9ddb95b18c5a6137722d868e4 - data: 502019-09-20 13:02:32 +020015070618115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.759884' - updated_at: '2021-05-31 15:00:36.759884' -footprint_debug_443: - id: 443 - footprint: 169403ba2131226cf53b2c06ef2cef29570c22eb955bc263af6112d051f06617 - data: 512019-09-20 13:02:32 +0200151Subscription8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.855391' - updated_at: '2021-05-31 15:00:36.855391' -footprint_debug_444: - id: 444 - footprint: 9612c3c2b51c32d8827f03dbf76211f1595ca940b92837cad1ecde00c35543a6 - data: 522019-09-20 13:02:32 +020015270628115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.889041' - updated_at: '2021-05-31 15:00:36.889041' -footprint_debug_445: - id: 445 - footprint: 36dc3394e404aa37bb974a4c97945c6ba26a1721dbf12d269a48c7a94dc0490d - data: 532019-09-20 13:02:32 +0200153Machine reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.913407' - updated_at: '2021-05-31 15:00:36.913407' -footprint_debug_446: - id: 446 - footprint: 963edffba941ff733926b4cb6c5f439d9c348463fb4391bb6f0081f246eaa9bc - data: 542019-09-20 13:02:32 +020015470638115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.943488' - updated_at: '2021-05-31 15:00:36.943488' -footprint_debug_447: - id: 447 - footprint: f6fc678562339ce277e855f3e83ab624fc3d8ed36097323417dc460728b7efdc - data: 552019-09-20 13:02:32 +0200155Training reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.969389' - updated_at: '2021-05-31 15:00:36.969389' -footprint_debug_448: - id: 448 - footprint: e26264ccf8cb9d99b4cda6df9924a73af3f85889b48b63e5c1571e4c3590985b - data: 562019-09-20 13:02:32 +020015670648115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:36.985435' - updated_at: '2021-05-31 15:00:36.985435' -footprint_debug_449: - id: 449 - footprint: 8b59de6703a1c44be6016b465db5c62c0b879884c57d2abc467f0615240c1121 - data: 572019-09-20 13:02:32 +0200157Event reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.002017' - updated_at: '2021-05-31 15:00:37.002017' -footprint_debug_450: - id: 450 - footprint: bd46083a2bcc46ce9a417bb25354df0cb137822a426c0c9ca20705d61bce8457 - data: 582019-09-20 13:02:32 +020015870658115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.019481' - updated_at: '2021-05-31 15:00:37.019481' -footprint_debug_451: - id: 451 - footprint: 236ec67c6b4ff1272e3c4a6dbbdc12a900c9ca62e9f408beb51814587b1f88ea - data: 592019-09-20 13:02:32 +0200159Space reservation8115a13fd79788da96e1c55875b4e1e7971baa938ace50e81e4e1e4cee186a60 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.036719' - updated_at: '2021-05-31 15:00:37.036719' -footprint_debug_452: - id: 452 - footprint: 9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - data: |- - 602020-03-25 10:24:09 +0100160
-
-
News
-
-
-
-
Projects
-
-
-
Last tweet
-
Last members
-
-
-
-
-
Next events
-
-
-
6705cd67e864f65c5ed6c5e207a4d2267830b8ffb89a44f0a20ef02431342269 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.051646' - updated_at: '2021-05-31 15:00:37.051646' -footprint_debug_453: - id: 453 - footprint: 675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - data: 612020-05-22 17:22:08 +02001616073ebbb9d581850b5a82fcca49ce45e29c1d2c9813661f3079a14227c78f5b563 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.068544' - updated_at: '2021-05-31 15:00:37.068544' -footprint_debug_454: - id: 454 - footprint: 804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - data: 622020-06-01 13:12:21 +0200162true675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.084970' - updated_at: '2021-05-31 15:00:37.084970' -footprint_debug_455: - id: 455 - footprint: ff6251e103143d45bf911e444a1b084701d5f631389cf3cc855d228e245be390 - data: 632020-06-01 13:12:21 +0200163true675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.135036' - updated_at: '2021-05-31 15:00:37.135036' -footprint_debug_456: - id: 456 - footprint: 93d86a4c99b9a33304e9b39266d96d2d048badd537bd443b92b9cfd6f03548a7 - data: 642020-06-01 13:12:21 +0200164once675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.151679' - updated_at: '2021-05-31 15:00:37.151679' -footprint_debug_457: - id: 457 - footprint: 39b0af95095e06459166e6327f0a170698918f1b53aecbcb6960a599e9d6701d - data: 652020-06-01 13:12:21 +0200165noreply@fab-manager.com675605fecc999596202a2f531453f42dedb3254bb91bcde5e0cba9a0f800ee93 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.180740' - updated_at: '2021-05-31 15:00:37.180740' -footprint_debug_458: - id: 458 - footprint: 87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - data: 662020-06-08 19:12:16 +0200166true804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.201827' - updated_at: '2021-05-31 15:00:37.201827' -footprint_debug_459: - id: 459 - footprint: da7ee4f56775d9127303cf3b6867aeb90a663e85d0b607ff1e3738f12c72d01e - data: 672020-06-08 19:12:16 +0200167pk_test_aScrMu3y4AocfCN5XLJjGzmQ804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.264447' - updated_at: '2021-05-31 15:00:37.264447' -footprint_debug_460: - id: 460 - footprint: 394d64c697b4025410eb7c60286badf50e76b54c461a5734a41b65bd0734ec08 - data: 682020-06-08 19:12:16 +0200168sk_test_mGokO9TGtrVxMOyK4yZiktBE804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.295151' - updated_at: '2021-05-31 15:00:37.295151' -footprint_debug_461: - id: 461 - footprint: 7e721af60be5ca521dcc21dd1f687062deabbf90e5adc14158872da3b4b58bbe - data: 692020-06-08 19:12:16 +0200169usd804c83233f933d0928a67958a3a9fc8bacc435b46eabd9d755016132b86f2ff2 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.310071' - updated_at: '2021-05-31 15:00:37.310071' -footprint_debug_462: - id: 462 - footprint: 6da5b0623d0f4cc091e09ffb0af687e5693103069783de400d14fa7afc0b40ba - data: 702020-06-15 12:04:06 +0200170FabManager_invoice87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - klass: HistoryValue - created_at: '2021-05-31 15:00:37.330672' - updated_at: '2021-05-31 15:00:37.330672' -footprint_debug_463: - id: 463 - footprint: 903b26f65fe1b3180dd0d8b29c2c59eb04e569c0f8140d5e0f28d90cf3a47fe3 - data: 712020-06-15 12:04:06 +0200171false87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - klass: HistoryValue - created_at: '2021-05-31 15:00:37.351900' - updated_at: '2021-05-31 15:00:37.351900' -footprint_debug_464: - id: 464 - footprint: 11da784cad45332300eb73c815c1d8d677835e5615eab8e8ad6ded065a2a8309 - data: 722020-06-15 12:04:06 +0200172true87f5dd83a6559d9e1ed8650342ce20bebe1c33bb51ed10098425316ec96e1efc - klass: HistoryValue - created_at: '2021-05-31 15:00:37.380529' - updated_at: '2021-05-31 15:00:37.380529' -footprint_debug_465: - id: 465 - footprint: e6359c30093db9ba8aeee8e6ca0b248b2de626e3e3f9feb87a41eda483f2a320 - data: 732020-06-17 12:48:19 +0200173true6da5b0623d0f4cc091e09ffb0af687e5693103069783de400d14fa7afc0b40ba - klass: HistoryValue - created_at: '2021-05-31 15:00:37.401823' - updated_at: '2021-05-31 15:00:37.401823' -footprint_debug_466: - id: 466 - footprint: 6acf15ed45264b89f24f2ae69083cb15267b39999333d3ead5e47eb6bf43d2a8 - data: 742020-04-15 16:38:40 +0200174until_start9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.418354' - updated_at: '2021-05-31 15:00:37.418354' -footprint_debug_467: - id: 467 - footprint: 14acebf5826eeacbbdc909b6493cfa6d3c54eec353a3afb6d3464763ad825235 - data: 752020-04-15 16:38:40 +0200175FabManager_paymentSchedule9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.435897' - updated_at: '2021-05-31 15:00:37.435897' -footprint_debug_468: - id: 468 - footprint: 632ccda80572b2007a58348687c9c039c886fc546410b9d2ed42b88b67cc14d0 - data: 762020-04-15 16:38:40 +0200176true9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.451714' - updated_at: '2021-05-31 15:00:37.451714' -footprint_debug_469: - id: 469 - footprint: e20b25798f378ede57e81575f4e49a72381a02d7fb6704914e9eec4f2c4dc694 - data: 772020-04-15 16:38:40 +0200177false9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.468418' - updated_at: '2021-05-31 15:00:37.468418' -footprint_debug_470: - id: 470 - footprint: 5b41d5f35a871e35554b236ac7ea4257c104d18a33ae69e840fb5f4f60fe4907 - data: 782020-04-15 16:38:40 +0200178stripe9f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.487299' - updated_at: '2021-05-31 15:00:37.487299' -footprint_debug_471: - id: 471 - footprint: 6bce8d94ae14b39a89f220d8c73f4daf44a795888ca011bf1a11da3a35eaf171 - data: 792020-04-15 16:38:40 +02001799f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.510634' - updated_at: '2021-05-31 15:00:37.510634' -footprint_debug_472: - id: 472 - footprint: b1b314da439b81e95281909992e79f4d118e08633607010f777d6ef40ad28d8e - data: 802020-04-15 16:38:40 +02001809f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.526848' - updated_at: '2021-05-31 15:00:37.526848' -footprint_debug_473: - id: 473 - footprint: 57dac418c605a111ab2a9c253704f9d9b182dfbb74068fc6596f3d20c611fb42 - data: 812020-04-15 16:38:40 +02001819f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.543567' - updated_at: '2021-05-31 15:00:37.543567' -footprint_debug_474: - id: 474 - footprint: 68a9d660f03f0e1408ee406ccf7df781147f3a7a2e5ac158a8d3ee4aaaca655a - data: 822020-04-15 16:38:40 +02001829f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.559976' - updated_at: '2021-05-31 15:00:37.559976' -footprint_debug_475: - id: 475 - footprint: 5a984dc2686c93d0380e04c017ce8ec05d18cb3c4c0fec8d4154605986078903 - data: 832020-04-15 16:38:40 +02001839f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.578919' - updated_at: '2021-05-31 15:00:37.578919' -footprint_debug_476: - id: 476 - footprint: bdf31d00b03e511c0a2a1bf18f628462655f32834b6ee6822d1a883055a191f4 - data: 842020-04-15 16:38:40 +02001849f5d5d9c0fc4bb54cebf6928821ef5e63b5151d9a65810314ac1ad665ed35d92 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.601794' - updated_at: '2021-05-31 15:00:37.601794' -footprint_debug_477: - id: 477 - footprint: f67be79a6558146d67c1e14c7f7db4c248a2cb8effa7de41952dc3f92aa2bd8b - data: 852020-12-14 15:37:35 +0100110YYMMmmmX[/VL]R[/A]S[/E]e6359c30093db9ba8aeee8e6ca0b248b2de626e3e3f9feb87a41eda483f2a320 - klass: HistoryValue - created_at: '2021-05-31 15:00:37.620756' - updated_at: '2021-05-31 15:00:37.620756' diff --git a/test/fixtures/history_values.yml b/test/fixtures/history_values.yml index ea541c3d5..eadf4f7ba 100644 --- a/test/fixtures/history_values.yml +++ b/test/fixtures/history_values.yml @@ -15,7 +15,6 @@ history_value_1: des Fab-managers.

' created_at: '2018-12-17 11:23:01.224566' updated_at: '2021-05-31 15:00:35.658406' - footprint: fcc5700c917a25e79d5bb04b90531be52473b48cbe1e00009d412db88c9fc278 invoicing_profile_id: 1 history_value_2: @@ -24,7 +23,6 @@ history_value_2: value: Imaginer, Fabriquer,
Partager au Fab Lab
de La Casemate created_at: '2018-12-17 11:23:01.565164' updated_at: '2021-05-31 15:00:35.684113' - footprint: d2af67ae4b2bc30bb76867c5071405abade0657bee94a96f09f1129a6238d147 invoicing_profile_id: 1 history_value_3: @@ -36,7 +34,6 @@ history_value_3:

Visitez le site de Fab-manager

created_at: '2018-12-17 11:23:01.569316' updated_at: '2021-05-31 15:00:35.700825' - footprint: 33c39abf9e852b7f31d509d5cda12fe401160436a0b684fbbd8939320ac79159 invoicing_profile_id: 1 history_value_4: @@ -45,7 +42,6 @@ history_value_4: value: fab_manager created_at: '2018-12-17 11:23:01.572468' updated_at: '2021-05-31 15:00:35.718150' - footprint: 18bd852ed1070b3305fd2f45ae68688ffc8391b555778949dbf717aaee8f90dd invoicing_profile_id: 1 history_value_5: @@ -57,7 +53,6 @@ history_value_5: Passé ce délais, aucun changement ne pourra être effectué. created_at: '2018-12-17 11:23:01.569316' updated_at: '2021-05-31 15:00:35.734666' - footprint: 92120f18756df89476a3413456acc41a8bc2f169112f6e80b493d2daa1317b54 invoicing_profile_id: 1 history_value_6: @@ -69,7 +64,6 @@ history_value_6: proposé. Passé ce délais, aucun changement ne pourra être effectué. created_at: '2018-12-17 11:23:01.569316' updated_at: '2021-05-31 15:00:35.750798' - footprint: aacaa245eb491bebb1768902f708c3397efca9f4db1adbf2e90a42a16831e986 invoicing_profile_id: 1 history_value_7: @@ -85,7 +79,6 @@ history_value_7: L''équipe du Fab Lab.

' created_at: '2018-12-17 11:23:01.588478' updated_at: '2021-05-31 15:00:35.767955' - footprint: 5f680f87a44d7cf1f7cfedfcf235b0a99e44e30ab2cb413372366d8cab4d3d5e invoicing_profile_id: 1 history_value_9: @@ -94,7 +87,6 @@ history_value_9: value: iVBORw0KGgoAAAANSUhEUgAAAG0AAABZCAYAAAA0E6rtAAAACXBIWXMAAAsTAAALEwEAmpwYAAA57WlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxMzggNzkuMTU5ODI0LCAyMDE2LzA5LzE0LTAxOjA5OjAxICAgICAgICAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgICAgICAgICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgICAgICAgICB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgICAgICAgICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIj4KICAgICAgICAgPHhtcDpDcmVhdG9yVG9vbD5BZG9iZSBQaG90b3Nob3AgQ0MgMjAxNyAoV2luZG93cyk8L3htcDpDcmVhdG9yVG9vbD4KICAgICAgICAgPHhtcDpDcmVhdGVEYXRlPjIwMTctMDEtMDNUMTE6MTg6MTgrMDE6MDA8L3htcDpDcmVhdGVEYXRlPgogICAgICAgICA8eG1wOk1vZGlmeURhdGU+MjAxNy0wNi0wNlQxNTo1NjoxMiswMjowMDwveG1wOk1vZGlmeURhdGU+CiAgICAgICAgIDx4bXA6TWV0YWRhdGFEYXRlPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3htcDpNZXRhZGF0YURhdGU+CiAgICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2UvcG5nPC9kYzpmb3JtYXQ+CiAgICAgICAgIDxwaG90b3Nob3A6Q29sb3JNb2RlPjM8L3Bob3Rvc2hvcDpDb2xvck1vZGU+CiAgICAgICAgIDx4bXBNTTpJbnN0YW5jZUlEPnhtcC5paWQ6MmYwMTE5MTMtODI5NS0zOTQ0LWJmZjYtMTY5ZTNhZTQ5OThlPC94bXBNTTpJbnN0YW5jZUlEPgogICAgICAgICA8eG1wTU06RG9jdW1lbnRJRD5hZG9iZTpkb2NpZDpwaG90b3Nob3A6ZGU3ZGE1MmYtNGFiZi0xMWU3LTljODAtYWJjY2ZlM2JkNzdmPC94bXBNTTpEb2N1bWVudElEPgogICAgICAgICA8eG1wTU06T3JpZ2luYWxEb2N1bWVudElEPnhtcC5kaWQ6YTE5NTAzOTAtOGQwOS0zMzQ3LWFkNGQtMzkyNDQ2YjRiNWJiPC94bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ+CiAgICAgICAgIDx4bXBNTTpIaXN0b3J5PgogICAgICAgICAgICA8cmRmOlNlcT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+Y3JlYXRlZDwvc3RFdnQ6YWN0aW9uPgogICAgICAgICAgICAgICAgICA8c3RFdnQ6aW5zdGFuY2VJRD54bXAuaWlkOmExOTUwMzkwLThkMDktMzM0Ny1hZDRkLTM5MjQ0NmI0YjViYjwvc3RFdnQ6aW5zdGFuY2VJRD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OndoZW4+MjAxNy0wMS0wM1QxMToxODoxOCswMTowMDwvc3RFdnQ6d2hlbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OnNvZnR3YXJlQWdlbnQ+QWRvYmUgUGhvdG9zaG9wIENDIDIwMTcgKFdpbmRvd3MpPC9zdEV2dDpzb2Z0d2FyZUFnZW50PgogICAgICAgICAgICAgICA8L3JkZjpsaT4KICAgICAgICAgICAgICAgPHJkZjpsaSByZGY6cGFyc2VUeXBlPSJSZXNvdXJjZSI+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDphY3Rpb24+c2F2ZWQ8L3N0RXZ0OmFjdGlvbj4KICAgICAgICAgICAgICAgICAgPHN0RXZ0Omluc3RhbmNlSUQ+eG1wLmlpZDoyZjAxMTkxMy04Mjk1LTM5NDQtYmZmNi0xNjllM2FlNDk5OGU8L3N0RXZ0Omluc3RhbmNlSUQ+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDp3aGVuPjIwMTctMDYtMDZUMTU6NTY6MTIrMDI6MDA8L3N0RXZ0OndoZW4+CiAgICAgICAgICAgICAgICAgIDxzdEV2dDpzb2Z0d2FyZUFnZW50PkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKTwvc3RFdnQ6c29mdHdhcmVBZ2VudD4KICAgICAgICAgICAgICAgICAgPHN0RXZ0OmNoYW5nZWQ+Lzwvc3RFdnQ6Y2hhbmdlZD4KICAgICAgICAgICAgICAgPC9yZGY6bGk+CiAgICAgICAgICAgIDwvcmRmOlNlcT4KICAgICAgICAgPC94bXBNTTpIaXN0b3J5PgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpYUmVzb2x1dGlvbj43MjAwMDAvMTAwMDA8L3RpZmY6WFJlc29sdXRpb24+CiAgICAgICAgIDx0aWZmOllSZXNvbHV0aW9uPjcyMDAwMC8xMDAwMDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPHRpZmY6UmVzb2x1dGlvblVuaXQ+MjwvdGlmZjpSZXNvbHV0aW9uVW5pdD4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT42NTUzNTwvZXhpZjpDb2xvclNwYWNlPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTA5PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjg5PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgCjw/eHBhY2tldCBlbmQ9InciPz7jSvdMAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAACL8SURBVHja7J15nB5Ftfe/VdXLsy8zk5lM9hASsrDKImgiuyCL7ILgq4KKu9flivuCiKjoFeWqCCoKQpTLIsiOrBqI5Bo2IQsJ2ZPJZPZn7ae7q94/+kkyQzIhExKSwVufT08mz3RX91Onzjm/86tTp4Vh+9oKYCFQA/YlThaHB+jlBmxuIcdyesmQQVAixELjYOPRSo25KDoJMdQ4mjTLKNFInBUENOGzEoc4vphEYnwVe4KNPdmgJoMeKxAjDSYnEAnABgSgo0cxZQNdINYJ9CqfcJmAxQaWpulZW0GZEI9RJHgcRYDmEKCIxQbKOLhoYF9COrDoJsQGRpNhPj20U+Xs+g0Ha712jKXpRhwdsrObhcAIQ61apeZ7xJXiQa+IxRvQNo5yWP/dABpDI8nRAn/mQcTfHmJN82GqTTjGECLw61fp+tn9ezObfhcIQAIKGwlIA2JlmRELfbz5LvajFeSTEJR0/ezh3qw3QmA1DApDDIFGjsnSOFMgjs/iHA/B2Co1DB4QIgDhOsjGHCqbRyQzyKYUoiEGjgVKQqjBCzBdFXRHCV3uRff1YDp60V5FAOMlanwM6wRD+kt98MxEggcM4pEqxblgSgEG+/+EtvUWYEigaMbZL0fiPQXEOQ5iH6gR0IfARubSqGlNWJP2wZk+HWvGOKzRLagRo5DZEchUGlSsrlEbm4awgi4VCHs7CNvbCFevI1i4Ev/FBfgvLyRc1AHdRWkIDk5iHSywLwlIPyHRs9OEd4Nsq9Qnyv8JDRAYAiRdJGaOJf4xkCeFeHlDDYRCjmoh/tYZuMcdQezQI7D2HovKtQDudt5BgkoiM0lkZiT22H3hYOA0AI+wux1/6XJq85/Ge+gf+P94kWDdOssEwTEK65gmsotq6D/a+L8PKS4zmH93oQkE4jBJ8uIa6mxFNaspI5wksbcfSuykY3CPOgJ3/0MRTnoX3N9F5ceiDhlL7JBZmA+WqS2aT23OfKoPPob3xP8SdHbto1DfypA6uwP1q4DwJkGpSw/Q5je50Mymn3arwP2YwP64xB9h6IV0lsQJx5M4+1RiJ5yIyo1+Q7+kcBK4+83E3W8myQs/iDdvDuU7/oJ359/xly6fYVA/s4m9O0bsexA+atD/HkKTCAycKkhfKggPgh6MZRM76ShSn7yQ+DEnIqzUbv/C0s0Qn/ku4jPfhf+J5yjdfAvl39+Jv/SV42ycQxXJHxjCnwSYavhmFppANKTJfUUgPwrVNBRxDtqX9Fc/TuKkM5CJhj3yy9uTDiD3jf1JnnsWpRtnU7zu1my4fv33KqQOzGB/thtvXfhGoLUhNvXt7TyxF+iox1rN2CgUVTzGkZoxntj1BnGBps9V2RiZL15E/r9/TOzQYxB2fA/3EALV2ErsmHfiHn8IplKg8vyiGSn0kXncuY3U2rfl5Txl0e0mUGbnAxmJAAFhEBDqEFtKloY1xI4yIhYumvCoEWR/1Y4/Bbpx9p1K/spvEj/xrGEbuBpdpfw/f6D30p/AgsWLIPFegXxGI9HKEE6OU7MCTBAgAoHZIKkJK3IObxAjskNQSeMjiJ8myNzVSW2KoJvE2Scw4sFbhrXAAISMkTz3w7Q8fhfOOafuU6Z0bwU9xcOmImwqCYdSyqGYcigmHTxpIcwbGy4MSWhhHR9Kkh80iFsExbShRObLn6LpltnYrfvwZmlqxCSabrmdkX/4r5FWxvzF0DFNoVGhxvLrR6CR5o2P7+RQBGYBY8mdHyN7vaHqGAHZy/+D/BVXIEWSN2NLXfAZmu/5w5TYhL2vC4OOFnwNYvdyKEMS2jhyZ7SQusGniHENuau/QvarlwMOb+YWm/luRj5229uzp59wDZWiFRaKaM+L7M5uEKD6Gv259C2PiJASeOSOtkjdEFJMQUj+qq+Q+dSX+HdpMtdM6pQTp1LodorPPfOwPXok0tiYDVWEkOwKAnNQ9PivbTAcCkGKJAHuZIV7hyCYoSmT+95nyX7lO/CmWOgYIgjrai/odUvfW3nuX/es/NS3CMsVZDy2i4LoQdbTzDaEFkawI6lwrxaEMzS9ZD73IbJfuYx/1yYbmpOmpprXfvVj+N2dWA2NoHcxGDED6WxLDs5yILHQxL4i4YSQLhJnHkfuh1fsqifDX72U2spX0NUyQu6BxK0UiESy1nPzbftUVjx/pJMbmzIm2NUWxxdKrreMtcRgSgYQSwbRMos4FvmTQ8QfoCdnHziREbfPxp64705/qtqaJXRefTWV+/9B2N0LYW23I7Stz2SBCUKjC9WSULKG2uX+QRhDKISpSOQC41X+685y1/1i8Vbva7BIjlTk74Dq4SJpaJz9MxKnnr/zp9GGlaz9wMUU7nsUiYtw3T3aVwoAx0I4kjd6CU4JWerwq+dZFTKvYjsMNgKX+MUQHG4okfrURbtEYAB9f76N4n1zUHYamYkzYCRej+wMr68fM4jENqaomNfoV2ylv9cp5MDo5EjLvcSyBtzHINAo4ocJ5Ec03TgHTiPzuc/vstkTrFqFEDYi4cBGdkEAAYR9JRiyzzAI6SKzMbAE1DS6t4LB385+DEI50QSS/QZaCkw5RJfLbE5R2s7nQYDlIJIOwtpxDRVA1egJVhp/0wchggCJjbrIEIwRlkvqSx/Hatlr1+m8bcOrQIephsikQ8Pn3os9ZgymUt1un4NjUZk3n/K9T2LKIDMxcp84HWevvTA1f/PEGOR64SjKT/2T4v3zEI5A1H2rKdawxjWQOe88VKYR43mDDq0xGlOrEvb14Le3E7zchr9gFUFvB9LNIlOxbT/Ha3gUayzlTf/rxaGN/CwXeXZIH/FTjyHx7tPfAGv9KpNYDRCNSRo++0mcsTOG3Fv3LddS/MsTaK+GlWim4Qufwd3rwO2+3rn/dor3zIMgjDLAtEFXa6jRjTR+8Quo1FBW3jVhqQdvwbMU7ryT7qtuRXcWkI2pHdY46UNd16IRU6iLNbVGmUqTvvgDqETT7nH3xmBK3g7CUVMfkACZTSAT+aEp/9ixqKwLFT3QP4UGM+RMBIlKNpA45BhaLvspY/7831gjmwg7SzuMkKVTZw5HAz0k9k/C8YYSsVPeRuydJw/PCNiYekCqUePzqHzj0JiI1mbU6Aw60FtahNfJ6qeOPYPmn38LmXTR5doOgST5QVKcS5KzSAHue0K8FmGniJ95GkLGGbbNENEDrQ1Id2g0k0ynsEa1RIBjFyy9ZM98D+kzj0FXylHi7VCF9i08vo/HZcTHS9RpITXcd+xP/Jhjhq28hGWB0Qgs7JZWhprlIe089qgJGMIdoKi253yX5CnHI6RAe0NPH5LLkaxE0Ik+XKL3FShi7zoW1Th2eKgTQb8jmrUmrGG0Bhys1h35HhJr1KhI04YotMI9f2Ltpy+m+MS92zwvtv8UrLEtmFow5Kez3o6giyRFnONCaqhxrbhHHjYsNKo8/3G6r7kWQT3HXwiEpfBeXooUNiQdrFE7lmNpj21EYDCBQQxBUUvz/sb6/76O8kOPM/7hydijJ2+9/9bx2A3NBCvWA0NzQ5ZNFRvVDMmjwMc+eCrufocMC6H5y1+m+7pbEFiR4DYGs3YMEUpUc6Lum7amowYqRVAWwtly0KwxLRBzMaEZElZQiTQ2ktqiDryXFg4qNJHOI7PpTdZhSEJbDxRxDncIJxlsYkcfinCzw8N3SRclsoikQiirP0mH7q4iGzKohtzWLw41tVULUblmrObxWw7MqBasxhxBW9+QfOJG3CKVA54/uAGWDiLnbERMQ4rZZBoLgTvTUBMym8I55G3DCHEIEDIyjf0PEbESVtMIVHqQvQKhj7fkecLezkHM11hUfgSEwet7vm3GojsYpy1B4MB0Q4ic0oi115hhBhWJOMJXH2hUtgGZ2HoqutEa75VFhIXurZugxjFYo0dgCIb+PPV/RWzwUMNoD9PjsSOBmowTHxPCFIHG2XsKVkvL8AnFwiph2EvY3UfY0UfY0YvuKNWZDIPM5hCxxNYvDgJqS1YQ9vYMRmZh792MQA/JdulKkRANeY01tnXQ84INqwg6NkSmd4hRhaVx9pKYyQaNPX06kBo2QnMmTiH/sXMQSFAKYSmCnh6qDz1LWOzBGjcCYW09tU8XCtReakMfVRgcQU6sx3hDCLDdyVPIHHcImXPPw52y/6DnVebNx1vyCiLmDvl7Wy5MNmiIuVgzxg0ryxg/6EhG//LIAZ95K55n9bMfwKxdgzWmedBrw+4NhGs60cXBVxDsMeMR0sEMIVbLn/8pcud/EoEaHPWuep7OS68GD2R+6Ns7LIE1CXxUYx61DXUeNi0UmFqIVAmsEYMTxUHXOsKuTvQ2SGmroRUh7aFBuyjxbWu6TfX5x+m+4Qb6fv8QYUcB1Zip85lD9GkCMRZCZDaP1Txq+AvNGEwYoNJZrOZt+ZR1BB3d6J6+wYU2ajQiaUN1Z/CPBl0pEXR1oSv1BdkdzOKSQItBIxJpZLaJN0ULfGQ6g9U4cnCF7OpGBx5h2+BCs8eNxhqXwXh6J6StKBJvPYWxv72TiU/fQeygqQTdxR0ipCWYHBhkPolIpIa/wCwbbJBjsqjGEYMLrVCK6pl0dhNt4NpaEJtBjWseEuwPC52EPavraRKD8I7T30brr3+APTJP2FvdIU1LAIjGGMKODSv5aK9E0LGaoGstQddadLWXYP0ajPaxxzUiM4MzO2FvoY4iu9F+aZCQK4EzYWI9v2T7Wu+t17PypLNo/+F3MbXBkWn8LUeSOvNoTFhlqE7NAhEDEDEbtoF49sRWnvswG778faRtRZBfSoK+AuGaEvZZYxFi8I0h4SvrolpN61ahC33Ihq2DFnfCZAwewmwfNK+tXkXfU09TeWYRqeOOJXHwrMEFd/hB9F5zJxgNQg1FaHVJKclwy80PO9dTmvt0P8I4ylMTMoHdOmob36eGsAQ2MUTOxlRqgw/Q1Imb+t2e4ZFuHIVCeDF0W8c2z7VbxiBsB2PMkDIPLKJ8sF2fj74rGCwVQ4k8Ir2ZMDYVD7BQmYZtUEiShku+SPYjFyESCVR+cJTpTBiNSibQpe30ayb6IdRrs8DCjYOREIaR6pjtFpqpgcFU/br81DCT3MDDhBqZsLBGDI6EhbSI7bP/9g1QcxPWyBaqS1cN/cFeaz+C3LEtUhIogcB0VjB+ZZjHaECgkQ1x1OiRO6VLlW/CbmzGUNuhmHGXAGSQXQKB7ipiSn2I3PCG/cYYZFMG2ZjfKf1JuxHV0Dj0FEVtQOvtsxQYjOdvaR6FQNhqiyUeaTBtIDH1am7DX9XAampCpXZWzS2J2qfOFG1HDo4QUTXLUJchvj1pBCIKE6s+eB54teio1jAVDxNuucfbAr0SFLq3G92+DsbvP9xlhtU4EpV+rdX3GuDVPUScbW0/t/ceHS0uB6+tOUGhBx/IHjWN2MFveQ34G2CqNexpeUZ89zOoZH5TurlwHfz2drp+dBP+whWI1OaQw5LoZQZB2N1LsKYN99BhKjABhAaBwR41EmFtS9NC2r/2DQqz78Ea10rTd79Mcuaxg57tjh2NwsaEr61quXe/l/gBh5A69l1YuW37VV0ro6mhGjOkTz0faQ806brSS99vH6ZWW4LoV1JRhuilIKHiESxYNbyNY2jAsVATm7d9Xq1Aae4c+pa9SOHxv1F7+ZVtx1Nj9kKS2a7Ug/ihR5E7+yNY+dfOAAg71gFBpMFbCbl0TxfGq2wRb0qbYLlBLjMI/IULgWGMIEODSMewWradBh5WC1AOcEhgJXLgl7eN1lonIFsymNeTL7KVVnn2JTSVwUMDIbaaZyI3UF4hYbFA4i9eTNCxfhgjR42Mx5CZbYMQXSyie3sQ2JggJOjr2bbQmpqxJzXCTqwDWXvlOUp3/Q2BM+RQTU5CU8EsAEW4uJ1g2Z5gIuvbLG33NRgRNXAiao1KZbBGtLyGeQwI+qL6yegQXShs+z5OEmevcdHmffH6N/CHpfW0X3oFtUUrkMSjPrcmOcup04sDTaelCYnh/x2cz+quIrWnnyJ26KzdDioMBl3qBHzC0paaIJNZwkpfXbxis3lMJBGuwphSfdfmwI5VMk/QthJT9BDKRuuQsHMDobceoRIY71VLJVIhbFBNjRijCUsdqEwTutT72hNPa0wQYmo1dM1Dd/ZQfWY+vbNvo/zos8hsGtPrY3RAWOpE2HF0uRjdNpFAFzfU/ejAiWL9BZiCN2c8saVV/EnVv84l/aFeRCy725RMJGxMxaf9a9/HyuejwHNAMArCtqitWIWI2wgZfShTDkHHBtq//H1UPD4Q7W0q328RtK0HbSNSCqldyg/PZ90HPgVSsWkDmu7nV6TAW7CEcH2J9k9/AxlLYvxgcI6pzi+bMMT4NUylTNhXIGzvJVjbhfE8VDYFjkIkIVjZTdvFlyDt2KZnFpYiLJXwV61GpAdaHCtBDB+7zYdHJPYk/58v4T03j9hbj9t9mmZL8DWle56sLyaqfghKbxoVYcWQ2XidUQijPRidvZTueqK+AaN+mTH9rosyk2UuAcIgqgJ/URu1hSuJygRsTAPffE8BEHMRCAq3PcLGoh1b8Zb1Y2Pypd4sSSEQMtprIGLxaOMjISQUus+jcOtjRF9gI5GqAYVMJxCuNQBdytMQHEIFg/+QxiVc1Yb3xNO736UpkLk4Mp2MvrAQUSFMqVC5JDIWxwQ+ulAl7OyDqo9wBbpSw2iDyidRDal6ERmDTCdRzVmEFcPoWn23igBHQCzafSMtB7slH2kBINMxrOY0uDamWsaYANWYQsZigEbGHVRTCpVPRkNtWch8GmEpIKgvGTmoXBLVlAIp0F4t2sDvgu4toTuLCEchU7E6KImWmGTMjfq15RbhgKWooIBWvLlrsV4w6P2q9z1M6sL3oZp2T0qdCTWmBo1ffB+pE4+jcO9f6fn1zdijR5K78HycGTPQxQK9N95M3y33k3nPiWTOPhNrZAvewkX0XHcz3rxFgMFqaSD7kbNIHPkORDZNsGIVfTffQuGORxGkaPz2R3An7EPxgfuIH3gQsbcehi6X6P3NDRRuepCwFC2bZC86jfQpJ6OamwnWt1G47S6Ktz8G5YCwXME9YC/yn76I2L77UfnH01Tm/4PUrOMJyxW6f3493qLF2M2t5D52LolZMxGOTfWZZ+j6xfXUFi8jMetwGj56IUF7O96SF0keeTS15a/Q9aPfYSoBwlWb8cjFwPuBS5Aso+WyVTSaFdYIU/jT9eaNaG3fucS8qBrMgmyrWdgw2ixsGG0WZFrMS26r6b3jZmOMMTr0THHuA6a67MUB1/qda03PX24wYblnwOeVF+aaxXtNM4vG7GUKj9+9xT21qZpVHzjPvOgkTe+9s+ufhgPPCQpm+QknmBfAdPzqB1v2oaum7VtfMC+SMC9Pnm7K/3py4N9DzxhjTFBoN0v2P8QscBpM7103bdFP+aW/mZdSObPi9FP7PZ9vjDGm957ZZkHDKLMg0WIWNtbHJj9qqbwWuAH4AxqDd6vEXW+CEpU77sLoym4EkGYzDycdkm99J+6E6QPNREMr2VP+HzI+EDTF9j2U2BHTSZ04k9Q7TgRgw/e+w8rz3k3QvhKBS8MnPow1Kk/YU+yHIPqHEyncQ6YSP3Bf8hd/CIDCPXew+sLzqMz7O0K4ZM46G2v8SHIfOpf4jCMA6P3z72m/8kuE3Z11VqOECTyyn76AzKnno70KHVddTvsVX0WXC8SnzST3yfcSdm/Y7BmrFbyXn6E8Z25k9tWr0OPGVSIbKFJ5rp3EXy3iF1TvfYrqw/cSP37PqElsdEDxgTsxlQqpk05HxiK/o8s99Mz+He4+00nOfOfmdbCmPKVbH2fFqccjx0q8p9bir15LbfkSrOZxWA2tqFQefL/eTx+9N96ASMfJnnM+wo7jjBlF39oS6z7wccj71J5dgvfMchJvfxvxQ2ci3RzutCm4hx0IgLfiGdZ9+At4nZ1YmVE0fPQ/wNdYTXlih0VEvL/iJYp/foCgdx2Zs84hNuUgEoe/BX/B8k0gputHP2LDN36CdJJRUZxXhWpW/zcbRXgpvFbgvkv39TQUrr0RZ9bRqNjur6vvL3mBdR/7AkZUmXjAATiT9gOg9Mj9rPjw5xhx8Xn9hGYgCPHXrSd58nFkLziT+E9mINwEwkS5/cb3Iwdfj86rzz7Nus99HXf6GFJHH4XVOgkcG699Bc7aKTSccSHuJftitzYjdKLeRw3pJlDJSNNrS14h7OzBQrKxDrvRGpXJYzdGfKiz9wFMePTBepAejb7Kj0Am6wVhhCFY04mhiointpqGYK2pbx2NQKZAUHrCkLxdkvxw9a4nqNxzF6mzPrjbhabDABlkMckYRg7kGyWgYukBdJbWJRq/fiEtl14V8Xxz51L913OkTj4Ru3X8wLUcAMug3AaUk4vQHRC2ryd19BGMf+g2BEn8dWsp/Plx3GlTiU3dd3OVcLHpxph62DCQp9x8n6B7A7VFi6M4zitjAijNfaKO9KNUD5Fyog1ocuslmaxyv3gjihA0IcHvbNxTTK04svCDXxI78lispt27cV4ohbAkRkqQ/TgfR/WPpqIhqgaopgSxww+KzNaSf7LqrHOorl3N5PmPR0Izr2LWpYpKKgm5SfuMXSVx4iEIkmivm7UfeT999zzM6F9fRWzqviAVulwiLEZZys6kvbAbRlHrWoNKJ+vPLQl7ewna26PJt2EVbZ/6JNVnFiHTaax9svgvtpM++YStyXjr8bvZHMCj69GFpjbHEP5GkKU273kKV/9096xnqn5JRsqKCCshELLfRNv4ez+mXNgWxtforohqslv3pvm/LmfSk38lftA76jRYBhx7E/4Qth3Fg0oibGcj6YUp1muHOVlyF32QcTf/htz7ImCicjnCzm4qf38qWneb+BbG3P5bxv3pt2TOOK8OFgRhZzelx54CDO7Uwxh1zXWM/NkVjP79dUx66lnSZ59C0N3Vb4Ja25ScTFKk/5GiRJICFoVrwJovSFK86kYqD9z2xquXEgPM1yYqyurHtjuy3/RjEwVkSgF9f7qH2urFyGSW3Lnvx5kwmcqzj0WnN2Sx9s5BGCFUHUSZvsZodFDZNDqF/3mY2pqXEEKSPfN9pM8+h6BtKRCiRo3A2ruVnl/MpvjQXwBIHvlOsud8AFnffC8sCcqh77e30fWbn2IIiB92BI2f/k8yZ5yFtLLInI1w+1kKodlWmpYlB5GoJFwdoC+H2A2mrzvZ/c3vYU2fjj122s52VltMKiElQkHxrnsI17eBBn/NKnSlAEFI9zW/xm4ehXAdKvOfQZHAe3YBXb+4EnRUR6T2wkoqj73Amr6LSZ04C5lK0XfbA4QdbSSPextGC4J1PfTedDve84uorVqFoYa/uo31l3wNK99A9fkF+AvXsPqci8icfzpWvpnSI4/jvfACyWOPQOYbML09+G0dtH3+y6ROuw+7cS+8Jc+SOvVUMieeC5aNdF3CoED7F6+k/Pd/kHjrW5HJDEHHGsqPPk35wXnY00ay4YqvoIOAytynkW5i8Km8fFvjiY2k4ccS+fmQDSTOO5kRN92MkImdJrP2y75ExzevQeWS0TKE2WwfTdmvE6jRYqBI2ogQdNVnY50qYSlEwsFUw6g0YD1HVDg2QkFYKEeEsqgv+BiF0VGgI90kRvsYv4IQDjKbxAQaXSxFjsJKIFMxdF+xXqPEQddq0S1EpPlSO8iWOA1f/TAEFrV/voxsTdP4+c9gt+5F5fk5rD75IoK1HQhHoatVhO0ilIXxPUxYQ8bTYAl0sRy5gLiDjDtbTcEzxiy3xmzTr4T4mMsqcGAvjcdU/vgAPWO/Sv6HV+00oSVmzUJlfkfQU0DlMnUAFQ0yrkRsrIcpRISSZVQSe2PRMpQAaRDOq/yaFdkRZdcZeQ3SsSKQEdZz/KWIci+0E91DgZAClU1u+jvKIHPJaEKEGpWOgZKYIARhMH0BamSK7PvOw87vPXDdrNxO19XX4q9uR2UTYAuUa0fPYwJEzEE6iQjWh0Swv27et5ozKaCmxX3i3a/BS6xD8VHi095L7s8dVKcYKuSu/CLZ//zmzrKPdP/6l3Rc9lNqK9fsoS81NggVR+biAwdTgKmEiEyczLknkjzhSNToFowf4C9+hcIf76Z875MQcxAxueML3yIyE77WNzeV+z6xXSP0fuCXZE/oIz3bo5jHgoZrvkn6Q5/bacNSXTSfwh13UV34L4wX1FeJ9wB5iWhtpzLn+XnBmsI6kbLsAT5YCvBCdLGETMdQTXlMEBKu78TUAmQiCTFrR7ONpTCEEK7ywuDBlkrlgZFBubxdw3I+cBOwlvx5htTskCImLsj//FtkLvzMTp7TIa9d1fmNZUEFkp5bbzp29Tnve8TKjxJbVOoUQCnE1MJ64BTBXJFS0drgDmaHGyEQgUEERVMJPEYbxYigun27LQ4EzgCWU/1XDbkiQfp0E/hU730U4h6xt82CnfTWWoHcww4BoK0pU64O17Svqzw1B/nq2iQCCCUiUJu2XQkUuGJIu2G2puVCgzA+gQ7JIEjqYOjvT+ui53cBfZ+QxEN8Q+8Xr6T761/GMMw3bwzmcbvX0/n1C38cdiyZH5t1OJpgtz/TkIS2cQHep/TLGuEFhnTFkKDv8p/Rcd578dsWvakE5j31MG1HH31lde5jl9gjWhAVb48w2tbQzRdoFJrSn1zEhpDMtYL8pNKf7sV/cRn5H3+b+DvPGN7a1bOW8s+uZv1Vv7r8X93dX1eZOC/MeBtedy+j3Qx5qfD17nuh8nb5tAPqPq2daNtCCguDZCSFZTXcRzRqmiAxMWxfR/Xuv6JLa7EOmIZMZIeVsExQpXzPbHo//Y2w+/d//LpXLX9nDVDxAiqdXZRKZZpiCZKWTfgq6L+puGv/5rJLfNoOCS2JhUGRpYZHot0jvFsgpCKxn6nW3MoTc/Ae+RuyycKeOAFh7dlVE4xfpPrEA/R8+7v0fvMXK/1liz9ZQf8yJHpVtKibJAE0OnESw11oVZJ46Iqi+JDAesngTFXER4ZrV1K5/SH8Bc8hRyaxx4ypF5Tfg8yg10d1zoP0XPoD+i79Od685x7zdPihPvwHXQwa6OwH4vUeIrSd9Ub5KKcDcaemMA9in5TkPkHg5yq3PkT1wXnETjqc5AVnEjv6eGRyxG5lN4K2pVQfeJDy7ffiPfY8YV93l4+62iCvFjidhvIebRl28hvuBVBba5Bf08i7DfJjhvzZqq+SqPzxPqp3P4kz6yDix78D97iZODPe8obV/g83rKA670m8R+bhPT4H/5ml6LCqDfZfbNyfpOl5fD0WNi57erN2TbcC4ClB8ekY1h/KJD8icU4QxVqmet/f8O5/EjVxNO7b98eddRj2/m/BmjoRKzuSjXkTr5fP1OV2guVr8RctwPvfp6k98jz+Sy+j+3rrX9v6myR5HRRvh7DkoJEMj2btOiMksNFhkupDCvNQgDzYJ/4+cE7XhgnmlXWEr6yicuNDkIlj7TcKe/J0nAOnYc0Yj9U6CjWiFZHMItwYwtroIDamWweYwIeahy72EHasJVi3jmDRaoIXFuMvWYi/YBV6bRHMxvjKqQpSj2iq14N3t8Kp6k0OZ/gUvrF29Q0MAgeNS+2fUP1nF8mfWYiZGuckTfxIi7BV95WozVlIbc6LlACZiqNGNCEzeUQsCVkXkXEQrh2tuYUaPB/dV4MeD+OVCPu6CDu7MX1lNuaVSxQGx2hiLxrCu4D7AorzJDVPYe006u1NJ7T+YAVCJHpZnuKyblI3xtETejFvl7gH28QOAPYP0E2yGBAW1xOwlmjT05av+RNsep1cffAjLbRJEKJWB+jnArz5DqW5Ls7fl1Hts4FcXVDD+WXP1u66sUGSpLC8jXB5EnWTpCh68MeOJLZ3F4mpFtbeCsYDLQKSIFyiTBEZrS4JH4xnoCgwayUsA/PyagqL4nhLxhFrW4HApUiCDAaFIOTN0P7/ANXjuuhKlYnHAAAAAElFTkSuQmCC created_at: '2018-12-17 11:23:01.596760' updated_at: '2021-05-31 15:00:35.785632' - footprint: 7c12bc5ef224719d5f2d1b70f6ae11ff1084e2827bd1a832ee33c492f5ba7903 invoicing_profile_id: 1 history_value_10: @@ -103,7 +95,6 @@ history_value_10: value: YYMMmmmX[/VL]R[/A] created_at: '2018-12-17 11:23:01.603733' updated_at: '2021-05-31 15:00:35.801133' - footprint: 82424423a180ef69ffe18984abd33ac5e3b0017ffd15d7e22e17fd3ab0210865 invoicing_profile_id: 1 history_value_11: @@ -112,7 +103,6 @@ history_value_11: value: 'true' created_at: '2018-12-17 11:23:01.607174' updated_at: '2021-05-31 15:00:35.817977' - footprint: c6aa1b83704e11c18d326f5df2349e9041de927cda49788d42cba893a48514b2 invoicing_profile_id: 1 history_value_12: @@ -121,7 +111,6 @@ history_value_12: value: INMEDFABLAB created_at: '2018-12-17 11:23:01.610103' updated_at: '2021-05-31 15:00:35.895060' - footprint: f79a8336b722a3ac5a7bf59c1b0e9aa6aaa934ed898306c9c47a905bab61ddb6 invoicing_profile_id: 1 history_value_13: @@ -130,7 +119,6 @@ history_value_13: value: nnnnnn-MM-YY created_at: '2018-12-17 11:23:01.615671' updated_at: '2021-05-31 15:00:35.926928' - footprint: 7a6264b7a419253548d01411b1a456db3a89c1126afd719f72c8beaf53c21c2d invoicing_profile_id: 1 history_value_14: @@ -139,7 +127,6 @@ history_value_14: value: 'false' created_at: '2018-12-17 11:23:01.618886' updated_at: '2021-05-31 15:00:35.951174' - footprint: cf32967f739a60a462bd288d7a47cc2fc6ef693a28c900bbdff46ee9a9a07e11 invoicing_profile_id: 1 history_value_15: @@ -148,7 +135,6 @@ history_value_15: value: '20.0' created_at: '2018-12-17 11:23:01.625154' updated_at: '2021-05-31 15:00:35.967958' - footprint: 803a61518d27513c0443a22279a769f412d41db1ffab6142d425abd0a8579d9f invoicing_profile_id: 1 history_value_16: @@ -157,7 +143,6 @@ history_value_16: value: Notre association n'est pas assujettie à la TVA created_at: '2018-12-17 11:23:01.632653' updated_at: '2021-05-31 15:00:35.984439' - footprint: 55e22dcd89691bffbfa95c265dd24ef35e07c62fac6e6f1840663c3e998503a7 invoicing_profile_id: 1 history_value_17: @@ -168,7 +153,6 @@ history_value_17: - APE 913 E' created_at: '2018-12-17 11:23:01.569316' updated_at: '2021-05-31 15:00:36.001175' - footprint: c048d95a3acfa7543e4783cdaca27cbcea20c4b7277851a83a9aae2be2b182c3 invoicing_profile_id: 1 history_value_18: @@ -177,7 +161,6 @@ history_value_18: value: '1970-01-01 08:00:00' created_at: '2018-12-17 11:23:01.639995' updated_at: '2021-05-31 15:00:36.018287' - footprint: 5905fc634b5cedc240c37dc18e62724d7d9abd575771c364863ab506fbcdf416 invoicing_profile_id: 1 history_value_19: @@ -186,7 +169,6 @@ history_value_19: value: '1970-01-01 23:59:59' created_at: '2018-12-17 11:23:01.643667' updated_at: '2021-05-31 15:00:36.035246' - footprint: 143a551e8b8de5384c620274e831fced32b7b7d985ccf40d440b67549c13042e invoicing_profile_id: 1 history_value_20: @@ -195,7 +177,6 @@ history_value_20: value: 'true' created_at: '2018-12-17 11:23:01.647950' updated_at: '2021-05-31 15:00:36.051310' - footprint: 95501effa7a2073ffaca9e8ec407fc178988ba4499faea96cfd793e3f495fe0b invoicing_profile_id: 1 history_value_21: @@ -204,7 +185,6 @@ history_value_21: value: '24' created_at: '2018-12-17 11:23:01.650611' updated_at: '2021-05-31 15:00:36.068779' - footprint: 46757a1c25a8229fbecb3b6ff82d8fc8da245cb5cb920405bb7cb50fd4196505 invoicing_profile_id: 1 history_value_22: @@ -213,7 +193,6 @@ history_value_22: value: 'false' created_at: '2018-12-17 11:23:01.653441' updated_at: '2021-05-31 15:00:36.084483' - footprint: 290e6d49ad1f96f64342b16dbb3a475deebef1088c301a0f8cb0df4528ed209d invoicing_profile_id: 1 history_value_23: @@ -222,7 +201,6 @@ history_value_23: value: '24' created_at: '2018-12-17 11:23:01.655971' updated_at: '2021-05-31 15:00:36.101131' - footprint: 1b55d6e3cf85d113ce2758f580b99bbb06be5135ad6d1e0d88d07ceb3b266910 invoicing_profile_id: 1 history_value_24: @@ -231,7 +209,6 @@ history_value_24: value: "#cb1117" created_at: '2018-12-17 11:23:01.658780' updated_at: '2021-05-31 15:00:36.119229' - footprint: bd9bf053e6c5808250ac1c3c52f294ce659826e794255c399087dd386331efaa invoicing_profile_id: 1 history_value_25: @@ -240,7 +217,6 @@ history_value_25: value: "#ffdd00" created_at: '2018-12-17 11:23:01.666698' updated_at: '2021-05-31 15:00:36.159487' - footprint: 951d7020b222f864b93f5002a435415bc5e8f13ba29826998300c0807ba39a78 invoicing_profile_id: 1 history_value_26: @@ -251,7 +227,6 @@ history_value_26: et les créneaux machines. created_at: '2018-12-17 11:23:01.569316' updated_at: '2021-05-31 15:00:36.176364' - footprint: f0b97bb9f3423c3528b712b3f06cacec1db36d4c208f8710fa398115a7f32156 invoicing_profile_id: 1 history_value_27: @@ -260,7 +235,6 @@ history_value_27: value: Fab Lab de La Casemate created_at: '2018-12-17 11:23:01.724770' updated_at: '2021-05-31 15:00:36.196140' - footprint: 72ba74e249744233139251bfd9481ce3e44ab586d3424eacdfd8b4f1c042f9bb invoicing_profile_id: 1 history_value_28: @@ -269,7 +243,6 @@ history_value_28: value: male created_at: '2018-12-17 11:23:01.728465' updated_at: '2021-05-31 15:00:36.228419' - footprint: d46f86b720fad7226072cb3f56281df70e4d78b620630ccb1440c7ed84346132 invoicing_profile_id: 1 history_value_29: @@ -278,7 +251,6 @@ history_value_29: value: created_at: '2018-12-17 11:23:01.724770' updated_at: '2021-05-31 15:00:36.296904' - footprint: 93e02e71a511d5a09f3c0fd2e2e0d29f9db3b2187ec65e39a02b667363f76c0f invoicing_profile_id: 1 history_value_30: @@ -287,7 +259,6 @@ history_value_30: value: '3' created_at: '2018-12-17 11:23:01.724770' updated_at: '2021-05-31 15:00:36.317666' - footprint: 37ba96352a0be161fd7f1b342c2de7ab6da21b8abfb1772856ddd5a00ee82517 invoicing_profile_id: 1 history_value_31: @@ -296,7 +267,6 @@ history_value_31: value: '1' created_at: '2018-12-17 11:23:01.724770' updated_at: '2021-05-31 15:00:36.343513' - footprint: d01369ca019e03aa1e83118cabb3bf0f1b8f2c3532865f1c8828d03c0dbcb428 invoicing_profile_id: 1 history_value_32: @@ -305,7 +275,6 @@ history_value_32: value: f created_at: '2018-12-17 11:23:01.724770' updated_at: '2021-05-31 15:00:36.361506' - footprint: 0c23694d5590b3cdf6ed995476e3392dfee7e82eb4836e38e04266b05896e99c invoicing_profile_id: 1 history_value_33: @@ -314,7 +283,6 @@ history_value_33: value: default created_at: '2018-12-17 11:23:01.724770' updated_at: '2021-05-31 15:00:36.385235' - footprint: 2bcaca605919534335d0032086b38bb31e7aadec39058d22d7e5f365871e11d7 invoicing_profile_id: 1 history_value_34: @@ -323,7 +291,6 @@ history_value_34: value: A propos de Fab-manager created_at: '2018-12-31 10:22:25.116369' updated_at: '2021-05-31 15:00:36.403791' - footprint: 7b96125008785cb8ce5c725083a3c20bfa1161243c53765382092285bb772b54 invoicing_profile_id: 1 history_value_35: @@ -333,7 +300,6 @@ history_value_35: d'emploi." created_at: '2018-12-31 10:22:25.116369' updated_at: '2021-05-31 15:00:36.417809' - footprint: 9bbdbe6835a9d5e4dcadd4222525f2fa0657b67f125592ee76179ecf45799f72 invoicing_profile_id: 1 history_value_36: @@ -342,7 +308,6 @@ history_value_36: value: t created_at: '2018-12-31 10:22:25.116369' updated_at: '2021-05-31 15:00:36.434827' - footprint: 74a9fea2124a6250d215499ed7d28f2ec54f8cbbc355cedc3ac13f1380ec0150 invoicing_profile_id: 1 history_value_37: @@ -351,7 +316,6 @@ history_value_37: value: '24' created_at: '2018-12-31 10:22:25.116369' updated_at: '2021-05-31 15:00:36.451189' - footprint: 5ae4b7e440c917f38118f8a11d7d5934a63374983e7707f873555e59c58a8b22 invoicing_profile_id: 1 history_value_38: @@ -371,7 +335,6 @@ history_value_38: afin de prendre connaissance de ses éventuelles modifications.

" created_at: '2018-12-31 10:22:25.116369' updated_at: '2021-05-31 15:00:36.468263' - footprint: fc3895300ab141d1b3fc446e02b452cf5ebea06c6b810cefaba21e1309de8f39 invoicing_profile_id: 1 history_value_39: @@ -380,7 +343,6 @@ history_value_39: value: '530' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.484622' - footprint: 20878d5d457368686597fa041584130d603c828a873aca26a1b953b86e992f49 invoicing_profile_id: 1 history_value_40: @@ -389,7 +351,6 @@ history_value_40: value: '5801' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.502632' - footprint: ede5cb6a44856ef2271110283094daa2b4a1656287f7888ca5a99fb9a2dff8bf invoicing_profile_id: 1 history_value_41: @@ -398,7 +359,6 @@ history_value_41: value: Payment by card created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.518127' - footprint: bad61ed94921d492052622f6da1e7b1611c8abee4d0e3260229f0bf23bc24f70 invoicing_profile_id: 1 history_value_42: @@ -407,7 +367,6 @@ history_value_42: value: '5802' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.534681' - footprint: daffc10930507102df7bc0dedce9be773b0483ed7d7e1bf3524a6cb2408ca745 invoicing_profile_id: 1 history_value_43: @@ -416,7 +375,6 @@ history_value_43: value: Payment by wallet created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.553577' - footprint: 430cdf800a4e84f0385ebbdb7b48a107450c618b9c49b9b97016e80047407036 invoicing_profile_id: 1 history_value_44: @@ -425,7 +383,6 @@ history_value_44: value: '5803' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.576371' - footprint: fc4dbe201e24a9f3a1150853b191d84b23d79ed043811387613ef30319551e76 invoicing_profile_id: 1 history_value_45: @@ -434,7 +391,6 @@ history_value_45: value: Payment by other created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.593026' - footprint: 383ef2b5ad5aaa5e014893e0ca8f7bdcd13d565a3bfd97446e5543e8d0dca941 invoicing_profile_id: 1 history_value_46: @@ -443,7 +399,6 @@ history_value_46: value: '419100' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.672119' - footprint: 160a865d5709e9b365b1e18fa930e9069cab3b4e3c23e7d79cd0fdeee758539b invoicing_profile_id: 1 history_value_47: @@ -452,7 +407,6 @@ history_value_47: value: Wallet credit created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.693696' - footprint: 5399df590335e6c3016dc156d70c0dba89c18c2638fd36912b9de2b469ee2096 invoicing_profile_id: 1 history_value_48: @@ -461,7 +415,6 @@ history_value_48: value: '4457' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.710257' - footprint: f585a1b670e6cb1632398360513793ce1f459f49884f971ca7f36594bb67fa70 invoicing_profile_id: 1 history_value_49: @@ -470,7 +423,6 @@ history_value_49: value: VAT created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.726521' - footprint: 39ce7d4f81ca7570444c28f1439a38ca4c3b7b7669202a9db7caa3dcf7d96c16 invoicing_profile_id: 1 history_value_50: @@ -479,7 +431,6 @@ history_value_50: value: '7061' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.751938' - footprint: a378c9f8b31b18f8e2263cc1cda13f5f36945faca5964b9267c605bb89f47805 invoicing_profile_id: 1 history_value_51: @@ -488,7 +439,6 @@ history_value_51: value: Subscription created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.838598' - footprint: c130333282240854ea012e308e6a7eab701fa49182b0066eb308cbe71d2f4746 invoicing_profile_id: 1 history_value_52: @@ -497,7 +447,6 @@ history_value_52: value: Machine reservation created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.872288' - footprint: 0ee671e962f92a3af95538fdd65a64ff410b208ab790c4e6f7b0a9f5a13dc1a2 invoicing_profile_id: 1 history_value_53: @@ -506,7 +455,6 @@ history_value_53: value: '7062' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.904414' - footprint: ad09bac8c58754444a9970108d613aefaeceed540609688f5668c68ca5c03531 invoicing_profile_id: 1 history_value_54: @@ -515,7 +463,6 @@ history_value_54: value: Training reservation created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.930713' - footprint: 89f17add783f9977c4b13bc22f5776d0427c3d9af8c83206af57de7c72c153b0 invoicing_profile_id: 1 history_value_55: @@ -524,7 +471,6 @@ history_value_55: value: '7063' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.955492' - footprint: f2e20f936e3fc917bc82e97adb321f957c2cd6ac992f3223ffe2be529ea1649f invoicing_profile_id: 1 history_value_56: @@ -533,7 +479,6 @@ history_value_56: value: Event reservation created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.977369' - footprint: 5ce909aa92740dbd65647ff3a5d5fdc75ad6c2a02b5fa9bbeea1aa27f907416a invoicing_profile_id: 1 history_value_57: @@ -542,7 +487,6 @@ history_value_57: value: '7064' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:36.993279' - footprint: ed7ecf389b9560728ce43257bef442a2404f463ebbc0fbaeaad05f113cca21df invoicing_profile_id: 1 history_value_58: @@ -551,7 +495,6 @@ history_value_58: value: '7065' created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:37.010029' - footprint: 6a4d523d8c2dcde1e8022015231d1da44532323f707021fe13e0353c08846f97 invoicing_profile_id: 1 history_value_59: @@ -560,7 +503,6 @@ history_value_59: value: Space reservation created_at: '2019-09-20 11:02:32.125400' updated_at: '2021-05-31 15:00:37.027157' - footprint: d92dcf0fa46d32c84c8ab6bdc66928d9e938d4f79a1e188eb5260b56f600f8db invoicing_profile_id: 1 history_value_60: @@ -588,7 +530,6 @@ history_value_60:
created_at: '2020-03-25 09:24:09.016676' updated_at: '2021-05-31 15:00:37.043394' - footprint: 4e882aea02b7fdb3b1eae71f451513e7375118ae26ea709ffa09056ec249bb65 invoicing_profile_id: 1 history_value_61: @@ -597,7 +538,6 @@ history_value_61: value: '60' created_at: '2020-05-22 15:22:08.254410' updated_at: '2021-05-31 15:00:37.059981' - footprint: 57c0ed1d28d4b500ea05d732ab976f5aa95f9c15924b7a13fa6935f435be1909 invoicing_profile_id: 1 history_value_62: @@ -606,7 +546,6 @@ history_value_62: value: 'true' created_at: '2020-06-01 11:12:21.255550' updated_at: '2021-05-31 15:00:37.078041' - footprint: 5f46debc9978342faa947bd6aa2849d887e391b281131c1cdc8cc71aee2fc405 invoicing_profile_id: 1 history_value_63: @@ -615,7 +554,6 @@ history_value_63: value: 'true' created_at: '2020-06-01 11:12:21.255550' updated_at: '2021-05-31 15:00:37.121791' - footprint: dad09e0bfae64911e10203395af0e95fdc50dde56fc38da38a65fbe3c03ba095 invoicing_profile_id: 1 history_value_64: @@ -624,7 +562,6 @@ history_value_64: value: once created_at: '2020-06-01 11:12:21.255550' updated_at: '2021-05-31 15:00:37.143385' - footprint: 6db8d46c843db553945d339d3f113a14d814f2001168b67988a479154bb15252 invoicing_profile_id: 1 history_value_65: @@ -633,7 +570,6 @@ history_value_65: value: noreply@fab-manager.com created_at: '2020-06-01 11:12:21.255550' updated_at: '2021-05-31 15:00:37.163510' - footprint: d3084c6d7c6b28ead038f3573c73e4c4280d6f095cbba22d83604736ce51cc2c invoicing_profile_id: 1 history_value_66: @@ -642,7 +578,6 @@ history_value_66: value: 'true' created_at: '2020-06-08 17:12:16.846525' updated_at: '2021-05-31 15:00:37.193791' - footprint: c05878daaa7a94c0cb37905bcb136a496cf0d164c051a5965a0167ad69bda425 invoicing_profile_id: 1 history_value_67: @@ -651,7 +586,6 @@ history_value_67: value: <%=ENV.fetch('STRIPE_PUBLISHABLE_KEY', 'pk_test_faketestfaketestfaketest') %> created_at: '2020-06-08 17:12:16.846525' updated_at: '2021-05-31 15:00:37.210049' - footprint: 4984215605d9f30ac4f9594bc0d552d6b5e280f650801399b698aa43188001a5 invoicing_profile_id: 1 history_value_68: @@ -660,7 +594,6 @@ history_value_68: value: <%=ENV.fetch('STRIPE_API_KEY', 'sk_test_testfaketestfaketestfake') %> created_at: '2020-06-08 17:12:16.846525' updated_at: '2021-05-31 15:00:37.280668' - footprint: 48db504877d3329e39d1e816b243629c44b47be9f2837e2e4af4f30ca7cbd3e8 invoicing_profile_id: 1 history_value_69: @@ -669,7 +602,6 @@ history_value_69: value: usd created_at: '2020-06-08 17:12:16.846525' updated_at: '2021-05-31 15:00:37.302102' - footprint: 7211260d30ec9d95dd6a7ac8e7a838b2f5898de5968cec897d26bf0a56dfdc53 invoicing_profile_id: 1 history_value_70: @@ -678,7 +610,6 @@ history_value_70: value: FabManager_invoice created_at: '2020-06-15 10:04:06.216541' updated_at: '2021-05-31 15:00:37.318496' - footprint: d124d5d58b2fbed18998fb1a7401a0539d75bc920dde8360743cf0dc08976ac5 invoicing_profile_id: 1 history_value_71: @@ -687,7 +618,6 @@ history_value_71: value: 'false' created_at: '2020-06-15 10:04:06.216541' updated_at: '2021-05-31 15:00:37.344188' - footprint: 8c09996f01a428e949e4fa4bfae71c96d1c6b4c4a10d1902cc65812c7eb458b4 invoicing_profile_id: 1 history_value_72: @@ -696,7 +626,6 @@ history_value_72: value: 'true' created_at: '2020-06-15 10:04:06.216541' updated_at: '2021-05-31 15:00:37.363871' - footprint: 26f881c216c0a594cf374f80b69678286895b029a5fee6fbf8d7d659900a233d invoicing_profile_id: 1 history_value_73: @@ -705,7 +634,6 @@ history_value_73: value: 'true' created_at: '2020-06-17 10:48:19.002417' updated_at: '2021-05-31 15:00:37.393731' - footprint: 4164041cd3be3b4dab97e2e05a474268b3de72bae719b2bbcbe1bff00f8d171d invoicing_profile_id: 1 history_value_74: @@ -714,7 +642,6 @@ history_value_74: value: until_start created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.410025' - footprint: c2fe239e922b92a3b43ec5e66abe3920df43ac7e0c4abc173f27f90402c5d69e invoicing_profile_id: 1 history_value_75: @@ -723,7 +650,6 @@ history_value_75: value: FabManager_paymentSchedule created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.426690' - footprint: 49fd4ced3dc924d2a2f366be7e9c76eada6822926ea48174735c2308eb0a13e3 invoicing_profile_id: 1 history_value_76: @@ -732,7 +658,6 @@ history_value_76: value: 'true' created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.443392' - footprint: 1ed04193b188b80f15fc661cbb18171085cd596d100af973080560d3507f008a invoicing_profile_id: 1 history_value_77: @@ -741,7 +666,6 @@ history_value_77: value: 'false' created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.460191' - footprint: c1c405081f2c5f18d8ee38c2932b44b04904b1deafc96f4412ee3e0dcb006a52 invoicing_profile_id: 1 history_value_78: @@ -750,7 +674,6 @@ history_value_78: value: stripe created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.476925' - footprint: 4825ae0d2e6fe1146a16141e9deac8b61e22bea5fa4ce9c5f1490766781a9d6b invoicing_profile_id: 1 history_value_79: @@ -759,7 +682,6 @@ history_value_79: value: 69876357 created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.503801' - footprint: 86ef63d061ce61d9aff61c1ef912586b415a09a2fe7102616af29038cdfa1da4 invoicing_profile_id: 1 history_value_80: @@ -768,7 +690,6 @@ history_value_80: value: testpassword_DEMOPRIVATEKEY23G4475zXZQ2UA5x7M created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.518625' - footprint: 42c94550c236ffc7cf15dda0b6031b7c33c06b606e0cec00419e31a1d566c2f9 invoicing_profile_id: 1 history_value_81: @@ -777,7 +698,6 @@ history_value_81: value: https://api.payzen.eu created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.535175' - footprint: 3fe3bf39caf3011b00cc00ce5b5d2a05ab1f16956704689dbf39f85a350a4fea invoicing_profile_id: 1 history_value_82: @@ -786,7 +706,6 @@ history_value_82: value: 69876357:testpublickey_DEMOPUBLICKEY95me92597fd28tGD4r5 created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.551956' - footprint: 6757d18bcff2cb3bb832f57bc1c7078d982310065e367f580c4379ddf6caee91 invoicing_profile_id: 1 history_value_83: @@ -795,7 +714,6 @@ history_value_83: value: 83daf5e7b80d990f037407bab78dff9904aaf3c19 created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.568426' - footprint: 881e9b272a657bb515312f625b5049248d7784eee24316c8490bf08be9d98bf0 invoicing_profile_id: 1 history_value_84: @@ -804,7 +722,6 @@ history_value_84: value: EUR created_at: '2020-04-15 14:38:40.000421' updated_at: '2021-05-31 15:00:37.593645' - footprint: 1e62d53c0704eeebf40caa8277b8bf491cd3e602f0689412d202105c6777d43e invoicing_profile_id: 1 history_value_85: @@ -813,7 +730,6 @@ history_value_85: value: YYMMmmmX[/VL]R[/A]S[/E] created_at: '2020-12-14 14:37:35.615124' updated_at: '2021-05-31 15:00:37.610104' - footprint: 424bda69956b6d082c5f0075f7f753bbb0a87a8b44b3e69b5fe9a20004be1585 invoicing_profile_id: 1 history_value_86: @@ -822,7 +738,6 @@ history_value_86: value: true created_at: '2021-06-15 12:05:21.513651' updated_at: '2021-06-15 12:05:21.513651' - footprint: 350ca0033f3e65b6e8186dbb0545b55ecb3768e1a08501549b81d95e34809440 invoicing_profile_id: 1 history_value_87: @@ -831,7 +746,6 @@ history_value_87: value: Prepaid pack created_at: '2022-10-26 12:46:16.125400000 Z' updated_at: '2022-10-26 12:46:16.125400000 Z' - footprint: invoicing_profile_id: 1 history_value_88: @@ -840,7 +754,6 @@ history_value_88: value: '7066' created_at: '2022-10-26 12:46:16.125400000 Z' updated_at: '2022-10-26 12:46:16.125400000 Z' - footprint: invoicing_profile_id: 1 history_value_89: @@ -849,7 +762,6 @@ history_value_89: value: Shop order created_at: '2022-10-26 12:46:16.125400000 Z' updated_at: '2022-10-26 12:46:16.125400000 Z' - footprint: invoicing_profile_id: 1 history_value_90: @@ -858,7 +770,6 @@ history_value_90: value: '7071' created_at: '2022-10-26 12:46:16.125400000 Z' updated_at: '2022-10-26 12:46:16.125400000 Z' - footprint: invoicing_profile_id: 1 history_value_91: @@ -867,7 +778,6 @@ history_value_91: value: 'CB01' created_at: 2022-12-09 14:00:14.512000000 Z updated_at: 2022-12-09 14:00:14.512000000 Z - footprint: invoicing_profile_id: 1 history_value_92: @@ -876,7 +786,6 @@ history_value_92: value: 'W001' created_at: 2022-12-09 14:00:14.512000000 Z updated_at: 2022-12-09 14:00:14.512000000 Z - footprint: invoicing_profile_id: 1 history_value_93: @@ -885,7 +794,6 @@ history_value_93: value: 'CA01' created_at: 2022-12-09 14:00:14.512000000 Z updated_at: 2022-12-09 14:00:14.512000000 Z - footprint: invoicing_profile_id: 1 history_value_94: @@ -894,7 +802,6 @@ history_value_94: value: 'W002' created_at: 2022-12-09 14:00:14.512000000 Z updated_at: 2022-12-09 14:00:14.512000000 Z - footprint: invoicing_profile_id: 1 history_value_95: @@ -903,7 +810,6 @@ history_value_95: value: 'TVA1' created_at: 2022-12-09 14:00:14.512000000 Z updated_at: 2022-12-09 14:00:14.512000000 Z - footprint: invoicing_profile_id: 1 history_value_96: @@ -912,7 +818,6 @@ history_value_96: value: 'false' created_at: 2022-12-22 14:45:07.891240000 Z updated_at: 2022-12-22 14:45:07.891240000 Z - footprint: invoicing_profile_id: 1 history_value_97: @@ -921,7 +826,6 @@ history_value_97: value: '0' created_at: 2022-11-29 21:02:47.354751000 Z updated_at: 2022-11-29 21:02:47.354751000 Z - footprint: invoicing_profile_id: 1 history_value_98: @@ -930,7 +834,6 @@ history_value_98: value: 'TVA' created_at: 2022-12-23 14:39:12.214510000 Z updated_at: 2022-12-23 14:39:12.214510000 Z - footprint: invoicing_profile_id: 1 history_value_99: @@ -939,5 +842,4 @@ history_value_99: value: 'true' created_at: '2022-12-20 14:38:40.000421' updated_at: '2022-12-20 14:38:40.000421' - footprint: invoicing_profile_id: 1 diff --git a/test/fixtures/invoice_items.yml b/test/fixtures/invoice_items.yml index fc5d8f92a..132f88f17 100644 --- a/test/fixtures/invoice_items.yml +++ b/test/fixtures/invoice_items.yml @@ -7,7 +7,6 @@ invoice_item_1: updated_at: '2021-05-27 09:26:26.450083' description: Sleede - standard, association - month invoice_item_id: - footprint: d2b756f158d6332c32b7b262118f5bdcfd68221ab089c355e6776c1298d937b8 object_type: Subscription object_id: 1 main: true @@ -20,7 +19,6 @@ invoice_item_2: description: Mensuel tarif réduit - étudiant, - de 25 ans, enseignant, demandeur d'emploi - month invoice_item_id: - footprint: f02559738cb3674e74021ac1894e512e1864eb9fc177e885283a214fa5e0dd74 object_type: Subscription object_id: 2 main: true @@ -32,7 +30,6 @@ invoice_item_3: updated_at: '2021-05-27 09:26:26.465302' description: Mensuel - standard, association - month invoice_item_id: - footprint: e6141fbc1db017356f855ebc784cb2e084fbf82ed56a0dc295c8a39dcc2a0f92 object_type: Subscription object_id: 3 main: true @@ -44,7 +41,6 @@ invoice_item_4: updated_at: '2021-05-27 09:26:26.468890' description: Formation Laser / Vinyle April 11, 2012 08:00 - 12:00 PM invoice_item_id: - footprint: b66ade050a2ef9ebb18067ac1af2828fec2077037100d7068481e00097af4bc0 object_type: Reservation object_id: 1 main: true @@ -56,7 +52,6 @@ invoice_item_5: updated_at: '2021-05-27 09:26:26.472232' description: Imprimante 3D June 15, 2015 12:00 - 01:00 PM invoice_item_id: - footprint: a0f096de802df8d5708d4dcc23d7384ab95f246fb80e59564b2c3363db103b02 object_type: Reservation object_id: 2 main: true @@ -68,7 +63,6 @@ invoice_item_6: updated_at: '2021-05-27 09:26:26.475460' description: Mensuel - standard, association - month invoice_item_id: - footprint: 88e73e7d2f29fe8f029a646a54e5e8884ddf9cd9b207544e9f3d18c70d181749 object_type: Subscription object_id: 4 main: true @@ -80,7 +74,6 @@ invoice_item_11702: updated_at: '2022-09-20 15:14:23.180166' description: Tablette lamellé-collé x 1 invoice_item_id: - footprint: 1d112a787e89d444f2817b909d7857a3a26fc2a3cd4c4404fb50bec282988a02 object_type: OrderItem object_id: 1 main: true @@ -92,7 +85,6 @@ invoice_item_11703: updated_at: '2022-09-20 15:14:23.289957' description: Panneaux de MDF x 1 invoice_item_id: - footprint: 67f143564abfeab7cb93988a02987a5a2b04a2632d0f9cfde61fa39c398cd02b object_type: OrderItem object_id: 2 main: false @@ -104,7 +96,6 @@ invoice_item_11704: updated_at: '2022-09-20 15:14:48.385139' description: Panneau de contre-plaqué x 4 invoice_item_id: - footprint: ea51c614632c018f0fae53c2bf8503c71d18c082ae3246155971e19ac2db143a object_type: OrderItem object_id: 3 main: true @@ -116,7 +107,6 @@ invoice_item_11712: updated_at: '2022-10-04 12:36:03.282529' description: Filament PLA blanc x 1 invoice_item_id: - footprint: 4c5c8a1d7884502ea7791aeed1701cf3761562855d51ed19396b344c665c308b object_type: OrderItem object_id: 16 main: true @@ -128,7 +118,6 @@ invoice_item_11713: updated_at: '2022-10-04 12:36:03.290235' description: Filament PLA bleu x 1 invoice_item_id: - footprint: 12c1a2c7fdb0f4b35d0c24137e6e0bdbbb39fa5c6500aa7837c67f92084d5071 object_type: OrderItem object_id: 17 main: false @@ -140,7 +129,6 @@ invoice_item_11714: updated_at: '2022-10-04 13:54:42.992564' description: Filament PLA blanc x 1 invoice_item_id: - footprint: cdb07fe1f0b986b9a53b6ec71f91a96e8b8d438592e88fd0041133b2ab46c8ca object_type: OrderItem object_id: 18 main: true @@ -152,7 +140,6 @@ invoice_item_11715: updated_at: '2022-10-04 13:54:43.024326' description: Panneau de contre-plaqué x 1 invoice_item_id: - footprint: 3ac08745b737bc370424ee9f1b68b421000eb98e0f3e65d7395d905d75de05c6 object_type: OrderItem object_id: 19 main: false @@ -164,7 +151,6 @@ invoice_item_11716: updated_at: '2022-10-04 14:04:12.749266' description: Bulldozer x 1 invoice_item_id: - footprint: 1f4b6489579d7f045c846b97bc8ed402ec91f6fd7a5c2fa93b74eb7d21c7de39 object_type: OrderItem object_id: 20 main: true @@ -176,7 +162,6 @@ invoice_item_11717: updated_at: '2022-10-04 14:17:52.871262' description: Sticker Hello x 2 invoice_item_id: - footprint: 0fbecff886d9c2ffc332def13fa2c8869be8a40d2be7a3126a77974bd920c563 object_type: OrderItem object_id: 21 main: true @@ -188,7 +173,6 @@ invoice_item_11718: updated_at: '2022-10-04 14:17:52.878780' description: Tablette lamellé-collé x 1 invoice_item_id: - footprint: ad160b9357518b31f63661fe38998b8c1d97fda61bc744876826ae638a8142a0 object_type: OrderItem object_id: 22 main: false @@ -200,7 +184,6 @@ invoice_item_11719: updated_at: '2022-10-04 14:25:37.322782' description: Tablette lamellé-collé x 3 invoice_item_id: - footprint: 409a6f0b9f67510038a8b9a407db6d09b97f12d7169d6f6f121eedb2941d1bfc object_type: OrderItem object_id: 11 main: true @@ -212,7 +195,6 @@ invoice_item_11720: updated_at: '2022-10-04 14:32:28.226556' description: Tablette lamellé-collé x 3 invoice_item_id: - footprint: 733610b9c8e33f6a63f497d867d40386c623f12a526814d09d88a96f53741b7b object_type: OrderItem object_id: 23 main: true @@ -224,7 +206,6 @@ invoice_item_11721: updated_at: '2022-10-04 14:35:40.608505' description: Panneau de 3 plis mélèze x 1 invoice_item_id: - footprint: c1ad8c20d080ebc8267ff0d1b668feb8c989c2561be75d311f29f49a03405895 object_type: OrderItem object_id: 24 main: true diff --git a/test/fixtures/invoices.yml b/test/fixtures/invoices.yml index c852bd79e..ee25fc100 100644 --- a/test/fixtures/invoices.yml +++ b/test/fixtures/invoices.yml @@ -4,7 +4,7 @@ invoice_1: total: 10000 created_at: '2012-03-12 11:03:31.651441' updated_at: '2021-05-27 09:26:26.481266' - reference: 1604001/VL + reference: 1203001/VL payment_method: card avoir_date: invoice_id: @@ -14,18 +14,18 @@ invoice_1: wallet_amount: wallet_transaction_id: coupon_id: - footprint: e4edca90b74e7d1a6f59cd62a9434027ab8cec8f3f71737938123686afaa53f6 environment: test invoicing_profile_id: 3 operator_profile_id: 3 statistic_profile_id: 3 + order_number: 000001-03-12 invoice_2: id: 2 total: 2000 created_at: '2012-03-12 13:40:22.342717' updated_at: '2021-05-27 09:26:26.485839' - reference: '1604002' + reference: '1203002' payment_method: avoir_date: invoice_id: @@ -35,11 +35,11 @@ invoice_2: wallet_amount: wallet_transaction_id: coupon_id: - footprint: 52f5c2cb9e58d0ad421c93437f57fe2dd364ca412c85775cd59e7510031f1091 environment: test invoicing_profile_id: 4 operator_profile_id: 1 statistic_profile_id: 4 + order_number: 000002-03-12 invoice_3: id: 3 @@ -56,18 +56,18 @@ invoice_3: wallet_amount: wallet_transaction_id: coupon_id: - footprint: 2396b77776092cf80e3b2c1effef36e655af63a52a781eb73f27d9f44e546bae environment: test invoicing_profile_id: 7 operator_profile_id: 1 statistic_profile_id: 7 + order_number: 000003-06-15 invoice_4: id: 4 total: 0 created_at: '2016-04-05 08:35:52.931187' updated_at: '2021-05-27 09:26:26.494005' - reference: '1203002' + reference: '1604002' payment_method: avoir_date: invoice_id: @@ -77,18 +77,18 @@ invoice_4: wallet_amount: wallet_transaction_id: coupon_id: - footprint: c0809383b304668ac5226fb502f92eb26c51701380ea9ba9526b80b0295b603d environment: test invoicing_profile_id: 7 operator_profile_id: 1 statistic_profile_id: 7 + order_number: 000004-04-16 invoice_5: id: 5 total: 1500 created_at: '2016-04-05 08:36:46.853368' updated_at: '2021-05-27 09:26:26.498207' - reference: '1506031' + reference: '1604031' payment_method: avoir_date: invoice_id: @@ -98,11 +98,11 @@ invoice_5: wallet_amount: wallet_transaction_id: coupon_id: - footprint: f5d538feef1e83fd8f2b1431e7797e1d267f034e3612bdd9725a58e7ba947b27 environment: test invoicing_profile_id: 3 operator_profile_id: 1 statistic_profile_id: 3 + order_number: 000005-04-16 invoice_6: id: 6 @@ -119,11 +119,11 @@ invoice_6: wallet_amount: wallet_transaction_id: coupon_id: - footprint: eb22a99b5fec426dda0214bbaca3ea938fabe42c73bbf1f86712f67a5f61d236 environment: test invoicing_profile_id: 8 operator_profile_id: 1 statistic_profile_id: 8 + order_number: 000006-01-21 invoice_5811: id: 5811 total: 4500 @@ -139,11 +139,11 @@ invoice_5811: wallet_amount: wallet_transaction_id: coupon_id: - footprint: '094590df6330de6a2b5d2ce7230673c7178f2639ca8ceb51ba272795349fff95' environment: development invoicing_profile_id: 3 operator_profile_id: 1 statistic_profile_id: 3 + order_number: 000009-08-22 invoice_5812: id: 5812 total: 6000 @@ -159,11 +159,11 @@ invoice_5812: wallet_amount: wallet_transaction_id: coupon_id: - footprint: ea5cc57a8af956f9a3e66ec1f9bd7fe5fe51e1220955cacb11a3cc99d2e6aa54 environment: development invoicing_profile_id: 7 operator_profile_id: 1 statistic_profile_id: 7 + order_number: 005877-09-22 invoice_5816: id: 5816 total: 319 @@ -179,11 +179,11 @@ invoice_5816: wallet_amount: wallet_transaction_id: coupon_id: - footprint: ca8879f07cf1bd29500a9df29ce110843fb204ab0da8140bb4c6e8e908a65e0b environment: development invoicing_profile_id: 4 operator_profile_id: 4 statistic_profile_id: 4 + order_number: 005888-10-22 invoice_5817: id: 5817 total: 1295 @@ -199,11 +199,11 @@ invoice_5817: wallet_amount: wallet_transaction_id: coupon_id: 30 - footprint: 838ae505dfba54f6a69cd341abf8f97fd9370c2acb81e37c6e70d98049d80646 environment: development invoicing_profile_id: 4 operator_profile_id: 4 statistic_profile_id: 4 + order_number: 005890-10-22 invoice_5818: id: 5818 total: 1000 @@ -219,11 +219,11 @@ invoice_5818: wallet_amount: wallet_transaction_id: coupon_id: - footprint: 93db8c6ded7066a71927b6950cf5a9ea69aff25036df3a5a4259615347f2c8b2 environment: development invoicing_profile_id: 4 operator_profile_id: 4 statistic_profile_id: 4 + order_number: 005892-10-22 invoice_5819: id: 5819 total: 4002 @@ -239,11 +239,11 @@ invoice_5819: wallet_amount: wallet_transaction_id: coupon_id: - footprint: bfd2f78a99aadd137f3f28fe8258a46ff8afa69b458f0a6f2dce1205fab22784 environment: development invoicing_profile_id: 4 operator_profile_id: 4 statistic_profile_id: 4 + order_number: 005894-10-22 invoice_5820: id: 5820 total: 12000 @@ -259,11 +259,11 @@ invoice_5820: wallet_amount: wallet_transaction_id: coupon_id: - footprint: db6a663a25e19229ee93868765e1463ec7bd7856b173c5dd326d70d98369cfc0 environment: development invoicing_profile_id: 3 operator_profile_id: 1 statistic_profile_id: 3 + order_number: 005882-09-22 invoice_5821: id: 5821 total: 12000 @@ -279,11 +279,11 @@ invoice_5821: wallet_amount: wallet_transaction_id: coupon_id: - footprint: 3ed9a13e5c7155bc3b186f3215b90345cc5520822728796e7c1c00ad5128ed01 environment: development invoicing_profile_id: 2 operator_profile_id: 1 statistic_profile_id: 2 + order_number: 005898-10-22 invoice_5822: id: 5822 total: 3000 @@ -299,8 +299,8 @@ invoice_5822: wallet_amount: wallet_transaction_id: coupon_id: - footprint: 63d069e72b4992244861e9450b0c3ba3b9b30638af972a631b81578091d2925d environment: development invoicing_profile_id: 2 operator_profile_id: 1 statistic_profile_id: 2 + order_number: 005900-10-22 diff --git a/test/fixtures/order_activities.yml b/test/fixtures/order_activities.yml index 707e9d505..8b06e3113 100644 --- a/test/fixtures/order_activities.yml +++ b/test/fixtures/order_activities.yml @@ -116,8 +116,8 @@ order_activity_21: operator_profile_id: activity_type: paid note: - created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> order_activity_22: id: 22 order_id: 15 @@ -125,5 +125,5 @@ order_activity_22: activity_type: ready note: "

Votre commande est prête, merci de venir la récupérer jeudi après 14 h.

" - created_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> diff --git a/test/fixtures/order_items.yml b/test/fixtures/order_items.yml index 10d1da467..b9e6a37eb 100644 --- a/test/fixtures/order_items.yml +++ b/test/fixtures/order_items.yml @@ -126,8 +126,8 @@ order_item_24: amount: 3000 quantity: 1 is_offered: - created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> order_item_25: id: 25 order_id: 18 @@ -136,8 +136,8 @@ order_item_25: amount: 500 quantity: 1 is_offered: - created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> order_item_26: id: 26 order_id: 19 @@ -146,8 +146,8 @@ order_item_26: amount: 52300 quantity: 5 is_offered: - created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> order_item_27: id: 27 order_id: 20 @@ -156,8 +156,8 @@ order_item_27: amount: 52300 quantity: 5 is_offered: - created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> order_item_28: id: 28 order_id: 20 @@ -166,5 +166,5 @@ order_item_28: amount: 500 quantity: 2 is_offered: - created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> diff --git a/test/fixtures/orders.yml b/test/fixtures/orders.yml index 6ece87147..dd51ec67a 100644 --- a/test/fixtures/orders.yml +++ b/test/fixtures/orders.yml @@ -3,7 +3,7 @@ order_1: statistic_profile_id: 3 operator_profile_id: 1 token: 3R9wtsPjyYMHKqy-I2V5Cg1661868752184 - reference: + reference: 000009-08-22 state: paid total: 4500 created_at: '2022-08-30 14:12:32.213832' @@ -150,8 +150,8 @@ order_15: reference: '005900-10-22' state: ready total: 3000 - created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> wallet_amount: wallet_transaction_id: payment_method: local @@ -168,8 +168,8 @@ order_16: reference: '005901-<%= DateTime.current.utc.strftime('%m') %>-<%= DateTime.current.utc.strftime('%d') %>' state: cart total: 0 - created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> wallet_amount: wallet_transaction_id: payment_method: @@ -186,8 +186,8 @@ order_17: reference: '005902-<%= DateTime.current.utc.strftime('%m') %>-<%= DateTime.current.utc.strftime('%d') %>' state: cart total: 0 - created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> wallet_amount: wallet_transaction_id: payment_method: @@ -204,8 +204,8 @@ order_18: reference: '005902-<%= DateTime.current.utc.strftime('%m') %>-<%= DateTime.current.utc.strftime('%d') %>' state: cart total: 500 - created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> wallet_amount: wallet_transaction_id: payment_method: @@ -222,8 +222,8 @@ order_19: reference: '005903-<%= DateTime.current.utc.strftime('%m') %>-<%= DateTime.current.utc.strftime('%d') %>' state: cart total: 261500 - created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> wallet_amount: wallet_transaction_id: payment_method: @@ -240,8 +240,8 @@ order_20: reference: '005904-<%= DateTime.current.utc.strftime('%m') %>-<%= DateTime.current.utc.strftime('%d') %>' state: cart total: 262500 - created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> wallet_amount: wallet_transaction_id: payment_method: diff --git a/test/fixtures/payment_schedule_items.yml b/test/fixtures/payment_schedule_items.yml index d6506532f..70639599e 100644 --- a/test/fixtures/payment_schedule_items.yml +++ b/test/fixtures/payment_schedule_items.yml @@ -3,12 +3,11 @@ payment_schedule_item_105: amount: 9474 due_date: '2021-06-14 12:24:45.836045' state: paid - details: '{"recurring": 9466, "adjustment": 8, "other_items": 0}' + details: {"recurring": 9466, "adjustment": 8, "other_items": 0} payment_method: card client_secret: payment_schedule_id: 12 invoice_id: - footprint: 6168dcf85b00be2b45a36bbb3217e8b965a179c37922962978960062eac4bec6 created_at: '2021-06-14 12:24:45.847551' updated_at: '2021-06-14 13:00:41.302605' @@ -17,12 +16,11 @@ payment_schedule_item_106: amount: 9466 due_date: '2021-07-14 12:24:45.836332' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: ada6f6afe6489919d193ff6030923c0d524294529f13374f9a57d5691e9669fd created_at: '2021-06-14 12:24:45.855717' updated_at: '2021-06-14 12:24:45.858475' @@ -32,12 +30,11 @@ payment_schedule_item_107: amount: 9466 due_date: '2021-08-14 12:24:45.836606' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 7ca8bf5648235c8a706a01c5e788939ad5cfcc66c26782127ed1ed766379b005 created_at: '2021-06-14 12:24:45.863237' updated_at: '2021-06-14 12:24:45.865874' @@ -46,12 +43,11 @@ payment_schedule_item_108: amount: 9466 due_date: '2021-09-14 12:24:45.836767' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9d4925443f1537e07258140930489565542e48c39e3f9e48dd982bfae64cb759 created_at: '2021-06-14 12:24:45.869357' updated_at: '2021-06-14 12:24:45.872088' @@ -60,12 +56,11 @@ payment_schedule_item_109: amount: 9466 due_date: '2021-10-14 12:24:45.836900' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 157ff90f880ebc5532be14898da65dcfc227fa54aaadc37a1f123dbeefa32640 created_at: '2021-06-14 12:24:45.875500' updated_at: '2021-06-14 12:24:45.879057' @@ -74,12 +69,11 @@ payment_schedule_item_110: amount: 9466 due_date: '2021-11-14 12:24:45.837025' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9b162c2b342d8c82e9163202a22a405b879d4b2ad2409a61ad10942f743bc576 created_at: '2021-06-14 12:24:45.882343' updated_at: '2021-06-14 12:24:45.884709' @@ -88,12 +82,11 @@ payment_schedule_item_111: amount: 9466 due_date: '2021-12-14 12:24:45.837025' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9b162c2b342d8c82e9163202a22a405b879d4b2ad2409a61ad10942f743bc576 created_at: '2021-06-14 12:24:45.882343' updated_at: '2021-06-14 12:24:45.884709' @@ -102,12 +95,11 @@ payment_schedule_item_112: amount: 9466 due_date: '2022-01-14 12:24:45.837025' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9b162c2b342d8c82e9163202a22a405b879d4b2ad2409a61ad10942f743bc576 created_at: '2021-06-14 12:24:45.882343' updated_at: '2021-06-14 12:24:45.884709' @@ -116,12 +108,11 @@ payment_schedule_item_113: amount: 9466 due_date: '2022-02-14 12:24:45.837025' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9b162c2b342d8c82e9163202a22a405b879d4b2ad2409a61ad10942f743bc576 created_at: '2021-06-14 12:24:45.882343' updated_at: '2021-06-14 12:24:45.884709' @@ -130,12 +121,11 @@ payment_schedule_item_114: amount: 9466 due_date: '2022-03-14 12:24:45.837025' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9b162c2b342d8c82e9163202a22a405b879d4b2ad2409a61ad10942f743bc576 created_at: '2021-06-14 12:24:45.882343' updated_at: '2021-06-14 12:24:45.884709' @@ -144,12 +134,11 @@ payment_schedule_item_115: amount: 9466 due_date: '2022-04-14 12:24:45.837025' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9b162c2b342d8c82e9163202a22a405b879d4b2ad2409a61ad10942f743bc576 created_at: '2021-06-14 12:24:45.882343' updated_at: '2021-06-14 12:24:45.884709' @@ -158,180 +147,167 @@ payment_schedule_item_116: amount: 9466 due_date: '2022-05-14 12:24:45.837025' state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 12 invoice_id: - footprint: 9b162c2b342d8c82e9163202a22a405b879d4b2ad2409a61ad10942f743bc576 created_at: '2021-06-14 12:24:45.882343' updated_at: '2021-06-14 12:24:45.884709' payment_schedule_item_117: id: 117 amount: 9474 - due_date: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466, "adjustment": 8, "other_items": 0}' + details: {"recurring": 9466, "adjustment": 8, "other_items": 0} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_118: id: 118 amount: 9466 - due_date: <%= 8.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 8.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_119: id: 119 amount: 9466 - due_date: <%= 7.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 7.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_120: id: 120 amount: 9466 - due_date: <%= 6.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 6.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_121: id: 121 amount: 9466 - due_date: <%= 5.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 5.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_122: id: 122 amount: 9466 - due_date: <%= 4.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 4.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_123: id: 123 amount: 9466 - due_date: <%= 3.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 3.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_124: id: 124 amount: 9466 - due_date: <%= 2.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 2.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_125: id: 125 amount: 9466 - due_date: <%= 1.month.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 1.month.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: paid - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: card client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_126: id: 126 amount: 9466 - due_date: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= DateTime.current.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_127: id: 127 amount: 9466 - due_date: <%= 1.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 1.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> payment_schedule_item_128: id: 128 amount: 9466 - due_date: <%= 2.months.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + due_date: <%= 2.months.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> state: new - details: '{"recurring": 9466}' + details: {"recurring": 9466} payment_method: client_secret: payment_schedule_id: 13 invoice_id: - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> diff --git a/test/fixtures/payment_schedule_objects.yml b/test/fixtures/payment_schedule_objects.yml index 78b92dc18..9b67a8baa 100644 --- a/test/fixtures/payment_schedule_objects.yml +++ b/test/fixtures/payment_schedule_objects.yml @@ -4,7 +4,6 @@ payment_schedule_object_10: object_id: 5 payment_schedule_id: 12 main: true - footprint: a1ef3a0c3abac7e02bc11193458c0d1e90a5acf290c9e3b4e7c049a7efcbeb30 created_at: '2021-06-14 12:24:45.890373' updated_at: '2021-06-14 12:24:45.894701' @@ -14,6 +13,5 @@ payment_schedule_object_11: object_id: 6 payment_schedule_id: 13 main: true - footprint: fakefakefakefakefakefake - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> diff --git a/test/fixtures/payment_schedules.yml b/test/fixtures/payment_schedules.yml index 7e7495b65..c85767667 100644 --- a/test/fixtures/payment_schedules.yml +++ b/test/fixtures/payment_schedules.yml @@ -6,13 +6,13 @@ payment_schedule_12: wallet_amount: wallet_transaction_id: coupon_id: - footprint: d4b66236895cdf18e21f64429a388050407f29bc228141ed95c89686b7daa716 environment: development invoicing_profile_id: 9 statistic_profile_id: 9 operator_profile_id: 1 created_at: '2021-06-14 12:24:45.843714' updated_at: '2021-06-14 12:24:45.908386' + order_number: 000007-06-21 payment_schedule_13: id: 13 @@ -22,10 +22,10 @@ payment_schedule_13: wallet_amount: wallet_transaction_id: coupon_id: - footprint: fakefakefakefakefakefake environment: development invoicing_profile_id: 10 statistic_profile_id: 10 operator_profile_id: 10 - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + order_number: <%= 9.months.ago.utc.strftime('000008-%m-%y') %> diff --git a/test/fixtures/slots.yml b/test/fixtures/slots.yml index 63bb121ed..451df709d 100644 --- a/test/fixtures/slots.yml +++ b/test/fixtures/slots.yml @@ -19,8 +19,8 @@ slot_2: slot_9: id: 9 - start_at: <%= DateTime.current.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.880751' updated_at: '2022-07-12 15:18:43.880751' availability_id: 3 @@ -28,8 +28,8 @@ slot_9: slot_10: id: 10 - start_at: <%= DateTime.current.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.882957' updated_at: '2022-07-12 15:18:43.882957' availability_id: 3 @@ -37,8 +37,8 @@ slot_10: slot_11: id: 11 - start_at: <%= DateTime.current.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.884691' updated_at: '2022-07-12 15:18:43.884691' availability_id: 3 @@ -46,8 +46,8 @@ slot_11: slot_12: id: 12 - start_at: <%= DateTime.current.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.886431' updated_at: '2022-07-12 15:18:43.886431' availability_id: 3 @@ -55,8 +55,8 @@ slot_12: slot_13: id: 13 - start_at: <%= DateTime.current.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.888074' updated_at: '2022-07-12 15:18:43.888074' availability_id: 3 @@ -64,8 +64,8 @@ slot_13: slot_14: id: 14 - start_at: <%= DateTime.current.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.889691' updated_at: '2022-07-12 15:18:43.889691' availability_id: 3 @@ -73,8 +73,8 @@ slot_14: slot_15: id: 15 - start_at: <%= (DateTime.current + 1.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.893096' updated_at: '2022-07-12 15:18:43.893096' availability_id: 4 @@ -82,8 +82,8 @@ slot_15: slot_16: id: 16 - start_at: <%= (DateTime.current + 1.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.894777' updated_at: '2022-07-12 15:18:43.894777' availability_id: 4 @@ -91,8 +91,8 @@ slot_16: slot_17: id: 17 - start_at: <%= (DateTime.current + 1.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.896423' updated_at: '2022-07-12 15:18:43.896423' availability_id: 4 @@ -100,8 +100,8 @@ slot_17: slot_18: id: 18 - start_at: <%= (DateTime.current + 1.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.898021' updated_at: '2022-07-12 15:18:43.898021' availability_id: 4 @@ -109,8 +109,8 @@ slot_18: slot_19: id: 19 - start_at: <%= (DateTime.current + 1.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.899592' updated_at: '2022-07-12 15:18:43.899592' availability_id: 4 @@ -118,8 +118,8 @@ slot_19: slot_20: id: 20 - start_at: <%= (DateTime.current + 1.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.900938' updated_at: '2022-07-12 15:18:43.900938' availability_id: 4 @@ -127,8 +127,8 @@ slot_20: slot_21: id: 21 - start_at: <%= (DateTime.current + 2.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.904013' updated_at: '2022-07-12 15:18:43.904013' availability_id: 5 @@ -136,8 +136,8 @@ slot_21: slot_22: id: 22 - start_at: <%= (DateTime.current + 2.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.905470' updated_at: '2022-07-12 15:18:43.905470' availability_id: 5 @@ -145,8 +145,8 @@ slot_22: slot_23: id: 23 - start_at: <%= (DateTime.current + 2.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.907030' updated_at: '2022-07-12 15:18:43.907030' availability_id: 5 @@ -154,8 +154,8 @@ slot_23: slot_24: id: 24 - start_at: <%= (DateTime.current + 2.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.908585' updated_at: '2022-07-12 15:18:43.908585' availability_id: 5 @@ -163,8 +163,8 @@ slot_24: slot_25: id: 25 - start_at: <%= (DateTime.current + 2.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.910138' updated_at: '2022-07-12 15:18:43.910138' availability_id: 5 @@ -172,8 +172,8 @@ slot_25: slot_26: id: 26 - start_at: <%= (DateTime.current + 2.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.911643' updated_at: '2022-07-12 15:18:43.911643' availability_id: 5 @@ -181,8 +181,8 @@ slot_26: slot_27: id: 27 - start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.914664' updated_at: '2022-07-12 15:18:43.914664' availability_id: 6 @@ -190,8 +190,8 @@ slot_27: slot_28: id: 28 - start_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.916047' updated_at: '2022-07-12 15:18:43.916047' availability_id: 6 @@ -199,8 +199,8 @@ slot_28: slot_29: id: 29 - start_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.917304' updated_at: '2022-07-12 15:18:43.917304' availability_id: 6 @@ -208,8 +208,8 @@ slot_29: slot_30: id: 30 - start_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.918798' updated_at: '2022-07-12 15:18:43.918798' availability_id: 6 @@ -217,8 +217,8 @@ slot_30: slot_31: id: 31 - start_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.920194' updated_at: '2022-07-12 15:18:43.920194' availability_id: 6 @@ -226,8 +226,8 @@ slot_31: slot_32: id: 32 - start_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.921662' updated_at: '2022-07-12 15:18:43.921662' availability_id: 6 @@ -235,8 +235,8 @@ slot_32: slot_33: id: 33 - start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.924285' updated_at: '2022-07-12 15:18:43.924285' availability_id: 7 @@ -244,8 +244,8 @@ slot_33: slot_34: id: 34 - start_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.925669' updated_at: '2022-07-12 15:18:43.925669' availability_id: 7 @@ -253,8 +253,8 @@ slot_34: slot_35: id: 35 - start_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.927038' updated_at: '2022-07-12 15:18:43.927038' availability_id: 7 @@ -262,8 +262,8 @@ slot_35: slot_36: id: 36 - start_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.928407' updated_at: '2022-07-12 15:18:43.928407' availability_id: 7 @@ -271,8 +271,8 @@ slot_36: slot_37: id: 37 - start_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.929907' updated_at: '2022-07-12 15:18:43.929907' availability_id: 7 @@ -280,8 +280,8 @@ slot_37: slot_38: id: 38 - start_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 3.day).change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 3.day).change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.931295' updated_at: '2022-07-12 15:18:43.931295' availability_id: 7 @@ -334,8 +334,8 @@ slot_43: slot_44: id: 44 - start_at: <%= 20.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 20.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 20.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 20.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.942392' updated_at: '2022-07-12 15:18:43.942392' availability_id: 14 @@ -343,8 +343,8 @@ slot_44: slot_45: id: 45 - start_at: <%= 20.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 20.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 20.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 20.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.943779' updated_at: '2022-07-12 15:18:43.943779' availability_id: 14 @@ -352,8 +352,8 @@ slot_45: slot_46: id: 46 - start_at: <%= 20.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 20.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 20.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 20.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.945154' updated_at: '2022-07-12 15:18:43.945154' availability_id: 14 @@ -361,8 +361,8 @@ slot_46: slot_47: id: 47 - start_at: <%= 20.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 20.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 20.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 20.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.946515' updated_at: '2022-07-12 15:18:43.946515' availability_id: 14 @@ -370,8 +370,8 @@ slot_47: slot_48: id: 48 - start_at: <%= 40.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 40.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 40.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 40.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.949178' updated_at: '2022-07-12 15:18:43.949178' availability_id: 15 @@ -379,8 +379,8 @@ slot_48: slot_49: id: 49 - start_at: <%= 40.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 40.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 40.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 40.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.950348' updated_at: '2022-07-12 15:18:43.950348' availability_id: 15 @@ -388,8 +388,8 @@ slot_49: slot_50: id: 50 - start_at: <%= 40.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 40.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 40.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 40.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.951535' updated_at: '2022-07-12 15:18:43.951535' availability_id: 15 @@ -397,8 +397,8 @@ slot_50: slot_51: id: 51 - start_at: <%= 40.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 40.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 40.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 40.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.952864' updated_at: '2022-07-12 15:18:43.952864' availability_id: 15 @@ -406,8 +406,8 @@ slot_51: slot_52: id: 52 - start_at: <%= 80.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 80.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 80.days.from_now.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 80.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.955443' updated_at: '2022-07-12 15:18:43.955443' availability_id: 16 @@ -415,8 +415,8 @@ slot_52: slot_53: id: 53 - start_at: <%= 80.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 80.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 80.days.from_now.change({:hour => 7}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 80.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.956657' updated_at: '2022-07-12 15:18:43.956657' availability_id: 16 @@ -424,8 +424,8 @@ slot_53: slot_54: id: 54 - start_at: <%= 80.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 80.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 80.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 80.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.957811' updated_at: '2022-07-12 15:18:43.957811' availability_id: 16 @@ -433,8 +433,8 @@ slot_54: slot_55: id: 55 - start_at: <%= 80.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 80.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 80.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 80.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.959063' updated_at: '2022-07-12 15:18:43.959063' availability_id: 16 @@ -442,8 +442,8 @@ slot_55: slot_56: id: 56 - start_at: <%= 10.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 12.days.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 10.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 12.days.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:43.961319' updated_at: '2022-07-12 15:18:43.961319' availability_id: 17 @@ -451,8 +451,8 @@ slot_56: slot_112: id: 112 - start_at: <%= 2.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 2.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 2.days.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 2.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.038089' updated_at: '2022-07-12 15:18:44.038089' availability_id: 18 @@ -460,8 +460,8 @@ slot_112: slot_113: id: 113 - start_at: <%= 2.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 2.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 2.days.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 2.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.039392' updated_at: '2022-07-12 15:18:44.039392' availability_id: 18 @@ -469,8 +469,8 @@ slot_113: slot_114: id: 114 - start_at: <%= 2.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 2.days.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 2.days.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 2.days.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.040522' updated_at: '2022-07-12 15:18:44.040522' availability_id: 18 @@ -478,8 +478,8 @@ slot_114: slot_115: id: 115 - start_at: <%= 2.days.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 2.days.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 2.days.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 2.days.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.041937' updated_at: '2022-07-12 15:18:44.041937' availability_id: 18 @@ -487,8 +487,8 @@ slot_115: slot_116: id: 116 - start_at: <%= 1.day.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.044421' updated_at: '2022-07-12 15:18:44.044421' availability_id: 19 @@ -496,8 +496,8 @@ slot_116: slot_117: id: 117 - start_at: <%= 1.day.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 9}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.045689' updated_at: '2022-07-12 15:18:44.045689' availability_id: 19 @@ -505,8 +505,8 @@ slot_117: slot_118: id: 118 - start_at: <%= 1.day.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.047009' updated_at: '2022-07-12 15:18:44.047009' availability_id: 19 @@ -514,8 +514,8 @@ slot_118: slot_119: id: 119 - start_at: <%= 1.day.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 11}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.048272' updated_at: '2022-07-12 15:18:44.048272' availability_id: 19 @@ -523,8 +523,8 @@ slot_119: slot_120: id: 120 - start_at: <%= 1.day.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 12}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.049599' updated_at: '2022-07-12 15:18:44.049599' availability_id: 19 @@ -532,8 +532,8 @@ slot_120: slot_121: id: 121 - start_at: <%= 1.day.from_now.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 13}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.050947' updated_at: '2022-07-12 15:18:44.050947' availability_id: 19 @@ -541,8 +541,8 @@ slot_121: slot_122: id: 122 - start_at: <%= 1.day.from_now.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 14}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.052817' updated_at: '2022-07-12 15:18:44.052817' availability_id: 19 @@ -550,8 +550,8 @@ slot_122: slot_123: id: 123 - start_at: <%= 1.day.from_now.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 15}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.054966' updated_at: '2022-07-12 15:18:44.054966' availability_id: 19 @@ -559,8 +559,8 @@ slot_123: slot_124: id: 124 - start_at: <%= 1.day.from_now.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 16}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.057217' updated_at: '2022-07-12 15:18:44.057217' availability_id: 19 @@ -568,8 +568,8 @@ slot_124: slot_125: id: 125 - start_at: <%= 1.day.from_now.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 1.day.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.day.from_now.change({:hour => 17}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 1.day.from_now.change({:hour => 18}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.059135' updated_at: '2022-07-12 15:18:44.059135' availability_id: 19 @@ -577,8 +577,8 @@ slot_125: slot_126: id: 126 - start_at: <%= DateTime.current.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= DateTime.current.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= DateTime.current.change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= DateTime.current.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.061887' updated_at: '2022-07-12 15:18:44.061887' availability_id: 1 @@ -586,8 +586,8 @@ slot_126: slot_127: id: 127 - start_at: <%= (DateTime.current + 1.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 1.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 1.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 1.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.063528' updated_at: '2022-07-12 15:18:44.063528' availability_id: 2 @@ -595,8 +595,8 @@ slot_127: slot_128: id: 128 - start_at: <%= (DateTime.current + 2.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (DateTime.current + 2.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= (DateTime.current + 2.day).change({:hour => 6}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (DateTime.current + 2.day).change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-12 15:18:44.065114' updated_at: '2022-07-12 15:18:44.065114' availability_id: 8 @@ -631,8 +631,8 @@ slot_131: slot_132: id: 132 - start_at: <%= 10.days.ago.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 10.days.ago.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 10.days.ago.change({:hour => 8}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 10.days.ago.change({:hour => 10}).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-07-18 12:38:21.616510' updated_at: '2022-07-18 12:38:21.616510' availability_id: 20 @@ -640,8 +640,8 @@ slot_132: slot_133: id: 133 - start_at: <%= 10.minutes.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= (10.minutes.from_now + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 10.minutes.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= (10.minutes.from_now + 1.hour).strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: '2022-12-14 12:01:26.165110' updated_at: '2022-12-14 12:01:26.165110' availability_id: 21 @@ -649,8 +649,8 @@ slot_133: slot_134: id: 134 - start_at: <%= 1.hour.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - end_at: <%= 2.hours.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + start_at: <%= 1.hour.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + end_at: <%= 2.hours.from_now.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> created_at: 2023-01-24 13:34:43.841240000 Z updated_at: 2023-01-24 13:34:43.841240000 Z availability_id: 22 diff --git a/test/fixtures/statistic_profile_prepaid_packs.yml b/test/fixtures/statistic_profile_prepaid_packs.yml index 987890d48..dff69e45a 100644 --- a/test/fixtures/statistic_profile_prepaid_packs.yml +++ b/test/fixtures/statistic_profile_prepaid_packs.yml @@ -4,10 +4,10 @@ statistic_profile_prepaid_pack_1: prepaid_pack_id: 1 statistic_profile_id: 10 minutes_used: 600 - expires_at: <%= 11.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + expires_at: <%= 11.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> statistic_profile_prepaid_pack_2: prepaid_pack_id: 1 statistic_profile_id: 10 minutes_used: 0 - expires_at: <%= 12.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + expires_at: <%= 12.month.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> diff --git a/test/fixtures/subscriptions.yml b/test/fixtures/subscriptions.yml index 711644d4c..667336023 100644 --- a/test/fixtures/subscriptions.yml +++ b/test/fixtures/subscriptions.yml @@ -3,18 +3,18 @@ subscription_1: id: 1 plan_id: 2 statistic_profile_id: 3 - created_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - expiration_date: <%= (1.month.from_now - 11.days).utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - canceled_at: <%= (10.days.ago + 1.minute).utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + expiration_date: <%= (1.month.from_now - 11.days).utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + canceled_at: <%= (10.days.ago + 1.minute).utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> subscription_2: id: 2 plan_id: 3 statistic_profile_id: 4 - created_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - expiration_date: <%= (1.month.from_now - 11.days).utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 10.days.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + expiration_date: <%= (1.month.from_now - 11.days).utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> canceled_at: # subscription has expired (do not change dates) @@ -50,7 +50,7 @@ subscription_6: id: 6 plan_id: 4 statistic_profile_id: 10 - created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> - expiration_date: <%= 3.months.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %> + created_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + updated_at: <%= 9.months.ago.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> + expiration_date: <%= 3.months.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') %> canceled_at: diff --git a/test/helpers/auth_provider_helper.rb b/test/helpers/auth_provider_helper.rb index 7ba055a8d..07d6fb6ab 100644 --- a/test/helpers/auth_provider_helper.rb +++ b/test/helpers/auth_provider_helper.rb @@ -41,7 +41,7 @@ module AuthProviderHelper issuer: 'https://sso.sleede.dev/auth/realms/master', discovery: true, client_auth_method: 'basic', - scope: %w[openid profile email toto], + scope: %w[openid profile email], prompt: 'consent', send_scope_to_token_endpoint: true, profile_url: 'https://sso.sleede.dev/auth/realms/master/account/', diff --git a/test/helpers/invoice_helper.rb b/test/helpers/invoice_helper.rb index d63ed0f9b..37fb32ae1 100644 --- a/test/helpers/invoice_helper.rb +++ b/test/helpers/invoice_helper.rb @@ -42,6 +42,7 @@ module InvoiceHelper ) reservation.save invoice = Invoice.new( + total: 1000, invoicing_profile: customer.invoicing_profile, statistic_profile: customer.statistic_profile, operator_profile: operator.invoicing_profile, diff --git a/test/integration/abuses_test.rb b/test/integration/abuses_test.rb index 827e6f0ec..913ff44ec 100644 --- a/test/integration/abuses_test.rb +++ b/test/integration/abuses_test.rb @@ -22,7 +22,7 @@ class AbusesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct object was signaled abuse = json_response(response.body) @@ -67,7 +67,7 @@ class AbusesTest < ActionDispatch::IntegrationTest get '/api/abuses' # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the abuses abuses = json_response(response.body) diff --git a/test/integration/accounting_period_test.rb b/test/integration/accounting_period_test.rb index 7deee6c8b..585f8ce72 100644 --- a/test/integration/accounting_period_test.rb +++ b/test/integration/accounting_period_test.rb @@ -22,7 +22,7 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct period was closed successfully period = json_response(response.body) @@ -49,10 +49,10 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 422, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # check the error - assert_match(/#{I18n.t('errors.messages.invalid_duration', DAYS: diff)}/, response.body) + assert_match(/#{I18n.t('errors.messages.invalid_duration', **{ DAYS: diff })}/, response.body) end test 'admin tries to close an overlapping period' do @@ -69,7 +69,7 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 422, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # check the error assert_match(/#{I18n.t('errors.messages.cannot_overlap')}/, response.body) @@ -89,7 +89,7 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 422, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # check the error assert_match(/#{I18n.t('errors.messages.must_be_in_the_past')}/, response.body) @@ -99,7 +99,7 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest get '/api/accounting_periods/last_closing_end' assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type resp = json_response(response.body) period_end = AccountingPeriod.first.end_at @@ -117,7 +117,7 @@ class AccountingPeriodTest < ActionDispatch::IntegrationTest get '/api/accounting_periods' # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the periods periods = json_response(response.body) diff --git a/test/integration/admins_test.rb b/test/integration/admins_test.rb index ccc505bf6..fb65ebaed 100644 --- a/test/integration/admins_test.rb +++ b/test/integration/admins_test.rb @@ -36,7 +36,7 @@ class AdminsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct admin was created admin = json_response(response.body) @@ -52,7 +52,7 @@ class AdminsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok admins = json_response(response.body) diff --git a/test/integration/age_ranges_test.rb b/test/integration/age_ranges_test.rb index d79adf7bb..72a7f188a 100644 --- a/test/integration/age_ranges_test.rb +++ b/test/integration/age_ranges_test.rb @@ -17,7 +17,7 @@ class AgeRangesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct age range was created res = json_response(response.body) @@ -36,7 +36,7 @@ class AgeRangesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the age range was updated res = json_response(response.body) @@ -49,7 +49,7 @@ class AgeRangesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok ranges = json_response(response.body) diff --git a/test/integration/analytics_test.rb b/test/integration/analytics_test.rb index a5f456f9a..7d4de015e 100644 --- a/test/integration/analytics_test.rb +++ b/test/integration/analytics_test.rb @@ -15,7 +15,7 @@ class AnalyticsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the resulting data was created res = json_response(response.body) diff --git a/test/integration/auth_providers_test.rb b/test/integration/auth_providers_test.rb index 372c31dc8..f7474ab7f 100644 --- a/test/integration/auth_providers_test.rb +++ b/test/integration/auth_providers_test.rb @@ -9,10 +9,13 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest def setup @admin = User.find_by(username: 'admin') login_as(@admin, scope: :user) - Fablab::Application.load_tasks if Rake::Task.tasks.empty? + FabManager::Application.load_tasks if Rake::Task.tasks.empty? end test 'create an auth external provider and activate it' do + # clean any existing auth provider config + FileUtils.rm('config/auth_provider.yml', force: true) + name = 'GitHub' post '/api/auth_providers', params: { @@ -22,7 +25,7 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the provider was correctly created db_provider = OAuth2Provider.includes(:auth_provider).where('auth_providers.name': name).first&.auth_provider @@ -40,9 +43,18 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest db_provider&.reload assert_equal 'active', db_provider&.status assert_equal AuthProvider.active.id, db_provider&.id - User.all.each do |u| + User.find_each do |u| assert_not_nil u.auth_token end + + # Check the configuration file + assert File.exist?('config/auth_provider.yml') + config = ProviderConfig.new + assert_equal 'OAuth2Provider', config.providable_type + assert_equal name, config.name + + # clean test provider config + FileUtils.rm('config/auth_provider.yml', force: true) end test 'update an authentication provider' do @@ -61,7 +73,7 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type provider.reload @@ -91,7 +103,7 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the answer res = json_response(response.body) @@ -104,7 +116,7 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the provider res = json_response(response.body) @@ -116,7 +128,7 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest get '/api/auth_providers/mapping_fields' assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the returned fields res = json_response(response.body) @@ -130,7 +142,7 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest get '/api/auth_providers/active' assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the returned fields res = json_response(response.body) @@ -153,7 +165,7 @@ class AuthProvidersTest < ActionDispatch::IntegrationTest headers: default_headers assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # check resulting notification notification = Notification.find_by( diff --git a/test/integration/availabilities/as_admin_test.rb b/test/integration/availabilities/as_admin_test.rb index 891e042fd..524d55fa1 100644 --- a/test/integration/availabilities/as_admin_test.rb +++ b/test/integration/availabilities/as_admin_test.rb @@ -18,7 +18,7 @@ class Availabilities::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availability was returned availability = json_response(response.body) @@ -37,7 +37,7 @@ class Availabilities::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) @@ -61,7 +61,7 @@ class Availabilities::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) @@ -83,7 +83,7 @@ class Availabilities::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) @@ -121,7 +121,7 @@ class Availabilities::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the id availability = json_response(response.body) diff --git a/test/integration/availabilities/as_public_test.rb b/test/integration/availabilities/as_public_test.rb index c8dd3fd62..1b99204d9 100644 --- a/test/integration/availabilities/as_public_test.rb +++ b/test/integration/availabilities/as_public_test.rb @@ -11,7 +11,7 @@ class Availabilities::AsPublicTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) @@ -33,7 +33,7 @@ class Availabilities::AsPublicTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) @@ -48,7 +48,7 @@ class Availabilities::AsPublicTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) @@ -69,7 +69,7 @@ class Availabilities::AsPublicTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) @@ -90,7 +90,7 @@ class Availabilities::AsPublicTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) diff --git a/test/integration/availabilities/as_user_test.rb b/test/integration/availabilities/as_user_test.rb index 817198602..5a81e9fe3 100644 --- a/test/integration/availabilities/as_user_test.rb +++ b/test/integration/availabilities/as_user_test.rb @@ -20,7 +20,7 @@ class Availabilities::AsUserTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct availabilities was returned availabilities = json_response(response.body) diff --git a/test/integration/availabilities/update_test.rb b/test/integration/availabilities/update_test.rb index 2c03f23cd..43ec7ad66 100644 --- a/test/integration/availabilities/update_test.rb +++ b/test/integration/availabilities/update_test.rb @@ -24,7 +24,7 @@ class Availabilities::UpdateTest < ActionDispatch::IntegrationTest } assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type res = json_response(response.body) assert_not_includes res[:machine_ids], machine.id diff --git a/test/integration/categories_test.rb b/test/integration/categories_test.rb index c27e4c2c7..856dad811 100644 --- a/test/integration/categories_test.rb +++ b/test/integration/categories_test.rb @@ -17,7 +17,7 @@ class CategoriesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct category was created res = json_response(response.body) @@ -36,7 +36,7 @@ class CategoriesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the category was updated res = json_response(response.body) @@ -49,7 +49,7 @@ class CategoriesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok cats = json_response(response.body) diff --git a/test/integration/components_test.rb b/test/integration/components_test.rb index edeec1d08..8073b8999 100644 --- a/test/integration/components_test.rb +++ b/test/integration/components_test.rb @@ -17,7 +17,7 @@ class ComponentsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct component was created res = json_response(response.body) @@ -36,7 +36,7 @@ class ComponentsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the component was updated res = json_response(response.body) @@ -49,7 +49,7 @@ class ComponentsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok comps = json_response(response.body) diff --git a/test/integration/credits/machine_test.rb b/test/integration/credits/machine_test.rb index 670bc5e44..5a28e75e7 100644 --- a/test/integration/credits/machine_test.rb +++ b/test/integration/credits/machine_test.rb @@ -2,64 +2,64 @@ require 'test_helper' -module Credits - class TrainingTest < ActionDispatch::IntegrationTest - # Called before every test method runs. Can be used - # to set up fixture information. - def setup - admin = User.with_role(:admin).first - login_as(admin, scope: :user) - end +module Credits; end - test 'create machine credit' do - # First, we create a new credit - post '/api/credits', - params: { - credit: { - creditable_id: 5, - creditable_type: 'Machine', - hours: 1, - plan_id: 1 - } - }.to_json, - headers: default_headers +class Credits::TrainingTest < ActionDispatch::IntegrationTest + # Called before every test method runs. Can be used + # to set up fixture information. + def setup + admin = User.with_role(:admin).first + login_as(admin, scope: :user) + end - # Check response format & status - assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + test 'create machine credit' do + # First, we create a new credit + post '/api/credits', + params: { + credit: { + creditable_id: 5, + creditable_type: 'Machine', + hours: 1, + plan_id: 1 + } + }.to_json, + headers: default_headers - # Check the credit was created correctly - credit = json_response(response.body) - c = Credit.where(id: credit[:id]).first - assert_not_nil c, 'Credit was not created in database' + # Check response format & status + assert_equal 201, response.status, response.body + assert_match Mime[:json].to_s, response.content_type - # Check that 1 hour is associated with the credit - assert_equal 1, c.hours - end + # Check the credit was created correctly + credit = json_response(response.body) + c = Credit.where(id: credit[:id]).first + assert_not_nil c, 'Credit was not created in database' - test 'update a credit' do - put '/api/credits/13', - params: { - credit: { - creditable_id: 4, - creditable_type: 'Machine', - hours: 5, - plan_id: 3 - } - }.to_json, - headers: default_headers + # Check that 1 hour is associated with the credit + assert_equal 1, c.hours + end - # Check response format & status - assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + test 'update a credit' do + put '/api/credits/13', + params: { + credit: { + creditable_id: 4, + creditable_type: 'Machine', + hours: 5, + plan_id: 3 + } + }.to_json, + headers: default_headers - # Check the credit was correctly updated - credit = json_response(response.body) - assert_equal 13, credit[:id] - c = Credit.find(credit[:id]) - assert c.updated_at > 1.minute.ago + # Check response format & status + assert_equal 200, response.status, response.body + assert_match Mime[:json].to_s, response.content_type - assert_equal 5, c.hours - end + # Check the credit was correctly updated + credit = json_response(response.body) + assert_equal 13, credit[:id] + c = Credit.find(credit[:id]) + assert c.updated_at > 1.minute.ago + + assert_equal 5, c.hours end end diff --git a/test/integration/credits/training_test.rb b/test/integration/credits/training_test.rb index 55d3059b9..552a5ced2 100644 --- a/test/integration/credits/training_test.rb +++ b/test/integration/credits/training_test.rb @@ -2,54 +2,54 @@ require 'test_helper' -module Credits - class TrainingTest < ActionDispatch::IntegrationTest - # Called before every test method runs. Can be used - # to set up fixture information. - def setup - admin = User.with_role(:admin).first - login_as(admin, scope: :user) - end +module Credits; end - test 'create training credit' do - # First, we create a new credit - post '/api/credits', - params: { - credit: { - creditable_id: 4, - creditable_type: 'Training', - plan_id: '1' - } - }.to_json, - headers: default_headers +class Credits::TrainingTest < ActionDispatch::IntegrationTest + # Called before every test method runs. Can be used + # to set up fixture information. + def setup + admin = User.with_role(:admin).first + login_as(admin, scope: :user) + end - # Check response format & status - assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + test 'create training credit' do + # First, we create a new credit + post '/api/credits', + params: { + credit: { + creditable_id: 4, + creditable_type: 'Training', + plan_id: '1' + } + }.to_json, + headers: default_headers - # Check the credit was created correctly - credit = json_response(response.body) - c = Credit.where(id: credit[:id]).first - assert_not_nil c, 'Credit was not created in database' + # Check response format & status + assert_equal 201, response.status, response.body + assert_match Mime[:json].to_s, response.content_type - # Check that no hours were associated with the credit - assert_nil c.hours - end + # Check the credit was created correctly + credit = json_response(response.body) + c = Credit.where(id: credit[:id]).first + assert_not_nil c, 'Credit was not created in database' - test 'create a existing credit' do - post '/api/credits', - params: { - credit: { - creditable_id: 4, - creditable_type: 'Training', - plan_id: '2' - } - }.to_json, - headers: default_headers + # Check that no hours were associated with the credit + assert_nil c.hours + end - # Check response format & status - assert_equal 422, response.status, response.body - assert_equal Mime[:json], response.content_type - end + test 'create a existing credit' do + post '/api/credits', + params: { + credit: { + creditable_id: 4, + creditable_type: 'Training', + plan_id: '2' + } + }.to_json, + headers: default_headers + + # Check response format & status + assert_equal 422, response.status, response.body + assert_match Mime[:json].to_s, response.content_type end end diff --git a/test/integration/credits/user_info_test.rb b/test/integration/credits/user_info_test.rb index 8c6d8be2a..b18c0753f 100644 --- a/test/integration/credits/user_info_test.rb +++ b/test/integration/credits/user_info_test.rb @@ -2,46 +2,46 @@ require 'test_helper' -module Credits - class UserInfoTest < ActionDispatch::IntegrationTest - def setup - @user_without_subscription = User.find_by(username: 'lseguin') - @user_with_subscription = User.find_by(username: 'kdumas') - end +module Credits; end - test 'user fetch her credits info' do - login_as(@user_with_subscription, scope: :user) - get "/api/credits/user/#{@user_with_subscription.id}/Machine" +class Credits::UserInfoTest < ActionDispatch::IntegrationTest + def setup + @user_without_subscription = User.find_by(username: 'lseguin') + @user_with_subscription = User.find_by(username: 'kdumas') + end - # Check response format & status - assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + test 'user fetch her credits info' do + login_as(@user_with_subscription, scope: :user) + get "/api/credits/user/#{@user_with_subscription.id}/Machine" - # Check the correct credits was returned - credits = json_response(response.body) - assert_equal @user_with_subscription.subscribed_plan.credits.where(creditable_type: 'Machine').count, - credits.length, - 'not all credits were returned' - end + # Check response format & status + assert_equal 200, response.status + assert_match Mime[:json].to_s, response.content_type - test 'user without credits fetch his credits info' do - login_as(@user_without_subscription, scope: :user) - get "/api/credits/user/#{@user_without_subscription.id}/Machine" + # Check the correct credits was returned + credits = json_response(response.body) + assert_equal @user_with_subscription.subscribed_plan.credits.where(creditable_type: 'Machine').count, + credits.length, + 'not all credits were returned' + end - # Check response format & status - assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + test 'user without credits fetch his credits info' do + login_as(@user_without_subscription, scope: :user) + get "/api/credits/user/#{@user_without_subscription.id}/Machine" - # Check the correct credits was returned - credits = json_response(response.body) - assert_equal 0, credits.length, 'unexpected credits returned' - end + # Check response format & status + assert_equal 200, response.status + assert_match Mime[:json].to_s, response.content_type - test 'user tries to fetch credits info from another user' do - login_as(@user_without_subscription, scope: :user) - get "/api/credits/user/#{@user_with_subscription.id}/Machine" + # Check the correct credits was returned + credits = json_response(response.body) + assert_equal 0, credits.length, 'unexpected credits returned' + end - assert_equal 403, response.status - end + test 'user tries to fetch credits info from another user' do + login_as(@user_without_subscription, scope: :user) + get "/api/credits/user/#{@user_with_subscription.id}/Machine" + + assert_equal 403, response.status end end diff --git a/test/integration/event_themes_test.rb b/test/integration/event_themes_test.rb index 1422be021..9c41b748c 100644 --- a/test/integration/event_themes_test.rb +++ b/test/integration/event_themes_test.rb @@ -17,7 +17,7 @@ class EventThemesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct event theme was created res = json_response(response.body) @@ -36,7 +36,7 @@ class EventThemesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the event theme was updated res = json_response(response.body) @@ -49,7 +49,7 @@ class EventThemesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok themes = json_response(response.body) diff --git a/test/integration/events/as_admin_test.rb b/test/integration/events/as_admin_test.rb index 33672f351..e4d721ed4 100644 --- a/test/integration/events/as_admin_test.rb +++ b/test/integration/events/as_admin_test.rb @@ -29,7 +29,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the event was created correctly event = json_response(response.body) @@ -57,7 +57,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the places numbers were updated successfully e = Event.where(id: event[:id]).first @@ -88,7 +88,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the remaining places were updated successfully e = Event.where(id: event[:id]).first @@ -112,7 +112,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the places numbers were updated successfully e = Event.where(id: event[:id]).first @@ -148,7 +148,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the event was created correctly event = json_response(response.body) @@ -190,7 +190,7 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the reservation match the required event result = json_response(response.body) @@ -205,7 +205,6 @@ class Events::AsAdminTest < ActionDispatch::IntegrationTest # Check the resulting invoice generation and it has right price assert_invoice_pdf i - assert_not_nil i.debug_footprint assert_equal (4 * 20) + (4 * 16), i.total / 100.0 end end diff --git a/test/integration/events/as_user_test.rb b/test/integration/events/as_user_test.rb index 64eecf553..3d0b9b8f4 100644 --- a/test/integration/events/as_user_test.rb +++ b/test/integration/events/as_user_test.rb @@ -93,7 +93,6 @@ class Events::AsUserTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint VCR.use_cassette('reserve_event_with_many_prices_and_payment_means_retrieve_invoice_from_stripe') do stp_intent = invoice.payment_gateway_object.gateway_object.retrieve diff --git a/test/integration/events/delete_test.rb b/test/integration/events/delete_test.rb index 245bc62e6..4799d5d4e 100644 --- a/test/integration/events/delete_test.rb +++ b/test/integration/events/delete_test.rb @@ -16,7 +16,7 @@ class Events::DeleteTest < ActionDispatch::IntegrationTest # Check response format & status assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type res = json_response(response.body) assert_equal 1, res[:deleted] diff --git a/test/integration/events/recurrence_test.rb b/test/integration/events/recurrence_test.rb index 258f66c5c..6069ea00e 100644 --- a/test/integration/events/recurrence_test.rb +++ b/test/integration/events/recurrence_test.rb @@ -17,7 +17,7 @@ class Events::RecurrenceTest < ActionDispatch::IntegrationTest event: { title: name, event_image_attributes: { - attachment: fixture_file_upload('/files/event/Skateboard.jpg') + attachment: fixture_file_upload('event/Skateboard.jpg') }, description: 'Come make you own skatebord from stratch...', start_date: 1.week.from_now.utc, @@ -30,8 +30,8 @@ class Events::RecurrenceTest < ActionDispatch::IntegrationTest recurrence: 'week', recurrence_end_at: 10.weeks.from_now.utc, event_files_attributes: [ - { attachment: fixture_file_upload('/files/document.pdf', 'application/pdf', true) }, - { attachment: fixture_file_upload('/files/document2.pdf', 'application/pdf', true) } + { attachment: fixture_file_upload('document.pdf', 'application/pdf', true) }, + { attachment: fixture_file_upload('document2.pdf', 'application/pdf', true) } ], event_price_categories_attributes: [ { price_category_id: 1, amount: 10 }, @@ -47,7 +47,7 @@ class Events::RecurrenceTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the events were correctly created db_events = Event.where(title: name) @@ -81,7 +81,7 @@ class Events::RecurrenceTest < ActionDispatch::IntegrationTest event: { title: name, event_image_attributes: { - attachment: fixture_file_upload('/files/event/Party.jpg') + attachment: fixture_file_upload('event/Party.jpg') }, description: 'Come party tonight at the fablab...', start_date: 2.weeks.from_now, @@ -99,7 +99,7 @@ class Events::RecurrenceTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the events were correctly created db_events = Event.where(title: name) diff --git a/test/integration/events/recurrence_update_test.rb b/test/integration/events/recurrence_update_test.rb index 81f2f2611..80a843968 100644 --- a/test/integration/events/recurrence_update_test.rb +++ b/test/integration/events/recurrence_update_test.rb @@ -18,7 +18,7 @@ class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest event: { title: name, event_image_attributes: { - attachment: fixture_file_upload('/files/event/Party.jpg') + attachment: fixture_file_upload('event/Party.jpg') }, description: 'Come party tonight at the fablab...', start_date: 2.weeks.from_now, @@ -36,7 +36,7 @@ class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the events were correctly created db_events = Event.where(title: name) @@ -46,13 +46,17 @@ class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest event = db_events.first new_title = 'Skateboard party' new_descr = 'Come make a skateboard tonight at the Fablab' - new_image = '/files/event/Skateboard.jpg' + new_image = 'event/Skateboard.jpg' + new_file = 'document.pdf' put "/api/events/#{event&.id}", params: { event: { title: new_title, event_image_attributes: { attachment: fixture_file_upload(new_image) }, + event_files_attributes: { + '0' => { attachment: fixture_file_upload(new_file) } + }, description: new_descr, category_id: 1, event_theme_ids: [1], @@ -69,7 +73,7 @@ class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest # Check response format & status assert_response :success, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the events were correctly updated res = json_response(response.body) @@ -85,9 +89,13 @@ class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest assert_includes db_event.event_theme_ids, 1 assert_equal 1, db_event.age_range_id assert FileUtils.compare_file( - File.join(ActionDispatch::IntegrationTest.fixture_path, new_image), + File.join(ActionDispatch::IntegrationTest.fixture_path, "files/#{new_image}"), db_event.event_image.attachment.file.path ) + assert FileUtils.compare_file( + File.join(ActionDispatch::IntegrationTest.fixture_path, "files/#{new_file}"), + db_event.event_files[0].attachment.file.path + ) end # Update again but only the next events @@ -114,7 +122,7 @@ class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest # Check response format & status assert_response :success, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the events were correctly updated res = json_response(response.body) @@ -126,7 +134,7 @@ class Events::RecurrenceUpdateTest < ActionDispatch::IntegrationTest db_event = Event.find(res_event[:event][:id]) assert_equal 2, db_event.category_id assert FileUtils.compare_file( - File.join(ActionDispatch::IntegrationTest.fixture_path, new_image), + File.join(ActionDispatch::IntegrationTest.fixture_path, "files/#{new_image}"), db_event.event_image.attachment.file.path ) end diff --git a/test/integration/events/timezone_test.rb b/test/integration/events/timezone_test.rb index b7b5700ea..2c2489e41 100644 --- a/test/integration/events/timezone_test.rb +++ b/test/integration/events/timezone_test.rb @@ -31,7 +31,7 @@ class Events::TimezoneTest < ActionDispatch::IntegrationTest analytical_section: '' }, event_image_attributes: { - attachment: fixture_file_upload('/files/event/Skateboard.jpg') + attachment: fixture_file_upload('event/Skateboard.jpg') } } }.to_json, @@ -39,7 +39,7 @@ class Events::TimezoneTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the event was created correctly event = json_response(response.body) diff --git a/test/integration/exports/accounting_export_test.rb b/test/integration/exports/accounting_export_test.rb index 3056c753c..496bc5e49 100644 --- a/test/integration/exports/accounting_export_test.rb +++ b/test/integration/exports/accounting_export_test.rb @@ -32,7 +32,7 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the export was created correctly res = json_response(response.body) @@ -139,6 +139,7 @@ class Exports::AccountingExportTest < ActionDispatch::IntegrationTest client_code = Setting.get("accounting_payment_#{mean}_code") assert_equal client_code, client_line[I18n.t('accounting_export.account_code')], 'Account code for client is wrong' + # the test above fails randomly... we don't know why! client_label = Setting.get("accounting_payment_#{mean}_label") assert_equal client_label, client_line[I18n.t('accounting_export.account_label')], 'Account label for client is wrong' diff --git a/test/integration/exports/availabilites_export_test.rb b/test/integration/exports/availabilites_export_test.rb index d254509eb..46ca89f05 100644 --- a/test/integration/exports/availabilites_export_test.rb +++ b/test/integration/exports/availabilites_export_test.rb @@ -17,7 +17,7 @@ class Exports::AvailabilitiesExportTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the export was created correctly res = json_response(response.body) @@ -57,4 +57,4 @@ class Exports::AvailabilitiesExportTest < ActionDispatch::IntegrationTest require 'fileutils' FileUtils.rm(e.file) end -end \ No newline at end of file +end diff --git a/test/integration/exports/members_export_test.rb b/test/integration/exports/members_export_test.rb index a2a8f44bd..c15d2117a 100644 --- a/test/integration/exports/members_export_test.rb +++ b/test/integration/exports/members_export_test.rb @@ -17,7 +17,7 @@ class Exports::MembersExportTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the export was created correctly res = json_response(response.body) diff --git a/test/integration/exports/reservations_export_test.rb b/test/integration/exports/reservations_export_test.rb index 942b966b9..f36499ee0 100644 --- a/test/integration/exports/reservations_export_test.rb +++ b/test/integration/exports/reservations_export_test.rb @@ -17,7 +17,7 @@ class Exports::ReservationsExportTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the export was created correctly res = json_response(response.body) @@ -49,4 +49,4 @@ class Exports::ReservationsExportTest < ActionDispatch::IntegrationTest require 'fileutils' FileUtils.rm(e.file) end -end \ No newline at end of file +end diff --git a/test/integration/exports/statistics_export_test.rb b/test/integration/exports/statistics_export_test.rb index 00a5cd4cd..0169aec0c 100644 --- a/test/integration/exports/statistics_export_test.rb +++ b/test/integration/exports/statistics_export_test.rb @@ -17,18 +17,17 @@ class Exports::StatisticsExportTest < ActionDispatch::IntegrationTest ::Statistics::BuilderService.generate_statistic({ start_date: '2015-06-01'.to_date.beginning_of_day, end_date: '2015-06-30'.to_date.end_of_day }) # Create a new export - post '/stats/machine/export', { - params: { - type_key: 'booking', - body: '{"query":{"bool":{"must":[{"term":{"type":"booking"}},{"range":{"date":{"gte":"2015-06-01T02:00:00+02:00",' \ - '"lte":"2015-06-30T23:59:59+02:00"}}}]}},"sort":[{"date":{"order":"desc"}}],"aggs":{"total_ca":{"sum":{"field":"ca"}}, ' \ - '"average_age":{"avg":{"field":"age"}},"total_stat":{"sum":{"field":"stat"}}}}' - } - } + post '/stats/machine/export', + params: { + type_key: 'booking', + body: '{"query":{"bool":{"must":[{"term":{"type":"booking"}},{"range":{"date":{"gte":"2015-06-01T02:00:00+02:00",' \ + '"lte":"2015-06-30T23:59:59+02:00"}}}]}},"sort":[{"date":{"order":"desc"}}],"aggs":{"total_ca":{"sum":{"field":"ca"}}, ' \ + '"average_age":{"avg":{"field":"age"}},"total_stat":{"sum":{"field":"stat"}}}}' + } # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the export was created correctly res = json_response(response.body) @@ -76,16 +75,15 @@ class Exports::StatisticsExportTest < ActionDispatch::IntegrationTest ::Statistics::BuilderService.generate_statistic({ start_date: '2015-06-01'.to_date.beginning_of_day, end_date: '2015-06-30'.to_date.end_of_day }) # Create a new export - post '/stats/global/export', { - params: { - type_key: 'booking', - body: '{"query":{"bool":{"must":[{"range":{"date":{"gte":"2015-06-01T02:00:00+02:00","lte":"2015-06-30T23:59:59+02:00"}}}]}}}' - } - } + post '/stats/global/export', + params: { + type_key: 'booking', + body: '{"query":{"bool":{"must":[{"range":{"date":{"gte":"2015-06-01T02:00:00+02:00","lte":"2015-06-30T23:59:59+02:00"}}}]}}}' + } # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the export was created correctly res = json_response(response.body) diff --git a/test/integration/exports/subscriptions_export_test.rb b/test/integration/exports/subscriptions_export_test.rb index 9129074b3..af9beedd2 100644 --- a/test/integration/exports/subscriptions_export_test.rb +++ b/test/integration/exports/subscriptions_export_test.rb @@ -17,7 +17,7 @@ class Exports::SubscriptionsExportTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the export was created correctly res = json_response(response.body) @@ -49,4 +49,4 @@ class Exports::SubscriptionsExportTest < ActionDispatch::IntegrationTest require 'fileutils' FileUtils.rm(e.file) end -end \ No newline at end of file +end diff --git a/test/integration/groups_test.rb b/test/integration/groups_test.rb index 77e85777c..ad7e1288b 100644 --- a/test/integration/groups_test.rb +++ b/test/integration/groups_test.rb @@ -18,7 +18,7 @@ class GroupsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct group was created res = json_response(response.body) @@ -38,7 +38,7 @@ class GroupsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the group was updated res = json_response(response.body) @@ -51,7 +51,7 @@ class GroupsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok groups = json_response(response.body) diff --git a/test/integration/invoices/as_admin_test.rb b/test/integration/invoices/as_admin_test.rb index e07703c9d..8299834a8 100644 --- a/test/integration/invoices/as_admin_test.rb +++ b/test/integration/invoices/as_admin_test.rb @@ -22,7 +22,7 @@ class InvoicesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check that we have all invoices invoices = json_response(response.body) @@ -49,7 +49,7 @@ class InvoicesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check that the refund match refund = json_response(response.body) diff --git a/test/integration/invoices/round_test.rb b/test/integration/invoices/round_test.rb index 6f3f6d166..f50b48205 100644 --- a/test/integration/invoices/round_test.rb +++ b/test/integration/invoices/round_test.rb @@ -45,7 +45,7 @@ class Invoices::RoundTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # in the invoice, we should have: # - machine reservation = 121 (97, coupon applied) @@ -108,7 +108,7 @@ class Invoices::RoundTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # in the invoice, we should have: # - machine reservation = 1423 (1138, coupon applied) @@ -171,7 +171,7 @@ class Invoices::RoundTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # in the invoice, we should have: # - machine reservation = 121 (99, coupon applied) @@ -234,7 +234,7 @@ class Invoices::RoundTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # in the invoice, we should have: # - machine reservation = 1423 (1277, coupon applied) diff --git a/test/integration/invoices/vat_test.rb b/test/integration/invoices/vat_test.rb index a9d8a64fc..9e388551a 100644 --- a/test/integration/invoices/vat_test.rb +++ b/test/integration/invoices/vat_test.rb @@ -32,14 +32,14 @@ class Invoices::VATTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type invoice = Invoice.last assert_invoice_pdf invoice do |lines| vat_line = I18n.t('invoices.including_VAT_RATE', - RATE: Setting.get('invoice_VAT-rate'), - AMOUNT: number_to_currency(invoice.total / 100.00), - NAME: 'TVQ+TPS') + **{ RATE: Setting.get('invoice_VAT-rate'), + AMOUNT: number_to_currency(invoice.total / 100.00), + NAME: 'TVQ+TPS' }) assert(lines.any? { |l| /#{Regexp.escape(vat_line)}/.match(l) }) end end diff --git a/test/integration/machine_categories_test.rb b/test/integration/machine_categories_test.rb index 4ad8fdc33..f44c55ead 100644 --- a/test/integration/machine_categories_test.rb +++ b/test/integration/machine_categories_test.rb @@ -21,7 +21,7 @@ class MachineCategoriesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the machine category was correctly created category = MachineCategory.where(name: name).first @@ -45,7 +45,7 @@ class MachineCategoriesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the machine category was correctly updated category = MachineCategory.find(1) diff --git a/test/integration/machines_test.rb b/test/integration/machines_test.rb index 1c9f73b32..b2c448f99 100644 --- a/test/integration/machines_test.rb +++ b/test/integration/machines_test.rb @@ -15,13 +15,13 @@ class MachinesTest < ActionDispatch::IntegrationTest machine: { name: name, machine_image_attributes: { - attachment: fixture_file_upload('/files/machines/Laser_cutting_machine.jpg') + attachment: fixture_file_upload('machines/Laser_cutting_machine.jpg') }, description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore...', spec: 'Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium...', machine_files_attributes: [ - { attachment: fixture_file_upload('/files/document.pdf', 'application/pdf', true) }, - { attachment: fixture_file_upload('/files/document2.pdf', 'application/pdf', true) } + { attachment: fixture_file_upload('document.pdf', 'application/pdf', true) }, + { attachment: fixture_file_upload('document2.pdf', 'application/pdf', true) } ], disabled: false, machine_category_id: 1 @@ -31,7 +31,7 @@ class MachinesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the machine was correctly created db_machine = Machine.where(name: name).first @@ -59,7 +59,7 @@ class MachinesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the machine was correctly updated db_machine = Machine.find(3) diff --git a/test/integration/members/as_admin_test.rb b/test/integration/members/as_admin_test.rb index 8a2d08a7e..ddebb1b77 100644 --- a/test/integration/members/as_admin_test.rb +++ b/test/integration/members/as_admin_test.rb @@ -39,7 +39,7 @@ class MembersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check that the user's match user = json_response(response.body) @@ -57,7 +57,7 @@ class MembersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 422, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check error message res = json_response(response.body) @@ -80,7 +80,7 @@ class MembersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check update result res = json_response(response.body) @@ -93,7 +93,7 @@ class MembersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check search result res = json_response(response.body) @@ -114,7 +114,7 @@ class MembersTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check search result res = json_response(response.body) diff --git a/test/integration/members/import_test.rb b/test/integration/members/import_test.rb index a5ec2677c..520197ad1 100644 --- a/test/integration/members/import_test.rb +++ b/test/integration/members/import_test.rb @@ -11,7 +11,7 @@ class ImportTest < ActionDispatch::IntegrationTest end test 'bulk import members through CSV' do - bulk_csv = fixture_file_upload('files/members.csv', 'text/csv') + bulk_csv = fixture_file_upload('members.csv', 'text/csv') post '/api/imports/members', params: { import_members: bulk_csv, @@ -19,7 +19,7 @@ class ImportTest < ActionDispatch::IntegrationTest }, headers: default_headers assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check that the returned import was created import = json_response(response.body) diff --git a/test/integration/members/list_test.rb b/test/integration/members/list_test.rb new file mode 100644 index 000000000..c3bf544d2 --- /dev/null +++ b/test/integration/members/list_test.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ListTest < ActionDispatch::IntegrationTest + def setup + @admin = User.find_by(username: 'admin') + login_as(@admin, scope: :user) + end + + test 'all members' do + post '/api/members/list', params: { query: { + search: '', + order_by: 'id', + page: 1, + size: 20 + } }.to_json, headers: default_headers + + # Check response format & status + assert_equal 200, response.status, response.body + assert_match Mime[:json].to_s, response.content_type + + # Check that we have all users + users = json_response(response.body) + assert_equal User.members.count, users.size, 'some users are missing' + + # Check that users are ordered by id + first_user = User.members.order(:id).limit(1).first + last_user = User.members.order(id: :desc).limit(1).first + assert_equal first_user.id, users.first[:id] + assert_equal last_user.id, users.last[:id] + end +end diff --git a/test/integration/notifications/notification_preferences_test.rb b/test/integration/notifications/notification_preferences_test.rb index 0909cbe63..c4ec4ad97 100644 --- a/test/integration/notifications/notification_preferences_test.rb +++ b/test/integration/notifications/notification_preferences_test.rb @@ -13,7 +13,7 @@ class NotificationPreferencesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok and don't include other users' notification preferences notification_preferences = json_response(response.body) @@ -36,7 +36,7 @@ class NotificationPreferencesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the status was updated res = json_response(response.body) diff --git a/test/integration/notifications/notification_types_test.rb b/test/integration/notifications/notification_types_test.rb index 81f5fdc90..df993771b 100644 --- a/test/integration/notifications/notification_types_test.rb +++ b/test/integration/notifications/notification_types_test.rb @@ -13,7 +13,7 @@ class NotificationTypesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok notification_types = json_response(response.body) @@ -26,7 +26,7 @@ class NotificationTypesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok notification_types = json_response(response.body) diff --git a/test/integration/notifications/notifications_test.rb b/test/integration/notifications/notifications_test.rb index cbdef9571..69b6ce9d2 100644 --- a/test/integration/notifications/notifications_test.rb +++ b/test/integration/notifications/notifications_test.rb @@ -11,7 +11,7 @@ class NotificationsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok # ! Only works if notifications fixtures for this user are < NOTIFICATIONS_PER_PAGE (See NotificationsController#index) @@ -29,7 +29,7 @@ class NotificationsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok notifications_total = json_response(response.body)[:totals][:total] @@ -51,7 +51,7 @@ class NotificationsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok # Beware that the order of last unread notifications is descending, @@ -76,7 +76,7 @@ class NotificationsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok updated_notification = json_response(response.body) diff --git a/test/integration/open_api/accounting_test.rb b/test/integration/open_api/accounting_test.rb index 9feca27af..8647d38f3 100644 --- a/test/integration/open_api/accounting_test.rb +++ b/test/integration/open_api/accounting_test.rb @@ -12,7 +12,7 @@ class OpenApi::AccountingTest < ActionDispatch::IntegrationTest test 'list all accounting lines' do get '/open_api/v1/accounting', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type lines = json_response(response.body) assert_not_empty lines[:lines] @@ -40,7 +40,7 @@ class OpenApi::AccountingTest < ActionDispatch::IntegrationTest test 'list all accounting lines with pagination' do get '/open_api/v1/accounting?page=1&per_page=5', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type lines = json_response(response.body) assert_equal 5, lines[:lines].count @@ -49,7 +49,7 @@ class OpenApi::AccountingTest < ActionDispatch::IntegrationTest test 'list all accounting lines with dates filtering' do get '/open_api/v1/accounting?after=2022-09-01T00:00:00+02:00&before=2022-09-30T23:59:59+02:00', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type lines = json_response(response.body) assert lines[:lines].count.positive? @@ -62,7 +62,7 @@ class OpenApi::AccountingTest < ActionDispatch::IntegrationTest test 'list all accounting lines with invoices filtering' do get '/open_api/v1/accounting?invoice_id=[1,2,3]', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type lines = json_response(response.body) assert lines[:lines].count.positive? @@ -72,7 +72,7 @@ class OpenApi::AccountingTest < ActionDispatch::IntegrationTest test 'list all accounting lines with type filtering' do get '/open_api/v1/accounting?type=[payment,vat]', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type lines = json_response(response.body) assert lines[:lines].count.positive? @@ -82,7 +82,7 @@ class OpenApi::AccountingTest < ActionDispatch::IntegrationTest test 'list all accounting payment lines should have payment details' do get '/open_api/v1/accounting?type=payment', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type card_code = Setting.get('accounting_payment_card_code') wallet_code = Setting.get('accounting_payment_wallet_code') diff --git a/test/integration/open_api/availabilities_test.rb b/test/integration/open_api/availabilities_test.rb new file mode 100644 index 000000000..7147d6bf4 --- /dev/null +++ b/test/integration/open_api/availabilities_test.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'test_helper' + +module OpenApi; end + +class OpenApi::AvailabilitiesTest < ActionDispatch::IntegrationTest + def setup + @token = OpenAPI::Client.find_by(name: 'minitest').token + end + + test 'list availabilities' do + get '/open_api/v1/availabilities', headers: open_api_headers(@token) + assert_response :success + availabilities = json_response(response.body) + assert_not_empty availabilities[:availabilities] + + assert(availabilities[:availabilities].none? { |a| a[:id].blank? }) + assert(availabilities[:availabilities].none? { |a| a[:start_at].blank? }) + assert(availabilities[:availabilities].none? { |a| a[:end_at].blank? }) + assert(availabilities[:availabilities].none? { |a| a[:available_type].blank? }) + assert(availabilities[:availabilities].none? { |a| a[:available_ids].empty? }) + assert(availabilities[:availabilities].none? { |a| a[:created_at].blank? }) + assert(availabilities[:availabilities].none? { |a| a[:slots].empty? }) + assert(availabilities[:availabilities].pluck(:slots).flatten.none? { |s| s[:id].blank? }) + assert(availabilities[:availabilities].pluck(:slots).flatten.none? { |s| s[:start_at].blank? }) + assert(availabilities[:availabilities].pluck(:slots).flatten.none? { |s| s[:end_at].blank? }) + end + + test 'list availabilities with pagination details' do + get '/open_api/v1/availabilities?page=1&per_page=5', headers: open_api_headers(@token) + assert_response :success + availabilities = json_response(response.body) + + assert_equal 5, availabilities[:availabilities].count + end + + test 'list availabilities for given IDs' do + get '/open_api/v1/availabilities?id=[3,4]', headers: open_api_headers(@token) + assert_response :success + availabilities = json_response(response.body) + assert_not_empty availabilities[:availabilities] + + assert(availabilities[:availabilities].all? { |a| [3, 4].include?(a[:id]) }) + end + + test 'list availabilities for given type' do + get '/open_api/v1/availabilities?available_type=Machine', headers: open_api_headers(@token) + assert_response :success + availabilities = json_response(response.body) + assert_not_empty availabilities[:availabilities] + + assert(availabilities[:availabilities].all? { |a| a[:available_type] == 'Machine' }) + end + + test 'list availabilities for given type and IDs' do + get '/open_api/v1/availabilities?available_type=Machine&available_id[]=1&available_id[]=2', headers: open_api_headers(@token) + assert_response :success + availabilities = json_response(response.body) + assert_not_empty availabilities[:availabilities] + + assert(availabilities[:availabilities].all? { |a| a[:available_type] == 'Machine' }) + assert(availabilities[:availabilities].all? { |a| a[:available_ids].any? { |id| [1, 2].include?(id) } }) + end + + test 'list availabilities with given available_id but no available_type does not filter by id' do + get '/open_api/v1/availabilities?&available_id=1', headers: open_api_headers(@token) + assert_response :success + availabilities = json_response(response.body) + assert_not_empty availabilities[:availabilities] + + assert(availabilities[:availabilities].any? { |a| a[:available_ids] != 1 }) + end + + test 'list availabilities with date filtering' do + get '/open_api/v1/availabilities?after=2016-04-01T00:00:00+01:00&before=2016-05-31T23:59:59+02:00', headers: open_api_headers(@token) + assert_response :success + availabilities = json_response(response.body) + assert_not_empty availabilities[:availabilities] + + assert(availabilities[:availabilities].all? do |a| + start = Time.zone.parse(a[:start_at]) + ending = Time.zone.parse(a[:end_at]) + start >= '2016-04-01'.to_date && ending <= '2016-05-31'.to_date + end) + end +end diff --git a/test/integration/open_api/invoices_test.rb b/test/integration/open_api/invoices_test.rb index eb19a02e6..1158d20cd 100644 --- a/test/integration/open_api/invoices_test.rb +++ b/test/integration/open_api/invoices_test.rb @@ -12,7 +12,7 @@ class OpenApi::InvoicesTest < ActionDispatch::IntegrationTest test 'list invoices' do get '/open_api/v1/invoices', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type assert_not_empty json_response(response.body)[:invoices] end diff --git a/test/integration/open_api/prices_test.rb b/test/integration/open_api/prices_test.rb index efe43a3d5..116399e17 100644 --- a/test/integration/open_api/prices_test.rb +++ b/test/integration/open_api/prices_test.rb @@ -33,7 +33,7 @@ class OpenApi::PricesTest < ActionDispatch::IntegrationTest test 'list all prices for some groups' do get '/open_api/v1/prices?group_id=[1,2]', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type prices = json_response(response.body) assert_equal [1, 2], prices[:prices].pluck(:group_id).uniq.sort diff --git a/test/integration/open_api/reservations_test.rb b/test/integration/open_api/reservations_test.rb index 3f3b71b88..73d7baaf3 100644 --- a/test/integration/open_api/reservations_test.rb +++ b/test/integration/open_api/reservations_test.rb @@ -12,7 +12,7 @@ class OpenApi::ReservationsTest < ActionDispatch::IntegrationTest test 'list reservations ' do get '/open_api/v1/reservations', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type assert_not_empty json_response(response.body)[:reservations] end @@ -20,7 +20,7 @@ class OpenApi::ReservationsTest < ActionDispatch::IntegrationTest test 'list all reservations with pagination' do get '/open_api/v1/reservations?page=1&per_page=5', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type reservations = json_response(response.body) assert reservations[:reservations].count <= 5 @@ -29,7 +29,7 @@ class OpenApi::ReservationsTest < ActionDispatch::IntegrationTest test 'list all reservations for a user' do get '/open_api/v1/reservations?user_id=3', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type reservations = json_response(response.body) assert_not_empty reservations[:reservations] @@ -39,7 +39,7 @@ class OpenApi::ReservationsTest < ActionDispatch::IntegrationTest test 'list all reservations for a user with pagination' do get '/open_api/v1/reservations?user_id=3&page=1&per_page=5', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type reservations = json_response(response.body) assert reservations[:reservations].count <= 5 @@ -49,7 +49,7 @@ class OpenApi::ReservationsTest < ActionDispatch::IntegrationTest test 'list all reservations with dates filtering' do get '/open_api/v1/reservations?after=2012-01-01T00:00:00+02:00&before=2012-12-31T23:59:59+02:00', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type reservations = json_response(response.body) assert reservations[:reservations].count.positive? @@ -62,7 +62,7 @@ class OpenApi::ReservationsTest < ActionDispatch::IntegrationTest test 'list all machine reservations for a user' do get '/open_api/v1/reservations?reservable_type=Machine&user_id=3', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type reservations = json_response(response.body) assert_not_empty reservations[:reservations] @@ -73,10 +73,20 @@ class OpenApi::ReservationsTest < ActionDispatch::IntegrationTest test 'list all machine 2 reservations' do get '/open_api/v1/reservations?reservable_type=Machine&reservable_id=2', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type reservations = json_response(response.body) assert_not_empty reservations[:reservations] assert_equal [2], reservations[:reservations].pluck(:reservable_id).uniq end + + test 'list reservations filtered by availability' do + get '/open_api/v1/reservations?availability_id=13', headers: open_api_headers(@token) + assert_response :success + assert_match Mime[:json].to_s, response.content_type + + reservations = json_response(response.body) + assert_not_empty reservations[:reservations] + assert_equal [13], reservations[:reservations].pluck(:reserved_slots).flatten.pluck(:availability_id).uniq + end end diff --git a/test/integration/open_api/subscriptions_test.rb b/test/integration/open_api/subscriptions_test.rb index 2ea5e26bf..5273c1778 100644 --- a/test/integration/open_api/subscriptions_test.rb +++ b/test/integration/open_api/subscriptions_test.rb @@ -12,7 +12,7 @@ class OpenApi::SubscriptionsTest < ActionDispatch::IntegrationTest test 'list subscriptions' do get '/open_api/v1/subscriptions', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type assert_not_empty json_response(response.body)[:subscriptions] end @@ -20,7 +20,7 @@ class OpenApi::SubscriptionsTest < ActionDispatch::IntegrationTest test 'list subscriptions with pagination' do get '/open_api/v1/subscriptions?page=1&per_page=5', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type subscriptions = json_response(response.body) assert subscriptions[:subscriptions].count <= 5 diff --git a/test/integration/open_api/trainings_test.rb b/test/integration/open_api/trainings_test.rb index deda96800..9792044f8 100644 --- a/test/integration/open_api/trainings_test.rb +++ b/test/integration/open_api/trainings_test.rb @@ -13,5 +13,4 @@ class OpenApi::TrainingsTest < ActionDispatch::IntegrationTest get '/open_api/v1/trainings', headers: open_api_headers(@token) assert_response :success end - end diff --git a/test/integration/open_api/users_test.rb b/test/integration/open_api/users_test.rb index fde626a3c..03b10f7b5 100644 --- a/test/integration/open_api/users_test.rb +++ b/test/integration/open_api/users_test.rb @@ -12,7 +12,7 @@ class OpenApi::UsersTest < ActionDispatch::IntegrationTest test 'list all users' do get '/open_api/v1/users', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type users = json_response(response.body) assert_equal User.count, users[:users].length @@ -32,7 +32,7 @@ class OpenApi::UsersTest < ActionDispatch::IntegrationTest test 'list all users with pagination' do get '/open_api/v1/users?page=1&per_page=5', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type users = json_response(response.body) assert_equal 5, users[:users].length @@ -41,7 +41,7 @@ class OpenApi::UsersTest < ActionDispatch::IntegrationTest test 'list all users filtering by IDs' do get '/open_api/v1/users?user_id=[3,4,5]', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type users = json_response(response.body) assert users[:users].count.positive? @@ -51,7 +51,7 @@ class OpenApi::UsersTest < ActionDispatch::IntegrationTest test 'list all users filtering by IDs other syntax' do get '/open_api/v1/users?user_id[]=3&user_id[]=4&user_id[]=5', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type users = json_response(response.body) assert users[:users].count.positive? @@ -61,7 +61,7 @@ class OpenApi::UsersTest < ActionDispatch::IntegrationTest test 'list a user filtering by ID' do get '/open_api/v1/users?user_id=2', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type users = json_response(response.body) assert_equal 1, users[:users].count @@ -71,7 +71,7 @@ class OpenApi::UsersTest < ActionDispatch::IntegrationTest test 'list all users filtering by email' do get '/open_api/v1/users?email=jean.dupond@gmail.com', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type users = json_response(response.body) assert_equal 1, users[:users].count @@ -81,7 +81,7 @@ class OpenApi::UsersTest < ActionDispatch::IntegrationTest test 'list all users created after date' do get '/open_api/v1/users?created_after=2018-01-01T00:00:00+01:00', headers: open_api_headers(@token) assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type users = json_response(response.body) assert users[:users].count.positive? diff --git a/test/integration/open_id_connect_test.rb b/test/integration/open_id_connect_test.rb index ef408c587..5cc17d415 100644 --- a/test/integration/open_id_connect_test.rb +++ b/test/integration/open_id_connect_test.rb @@ -9,10 +9,13 @@ class OpenIdConnectTest < ActionDispatch::IntegrationTest setup do @admin = User.find_by(username: 'admin') login_as(@admin, scope: :user) - Fablab::Application.load_tasks if Rake::Task.tasks.empty? + FabManager::Application.load_tasks if Rake::Task.tasks.empty? end test 'create and activate an OIDC provider' do + # clean any existing auth provider config + FileUtils.rm('config/auth_provider.yml', force: true) + name = 'Sleede' post '/api/auth_providers', params: { @@ -22,7 +25,7 @@ class OpenIdConnectTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the provider was correctly created db_provider = OpenIdConnectProvider.includes(:auth_provider).where('auth_providers.name': name).first&.auth_provider @@ -42,18 +45,13 @@ class OpenIdConnectTest < ActionDispatch::IntegrationTest assert_equal 'active', db_provider&.status assert_equal AuthProvider.active.id, db_provider&.id - # TODO, login with the SSO (need debugging) - ## The following doesn't work but I can't find out why... Maybe configuring Devise like this is not the right way, - ## but when testing the process with Capybara, I always fall with the message "Not found. Authentication passthru." + # Check the configuration file + assert File.exist?('config/auth_provider.yml') + config = ProviderConfig.new + assert_equal 'OpenIdConnectProvider', config.providable_type + assert_equal name, config.name - # Simulate an application restart (reload routes and change devise setup) - # logout - # Devise.setup do |config| - # require_relative '../../lib/omni_auth/openid_connect' - # config.omniauth OmniAuth::Strategies::SsoOpenidConnectProvider.name&.to_sym, - # db_provider&.providable&.config - # end - # User.devise :omniauthable, omniauth_providers: [db_provider&.strategy_name&.to_sym] - # Rails.application.reload_routes! + # clean test provider config + FileUtils.rm('config/auth_provider.yml', force: true) end end diff --git a/test/integration/order/create_cart_item_test.rb b/test/integration/order/create_cart_item_test.rb index 11a712ee9..35fa923f9 100644 --- a/test/integration/order/create_cart_item_test.rb +++ b/test/integration/order/create_cart_item_test.rb @@ -20,7 +20,7 @@ class CreateCartItemTest < ActionDispatch::IntegrationTest } # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the cart item was created correctly res = json_response(response.body) @@ -46,7 +46,7 @@ class CreateCartItemTest < ActionDispatch::IntegrationTest } # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the cart item was created correctly res = json_response(response.body) @@ -70,7 +70,7 @@ class CreateCartItemTest < ActionDispatch::IntegrationTest } # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the cart item was created correctly res = json_response(response.body) @@ -94,7 +94,7 @@ class CreateCartItemTest < ActionDispatch::IntegrationTest } # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the cart item was created correctly res = json_response(response.body) @@ -119,7 +119,7 @@ class CreateCartItemTest < ActionDispatch::IntegrationTest } # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the cart item was created correctly res = json_response(response.body) @@ -138,7 +138,7 @@ class CreateCartItemTest < ActionDispatch::IntegrationTest } # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the cart item was created correctly res = json_response(response.body) @@ -156,7 +156,7 @@ class CreateCartItemTest < ActionDispatch::IntegrationTest } # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the cart item was created correctly res = json_response(response.body) diff --git a/test/integration/plans/create_plan_test.rb b/test/integration/plans/create_plan_test.rb index 9070d7224..bb2eeb06f 100644 --- a/test/integration/plans/create_plan_test.rb +++ b/test/integration/plans/create_plan_test.rb @@ -27,7 +27,7 @@ class CreatePlanTest < ActionDispatch::IntegrationTest description: 'lorem ipsum dolor sit amet', partner_id: 6, plan_file_attributes: { - attachment: fixture_file_upload('/files/document.pdf') + attachment: fixture_file_upload('document.pdf') } } }.to_json, @@ -35,7 +35,7 @@ class CreatePlanTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the created plans res = json_response(response.body) @@ -68,7 +68,7 @@ class CreatePlanTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the created plan res = json_response(response.body) diff --git a/test/integration/prepaid_packs_test.rb b/test/integration/prepaid_packs_test.rb index b161ab915..31e730890 100644 --- a/test/integration/prepaid_packs_test.rb +++ b/test/integration/prepaid_packs_test.rb @@ -25,7 +25,7 @@ class PrepaidPacksTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct prepaid pack was created res = json_response(response.body) @@ -52,7 +52,7 @@ class PrepaidPacksTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the prepaid pack was updated res = json_response(response.body) @@ -65,7 +65,7 @@ class PrepaidPacksTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok pack = json_response(response.body) diff --git a/test/integration/prices/compute_test.rb b/test/integration/prices/compute_test.rb index fb63358db..0b54e581e 100644 --- a/test/integration/prices/compute_test.rb +++ b/test/integration/prices/compute_test.rb @@ -2,94 +2,94 @@ require 'test_helper' -module Prices - class AsAdminTest < ActionDispatch::IntegrationTest - setup do - admin = User.with_role(:admin).first - login_as(admin, scope: :user) - end +module Prices; end - test 'compute price for a simple training' do - user = User.find_by(username: 'jdupond') - availability = Availability.find(2) - slot = Availability.find(2).slots.first - printer_training = availability.trainings.first +class Prices::AsAdminTest < ActionDispatch::IntegrationTest + setup do + admin = User.with_role(:admin).first + login_as(admin, scope: :user) + end - post '/api/prices/compute', - params: { - customer_id: user.id, - items: [ - { - reservation: { - reservable_id: printer_training.id, - reservable_type: printer_training.class.name, - slots_reservations_attributes: [ - { - slot_id: slot.id, - offered: false - } - ] - } + test 'compute price for a simple training' do + user = User.find_by(username: 'jdupond') + availability = Availability.find(2) + slot = Availability.find(2).slots.first + printer_training = availability.trainings.first + + post '/api/prices/compute', + params: { + customer_id: user.id, + items: [ + { + reservation: { + reservable_id: printer_training.id, + reservable_type: printer_training.class.name, + slots_reservations_attributes: [ + { + slot_id: slot.id, + offered: false + } + ] } - ] - }.to_json, - headers: default_headers + } + ] + }.to_json, + headers: default_headers - # Check response format & status - assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + # Check response format & status + assert_equal 200, response.status, response.body + assert_match Mime[:json].to_s, response.content_type - # Check the price was computed correctly - price = json_response(response.body) - assert_equal (printer_training.trainings_pricings.where(group_id: user.group_id).first.amount / 100.0), - price[:price], - 'Computed price did not match training price' - end + # Check the price was computed correctly + price = json_response(response.body) + assert_equal (printer_training.trainings_pricings.where(group_id: user.group_id).first.amount / 100.0), + price[:price], + 'Computed price did not match training price' + end - test 'compute price for a machine reservation with an offered slot and a subscription' do - user = User.find_by(username: 'jdupond') - availability = Availability.find(3) - laser = availability.machines.where(id: 1).first - plan = Plan.find_by(group_id: user.group_id, interval: 'month') + test 'compute price for a machine reservation with an offered slot and a subscription' do + user = User.find_by(username: 'jdupond') + availability = Availability.find(3) + laser = availability.machines.where(id: 1).first + plan = Plan.find_by(group_id: user.group_id, interval: 'month') - post '/api/prices/compute', - params: { - customer_id: user.id, - items: [ - { - reservation: { - reservable_id: laser.id, - reservable_type: laser.class.name, - slots_reservations_attributes: [ - { - slot_id: availability.slots.first.id, - offered: true - }, - { - slot_id: availability.slots.last.id, - offered: false - } - ] - } - }, - { - subscription: { - plan_id: plan.id - } + post '/api/prices/compute', + params: { + customer_id: user.id, + items: [ + { + reservation: { + reservable_id: laser.id, + reservable_type: laser.class.name, + slots_reservations_attributes: [ + { + slot_id: availability.slots.first.id, + offered: true + }, + { + slot_id: availability.slots.last.id, + offered: false + } + ] } - ] - }.to_json, - headers: default_headers + }, + { + subscription: { + plan_id: plan.id + } + } + ] + }.to_json, + headers: default_headers - # Check response format & status - assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + # Check response format & status + assert_equal 200, response.status, response.body + assert_match Mime[:json].to_s, response.content_type - # Check the event was created correctly - price = json_response(response.body) - assert_equal ((laser.prices.where(group_id: user.group_id, plan_id: plan.id).first.amount + plan.amount) / 100.0), - price[:price], - 'Computed price did not match machine + subscription price' - end + # Check the event was created correctly + price = json_response(response.body) + assert_equal ((laser.prices.where(group_id: user.group_id, plan_id: plan.id).first.amount + plan.amount) / 100.0), + price[:price], + 'Computed price did not match machine + subscription price' end end diff --git a/test/integration/products_test.rb b/test/integration/products_test.rb index 96a827523..174df95d8 100644 --- a/test/integration/products_test.rb +++ b/test/integration/products_test.rb @@ -26,12 +26,12 @@ class ProductsTest < ActionDispatch::IntegrationTest low_stock_threshold: 100, machine_ids: [4, 6], product_files_attributes: [ - { attachment: fixture_file_upload('/files/document.pdf', 'application/pdf', true) }, - { attachment: fixture_file_upload('/files/document2.pdf', 'application/pdf', true) } + { attachment: fixture_file_upload('document.pdf', 'application/pdf', true) }, + { attachment: fixture_file_upload('document2.pdf', 'application/pdf', true) } ], product_images_attributes: [ - { attachment: fixture_file_upload('/files/products/pla-filament.jpg', 'image/jpg'), is_main: true }, - { attachment: fixture_file_upload('/files/products/pla-filament2.jpg', 'image/jpg'), is_main: false } + { attachment: fixture_file_upload('products/pla-filament.jpg', 'image/jpg'), is_main: true }, + { attachment: fixture_file_upload('products/pla-filament2.jpg', 'image/jpg'), is_main: false } ], advanced_accounting_attributes: { code: '704611', @@ -47,7 +47,7 @@ class ProductsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the poduct was correctly created db_product = Product.where(name: name).first @@ -90,7 +90,7 @@ class ProductsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the product was correctly updated db_product.reload @@ -121,7 +121,7 @@ class ProductsTest < ActionDispatch::IntegrationTest }.to_json, headers: default_headers assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the new product product = Product.last diff --git a/test/integration/reservations/last_minute_test.rb b/test/integration/reservations/last_minute_test.rb index 88b366f75..b91c87e8f 100644 --- a/test/integration/reservations/last_minute_test.rb +++ b/test/integration/reservations/last_minute_test.rb @@ -40,7 +40,7 @@ class Reservations::LastMinuteTest < ActionDispatch::IntegrationTest # general assertions assert_equal 422, response.status - assert_match(I18n.t('cart_item_validation.deadline', { MINUTES: 120 }), response.body) + assert_match(I18n.t('cart_item_validation.deadline', **{ MINUTES: 120 }), response.body) end test 'user can reserve last minute booking' do diff --git a/test/integration/reservations/local_payment_test.rb b/test/integration/reservations/local_payment_test.rb index 44b017821..6c486aeb0 100644 --- a/test/integration/reservations/local_payment_test.rb +++ b/test/integration/reservations/local_payment_test.rb @@ -70,7 +70,6 @@ class Reservations::LocalPaymentTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint # notification assert_not_empty Notification.where(attached_object: reservation) @@ -129,7 +128,6 @@ class Reservations::LocalPaymentTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint # notification assert_not_empty Notification.where(attached_object: reservation) @@ -206,7 +204,6 @@ class Reservations::LocalPaymentTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint # notification assert_not_empty Notification.where(attached_object: reservation) @@ -247,7 +244,7 @@ class Reservations::LocalPaymentTest < ActionDispatch::IntegrationTest # general assertions assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type result = json_response(response.body) # Check the DB objects have been created as they should @@ -290,7 +287,6 @@ class Reservations::LocalPaymentTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint # notification assert_not_empty Notification.where(attached_object: reservation) diff --git a/test/integration/reservations/local_payment_with_wallet_test.rb b/test/integration/reservations/local_payment_with_wallet_test.rb index be4488b43..e0d53f7f0 100644 --- a/test/integration/reservations/local_payment_with_wallet_test.rb +++ b/test/integration/reservations/local_payment_with_wallet_test.rb @@ -74,7 +74,6 @@ class Reservations::LocalPaymentWithWalletTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint # notification assert_not_empty Notification.where(attached_object: reservation) @@ -193,7 +192,6 @@ class Reservations::LocalPaymentWithWalletTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint # notification assert_not_empty Notification.where(attached_object: reservation) diff --git a/test/integration/reservations/pay_with_prepaid_pack_test.rb b/test/integration/reservations/pay_with_prepaid_pack_test.rb index 160c6786a..e23ddbefd 100644 --- a/test/integration/reservations/pay_with_prepaid_pack_test.rb +++ b/test/integration/reservations/pay_with_prepaid_pack_test.rb @@ -60,7 +60,6 @@ class Reservations::PayWithPrepaidPackTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/reservations/pay_with_wallet_test.rb b/test/integration/reservations/pay_with_wallet_test.rb index 9c531017d..04f5c040b 100644 --- a/test/integration/reservations/pay_with_wallet_test.rb +++ b/test/integration/reservations/pay_with_wallet_test.rb @@ -74,7 +74,6 @@ class Reservations::PayWithWalletTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -155,7 +154,6 @@ class Reservations::PayWithWalletTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -223,7 +221,7 @@ class Reservations::PayWithWalletTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the response res = json_response(response.body) diff --git a/test/integration/reservations/payment_schedule_test.rb b/test/integration/reservations/payment_schedule_test.rb index df7147d6a..9bde412f6 100644 --- a/test/integration/reservations/payment_schedule_test.rb +++ b/test/integration/reservations/payment_schedule_test.rb @@ -56,7 +56,7 @@ class Reservations::PaymentScheduleTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type assert_equal reservations_count + 1, Reservation.count, 'missing the reservation' assert_equal invoice_count, Invoice.count, "an invoice was generated but it shouldn't" assert_equal invoice_items_count, InvoiceItem.count, "some invoice items were generated but they shouldn't" @@ -81,7 +81,7 @@ class Reservations::PaymentScheduleTest < ActionDispatch::IntegrationTest assert_nil payment_schedule.wallet_amount assert_nil payment_schedule.coupon_id assert_equal 'test', payment_schedule.environment - assert payment_schedule.check_footprint + assert payment_schedule.check_footprint, payment_schedule.debug_footprint assert_equal @user_without_subscription.invoicing_profile.id, payment_schedule.invoicing_profile_id assert_equal @admin.invoicing_profile.id, payment_schedule.operator_profile_id assert_schedule_pdf(payment_schedule) diff --git a/test/integration/reservations/privileged_user_test.rb b/test/integration/reservations/privileged_user_test.rb index a68d03e8d..017051219 100644 --- a/test/integration/reservations/privileged_user_test.rb +++ b/test/integration/reservations/privileged_user_test.rb @@ -109,7 +109,6 @@ class Reservations::PrivilegedUserTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/reservations/reserve_machine_test.rb b/test/integration/reservations/reserve_machine_test.rb index ba4df59b1..262dbf5de 100644 --- a/test/integration/reservations/reserve_machine_test.rb +++ b/test/integration/reservations/reserve_machine_test.rb @@ -72,7 +72,6 @@ class Reservations::ReserveMachineTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -124,7 +123,7 @@ class Reservations::ReserveMachineTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, "API does not return the expected status. #{response.body}" - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the error was handled assert_match(/Your card was declined/, response.body) @@ -204,7 +203,6 @@ class Reservations::ReserveMachineTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/reservations/reserve_space_test.rb b/test/integration/reservations/reserve_space_test.rb index 7e8885f81..5755381a9 100644 --- a/test/integration/reservations/reserve_space_test.rb +++ b/test/integration/reservations/reserve_space_test.rb @@ -72,7 +72,6 @@ class Reservations::ReserveSpaceTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/reservations/reserve_training_test.rb b/test/integration/reservations/reserve_training_test.rb index 1cefca105..ed7f5a5f2 100644 --- a/test/integration/reservations/reserve_training_test.rb +++ b/test/integration/reservations/reserve_training_test.rb @@ -68,7 +68,6 @@ class Reservations::ReserveTrainingTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -178,7 +177,7 @@ class Reservations::ReserveTrainingTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the response sub = json_response(response.body) @@ -187,7 +186,7 @@ class Reservations::ReserveTrainingTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type assert_equal reservations_count + 1, Reservation.count, 'missing the reservation' assert_equal invoice_count, Invoice.count, "an invoice was generated but it shouldn't" assert_equal invoice_items_count, InvoiceItem.count, "some invoice items were generated but they shouldn't" diff --git a/test/integration/reservations/space_seats_test.rb b/test/integration/reservations/space_seats_test.rb index 5370e4b9a..8daa9d567 100644 --- a/test/integration/reservations/space_seats_test.rb +++ b/test/integration/reservations/space_seats_test.rb @@ -38,7 +38,7 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the availability res = json_response(response.body) @@ -99,7 +99,6 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -168,7 +167,6 @@ class Reservations::SpaceSeatsTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/reservations/with_subscription_test.rb b/test/integration/reservations/with_subscription_test.rb index 4fa92110a..ff136f548 100644 --- a/test/integration/reservations/with_subscription_test.rb +++ b/test/integration/reservations/with_subscription_test.rb @@ -82,7 +82,6 @@ class Reservations::WithSubscriptionTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -150,7 +149,6 @@ class Reservations::WithSubscriptionTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -223,13 +221,12 @@ class Reservations::WithSubscriptionTest < ActionDispatch::IntegrationTest invoice_item = InvoiceItem.last assert_equal machine.prices.find_by(group_id: @vlonchamp.group_id, plan_id: nil).amount, invoice_item.amount - assert invoice_item.check_footprint + assert invoice_item.check_footprint, invoice_item.debug_footprint # invoice assertions item = InvoiceItem.find_by(object: reservation) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/settings_test.rb b/test/integration/settings_test.rb index 03decf6fa..5396d9c8d 100644 --- a/test/integration/settings_test.rb +++ b/test/integration/settings_test.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'test_helper' + class SettingsTest < ActionDispatch::IntegrationTest # Called before every test method runs. Can be used # to set up fixture information. @@ -16,7 +18,7 @@ class SettingsTest < ActionDispatch::IntegrationTest } } assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type resp = json_response(response.body) assert_equal 'fablab_name', resp[:setting][:name] assert_equal 'Test Fablab', resp[:setting][:value] @@ -37,14 +39,14 @@ class SettingsTest < ActionDispatch::IntegrationTest } } assert_equal 422, response.status - assert_match /Name is not included in the list/, response.body + assert_match(/Name is not included in the list/, response.body) end test 'show setting' do get '/api/settings/fablab_name' assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type resp = json_response(response.body) assert_equal 'fablab_name', resp[:setting][:name], 'wrong parameter name' assert_equal 'Fab Lab de La Casemate', resp[:setting][:value], 'wrong parameter value' diff --git a/test/integration/slots_reservations_test.rb b/test/integration/slots_reservations_test.rb index c538345e1..588e21fb6 100644 --- a/test/integration/slots_reservations_test.rb +++ b/test/integration/slots_reservations_test.rb @@ -14,7 +14,7 @@ class SlotsReservationsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the reservation was correctly canceled slots_reservation = SlotsReservation.find(1) @@ -23,6 +23,7 @@ class SlotsReservationsTest < ActionDispatch::IntegrationTest # place cache slot = slots_reservation.slot + slot.reload cached = slot.places.detect do |p| p['reservable_id'] == slots_reservation.reservation.reservable_id && p['reservable_type'] == slots_reservation.reservation.reservable_type end @@ -77,7 +78,7 @@ class SlotsReservationsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the reservation was correctly moved slots_reservation.reload diff --git a/test/integration/spaces_test.rb b/test/integration/spaces_test.rb index 11143f6f1..d29ff1eeb 100644 --- a/test/integration/spaces_test.rb +++ b/test/integration/spaces_test.rb @@ -15,14 +15,14 @@ class SpacesTest < ActionDispatch::IntegrationTest space: { name: name, space_image_attributes: { - attachment: fixture_file_upload('/files/spaces/Biology_laboratory.jpg') + attachment: fixture_file_upload('spaces/Biology_laboratory.jpg') }, description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras ante mi, porta ac dictum quis, feugiat...', characteristics: 'Sed fermentum ante ut elit lobortis, id auctor libero cursus. Sed augue lectus, mollis at luctus eu...', default_places: 6, space_files_attributes: [ - { attachment: fixture_file_upload('/files/document.pdf', 'application/pdf', true) }, - { attachment: fixture_file_upload('/files/document2.pdf', 'application/pdf', true) } + { attachment: fixture_file_upload('document.pdf', 'application/pdf', true) }, + { attachment: fixture_file_upload('document2.pdf', 'application/pdf', true) } ], disabled: false } @@ -31,7 +31,7 @@ class SpacesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the space was correctly created db_space = Space.where(name: name).first @@ -59,7 +59,7 @@ class SpacesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the space was correctly updated db_space = Space.find(1) diff --git a/test/integration/statuses_test.rb b/test/integration/statuses_test.rb index 0910a5f12..f05b11943 100644 --- a/test/integration/statuses_test.rb +++ b/test/integration/statuses_test.rb @@ -17,7 +17,7 @@ class StatusesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct status was created res = json_response(response.body) @@ -36,7 +36,7 @@ class StatusesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the status was updated res = json_response(response.body) @@ -49,7 +49,7 @@ class StatusesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok statuses = json_response(response.body) diff --git a/test/integration/store/admin_order_for_himself_test.rb b/test/integration/store/admin_order_for_himself_test.rb index 81e02908a..0391aa0af 100644 --- a/test/integration/store/admin_order_for_himself_test.rb +++ b/test/integration/store/admin_order_for_himself_test.rb @@ -43,7 +43,6 @@ class Store::AdminOrderForHimselfTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not @cart1.payment_gateway_object.blank? assert_not invoice.payment_gateway_object.blank? @@ -110,7 +109,6 @@ class Store::AdminOrderForHimselfTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not @cart1.payment_gateway_object.blank? assert_not invoice.payment_gateway_object.blank? @@ -167,16 +165,15 @@ class Store::AdminOrderForHimselfTest < ActionDispatch::IntegrationTest # invoice_items assertions invoice_item = InvoiceItem.last - assert invoice_item.check_footprint + assert invoice_item.check_footprint, invoice_item.debug_footprint # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? - assert invoice.check_footprint + assert invoice.check_footprint, invoice.debug_footprint # notification assert_not_empty Notification.where(attached_object: invoice) @@ -235,7 +232,6 @@ class Store::AdminOrderForHimselfTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert @cart1.payment_gateway_object.blank? assert invoice.payment_gateway_object.blank? diff --git a/test/integration/store/admin_pay_order_test.rb b/test/integration/store/admin_pay_order_test.rb index 267076ce0..2be33ae44 100644 --- a/test/integration/store/admin_pay_order_test.rb +++ b/test/integration/store/admin_pay_order_test.rb @@ -41,7 +41,6 @@ class Store::AdminPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert @cart1.payment_gateway_object.blank? assert invoice.payment_gateway_object.blank? @@ -101,7 +100,6 @@ class Store::AdminPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert @cart1.payment_gateway_object.blank? assert invoice.payment_gateway_object.blank? @@ -168,7 +166,6 @@ class Store::AdminPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -226,7 +223,6 @@ class Store::AdminPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/store/user_pay_order_test.rb b/test/integration/store/user_pay_order_test.rb index f440bd56c..e24526d49 100644 --- a/test/integration/store/user_pay_order_test.rb +++ b/test/integration/store/user_pay_order_test.rb @@ -41,7 +41,6 @@ class Store::UserPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -98,7 +97,6 @@ class Store::UserPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_not @cart1.payment_gateway_object.blank? assert_not invoice.payment_gateway_object.blank? @@ -167,7 +165,6 @@ class Store::UserPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? @@ -224,7 +221,6 @@ class Store::UserPayOrderTest < ActionDispatch::IntegrationTest # invoice assertions invoice = Invoice.last assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert invoice.payment_gateway_object.blank? assert_not invoice.total.blank? diff --git a/test/integration/subscriptions/cancel_test.rb b/test/integration/subscriptions/cancel_test.rb index 46f657699..f0609ba04 100644 --- a/test/integration/subscriptions/cancel_test.rb +++ b/test/integration/subscriptions/cancel_test.rb @@ -17,7 +17,7 @@ class Subscriptions::CancelTest < ActionDispatch::IntegrationTest # Check response format & status assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the subscription was canceled subscription.reload @@ -46,7 +46,7 @@ class Subscriptions::CancelTest < ActionDispatch::IntegrationTest post '/api/local_payment/confirm_payment', params: { customer_id: subscription.user.id, - items: [{ free_extension: { end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N Z') } }] + items: [{ free_extension: { end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') } }] }.to_json, headers: default_headers assert_response :success @@ -55,7 +55,7 @@ class Subscriptions::CancelTest < ActionDispatch::IntegrationTest # Check response format & status assert_response :success - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the subscription was canceled subscription.reload diff --git a/test/integration/subscriptions/create_as_admin_test.rb b/test/integration/subscriptions/create_as_admin_test.rb index 76a1ec91e..e78117b90 100644 --- a/test/integration/subscriptions/create_as_admin_test.rb +++ b/test/integration/subscriptions/create_as_admin_test.rb @@ -30,7 +30,7 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct plan was subscribed result = json_response(response.body) @@ -66,7 +66,6 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object_type: 'Subscription', object_id: subscription.id) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription' end @@ -97,7 +96,7 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the response res = json_response(response.body) diff --git a/test/integration/subscriptions/create_as_user_test.rb b/test/integration/subscriptions/create_as_user_test.rb index 2ea35a3da..f6f9e1ff8 100644 --- a/test/integration/subscriptions/create_as_user_test.rb +++ b/test/integration/subscriptions/create_as_user_test.rb @@ -31,7 +31,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct plan was subscribed result = json_response(response.body) @@ -73,7 +73,6 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object_type: 'Subscription', object_id: subscription[:id]) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription' end @@ -99,7 +98,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 422, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the error was handled assert_match(/plan is reserved for members of group/, response.body) @@ -133,7 +132,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct plan was subscribed result = json_response(response.body) @@ -178,7 +177,6 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object_type: 'Subscription', object_id: subscription[:id]) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription' # wallet @@ -215,7 +213,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the response res = json_response(response.body) @@ -244,7 +242,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest # Check generalities assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type res = json_response(response.body) assert res[:requires_action] diff --git a/test/integration/subscriptions/create_with_payment_schedule_test.rb b/test/integration/subscriptions/create_with_payment_schedule_test.rb index 59b551297..a8b177aae 100644 --- a/test/integration/subscriptions/create_with_payment_schedule_test.rb +++ b/test/integration/subscriptions/create_with_payment_schedule_test.rb @@ -34,7 +34,7 @@ class Subscriptions::CreateWithPaymentScheduleTest < ActionDispatch::Integration # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the response sub = json_response(response.body) diff --git a/test/integration/subscriptions/free_extension_test.rb b/test/integration/subscriptions/free_extension_test.rb index 33b9c34ec..3544110ed 100644 --- a/test/integration/subscriptions/free_extension_test.rb +++ b/test/integration/subscriptions/free_extension_test.rb @@ -23,7 +23,7 @@ class Subscriptions::FreeExtensionTest < ActionDispatch::IntegrationTest items: [ { free_extension: { - end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N Z') + end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') } } ] @@ -32,7 +32,7 @@ class Subscriptions::FreeExtensionTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check that the subscribed plan was not altered res = json_response(response.body) @@ -69,7 +69,7 @@ class Subscriptions::FreeExtensionTest < ActionDispatch::IntegrationTest items: [ { free_extension: { - end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N Z') + end_at: new_date.strftime('%Y-%m-%d %H:%M:%S.%9N %Z') } } ] @@ -77,7 +77,7 @@ class Subscriptions::FreeExtensionTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 422, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check that the subscribed plan was not altered res = json_response(response.body) diff --git a/test/integration/subscriptions/renew_as_admin_test.rb b/test/integration/subscriptions/renew_as_admin_test.rb index 80db5fca9..439baa1ed 100644 --- a/test/integration/subscriptions/renew_as_admin_test.rb +++ b/test/integration/subscriptions/renew_as_admin_test.rb @@ -30,7 +30,7 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct plan was subscribed result = json_response(response.body) @@ -75,7 +75,6 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object_type: 'Subscription', object_id: subscription[:id]) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription' end @@ -93,7 +92,7 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest items: [ { subscription: { - start_at: subscription.expired_at.strftime('%Y-%m-%d %H:%M:%S.%9N Z'), + start_at: subscription.expired_at.strftime('%Y-%m-%d %H:%M:%S.%9N %Z'), plan_id: subscription.plan_id } } @@ -103,7 +102,7 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type res_subscription = json_response(response.body) assert_equal 'Subscription', res_subscription[:main_object][:type] diff --git a/test/integration/subscriptions/renew_as_user_test.rb b/test/integration/subscriptions/renew_as_user_test.rb index 005e5fe64..bd229f1e0 100644 --- a/test/integration/subscriptions/renew_as_user_test.rb +++ b/test/integration/subscriptions/renew_as_user_test.rb @@ -31,7 +31,7 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, "API does not return the expected status. #{response.body}" - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct plan was subscribed result = json_response(response.body) @@ -76,7 +76,6 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest item = InvoiceItem.find_by(object_type: 'Subscription', object_id: subscription[:id]) invoice = item.invoice assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription' end @@ -103,7 +102,7 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, "API does not return the expected status. #{response.body}" - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the error was handled assert_match(/Your card was declined/, response.body) diff --git a/test/integration/tags_test.rb b/test/integration/tags_test.rb index 39abed9f6..fa76e96dd 100644 --- a/test/integration/tags_test.rb +++ b/test/integration/tags_test.rb @@ -17,7 +17,7 @@ class TagsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct tag was created res = json_response(response.body) @@ -36,7 +36,7 @@ class TagsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the tag was updated res = json_response(response.body) @@ -49,7 +49,7 @@ class TagsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok tags = json_response(response.body) diff --git a/test/integration/themes_test.rb b/test/integration/themes_test.rb index 94226b6e4..f479edd51 100644 --- a/test/integration/themes_test.rb +++ b/test/integration/themes_test.rb @@ -17,7 +17,7 @@ class ThemesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct tag was created res = json_response(response.body) @@ -36,7 +36,7 @@ class ThemesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the tag was updated res = json_response(response.body) @@ -49,7 +49,7 @@ class ThemesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the list items are ok themes = json_response(response.body) diff --git a/test/integration/trainings/availabilities_test.rb b/test/integration/trainings/availabilities_test.rb index 6e0c31450..ce3d39311 100644 --- a/test/integration/trainings/availabilities_test.rb +++ b/test/integration/trainings/availabilities_test.rb @@ -16,7 +16,7 @@ class Trainings::AvailabilitiesTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the correct training was returned result = json_response(response.body) diff --git a/test/integration/trainings_test.rb b/test/integration/trainings_test.rb index 0b627649c..3171aa077 100644 --- a/test/integration/trainings_test.rb +++ b/test/integration/trainings_test.rb @@ -15,7 +15,7 @@ class TrainingsTest < ActionDispatch::IntegrationTest training: { name: name, training_image_attributes: { - attachment: fixture_file_upload('/files/trainings/first-aid.jpg') + attachment: fixture_file_upload('trainings/first-aid.jpg') }, description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore...', machine_ids: [], @@ -32,7 +32,7 @@ class TrainingsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the training was correctly created db_training = Training.where(name: name).first @@ -61,7 +61,7 @@ class TrainingsTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 200, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Check the training was correctly updated db_training = Training.find(3) diff --git a/test/integration/wallets_test.rb b/test/integration/wallets_test.rb index 1e050cf08..f0aa9c59a 100644 --- a/test/integration/wallets_test.rb +++ b/test/integration/wallets_test.rb @@ -20,7 +20,7 @@ class WalletsTest < ActionDispatch::IntegrationTest test 'get my wallet' do get "/api/wallet/by_user/#{@vlonchamp.id}" assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type wallet = json_response(response.body) assert_equal @vlonchamp.wallet.invoicing_profile_id, wallet[:invoicing_profile_id] assert_equal @vlonchamp.wallet.amount, wallet[:amount] @@ -32,7 +32,7 @@ class WalletsTest < ActionDispatch::IntegrationTest @user1 = User.first get "/api/wallet/by_user/#{@user1.id}" assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type wallet = json_response(response.body) assert_equal @user1.wallet.invoicing_profile_id, wallet[:invoicing_profile_id] assert_equal @user1.wallet.amount, wallet[:amount] @@ -48,7 +48,7 @@ class WalletsTest < ActionDispatch::IntegrationTest w = @vlonchamp.wallet get "/api/wallet/#{w.id}/transactions" assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type transactions = json_response(response.body) assert_equal w.wallet_transactions.count, transactions.size assert_equal wallet_transactions(:transaction1).id, transactions.first[:id] @@ -70,7 +70,7 @@ class WalletsTest < ActionDispatch::IntegrationTest params: { amount: amount } assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type wallet = json_response(response.body) w.reload assert_equal w.amount, expected_amount @@ -96,7 +96,7 @@ class WalletsTest < ActionDispatch::IntegrationTest } assert_equal 200, response.status - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type wallet = json_response(response.body) w.reload assert_equal w.amount, expected_amount @@ -108,6 +108,5 @@ class WalletsTest < ActionDispatch::IntegrationTest assert_equal amount, (invoice.total / 100.0), 'Avoir total does not match the amount credited to the wallet' assert_equal amount, (invoice.invoice_items.first.amount / 100.0), 'Invoice item amount does not match' assert_invoice_pdf invoice - assert_not_nil invoice.debug_footprint end end diff --git a/test/models/chained_element_test.rb b/test/models/chained_element_test.rb new file mode 100644 index 000000000..af99b86cc --- /dev/null +++ b/test/models/chained_element_test.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +require 'test_helper' + +class ChainedElementTest < ActiveSupport::TestCase + test 'create a first element' do + source = Invoice.first + element = ChainedElement.create!( + element: source, + previous: nil + ) + assert element.persisted? + assert_not_nil element.content + assert_not_nil element.footprint + assert_nil element.previous + + assert element.content.is_a?(Hash) + FootprintService.footprint_columns(Invoice).each do |col| + if source[col].blank? + assert_not_includes element.content.keys, col + else + assert_includes element.content.keys, col + end + end + assert_includes element.content.keys, 'previous' + + assert_equal source.id, element.content['id'] + assert_equal source.total, element.content['total'] + assert_equal source.reference, element.content['reference'] + assert_equal source.payment_method, element.content['payment_method'] + assert_nil element.content['previous'] + assert_not element.corrupted? + end + + test 'chain two elements' do + source1 = sample_reservation_invoice(users(:user2), users(:user1)) + element1 = source1.chained_element + assert element1.persisted? + assert source1.check_footprint + + source2 = sample_reservation_invoice(users(:user3), users(:user1)) + element2 = source2.chained_element + assert element2.persisted? + assert element2.content.is_a?(Hash) + assert_equal element1.footprint, element2.content['previous'] + assert_equal element1.id, element2.previous_id + + assert_not element1.corrupted? + assert_not element2.corrupted? + assert source2.check_footprint + end + + test 'chain element with children embedded json' do + source = sample_schedule(users(:user2), users(:user1)) + previous = nil + source.payment_schedule_items.each do |item| + element = item.chained_element + + assert element.persisted? + assert_not_nil element.content + assert_not_nil element.footprint + assert_equal previous, element.previous unless previous.nil? + + assert element.content.is_a?(Hash) + FootprintService.footprint_columns(PaymentScheduleItem).each do |col| + if item[col].blank? + assert_not_includes element.content.keys, col + else + assert_includes element.content.keys, col + assert item.chained_element.content[col].is_a?(Hash) if item[col].is_a?(Hash) + end + end + assert_includes element.content.keys, 'previous' + + assert_equal item.id, element.content['id'] + assert_equal item.details, element.content['details'] + assert_equal item.payment_schedule_id, element.content['payment_schedule_id'] + assert_not_nil element.content['previous'] unless previous.nil? + assert_not element.corrupted? + + previous = element + end + assert source.check_footprint + end +end diff --git a/test/models/event_price_category_test.rb b/test/models/event_price_category_test.rb index 2b1733689..d845ff549 100644 --- a/test/models/event_price_category_test.rb +++ b/test/models/event_price_category_test.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require 'test_helper' class EventPriceCategoryTest < ActiveSupport::TestCase test "event price's category cannot be empty" do - epc = EventPriceCategory.new({price_category_id: 1, event_id: 3}) + epc = EventPriceCategory.new({ price_category_id: 1, event_id: 3 }) assert epc.invalid? assert epc.errors[:amount].present? end diff --git a/test/models/event_test.rb b/test/models/event_test.rb index 63685e4a4..ffd968c91 100644 --- a/test/models/event_test.rb +++ b/test/models/event_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class EventTest < ActiveSupport::TestCase diff --git a/test/models/export_test.rb b/test/models/export_test.rb index f2dd2116b..478282376 100644 --- a/test/models/export_test.rb +++ b/test/models/export_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class ExportTest < ActiveSupport::TestCase diff --git a/test/models/price_category_test.rb b/test/models/price_category_test.rb index a41deaf46..52496f6cf 100644 --- a/test/models/price_category_test.rb +++ b/test/models/price_category_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class PriceCategoryTest < ActiveSupport::TestCase diff --git a/test/models/space_test.rb b/test/models/space_test.rb index 54806fa80..008de7e84 100644 --- a/test/models/space_test.rb +++ b/test/models/space_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class SpaceTest < ActiveSupport::TestCase @@ -17,7 +19,7 @@ class SpaceTest < ActiveSupport::TestCase test 'update a space' do new_name = 'Bio-tech lab' space = Space.create!(bio_lab) - space.update_attributes(name: new_name) + space.update(name: new_name) subtype = StatisticSubType.find_by(key: space.slug) assert_equal new_name, subtype.label end diff --git a/test/models/ticket_test.rb b/test/models/ticket_test.rb index 5007c4e81..ba11a82dd 100644 --- a/test/models/ticket_test.rb +++ b/test/models/ticket_test.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require 'test_helper' class TicketTest < ActiveSupport::TestCase - test "ticket must have at least 1 seat" do - t = Ticket.new({event_price_category_id: 1, booked: -1}) + test 'ticket must have at least 1 seat' do + t = Ticket.new({ event_price_category_id: 1, booked: -1 }) assert t.invalid? assert t.errors[:booked].present? end diff --git a/test/models/wallet_test.rb b/test/models/wallet_test.rb index 16dbb76bf..11833f27e 100644 --- a/test/models/wallet_test.rb +++ b/test/models/wallet_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class WalletTest < ActiveSupport::TestCase diff --git a/test/models/wallet_transaction_test.rb b/test/models/wallet_transaction_test.rb index ec79d65ed..2ae7b65d5 100644 --- a/test/models/wallet_transaction_test.rb +++ b/test/models/wallet_transaction_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class WalletTransactionTest < ActiveSupport::TestCase diff --git a/test/services/accounting_service_test.rb b/test/services/accounting_service_test.rb index d0c42333b..00dbfb983 100644 --- a/test/services/accounting_service_test.rb +++ b/test/services/accounting_service_test.rb @@ -52,7 +52,7 @@ class AccountingServiceTest < ActionDispatch::IntegrationTest # Check response format & status assert_equal 201, response.status, response.body - assert_equal Mime[:json], response.content_type + assert_match Mime[:json].to_s, response.content_type # Build the accounting lines invoice_id = Invoice.last.id diff --git a/test/services/availabilities/visibility_service_test.rb b/test/services/availabilities/visibility_service_test.rb index b461ed38f..17a9c52f8 100644 --- a/test/services/availabilities/visibility_service_test.rb +++ b/test/services/availabilities/visibility_service_test.rb @@ -42,15 +42,15 @@ class Availabilities::VisibilityServiceTest < ActiveSupport::TestCase starting = Time.current.beginning_of_day ending = 1.month.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@no_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] - assert_datetimes_equal 1.month.from_now, window[1] + assert_datetimes_near Time.current, window[0] + assert_datetimes_near 1.month.from_now, window[1] end test 'member visibility for the previous month' do starting = 1.month.ago.end_of_day ending = Time.current.beginning_of_day window = Availabilities::VisibilityService.new.visibility(@no_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] + assert_datetimes_near Time.current, window[0] assert_equal ending, window[1] end @@ -58,23 +58,23 @@ class Availabilities::VisibilityServiceTest < ActiveSupport::TestCase starting = Time.current.beginning_of_day ending = 1.year.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@no_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] - assert_datetimes_equal 1.month.from_now, window[1] + assert_datetimes_near Time.current, window[0] + assert_datetimes_near 1.month.from_now, window[1] end test 'subscriber visibility for the coming month' do starting = Time.current.beginning_of_day ending = 1.month.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@with_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] - assert_datetimes_equal 1.month.from_now, window[1] + assert_datetimes_near Time.current, window[0] + assert_datetimes_near 1.month.from_now, window[1] end test 'subscriber visibility for the previous month' do starting = 1.month.ago.end_of_day ending = Time.current.beginning_of_day window = Availabilities::VisibilityService.new.visibility(@with_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] + assert_datetimes_near Time.current, window[0] assert_equal ending, window[1] end @@ -82,15 +82,15 @@ class Availabilities::VisibilityServiceTest < ActiveSupport::TestCase starting = Time.current.beginning_of_day ending = 1.year.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@with_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] - assert_datetimes_equal 1.month.from_now, window[1] + assert_datetimes_near Time.current, window[0] + assert_datetimes_near 1.month.from_now, window[1] end test '1 year subscriber visibility for the coming month' do starting = Time.current.beginning_of_day ending = 1.month.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@with_1y_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] + assert_datetimes_near Time.current, window[0] assert_equal ending, window[1] end @@ -98,7 +98,7 @@ class Availabilities::VisibilityServiceTest < ActiveSupport::TestCase starting = 1.month.ago.end_of_day ending = Time.current.beginning_of_day window = Availabilities::VisibilityService.new.visibility(@with_1y_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] + assert_datetimes_near Time.current, window[0] assert_equal ending, window[1] end @@ -106,16 +106,16 @@ class Availabilities::VisibilityServiceTest < ActiveSupport::TestCase starting = Time.current.beginning_of_day ending = 1.year.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@with_1y_subscription, 'space', starting, ending) - assert_datetimes_equal Time.current, window[0] - assert_datetimes_equal 3.months.from_now, window[1] + assert_datetimes_near Time.current, window[0] + assert_datetimes_near 3.months.from_now, window[1] end test '1 year subscriber visibility for trainings in the coming year' do starting = Time.current.beginning_of_day ending = 1.year.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@with_1y_subscription, 'training', starting, ending) - assert_datetimes_equal Time.current, window[0] - assert_datetimes_equal 1.month.from_now, window[1] + assert_datetimes_near Time.current, window[0] + assert_datetimes_near 1.month.from_now, window[1] end test 'subscriber with plan custom visibility' do @@ -124,7 +124,7 @@ class Availabilities::VisibilityServiceTest < ActiveSupport::TestCase starting = Time.current.beginning_of_day ending = 1.month.from_now.end_of_day window = Availabilities::VisibilityService.new.visibility(@with_subscription, 'machines', starting, ending) - assert_datetimes_equal Time.current, window[0] - assert_datetimes_equal 48.hours.from_now, window[1] + assert_datetimes_near Time.current, window[0] + assert_datetimes_near 48.hours.from_now, window[1] end end diff --git a/test/services/invoices/number_service_test.rb b/test/services/invoices/number_service_test.rb index caf538ee4..88a8b9ba5 100644 --- a/test/services/invoices/number_service_test.rb +++ b/test/services/invoices/number_service_test.rb @@ -140,4 +140,9 @@ class Invoices::NumberServiceTest < ActiveSupport::TestCase periodicity = Invoices::NumberService.number_periodicity(invoice, 'invoice_order-nb') assert_equal 'month', periodicity end + + test 'find document by number' do + invoice = Invoices::NumberService.find_by_number(1, date: Time.zone.parse('2012-03-01')) + assert_equal Invoice.first, invoice + end end diff --git a/test/services/subscription_extension_after_reservation_test.rb b/test/services/subscription_extension_after_reservation_test.rb index f544527a3..f095fde37 100644 --- a/test/services/subscription_extension_after_reservation_test.rb +++ b/test/services/subscription_extension_after_reservation_test.rb @@ -40,8 +40,13 @@ class SubscriptionExtensionAfterReservationTest < ActiveSupport::TestCase end test "not eligible if user doesn't have subscription" do - @user.subscriptions.destroy_all - assert_not Subscriptions::ExtensionAfterReservation.new(@reservation_training).eligible_to_extension? + user = users(:user2) # no subscriptions + reservation_training = Reservation.new( + statistic_profile: user.statistic_profile, + reservable: @training, + slots_reservations: [@slot_reservation_training] + ) + assert_not Subscriptions::ExtensionAfterReservation.new(reservation_training).eligible_to_extension? end test 'not eligible if subscription is expired' do diff --git a/test/services/users_credits_manager_test.rb b/test/services/users_credits_manager_test.rb index 729ac18d2..91c4143a8 100644 --- a/test/services/users_credits_manager_test.rb +++ b/test/services/users_credits_manager_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class UsersCreditsManagerTest < ActiveSupport::TestCase @@ -18,10 +20,14 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase ## context machine reservation test 'machine reservation from user without subscribed plan' do - @user.subscriptions.destroy_all + user = users(:user2) # no subscriptions + reservation_machine = Reservation.new( + statistic_profile: user.statistic_profile, + reservable: @machine + ) - @reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }]) - manager = UsersCredits::Manager.new(reservation: @reservation_machine) + reservation_machine.assign_attributes(slots_reservations_attributes: [{ slot_id: @availability.slots.first }]) + manager = UsersCredits::Manager.new(reservation: reservation_machine) assert_equal false, manager.will_use_credits? assert_equal 0, manager.free_hours_count @@ -114,9 +120,14 @@ class UsersCreditsManagerTest < ActiveSupport::TestCase # context training reservation test 'training reservation from user without subscribed plan' do - @user.subscriptions.destroy_all + user = users(:user2) # no subscriptions + reservation_training = Reservation.new( + statistic_profile: user.statistic_profile, + reservable: @training, + slots_reservations_attributes: [{ slot_id: @training.availabilities.first.slots.first.id }] + ) - manager = UsersCredits::Manager.new(reservation: @reservation_training) + manager = UsersCredits::Manager.new(reservation: reservation_training) assert_equal false, manager.will_use_credits? diff --git a/test/services/users_export_service_test.rb b/test/services/users_export_service_test.rb index 90d9cf1e0..49c4d01a4 100644 --- a/test/services/users_export_service_test.rb +++ b/test/services/users_export_service_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class UsersExportServiceTest < ActiveSupport::TestCase diff --git a/test/test_helper.rb b/test/test_helper.rb index ec78bdec9..8b8946b6d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -15,6 +15,9 @@ require 'helpers/invoice_helper' require 'helpers/payment_schedule_helper' require 'fileutils' +# We remove this constraint before running tests, otherwise it will prevent loading the fixtures into the DB +ActiveRecord::Base.connection.execute("DROP RULE IF EXISTS accounting_periods_del_protect ON #{AccountingPeriod.arel_table.name};") + VCR.configure do |config| config.cassette_library_dir = 'test/vcr_cassettes' config.hook_into :webmock @@ -114,9 +117,9 @@ class ActiveSupport::TestCase assert_equal expected.to_date, actual.to_date, msg end - def assert_datetimes_equal(expected, actual, msg = nil) + def assert_datetimes_near(expected, actual, msg = nil) assert_not_nil actual, msg - assert_equal expected.iso8601, actual.iso8601, msg + assert_in_delta expected.to_i, actual.to_i, 1, msg end end diff --git a/test/vcr_cassettes/last_minute_space_reservations_not_allowed.yml b/test/vcr_cassettes/last_minute_space_reservations_not_allowed.yml index 93abb5a3f..0a9b2ecdd 100644 --- a/test/vcr_cassettes/last_minute_space_reservations_not_allowed.yml +++ b/test/vcr_cassettes/last_minute_space_reservations_not_allowed.yml @@ -5,7 +5,7 @@ http_interactions: uri: https://api.stripe.com/v1/payment_methods body: encoding: UTF-8 - string: type=card&card[number]=4242424242424242&card[exp_month]=4&card[exp_year]=2023&card[cvc]=314 + string: type=card&card[number]=4242424242424242&card[exp_month]=4&card[exp_year]=2024&card[cvc]=314 headers: User-Agent: - Stripe/v1 RubyBindings/5.29.0 @@ -13,14 +13,12 @@ http_interactions: - Bearer sk_test_testfaketestfaketestfake Content-Type: - application/x-www-form-urlencoded - X-Stripe-Client-Telemetry: - - '{"last_request_metrics":{"request_id":"req_amT9NxCRaztTRy","request_duration_ms":1}}' Stripe-Version: - '2019-08-14' X-Stripe-Client-User-Agent: - - '{"bindings_version":"5.29.0","lang":"ruby","lang_version":"2.6.10 p210 (2022-04-12)","platform":"x86_64-linux","engine":"ruby","publisher":"stripe","uname":"Linux - version 6.0.12-arch1-1 (linux@archlinux) (gcc (GCC) 12.2.0, GNU ld (GNU Binutils) - 2.39.0) #1 SMP PREEMPT_DYNAMIC Thu, 08 Dec 2022 11:03:38 +0000","hostname":"Sylvain-desktop"}' + - '{"bindings_version":"5.29.0","lang":"ruby","lang_version":"3.2.1 p31 (2023-02-08)","platform":"x86_64-linux","engine":"ruby","publisher":"stripe","uname":"Linux + version 6.2.5-arch1-1 (linux@archlinux) (gcc (GCC) 12.2.1 20230201, GNU ld + (GNU Binutils) 2.40) #1 SMP PREEMPT_DYNAMIC Sat, 11 Mar 2023 14:28:13 +0000","hostname":"Sylvain-desktop"}' Accept-Encoding: - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 Accept: @@ -33,7 +31,7 @@ http_interactions: Server: - nginx Date: - - Thu, 22 Dec 2022 10:09:41 GMT + - Mon, 27 Mar 2023 07:58:29 GMT Content-Type: - application/json Content-Length: @@ -53,11 +51,11 @@ http_interactions: Cache-Control: - no-cache, no-store Idempotency-Key: - - d9ca78cb-ea0a-4ed1-a984-940ce3e62de7 + - 652a03e5-1c3f-4641-9791-7667a9348880 Original-Request: - - req_DNouBb0WOLWrs9 + - req_qtg1gz6QhbwWR6 Request-Id: - - req_DNouBb0WOLWrs9 + - req_qtg1gz6QhbwWR6 Stripe-Should-Retry: - 'false' Stripe-Version: @@ -68,7 +66,7 @@ http_interactions: encoding: UTF-8 string: |- { - "id": "pm_1MHlia2sOmf47Nz9eMYr41dZ", + "id": "pm_1MqAwj2sOmf47Nz9Wozdxx5g", "object": "payment_method", "billing_details": { "address": { @@ -92,7 +90,7 @@ http_interactions: }, "country": "US", "exp_month": 4, - "exp_year": 2023, + "exp_year": 2024, "fingerprint": "o52jybR7bnmNn6AT", "funding": "credit", "generated_from": null, @@ -108,11 +106,11 @@ http_interactions: }, "wallet": null }, - "created": 1671703781, + "created": 1679903909, "customer": null, "livemode": false, "metadata": {}, "type": "card" } - recorded_at: Thu, 22 Dec 2022 10:09:41 GMT -recorded_with: VCR 6.0.0 + recorded_at: Mon, 27 Mar 2023 07:58:29 GMT +recorded_with: VCR 6.1.0 diff --git a/yarn.lock b/yarn.lock index e02cd67c9..29b0287bb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2610,7 +2610,7 @@ "@jridgewell/set-array" "^1.0.0" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/gen-mapping@^0.3.2": +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.2" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9" integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A== @@ -2639,6 +2639,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" @@ -7572,9 +7580,9 @@ json5@^1.0.1: minimist "^1.2.0" json5@^2.1.2, json5@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" - integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== "jsx-ast-utils@^2.4.1 || ^3.0.0": version "3.2.0" @@ -8134,8 +8142,7 @@ object-keys@^1.0.12, object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-to-formdata-tz@4.4.3, "object-to-formdata@npm:object-to-formdata-tz@4.4.3": - name object-to-formdata +object-to-formdata-tz@^4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/object-to-formdata-tz/-/object-to-formdata-tz-4.4.3.tgz#3059059d0f02ce90c7fdd9d83f491e8af34707ae" integrity sha512-3XK2hDLCUAfpwatU6Jr3WzzF3ncmzScXPUiIOWgXdYwnxijCojqH41w3DdHRLoPs3MgUHzHBAtLVOFmSlaDWlQ== @@ -9594,10 +9601,10 @@ setprototypeof@1.2.0: resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== -shakapacker@6.5.5: - version "6.5.5" - resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-6.5.5.tgz#34c027b3d3b34b8241a946d4af256df81c0c04f7" - integrity sha512-KsDhjihjmkJVpdnuDvHj70RzRjreXcnMQtePp+TkHzi4sXO8gwt0btoTNrwuLrgxOfac7UQadDFYFGzJwoPz5w== +shakapacker@6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/shakapacker/-/shakapacker-6.6.0.tgz#1e372a7ce6fa93f1a7bd1820737b8168679eb220" + integrity sha512-7sNnv8PXMlgm2Ob7vZOayLKu0+PPMN3q0HEyAlkFIJtHJt7wA3p1rObhlk0/OrNeBa4dio/9HiBUeEU7bZsHvw== dependencies: glob "^7.2.0" js-yaml "^4.1.0" @@ -9701,7 +9708,7 @@ source-map@^0.5.0, source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.7.3, source-map@~0.7.2: +source-map@^0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== @@ -9973,13 +9980,13 @@ terser@^4.6.3: source-map-support "~0.5.12" terser@^5.7.2: - version "5.12.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.12.0.tgz#728c6bff05f7d1dcb687d8eace0644802a9dae8a" - integrity sha512-R3AUhNBGWiFc77HXag+1fXpAxTAFRQTJemlJKjAgD9r8xXTpjNKqIXwHM/o7Rh+O0kUJtS3WQVdBeMKFk5sw9A== + version "5.16.8" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.8.tgz#ccde583dabe71df3f4ed02b65eb6532e0fae15d5" + integrity sha512-QI5g1E/ef7d+PsDifb+a6nnVgC4F22Bg6T0xrBrz6iloVB4PUkkunp6V8nzoOOZJIzjWVdAGqCdlKlhLq/TbIA== dependencies: + "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" commander "^2.20.0" - source-map "~0.7.2" source-map-support "~0.5.20" test-exclude@^6.0.0: