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 601096db4..ee4763811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,39 @@ # Changelog Fab-manager +- 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 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/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/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/fr.yml b/config/locales/fr.yml index 3f34fa9da..1af266fa6 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/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..6886b53eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fab-manager", - "version": "5.9.1", + "version": "6.0.0-alpha", "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..e1130a257 100755 --- a/scripts/tests.sh +++ b/scripts/tests.sh @@ -15,8 +15,4 @@ if [[ -z "$stripe_secret_key" ]]; then if [[ -z "$stripe_secret_key" ]]; then echo "Key was not set, exiting..."; exit 1; fi fi -RAILS_ENV='test' bin/rails db:drop -RAILS_ENV='test' bin/rails db:create -RAILS_ENV='test' bin/rails db:migrate -clear -STRIPE_PUBLISHABLE_KEY="$stripe_public_key" STRIPE_API_KEY="$stripe_secret_key" RAILS_ENV='test' bundle exec bin/rails test "$@" +STRIPE_PUBLISHABLE_KEY="$stripe_public_key" STRIPE_API_KEY="$stripe_secret_key" RAILS_ENV='test' bin/rails test "$@" diff --git a/setup/docker-compose.yml b/setup/docker-compose.yml index 14535a251..480326d2f 100644 --- a/setup/docker-compose.yml +++ b/setup/docker-compose.yml @@ -19,6 +19,7 @@ services: - ./log:/var/log/supervisor - ./plugins:/usr/src/app/plugins - ./accounting:/usr/src/app/accounting + - ./config/auth_provider.yml:/usr/src/app/auth_provider.yml depends_on: - postgres - redis diff --git a/setup/setup.sh b/setup/setup.sh index e31e016e4..1b68c62c8 100755 --- a/setup/setup.sh +++ b/setup/setup.sh @@ -437,8 +437,7 @@ setup_assets_and_databases() read -rp "Continue? (Y/n) " confirm 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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 + 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+tn9ezObfhcIQAIKGwlIA2JlmRELfbz5LvajF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 - 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+tn9ezObfhcIQAIKGwlIA2JlmRELfbz5LvajF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 - 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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 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 b992b4e7d..66964cba7 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,8 +46,8 @@ 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_file = '/files/document.pdf' + new_image = 'event/Skateboard.jpg' + new_file = 'document.pdf' put "/api/events/#{event&.id}", params: { event: { title: new_title, @@ -73,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) @@ -89,7 +89,7 @@ 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( @@ -122,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) @@ -134,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: