diff --git a/Gemfile.lock b/Gemfile.lock index 5cf57f06..a95aad7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,6 +4,10 @@ GIT tag: v1.0.10 specs: laa-criminal-legal-aid-schemas (1.0.10) + revision: aa0a86bf5bd66514b74c65ce0b55f4b3a7154d2b + tag: v1.0.9 + specs: + laa-criminal-legal-aid-schemas (1.0.9) dry-schema (~> 1.13) dry-struct (~> 1.6.0) json-schema (~> 4.0.0) diff --git a/app/api/datastore/entities/v1/search_result.rb b/app/api/datastore/entities/v1/search_result.rb index 4d19b361..56f5c885 100644 --- a/app/api/datastore/entities/v1/search_result.rb +++ b/app/api/datastore/entities/v1/search_result.rb @@ -11,15 +11,31 @@ class SearchResult < Grape::Entity expose :review_status expose :parent_id expose :work_stream + expose :return_reason + expose :return_details + expose :office_code + expose :provider_name private + def applicant + object.submitted_application&.dig('client_details', 'applicant') + end + def applicant_name "#{applicant&.dig('first_name')} #{applicant&.dig('last_name')}" end - def applicant - object.submitted_application&.dig('client_details', 'applicant') + def provider + object.submitted_application&.dig('provider_details') + end + + def provider_name + "#{provider&.dig('legal_rep_first_name')} #{provider&.dig('legal_rep_last_name')}" + end + + def return_details + object.return_details&.fetch('details', nil) end def parent_id diff --git a/app/api/datastore/v1/searching.rb b/app/api/datastore/v1/searching.rb index 47234a9c..9fb5c6ee 100644 --- a/app/api/datastore/v1/searching.rb +++ b/app/api/datastore/v1/searching.rb @@ -20,6 +20,9 @@ class Searching < Base optional :submitted_after, type: DateTime optional :submitted_before, type: DateTime + + optional :reviewed_after, type: DateTime + optional :reviewed_before, type: DateTime end optional :sorting, type: JSON, desc: 'Sorting JSON.', default: Sorting.new.attributes do diff --git a/app/models/search_filter.rb b/app/models/search_filter.rb index 2dc57993..aea31bd5 100644 --- a/app/models/search_filter.rb +++ b/app/models/search_filter.rb @@ -10,6 +10,8 @@ class SearchFilter attribute :search_text, :string attribute :submitted_after, :datetime attribute :submitted_before, :datetime + attribute :reviewed_after, :datetime + attribute :reviewed_before, :datetime attribute :work_stream, array: true, default: -> { [] } def active_filters @@ -41,6 +43,14 @@ def filter_submitted_before(scope) scope.where('submitted_at < ?', submitted_before) end + def filter_reviewed_after(scope) + scope.where('reviewed_at > ?', reviewed_after) + end + + def filter_reviewed_before(scope) + scope.where('reviewed_at < ?', reviewed_before) + end + def filter_application_id_in(scope) scope.where(id: application_id_in) end diff --git a/app/models/sorting.rb b/app/models/sorting.rb index c9f4be97..d6f9a4ac 100644 --- a/app/models/sorting.rb +++ b/app/models/sorting.rb @@ -13,6 +13,9 @@ class Sorting applicant_name: [:applicant_last_name, :applicant_first_name], returned_at: [:returned_at], reviewed_at: [:reviewed_at], + return_reason: [:return_reason], + office_code: [:office_code], + reference: [:reference], submitted_at: [:submitted_at] }.freeze diff --git a/db/migrate/20231117142406_add_return_reason_virtual_attribute_to_crime_applications.rb b/db/migrate/20231117142406_add_return_reason_virtual_attribute_to_crime_applications.rb new file mode 100644 index 00000000..245f49d3 --- /dev/null +++ b/db/migrate/20231117142406_add_return_reason_virtual_attribute_to_crime_applications.rb @@ -0,0 +1,14 @@ +class AddReturnReasonVirtualAttributeToCrimeApplications < ActiveRecord::Migration[7.0] + def change + add_column( + :crime_applications, + :return_reason, + :virtual, + as: "(return_details->>'reason')", + type: :string, + stored: true + ) + + add_index :crime_applications, :return_reason + end +end diff --git a/db/migrate/20231117142441_add_index_for_office_code_virtual_attribute_on_crime_applications.rb b/db/migrate/20231117142441_add_index_for_office_code_virtual_attribute_on_crime_applications.rb new file mode 100644 index 00000000..a77537c9 --- /dev/null +++ b/db/migrate/20231117142441_add_index_for_office_code_virtual_attribute_on_crime_applications.rb @@ -0,0 +1,5 @@ +class AddIndexForOfficeCodeVirtualAttributeOnCrimeApplications < ActiveRecord::Migration[7.0] + def change + add_index :crime_applications, :office_code + end +end diff --git a/db/schema.rb b/db/schema.rb index 3c8d30ff..9c536a72 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_11_06_141454) do +ActiveRecord::Schema[7.0].define(version: 2023_11_17_142441) do # These are extensions that must be enabled in order to support this database enable_extension "citext" enable_extension "plpgsql" @@ -32,8 +32,11 @@ t.virtual "office_code", type: :string, as: "((submitted_application -> 'provider_details'::text) ->> 'office_code'::text)", stored: true t.jsonb "return_details" t.string "work_stream", default: "criminal_applications_team", null: false + t.virtual "return_reason", type: :string, as: "(return_details ->> 'reason'::text)", stored: true t.index ["applicant_last_name", "applicant_first_name"], name: "index_crime_applications_on_applicant_name" + t.index ["office_code"], name: "index_crime_applications_on_office_code" t.index ["reference"], name: "index_crime_applications_on_reference" + t.index ["return_reason"], name: "index_crime_applications_on_return_reason" t.index ["review_status", "reviewed_at"], name: "index_crime_applications_on_review_status_and_reviewed_at" t.index ["review_status", "submitted_at"], name: "index_crime_applications_on_review_status_and_submitted_at" t.index ["searchable_text"], name: "index_crime_applications_on_searchable_text", using: :gin diff --git a/spec/api/datastore/entities/v1/search_result_spec.rb b/spec/api/datastore/entities/v1/search_result_spec.rb index 1e337a2f..5f419623 100644 --- a/spec/api/datastore/entities/v1/search_result_spec.rb +++ b/spec/api/datastore/entities/v1/search_result_spec.rb @@ -1,13 +1,26 @@ require 'rails_helper' +# rubocop:disable RSpec/MultipleMemoizedHelpers +# RSpec.describe Datastore::Entities::V1::SearchResult do subject(:representation) do JSON.parse(described_class.represent(crime_application).to_json).symbolize_keys end let(:crime_application) do - instance_double(CrimeApplication, id:, review_status:, status:, submitted_at:, reviewed_at:, - submitted_application:, work_stream:) + instance_double( + CrimeApplication, + id:, + review_status:, + status:, + submitted_at:, + reviewed_at:, + submitted_application:, + work_stream:, + return_reason:, + return_details:, + office_code: + ) end let(:id) { SecureRandom.uuid } @@ -16,6 +29,9 @@ let(:reviewed_at) { '2023-05-22T12:42:10.907Z' } let(:status) { 'submitted' } let(:review_status) { 'assessment_completed' } + let(:return_reason) { 'evidence_issue' } + let(:return_details) { { 'details' => 'There was an issue with the uploaded evidence' } } + let(:office_code) { 'XYZ123' } let(:work_stream) { 'criminal_applications_team' } let(:submitted_application) do @@ -57,4 +73,27 @@ it 'represents the work_stream' do expect(representation.fetch(:work_stream)).to eq 'criminal_applications_team' end + + it 'represents the office_code' do + expect(representation.fetch(:office_code)).to eq office_code + end + + it 'represents the return_reason' do + expect(representation.fetch(:return_reason)).to eq 'evidence_issue' + end + + it 'represents the return_details' do + expect(representation.fetch(:return_details)).to eq 'There was an issue with the uploaded evidence' + end + + context 'when return details are empty' do + let(:return_details) { {} } + let(:return_reason) { nil } + + it 'represents details and reason as nil' do + expect(representation.fetch(:return_reason)).to be_nil + expect(representation.fetch(:return_details)).to be_nil + end + end end +# rubocop:enable RSpec/MultipleMemoizedHelpers diff --git a/spec/api/datastore/v1/searching/filter_by_reviewed_at_spec.rb b/spec/api/datastore/v1/searching/filter_by_reviewed_at_spec.rb new file mode 100644 index 00000000..f2558286 --- /dev/null +++ b/spec/api/datastore/v1/searching/filter_by_reviewed_at_spec.rb @@ -0,0 +1,42 @@ +require 'rails_helper' + +RSpec.describe 'searches filter by reviewed_at' do + subject(:api_request) do + post '/api/v1/searches', params: { search: search, pagination: {} } + end + + let(:search) { {} } + let(:records) { JSON.parse(response.body).fetch('records') } + + before do + CrimeApplication.insert_all( + [ + { reviewed_at: 3.days.ago, submitted_application: { reference: 101 } }, + { reviewed_at: 2.days.ago, submitted_application: { reference: 102 } }, + { reviewed_at: 1.day.ago, submitted_application: { reference: 103 } } + ] + ) + + api_request + end + + it 'defaults to showing all applications' do + expect(records.pluck('reference')).to contain_exactly(101, 102, 103) + end + + context 'when reviewed_after is provided' do + let(:search) { { reviewed_after: 2.days.ago } } + + it 'only shows records reviewed after' do + expect(records.pluck('reference')).to contain_exactly(102, 103) + end + end + + context 'when reviewed_before is provided' do + let(:search) { { reviewed_before: 2.days.ago } } + + it 'only shows records reviewed before' do + expect(records.pluck('reference')).to eq([101]) + end + end +end