diff --git a/Gemfile b/Gemfile index c24d96b7..4228e224 100644 --- a/Gemfile +++ b/Gemfile @@ -1,7 +1,7 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 4.0' +gem 'rails', '~> 4.2' # We <3 New Relic gem 'newrelic_rpm' @@ -39,6 +39,9 @@ gem 'simple_form' # Datagrid is nice gem 'datagrid' +# Wicked gem +gem 'wicked' + group :doc do # bundle exec rake doc:rails generates the API under doc/api. gem 'sdoc', require: false @@ -60,8 +63,8 @@ gem 'devise_cas_authenticatable' # Token authentication for partners gem 'simple_token_authentication' -# CanCan is used for authorization -gem 'cancan' +# CanCanCan is used for authorization +gem 'cancancan', '~> 1.9' gem 'httparty' # Logging is awesome, and paper_trail even more @@ -93,7 +96,7 @@ gem 'spreadsheet' # Run stuff in the background gem 'daemons' -gem 'delayed_job', '~> 4.0' +gem 'delayed_job', '~> 4.0.6' gem 'delayed_job_active_record' # diff --git a/Gemfile.lock b/Gemfile.lock index 0482627a..c0888c56 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,100 +9,112 @@ GIT GEM remote: https://rubygems.org/ specs: - actionmailer (4.1.5) - actionpack (= 4.1.5) - actionview (= 4.1.5) - mail (~> 2.5.4) - actionpack (4.1.5) - actionview (= 4.1.5) - activesupport (= 4.1.5) - rack (~> 1.5.2) + actionmailer (4.2.0) + actionpack (= 4.2.0) + actionview (= 4.2.0) + activejob (= 4.2.0) + mail (~> 2.5, >= 2.5.4) + rails-dom-testing (~> 1.0, >= 1.0.5) + actionpack (4.2.0) + actionview (= 4.2.0) + activesupport (= 4.2.0) + rack (~> 1.6.0) rack-test (~> 0.6.2) - actionview (4.1.5) - activesupport (= 4.1.5) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.1) + actionview (4.2.0) + activesupport (= 4.2.0) builder (~> 3.1) erubis (~> 2.7.0) - activemodel (4.1.5) - activesupport (= 4.1.5) + rails-dom-testing (~> 1.0, >= 1.0.5) + rails-html-sanitizer (~> 1.0, >= 1.0.1) + activejob (4.2.0) + activesupport (= 4.2.0) + globalid (>= 0.3.0) + activemodel (4.2.0) + activesupport (= 4.2.0) builder (~> 3.1) - activerecord (4.1.5) - activemodel (= 4.1.5) - activesupport (= 4.1.5) - arel (~> 5.0.0) - activesupport (4.1.5) - i18n (~> 0.6, >= 0.6.9) + activerecord (4.2.0) + activemodel (= 4.2.0) + activesupport (= 4.2.0) + arel (~> 6.0) + activesupport (4.2.0) + i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) - thread_safe (~> 0.1) + thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) - addressable (2.3.6) - airbrake (4.0.0) + addressable (2.3.7) + airbrake (4.1.0) builder multi_json annotate (2.6.5) activerecord (>= 2.3.0) rake (>= 0.8.7) - arel (5.0.1.20140414130214) - bcrypt (3.1.7) + arel (6.0.0) + bcrypt (3.1.10) builder (3.2.2) - cancan (1.6.10) - capistrano (3.2.1) + cancancan (1.10.1) + capistrano (3.3.5) + capistrano-stats (~> 1.1.0) i18n rake (>= 10.0.0) sshkit (~> 1.3) - capistrano-bundler (1.1.3) + capistrano-bundler (1.1.4) capistrano (~> 3.1) sshkit (~> 1.2) capistrano-rails (1.1.2) capistrano (~> 3.1) capistrano-bundler (~> 1.1) - capistrano-rvm (0.1.1) + capistrano-rvm (0.1.2) capistrano (~> 3.0) sshkit (~> 1.2) - capybara (2.4.1) + capistrano-stats (1.1.1) + capybara (2.4.4) mime-types (>= 1.16) nokogiri (>= 1.3.3) rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) chartkick (1.3.2) - choice (0.1.6) + choice (0.1.7) chronic (0.10.2) - ckeditor_rails (4.4.3) + ckeditor_rails (4.4.6) railties (>= 3.0) climate_control (0.0.3) activesupport (>= 3.0) cliver (0.3.2) - cocaine (0.5.4) + cocaine (0.5.5) climate_control (>= 0.0.3, < 1.0) - coffee-rails (4.0.1) + coffee-rails (4.1.0) coffee-script (>= 2.2.0) railties (>= 4.0.0, < 5.0) coffee-script (2.3.0) coffee-script-source execjs - coffee-script-source (1.8.0) - colorize (0.7.3) - coveralls (0.7.1) - multi_json (~> 1.3) - rest-client - simplecov (>= 0.7) - term-ansicolor - thor + coffee-script-source (1.9.0) + colorize (0.7.5) + coveralls (0.7.9) + multi_json (~> 1.10) + rest-client (~> 1.7) + simplecov (~> 0.9.1) + term-ansicolor (~> 1.3) + thor (~> 0.19.1) crack (0.4.2) safe_yaml (~> 1.0.0) daemons (1.1.9) - datagrid (1.3.1) + datagrid (1.3.6) rails (>= 3.0) - delayed_job (4.0.2) - activesupport (>= 3.0, < 4.2) - delayed_job_active_record (4.0.2) - activerecord (>= 3.0, < 4.2) + delayed_job (4.0.6) + activesupport (>= 3.0, < 5.0) + delayed_job_active_record (4.0.3) + activerecord (>= 3.0, < 5.0) delayed_job (>= 3.0, < 4.1) - devise (3.2.4) + devise (3.4.1) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 3.2.6, < 5) + responders thread_safe (~> 0.1) warden (~> 1.2.3) devise_cas_authenticatable (1.3.7) @@ -110,132 +122,145 @@ GEM rubycas-client (>= 2.2.1) docile (1.1.5) erubis (2.7.0) - execjs (2.2.1) + execjs (2.3.0) + globalid (0.3.2) + activesupport (>= 4.1.0) hike (1.2.3) - httparty (0.13.1) + httparty (0.13.3) json (~> 1.8) multi_xml (>= 0.5.2) - i18n (0.6.11) - iban-tools (0.0.9) + i18n (0.7.0) + iban-tools (1.0.0) jbuilder (1.5.3) activesupport (>= 3.0.0) multi_json (>= 1.2.0) - jquery-rails (3.1.2) - railties (>= 3.0, < 5.0) + jquery-rails (4.0.3) + rails-dom-testing (~> 1.0) + railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.1) - libv8 (3.16.14.3) - mail (2.5.4) - mime-types (~> 1.16) - treetop (~> 1.4.8) - mime-types (1.25.1) - mini_portile (0.6.0) - minitest (5.4.1) + json (1.8.2) + libv8 (3.16.14.7) + loofah (2.0.1) + nokogiri (>= 1.5.9) + mail (2.6.3) + mime-types (>= 1.16, < 3) + mime-types (2.4.3) + mini_portile (0.6.2) + minitest (5.5.1) multi_json (1.10.1) multi_xml (0.5.5) - mysql2 (0.3.16) + mysql2 (0.3.17) net-scp (1.2.1) net-ssh (>= 2.6.5) - net-ssh (2.9.1) - netrc (0.7.7) - newrelic_rpm (3.9.5.251) - nokogiri (1.6.3.1) - mini_portile (= 0.6.0) + net-ssh (2.9.2) + netrc (0.10.2) + newrelic_rpm (3.9.9.275) + nokogiri (1.6.6.2) + mini_portile (~> 0.6.0) orm_adapter (0.5.0) - paper_trail (3.0.5) + paper_trail (3.0.6) activerecord (>= 3.0, < 5.0) activesupport (>= 3.0, < 5.0) - paperclip (4.2.0) + paperclip (4.2.1) activemodel (>= 3.0.0) activesupport (>= 3.0.0) cocaine (~> 0.5.3) mime-types - pdf-core (0.2.5) - poltergeist (1.5.1) + pdf-core (0.4.0) + poltergeist (1.6.0) capybara (~> 2.1) cliver (~> 0.3.1) multi_json (~> 1.0) websocket-driver (>= 0.2.0) - polyglot (0.3.5) - prawn (1.2.1) - pdf-core (~> 0.2.5) - ttfunk (~> 1.2.0) - puma (2.9.0) + prawn (1.3.0) + pdf-core (~> 0.4.0) + ttfunk (~> 1.4.0) + puma (2.11.0) rack (>= 1.1, < 2.0) - rack (1.5.2) - rack-test (0.6.2) + rack (1.6.0) + rack-test (0.6.3) rack (>= 1.0) - rails (4.1.5) - actionmailer (= 4.1.5) - actionpack (= 4.1.5) - actionview (= 4.1.5) - activemodel (= 4.1.5) - activerecord (= 4.1.5) - activesupport (= 4.1.5) + rails (4.2.0) + actionmailer (= 4.2.0) + actionpack (= 4.2.0) + actionview (= 4.2.0) + activejob (= 4.2.0) + activemodel (= 4.2.0) + activerecord (= 4.2.0) + activesupport (= 4.2.0) bundler (>= 1.3.0, < 2.0) - railties (= 4.1.5) - sprockets-rails (~> 2.0) + railties (= 4.2.0) + sprockets-rails + rails-deprecated_sanitizer (1.0.3) + activesupport (>= 4.2.0.alpha) + rails-dom-testing (1.0.5) + activesupport (>= 4.2.0.beta, < 5.0) + nokogiri (~> 1.6.0) + rails-deprecated_sanitizer (>= 1.0.1) rails-erd (1.1.0) activerecord (>= 3.0) activesupport (>= 3.0) choice (~> 0.1.6) ruby-graphviz (~> 1.0.4) - railties (4.1.5) - actionpack (= 4.1.5) - activesupport (= 4.1.5) + rails-html-sanitizer (1.0.1) + loofah (~> 2.0) + railties (4.2.0) + actionpack (= 4.2.0) + activesupport (= 4.2.0) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rake (10.3.2) - rdoc (4.1.1) - json (~> 1.4) + rake (10.4.2) + rdoc (4.2.0) ref (1.0.5) + responders (2.1.0) + railties (>= 4.2.0, < 5) rest-client (1.7.2) mime-types (>= 1.16, < 3.0) netrc (~> 0.7) ri_cal (0.8.8) - rmagick (2.13.3) + rmagick (2.13.4) ruby-graphviz (1.0.9) - ruby-ole (1.2.11.7) + ruby-ole (1.2.11.8) rubycas-client (2.3.9) activesupport - safe_yaml (1.0.3) + safe_yaml (1.0.4) sass (3.2.19) - sass-rails (4.0.3) + sass-rails (4.0.5) railties (>= 4.0.0, < 5.0) - sass (~> 3.2.0) - sprockets (~> 2.8, <= 2.11.0) + sass (~> 3.2.2) + sprockets (~> 2.8, < 3.0) sprockets-rails (~> 2.0) sdoc (0.4.1) json (~> 1.7, >= 1.7.7) rdoc (~> 4.0) - select2-rails (3.5.9.1) + select2-rails (3.5.9.2) thor (~> 0.14) - simple_form (3.0.2) + simple_form (3.1.0) actionpack (~> 4.0) activemodel (~> 4.0) - simple_token_authentication (1.5.0) + simple_token_authentication (1.7.0) actionmailer (>= 3.2.6, < 5) - activerecord (>= 3.2.6, < 5) - devise (~> 3.2.0) - simplecov (0.9.0) + actionpack (>= 3.2.6, < 5) + devise (~> 3.2) + simplecov (0.9.1) docile (~> 1.1.0) - multi_json + multi_json (~> 1.0) simplecov-html (~> 0.8.0) simplecov-html (0.8.0) - spreadsheet (1.0.0) + spreadsheet (1.0.1) ruby-ole (>= 1.0) - sprockets (2.11.0) + sprockets (2.12.3) hike (~> 1.2) multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.1.4) + sprockets-rails (2.2.4) actionpack (>= 3.0) activesupport (>= 3.0) - sprockets (~> 2.8) - sqlite3 (1.3.9) - sshkit (1.5.1) - colorize + sprockets (>= 2.8, < 4.0) + sqlite3 (1.3.10) + sshkit (1.6.1) + colorize (>= 0.7.0) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) term-ansicolor (1.3.0) @@ -246,27 +271,27 @@ GEM thor (0.19.1) thread_safe (0.3.4) tilt (1.4.1) - tins (1.3.2) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - ttfunk (1.2.2) - turbolinks (2.3.0) + tins (1.3.4) + ttfunk (1.4.0) + turbolinks (2.5.3) coffee-rails tzinfo (1.2.2) thread_safe (~> 0.1) - uglifier (2.5.3) + uglifier (2.7.0) execjs (>= 0.3.0) json (>= 1.8.0) warden (1.2.3) rack (>= 1.0) - webmock (1.18.0) + webmock (1.20.4) addressable (>= 2.3.6) crack (>= 0.3.2) - websocket-driver (0.3.4) - whenever (0.9.2) - activesupport (>= 2.3.4) + websocket-driver (0.5.1) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.1) + whenever (0.9.4) chronic (>= 0.6.3) + wicked (1.1.0) + rails (>= 3.0.7) will_paginate (3.0.7) will_paginate-bootstrap (1.0.1) will_paginate (>= 3.0.3) @@ -280,7 +305,7 @@ DEPENDENCIES airbrake annotate barcodes! - cancan + cancancan (~> 1.9) capistrano (~> 3.1) capistrano-rails (~> 1.1) capistrano-rvm @@ -291,7 +316,7 @@ DEPENDENCIES coveralls daemons datagrid - delayed_job (~> 4.0) + delayed_job (~> 4.0.6) delayed_job_active_record devise devise_cas_authenticatable @@ -305,7 +330,7 @@ DEPENDENCIES paperclip (~> 4.0) poltergeist puma - rails (~> 4.0) + rails (~> 4.2) rails-erd ri_cal sass-rails (~> 4.0) @@ -320,5 +345,6 @@ DEPENDENCIES uglifier (>= 1.3.0) webmock whenever + wicked will_paginate (~> 3.0) will_paginate-bootstrap diff --git a/app/assets/javascripts/included_zones.js.coffee b/app/assets/javascripts/included_zones.js.coffee deleted file mode 100644 index 24f83d18..00000000 --- a/app/assets/javascripts/included_zones.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/javascripts/orders.js.coffee b/app/assets/javascripts/orders.js.coffee new file mode 100644 index 00000000..637f9186 --- /dev/null +++ b/app/assets/javascripts/orders.js.coffee @@ -0,0 +1,45 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ + +ready = -> + + # Manual order locking + $('#table-orders').on 'click', '.order-lock', -> + form = $(this).closest('form') + if form.find('.disabling').first().is(':disabled') + form.find('.disabling').prop('disabled', false) + form.find('.glyphicon').removeClass('glyphicon-lock') + form.find('.glyphicon').addClass('glyphicon-floppy-save') + else + form.submit() + + # Using the checkbox to set the paid amount to the price (or zero) + $('#table-orders').on 'change', '.order-box', -> + form = $(this).closest('form') + if $(this).is(':checked') + form.find('.order-paid').val('0.00') + else + form.find('.order-paid').val(form.find('.order-price').val()) + + $("a[data-toggle = 'tooltip']").tooltip({'container': 'body'}) + + $('th.to_pay').attr("width", 175) + + $('.btn-inc').on 'click', -> + input = $(this).parent().parent().find('input').first() + input.val(parseInt(input.val()) + 1) + + $('.btn-dec').on 'click', -> + input = $(this).parent().parent().find('input').first() + if input.val() != '0' + input.val(parseInt(input.val()) - 1) + + $('#order_email').on 'change', -> + $('#order_email_confirmation').val('') + + $('#order_email_confirmation').val($('#order_email').val()) + + +$(document).ready(ready) +$(document).on('page:load', ready) diff --git a/app/assets/javascripts/periods.js.coffee b/app/assets/javascripts/periods.js.coffee deleted file mode 100644 index 40b91eda..00000000 --- a/app/assets/javascripts/periods.js.coffee +++ /dev/null @@ -1,43 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ - -ready = -> - # Fancy fields - datePickerOptions = { - autoclose: true, - weekStart: 1, - language: 'nl', - startDate: $.format.date(Date(), "yyyy-MM-dd HH:mm") - }; - - dayPickerOptions = { - autoclose: true, - weekStart: 1, - language: 'nl', - startDate: $.format.date(Date(), "yyyy-MM-dd"), - format: 'yyyy-mm-dd' - }; - - $('#period-start').datetimepicker(datePickerOptions); - $('#period-end').datetimepicker(datePickerOptions); - - $('#new_period :checkbox').change -> - if $(this).is(':checked') - $('#period-start').datetimepicker("remove") - $('#period-end').datetimepicker("remove") - $('#period-start').datepicker(dayPickerOptions); - $('#period-end').datepicker(dayPickerOptions); - else - $('#period-start').datepicker("remove") - $('#period-end').datepicker("remove") - $('#period-start').datetimepicker(datePickerOptions); - $('#period-end').datetimepicker(datePickerOptions); - - - # Adds Bootstrap error classes to all faulty fields - $(".field_with_errors").parent().filter(".form-group").addClass("has-error"); - -$(document).ready(ready) -$(document).on('page:load', ready) - diff --git a/app/assets/javascripts/registrations.js.coffee b/app/assets/javascripts/registrations.js.coffee index f932de21..24f83d18 100644 --- a/app/assets/javascripts/registrations.js.coffee +++ b/app/assets/javascripts/registrations.js.coffee @@ -1,43 +1,3 @@ # Place all the behaviors and hooks related to the matching controller here. # All this logic will automatically be available in application.js. # You can use CoffeeScript in this file: http://coffeescript.org/ - -ready = -> - - # Manual registration locking - $('#table-registrations').on 'click', '.registration-lock', -> - form = $(this).closest('form') - if form.find('.disabling').first().is(':disabled') - form.find('.disabling').prop('disabled', false) - form.find('.glyphicon').removeClass('glyphicon-lock') - form.find('.glyphicon').addClass('glyphicon-floppy-save') - else - form.submit() - - # Using the checkbox to set the paid amount to the price (or zero) - $('#table-registrations').on 'change', '.registration-box', -> - form = $(this).closest('form') - if $(this).is(':checked') - form.find('.registration-paid').val('0.00') - else - form.find('.registration-paid').val(form.find('.registration-price').val()) - - $("a[data-toggle = 'tooltip']").tooltip({'container': 'body'}) - - $('th.to_pay').attr("width", 175) - - hideCommentFieldIfNeeded = (value) -> - val = parseInt(value) - if (window.ticketsWithComments && window.ticketsWithComments.indexOf(val) == -1) - $("#registration_comment").parent().hide(); - else - $("#registration_comment").parent().show(); - - $("#registration_access_levels").on 'change', -> - hideCommentFieldIfNeeded($(this).val()) - - hideCommentFieldIfNeeded($("#registration_access_levels").val()) - - -$(document).ready(ready) -$(document).on('page:load', ready) diff --git a/app/assets/javascripts/tickets.js.coffee b/app/assets/javascripts/tickets.js.coffee new file mode 100644 index 00000000..4660b210 --- /dev/null +++ b/app/assets/javascripts/tickets.js.coffee @@ -0,0 +1,21 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://coffeescript.org/ + +ready = -> + + hideCommentFieldIfNeeded = (value) -> + val = parseInt(value) + if (window.ticketsWithComments && window.ticketsWithComments.indexOf(val) == -1) + $("#ticket_comment").parent().hide(); + else + $("#ticket_comment").parent().show(); + + $("#ticket_access_levels").on 'change', -> + hideCommentFieldIfNeeded($(this).val()) + + hideCommentFieldIfNeeded($("#ticket_access_levels").val()) + + +$(document).ready(ready) +$(document).on('page:load', ready) diff --git a/app/assets/javascripts/zones.js.coffee b/app/assets/javascripts/zones.js.coffee deleted file mode 100644 index 24f83d18..00000000 --- a/app/assets/javascripts/zones.js.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/app/assets/stylesheets/included_zones.css.scss b/app/assets/stylesheets/included_zones.css.scss deleted file mode 100644 index d9914ffd..00000000 --- a/app/assets/stylesheets/included_zones.css.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the IncludedZones controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/orders.css.scss b/app/assets/stylesheets/orders.css.scss new file mode 100644 index 00000000..bb9fcdf5 --- /dev/null +++ b/app/assets/stylesheets/orders.css.scss @@ -0,0 +1,14 @@ +// Place all the styles related to the Orders controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ +#table-orders td { + vertical-align: middle; +} + +.no-margin { + margin: 0px; +} + +.no-padding { + padding: 0px; +} diff --git a/app/assets/stylesheets/registrations.css.scss b/app/assets/stylesheets/registrations.css.scss index 41b182ea..f6e17a22 100644 --- a/app/assets/stylesheets/registrations.css.scss +++ b/app/assets/stylesheets/registrations.css.scss @@ -1,14 +1,3 @@ -// Place all the styles related to the Registrations controller here. +// Place all the styles related to the registrations controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ -#table-registrations td { - vertical-align: middle; -} - -.no-margin { - margin: 0px; -} - -.no-padding { - padding: 0px; -} diff --git a/app/assets/stylesheets/periods.css.scss b/app/assets/stylesheets/tickets.css.scss similarity index 64% rename from app/assets/stylesheets/periods.css.scss rename to app/assets/stylesheets/tickets.css.scss index 027648e1..92b729b4 100644 --- a/app/assets/stylesheets/periods.css.scss +++ b/app/assets/stylesheets/tickets.css.scss @@ -1,3 +1,3 @@ -// Place all the styles related to the Periods controller here. +// Place all the styles related to the Tickets controller here. // They will automatically be included in application.css. // You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/zones.css.scss b/app/assets/stylesheets/zones.css.scss deleted file mode 100644 index cbad403f..00000000 --- a/app/assets/stylesheets/zones.css.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the Zones controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/access_levels_controller.rb b/app/controllers/access_levels_controller.rb index 2822878e..a6af5834 100644 --- a/app/controllers/access_levels_controller.rb +++ b/app/controllers/access_levels_controller.rb @@ -44,7 +44,7 @@ def destroy @event = Event.find params.require(:event_id) authorize! :update, @event access_level = AccessLevel.find params.require(:id) - unless access_level.registrations.any? + unless access_level.tickets.any? # Save the name so we can respond it as we still have to # be able to delete it @id = access_level.id @@ -54,17 +54,6 @@ def destroy end end - def set_zones - @event = Event.find params.require(:event_id) - authorize! :update, @event - access_level = AccessLevel.find params.require(:access_level_id) - zones = params.require(:access_level).require(:zones) - # Features introduced in new versions apparently suck pretty hard - # manually parse the output here from collection_check_boxes, because rails - access_level.set_zones_by_ids zones[0..-2].map { |z| z.split.first.to_i } - redirect_to @event - end - def toggle_visibility @event = Event.find params.require(:event_id) authorize! :update, @event diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 2cee80c3..664a86fc 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -17,13 +17,6 @@ def index end def show - @registration = @event.registrations.build - - if current_user - @registration.name = current_user.display_name - @registration.student_number = current_user.cas_ugentStudentID - @registration.email = current_user.cas_mail - end end def new @@ -68,9 +61,9 @@ def statistics @event = Event.find params.require(:id) authorize! :view_stats, @event - if not @event.registrations.empty? + if not @event.tickets.empty? - min, max = @event.registrations.pluck(:created_at).minmax + min, max = @event.tickets.pluck(:created_at).minmax zeros = Hash[] while min <= max zeros[min.strftime("%Y-%m-%d")] = 0 @@ -78,7 +71,7 @@ def statistics end @data = @event.access_levels.map do |al| - {name: al.name, data: zeros.merge(al.registrations.group('date(registrations.created_at)').count)} + {name: al.name, data: zeros.merge(al.tickets.group('date(tickets.created_at)').count)} end else @@ -96,17 +89,17 @@ def check_in authorize! :update, @event barcode = params.require(:code) - @registration = @event.registrations.find_by_barcode barcode + @ticket = @event.tickets.find_by_barcode barcode - if @registration - if not @registration.is_paid - flash.now[:warning] = "Person has not paid yet! Resting amount: €" + @registration.to_pay.to_s - elsif @registration.checked_in_at - flash.now[:warning] = "Person already checked in at " + view_context.nice_time(@registration.checked_in_at) + "!" + if @ticket + if not @ticket.order.is_paid + flash.now[:warning] = "Person has not paid yet! Resting amount: €" + @ticket.order.to_pay.to_s + elsif @ticket.checked_in_at + flash.now[:warning] = "Person already checked in at " + view_context.nice_time(@ticket.checked_in_at) + "!" else flash.now[:success] = "Person has been scanned!" - @registration.checked_in_at = Time.now - @registration.save! + @ticket.checked_in_at = Time.now + @ticket.save! end else flash.now[:error] = "Barcode not found" diff --git a/app/controllers/orders/build_controller.rb b/app/controllers/orders/build_controller.rb new file mode 100644 index 00000000..72545b83 --- /dev/null +++ b/app/controllers/orders/build_controller.rb @@ -0,0 +1,68 @@ +class Orders::BuildController < ApplicationController + include Wicked::Wizard + + steps :add_tickets, :add_info, :add_ticket_info, :confirmation + + def show + @event = Event.find params.require(:event_id) + @order = @event.orders.find params.require(:order_id) + + case step + when :add_tickets + @access_levels = @event.access_levels.find_all { |al| can? :show, al } + when :add_info + when :add_ticket_info + @tickets = @order.tickets + when :confirmation + end + + render_wizard + end + + def create + @event = Event.find params.require(:event_id) + @order = @event.orders.create! status: 'initial' + + redirect_to wizard_path(steps.first, order_id: @order.id) + end + + def update + @event = Event.find params.require(:event_id) + @order = @event.orders.find params.require(:order_id) + + + case step + when :add_tickets + @access_levels = @event.access_levels.find_all { |al| can? :show, al } + params.require(:access_levels).each do |id, amount| + amount = amount[:amount].to_i + tickets = @order.tickets.where(access_level_id: id) + if tickets.count > amount + # destroy last tickets + tickets.where.not(id: tickets.limit(amount).pluck(:id)).destroy_all + else + # create exactly as many as needed + (amount - tickets.count).times do + @order.tickets.create! access_level_id: id, status: 'initial' + end + end + end + when :add_info + @order.update params.require(:order).permit(:name, :email, :email_confirmation, :gsm) + when :add_ticket_info + @tickets = @order.tickets + params.require(:tickets).each do |id, ticket| + @tickets.find(id).update_columns ticket.merge({ status: 'filled_in' }) + end + when :confirmation + @order.deliver + end + + @order.status = step.to_s + @order.status = 'active' if step == steps.last + @order.save + + render_wizard @order + end + +end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb new file mode 100644 index 00000000..92da78bb --- /dev/null +++ b/app/controllers/orders_controller.rb @@ -0,0 +1,134 @@ +class OrdersController < ApplicationController + + before_action :authenticate_user!, only: [:index, :destroy, :resend, :update, :email, :upload] + + require 'csv' + + respond_to :html, :js + + def index + @event = Event.find params.require(:event_id) + + authorize! :read, @event + + @ordersgrid = OrdersGrid.new(params[:orders_grid]) do |scope| + scope.where(event_id: @event.id).order("orders.price - paid DESC") + end + + @orders = @ordersgrid.assets + @orders = @orders.paginate(page: params[:page], per_page: 25) + end + + def new + @event = Event.find params.require(:event_id) + @orders = Order.new + end + + def destroy + @event = Event.find params.require(:event_id) + authorize! :destroy, @event + order = Order.find params.require(:id) + @id = order.id + order.destroy + end + + def info + @order = Order.find params.require(:id) + authorize! :read, @order.event + end + + def resend + @order = Order.find params.require(:id) + authorize! :update, @order.event + + @order.deliver + end + + def create + @event = Event.find params.require(:event_id) + + # Check if the user can register + authorize! :register, @event + + render "events/show" + end + + def update + @order = Order.find params.require(:id) + authorize! :update, @order + + paid = @order.paid + @order.update params.require(:order).permit(:to_pay) + if @order.paid != paid # Did the amount change? + @order.deliver + end + + respond_with @order + end + + def email + @event = Event.find params.require(:event_id) + authorize! :read, @event + + to = @event.orders.pluck(:email) + + MassMailer.general_message(@event.contact_email, to, params['email']['subject'], params['email']['body']).deliver + + redirect_to event_orders_path(@event) + end + + def upload + @event = Event.find params.require(:event_id) + authorize! :update, @event + sep = params.require('separator') + paid = params.require('amount_column').upcase + fails = [] + counter = 0 + + begin + CSV.parse(params.require(:csv_file).read.upcase, col_sep: sep, headers: :first_row) do |row| + + order = Order.find_payment_code_from_csv(row.to_s) + # If the order doesn't exist + unless order + fails << row if order.nil? + next + end + + # if we can't read the amount of money, FAIL + amount = row[paid].sub(',', '.') + begin + amount = Float(amount) + rescue + fails << row + next + end + + order.paid += amount + order.payment_code = Order.create_payment_code + order.save + + order.deliver + + counter += 1 + end + + success_msg = "Updated #{ActionController::Base.helpers.pluralize counter, "payment"} successfully." + if fails.any? + flash.now[:success] = success_msg + flash.now[:error] = "The rows listed below contained an invalid code, please fix them by hand." + @csvheaders = fails.first.headers + @csvfails = fails + render 'upload' + else + flash[:success] = success_msg + redirect_to action: :index + end + rescue CSV::MalformedCSVError + flash[:error] = "The file could not be parsed. Make sure that you uploaded the correct file and that the column seperator settings have been set to the correct seperator." + redirect_to action: :index + end + + end + +end diff --git a/app/controllers/partners_controller.rb b/app/controllers/partners_controller.rb index 7acabf55..30ab0490 100644 --- a/app/controllers/partners_controller.rb +++ b/app/controllers/partners_controller.rb @@ -81,18 +81,24 @@ def confirm if @partner.confirmed flash.now[:error] = "You have already registered for this event. Please check your mailbox." else - @registration = @event.registrations.new( + @order = @event.orders.new( + name: @partner.name, email: @partner.email, + price: @partner.access_level.price, + paid: 0, + ) + @ticket = @order.tickets.new( name: @partner.name, + email: @partner.email, student_number: nil, comment: nil, - price: @partner.access_level.price, - paid: 0 + access_level: @partner.access_level, + event: @event, ) - @registration.access_levels << @partner.access_level @partner.confirmed = true - if @registration.save and @partner.save then - @registration.deliver + + if @ticket.save and @order.save and @partner.save then + @order.deliver flash.now[:success] = "Your invitation has been confirmed. Your ticket should arrive shortly." else flash.now[:error] = "Is seems there already is someone with your name and/or email registered for this event. #{view_context.mail_to @event.contact_email, "Contact us"} if this is not correct.".html_safe diff --git a/app/controllers/periods_controller.rb b/app/controllers/periods_controller.rb deleted file mode 100644 index 42563832..00000000 --- a/app/controllers/periods_controller.rb +++ /dev/null @@ -1,36 +0,0 @@ -class PeriodsController < ApplicationController - - # You need to be logged in for everything. - before_action :authenticate_user! - - respond_to :html, :js - - def index - @event = Event.find params.require(:event_id) - authorize! :read, @event - end - - def show - @period = Period.find params.require(:id) - authorize! :read, @period.event - end - - def new - @period = Period.new - end - - def create - @event = Event.find params.require(:event_id) - authorize! :update, @event - @period = @event.periods.create params.require(:period).permit(:name, :starts, :ends) - end - - def destroy - @event = Event.find params.require(:event_id) - authorize! :update, @event - period = Period.find params.require(:id) - @id = period.id - period.destroy - end - -end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb deleted file mode 100644 index be4d549c..00000000 --- a/app/controllers/registrations_controller.rb +++ /dev/null @@ -1,190 +0,0 @@ -class RegistrationsController < ApplicationController - - before_action :authenticate_user!, only: [:index, :destroy, :resend, :update, :email, :upload] - - require 'csv' - - respond_to :html, :js - - def index - @event = Event.find params.require(:event_id) - - authorize! :read, @event - - @registrationsgrid = RegistrationsGrid.new(params[:registrations_grid]) do |scope| - scope.where(event_id: @event.id).order("registrations.price - paid DESC") - end - - @registrations = @registrationsgrid.assets - @registrations = @registrations.paginate(page: params[:page], per_page: 25) - end - - def new - @event = Event.find params.require(:event_id) - @registration = Registration.new - end - - def destroy - @event = Event.find params.require(:event_id) - authorize! :destroy, @event - registration = Registration.find params.require(:id) - @id = registration.id - registration.destroy - end - - def info - @registration = Registration.find params.require(:id) - authorize! :read, @registration.event - end - - def resend - @registration = Registration.find params.require(:id) - authorize! :update, @registration.event - if @registration.is_paid - RegistrationMailer.ticket(@registration).deliver - else - RegistrationMailer.confirm_registration(@registration).deliver - end - end - - def basic - @event = Event.find params.require(:event_id) - - # Check if the user can register - authorize! :register, @event - requested_access_level = @event.access_levels.find(params.require(:registration).require(:access_levels)) - authorize! :register, requested_access_level - - # Make the registration - @registration = @event.registrations.new params.require(:registration).permit(:email, :name, :student_number, :comment) - @registration.access_levels << requested_access_level - @registration.price = requested_access_level.price - @registration.paid = 0 - - # overwrite student_number so setting this will not work - if requested_access_level.member_only? - @registration.student_number = current_user.cas_ugentStudentID - end - @registration.save - - # Send the confirmation email. - if not @registration.errors.any? - @registration.generate_barcode - - if @registration.is_paid - RegistrationMailer.ticket(@registration).deliver - else - RegistrationMailer.confirm_registration(@registration).deliver - end - - flash[:success] = "Registration successful. Please check your mailbox for your ticket or further payment information." - respond_with @event - else - render "events/show" - end - end - - def advanced - # TODO can can - @event = Event.find params.require(:event_id) - @registration = @event.registrations.create params.require(:registration).permit(:email, :name) - params.require(:registration).require(:checkboxes).each do |access_level, periods| - periods.each do |period, checked| - if checked == "on" then - access = @registration.accesses.build access_level_id: access_level, period_id: period - access.save - end - end - end - end - - def update - @registration = Registration.find params.require(:id) - paid = @registration.paid - authorize! :update, @registration - @registration.update params.require(:registration).permit(:to_pay) - if @registration.paid != paid then - if @registration.is_paid - RegistrationMailer.ticket(@registration).deliver - if @registration.paid > @registration.price - RegistrationMailer.notify_overpayment(@registration).deliver - end - else - RegistrationMailer.confirm_registration(@registration).deliver - end - end - respond_with @registration - end - - def email - @event = Event.find params.require(:event_id) - authorize! :read, @event - to_id = params['to'].to_i - if to_id == -1 - to = @event.registrations.pluck(:email) - else - to = @event.access_levels.find_by_id(to_id).registrations.pluck(:email) - end - MassMailer.general_message(@event.contact_email, to, params['email']['subject'], params['email']['body']).deliver - redirect_to event_registrations_path(@event) - end - - def upload - @event = Event.find params.require(:event_id) - authorize! :update, @event - sep = params.require('separator') - paid = params.require('amount_column').upcase - fails = [] - counter = 0 - - begin - CSV.parse(params.require(:csv_file).read.upcase, col_sep: sep, headers: :first_row) do |row| - - registration = Registration.find_payment_code_from_csv(row.to_s) - # If the registration doesn't exist - unless registration - fails << row if registration.nil? - next - end - - # if we can't read the amount of money, FAIL - amount = row[paid].sub(',', '.') - begin - amount = Float(amount) - rescue - fails << row - next - end - - registration.paid += amount - registration.payment_code = Registration.create_payment_code - registration.save - - if registration.is_paid - RegistrationMailer.ticket(registration).deliver - else - RegistrationMailer.confirm_registration(registration).deliver - end - - counter += 1 - end - - success_msg = "Updated #{ActionController::Base.helpers.pluralize counter, "payment"} successfully." - if fails.any? - flash.now[:success] = success_msg - flash.now[:error] = "The rows listed below contained an invalid code, please fix them by hand." - @csvheaders = fails.first.headers - @csvfails = fails - render 'upload' - else - flash[:success] = success_msg - redirect_to action: :index - end - rescue CSV::MalformedCSVError - flash[:error] = "The file could not be parsed. Make sure that you uploaded the correct file and that the column seperator settings have been set to the correct seperator." - redirect_to action: :index - end - - end - -end diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb new file mode 100644 index 00000000..363caa2d --- /dev/null +++ b/app/controllers/tickets_controller.rb @@ -0,0 +1,68 @@ +class TicketsController < ApplicationController + + before_action :authenticate_user!, only: [:index, :destroy, :resend, :update, :email, :upload] + + require 'csv' + + respond_to :html, :js + + def index + @event = Event.find params.require(:event_id) + + authorize! :read, @event + + @ticketsgrid = TicketsGrid.new(params[:tickets_grid]) do |scope| + scope.where(event_id: @event.id) + end + + @tickets = @ticketsgrid.assets + @tickets = @tickets.paginate(page: params[:page], per_page: 25) + end + + def new + @event = Event.find params.require(:event_id) + @tickets = Ticket.new + end + + def destroy + @event = Event.find params.require(:event_id) + authorize! :destroy, @event + ticket = Ticket.find params.require(:id) + @id = ticket.id + ticket.destroy + end + + def info + @ticket = Ticket.find params.require(:id) + authorize! :read, @ticket.event + end + + def resend + @ticket = Ticket.find params.require(:id) + authorize! :update, @ticket.event + + TicketMailer.ticket(@ticket).deliver + end + + def create + end + + def update + @ticket = Ticket.find params.require(:id) + respond_with @ticket + end + + def email + @event = Event.find params.require(:event_id) + authorize! :read, @event + to_id = params['to'].to_i + if to_id == -1 + to = @event.tickets.pluck(:email) + else + to = @event.access_levels.find_by_id(to_id).tickets.pluck(:email) + end + MassMailer.general_message(@event.contact_email, to, params['email']['subject'], params['email']['body']).deliver + redirect_to event_tickets_path(@event) + end + +end diff --git a/app/controllers/zones_controller.rb b/app/controllers/zones_controller.rb deleted file mode 100644 index 26895e6b..00000000 --- a/app/controllers/zones_controller.rb +++ /dev/null @@ -1,35 +0,0 @@ -class ZonesController < ApplicationController - - # You need to be logged in for everything. - before_action :authenticate_user!, except: :show - - respond_to :html, :js - - def index - @event = Event.find params.require(:event_id) - authorize! :read, @event - end - - def show - @zone = Zone.find params.require(:id) - end - - def new - @zone = Zone.new - end - - def create - @event = Event.find params.require(:event_id) - authorize! :update, @event - @zone = @event.zones.create params.require(:zone).permit(:name) - end - - def destroy - zone = Zone.find params.require(:id) - @id = zone.id - @event = Event.find params.require(:event_id) - authorize! :update, @event - zone.destroy - end - -end diff --git a/app/grids/orders_grid.rb b/app/grids/orders_grid.rb new file mode 100644 index 00000000..243970e3 --- /dev/null +++ b/app/grids/orders_grid.rb @@ -0,0 +1,24 @@ +class OrdersGrid + include Datagrid + + scope do + Order.active + end + + # We use the lower() instead of ilike because SQLite dev doesn't like ilike + filter(:name) { |value| where("lower(orders.name) like ?", "%#{value.downcase}%") } + filter(:email) { |value| where("lower(orders.email) like ?", "%#{value.downcase}%") } + filter(:payment_code) { |value| where("orders.payment_code like ?","%#{value}%") } + filter(:only_paid) { |value| where("paid = price") if value == '1' } + filter(:only_unpaid) { |value| where.not("paid = price") if value == '1' } + + column(:name) + column(:email) + column(:payment_code) + column(:to_pay, html: true, order: "orders.price - paid", descending: true) do |order| + render partial: 'order_payment_form', locals: { order: order } + end + column(:actions, html: true) do |order| + render partial: 'order_actions', locals: { order: order } + end +end diff --git a/app/grids/registrations_grid.rb b/app/grids/registrations_grid.rb deleted file mode 100644 index 2400cded..00000000 --- a/app/grids/registrations_grid.rb +++ /dev/null @@ -1,30 +0,0 @@ -class RegistrationsGrid - include Datagrid - - scope do - Registration - end - - # We use the lower() instead of ilike because SQLite dev doesn't like ilike - filter(:name) { |value| where("lower(registrations.name) like ?", "%#{value.downcase}%") } - filter(:email) { |value| where("lower(registrations.email) like ?", "%#{value.downcase}%") } - filter(:access_level) { |value, scope| scope.joins(:access_levels).where(access_levels: { id: value }) } - filter(:payment_code) { |value| where("registrations.payment_code like ?","%#{value}%") } - filter(:only_paid) { |value| where("paid = price") if value == '1' } - filter(:only_unpaid) { |value| where.not("paid = price") if value == '1' } - - column(:name) - column(:email) - column(:access_level, header: "Ticket", order: proc { |scope| - scope.joins(:accesses).joins(:access_levels).order("access_levels.name") - }) do |registration| - registration.access_levels.first.try :name - end - column(:payment_code) - column(:to_pay, html: true, order: "registrations.price - paid", descending: true) do |registration| - render partial: 'registration_payment_form', locals: { registration: registration } - end - column(:actions, html: true) do |registration| - render partial: 'registration_actions', locals: { registration: registration } - end -end diff --git a/app/grids/tickets_grid.rb b/app/grids/tickets_grid.rb new file mode 100644 index 00000000..f1501eea --- /dev/null +++ b/app/grids/tickets_grid.rb @@ -0,0 +1,23 @@ +class TicketsGrid + include Datagrid + + scope do + Ticket.active + end + + # We use the lower() instead of ilike because SQLite dev doesn't like ilike + filter(:name) { |value| where("lower(tickets.name) like ?", "%#{value.downcase}%") } + filter(:email) { |value| where("lower(tickets.email) like ?", "%#{value.downcase}%") } + filter(:access_level) { |value, scope| scope.joins(:access_levels).where(access_levels: { id: value }) } + + column(:name) + column(:email) + column(:access_level, header: "Ticket", order: proc { |scope| + scope.joins(:access_levels).order("access_levels.name") + }) do |ticket| + ticket.access_level.try :name + end + column(:actions, html: true) do |ticket| + render partial: 'ticket_actions', locals: { ticket: ticket } + end +end diff --git a/app/helpers/orders_helper.rb b/app/helpers/orders_helper.rb new file mode 100644 index 00000000..70dd31a0 --- /dev/null +++ b/app/helpers/orders_helper.rb @@ -0,0 +1,12 @@ +module OrdersHelper + + def nice_changeset(name, change) + case name + when 'paid' + "Changed the amount paid from #{euro(@registration.price - change[0]/100)} to #{euro(@registration.price - change[1])}" + when 'payment_code' + "Payment code updated to #{change[1]}" + end + end + +end diff --git a/app/helpers/registrations_helper.rb b/app/helpers/registrations_helper.rb index c123db3f..b1003768 100644 --- a/app/helpers/registrations_helper.rb +++ b/app/helpers/registrations_helper.rb @@ -1,14 +1,2 @@ module RegistrationsHelper - - def nice_changeset(name, change) - case name - when 'paid' - "Changed the amount paid from #{euro(@registration.price - change[0]/100)} to #{euro(@registration.price - change[1])}" - when 'checked_in_at' - "Checked in at #{nice_time change[1]}" - when 'payment_code' - "Payment code updated to #{change[1]}" - end - end - end diff --git a/app/helpers/tickets_helper.rb b/app/helpers/tickets_helper.rb new file mode 100644 index 00000000..e6a606b6 --- /dev/null +++ b/app/helpers/tickets_helper.rb @@ -0,0 +1,10 @@ +module TicketsHelper + + def nice_changeset(name, change) + case name + when 'checked_in_at' + "Checked in at #{nice_time change[1]}" + end + end + +end diff --git a/app/mailers/order_mailer.rb b/app/mailers/order_mailer.rb new file mode 100644 index 00000000..09b63dea --- /dev/null +++ b/app/mailers/order_mailer.rb @@ -0,0 +1,17 @@ +class OrderMailer < ActionMailer::Base + + helper ApplicationHelper + + default from: "noreply@event.fkgent.be" + + def confirm_order(order) + @order = order + mail to: "#{order.name} <#{order.email}>", subject: "Order for #{order.event.name}" + end + + def notify_overpayment(order) + @order = order + mail to: "#{order.name} <#{order.email}>", subject: "Overpayment for #{order.event.name}" + end + +end diff --git a/app/mailers/registration_mailer.rb b/app/mailers/registration_mailer.rb deleted file mode 100644 index 3e055e7f..00000000 --- a/app/mailers/registration_mailer.rb +++ /dev/null @@ -1,26 +0,0 @@ -class RegistrationMailer < ActionMailer::Base - - helper ApplicationHelper - - default from: "noreply@event.fkgent.be" - - def confirm_registration(registration) - @registration = registration - mail to: "#{registration.name} <#{registration.email}>", subject: "Registration for #{registration.event.name}" - end - - def ticket(registration) - @registration = registration - - barcode = Barcodes.create('EAN13', data: registration.barcode_data, bar_width: 35, bar_height: 1500, caption_height: 300, caption_size: 275 ) # required: height > size - attachments.inline['barcode.png'] = Barcodes::Renderer::Image.new(barcode).render - - mail to: "#{registration.name} <#{registration.email}>", subject: "Ticket for #{registration.event.name}" - end - - def notify_overpayment(registration) - @registration = registration - mail to: "#{registration.name} <#{registration.email}>", subject: "Overpayment for #{registration.event.name}" - end - -end diff --git a/app/mailers/ticket_mailer.rb b/app/mailers/ticket_mailer.rb new file mode 100644 index 00000000..217cf4a7 --- /dev/null +++ b/app/mailers/ticket_mailer.rb @@ -0,0 +1,16 @@ +class TicketMailer < ActionMailer::Base + + helper ApplicationHelper + + default from: "noreply@event.fkgent.be" + + def ticket(ticket) + @ticket = ticket + + barcode = Barcodes.create('EAN13', data: ticket.barcode_data, bar_width: 35, bar_height: 1500, caption_height: 300, caption_size: 275 ) # required: height > size + attachments.inline['barcode.png'] = Barcodes::Renderer::Image.new(barcode).render + + mail to: "#{ticket.name} <#{ticket.email}>", subject: "Ticket for #{ticket.event.name}" + end + +end diff --git a/app/models/ability.rb b/app/models/ability.rb index c90c4238..6fa60cd9 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -39,7 +39,8 @@ def user_rules(user) # Admins can do anything! if user.admin? can :manage, Event - can :manage, Registration + can :manage, Ticket + can :manage, Order can :manage, Partner end @@ -56,6 +57,18 @@ def user_rules(user) end end + can :show, AccessLevel do |access_level| + # not if you can't register for the event + next false unless can? :register, access_level.event + + next false if access_level.hidden + + # don't support private tickets for the moment + next false unless access_level.public + + true + end + # can you register for an access level can :register, AccessLevel do |access_level| # not if you can't register for the event @@ -74,9 +87,14 @@ def user_rules(user) end end - # add modify registrations permission for club members - can :update, Registration do |registration| - clubs.include? registration.event.club + # add modify tickets permission for club members + can :update, Ticket do |ticket| + clubs.include? ticket.event.club + end + + # add modify tickets permission for club members + can :update, Order do |order| + clubs.include? order.event.club end # can view statistics? diff --git a/app/models/access.rb b/app/models/access.rb deleted file mode 100644 index 83ce2998..00000000 --- a/app/models/access.rb +++ /dev/null @@ -1,17 +0,0 @@ -# == Schema Information -# -# Table name: accesses -# -# id :integer not null, primary key -# period_id :integer -# registration_id :integer -# created_at :datetime -# updated_at :datetime -# access_level_id :integer -# - -class Access < ActiveRecord::Base - belongs_to :access_level - belongs_to :period - belongs_to :registration -end diff --git a/app/models/access_level.rb b/app/models/access_level.rb index 58b87a9e..b201d406 100644 --- a/app/models/access_level.rb +++ b/app/models/access_level.rb @@ -10,7 +10,7 @@ # updated_at :datetime # capacity :integer # price :integer -# public :boolean default(TRUE) +# public :boolean default("t") # has_comment :boolean # hidden :boolean # member_only :boolean @@ -19,11 +19,9 @@ class AccessLevel < ActiveRecord::Base belongs_to :event - has_many :included_zones, dependent: :destroy - has_many :zones, through: :included_zones + has_many :tickets - has_many :accesses, dependent: :destroy - has_many :registrations, through: :accesses + attr_accessor :amount has_and_belongs_to_many :promos @@ -54,7 +52,7 @@ def name_with_price end def tickets_left - capacity - registrations.count if capacity.presence + self.capacity - self.tickets.count if self.capacity.presence end def price diff --git a/app/models/event.rb b/app/models/event.rb index 2859be18..4ee7be20 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -14,16 +14,16 @@ # registration_open_date :datetime # registration_close_date :datetime # bank_number :string(255) -# show_ticket_count :boolean default(TRUE) +# show_ticket_count :boolean default("t") # contact_email :string(255) # export_file_name :string(255) # export_content_type :string(255) # export_file_size :integer # export_updated_at :datetime -# export_status :string(255) # show_statistics :boolean +# export_status :string(255) # club_id :integer -# registration_open :boolean default(TRUE) +# registration_open :boolean default("t") # class Event < ActiveRecord::Base @@ -32,12 +32,10 @@ class Event < ActiveRecord::Base has_many :access_levels, dependent: :destroy has_many :partners, dependent: :destroy - has_many :zones, dependent: :destroy - has_many :registrations, dependent: :destroy + has_many :tickets, through: :orders + has_many :orders, dependent: :destroy has_many :promos, dependent: :destroy - has_many :periods, dependent: :destroy - validates :description, presence: true validates :end_date, presence: true validates :location, presence: true @@ -65,9 +63,9 @@ def generate_xls xls = Spreadsheet::Workbook.new sheet = xls.create_worksheet - sheet.update_row 0, "Naam", "Email", "Studentnummer", "Ticket", "Comment" - registrations.select(&:is_paid).each.with_index do |reg, i| - sheet.update_row i + 1, reg.name, reg.email, reg.student_number, reg.access_levels.first.name, reg.comment + sheet.update_row 0, "Naam", "Email", "Studentnummer", "Ticket", "Comment", "Is paid" + tickets.each.with_index do |ticket, i| + sheet.update_row i + 1, ticket.name, ticket.email, ticket.student_number, ticket.access_level.name, ticket.comment, ticket.order.is_paid end data = Tempfile.new(["export", ".xls"]) diff --git a/app/models/included_zone.rb b/app/models/included_zone.rb deleted file mode 100644 index 40c189ce..00000000 --- a/app/models/included_zone.rb +++ /dev/null @@ -1,15 +0,0 @@ -# == Schema Information -# -# Table name: included_zones -# -# id :integer not null, primary key -# zone_id :integer -# access_level_id :integer -# created_at :datetime -# updated_at :datetime -# - -class IncludedZone < ActiveRecord::Base - belongs_to :zone - belongs_to :access_level -end diff --git a/app/models/order.rb b/app/models/order.rb new file mode 100644 index 00000000..456f707a --- /dev/null +++ b/app/models/order.rb @@ -0,0 +1,137 @@ +# == Schema Information +# +# Table name: orders +# +# id :integer not null, primary key +# status :string default("initial") +# name :string +# email :string +# gsm :string +# ticket_id :integer +# event_id :integer +# paid :integer +# price :integer +# created_at :datetime +# updated_at :datetime +# payment_code :string +# + +class Order < ActiveRecord::Base + belongs_to :event + has_many :tickets + + scope :paid, -> { where("price <= paid") } + scope :active, -> { where(status: 'active') } + + has_paper_trail only: [:paid, :payment_code] + + # Should validate on add_tickets + validates :tickets, presence: { message: "is empty! Please pick at least one." }, if: :active_or_add_tickets? + + # Should validate on add_info + validates :name, presence: true, if: :active_or_add_info? + # This should be a setting per event basis + # validates :gsm, presence: true, if: :active_or_add_info? + validates :email, email: true, presence: true, confirmation: true, if: :active_or_add_info? + + # Should validate on add_ticket_info + validates_associated :tickets, if: :active_or_add_ticket_info? + + # Should validate on pay + validates :paid, presence: true, numericality: { only_integer: true }, if: :active_or_pay? + validates :price, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, if: :active_or_pay? + validates :payment_code, presence: true, uniqueness: true, if: :active_or_pay? + + default_scope { order "name ASC" } + + before_validation do |record| + if record.payment_code.nil? then + record.payment_code = self.class.create_payment_code + end + end + + # Wicked methods + def active? + status == 'active' + end + + def active_or_add_tickets? + status.include?('add_tickets') || active? + end + + def active_or_add_info? + status.include?('add_info') || active? + end + + def active_or_add_ticket_info? + status.include?('add_ticket_info') || active? + end + + def active_or_pay? + status.include?('pay') || active? + end + + def paid + from_cents read_attribute(:paid) + end + + def paid=(value) + write_attribute :paid, to_cents(value) + end + + def to_pay + self.price - self.paid + end + + def to_pay=(value) + self.paid = self.price - (to_cents(value) / 100.0) + end + + def price + from_cents read_attribute(:price) + end + + def price=(value) + write_attribute(:price, to_cents(value)) + end + + def is_paid + self.price <= self.paid + end + + def self.find_payment_code_from_csv(csvline) + match = /GAN\d+/.match(csvline) + if match + return Order.find_by_payment_code(match[0]) + else + return false + end + end + + def self.create_payment_code + random = rand(10**15) + return sprintf("GAN%02d%015d", random % 97, random) + end + + def deliver + if self.is_paid + self.tickets.all.map(&:deliver) + if self.paid > self.price + OrderMailer.notify_overpayment(self).deliver_now + end + else + OrderMailer.confirm_order(self).deliver_now + end + end + + private + + def from_cents(value) + (value || 0) / 100.0 + end + + def to_cents(value) + if value.is_a? String then value.sub!(',', '.') end + (value.to_f * 100).to_int + end +end diff --git a/app/models/partner.rb b/app/models/partner.rb index f0b0ccad..d2e8b4e7 100644 --- a/app/models/partner.rb +++ b/app/models/partner.rb @@ -12,7 +12,7 @@ # reset_password_token :string(255) # reset_password_sent_at :datetime # remember_created_at :datetime -# sign_in_count :integer default(0), not null +# sign_in_count :integer default("0"), not null # current_sign_in_at :datetime # last_sign_in_at :datetime # current_sign_in_ip :string(255) diff --git a/app/models/period.rb b/app/models/period.rb deleted file mode 100644 index 41cabe0c..00000000 --- a/app/models/period.rb +++ /dev/null @@ -1,17 +0,0 @@ -# == Schema Information -# -# Table name: periods -# -# id :integer not null, primary key -# starts :datetime -# ends :datetime -# name :string(255) -# created_at :datetime -# updated_at :datetime -# event_id :integer -# - -class Period < ActiveRecord::Base - belongs_to :event - has_many :accesses -end diff --git a/app/models/promo.rb b/app/models/promo.rb index 443f48e5..2246d6ea 100644 --- a/app/models/promo.rb +++ b/app/models/promo.rb @@ -8,7 +8,7 @@ # limit :integer # created_at :datetime # updated_at :datetime -# sold_tickets :integer default(0) +# sold_tickets :integer default("0") # class Promo < ActiveRecord::Base diff --git a/app/models/registration.rb b/app/models/registration.rb deleted file mode 100644 index a6b42d6b..00000000 --- a/app/models/registration.rb +++ /dev/null @@ -1,129 +0,0 @@ -# == Schema Information -# -# Table name: registrations -# -# id :integer not null, primary key -# barcode :string(255) -# name :string(255) -# email :string(255) -# created_at :datetime -# updated_at :datetime -# event_id :integer -# paid :integer -# student_number :string(255) -# price :integer -# checked_in_at :datetime -# comment :text -# barcode_data :string(255) -# payment_code :string(255) -# - -class Registration < ActiveRecord::Base - belongs_to :event - has_many :accesses, dependent: :destroy - has_many :access_levels, through: :accesses - - scope :paid, -> { where("price <= paid") } - - validates :name, presence: true, uniqueness: { scope: :event_id } - # Uniqueness temporarily disabled; see the Partner model for the reason - #validates :email, presence: true, uniqueness: { scope: :event_id } - validates :email, presence: true, email: true - validates :student_number, format: {with: /\A[0-9]*\Z/, message: "has invalid format" }, - uniqueness: { scope: :event }, allow_blank: true - validates :student_number, presence: true, if: "access_levels.first.try(:member_only?)" - validates :paid, presence: true, numericality: { only_integer: true } - validates :price, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } - validates :payment_code, presence: true, uniqueness: true - - has_paper_trail only: [:paid, :payment_code, :checked_in_at] - - before_validation do |record| - if record.payment_code.nil? then - record.payment_code = Registration.create_payment_code - end - end - - after_save do |record| - record.access_levels.each do |access_level| - if access_level.capacity != nil and access_level.registrations.count > access_level.capacity - record.errors.add :access_levels, "type is sold out." - raise ActiveRecord::Rollback - end - end - end - - default_scope { order "name ASC" } - - def paid - from_cents read_attribute(:paid) - end - - def paid=(value) - write_attribute :paid, to_cents(value) - end - - def to_pay - self.price - self.paid - end - - def to_pay=(value) - self.paid = self.price - (to_cents(value) / 100.0) - end - - def price - from_cents read_attribute(:price) - end - - def price=(value) - write_attribute(:price, to_cents(value)) - end - - def is_paid - self.price <= self.paid - end - - def generate_barcode - self.barcode_data = 12.times.map { SecureRandom.random_number(10) }.join - calculated_barcode = Barcodes.create('EAN13', data: self.barcode_data) - self.barcode = calculated_barcode.caption_data - self.save! - end - - def self.find_payment_code_from_csv(csvline) - match = /GAN\d+/.match(csvline) - if match - return Registration.find_by_payment_code(match[0]) - else - return false - end - end - - def self.create_payment_code - random = rand(10**15) - return sprintf("GAN%02d%015d", random % 97, random) - end - - def deliver - if self.barcode.nil? - self.generate_barcode - end - - if self.is_paid - RegistrationMailer.ticket(self).deliver - else - RegistrationMailer.confirm_registration(self).deliver - end - end - - private - - def from_cents(value) - (value || 0) / 100.0 - end - - def to_cents(value) - if value.is_a? String then value.sub!(',', '.') end - (value.to_f * 100).to_int - end -end diff --git a/app/models/ticket.rb b/app/models/ticket.rb new file mode 100644 index 00000000..d3cd4e2e --- /dev/null +++ b/app/models/ticket.rb @@ -0,0 +1,87 @@ +# == Schema Information +# +# Table name: tickets +# +# id :integer not null, primary key +# name :string +# email :string +# checked_in_at :datetime +# order_id :integer +# student_number :string +# comment :text +# barcode :string +# barcode_data :string +# created_at :datetime +# updated_at :datetime +# access_level_id :integer +# status :string default("initial") +# + +class Ticket < ActiveRecord::Base + has_one :event, through: :order + belongs_to :order + belongs_to :access_level + + has_paper_trail only: [:checked_in_at] + + scope :active, -> { where(status: 'active') } + default_scope { order(:id) } + + # A ticket should have an access_level set + validates :access_level, presence: true + + # NAME VALIDATION + # name should always be present + validates :name, uniqueness: { scope: [:order, :access_level] }, presence: true, if: :parent_add_ticket_info? + # a user cannot order a ticket which name already exists in a valid order in the event + validates :name, uniqueness: { scope: :event }, if: Proc.new { |t| t.access_level.member_only && t.order.active? } + + # EMAIL VALIDATION + # email should always be present + validates :email, presence: true, if: :parent_add_ticket_info? + + validates :student_number, + format: {with: /\A[0-9]*\Z/, message: "has invalid format" }, + uniqueness: { scope: :event }, presence: true, + if: Proc.new { |t| t.access_level.member_only && t.order.active? } + + # after_save do |ticket| + # al = ticket.access_level + # if al.capacity != nil and al.tickets.count > al.capacity + # ticket.errors.add :access_level, "type is sold out." + # raise ActiveRecord::Rollback + # end + # end + + def initial? + status == 'initial' + end + + def filled_in? + status == 'filled_in' + end + + def active? + status == 'active' + end + + def parent_add_ticket_info? + self.order.active_or_add_ticket_info? + end + + def deliver + if self.barcode.nil? + self.generate_barcode + end + + TicketMailer.ticket(self).deliver_now + end + + def generate_barcode + self.barcode_data = 12.times.map { SecureRandom.random_number(10) }.join + calculated_barcode = Barcodes.create('EAN13', data: self.barcode_data) + self.barcode = calculated_barcode.caption_data + self.save! + end + +end diff --git a/app/models/user.rb b/app/models/user.rb index ced33f4a..5ea3bf15 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,7 +5,7 @@ # id :integer not null, primary key # username :string(255) default(""), not null # remember_created_at :datetime -# sign_in_count :integer default(0), not null +# sign_in_count :integer default("0"), not null # current_sign_in_at :datetime # last_sign_in_at :datetime # current_sign_in_ip :string(255) @@ -37,8 +37,8 @@ def digest(*args) end # using httparty because it is much easier to read than net/http code - resp = HTTParty.get(Rails.application.config.fk_auth_url, :query => { - :k => digest(username, Rails.application.config.fk_auth_key), + resp = HTTParty.get(Rails.application.secrets.fk_auth_url, :query => { + :k => digest(username, Rails.application.secrets.fk_auth_key), :u => username }) @@ -47,7 +47,7 @@ def digest(*args) hash = JSON[resp.body] clubs_dig = hash['data'].map { |c| c['internalName'] } - dig = digest(Rails.application.config.fk_auth_salt, username, clubs_dig) + dig = digest(Rails.application.secrets.fk_auth_salt, username, clubs_dig) # Process clubs if the controle is correct if hash['controle'] == dig @@ -91,7 +91,7 @@ def display_name # fetch clubs where user is enrolled in def fetch_enrolled_clubs resp = HTTParty.get("http://registratie.fkgent.be/api/v2/members/clubs_for_ugent_nr.json", query: - {key: Rails.application.config.enrollment_key, ugent_nr: self.cas_ugentStudentID}) + {key: Rails.application.secrets.enrolment_key, ugent_nr: self.cas_ugentStudentID}) if resp.code == 200 clubs = JSON[resp.body].map(&:downcase) diff --git a/app/models/zone.rb b/app/models/zone.rb deleted file mode 100644 index 5f5c3540..00000000 --- a/app/models/zone.rb +++ /dev/null @@ -1,18 +0,0 @@ -# == Schema Information -# -# Table name: zones -# -# id :integer not null, primary key -# name :string(255) -# event_id :integer -# created_at :datetime -# updated_at :datetime -# - -class Zone < ActiveRecord::Base - belongs_to :event - has_many :included_zones, dependent: :destroy - has_many :access_levels, through: :included_zones - - validates :name, presence: true -end diff --git a/app/views/access_levels/_access_level.html.erb b/app/views/access_levels/_access_level.html.erb index ed9155af..e022f9b5 100644 --- a/app/views/access_levels/_access_level.html.erb +++ b/app/views/access_levels/_access_level.html.erb @@ -1,7 +1,7 @@
Name: | <%= @registration.name %> |
---|---|
E-mail: | <%= @registration.email %> |
Student number: | <%= @registration.student_number %> |
Registered at: | <%= nice_time @registration.created_at %> |
Barcode: | <%= @registration.barcode %> |
Ticket: | <%= @registration.access_levels[0].name %> |
Comment: | <%= @registration.comment %> |
Name: | <%= @ticket.name %> |
E-mail: | <%= @ticket.email %> |
Student number: | <%= @ticket.student_number %> |
Registered at: | <%= nice_time @ticket.created_at %> |
Barcode: | <%= @ticket.barcode %> |
Ticket: | <%= @ticket.access_level.name %> |
Comment: | <%= @ticket.comment %> |
Beste <%= @order.name %>,
+ +Bedankt voor het bestellen van een ticket voor <%= @order.event.name %> van <%= @order.event.club.name %>. Als u zich niet opgegeven hebt voor dit ticket, dan heeft iemand anders uw e-mailadres gebruikt om dit te registreren. Mocht dit het geval zijn, mag u deze e-mail negeren.
+ +Om uw ticket te ontvangen via e-mail, schrijft u <%= number_with_precision @order.to_pay, precision: 2 %> euro over op het rekeningnummer <%= @order.event.bank_number || "our bank account" %>. Plaats de code "<%= @order.payment_code %>" in de mededeling van de overschrijving (zonder aanhalingstekens). Als u de code vergeet mee te geven of niet correct vermeldt in de beschrijving, dan kunnen wij uw betaling niet verwerken en zal u uw ticket niet ontvangen. U mag maximaal één code ingeven per overschrijving.
+ +Gelieve ten laatste 3 dagen voor het evenement te betalen. Indien dit niet meer lukt, gelieve ons te contacteren via <%= mail_to @order.event.contact_email, @order.event.contact_email %> om een andere betalingswijze af te spreken. Eens we uw betaling verwerkt hebben, zal u uw ticket via e-mail ontvangen.
+ +Mocht er zich eender welk probleem voordoen, kan u ons altijd via e-mail contacteren: <%= mail_to @order.event.contact_email, @order.event.contact_email %>
+ +Met vriendelijke groet,
<%= @order.event.club.name %>
-------------------------------------
Dear <%= @order.name %>,
+ +Thank you for buying a ticket for <%= @order.event.name %> of <%= @order.event.club.name %>. If you did not register for this ticket, someone else used your email address to register. If this is the case, please ignore this email.
+ +To receive your ticket by mail, please transfer <%= number_with_precision @order.to_pay, precision: 2 %> euro to <%= @order.event.bank_number || "our bank account" %>. Place "<%= @order.payment_code %>" in the description of your transfer (without the quotation marks). If you forget this code or you do not copy it correctly, we cannot process your payment and you will not receive your ticket. You are only allowed to enter one code per transfer.
+ +Please pay at least 3 days before the event. If this is no longer possible, please contact us via <%= mail_to @order.event.contact_email, @order.event.contact_email %> to agree upon a different payment method. You will receive your ticket by mail once we processed your payment.
+ +If you have any problems, you can contact us via mail: <%= mail_to @order.event.contact_email, @order.event.contact_email %>
+ +Kind regards,
<%= @order.event.club.name %>
Dear <%= @registration.name %>,
+Dear <%= @order.name %>,
-This mail is being sent to you because you payed to much for the ticket you bought with our event management application. Please check out any faults in below information and contact us at <%= mail_to @registration.event.contact_email, @registration.event.contact_email %> for any changes.
+This mail is being sent to you because you payed to much for the ticket you bought with our event management application. Please check out any faults in below information and contact us at <%= mail_to @order.event.contact_email, @order.event.contact_email %> for any changes.
Event | -<%= @registration.event.name %> | +<%= @order.event.name %> |
Organisation | -<%= @registration.event.club.name %> | +<%= @order.event.club.name %> |
Location | -<%= @registration.event.location %> | +<%= @order.event.location %> |
Price | -<%= @registration.price %> | +<%= @order.price %> |
Paid | -<%= @registration.paid %> | +<%= @order.paid %> |
Kind regards,
<%= @registration.event.club.name %>
Kind regards,
<%= @order.event.club.name %>