diff --git a/app/controllers/approvals_controller.rb b/app/controllers/approvals_controller.rb new file mode 100644 index 0000000..ad7bdd9 --- /dev/null +++ b/app/controllers/approvals_controller.rb @@ -0,0 +1,21 @@ +class ApprovalsController < ApplicationController + include MedicalReleaseContext + + before_action :set_medical_release + before_action :set_project + + layout "project" + + def create + @medical_release.approve_by(current_user) + if @medical_release.save + redirect_to [@project, :medical_releases], notice: t('.release_approved') + end + end + + private + + def set_project + @project = @medical_release.project + end +end diff --git a/app/helpers/tooltip_helper.rb b/app/helpers/tooltip_helper.rb index 77db302..f409b97 100644 --- a/app/helpers/tooltip_helper.rb +++ b/app/helpers/tooltip_helper.rb @@ -5,4 +5,12 @@ module TooltipHelper concat tag.div(class: "tooltip-inner") end end + + def get_approval_data_for_medical_release(medical_release) + if medical_release.approved_by_user_name.present? + "#{medical_release.approved_by_user_name} [#{medical_release.approved_by_user_email}]" + else + medical_release.approved_by_user_email + end + end end diff --git a/app/models/medical_release.rb b/app/models/medical_release.rb index 5d0692d..996bfc5 100644 --- a/app/models/medical_release.rb +++ b/app/models/medical_release.rb @@ -100,6 +100,18 @@ class MedicalRelease < ApplicationRecord "#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime("%Y.%m.%d")}_#{release_number}_#{filename_suffix.parameterize}" end + def approve_by(user) + return unless approved_at.nil? + + self.approved_by_user_name = user.full_name + self.approved_by_user_email = user.email + self.approved_at = Time.zone.now + end + + def approved? + approved_at.present? + end + private def valid_answers diff --git a/app/policies/medical_release_policy.rb b/app/policies/medical_release_policy.rb index 8866337..9ce60ce 100644 --- a/app/policies/medical_release_policy.rb +++ b/app/policies/medical_release_policy.rb @@ -15,6 +15,14 @@ class MedicalReleasePolicy < ReleasePolicy user.manager? || user.account_manager? end + def review? + user.account_manager? + end + + def approve? + review? + end + def edit_photos? true end diff --git a/app/views/approvals/new.html.erb b/app/views/approvals/new.html.erb new file mode 100644 index 0000000..688d2ba --- /dev/null +++ b/app/views/approvals/new.html.erb @@ -0,0 +1,15 @@ +
+ <%= card_header text: t(".heading"), close_action_path: [@project, :medical_releases] %> +
+ " width="90%" height="1200" /> + + <%= bootstrap_form_with model: @medical_release, method: :post, url: medical_release_approvals_path(@medical_release), local: true do |form| %> +
+ <%= link_to t("shared.cancel"), [@medical_release.project, :medical_releases], class: "col-3 text-reset" %> +
+ <%= form.button t('.actions.approve'), id: "approve_release", class: class_string("btn btn-block btn-success btn-primary"), data: { disable_with: t("shared.disable_with") } %> +
+
+ <% end %> +
+
\ No newline at end of file diff --git a/app/views/contracts/_for_office_use_only.erb b/app/views/contracts/_for_office_use_only.erb new file mode 100644 index 0000000..15abd19 --- /dev/null +++ b/app/views/contracts/_for_office_use_only.erb @@ -0,0 +1,13 @@ +<% if preview %> +

PREVIEW ONLY

+<% end %> + +

<%= t '.heading' %>

