From 74cc69d1bd13032311e955890f27041b7945689a Mon Sep 17 00:00:00 2001 From: Du Peng Date: Fri, 7 Feb 2020 17:37:00 +0100 Subject: [PATCH] Ability to configure reservation slot restrict for plans --- CHANGELOG.md | 15 ++-- .../controllers/admin/calendar.js.erb | 68 ++++++++++++++++++- .../javascripts/controllers/machines.js.erb | 2 + app/assets/javascripts/directives/cart.js.erb | 38 +++++++++++ .../admin/calendar/eventModal.html.erb | 35 +++++++++- .../templates/machines/reserve.html.erb | 2 + app/assets/templates/shared/_cart.html.erb | 9 +++ .../api/availabilities_controller.rb | 4 +- app/models/availability.rb | 8 ++- app/models/plan.rb | 1 - app/models/plans_availability.rb | 6 ++ .../api/availabilities/machine.json.jbuilder | 13 ++-- .../api/availabilities/spaces.json.jbuilder | 13 ++-- .../availabilities/trainings.json.jbuilder | 3 + config/locales/app.admin.en.yml | 3 + config/locales/app.admin.es.yml | 3 + config/locales/app.admin.fr.yml | 3 + config/locales/app.admin.pt.yml | 3 + config/locales/app.shared.en.yml | 2 + config/locales/app.shared.es.yml | 2 + config/locales/app.shared.fr.yml | 2 + config/locales/app.shared.pt.yml | 2 + ...00206132857_create_plans_availabilities.rb | 10 +++ db/schema.rb | 12 +++- 24 files changed, 232 insertions(+), 27 deletions(-) create mode 100644 app/models/plans_availability.rb create mode 100644 db/migrate/20200206132857_create_plans_availabilities.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 57ebfbbb7..183d8b00c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Changelog Fab Manager +- Ability to configure reservation slot restrict for plans - Ability to create and delete periodic calendar availabilities (recurrence) - Ability to fully customize the home page - Automated setup assistant @@ -140,7 +141,7 @@ ## v4.0.4 2019 August 14 - Fix a bug: #140 VAT rate is erroneous in invoices. - Note: this bug was introduced in v4.0.3 and requires (if you are on v4.0.3) to regenerate the invoices since August 1st (if + Note: this bug was introduced in v4.0.3 and requires (if you are on v4.0.3) to regenerate the invoices since August 1st (if - [TODO DEPLOY] `rake fablab:maintenance:regenerate_invoices[2019,8]` ## v4.0.3 2019 August 01 @@ -184,7 +185,7 @@ - Refactored user's profile to keep invoicing data after an user was deleted - Refactored user's profile to keep statistical data after an user was deleted - Ability to delete an user (fixes #129 and #120) -- Ask user acceptance before deposing analytics cookies +- Ask user acceptance before deposing analytics cookies - Fix a bug: (spanish) some translations are not loaded correctly - Fix a bug: some users may not appear in the admin's general listing - Fix a bug: Availabilities export report an erroneous number of reservations for machine availabilities (#131) @@ -381,8 +382,8 @@ - Fix a security issue: sprockets < 2.12.5 has a security vulnerability as described in [CVE-2018-3760](https://nvd.nist.gov/vuln/detail/CVE-2018-3760) - Ensure elasticSearch indices are started with green status on new installations - Refactored User.to_json to remove code duplication -- Fixed syntax and typos in README -- [TODO DEPLOY] **IMPORTANT** Please read [elastic_upgrade.md](doc/elastic_upgrade.md) for instructions on upgrading ElasticSearch. +- Fixed syntax and typos in README +- [TODO DEPLOY] **IMPORTANT** Please read [elastic_upgrade.md](doc/elastic_upgrade.md) for instructions on upgrading ElasticSearch. - [TODO DEPLOY] `rake fablab:fix:categories_slugs` - [TODO DEPLOY] -> (only dev) `bundle install` - [TODO DEPLOY] `rake db:seed` @@ -395,7 +396,7 @@ - Set Stripe API version, all fab-managers has to use this version because codebase relies on it - Fix a security issue: OmniAuth < 1.3.2 has a security vulnerability described in [CVE-2017-18076](https://nvd.nist.gov/vuln/detail/CVE-2017-18076) - Fix a security issue: rack-protection < 1.5.5 has a security vulnerability described in [CVE-2018-1000119](https://nvd.nist.gov/vuln/detail/CVE-2018-1000119) -- Fix a security issue: http gem < 0.7.3 has a security vulnerability described in [CVE-2015-1828](https://nvd.nist.gov/vuln/detail/CVE-2015-1828), updates twitter gem as a dependency +- Fix a security issue: http gem < 0.7.3 has a security vulnerability described in [CVE-2015-1828](https://nvd.nist.gov/vuln/detail/CVE-2015-1828), updates twitter gem as a dependency ## v2.6.3 2018 January 2 @@ -451,12 +452,12 @@ ## v2.5.13 2017 September 11 -- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with recursive events which the initial event was deleted +- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with recursive events which the initial event was deleted ## v2.5.12 2017 September 11 - Fix a bug: Long words overflow from homepage's events blocks -- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with non-recursive events +- Fix a bug: ActiveRecord::RecordNotFound when running rake task fix:recursive_events_over_DST with non-recursive events ## v2.5.11 2017 September 7 diff --git a/app/assets/javascripts/controllers/admin/calendar.js.erb b/app/assets/javascripts/controllers/admin/calendar.js.erb index d822d5521..4244e7878 100644 --- a/app/assets/javascripts/controllers/admin/calendar.js.erb +++ b/app/assets/javascripts/controllers/admin/calendar.js.erb @@ -297,7 +297,9 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }], trainingsPromise: ['Training', function (Training) { return Training.query().$promise; }], spacesPromise: ['Space', function (Space) { return Space.query().$promise; }], - tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }] + tagsPromise: ['Tag', function (Tag) { return Tag.query().$promise; }], + plansPromise: ['Plan', function (Plan) { return Plan.query().$promise; }], + groupsPromise: ['Group', function (Group) { return Group.query().$promise; }] } }); // when the modal is closed, we send the slot to the server for saving modalInstance.result.then( @@ -394,8 +396,8 @@ Application.Controllers.controller('AdminCalendarController', ['$scope', '$state /** * Controller used in the slot creation modal window */ -Application.Controllers.controller('CreateEventModalController', ['$scope', '$uibModalInstance', '$sce', 'moment', 'start', 'end', 'machinesPromise', 'Availability', 'trainingsPromise', 'spacesPromise', 'tagsPromise', 'growl', '_t', - function ($scope, $uibModalInstance, $sce, moment, start, end, machinesPromise, Availability, trainingsPromise, spacesPromise, tagsPromise, growl, _t) { +Application.Controllers.controller('CreateEventModalController', ['$scope', '$uibModalInstance', '$sce', 'moment', 'start', 'end', 'machinesPromise', 'Availability', 'trainingsPromise', 'spacesPromise', 'tagsPromise', 'plansPromise', 'groupsPromise', 'growl', '_t', + function ($scope, $uibModalInstance, $sce, moment, start, end, machinesPromise, Availability, trainingsPromise, spacesPromise, tagsPromise, plansPromise, groupsPromise, growl, _t) { // $uibModal parameter $scope.start = start; @@ -414,6 +416,21 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui // all tags list $scope.tags = tagsPromise; + $scope.isOnlySubscriptions = false; + $scope.selectedPlans = []; + $scope.selectedPlansBinding = {}; + // list of plans, classified by group + $scope.plansClassifiedByGroup = []; + for (let group of Array.from(groupsPromise)) { + const groupObj = { id: group.id, name: group.name, plans: [] }; + for (let plan of Array.from(plansPromise)) { + if (plan.group_id === group.id) { groupObj.plans.push(plan); } + } + if (groupObj.plans.length > 0) { + $scope.plansClassifiedByGroup.push(groupObj); + } + } + // machines associated with the created slot $scope.selectedMachines = []; $scope.selectedMachinesBinding = {}; @@ -463,6 +480,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui // localized name(s) of the selected tag(s) $scope.tagsName = ''; + // localized name(s) of the selected plan(s) + $scope.plansName = ''; + /** * Adds or removes the provided machine from the current slot * @param machine {Object} @@ -491,6 +511,34 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui } } + /** + * Adds or removes the provided plan from the current slot + * @param plan {Object} + */ + $scope.toggleSelectPlan = function (plan) { + const index = $scope.selectedPlans.indexOf(plan); + if (index > -1) { + return $scope.selectedMachines.splice(index, 1); + } else { + return $scope.selectedMachines.push(machine); + } + }; + + /** + * Select/unselect all the plans + */ + $scope.toggleAllPlans = function() { + const count = $scope.selectedPlans.length; + $scope.selectedPlans = []; + $scope.selectedPlansBinding = {}; + if (count == 0) { + plansPromise.forEach(function (plan) { + $scope.selectedPlans.push(plan); + $scope.selectedPlansBinding[plan.id] = true; + }) + } + }; + /** * Callback for the modal window validation: save the slot and closes the modal */ @@ -510,6 +558,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui if ($scope.availability.is_recurrent) { $scope.availability.occurrences = $scope.occurrences; } + if ($scope.isOnlySubscriptions && $scope.selectedPlans.length > 0) { + $scope.availability.plan_ids = $scope.selectedPlans.map(function (p) { return p.id; }); + } return Availability.save( { availability: $scope.availability }, function (availability) { $uibModalInstance.close(availability); } @@ -560,6 +611,14 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui $scope.selectedSpace = $scope.spaces[0]; } + // when disable is only subscriptions option, reset all selected plans + $scope.$watch('isOnlySubscriptions', function(value) { + if (!value) { + $scope.selectedPlans = []; + $scope.selectedPlansBinding = {}; + } + }); + // When we configure a machine/space availability, do not let the user change the end time, as the total // time must be dividable by Fablab.slotDuration minutes (base slot duration). For training availabilities, the user // can configure any duration as it does not matters. @@ -685,6 +744,9 @@ Application.Controllers.controller('CreateEventModalController', ['$scope', '$ui return $scope.availability.tag_ids.indexOf(t.id) > -1; }) $scope.tagsName = localizedList(tags); + if ($scope.isOnlySubscriptions && $scope.selectedPlans.length > 0) { + $scope.plansName = localizedList($scope.selectedPlans); + } } const localizedList = function (items) { diff --git a/app/assets/javascripts/controllers/machines.js.erb b/app/assets/javascripts/controllers/machines.js.erb index 733b1dca1..2ae5aebca 100644 --- a/app/assets/javascripts/controllers/machines.js.erb +++ b/app/assets/javascripts/controllers/machines.js.erb @@ -367,6 +367,8 @@ Application.Controllers.controller('ReserveMachineController', ['$scope', '$stat $scope.settings = settingsPromise; // list of plans, classified by group + $scope.groups = groupsPromise; + $scope.plans = plansPromise; $scope.plansClassifiedByGroup = []; for (let group of Array.from(groupsPromise)) { const groupObj = { id: group.id, name: group.name, plans: [] }; diff --git a/app/assets/javascripts/directives/cart.js.erb b/app/assets/javascripts/directives/cart.js.erb index ff2c4a810..cbe5a6980 100644 --- a/app/assets/javascripts/directives/cart.js.erb +++ b/app/assets/javascripts/directives/cart.js.erb @@ -23,6 +23,8 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', plan: '=', planSelectionTime: '=', settings: '=', + plans: '=', + groups: '=', onSlotAddedToCart: '=', onSlotRemovedFromCart: '=', onSlotStartToModify: '=', @@ -134,6 +136,27 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', $scope.payCart = function () { // first, we check that a user was selected if (Object.keys($scope.user).length > 0) { + + // check user was selected a plan if slot is restricted for subcriptions + const slotHasPlan = []; + $scope.events.reserved.forEach(slot => { + if (slot.plan_ids.length > 0) { + if ( + ($scope.selectedPlan && _.include(slot.plan_ids, $scope.selectedPlan.id)) || + ($scope.user.subscribed_plan && _.include(slot.plan_ids, $scope.user.subscribed_plan.id)) + ) { + slotHasPlan.push(true); + } else { + slotHasPlan.push(false); + } + } + }); + const hasPlanForSlot = slotHasPlan.every(a => a); + if (!hasPlanForSlot) { + return growl.error(_t('app.shared.cart.slot_restrict_subcriptions_must_select_plan')); + } + + const reservation = mkReservation($scope.user, $scope.events.reserved, $scope.selectedPlan); return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) { @@ -262,6 +285,21 @@ Application.Directives.directive('cart', [ '$rootScope', '$uibModal', 'dialogs', */ var slotSelectionChanged = function () { if ($scope.slot) { + // build a list of plans if this slot is restricted for subcriptions + if ($scope.slot.plan_ids.length > 0) { + const _plans = _.filter($scope.plans, p => _.include($scope.slot.plan_ids, p.id)); + $scope.slot.plansGrouped = []; + for (let group of Array.from($scope.groups)) { + const groupObj = { id: group.id, name: group.name, plans: [] }; + for (let plan of Array.from(_plans)) { + if (plan.group_id === group.id) { groupObj.plans.push(plan); } + } + if (groupObj.plans.length > 0) { + $scope.slot.plansGrouped.push(groupObj); + } + } + } + if (!$scope.slot.is_reserved && !$scope.events.modifiable && !$scope.slot.is_completed) { // slot is not reserved and we are not currently modifying a slot // -> can be added to cart or removed if already present diff --git a/app/assets/templates/admin/calendar/eventModal.html.erb b/app/assets/templates/admin/calendar/eventModal.html.erb index 3b7f245c1..6773e1e78 100644 --- a/app/assets/templates/admin/calendar/eventModal.html.erb +++ b/app/assets/templates/admin/calendar/eventModal.html.erb @@ -93,12 +93,41 @@ +
+

