diff --git a/app/assets/javascripts/admin/taxon_concept.js.coffee b/app/assets/javascripts/admin/taxon_concept.js.coffee index 2f351af95a..ad8b285f38 100644 --- a/app/assets/javascripts/admin/taxon_concept.js.coffee +++ b/app/assets/javascripts/admin/taxon_concept.js.coffee @@ -5,7 +5,10 @@ $(document).ready -> .focus(-> $(@).animate(height: "15em", 500)) .blur(-> $(@).animate(height: "4em", 500)) - $('.select2').select2() + $('.select2').select2({ + placeholder: "Choose an option", + allowClear: true + }) $(".datepicker").datepicker( format: "dd/mm/yyyy", diff --git a/app/assets/javascripts/species/controllers/downloads_for_eu_decisions_controller.js.coffee b/app/assets/javascripts/species/controllers/downloads_for_eu_decisions_controller.js.coffee index 08da453b31..df4c3a9ef5 100644 --- a/app/assets/javascripts/species/controllers/downloads_for_eu_decisions_controller.js.coffee +++ b/app/assets/javascripts/species/controllers/downloads_for_eu_decisions_controller.js.coffee @@ -15,14 +15,22 @@ Species.DownloadsForEuDecisionsController = Ember.Controller.extend selectedTaxonConcepts: [] timeScope: 'current' timeScopeIsCurrent: ( -> - @get('timeScope') == 'current' + current = @get('timeScope') == 'current' + if current + @set('selectedYears', []) + current ).property('timeScope') years: [1975..new Date().getFullYear()] selectedYears: [] positiveOpinions: true negativeOpinions: true noOpinions: true + srgReferral: true suspensions: true + euDecisionFilter: 'Default' + euDecisionFilterIsDefault: ( -> + @get('euDecisionFilter') == 'Default' + ).property('euDecisionFilter') autoCompleteTaxonConcepts: ( -> if @get('taxonConceptQuery') && @get('taxonConceptQuery').length > 0 @@ -37,7 +45,7 @@ Species.DownloadsForEuDecisionsController = Ember.Controller.extend } ).filter((e) -> e.taxonConcepts.length > 0 - ) + ) else @get('higherTaxaController.contentByRank') ).property('higherTaxaController.contentByRank.@each', 'taxonConceptQuery') @@ -71,27 +79,56 @@ Species.DownloadsForEuDecisionsController = Ember.Controller.extend ).property('selectedTaxonConcepts.@each') toParams: ( -> - { - data_type: 'EuDecisions' - filters: - designation: @get('designation') - geo_entities_ids: @get('selectedGeoEntitiesIds') - taxon_concepts_ids: @get('selectedTaxonConceptsIds') - set: @get('timeScope') - years: @get('selectedYears') - decision_types: - { - positiveOpinions: @get('positiveOpinions') + # IF EU DECISION FILTER IS "IN CONSULTATION" - DON'T APPLY ALL FILTERS + if @get('euDecisionFilter').toUpperCase() == 'IN CONSULTATION' + { + data_type: 'EuDecisions' + filters: { + designation: @get('designation') + csv_separator: @get('controllers.downloads.csvSeparator') + eu_decision_filter: @get('euDecisionFilter') + } + } + else + { + data_type: 'EuDecisions' + filters: { + #################################################### + ########## DEFAULT EU DECISION FILTERS ############# + #################################################### + designation: @get('designation') + csv_separator: @get('controllers.downloads.csvSeparator') + eu_decision_filter: @get('euDecisionFilter') + #################################################### + geo_entities_ids: @get('selectedGeoEntitiesIds') + set: @get('timeScope') + taxon_concepts_ids: @get('selectedTaxonConceptsIds') + years: @get('selectedYears') + decision_types: { negativeOpinions: @get('negativeOpinions') noOpinions: @get('noOpinions') + positiveOpinions: @get('positiveOpinions') + srgReferral: @get('srgReferral') suspensions: @get('suspensions') } - csv_separator: @get('controllers.downloads.csvSeparator') - } + #################################################### + #################################################### + #################################################### + } + } + ).property( - 'selectedGeoEntitiesIds.@each', 'selectedTaxonConceptsIds.@each', - 'timeScope', 'selectedYears.@each', 'positiveOpinions', 'negativeOpinions', - 'noOpinions', 'suspensions', 'controllers.downloads.csvSeparator' + 'controllers.downloads.csvSeparator', + 'euDecisionFilter', + 'negativeOpinions', + 'noOpinions', + 'positiveOpinions', + 'selectedGeoEntitiesIds.@each', + 'selectedTaxonConceptsIds.@each', + 'selectedYears.@each', + 'srgReferral', + 'suspensions', + 'timeScope' ) downloadUrl: ( -> diff --git a/app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee b/app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee index 8b29cc05da..1264667c48 100644 --- a/app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee +++ b/app/assets/javascripts/species/controllers/taxon_concept_controller.js.coffee @@ -2,6 +2,19 @@ Species.TaxonConceptController = Ember.ObjectController.extend Species.SearchCon Species.SignedInStatus, needs: ['search', 'taxonConceptDocuments'] searchContext: 'species' + legalHeadings: [ + { id: 'cites_listings', name: 'CITES Listing', class: 'first' }, + { id: 'cites_quotas', name: 'CITES Quotas' }, + { id: 'cites_suspensions', name: 'CITES Suspensions' }, + { id: 'eu_listings', name: 'EU Listing' }, + { id: 'eu_decisions', name: 'EU Decisions', class: 'last' } + ] + + actions: { + scrollIntoView: (id) -> + event.preventDefault() + document.getElementById(id).scrollIntoView({ behavior: 'smooth' }) + } isCms: ( -> if @get('taxonomy') != undefined diff --git a/app/assets/javascripts/species/controllers/taxon_concept_legal_controller.js.coffee b/app/assets/javascripts/species/controllers/taxon_concept_legal_controller.js.coffee index 4c04f80e7e..c38255cc99 100644 --- a/app/assets/javascripts/species/controllers/taxon_concept_legal_controller.js.coffee +++ b/app/assets/javascripts/species/controllers/taxon_concept_legal_controller.js.coffee @@ -7,6 +7,7 @@ Species.TaxonConceptLegalController = Ember.ArrayController.extend citesQuotasExpanded: false euDecisionsExpanded: false + actions: expandList: (id, flag) -> this.set(flag, true) diff --git a/app/assets/javascripts/species/models/taxon_concept.js.coffee b/app/assets/javascripts/species/models/taxon_concept.js.coffee index aa56b6efd2..4459fa23e6 100644 --- a/app/assets/javascripts/species/models/taxon_concept.js.coffee +++ b/app/assets/javascripts/species/models/taxon_concept.js.coffee @@ -24,6 +24,7 @@ Species.TaxonConcept = DS.Model.extend cmsInstruments: DS.attr("array") euListings: DS.attr("array") euDecisions: DS.attr("array") + srgHistory: DS.attr("array") distributionReferences: DS.attr("array") taxonomy: DS.attr("string") nomenclatureNoteEn: DS.attr("string") diff --git a/app/assets/javascripts/species/templates/downloads_for_eu.handlebars b/app/assets/javascripts/species/templates/downloads_for_eu.handlebars index ebf29d5856..3800fb3e30 100644 --- a/app/assets/javascripts/species/templates/downloads_for_eu.handlebars +++ b/app/assets/javascripts/species/templates/downloads_for_eu.handlebars @@ -77,82 +77,110 @@ isVisibleBinding="controller.legislationIsEuDecisions" controllerBinding="controllers.downloadsForEuDecisions" }} -
- DOCUMENT TYPE -
-
-
+ + + +
+
+
+
-
+
+
+
-
-
+
+ {{#if euDecisionFilterIsDefault }} +
+
+ +
+
-
+
+ +
+
+
+ +
-
-
-
-
- -
-
- {{#if timeScopeIsCurrent}} - Only current data has
been selected. - {{else}} - -
-
- -
-
- + {{/if}}
+ + +
{{view Species.StartDownloadButton controllerBinding="controller"}}
diff --git a/app/assets/javascripts/species/templates/taxon_concept.handlebars b/app/assets/javascripts/species/templates/taxon_concept.handlebars index 1c71ec5271..447bf4dd1e 100644 --- a/app/assets/javascripts/species/templates/taxon_concept.handlebars +++ b/app/assets/javascripts/species/templates/taxon_concept.handlebars @@ -38,11 +38,13 @@
  • {{#linkTo 'taxonConcept.legal'}}LEGAL{{/linkTo}}
  • diff --git a/app/assets/javascripts/species/templates/taxon_concept/_eu_decisions.handlebars b/app/assets/javascripts/species/templates/taxon_concept/_eu_decisions.handlebars index 78b856cd29..e42f8b6994 100644 --- a/app/assets/javascripts/species/templates/taxon_concept/_eu_decisions.handlebars +++ b/app/assets/javascripts/species/templates/taxon_concept/_eu_decisions.handlebars @@ -5,11 +5,12 @@ - - - - - + + + + + + @@ -35,6 +36,22 @@ {{decision.eu_decision_type.name}} {{/if}} +
    DATECOUNTRYEU DECISIONSNOTESDOCUMENTDATECOUNTRYEU DECISIONSSRG HISTORYNOTESDOCUMENT
    + {{#if decision.srg_history }} + {{#if decision.srg_history.description}} + + {{else}} + {{decision.srg_history.name}} + {{/if}} + {{/if}} + {{#if decision.subspecies_info}} {{{decision.subspecies_info}}}
    @@ -66,11 +83,12 @@ - - - - - + + + + + + @@ -92,6 +110,22 @@ {{decision.eu_decision_type.name}} {{/if}} + + @@ -21,9 +22,18 @@ + diff --git a/app/views/admin/eu_opinions/_form.html.erb b/app/views/admin/eu_opinions/_form.html.erb index 303b40aa44..ef5cc0e528 100644 --- a/app/views/admin/eu_opinions/_form.html.erb +++ b/app/views/admin/eu_opinions/_form.html.erb @@ -32,7 +32,7 @@ :name_en, @eu_opinion.geo_entity_id ), - { :include_blank => true }, + { }, {:class => 'eu_opinion select2', :style => 'width: 220px' } %> @@ -58,6 +58,18 @@ +
    + <%= f.label :srg_history_id, "SRG History", :class => 'control-label' %> +
    + <%= f.select :srg_history_id, + options_from_collection_for_select(@srg_histories, + :id, :name, @eu_opinion.srg_history_id), + { :include_blank => true }, + {:class => 'eu_opinion select2', :style => 'width: 220px' } + %> +
    +
    +
    diff --git a/app/views/admin/eu_opinions/_list.html.erb b/app/views/admin/eu_opinions/_list.html.erb index cfba72da08..a4c4fe24d8 100644 --- a/app/views/admin/eu_opinions/_list.html.erb +++ b/app/views/admin/eu_opinions/_list.html.erb @@ -3,6 +3,7 @@
    + @@ -17,9 +18,18 @@ + @@ -41,4 +51,3 @@ <% end -%> - diff --git a/app/views/admin/srg_histories/_form.html.erb b/app/views/admin/srg_histories/_form.html.erb new file mode 100644 index 0000000000..a10fec0b60 --- /dev/null +++ b/app/views/admin/srg_histories/_form.html.erb @@ -0,0 +1,7 @@ +<%= form_for :srg_history, :url => collection_url, :remote => true do |f| %> + + <%= error_messages_for(@srg_history) %> + + <%= f.text_field :name %>
    + <%= f.text_field :tooltip %>
    +<% end %> diff --git a/app/views/admin/srg_histories/_list.html.erb b/app/views/admin/srg_histories/_list.html.erb new file mode 100644 index 0000000000..628d38a88f --- /dev/null +++ b/app/views/admin/srg_histories/_list.html.erb @@ -0,0 +1,30 @@ + + + + + + + + <% collection.each do |srg_history| -%> + + + + + + <% end -%> + + diff --git a/app/views/shared/_topbar.html.erb b/app/views/shared/_topbar.html.erb index f0f4d3e7ca..19f467f3d7 100644 --- a/app/views/shared/_topbar.html.erb +++ b/app/views/shared/_topbar.html.erb @@ -56,6 +56,9 @@
  • <%= link_to 'EU decision types', admin_eu_decision_types_path %>
  • +
  • + <%= link_to 'Srg Histories', admin_srg_histories_path %> +
  • <%= link_to 'Languages', admin_languages_path %>
  • diff --git a/config/routes.rb b/config/routes.rb index 4b2275c45d..50a5fd9826 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -69,6 +69,7 @@ resources :ranks, :only => [:index, :create, :update, :destroy] resources :tags, :only => [:index, :create, :update, :destroy] resources :eu_decision_types, :only => [:index, :create, :update, :destroy] + resources :srg_histories, only: [:index, :create, :update, :destroy] resources :events do resource :document_batch, :only => [:new, :create] resources :documents, :only => [:index, :edit, :update, :destroy] do diff --git a/db/migrate/20200513105319_create_srg_histories.rb b/db/migrate/20200513105319_create_srg_histories.rb new file mode 100644 index 0000000000..31375c36eb --- /dev/null +++ b/db/migrate/20200513105319_create_srg_histories.rb @@ -0,0 +1,25 @@ +class CreateSrgHistories < ActiveRecord::Migration + def up + create_table :srg_histories do |t| + t.string :name + t.string :tooltip + + t.timestamps + end + + add_column :eu_decisions, :srg_history_id, :integer + add_foreign_key :eu_decisions, :srg_histories, name: 'eu_decisions_srg_history_id_fk' + + execute(<<-SQL + INSERT INTO srg_histories(name, tooltip, created_at, updated_at) + VALUES ('In consultation', NULL, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP), ('Discussed at SRG', 'no decision taken', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) + SQL + ) + end + + def down + remove_foreign_key :eu_decisions, name: 'eu_decisions_srg_history_id_fk' + remove_column :eu_decisions, :srg_history_id + drop_table :srg_histories + end +end diff --git a/db/migrate/20200514150717_add_srg_history_to_eu_decisions_view.rb b/db/migrate/20200514150717_add_srg_history_to_eu_decisions_view.rb new file mode 100644 index 0000000000..70b4701dec --- /dev/null +++ b/db/migrate/20200514150717_add_srg_history_to_eu_decisions_view.rb @@ -0,0 +1,27 @@ +class AddSrgHistoryToEuDecisionsView < ActiveRecord::Migration + def up + execute <<-SQL + CREATE TYPE api_srg_history AS ( + name TEXT, + description TEXT + ); + SQL + execute "DROP VIEW IF EXISTS api_eu_decisions_view" + execute "CREATE VIEW api_eu_decisions_view AS #{view_sql('20200514150717', 'api_eu_decisions_view')}" + + execute "DROP VIEW IF EXISTS eu_decisions_view" + execute "CREATE VIEW eu_decisions_view AS #{view_sql('20200514150717', 'eu_decisions_view')}" + end + + def down + execute "DROP VIEW IF EXISTS api_eu_decisions_view" + execute "CREATE VIEW api_eu_decisions_view AS #{view_sql('20150126161813', 'api_eu_decisions_view')}" + + execute "DROP VIEW IF EXISTS eu_decisions_view" + execute "CREATE VIEW eu_decisions_view AS #{view_sql('20150210140508', 'eu_decisions_view')}" + + execute <<-SQL + DROP TYPE api_srg_history + SQL + end +end diff --git a/db/views/api_eu_decisions_view/20200514150717.sql b/db/views/api_eu_decisions_view/20200514150717.sql new file mode 100644 index 0000000000..9f62d31275 --- /dev/null +++ b/db/views/api_eu_decisions_view/20200514150717.sql @@ -0,0 +1,136 @@ +SELECT +eu_decisions.id, +eu_decisions.type, +eu_decisions.taxon_concept_id, +ROW_TO_JSON( + ROW( + taxon_concept_id, + taxon_concepts.full_name, + taxon_concepts.author_year, + taxon_concepts.data->'rank_name' + )::api_taxon_concept +) AS taxon_concept, +eu_decisions.notes, +CASE + WHEN eu_decisions.type = 'EuOpinion' + THEN eu_decisions.start_date::DATE + WHEN eu_decisions.type = 'EuSuspension' + THEN start_event.effective_at::DATE +END AS start_date, +CASE + WHEN eu_decisions.type = 'EuOpinion' + THEN eu_decisions.is_current + WHEN eu_decisions.type = 'EuSuspension' + THEN + CASE + WHEN start_event.effective_at <= current_date AND start_event.is_current = true + AND (eu_decisions.end_event_id IS NULL OR end_event.effective_at > current_date) + THEN TRUE + ELSE + FALSE + END +END AS is_current, +eu_decisions.geo_entity_id, +ROW_TO_JSON( + ROW( + geo_entities.iso_code2, + geo_entities.name_en, + geo_entity_types.name + )::api_geo_entity +) AS geo_entity_en, +ROW_TO_JSON( + ROW( + geo_entities.iso_code2, + geo_entities.name_es, + geo_entity_types.name + )::api_geo_entity +) AS geo_entity_es, +ROW_TO_JSON( + ROW( + geo_entities.iso_code2, + geo_entities.name_fr, + geo_entity_types.name + )::api_geo_entity +) AS geo_entity_fr, +eu_decisions.start_event_id, +ROW_TO_JSON( + ROW( + start_event.name || CASE WHEN start_event.type = 'EcSrg' THEN ' Soc' ELSE '' END, + start_event.effective_at::DATE, + start_event.url + )::api_event +) AS start_event, +eu_decisions.end_event_id, +ROW_TO_JSON( + ROW( + end_event.name, + end_event.effective_at::DATE, + end_event.url + )::api_event +) AS end_event, +eu_decisions.term_id, +ROW_TO_JSON( + ROW( + terms.code, + terms.name_en + )::api_trade_code +) AS term_en, +ROW_TO_JSON( + ROW( + terms.code, + terms.name_es + )::api_trade_code +) AS term_es, +ROW_TO_JSON( + ROW( + terms.code, + terms.name_fr + )::api_trade_code +) AS term_fr, +ROW_TO_JSON( + ROW( + sources.code, + sources.name_en + )::api_trade_code +) AS source_en, +ROW_TO_JSON( + ROW( + sources.code, + sources.name_es + )::api_trade_code +) AS source_es, +ROW_TO_JSON( + ROW( + sources.code, + sources.name_fr + )::api_trade_code +) AS source_fr, +eu_decisions.source_id, +eu_decisions.eu_decision_type_id, +ROW_TO_JSON( + ROW( + eu_decision_types.name, + eu_decision_types.tooltip, + eu_decision_types.decision_type + )::api_eu_decision_type +) AS eu_decision_type, +eu_decisions.srg_history_id, +ROW_TO_JSON( + ROW( + srg_histories.name, + srg_histories.tooltip + )::api_srg_history +) AS srg_history, +eu_decisions.nomenclature_note_en, +eu_decisions.nomenclature_note_fr, +eu_decisions.nomenclature_note_es +FROM eu_decisions +JOIN geo_entities ON geo_entities.id = eu_decisions.geo_entity_id +JOIN geo_entity_types ON geo_entities.geo_entity_type_id = geo_entity_types.id +JOIN taxon_concepts ON taxon_concepts.id = eu_decisions.taxon_concept_id +LEFT JOIN events AS start_event ON start_event.id = eu_decisions.start_event_id +LEFT JOIN events AS end_event ON end_event.id = eu_decisions.end_event_id +LEFT JOIN trade_codes terms ON terms.id = eu_decisions.term_id AND terms.type = 'Term' +LEFT JOIN trade_codes sources ON sources.id = eu_decisions.source_id AND sources.type = 'Source' +LEFT JOIN eu_decision_types ON eu_decision_types.id = eu_decisions.eu_decision_type_id +LEFT JOIN srg_histories ON srg_histories.id = eu_decisions.srg_history_id; diff --git a/db/views/eu_decisions_view/20200514150717.sql b/db/views/eu_decisions_view/20200514150717.sql new file mode 100644 index 0000000000..d40df0fefc --- /dev/null +++ b/db/views/eu_decisions_view/20200514150717.sql @@ -0,0 +1,86 @@ +SELECT + taxon_concept_id, + taxon_concepts.taxonomic_position, + (taxon_concepts.data->'kingdom_id')::INT AS kingdom_id, + (taxon_concepts.data->'phylum_id')::INT AS phylum_id, + (taxon_concepts.data->'class_id')::INT AS class_id, + (taxon_concepts.data->'order_id')::INT AS order_id, + (taxon_concepts.data->'family_id')::INT AS family_id, + taxon_concepts.data->'kingdom_name' AS kingdom_name, + taxon_concepts.data->'phylum_name' AS phylum_name, + taxon_concepts.data->'class_name' AS class_name, + taxon_concepts.data->'order_name' AS order_name, + taxon_concepts.data->'family_name' AS family_name, + taxon_concepts.data->'genus_name' AS genus_name, + LOWER(taxon_concepts.data->'species_name') AS species_name, + LOWER(taxon_concepts.data->'subspecies_name') AS subspecies_name, + taxon_concepts.full_name AS full_name, + taxon_concepts.data->'rank_name' AS rank_name, + eu_decisions.start_date, + TO_CHAR(eu_decisions.start_date, 'DD/MM/YYYY') AS start_date_formatted, + t.original_start_date, + TO_CHAR(t.original_start_date, 'DD/MM/YYYY') AS original_start_date_formatted, + geo_entity_id, + geo_entities.name_en AS party, + CASE + WHEN eu_decision_types.name ~* '^i+\)' + THEN '(No opinion) ' || eu_decision_types.name + ELSE eu_decision_types.name + END AS decision_type_for_display, + eu_decision_types.decision_type AS decision_type, + srg_histories.name AS srg_history, + sources.name_en AS source_name, + sources.code || ' - ' || sources.name_en AS source_code_and_name, + terms.name_en AS term_name, + eu_decisions.notes, + start_event.name AS start_event_name, + CASE + WHEN ( + eu_decisions.type = 'EuOpinion' AND eu_decisions.is_current + ) + OR ( + eu_decisions.type = 'EuSuspension' + AND start_event.effective_at < current_date + AND start_event.is_current = true + AND (eu_decisions.end_event_id IS NULL OR end_event.effective_at > current_date) + ) + THEN TRUE + ELSE FALSE + END AS is_valid, + CASE + WHEN ( + eu_decisions.type = 'EuOpinion' AND eu_decisions.is_current + ) + OR ( + eu_decisions.type = 'EuSuspension' + AND start_event.effective_at < current_date + AND start_event.is_current = true + AND (eu_decisions.end_event_id IS NULL OR end_event.effective_at > current_date) + ) + THEN 'Valid' + ELSE 'Not Valid' + END AS is_valid_for_display, + CASE + WHEN eu_decisions.type = 'EuOpinion' + THEN eu_decisions.start_date + WHEN eu_decisions.type = 'EuSuspension' + THEN start_event.effective_at + END AS ordering_date, + CASE + WHEN LENGTH(eu_decisions.notes) > 0 THEN strip_tags(eu_decisions.notes) + ELSE '' + END + || CASE + WHEN LENGTH(eu_decisions.nomenclature_note_en) > 0 THEN E'\n' || strip_tags(eu_decisions.nomenclature_note_en) + ELSE '' + END AS full_note_en +FROM eu_decisions +LEFT JOIN eu_decision_types ON eu_decision_types.id = eu_decisions.eu_decision_type_id -- Eu Decision Type can be empty now +JOIN taxon_concepts ON taxon_concepts.id = eu_decisions.taxon_concept_id +LEFT JOIN srg_histories ON srg_histories.id = eu_decisions.srg_history_id +LEFT JOIN events AS start_event ON start_event.id = eu_decisions.start_event_id +LEFT JOIN events AS end_event ON end_event.id = eu_decisions.end_event_id +LEFT JOIN geo_entities ON geo_entities.id = eu_decisions.geo_entity_id +LEFT JOIN trade_codes sources ON sources.type = 'Source' AND sources.id = eu_decisions.source_id +LEFT JOIN trade_codes terms ON terms.type = 'Term' AND terms.id = eu_decisions.term_id +LEFT JOIN eu_suspensions_applicability_view t ON t.id = eu_decisions.id; diff --git a/lib/tasks/import_eu_decisions.rake b/lib/tasks/import_eu_decisions.rake index 5a318545b8..11d6fd7a98 100644 --- a/lib/tasks/import_eu_decisions.rake +++ b/lib/tasks/import_eu_decisions.rake @@ -73,7 +73,7 @@ namespace :import do AND UPPER(taxon_concepts.legacy_type) = BTRIM(UPPER(q.kingdom)) AND taxon_concepts.rank_id = ranks.id INNER JOIN geo_entities ON UPPER(geo_entities.iso_code2) = BTRIM(UPPER(q.country_iso2)) - INNER JOIN eu_decision_types ON UPPER(eu_decision_types.name) = BTRIM(UPPER(q.opinion)) + INNER JOIN eu_decision_types ON UPPER(eu_decision_types.name) = BTRIM(UPPER(q.opinion)) -- Eu Decision Type can be empty now. Consider LEFT JOIN if importing other files INNER JOIN events ON events.legacy_id = q.event_legacy_id AND events.designation_id = #{designation_id} LEFT JOIN trade_codes AS sources ON UPPER(sources.code) = BTRIM(UPPER(q.source)) diff --git a/lib/tasks/import_eu_opinions.rake b/lib/tasks/import_eu_opinions.rake index 1d805ca1bd..aaf6cd7624 100644 --- a/lib/tasks/import_eu_opinions.rake +++ b/lib/tasks/import_eu_opinions.rake @@ -24,7 +24,7 @@ namespace :import do FROM #{TMP_TABLE} t JOIN taxon_concepts ON taxon_concepts.id = t.taxon_concept_id JOIN events ON events.name = t.start_event_name - JOIN eu_decision_types ON t.opinion_name = eu_decision_types.name + JOIN eu_decision_types ON t.opinion_name = eu_decision_types.name -- Eu Decision Type can be empty now. Consider LEFT JOIN if importing other files JOIN geo_entities ON SQUISH_NULL(t.country_name) = geo_entities.name_en LEFT JOIN trade_codes terms on t.term_code = terms.code LEFT JOIN trade_codes sources on t.source_code = sources.code diff --git a/lib/tasks/set_eu_opinions_to_not_current.rake b/lib/tasks/set_eu_opinions_to_not_current.rake index bbd3c8d52e..172bfaccdf 100644 --- a/lib/tasks/set_eu_opinions_to_not_current.rake +++ b/lib/tasks/set_eu_opinions_to_not_current.rake @@ -16,7 +16,7 @@ task :set_eu_opinions_to_not_current => :environment do sources.id AS source_id FROM #{TMP_TABLE} t JOIN events ON events.name = t.start_regulation_name - JOIN eu_decision_types ON t.opinion_name = eu_decision_types.name + JOIN eu_decision_types ON t.opinion_name = eu_decision_types.name -- Eu Decision Type can be empty now. Consider LEFT JOIN if importing other files JOIN geo_entities ON SQUISH_NULL(t.country_name) = geo_entities.name_en LEFT JOIN trade_codes terms on t.term_code = terms.code LEFT JOIN trade_codes sources on t.source_code = sources.code diff --git a/lib/tasks/transfer_eu_opinions.rake b/lib/tasks/transfer_eu_opinions.rake new file mode 100644 index 0000000000..5ab1424793 --- /dev/null +++ b/lib/tasks/transfer_eu_opinions.rake @@ -0,0 +1,58 @@ +namespace :eu_opinions do + + desc "transfer the current eu_opinions with iii) eu_decision type to the new SRG referral decision type" + task :transfer_to_srg_referral_type => :environment do + old_decision_type_ids = EuDecisionType.where(name: "iii)").pluck(:id) + fail "Old decision type not found" if old_decision_type_ids.empty? + eu_opinions = EuOpinion.where(eu_decision_type_id: old_decision_type_ids, is_current: true) + fail "No eu opinions to transfer" if eu_opinions.count.zero? + new_decision_type_id = EuDecisionType.find_by_name("SRG Referral").try(:id) + fail "New decision type not found" if new_decision_type_id.nil? + + puts "There are #{eu_opinions.count} eu_opinions to be transferred" + + query = query_builder(new_decision_type_id, 'eu_decision_type', old_decision_type_ids) + res = ActiveRecord::Base.connection.execute query + + puts "#{res.cmd_tuples} rows transferred to new decision type" + end + + desc "transfer the current eu_opinions with ii) eu_decision type to the new SRG History 'In consultation'" + task :transfer_to_srg_history => :environment do + old_decision_type_ids = EuDecisionType.where(name: "ii)").pluck(:id) + fail "Old decision type not found" if old_decision_type_ids.empty? + eu_opinions = EuOpinion.where(eu_decision_type_id: old_decision_type_ids, is_current: true) + fail "No eu opinions to transfer" if eu_opinions.count.zero? + srg_history_id = SrgHistory.find_by_name("In consultation").try(:id) + fail "New decision type not found" if srg_history_id.nil? + + puts "There are #{eu_opinions.count} eu_opinions to be transferred" + + query = query_builder(srg_history_id, 'srg_history', old_decision_type_ids) + res = ActiveRecord::Base.connection.execute query + + puts "#{res.cmd_tuples} rows transferred to new decision type" + end + + def query_builder(new_type, model, old_types) + set_query = + if model =~ /history/i + "SET eu_decision_type_id = NULL, srg_history_id = #{new_type}, updated_at = CURRENT_TIMESTAMP" + else + "SET eu_decision_type_id = #{new_type}, updated_at = CURRENT_TIMESTAMP" + end + <<-SQL + WITH current_eu_opinions_with_old_type AS ( + SELECT * + FROM eu_decisions + WHERE type = 'EuOpinion' + AND eu_decision_type_id IN (#{old_types.join(',')}) + AND is_current = true + ) + UPDATE eu_decisions + #{set_query} + FROM current_eu_opinions_with_old_type + WHERE current_eu_opinions_with_old_type.id = eu_decisions.id + SQL + end +end diff --git a/spec/controllers/admin/eu_opinions_controller_spec.rb b/spec/controllers/admin/eu_opinions_controller_spec.rb index cf277f5dbd..75e6162eb3 100644 --- a/spec/controllers/admin/eu_opinions_controller_spec.rb +++ b/spec/controllers/admin/eu_opinions_controller_spec.rb @@ -9,24 +9,24 @@ describe "GET index" do it "renders the index template" do - get :index, :taxon_concept_id => @taxon_concept.id + get :index, taxon_concept_id: @taxon_concept.id response.should render_template("index") end it "renders the taxon_concepts_layout" do - get :index, :taxon_concept_id => @taxon_concept.id + get :index, taxon_concept_id: @taxon_concept.id response.should render_template('layouts/taxon_concepts') end end describe "GET new" do it "renders the new template" do - get :new, :taxon_concept_id => @taxon_concept.id + get :new, taxon_concept_id: @taxon_concept.id response.should render_template('new') end it "assigns @geo_entities (country and territory) with two objects" do - territory = create(:geo_entity, :geo_entity_type_id => territory_geo_entity_type.id) - country = create(:geo_entity) - get :new, :taxon_concept_id => @taxon_concept.id + create(:geo_entity, :geo_entity_type_id => territory_geo_entity_type.id) + create(:geo_entity) + get :new, taxon_concept_id: @taxon_concept.id assigns(:geo_entities).size.should == 2 end end @@ -35,25 +35,27 @@ context "when successful" do before do @eu_decision_type = create(:eu_decision_type) + @srg_history = create(:srg_history) end it "redirects to the EU Opinions index" do post :create, - :eu_opinion => { - :eu_decision_type_id => @eu_decision_type.id, - :start_date => Date.today, - :geo_entity_id => create( - :geo_entity, :geo_entity_type_id => country_geo_entity_type.id + eu_opinion: { + eu_decision_type_id: @eu_decision_type.id, + srg_history_id: @srg_history.id, + start_date: Date.today, + geo_entity_id: create( + :geo_entity, geo_entity_type_id: country_geo_entity_type.id ) }, - :taxon_concept_id => @taxon_concept.id + taxon_concept_id: @taxon_concept.id response.should redirect_to(admin_taxon_concept_eu_opinions_url(@taxon_concept.id)) end end context "when not successful" do it "renders new" do - post :create, :eu_opinion => {}, - :taxon_concept_id => @taxon_concept.id + post :create, eu_opinion: {}, + taxon_concept_id: @taxon_concept.id response.should render_template("new") end end @@ -63,16 +65,16 @@ before(:each) do @eu_opinion = create( :eu_opinion, - :taxon_concept_id => @taxon_concept.id + taxon_concept_id: @taxon_concept.id ) end it "renders the edit template" do - get :edit, :id => @eu_opinion.id, :taxon_concept_id => @taxon_concept.id + get :edit, id: @eu_opinion.id, taxon_concept_id: @taxon_concept.id response.should render_template('edit') end it "assigns @geo_entities" do - territory = create(:geo_entity, :geo_entity_type_id => territory_geo_entity_type.id) - get :edit, :id => @eu_opinion.id, :taxon_concept_id => @taxon_concept.id + territory = create(:geo_entity, geo_entity_type_id: territory_geo_entity_type.id) + get :edit, id: @eu_opinion.id, taxon_concept_id: @taxon_concept.id assigns(:geo_entities).should include(territory) end end @@ -81,33 +83,82 @@ before(:each) do @eu_opinion = create( :eu_opinion, - :taxon_concept_id => @taxon_concept.id + taxon_concept_id: @taxon_concept.id ) @eu_decision_type = create(:eu_decision_type) + @srg_history = create(:srg_history) end context "when successful" do - it "renders taxon_concepts EU Opinions page" do - put :update, - :eu_opinion => { - :eu_decision_type_id => @eu_decision_type.id - }, - :id => @eu_opinion.id, - :taxon_concept_id => @taxon_concept.id - response.should redirect_to( - admin_taxon_concept_eu_opinions_url(@taxon_concept) - ) + context "when eu decision type is present" do + it "renders taxon_concepts EU Opinions page" do + put :update, + eu_opinion: { + eu_decision_type_id: @eu_decision_type.id + }, + id: @eu_opinion.id, + taxon_concept_id: @taxon_concept.id + response.should redirect_to( + admin_taxon_concept_eu_opinions_url(@taxon_concept) + ) + end + end + + context "when eu decision type is not present" do + it "renders taxon_concepts EU Opinions page" do + put :update, + eu_opinion: { + eu_decision_type_id: nil, + srg_history_id: @srg_history.id + }, + id: @eu_opinion.id, + taxon_concept_id: @taxon_concept.id + response.should redirect_to( + admin_taxon_concept_eu_opinions_url(@taxon_concept) + ) + end end end context "when not successful" do + context "when eu decision type is present" do + it "renders new" do + put :update, + eu_opinion: { + eu_decision_type_id: @eu_decision_type.id, + start_date: nil + }, + id: @eu_opinion.id, + taxon_concept_id: @taxon_concept.id + response.should render_template('new') + end + end + + context "when eu decision type is not present" do + it "renders new" do + put :update, + eu_opinion: { + eu_decision_type_id: nil, + srg_history_id: @srg_history.id, + start_date: nil + }, + id: @eu_opinion.id, + taxon_concept_id: @taxon_concept.id + response.should render_template('new') + end + end + end + + context "when both eu_decision_type and srg_history are empty" do it "renders new" do put :update, - :eu_opinion => { - :eu_decision_type_id => nil + eu_opinion: { + eu_decision_type_id: nil, + srg_history_id: nil, + start_date: nil }, - :id => @eu_opinion.id, - :taxon_concept_id => @taxon_concept.id + id: @eu_opinion.id, + taxon_concept_id: @taxon_concept.id response.should render_template('new') end end @@ -117,12 +168,12 @@ before(:each) do @eu_opinion = create( :eu_opinion, - :taxon_concept_id => @taxon_concept.id + taxon_concept_id: @taxon_concept.id ) end it "redirects after delete" do - delete :destroy, :id => @eu_opinion.id, - :taxon_concept_id => @taxon_concept.id + delete :destroy, id: @eu_opinion.id, + taxon_concept_id: @taxon_concept.id response.should redirect_to( admin_taxon_concept_eu_opinions_url(@taxon_concept) ) diff --git a/spec/controllers/admin/srg_histories_controller_spec.rb b/spec/controllers/admin/srg_histories_controller_spec.rb new file mode 100644 index 0000000000..187f9afea4 --- /dev/null +++ b/spec/controllers/admin/srg_histories_controller_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe Admin::SrgHistoriesController do + login_admin + + describe "GET index" do + it "renders the index template" do + get :index + response.should render_template("index") + end + end + + describe "POST create" do + context "when successful" do + before do + @srg_history = create(:srg_history) + end + + it "renders the create js template" do + post :create, srg_history: { name: 'test' }, format: :js + + response.should render_template("create") + end + end + + context "when not successful" do + it "renders new" do + post :create, srg_history: {}, format: :js + + response.should render_template("new") + end + end + end + + describe "PUT update" do + before(:each) do + @srg_history = create(:srg_history) + end + + context "when successful" do + it "renders the create js template" do + put :update, id: @srg_history.id, format: :js + + response.should render_template("create") + end + end + + context "when not successful" do + it "renders new" do + put :update, + srg_history: { name: nil }, + id: @srg_history.id, + format: :js + + response.should render_template('new') + end + end + end + + describe "DELETE destroy" do + before(:each) do + @srg_history = create(:srg_history) + end + + it "redirects after delete" do + delete :destroy, id: @srg_history.id + + response.should redirect_to(admin_srg_histories_url) + end + end +end diff --git a/spec/controllers/admin/taxon_eu_suspensions_controller_spec.rb b/spec/controllers/admin/taxon_eu_suspensions_controller_spec.rb index 97fa305256..f43ded20cf 100644 --- a/spec/controllers/admin/taxon_eu_suspensions_controller_spec.rb +++ b/spec/controllers/admin/taxon_eu_suspensions_controller_spec.rb @@ -81,36 +81,85 @@ before(:each) do @eu_suspension = create( :eu_suspension, - :taxon_concept_id => @taxon_concept.id + taxon_concept_id: @taxon_concept.id ) - @eu_decision_type = create(:eu_decision_type) + @srg_history = create(:srg_history) end context "when successful" do - it "renders taxon_concepts EU suspensions page" do - put :update, - :eu_suspension => { - :eu_decision_type_id => @eu_decision_type.id, - :geo_entity_id => create( - :geo_entity, :geo_entity_type_id => country_geo_entity_type.id - ) - }, - :id => @eu_suspension.id, - :taxon_concept_id => @taxon_concept.id - response.should redirect_to( - admin_taxon_concept_eu_suspensions_url(@taxon_concept) - ) + context "when eu_decision_type is present" do + it "renders taxon_concepts EU suspensions page" do + put :update, + eu_suspension: { + eu_decision_type_id: create(:eu_decision_type), + geo_entity_id: create( + :geo_entity, :geo_entity_type_id => country_geo_entity_type.id + ) + }, + id: @eu_suspension.id, + taxon_concept_id: @taxon_concept.id + response.should redirect_to( + admin_taxon_concept_eu_suspensions_url(@taxon_concept) + ) + end + end + context "when eu_decision_type is not present" do + it "renders taxon_concepts EU suspensions page" do + put :update, + eu_suspension: { + eu_decision_type_id: nil, + srg_history_id: @srg_history.id, + geo_entity_id: create( + :geo_entity, :geo_entity_type_id => country_geo_entity_type.id + ) + }, + id: @eu_suspension.id, + taxon_concept_id: @taxon_concept.id + response.should redirect_to( + admin_taxon_concept_eu_suspensions_url(@taxon_concept) + ) + end end end context "when not successful" do + context "when eu_decision_type is present" do + it "renders new" do + put :update, + eu_suspension: { + eu_decision_type_id: create(:eu_decision_type), + geo_entity_id: nil + }, + id: @eu_suspension.id, + taxon_concept_id: @taxon_concept.id + response.should render_template('new') + end + end + context "when eu_decision_type is not present" do + it "renders new" do + put :update, + eu_suspension: { + eu_decision_type_id: nil, + srg_history_id: @srg_history.id, + geo_entity_id: nil + }, + id: @eu_suspension.id, + taxon_concept_id: @taxon_concept.id + response.should render_template('new') + end + end + end + + context "when both eu_decision_type and srg_history are empty" do it "renders new" do put :update, - :eu_suspension => { - :eu_decision_type_id => nil + eu_suspension: { + eu_decision_type_id: nil, + srg_history_id: nil, + start_date: nil }, - :id => @eu_suspension.id, - :taxon_concept_id => @taxon_concept.id + id: @eu_suspension.id, + taxon_concept_id: @taxon_concept.id response.should render_template('new') end end diff --git a/spec/factories/srg_history.rb b/spec/factories/srg_history.rb new file mode 100644 index 0000000000..2f87d6aae4 --- /dev/null +++ b/spec/factories/srg_history.rb @@ -0,0 +1,6 @@ +FactoryGirl.define do + factory :srg_history do + sequence(:name) { |n| "srg_history#{n}" } + tooltip 'asdfasdf' + end +end diff --git a/spec/models/eu_decision_spec.rb b/spec/models/eu_decision_spec.rb index 2a52adea0e..51341e7501 100644 --- a/spec/models/eu_decision_spec.rb +++ b/spec/models/eu_decision_spec.rb @@ -69,6 +69,38 @@ end end + describe :save do + context "Eu decision type and SRG history can't be blank at the same time" do + let(:eu_decision) { build(:eu_decision, srg_history_id: nil, eu_decision_type_id: nil) } + subject { eu_decision.save } + + specify { subject.should be_false } + + it 'should have an error message' do + subject + expect(eu_decision.errors[:base]).to_not be_empty + end + end + + context 'Eu decision creates correctly if only Eu decision type is populated' do + let(:eu_decision) { build(:eu_decision) } + + specify { subject.should be_true } + end + + context 'Eu decision creates correctly if only SRG history is populated' do + let(:eu_decision) { build(:eu_decision, eu_decision_type: nil, srg_history: create(:srg_history)) } + + specify { subject.should be_true } + end + + context 'Eu decision creates correctly if both Eu decision type and SRG history are populated' do + let(:eu_decision) { build(:eu_decision, srg_history: create(:srg_history)) } + + specify { subject.should be_true } + end + end + describe :destroy do context "downloads cache should be cleared" do before(:each) do
               
    + {{#if decision.srg_history }} + {{#if decision.srg_history.description}} + + {{else}} + {{decision.srg_history.name}} + {{/if}} + {{/if}} + {{#if decision.subspecies_info}} {{{decision.subspecies_info}}}
    diff --git a/app/assets/javascripts/species/views/downloads/downloads_popup.js.coffee b/app/assets/javascripts/species/views/downloads/downloads_popup.js.coffee index 9154e6c625..376cb8f2aa 100644 --- a/app/assets/javascripts/species/views/downloads/downloads_popup.js.coffee +++ b/app/assets/javascripts/species/views/downloads/downloads_popup.js.coffee @@ -1,6 +1,6 @@ Species.DownloadsPopup = Ember.View.extend templateName: 'species/downloads_popup' - classNames: ['dwonload-block'] + classNames: ['download-block'] didInsertElement: () -> $('input[name=csv_separator]').click( (e) -> diff --git a/app/assets/stylesheets/species/all.css b/app/assets/stylesheets/species/all.css index 4a4692a9c8..0caa75a686 100755 --- a/app/assets/stylesheets/species/all.css +++ b/app/assets/stylesheets/species/all.css @@ -516,7 +516,7 @@ body.inner #footer .holder{ .result-block h2:hover { background: #ecf2f6; } .result-block.add h2 { padding: 13px 28px 12px; } -.dwonload-block { +.download-block { width: 441px; margin-left: -180px; position: absolute; @@ -527,7 +527,7 @@ body.inner #footer .holder{ border: 1px solid #8fb7cf; z-index: 1000; } -.dwonload-block .close { +.download-block .close { width: 22px; height: 22px; overflow: hidden; @@ -537,7 +537,7 @@ body.inner #footer .holder{ text-indent: -9999px; background: url(/assets/species/btn-close.png) no-repeat; } -.dwonload-block .title { +.download-block .title { display: block; font-size: 17px; text-align: center; @@ -551,11 +551,11 @@ body.inner #footer .holder{ -webkit-border-radius: 12px 12px 0 0; border-radius: 12px 12px 0 0; } -.dwonload-block .tabset { +.download-block .tabset { text-align: center; padding: 21px 0 19px; } -.dwonload-block .tabset li { +.download-block .tabset li { min-width: 70px; margin: 0 -4px 0 0; text-align: center; @@ -567,7 +567,7 @@ body.inner #footer .holder{ vertical-align: top; cursor: pointer; } -.dwonload-block .tabset li a { +.download-block .tabset li a { display: block; text-decoration: none; background: #376382; @@ -576,22 +576,22 @@ body.inner #footer .holder{ border: 1px solid #2c516c; border-left: none; } -.dwonload-block .tabset li a:hover, .dwonload-block .tabset li.active a, .dwonload-block .tabset li a.active { background: #253848; } -.dwonload-block .tabset li:first-child a { +.download-block .tabset li a:hover, .download-block .tabset li.active a, .download-block .tabset li a.active { background: #253848; } +.download-block .tabset li:first-child a { -webkit-border-radius: 20px 0 0 20px; border-radius: 20px 0 0 20px; } -.dwonload-block .tabset li.last-child a { +.download-block .tabset li.last-child a { -webkit-border-radius: 0 20px 20px 0; border-radius: 0 20px 20px 0; } -.dwonload-block .tab-content { border-top: 1px solid #d6d7d7; } -.dwonload-block .csv_options_holder { +.download-block .tab-content { border-top: 1px solid #d6d7d7; } +.download-block .csv_options_holder { margin: 10px; text-align: center; line-height: 180%; } -.dwonload-block .csv_options_holder a { +.download-block .csv_options_holder a { cursor: pointer; } #csv_options{ display: none; } @@ -1044,6 +1044,14 @@ body.inner #footer .holder{ #main .block th.col11 { width: 212px; } #main .block th.col12 { width: 670px; } #main .block th.col13 { width: 145px; } +#main .block th.col14 { + width: 96px; + padding-right: 20px; + } +#main .block th.col15 { + width: 240px; + padding-right: 20px; + } #main #cms_listings.block th.col3{ width: 314px; } #main #cms_listings.block th.col4{ width: 458px; } @@ -1480,3 +1488,490 @@ div.alert .close { text-decoration: none; opacity: 0.2; } + + +.m-0 { + margin: 0 !important; +} + +.mt-0, +.my-0 { + margin-top: 0 !important; +} + +.mr-0, +.mx-0 { + margin-right: 0 !important; +} + +.mb-0, +.my-0 { + margin-bottom: 0 !important; +} + +.ml-0, +.mx-0 { + margin-left: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.mt-1, +.my-1 { + margin-top: 0.25rem !important; +} + +.mr-1, +.mx-1 { + margin-right: 0.25rem !important; +} + +.mb-1, +.my-1 { + margin-bottom: 0.25rem !important; +} + +.ml-1, +.mx-1 { + margin-left: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.mt-2, +.my-2 { + margin-top: 0.5rem !important; +} + +.mr-2, +.mx-2 { + margin-right: 0.5rem !important; +} + +.mb-2, +.my-2 { + margin-bottom: 0.5rem !important; +} + +.ml-2, +.mx-2 { + margin-left: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.mt-3, +.my-3 { + margin-top: 1rem !important; +} + +.mr-3, +.mx-3 { + margin-right: 1rem !important; +} + +.mb-3, +.my-3 { + margin-bottom: 1rem !important; +} + +.ml-3, +.mx-3 { + margin-left: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.mt-4, +.my-4 { + margin-top: 1.5rem !important; +} + +.mr-4, +.mx-4 { + margin-right: 1.5rem !important; +} + +.mb-4, +.my-4 { + margin-bottom: 1.5rem !important; +} + +.ml-4, +.mx-4 { + margin-left: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.mt-5, +.my-5 { + margin-top: 3rem !important; +} + +.mr-5, +.mx-5 { + margin-right: 3rem !important; +} + +.mb-5, +.my-5 { + margin-bottom: 3rem !important; +} + +.ml-5, +.mx-5 { + margin-left: 3rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.pt-0, +.py-0 { + padding-top: 0 !important; +} + +.pr-0, +.px-0 { + padding-right: 0 !important; +} + +.pb-0, +.py-0 { + padding-bottom: 0 !important; +} + +.pl-0, +.px-0 { + padding-left: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.pt-1, +.py-1 { + padding-top: 0.25rem !important; +} + +.pr-1, +.px-1 { + padding-right: 0.25rem !important; +} + +.pb-1, +.py-1 { + padding-bottom: 0.25rem !important; +} + +.pl-1, +.px-1 { + padding-left: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.pt-2, +.py-2 { + padding-top: 0.5rem !important; +} + +.pr-2, +.px-2 { + padding-right: 0.5rem !important; +} + +.pb-2, +.py-2 { + padding-bottom: 0.5rem !important; +} + +.pl-2, +.px-2 { + padding-left: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.pt-3, +.py-3 { + padding-top: 1rem !important; +} + +.pr-3, +.px-3 { + padding-right: 1rem !important; +} + +.pb-3, +.py-3 { + padding-bottom: 1rem !important; +} + +.pl-3, +.px-3 { + padding-left: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.pt-4, +.py-4 { + padding-top: 1.5rem !important; +} + +.pr-4, +.px-4 { + padding-right: 1.5rem !important; +} + +.pb-4, +.py-4 { + padding-bottom: 1.5rem !important; +} + +.pl-4, +.px-4 { + padding-left: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.pt-5, +.py-5 { + padding-top: 3rem !important; +} + +.pr-5, +.px-5 { + padding-right: 3rem !important; +} + +.pb-5, +.py-5 { + padding-bottom: 3rem !important; +} + +.pl-5, +.px-5 { + padding-left: 3rem !important; +} + +.bs-container { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.bs-container-fluid { + width: 100%; + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} + +.bs-row { + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin-right: -15px; + margin-left: -15px; +} + + +.bs-col-1, .bs-col-2, .bs-col-3, .bs-col-4, .bs-col-5, .bs-col-6, .bs-col-7, .bs-col-8, .bs-col-9, .bs-col-10, .bs-col-11, .bs-col-12, .bs-col, .bs-col-sm-1, .bs-col-sm-2, .bs-col-sm-3, .bs-col-sm-4, .bs-col-sm-5, .bs-col-sm-6, .bs-col-sm-7, .bs-col-sm-8, .bs-col-sm-9, .bs-col-sm-10, .bs-col-sm-11, .bs-col-sm-12, .bs-col-sm, .bs-col-md-1, .bs-col-md-2, .bs-col-md-3, .bs-col-md-4, .bs-col-md-5, .bs-col-md-6, .bs-col-md-7, .bs-col-md-8, .bs-col-md-9, .bs-col-md-10, .bs-col-md-11, .bs-col-md-12, .bs-col-md, .bs-col-lg-1, .bs-col-lg-2, .bs-col-lg-3, .bs-col-lg-4, .bs-col-lg-5, .bs-col-lg-6, .bs-col-lg-7, .bs-col-lg-8, .bs-col-lg-9, .bs-col-lg-10, .bs-col-lg-11, .bs-col-lg-12, .bs-col-lg, .bs-col-xl-1, .bs-col-xl-2, .bs-col-xl-3, .bs-col-xl-4, .bs-col-xl-5, .bs-col-xl-6, .bs-col-xl-7, .bs-col-xl-8, .bs-col-xl-9, .bs-col-xl-10, .bs-col-xl-11, .bs-col-xl-12, .bs-col-xl { + position: relative; + width: 100%; + padding-right: 15px; + padding-left: 15px; +} + + +.bs-col { + -ms-flex-preferred-size: 0; + flex-basis: 0; + -ms-flex-positive: 1; + flex-grow: 1; + min-width: 0; + max-width: 100%; +} + +.bs-col-auto { + -ms-flex: 0 0 auto; + flex: 0 0 auto; + width: auto; + max-width: 100%; +} + +.bs-col-1 { + -ms-flex: 0 0 8.333333%; + flex: 0 0 8.333333%; + max-width: 8.333333%; +} + +.bs-col-2 { + -ms-flex: 0 0 16.666667%; + flex: 0 0 16.666667%; + max-width: 16.666667%; +} + +.bs-col-3 { + -ms-flex: 0 0 25%; + flex: 0 0 25%; + max-width: 25%; +} + +.bs-col-4 { + -ms-flex: 0 0 33.333333%; + flex: 0 0 33.333333%; + max-width: 33.333333%; +} + +.bs-col-5 { + -ms-flex: 0 0 41.666667%; + flex: 0 0 41.666667%; + max-width: 41.666667%; +} + +.bs-col-6 { + -ms-flex: 0 0 50%; + flex: 0 0 50%; + max-width: 50%; +} + +.bs-col-7 { + -ms-flex: 0 0 58.333333%; + flex: 0 0 58.333333%; + max-width: 58.333333%; +} + +.bs-col-8 { + -ms-flex: 0 0 66.666667%; + flex: 0 0 66.666667%; + max-width: 66.666667%; +} + +.bs-col-9 { + -ms-flex: 0 0 75%; + flex: 0 0 75%; + max-width: 75%; +} + +.bs-col-10 { + -ms-flex: 0 0 83.333333%; + flex: 0 0 83.333333%; + max-width: 83.333333%; +} + +.bs-col-11 { + -ms-flex: 0 0 91.666667%; + flex: 0 0 91.666667%; + max-width: 91.666667%; +} + +.bs-col-12 { + -ms-flex: 0 0 100%; + flex: 0 0 100%; + max-width: 100%; +} + +.bs-border { + border: 1px solid #dee2e6 !important; +} + +.bs-border-top { + border-top: 1px solid #dee2e6 !important; +} + +.bs-border-right { + border-right: 1px solid #dee2e6 !important; +} + +.bs-border-bottom { + border-bottom: 1px solid #dee2e6 !important; +} + +.bs-border-left { + border-left: 1px solid #dee2e6 !important; +} + +.bs-border-0 { + border: 0 !important; +} + +.bs-border-top-0 { + border-top: 0 !important; +} + +.bs-border-right-0 { + border-right: 0 !important; +} + +.bs-border-bottom-0 { + border-bottom: 0 !important; +} + +.bs-border-left-0 { + border-left: 0 !important; +} + +.bs-border-primary { + border-color: #007bff !important; +} + +.bs-border-secondary { + border-color: #6c757d !important; +} + +.bs-border-success { + border-color: #28a745 !important; +} + +.bs-border-info { + border-color: #17a2b8 !important; +} + +.bs-border-warning { + border-color: #ffc107 !important; +} + +.bs-border-danger { + border-color: #dc3545 !important; +} + +.bs-border-light { + border-color: #f8f9fa !important; +} + +.bs-border-dark { + border-color: #343a40 !important; +} + +.bs-border-white { + border-color: #fff !important; +} diff --git a/app/assets/stylesheets/species/downloads.scss b/app/assets/stylesheets/species/downloads.scss index 18bcd01fc2..8f3b8d5837 100644 --- a/app/assets/stylesheets/species/downloads.scss +++ b/app/assets/stylesheets/species/downloads.scss @@ -379,3 +379,12 @@ } } } + +.download-block { + .sub-heading { + color: #2d3237; + font-weight: bold; + text-transform: uppercase; + user-select: none; + } +} diff --git a/app/controllers/admin/eu_decision_types_controller.rb b/app/controllers/admin/eu_decision_types_controller.rb index bfc9b69298..a287115aed 100644 --- a/app/controllers/admin/eu_decision_types_controller.rb +++ b/app/controllers/admin/eu_decision_types_controller.rb @@ -8,12 +8,6 @@ def index end end - def create - create! do |failure| - failure.js { render 'new' } - end - end - protected def collection diff --git a/app/controllers/admin/eu_opinions_controller.rb b/app/controllers/admin/eu_opinions_controller.rb index 1d88873d39..6c671e9eb8 100644 --- a/app/controllers/admin/eu_opinions_controller.rb +++ b/app/controllers/admin/eu_opinions_controller.rb @@ -40,6 +40,7 @@ def load_lib_objects @geo_entities = GeoEntity.order(:name_en).joins(:geo_entity_type). where(:geo_entity_types => { :name => GeoEntityType::SETS[GeoEntityType::DEFAULT_SET] }) @eu_decision_types = EuDecisionType.opinions + @srg_histories = SrgHistory.order(:name) @ec_srgs = Event.where("type = 'EcSrg' OR type = 'EuRegulation' AND name IN ('No 338/97', 'No 938/97', 'No 750/2013')" ).order("effective_at DESC") diff --git a/app/controllers/admin/srg_histories_controller.rb b/app/controllers/admin/srg_histories_controller.rb new file mode 100644 index 0000000000..2393622570 --- /dev/null +++ b/app/controllers/admin/srg_histories_controller.rb @@ -0,0 +1,8 @@ +class Admin::SrgHistoriesController < Admin::StandardAuthorizationController + protected + + def collection + @srg_histories ||= end_of_association_chain.page(params[:page]). + order('UPPER(name) ASC') + end +end diff --git a/app/models/eu_decision.rb b/app/models/eu_decision.rb index 061297314b..e138c0dc5c 100644 --- a/app/models/eu_decision.rb +++ b/app/models/eu_decision.rb @@ -34,12 +34,13 @@ class EuDecision < ActiveRecord::Base :is_current, :notes, :start_date, :start_event_id, :eu_decision_type_id, :taxon_concept_id, :type, :conditions_apply, :term_id, :source_id, :nomenclature_note_en, :nomenclature_note_es, :nomenclature_note_fr, - :created_by_id, :updated_by_id + :created_by_id, :updated_by_id, :srg_history_id belongs_to :taxon_concept belongs_to :m_taxon_concept, :foreign_key => :taxon_concept_id belongs_to :geo_entity belongs_to :eu_decision_type + belongs_to :srg_history belongs_to :source, :class_name => 'TradeCode' belongs_to :term, :class_name => 'TradeCode' belongs_to :start_event, :class_name => 'Event' @@ -49,7 +50,7 @@ class EuDecision < ActiveRecord::Base validates :taxon_concept, presence: true validates :geo_entity, presence: true - validates :eu_decision_type, presence: true + validate :eu_decision_type_and_or_srg_history translates :nomenclature_note @@ -85,4 +86,8 @@ def term_name term.try(:name_en) end + def eu_decision_type_and_or_srg_history + return if eu_decision_type_id || srg_history_id + errors.add(:base, "Eu decision type and SRG history can't be blank at the same time") + end end diff --git a/app/models/eu_decision_type.rb b/app/models/eu_decision_type.rb index f4a268cd45..f31be9c214 100644 --- a/app/models/eu_decision_type.rb +++ b/app/models/eu_decision_type.rb @@ -14,7 +14,7 @@ class EuDecisionType < ActiveRecord::Base attr_accessible :name, :tooltip, :decision_type include Dictionary build_dictionary :negative_opinion, :positive_opinion, :no_opinion, - :suspension + :suspension, :srg_referral scope :opinions, where('decision_type <> ?', EuDecisionType::SUSPENSION). order('UPPER(name) ASC') diff --git a/app/models/species/eu_decisions_export.rb b/app/models/species/eu_decisions_export.rb index 1447be7da8..7b0550d123 100644 --- a/app/models/species/eu_decisions_export.rb +++ b/app/models/species/eu_decisions_export.rb @@ -6,15 +6,18 @@ def initialize(filters) @geo_entities_ids = filters[:geo_entities_ids] @years = filters[:years] @decision_types = filters[:decision_types] + @eu_decision_filter = filters[:eu_decision_filter] @set = filters[:set] initialize_csv_separator(filters[:csv_separator]) initialize_file_name end + HISTORIC_III_OPINIONS = ['(No opinion) iii)','(No opinion) iii) removed'].freeze def query rel = EuDecision.from("#{table_name} AS eu_decisions"). select(sql_columns). order(:taxonomic_position, :party, :ordering_date) + return rel.where('srg_history = ?', @eu_decision_filter) if @eu_decision_filter == 'In consultation' if @set == 'current' rel = rel.where(is_valid: true) end @@ -39,19 +42,26 @@ def query 'EXTRACT(YEAR FROM start_date) IN (?)', @years ) end - if @decision_types['negativeOpinions'] == 'false' - rel = rel.where('decision_type <> ?', EuDecisionType::NEGATIVE_OPINION) - end - if @decision_types['positiveOpinions'] == 'false' - rel = rel.where('decision_type <> ?', EuDecisionType::POSITIVE_OPINION) - end - if @decision_types['noOpinions'] == 'false' - rel = rel.where('decision_type <> ?', EuDecisionType::NO_OPINION) - end - if @decision_types['suspensions'] == 'false' - rel = rel.where('decision_type <> ?', EuDecisionType::SUSPENSION) + + # decision_type can now be NULL. + # With the following condition, Postgresql does not take into account NULL values. + # Furthemore, the SRG_REFERRAL filter should also include the historic iii) when All + # filter value is selected + if excluded_decision_types.present? + rel = + if @set == 'all' && !excluded_decision_types.include?('SRG_REFERRAL') + rel.where("decision_type NOT IN(?) OR decision_type_for_display IN(?)", excluded_decision_types, HISTORIC_III_OPINIONS) + else + rel.where('decision_type NOT IN(?)', excluded_decision_types) + end end - rel + + # remove decisions with NULL type 'decision_type IS NOT NULL' + rel = rel.where('decision_type IS NOT NULL') + + # exclude EU decisions 'Discussed at SRG' by default + # IS DISTINCT FROM allows to return records with NULL as well + rel = rel.where('srg_history IS DISTINCT FROM ?', 'Discussed at SRG') end private @@ -69,7 +79,7 @@ def csv_column_headers 'Kingdom', 'Phylum', 'Class', 'Order', 'Family', 'Genus', 'Species', 'Subspecies', 'Full Name', 'Rank', 'Date of Decision', 'Valid since', 'Party', - 'EU Decision', 'Source', 'Term', + 'EU Decision', 'SRG History', 'Source', 'Term', 'Notes', 'Document', "Valid on Date: #{DateTime.now.strftime('%d/%m/%Y')}" ] end @@ -79,9 +89,16 @@ def sql_columns :kingdom_name, :phylum_name, :class_name, :order_name, :family_name, :genus_name, :species_name, :subspecies_name, :full_name, :rank_name, :start_date_formatted, :original_start_date_formatted, :party, - :decision_type_for_display, :source_code_and_name, :term_name, + :decision_type_for_display, :srg_history, :source_code_and_name, :term_name, :full_note_en, :start_event_name, :is_valid_for_display ] end + # Produces list of excluded decision types. + # e.g. SUSPENSIONS,SRG_REFERRAL + def excluded_decision_types + @excluded_decision_types ||= @decision_types.map do |key, value| + value == 'false' ? key.singularize.underscore.upcase : nil + end.compact + end end diff --git a/app/models/srg_history.rb b/app/models/srg_history.rb new file mode 100644 index 0000000000..85d6c426c9 --- /dev/null +++ b/app/models/srg_history.rb @@ -0,0 +1,7 @@ +class SrgHistory < ActiveRecord::Base + attr_accessible :name, :tooltip + + has_many :eu_decisions + + validates :name, presence: true, uniqueness: true +end diff --git a/app/serializers/species/eu_decision_serializer.rb b/app/serializers/species/eu_decision_serializer.rb index 5107e7b6a5..03dfb6b00b 100644 --- a/app/serializers/species/eu_decision_serializer.rb +++ b/app/serializers/species/eu_decision_serializer.rb @@ -3,6 +3,7 @@ class Species::EuDecisionSerializer < ActiveModel::Serializer :is_current, :subspecies_info, :nomenclature_note_en, :nomenclature_note_fr, :nomenclature_note_es, :eu_decision_type, + :srg_history, :geo_entity, :start_event, :source, @@ -13,6 +14,10 @@ def eu_decision_type object['eu_decision_type'] && JSON.parse(object['eu_decision_type']) end + def srg_history + object['srg_history'] && JSON.parse(object['srg_history']) + end + def geo_entity object['geo_entity_en'] && JSON.parse(object['geo_entity_en']) end diff --git a/app/serializers/species/show_taxon_concept_serializer_cites.rb b/app/serializers/species/show_taxon_concept_serializer_cites.rb index d37f7d7789..76cf9ebf67 100644 --- a/app/serializers/species/show_taxon_concept_serializer_cites.rb +++ b/app/serializers/species/show_taxon_concept_serializer_cites.rb @@ -124,6 +124,7 @@ def eu_decisions eu_decisions.nomenclature_note_fr, eu_decisions.nomenclature_note_es, eu_decision_type, + srg_history, start_event, end_event, geo_entity_en, diff --git a/app/views/admin/eu_opinions/_current_opinions_form.html.erb b/app/views/admin/eu_opinions/_current_opinions_form.html.erb index e3da58b02a..d11d5b290b 100644 --- a/app/views/admin/eu_opinions/_current_opinions_form.html.erb +++ b/app/views/admin/eu_opinions/_current_opinions_form.html.erb @@ -5,6 +5,7 @@
    Regulation Country or Territory TypeSRG history Term Source Notes<%= opinion.start_event && opinion.start_event.name %> <%= opinion.geo_entity && opinion.geo_entity.name_en %> - <%= opinion.eu_decision_type.name %> - <%= '(' + opinion.eu_decision_type.tooltip + ')' if opinion. - eu_decision_type.tooltip.present? %> + <% if opinion.eu_decision_type %> + <%= opinion.eu_decision_type.name %> + <%= '(' + opinion.eu_decision_type.tooltip + ')' if opinion. + eu_decision_type.tooltip.present? %> + <% end %> + + <% if opinion.srg_history %> + <%= opinion.srg_history.name %> + <%= '(' + opinion.srg_history.tooltip + ')' if opinion. + srg_history.tooltip.present? %> + <% end %> <%= opinion.term && opinion.term.code %> <%= opinion.source && opinion.source.code %> Regulation Country or Territory TypeSRG history Term Source Notes<%= opinion.start_event.try(:name) %> <%= opinion.geo_entity && opinion.geo_entity.name_en %> - <%= opinion.eu_decision_type.name %> - <%= '(' + opinion.eu_decision_type.tooltip + ')' if opinion. - eu_decision_type.tooltip.present? %> + <% if opinion.eu_decision_type %> + <%= opinion.eu_decision_type.try(:name) %> + <%= '(' + opinion.eu_decision_type.tooltip + ')' if opinion. + eu_decision_type.tooltip.present? %> + <% end %> + + <% if opinion.srg_history %> + <%= opinion.srg_history.name %> + <%= '(' + opinion.srg_history.tooltip + ')' if opinion. + srg_history.tooltip.present? %> + <% end %> <%= opinion.term && opinion.term.code %> <%= opinion.source && opinion.source.code %>
    NameTooltipActions
    + + <%= srg_history.name %> + + + + <%= srg_history.tooltip %> + + + <%= link_to delete_icon, resource_url(srg_history), :confirm => "Warning: you are about to delete data. Are you sure?", :method => :delete %> +