+ +
+ <%= description_list_pair t('.description_labels.producer'), releasable.project.account.name %> + <%= description_list_pair t('.description_labels.production'), releasable.project.name %> + <%= description_list_pair t('.description_labels.employee_issued_to'), releasable.name %> + <%= description_list_pair t('.description_labels.issued_by'), releasable.approved_by_user_name %> + <%= description_list_pair t('.description_labels.date_issued'), releasable.approved_at %> +
\ No newline at end of file diff --git a/app/views/contracts/pdf.html.erb b/app/views/contracts/pdf.html.erb index b430b4e..f9d72f7 100644 --- a/app/views/contracts/pdf.html.erb +++ b/app/views/contracts/pdf.html.erb @@ -25,6 +25,13 @@
<%= render "contracts/signature_page", releasable: releasable, contract_template: contract_template, preview: preview %>
+ +<% if releasable.class == MedicalRelease && releasable.approved? %> +
+ <%= render "contracts/for_office_use_only", releasable: releasable, preview: preview %> +
+<% end %> + <% if releasable.class == AcquiredMediaRelease %>
<%= render "contracts/files", release: releasable, preview: preview %> diff --git a/app/views/medical_releases/_medical_release.html.erb b/app/views/medical_releases/_medical_release.html.erb index 29c4b73..a598998 100644 --- a/app/views/medical_releases/_medical_release.html.erb +++ b/app/views/medical_releases/_medical_release.html.erb @@ -1,5 +1,13 @@ <%= check_box_tag "medical_release_ids[]", medical_release.id, false %> + + <% if medical_release.approved? %> + <% tooltip_user_data = get_approval_data_for_medical_release(medical_release) %> + + <% end %> + <% if medical_release.photo.attached? %> <%= image_tag medium_variant(medical_release.photo), class: "img-fluid" %> @@ -37,6 +45,9 @@ <% if policy(medical_release.tags).new? %> <%= link_to fa_icon("tags fw", text: "Tags"), [:new, medical_release, :acts_as_taggable_on_tag], class: "dropdown-item", remote: true %> <% end %> + <% if policy(MedicalRelease).review? %> + <%= link_to fa_icon("search fw", text: t('.actions.review')), new_medical_release_approvals_path(medical_release), class: "dropdown-item" %> + <% end %> <% if policy(MedicalRelease).download_single? && policy(Contract).show? && (medical_release.contract.attached? || medical_release.contract_template.present?) %> <%= link_to fa_icon("download fw", text: "Download"), [medical_release, :contracts, format: "pdf"], class: "dropdown-item", target: "_blank" %> <% end %> diff --git a/app/views/medical_releases/index.html.erb b/app/views/medical_releases/index.html.erb index e056d0f..abba148 100644 --- a/app/views/medical_releases/index.html.erb +++ b/app/views/medical_releases/index.html.erb @@ -22,6 +22,7 @@ <%= check_box_tag "medical_release_ids[]", false, false %> + <%= t '.table_headers.approved'%> <%= MedicalRelease.human_attribute_name(:person_name) %> <%= MedicalRelease.human_attribute_name(:contact_info) %> diff --git a/config/locales/en.yml b/config/locales/en.yml index d09ddeb..4fd633d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -171,6 +171,13 @@ en: sidebar: files: Files team_member: Team Member + approvals: + create: + release_approved: Medical release has been approved + new: + actions: + approve: Approve + heading: Review Medical Release blank_contracts: new: number_of_copies_label: Number of copies @@ -288,6 +295,14 @@ en: print_QR_code: Print out release QR codes releases_automatically_organized: Releases are automatically organized as they’re submitted contracts: + for_office_use_only: + description_labels: + date_issued: Date Issued + employee_issued_to: Employee Issued To + issued_by: Issued By + producer: Producer + production: Production + heading: For Office Use Only photos: guardian_2_photo_heading: Second guardian photo guardian_photo_heading: Guardian photo @@ -782,12 +797,16 @@ en: search: Search empty: Medical releases will appear here table_headers: + approved: Approved notes: Notes signed_at: Date Signed tags: Tags medical_release: actions: manage: Manage + review: Review + messages: + approved_tooltip: Approved by %{user} on %{timestamp} misc_releases: destroy: alert: The misc release has been deleted diff --git a/config/locales/es.yml b/config/locales/es.yml index 439e747..10d3be8 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -50,6 +50,13 @@ es: all_releases: All Releases (ES) complete_releases: Complete Releases (ES) incomplete_releases: Incomplete Releases (ES) + approvals: + create: + release_approved: Medical release has been approved (ES) + new: + actions: + approve: Approve (ES) + heading: Review Medical Release (ES) blank_contracts: new: number_of_copies_label: Number of copies (ES) @@ -107,6 +114,14 @@ es: print_QR_code: Print out release QR codes (ES) releases_automatically_organized: Releases are automatically organized as they’re submitted (ES) contracts: + for_office_use_only: + description_labels: + date_issued: Date Issued (ES) + employee_issued_to: Employee Issued To (ES) + issued_by: Issued By (ES) + producer: Producer (ES) + production: Production (ES) + heading: For Office Use Only (ES) photos: guardian_2_photo_heading: Second guardian photo (ES) guardian_photo_heading: Guardian photo (ES) @@ -274,6 +289,8 @@ es: create: Create Live Stream (ES) update: Save Changes (ES) create: 'Crear %{model}' + medical_release: + update: Approve (ES) update: 'Actualizar %{model}' location_releases: form: @@ -286,6 +303,14 @@ es: medical_releases: custom_validation_errors: question_answer_is_required: answer is required (ES) + index: + table_headers: + approved: Approved (ES) + medical_release: + actions: + review: Review (ES) + messages: + approved_tooltip: "" public: appearance_releases: create: diff --git a/config/routes.rb b/config/routes.rb index d43bfb9..5096446 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -137,12 +137,17 @@ Rails.application.routes.draw do end RELEASES = [:acquired_media_releases, :appearance_releases, :talent_releases, :material_releases, :location_releases] - ALL_RELEASES = RELEASES + [:music_releases, :medical_releases, :misc_releases] + ALL_RELEASES = RELEASES + [:music_releases, :misc_releases] ALL_RELEASES.each do |release| resources release, only: [], concerns: :taggable end + # Customization for medical releases + resources :medical_releases, only: [], concerns: :taggable do + resource :approvals, only: [:new, :create] + end + resources :bulk_taggings, only: [:new, :create] namespace :api do diff --git a/db/migrate/20200707155717_add_approval_info_columns_to_medical_releases.rb b/db/migrate/20200707155717_add_approval_info_columns_to_medical_releases.rb new file mode 100644 index 0000000..00fa2c7 --- /dev/null +++ b/db/migrate/20200707155717_add_approval_info_columns_to_medical_releases.rb @@ -0,0 +1,7 @@ +class AddApprovalInfoColumnsToMedicalReleases < ActiveRecord::Migration[6.0] + def change + add_column :medical_releases, :approved_by_user_name, :text + add_column :medical_releases, :approved_by_user_email, :text + add_column :medical_releases, :approved_at, :timestamp + end +end diff --git a/db/structure.sql b/db/structure.sql index 51b4216..616c0ac 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -1045,7 +1045,10 @@ CREATE TABLE public.medical_releases ( guardian_2_address_city character varying, guardian_2_address_state character varying, guardian_2_address_zip character varying, - guardian_2_address_country character varying + guardian_2_address_country character varying, + approved_by_user_name text, + approved_by_user_email text, + approved_at timestamp without time zone ); @@ -3902,6 +3905,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('20200619134853'), ('20200622180507'), ('20200625144713'), -('20200702152130'); +('20200702152130'), +('20200707155717'); diff --git a/spec/controllers/approvals_controller_spec.rb b/spec/controllers/approvals_controller_spec.rb new file mode 100644 index 0000000..ad374d1 --- /dev/null +++ b/spec/controllers/approvals_controller_spec.rb @@ -0,0 +1,36 @@ +require "rails_helper" + +RSpec.describe ApprovalsController, type: :controller do + render_views + + let(:user) { create(:user) } + let(:account) { user.primary_account } + let(:project) { create(:project, account: user.primary_account) } + + before do + sign_in user + end + + describe "#new" do + let!(:medical_release) { create(:medical_release, project: project) } + + it "responds successfully" do + get :new, params: { medical_release_id: medical_release } + + expect(response).to be_successful + end + end + + describe "#create" do + it "changes approval status successfully" do + medical_release = create(:medical_release, project: project) + + expect(MedicalRelease.last.approved?).to eq false + + post :create, params: { medical_release_id: medical_release } + + expect(response).to redirect_to [project, :medical_releases] + expect(MedicalRelease.last.approved?).to eq true + end + end +end diff --git a/spec/features/user_managing_medical_releases_spec.rb b/spec/features/user_managing_medical_releases_spec.rb index ad395f1..198497e 100644 --- a/spec/features/user_managing_medical_releases_spec.rb +++ b/spec/features/user_managing_medical_releases_spec.rb @@ -182,6 +182,18 @@ feature "User managing medical releases" do sign_in current_user end + scenario "Approved releases have checkmark and non-approved releases don't have checkmarks" do + create(:medical_release_with_contract_template, :native, project: project) + + visit project_medical_releases_path(project) + expect(page).to have_css('i.fa.fa-check-circle.fa-2x', count: 0) + + create(:medical_release_with_contract_template, :native, project: project, approved_by_user_email: "some@email.com", approved_at: DateTime.now) + visit project_medical_releases_path(project) + + expect(page).to have_css('i.fa.fa-check-circle.fa-2x', count: 1) + end + scenario "Download All is visible" do create(:medical_release_with_contract_template, :native, project: project) create(:medical_release_with_contract_template, :non_native, project: project) @@ -200,6 +212,15 @@ feature "User managing medical releases" do expect(page).to have_link("Download", exact: true, count: 2) end + scenario "Review action in Manage menu is visible" do + create(:medical_release_with_contract_template, :native, project: project) + create(:medical_release_with_contract_template, :non_native, project: project) + + visit project_medical_releases_path(project) + + expect(page).to have_link(review_action, exact: true) + end + scenario "Downloading PDF of native medical release is possible" do native_release = create(:medical_release_with_contract_template, :native, project: project) @@ -208,6 +229,64 @@ feature "User managing medical releases" do click_link *view_release_pdf_link_for(native_release) expect(content_type).to eq('application/pdf') end + + scenario "Reviewing release" do + create(:medical_release_with_contract_template, :native, project: project) + + visit project_medical_releases_path(project) + + click_link review_action + + expect(page).to have_content review_page_heading + expect(page).to have_content approve_button + end + + scenario 'When viewing the contract PDF of approved release there is page for office use only' do + medical_release = create(:medical_release_with_contract_template, + :native, + project: project, + person_first_name: 'Jane', + person_last_name: 'Doe', + approved_by_user_name: "Big Joe", + approved_by_user_email: "some@email.com", + approved_at: DateTime.now) + + sign_in(current_user) + visit project_medical_releases_path(project) + click_link *view_release_pdf_link_for(medical_release) + + expect(content_type).to eq('application/pdf') + expect(content_disposition).to include('inline') + expect(pdf_body).to have_content for_office_use_only.upcase + expect(pdf_body).to have_content producer_label + expect(pdf_body).to have_content production_label + expect(pdf_body).to have_content employee_issued_to_label + expect(pdf_body).to have_content issued_by_label + expect(pdf_body).to have_content date_issued + expect(pdf_body).to have_content 'Big Joe' + end + + scenario 'When viewing the contract PDF of not approved release there is no page for office use only' do + medical_release = create(:medical_release_with_contract_template, + :native, + project: project, + person_first_name: 'Jane', + person_last_name: 'Doe') + + sign_in(current_user) + visit project_medical_releases_path(project) + click_link *view_release_pdf_link_for(medical_release) + + expect(content_type).to eq('application/pdf') + expect(content_disposition).to include('inline') + expect(pdf_body).not_to have_content for_office_use_only.upcase + expect(pdf_body).not_to have_content producer_label + expect(pdf_body).not_to have_content production_label + expect(pdf_body).not_to have_content employee_issued_to_label + expect(pdf_body).not_to have_content issued_by_label + expect(pdf_body).not_to have_content date_issued + expect(pdf_body).not_to have_content 'Big Joe' + end end context "when the user is manager(project manager)" do @@ -235,6 +314,15 @@ feature "User managing medical releases" do expect(page).to have_link("Download", exact: true, count: 0) end + scenario "Review action in Manage menu is not visible" do + create(:medical_release_with_contract_template, :native, project: project) + create(:medical_release_with_contract_template, :non_native, project: project) + + visit project_medical_releases_path(project) + + expect(page).not_to have_link(review_action, exact: true) + end + scenario "Downloading PDF of native medical release is not possible" do native_release = create(:medical_release_with_contract_template, :native, project: project) @@ -279,6 +367,15 @@ feature "User managing medical releases" do expect(page).to have_link("Download", exact: true, count: 0) end + scenario "Review action in Manage menu is not visible" do + create(:medical_release_with_contract_template, :native, project: project) + create(:medical_release_with_contract_template, :non_native, project: project) + + visit project_medical_releases_path(project) + + expect(page).not_to have_link(review_action, exact: true) + end + scenario "Downloading PDF of native medical release is not possible" do native_release = create(:medical_release_with_contract_template, :native, project: project) @@ -458,4 +555,40 @@ feature "User managing medical releases" do def dummy_signature_legal_text 'Some signature legal language' end + + def review_action + t 'medical_releases.medical_release.actions.review' + end + + def review_page_heading + t 'approvals.new.heading' + end + + def approve_button + t 'approvals.new.actions.approve' + end + + def for_office_use_only + t 'contracts.for_office_use_only.heading' + end + + def producer_label + t 'contracts.for_office_use_only.description_labels.producer' + end + + def production_label + t 'contracts.for_office_use_only.description_labels.production' + end + + def employee_issued_to_label + t 'contracts.for_office_use_only.description_labels.employee_issued_to' + end + + def issued_by_label + t 'contracts.for_office_use_only.description_labels.issued_by' + end + + def date_issued + t 'contracts.for_office_use_only.description_labels.date_issued' + end end