{{ 'app.admin.calendar.restrict_this_slot_for_subcriptions_optional' }}

+
+
+ + +
+
+

{{ 'app.admin.calendar.select_some_plans' | translate }}

+ +
+ +
+
{{::group.name}}
+ +
+
+
+
+
+
+
{{ 'app.shared.cart.slot_restrict_plans' }}
+
+
{{::group.name}}
+
    +
  • {{::plan.name}}
  • +
+
+
diff --git a/app/controllers/api/availabilities_controller.rb b/app/controllers/api/availabilities_controller.rb index 405f8e443..cec87315d 100644 --- a/app/controllers/api/availabilities_controller.rb +++ b/app/controllers/api/availabilities_controller.rb @@ -148,8 +148,8 @@ class API::AvailabilitiesController < API::ApiController def availability_params params.require(:availability).permit(:start_at, :end_at, :available_type, :machine_ids, :training_ids, :nb_total_places, :is_recurrent, :period, :nb_periods, :end_date, - machine_ids: [], training_ids: [], space_ids: [], tag_ids: [], - machines_attributes: %i[id _destroy]) + machine_ids: [], training_ids: [], space_ids: [], tag_ids: [], plan_ids: [], + machines_attributes: %i[id _destroy], plans_attributes: %i[id _destroy]) end def lock_params diff --git a/app/models/availability.rb b/app/models/availability.rb index 13d48d253..0a01d0da7 100644 --- a/app/models/availability.rb +++ b/app/models/availability.rb @@ -4,7 +4,6 @@ # Eg. a 3D printer will be reservable on thursday from 9 to 11 pm # Availabilities may be subdivided into Slots (of 1h), for some types of reservables (eg. Machine) class Availability < ActiveRecord::Base - # elastic initialisations include Elasticsearch::Model index_name 'fablab' @@ -29,6 +28,10 @@ class Availability < ActiveRecord::Base has_many :tags, through: :availability_tags accepts_nested_attributes_for :tags, allow_destroy: true + has_many :plans_availabilities, dependent: :destroy + has_many :plans, through: :plans_availabilities + accepts_nested_attributes_for :plans, allow_destroy: true + scope :machines, -> { where(available_type: 'machines') } scope :trainings, -> { includes(:trainings).where(available_type: 'training') } scope :spaces, -> { includes(:spaces).where(available_type: 'space') } @@ -86,7 +89,7 @@ class Availability < ActiveRecord::Base def available_space_places return unless available_type == 'space' - ((end_at - start_at)/ApplicationHelper::SLOT_DURATION.minutes).to_i * nb_total_places + ((end_at - start_at) / ApplicationHelper::SLOT_DURATION.minutes).to_i * nb_total_places end def title(filter = {}) @@ -166,5 +169,4 @@ class Availability < ActiveRecord::Base errors.add(:machine_ids, I18n.t('availabilities.must_be_associated_with_at_least_1_machine')) end - end diff --git a/app/models/plan.rb b/app/models/plan.rb index 94d760994..a4d1b0d7a 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -25,7 +25,6 @@ class Plan < ActiveRecord::Base after_create :create_statistic_type after_create :set_name - validates :amount, :group, :base_name, presence: true validates :interval_count, numericality: { only_integer: true, greater_than_or_equal_to: 1 } validates :interval_count, numericality: { less_than: 13 }, if: proc { |plan| plan.interval == 'month' } diff --git a/app/models/plans_availability.rb b/app/models/plans_availability.rb new file mode 100644 index 000000000..baa30c111 --- /dev/null +++ b/app/models/plans_availability.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class PlansAvailability < ActiveRecord::Base + belongs_to :plan + belongs_to :availability +end diff --git a/app/views/api/availabilities/machine.json.jbuilder b/app/views/api/availabilities/machine.json.jbuilder index 255b9153b..7c62843a9 100644 --- a/app/views/api/availabilities/machine.json.jbuilder +++ b/app/views/api/availabilities/machine.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.array!(@slots) do |slot| json.id slot.id if slot.id json.can_modify slot.can_modify @@ -14,13 +16,16 @@ json.array!(@slots) do |slot| json.name slot.machine.name end # the user who booked the slot ... - json.user do - json.id slot.reservation.user.id - json.name slot.reservation.user.profile.full_name - end if @current_user_role == 'admin' and slot.reservation # ... if the slot was reserved + if (@current_user_role == 'admin') && slot.reservation + json.user do + json.id slot.reservation.user.id + json.name slot.reservation.user.profile.full_name + end + end # ... if the slot was reserved json.tag_ids slot.availability.tag_ids json.tags slot.availability.tags do |t| json.id t.id json.name t.name end + json.plan_ids slot.availability.plan_ids end diff --git a/app/views/api/availabilities/spaces.json.jbuilder b/app/views/api/availabilities/spaces.json.jbuilder index f8a0b417c..0528284fb 100644 --- a/app/views/api/availabilities/spaces.json.jbuilder +++ b/app/views/api/availabilities/spaces.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.array!(@slots) do |slot| json.id slot.id if slot.id json.can_modify slot.can_modify @@ -15,13 +17,16 @@ json.array!(@slots) do |slot| json.name slot.space.name end # the user who booked the slot ... - json.user do - json.id slot.reservation.user.id - json.name slot.reservation.user.profile.full_name - end if @current_user_role == 'admin' and slot.reservation # ... if the slot was reserved + if (@current_user_role == 'admin') && slot.reservation + json.user do + json.id slot.reservation.user.id + json.name slot.reservation.user.profile.full_name + end + end # ... if the slot was reserved json.tag_ids slot.availability.tag_ids json.tags slot.availability.tags do |t| json.id t.id json.name t.name end + json.plan_ids slot.availability.plan_ids end diff --git a/app/views/api/availabilities/trainings.json.jbuilder b/app/views/api/availabilities/trainings.json.jbuilder index cf76193cd..36782c8fb 100644 --- a/app/views/api/availabilities/trainings.json.jbuilder +++ b/app/views/api/availabilities/trainings.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.array!(@availabilities) do |a| json.id a.slot_id if a.slot_id if a.is_reserved @@ -31,4 +33,5 @@ json.array!(@availabilities) do |a| json.id t.id json.name t.name end + json.plan_ids slot.availability.plan_ids end diff --git a/config/locales/app.admin.en.yml b/config/locales/app.admin.en.yml index a29b730cc..0f6766af0 100644 --- a/config/locales/app.admin.en.yml +++ b/config/locales/app.admin.en.yml @@ -46,6 +46,9 @@ en: adjust_the_opening_hours: "Adjust the opening hours" to_time: "to" # context: time. eg. 'from 18:00 to 21:00' restrict_this_slot_with_labels_optional: "Restrict this slot with labels (optional)" + restrict_this_slot_for_subcriptions_optional: "Restrict this slot for subscription users (optional)" + select_some_plans: "Select some plans" + plans: "Plan(s):" recurrence: "Recurrence" enabled: "Enabled" period: "Period" diff --git a/config/locales/app.admin.es.yml b/config/locales/app.admin.es.yml index 016570414..263a58454 100644 --- a/config/locales/app.admin.es.yml +++ b/config/locales/app.admin.es.yml @@ -44,6 +44,9 @@ es: adjust_the_opening_hours: "Ajustar el horario de apertura" to_time: a restrict_this_slot_with_labels_optional: "Restringir este horario con etiquetas (opcional)" + restrict_this_slot_for_subcriptions_optional: "Restrict this slot for subscription users (optional)" + select_some_plans: "Select some plans" + plans: "Plan(s):" recurrence: "Recurrencia" enabled: "Activa" period: "Período" diff --git a/config/locales/app.admin.fr.yml b/config/locales/app.admin.fr.yml index 94c46c09b..b4024cdbf 100644 --- a/config/locales/app.admin.fr.yml +++ b/config/locales/app.admin.fr.yml @@ -46,6 +46,9 @@ fr: adjust_the_opening_hours: "Ajuster l'horaire" to_time: "à" # context: time. eg. 'from 18:00 to 21:00' restrict_this_slot_with_labels_optional: "Restreindre ce créneau avec des étiquettes (optionnel)" + restrict_this_slot_for_subcriptions_optional: "Restreindre ce créneau pour les abonnements (optionnel)" + select_some_plans: "Sélectionnez des formules d'abonnement" + plans: "Abonnement(s):" recurrence: "Récurrence" enabled: "Activée" period: "Période" diff --git a/config/locales/app.admin.pt.yml b/config/locales/app.admin.pt.yml index 2ba804e25..cdd97fe9e 100755 --- a/config/locales/app.admin.pt.yml +++ b/config/locales/app.admin.pt.yml @@ -46,6 +46,9 @@ pt: adjust_the_opening_hours: "Ajustar o horário de funcionamento" to_time: "ás" # context: time. eg. 'from 18:00 to 21:00' restrict_this_slot_with_labels_optional: "Restrinja este slot com etiquetas (opcional)" + restrict_this_slot_for_subcriptions_optional: "Restrict this slot for subscription users (optional)" + select_some_plans: "Select some plans" + plans: "Plan(s):" recurrence: "Recurrence" enabled: "Enabled" period: "Period" diff --git a/config/locales/app.shared.en.yml b/config/locales/app.shared.en.yml index dc22183b4..38e729b3b 100644 --- a/config/locales/app.shared.en.yml +++ b/config/locales/app.shared.en.yml @@ -439,3 +439,5 @@ en: a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." none: "None" online_payment_disabled: "Online payment is not available. Please contact the Fablab reception directly." + slot_restrict_plans: "This slot is restricted for the plans below:" + slot_restrict_subcriptions_must_select_plan: "The slot is restricted for subscriptions, please select a plan first." diff --git a/config/locales/app.shared.es.yml b/config/locales/app.shared.es.yml index 3e79b184c..76428ab9d 100644 --- a/config/locales/app.shared.es.yml +++ b/config/locales/app.shared.es.yml @@ -416,3 +416,5 @@ es: a_problem_occurred_during_the_payment_process_please_try_again_later: "A problem occurred during the payment process. Please try again later." none: "Ninguno" online_payment_disabled: "El pago en línea no está disponible. Póngase en contacto directamente con la recepción de Fablab." + slot_restrict_plans: "This slot is restricted for the plans below:" + slot_restrict_subcriptions_must_select_plan: "The slot is restricted for subscriptions, please select a plan first." diff --git a/config/locales/app.shared.fr.yml b/config/locales/app.shared.fr.yml index b0fe0c49f..77fb1dc5f 100644 --- a/config/locales/app.shared.fr.yml +++ b/config/locales/app.shared.fr.yml @@ -439,3 +439,5 @@ fr: a_problem_occurred_during_the_payment_process_please_try_again_later: "Il y a eu un problème lors de la procédure de paiement. Veuillez réessayer plus tard." none: "Aucune" online_payment_disabled: "Le payment par carte bancaire n'est pas disponible. Merci de contacter directement l'accueil du Fablab." + slot_restrict_plans: "Ce créneau est restreint pour les formules d'abonnement ci-desous:" + slot_restrict_subcriptions_must_select_plan: "Le créneau est restreint pour les abonnements, Veuillez tout d'abord sélectionner un formule d'abonnement" diff --git a/config/locales/app.shared.pt.yml b/config/locales/app.shared.pt.yml index f3e770b8e..197ba6c55 100755 --- a/config/locales/app.shared.pt.yml +++ b/config/locales/app.shared.pt.yml @@ -439,3 +439,5 @@ pt: a_problem_occurred_during_the_payment_process_please_try_again_later: "Um problema ocorreu durante o processo de pagamento. Por favor tente novamente mais tarde." none: "Vazio" online_payment_disabled: "O pagamento online não está disponível. Entre em contato diretamente com a recepção do Fablab." + slot_restrict_plans: "This slot is restricted for the plans below:" + slot_restrict_subcriptions_must_select_plan: "The slot is restricted for subscriptions, please select a plan first." diff --git a/db/migrate/20200206132857_create_plans_availabilities.rb b/db/migrate/20200206132857_create_plans_availabilities.rb new file mode 100644 index 000000000..740d5d98e --- /dev/null +++ b/db/migrate/20200206132857_create_plans_availabilities.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class CreatePlansAvailabilities < ActiveRecord::Migration + def change + create_table :plans_availabilities do |t| + t.belongs_to :plan, index: true + t.belongs_to :availability, index: true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 286c27881..ee59f3f76 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,12 +11,12 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20200127111404) do +ActiveRecord::Schema.define(version: 20200206132857) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" - enable_extension "pg_trgm" enable_extension "unaccent" + enable_extension "pg_trgm" create_table "abuses", force: :cascade do |t| t.integer "signaled_id" @@ -465,6 +465,14 @@ ActiveRecord::Schema.define(version: 20200127111404) do add_index "plans", ["group_id"], name: "index_plans_on_group_id", using: :btree + create_table "plans_availabilities", force: :cascade do |t| + t.integer "plan_id" + t.integer "availability_id" + end + + add_index "plans_availabilities", ["availability_id"], name: "index_plans_availabilities_on_availability_id", using: :btree + add_index "plans_availabilities", ["plan_id"], name: "index_plans_availabilities_on_plan_id", using: :btree + create_table "price_categories", force: :cascade do |t| t.string "name" t.text "conditions"