diff --git a/.gitignore b/.gitignore index f5c7ec4a5b..04223534d7 100644 --- a/.gitignore +++ b/.gitignore @@ -42,16 +42,23 @@ yarn-debug.log* /node_modules ~$* TODO.md -NOTES.md REVISION GIT_REVISION +sorbet + +## AWS +aws/ecs/private/* NOTES.md staging.env # aws private aws/ecs/private/ +# Deployment +k8s-deploy +config/ansible +config/jenkins # Ignore spreadsheet fiels /*.csv /*.xls -/*.xlsx \ No newline at end of file +/*.xlsx diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..36b356317b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "trailingComma": "none" +} diff --git a/.ruby-version b/.ruby-version index 0bee604df7..00355e29d1 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.3.3 +2.3.7 diff --git a/.rufo b/.rufo new file mode 100644 index 0000000000..67f7580b36 --- /dev/null +++ b/.rufo @@ -0,0 +1,2 @@ +trailing_commas false +quote_style :single diff --git a/.solargraph.yml b/.solargraph.yml index cbbec7e186..5cdd70c603 100644 --- a/.solargraph.yml +++ b/.solargraph.yml @@ -8,10 +8,13 @@ exclude: - test/**/* - vendor/**/* - ".bundle/**/*" -require: [] -domains: [] -reporters: -- require_not_found -require_paths: [] -plugins: [] +# require: [] +# domains: [] +# reporters: +# - rubocop:version=0.81.0 # diagnostics +formatter: + rubocop: + version: 0.61.0 +# require_paths: [] +# plugins: [] max_files: 5000 diff --git a/Capfile b/Capfile index 45bf7bf25a..dc52ad5bdb 100644 --- a/Capfile +++ b/Capfile @@ -2,10 +2,10 @@ require "dotenv" Dotenv.load # Load DSL and set up stages -require 'capistrano/setup' +require "capistrano/setup" # Include default deployment tasks -require 'capistrano/deploy' +require "capistrano/deploy" require "capistrano/scm/git" install_plugin Capistrano::SCM::Git # Include tasks from other gems included in your Gemfile @@ -21,15 +21,14 @@ install_plugin Capistrano::SCM::Git # # require 'capistrano/rbenv' # require 'capistrano/chruby' -# require 'capistrano/bundler' -# require 'capistrano/rails/assets' -# require 'capistrano/rails/migrations' -require 'capistrano/rvm' -require 'capistrano/passenger' -require 'capistrano/rails' +require "capistrano/bundler" +require "capistrano/rvm" +require "capistrano/passenger" +require "capistrano/rails/assets" +require "capistrano/rails/migrations" +require 'capistrano/sidekiq/systemd' -require 'whenever/capistrano' -require 'capistrano/sidekiq' -require 'appsignal/capistrano' +require "whenever/capistrano" +require "appsignal/capistrano" # Load custom tasks from `lib/capistrano/tasks` if you have any defined -Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r } +Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r } diff --git a/Dockerfile b/Dockerfile index 68cfe82015..701b10d94a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,9 @@ -FROM ruby:2.3.3 +FROM ruby:2.3.7 -RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - +RUN echo "deb http://archive.debian.org/debian stretch main contrib non-free" > /etc/apt/sources.list +RUN apt-get update -q && \ + apt-get install -qy procps curl ca-certificates gnupg2 build-essential --no-install-recommends && apt-get clean +RUN curl -fsSL https://deb.nodesource.com/setup_12.x | bash - RUN curl --silent https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - RUN apt-get update -qq && apt-get install -y nodejs postgresql-client fonts-khmeros memcached cron RUN mkdir /app diff --git a/Gemfile b/Gemfile index aab8ba27c1..ec02191956 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,6 @@ source 'https://rubygems.org' +gem 'bundler', '1.17.3' gem 'rails', '4.2.5' gem 'pg', '~> 0.18.4' gem 'jquery-rails' @@ -13,12 +14,12 @@ gem 'bootstrap-sass', '~> 3.3.5' gem 'devise', '~> 3.5', '>= 3.5.2' gem 'haml-rails', '~> 0.9' gem 'dotenv-rails', '~> 2.0.2' -gem 'roo', '~> 2.2' +gem 'roo', '~> 2.8.3' gem 'fog' gem 's3' gem 'ffaker', '~> 2.1.0' gem 'draper', '~> 2.1' -gem 'datagrid', '~> 1.4.2' +gem 'datagrid', '1.6.3' gem 'active_model_serializers' gem 'sinatra', require: false gem 'rack-cors', require: 'rack/cors' @@ -54,6 +55,7 @@ gem 'carrierwave', '~> 1.3.2' gem 'mini_magick', '~> 4.5' gem 'chartkick', '~> 3.4' gem 'font-awesome-rails', '~> 4.7' +gem 'ruby-ole', '~> 1.2', '>= 1.2.12.2' gem 'spreadsheet', '~> 1.1.3' gem 'apartment', '~> 1.2' gem 'dropzonejs-rails', '~> 0.7.3' @@ -105,6 +107,7 @@ group :staging, :demo do end group :development do + gem 'active_record_query_trace', '1.7' gem 'letter_opener', '~> 1.4.1' gem 'letter_opener_web', '~> 1.3', '>= 1.3.4' gem 'rubocop', '~> 0.81.0', require: false @@ -112,7 +115,7 @@ group :development do gem 'capistrano-rails', '~> 1.1.1' gem 'capistrano-passenger', '~> 0.1.1' gem 'capistrano-rvm', '~> 0.1.2' - gem 'capistrano-sidekiq', '~> 1.0', '>= 1.0.3' + gem 'capistrano-sidekiq-systemd', require: false gem 'capistrano-foreman' gem 'rack-mini-profiler', '~> 1.0' gem 'metainspector' @@ -132,3 +135,7 @@ end gem "sentry-raven", "~> 2.13" gem 'terser', '~> 1.1', '>= 1.1.12' + +gem "redis-rails", "~> 5.0" + +gem "ahoy_email", "1.0.3" diff --git a/Gemfile.lock b/Gemfile.lock index 5aa0dd7045..321c3295d1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -28,6 +28,7 @@ GEM activemodel (>= 3.2) active_record_doctor (1.8.0) activerecord (>= 4.2.0) + active_record_query_trace (1.7) active_record_union (1.2.0) activerecord (>= 4.0) activejob (4.2.5) @@ -50,6 +51,11 @@ GEM activerecord (>= 4.2, < 7.0) activesupport (>= 4.2, < 7.0) addressable (2.4.0) + ahoy_email (1.0.3) + actionmailer (>= 4.2) + addressable (>= 2.3.2) + nokogiri + safely_block (>= 0.1.1) airbrussh (1.3.2) sshkit (>= 1.6.1, != 1.7.0) ancestry (3.0.5) @@ -111,9 +117,8 @@ GEM capistrano-rvm (0.1.2) capistrano (~> 3.0) sshkit (~> 1.2) - capistrano-sidekiq (1.0.3) + capistrano-sidekiq-systemd (0.2.0) capistrano (>= 3.9.0) - sidekiq (>= 3.4, < 6.0) capybara (2.15.4) addressable mini_mime (>= 0.1.3) @@ -169,8 +174,8 @@ GEM octokit (~> 4.7) terminal-table (~> 1) database_cleaner (1.8.5) - datagrid (1.4.4) - rails (>= 3.2.22.2) + datagrid (1.6.3) + rails (>= 4.0) db_text_search (0.2.0) activerecord (>= 4.1.15, < 6.0) declarative (0.0.9) @@ -207,6 +212,7 @@ GEM dry-inflector (0.1.2) enumerize (2.3.1) activesupport (>= 3.2) + errbase (0.1.1) erubis (2.7.0) ethon (0.8.1) ffi (>= 1.3.0) @@ -575,7 +581,6 @@ GEM no_proxy_fix (0.1.2) nokogiri (1.10.10) mini_portile2 (~> 2.4.0) - racc (~> 1.4) nokogumbo (2.0.2) nokogiri (~> 1.8, >= 1.8.4) octokit (4.19.0) @@ -615,7 +620,6 @@ GEM slop (~> 3.4) pundit (1.1.0) activesupport (>= 3.0.0) - racc (1.5.2) rack (1.6.13) rack-cors (1.0.6) rack (>= 1.6.0) @@ -675,9 +679,25 @@ GEM railties (>= 3.2) tilt redis (3.3.5) + redis-actionpack (5.1.0) + actionpack (>= 4.0, < 7) + redis-rack (>= 1, < 3) + redis-store (>= 1.1.0, < 2) + redis-activesupport (5.3.0) + activesupport (>= 3, < 8) + redis-store (>= 1.3, < 2) + redis-rack (2.0.6) + rack (>= 1.5, < 3) + redis-store (>= 1.2, < 2) + redis-rails (5.0.2) + redis-actionpack (>= 5.0, < 6) + redis-activesupport (>= 5.0, < 6) + redis-store (>= 1.2, < 2) redis-session-store (0.11.3) actionpack (>= 3, < 7) redis (>= 3, < 5) + redis-store (1.6.0) + redis (>= 2.2, < 5) representable (3.0.4) declarative (< 0.1.0) declarative-option (< 0.2.0) @@ -687,9 +707,9 @@ GEM railties (>= 4.2.0, < 5.1) retriable (3.0.2) rexml (3.2.5) - roo (2.3.2) + roo (2.8.3) nokogiri (~> 1) - rubyzip (~> 1.1, < 2.0.0) + rubyzip (>= 1.3.0, < 3.0.0) rspec (3.9.0) rspec-core (~> 3.9.0) rspec-expectations (~> 3.9.0) @@ -731,9 +751,11 @@ GEM ruby-progressbar (1.11.0) ruby_parser (3.14.2) sexp_processor (~> 4.9) - rubyzip (1.2.0) + rubyzip (1.3.0) s3 (0.3.24) proxies (~> 0.2.0) + safely_block (0.2.2) + errbase (>= 0.1.1) sanitize (5.2.1) crass (~> 1.0.2) nokogiri (>= 1.8.0) @@ -880,7 +902,9 @@ PLATFORMS DEPENDENCIES active_model_serializers active_record_doctor (~> 1.8) + active_record_query_trace (= 1.7) acts_as_paranoid (~> 0.6.1) + ahoy_email (= 1.0.3) ancestry (~> 3.0, >= 3.0.5) apartment (~> 1.2) appsignal (~> 3.0, >= 3.0.24) @@ -891,13 +915,14 @@ DEPENDENCIES bourbon (~> 4.2) browser (~> 2.1) bullet (= 5.4.3) + bundler (= 1.17.3) cancancan (~> 1.13, >= 1.13.1) capistrano (= 3.9.0) capistrano-foreman capistrano-passenger (~> 0.1.1) capistrano-rails (~> 1.1.1) capistrano-rvm (~> 0.1.2) - capistrano-sidekiq (~> 1.0, >= 1.0.3) + capistrano-sidekiq-systemd capybara (~> 2.15.4) carrierwave (~> 1.3.2) caxlsx (~> 2.0, >= 2.0.2) @@ -907,7 +932,7 @@ DEPENDENCIES dalli (~> 2.7, >= 2.7.11) danger (~> 5.16, >= 5.16.1) database_cleaner (~> 1.5, >= 1.5.1) - datagrid (~> 1.4.2) + datagrid (= 1.6.3) devise (~> 3.5, >= 3.5.2) devise_token_auth (~> 0.1.37) doorkeeper (~> 4.4, >= 4.4.3) @@ -960,12 +985,14 @@ DEPENDENCIES rails (= 4.2.5) rails-erd react-rails (~> 2.6.0) + redis-rails (~> 5.0) redis-session-store (~> 0.11.3) - roo (~> 2.2) + roo (~> 2.8.3) rspec-activemodel-mocks (~> 1.1) rspec-rails (~> 4.0.0) rspec-sidekiq (~> 3.0, >= 3.0.3) rubocop (~> 0.81.0) + ruby-ole (~> 1.2, >= 1.2.12.2) s3 sass-rails (~> 5.0) select2-rails (~> 3.5.9.3) diff --git a/README.md b/README.md index 6c356ee380..3dc897f665 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,68 @@ # OSCaR - Open Source Case-management and Record-keeping - +### Open Source Case-management and Record-keeping. + +[![Build Status](https://travis-ci.com/DevZep/oscar-web.svg?branch=master)](https://travis-ci.com/DevZep/oscar-web) +[![Build Status](https://travis-ci.com/DevZep/oscar-web.svg?branch=stable)](https://travis-ci.com/DevZep/oscar-web) +[![Build Status](https://travis-ci.com/DevZep/oscar-web.svg?branch=staging)](https://travis-ci.com/DevZep/oscar-web) + +### Requirements + +- Docker Desktop (latest stable version for your platform) + +### Getting Started + +Given that we are using Docker, then most common development tasks you will just need the _core services_ which are essentially the OSCaR App Service (Rails) and the OSCaR Database Service (Postgres). To spin these services up only, use the following `make` command: + +``` +make start_core +``` + +This starts a Rails, Postgres and Webpack container. If you need the Mongo container running then execute the following command in a separate terminal: + +``` +make start_mongo +``` + +See the project [Makefile](./Makefile) for a list of all the available commands. + +Once the containers have fired up open a web browser and navigate to [http://localhost:3000](http://localhost:3000) to open the app. To login, click on the 'dev' organizations logo (there should only be the one logo) and the username (email) is any of the users (listed in the 'users' sheet) of the [lib/devdata/dev_tenant.xlsx](lib/devdata/dev_tenant.xlsx) spreadsheet with the password set to `123456789`. + +_NOTE_ If this is the first time you have run this you may need to stop the containers and run it again! + +## Debugging using Pry + +If you want to debug the Rails application using Pry you need to attach to the container running Rails first. To do that in a new terminal window run: + +``` +make rails_attach +``` + +Now when your code runs and gets to the `binding.pry` line it will halt and a Pry REPL session will be available in the terminal window where you are attached. + +When you have finished dubugging just type `exit` in the Pry REPL session as you normally would. Keep this terminal attached for convenience if you need to use Pry again. + +NOTE: To detach the tty **without also terminating the Rails container**, you need to use the escape sequence **Ctrl+P** followed by **Ctrl+Q**. + +## Troubleshooting + +#### Issue pending migrations when starting Docker container + +If you have pending migrations that **prevent the Docker container from starting** for example: + +``` +app | You have 2 pending migrations: +app | 20200603071312 ________ +app | 20200603081325 ________ +app | Run `rake db:migrate` to update your database then try again. +app exited with code 1 +``` + +Then you can fix this by running the following command and then starting services again. + +``` +make db_migrate +``` | Master Branch | Stable Branch | Staging Branch | | ------------------------------------------------------------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------: | diff --git a/_options b/_options deleted file mode 100644 index cdc0a7ab46..0000000000 --- a/_options +++ /dev/null @@ -1,71 +0,0 @@ -=> ["given_name", - "family_name", - "local_given_name", - "local_family_name", - "family", - "slug", - "school_name", - "other_info_of_exit", - "exit_note", - "main_school_contact", - "what3words", - "kid_id", - "code", - "client_contact_phone", - "client_email_address", - "house_number", - "street_number", - "referee_name", - "referee_phone", - "referee_email", - "carer_name", - "carer_phone", - "carer_email", - "location_of_concern", - "created_by", - "gender", - "status", - "agency_name", - "received_by_id", - "referral_source_id", - "followed_up_by_id", - "has_been_in_government_care", - "has_overdue_assessment", - "has_overdue_forms", - "has_overdue_task", - "no_case_note", - "has_been_in_orphanage", - "user_id", - "donor_name", - "active_program_stream", - "enrolled_program_stream", - "case_note_type", - "exit_reasons", - "exit_circumstance", - "rated_for_id_poor", - "province_id", - "district_id", - "birth_province_id", - "commune_id", - "village_id", - "referred_to", - "referred_from", - "referral_source_category_id", - "type_of_service", - "referee_relationship", - "address_type", - "phone_owner", - "family_id", - "age", - "time_in_cps", - "time_in_ngo", - "date_of_birth", - "initial_referral_date", - "follow_up_date", - "exit_date", - "accepted_date", - "case_note_date", - "created_at", - "date_of_referral", - "active_clients", - "care_plan_completed_date"] diff --git a/app/assets/images/chat_error.png b/app/assets/images/chat_error.png new file mode 100644 index 0000000000..84711902da Binary files /dev/null and b/app/assets/images/chat_error.png differ diff --git a/app/assets/images/error_page_not_found.png b/app/assets/images/error_page_not_found.png new file mode 100644 index 0000000000..89ea27bfa9 Binary files /dev/null and b/app/assets/images/error_page_not_found.png differ diff --git a/app/assets/images/header_icon.png b/app/assets/images/header_icon.png new file mode 100644 index 0000000000..1892e78562 Binary files /dev/null and b/app/assets/images/header_icon.png differ diff --git a/app/assets/images/indonesia.png b/app/assets/images/indonesia.png new file mode 100644 index 0000000000..dc848ced92 Binary files /dev/null and b/app/assets/images/indonesia.png differ diff --git a/app/assets/javascripts/advanced_filter_builder.coffee b/app/assets/javascripts/advanced_filter_builder.coffee index 131937fe6e..85f8c334b1 100644 --- a/app/assets/javascripts/advanced_filter_builder.coffee +++ b/app/assets/javascripts/advanced_filter_builder.coffee @@ -132,7 +132,7 @@ class CIF.AdvancedFilterBuilder rules = $("a[data-save-search-#{advancedSearchId}]").data("save-search-#{advancedSearchId}") $('button.client-advance-search').click() self.handleAddHotlineFilter() - $('.program-stream-column li.visibility, .hotline-call-column li.visibility').each -> + $('.program-stream-column li.visibility, .hotline-call-column li.visibility, .assessment-column li.visibility').each -> fieldCheckedBoxValue = $($(this).find('input')[0]).val() values = self.getSaveSearchFields(rules.rules) $($(this).find('input')[0]).iCheck('check') if values.includes(fieldCheckedBoxValue) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index b517172cd4..338596880c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -133,6 +133,7 @@ //= require prevent_required_file_uploader //= require format_special_characters //= require referrals/form +//= require referrals/show //= require government_forms/form //= require multiple_form/form //= require registrations/form @@ -150,3 +151,4 @@ //= require internal_referrals/form //= require service_receives/form //= require screening_assessments/form +//= require custom_data/form diff --git a/app/assets/javascripts/application_with_pack.js b/app/assets/javascripts/application_with_pack.js index 9b3f02faae..1e7f19d205 100644 --- a/app/assets/javascripts/application_with_pack.js +++ b/app/assets/javascripts/application_with_pack.js @@ -58,5 +58,4 @@ //= require clients/index //= require report_creator //= require clients/show -//= require clients/form //= require clients/book diff --git a/app/assets/javascripts/assessments/form.coffee b/app/assets/javascripts/assessments/form.coffee index 7c8bfad766..b32f5f9843 100644 --- a/app/assets/javascripts/assessments/form.coffee +++ b/app/assets/javascripts/assessments/form.coffee @@ -14,6 +14,24 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen _saveAssessment(form) _initICheckBox() + $("#assessment_assessment_date").on "change", _submitFormViaAjax + + saveTimer = null + $(".assessment_assessment_domains_reason textarea").on "keyup", -> + clearTimeout saveTimer + saveTimer = setTimeout _submitFormViaAjax, 1000 + + _submitFormViaAjax = -> + if $("form.assessment-form").data("autosave") + $.ajax + url: $("form.assessment-form").attr("action") + "&draft=true" + type: "PUT" + data: $("form.assessment-form").serialize() + dataType: "json" + success: (response) -> + if response.edit_url + history.replaceState(null, "", response.edit_url) + _initICheckBox = -> $('.i-checks').iCheck checkboxClass: 'icheckbox_square-green' @@ -82,9 +100,13 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen scoreColor = $(@).parents('.score_option').data("score-#{score}") domainId = $(@).parents('.score_option').data("domain-id") + $('.score_option input').removeClass('error') + $('.score_option em').remove() $(@).addClass("btn-secondary") $($(@).siblings().get(-1)).val(score) + _submitFormViaAjax() + $('.score_option input').attr('required','required') $('.col-xs-12').on 'click', '.score_option label', -> @@ -147,7 +169,8 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen return onStepChanging: (event, currentIndex, newIndex) -> - console.log 'onStepChanging' + return true if newIndex < currentIndex + currentTab = "#{rootId}-p-#{currentIndex}" domainId = $("#{currentTab}").find('.score_option').data('domain-id') @@ -160,7 +183,6 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen _filedsValidator(currentIndex, newIndex) onStepChanged: (event, currentIndex, priorIndex) -> - console.log 'onStepChanged' currentTab = "#{rootId}-p-#{currentIndex}" domainId = $("#{currentTab}").find('.score_option').data('domain-id') currentStep = $("#{rootId}-p-" + currentIndex) @@ -181,7 +203,6 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen form.validate().settings.ignore = ':disabled' form.valid() - _filedsValidator(currentIndex, newIndex) onFinished: -> @@ -302,12 +323,20 @@ CIF.AssessmentsNew = CIF.AssessmentsEdit = CIF.AssessmentsCreate = CIF.Assessmen $("#{task} .task_name_help, #{task} .task_completion_date_help").hide() _initUploader = -> - $('.file .optional').fileinput - showUpload: false - removeClass: 'btn btn-danger btn-outline' - browseLabel: 'Browse' - theme: "explorer" - allowedFileExtensions: ['jpg', 'png', 'jpeg', 'doc', 'docx', 'xls', 'xlsx', 'pdf'] + $fileInputs = $('.file .optional') + + $.each $fileInputs, (index, fileInput) -> + $(fileInput).fileinput + uploadAsync: false + removeClass: 'btn btn-danger btn-outline' + browseLabel: 'Browse' + theme: "explorer" + allowedFileExtensions: ['jpg', 'png', 'jpeg', 'doc', 'docx', 'xls', 'xlsx', 'pdf'] + uploadUrl: $(fileInput).closest(".assessment-domain-item").data("uploadAttachmentUrl") + + $(fileInput).on "filebatchselected", (event, files) -> + $(this).fileinput("upload") + return _handleDeleteAttachment = -> rows = $('.row-file') diff --git a/app/assets/javascripts/care_plans/form.coffee b/app/assets/javascripts/care_plans/form.coffee index a8d809b705..4301683ae4 100644 --- a/app/assets/javascripts/care_plans/form.coffee +++ b/app/assets/javascripts/care_plans/form.coffee @@ -1,6 +1,6 @@ CIF.Care_plansNew = CIF.Care_plansEdit = CIF.Care_plansCreate = CIF.Care_plansUpdate = do -> _init = -> - forms = $('form.care_plan-form') + forms = $('form.care_plan-form, #previous-care-plan' ) for form in forms _loadSteps($(form)) @@ -99,9 +99,8 @@ CIF.Care_plansNew = CIF.Care_plansEdit = CIF.Care_plansCreate = CIF.Care_plansUp form.submit() _disableRequiredFields = -> - formid = $('form.care_plan-form').attr('id') - form = $('#'+formid) - form.data("disableRequiredFields") + form = $('#previous-care-plan') + form.data("disable-required-fields") _taskRequiredField = (currentTab) -> $("#{currentTab}").find('.task-input-field')[0] && $("#{currentTab}").find('.task-input-field')[0].value diff --git a/app/assets/javascripts/case_notes/form.coffee b/app/assets/javascripts/case_notes/form.coffee index d6a912ab45..d3027a2770 100644 --- a/app/assets/javascripts/case_notes/form.coffee +++ b/app/assets/javascripts/case_notes/form.coffee @@ -16,6 +16,38 @@ CIF.Case_notesNew = CIF.Case_notesCreate = CIF.Case_notesEdit = CIF.Case_notesUp _taskProgressNoteToggle() _initTaskProgressNoteTooltip() + + $("#case_note_meeting_date").on "change", _submitFormViaAjax + $("#case_note_interaction_type").on "change", _submitFormViaAjax + $("#case_note_domain_group_ids").on "change", -> + _submitFormViaAjax() + + saveTimer = null + + $("#case_note_attendee").on "keyup", -> + clearTimeout saveTimer + saveTimer = setTimeout _submitFormViaAjax, 1000 + + $("#case_note_note").on "keyup", -> + clearTimeout saveTimer + saveTimer = setTimeout _submitFormViaAjax, 1000 + + _submitFormViaAjax = -> + if $("#case-note-form").data("autosave") + $(".task-arising.task-item-wrapper").addClass("saved") + + $.ajax + url: $("#case-note-form").attr("action") + "&draft=true" + type: "PUT" + data: $("#case-note-form").serialize() + dataType: "json" + success: (response) -> + if response.edit_url + history.replaceState(null, "", response.edit_url) + + $.each $(".task-arising.task-item-wrapper.saved"), (index, element) -> + $(element).find("input[name='task[]']").remove() + _initICheckBox = -> $('.i-checks').iCheck( checkboxClass: 'icheckbox_square-green' @@ -83,11 +115,17 @@ CIF.Case_notesNew = CIF.Case_notesCreate = CIF.Case_notesEdit = CIF.Case_notesUp _initUploader = -> $('.file .optional').fileinput - showUpload: false removeClass: 'btn btn-danger btn-outline' browseLabel: 'Browse' theme: "explorer" + uploadAsync: false allowedFileExtensions: ['jpg', 'png', 'jpeg', 'doc', 'docx', 'xls', 'xlsx', 'pdf'] + uploadUrl: $("#case-note-form").data("uploadUrl") + + $('.file .optional').on "filebatchselected", (event, files) -> + $(this).fileinput("upload") + return + _handleDeleteAttachment = -> rows = $('.row-file') @@ -157,6 +195,7 @@ CIF.Case_notesNew = CIF.Case_notesCreate = CIF.Case_notesEdit = CIF.Case_notesUp $('#tasksFromModal').modal('hide') _hideShowOnGoingTaskLable() _hideAddNewTask() + _submitFormViaAjax() else _showError(taskName, taskDate) $('.add-task-btn').removeAttr('disabled') @@ -178,7 +217,7 @@ CIF.Case_notesNew = CIF.Case_notesCreate = CIF.Case_notesEdit = CIF.Case_notesUp if $(".task-domain-#{domainId}").hasClass('hidden') $(".task-domain-#{domainId}").removeClass('hidden') - $("#tasks-domain-#{domainId} .task-arising").removeClass('hidden') + $("#tasks-domain-#{domainId} .task-arising").removeClass('hidden').addClass("task-item-wrapper") $("#tasks-domain-#{domainId} .task-arising ol").append(element) $(".panel-tasks-domain-#{domainId}").removeClass('hidden') @@ -295,7 +334,8 @@ CIF.Case_notesNew = CIF.Case_notesCreate = CIF.Case_notesEdit = CIF.Case_notesUp _hideAddNewTask = -> _checkCasenoteSelectedValue($('#case_note_domain_group_ids')) $.each $('#case_note_domain_group_ids').select2('data'), (index, object) -> - $("#domain-#{object.id}").show() if $("#domain-#{object.id} .task-arising .list-group > li").length > 0 + if $("#domain-#{object.id} .task-arising .list-group > li").length > 0 || $("#domain-#{object.id} input[data-task-id]").length > 0 + $("#domain-#{object.id}").show() $.each $('.case-note-domain-group'), (index, object)-> if $("##{object.id}").find('span.checkbox').length > 0 diff --git a/app/assets/javascripts/client_advance_search.coffee b/app/assets/javascripts/client_advance_search.coffee index 429f566e5d..471df34d7b 100644 --- a/app/assets/javascripts/client_advance_search.coffee +++ b/app/assets/javascripts/client_advance_search.coffee @@ -95,8 +95,10 @@ class CIF.ClientAdvanceSearch initSelect2: -> - $('#custom-form-select, #wizard-custom-form-select, #program-stream-select, #wizard-program-stream-select, #quantitative-case-select, #assessment-select').select2() + $('#custom-form-select, #wizard-custom-form-select, #program-stream-select, #wizard-program-stream-select, #quantitative-case-select').select2() $('#builder select').select2() + $('#assessment-select').select2() + $('#wizard-builder select').select2() setTimeout ( -> ids = ['#custom-form-select', '#wizard-custom-form-select', '#program-stream-select', '#wizard-program-stream-select', '#quantitative-case-select', '#wizard-builder', '#builder', '#assessment-select'] @@ -116,6 +118,57 @@ class CIF.ClientAdvanceSearch $(".csi-group .rule-operator-container select, .rule-value-container select").select2(width: 'resolve') ) + self = @ + + $('#assessment-select').on 'change', (e)-> + $(".assessment-data-dropdown li").addClass("hide") + self.showAssessmentColumns("") + + value = $('#assessment-select').select2('data') && $('#assessment-select').select2('data').id + $(".assessment-data-dropdown li.csi-#{value}").removeClass("hide") + $("input[id$='_advanced_search_assessment_selected']").val("[#{value}]") + + self.showAssessmentColumns($('#assessment-select option:selected').data("selectGroup")) + + unless $("#assessment-checkbox").is(":checked") + $(".assessment-data-dropdown li").addClass("hide") + $("input[id$='_advanced_search_assessment_selected']").val("[]") + self.showAssessmentColumns("") + + $('#assessment-select').trigger('change') + + showAssessmentColumns: (sectionText) -> + self = @ + + # Toggle domain score fields + $.each $('#assessment-select option'), (index, item) -> + $options = $("optgroup[label='#{$(item).data("selectGroup")}'] option") + + if $(item).data("selectGroup") == sectionText + $options.attr("disabled", false) + else + $options.attr("disabled", "disabled") + + # Toggle custom assessment fields + $options = $("optgroup[label='Custom Assessment'] option") + + if sectionText != undefined && sectionText.indexOf(" | ") > -1 + $options.attr("disabled", false) + else + $options.attr("disabled", "disabled") + + $('#builder select').select2(width: '250px') + + $('#builder select').on 'select2-open', (e)-> + setTimeout ( -> + self.hideDisabledGroup() + ), 50 + + + hideDisabledGroup: -> + $(".select2-result-with-children").each -> + $(@).hide() if $(@).find(".select2-disabled").length > 0 + basicFilterSetRule: -> self = @ basicQueryRules = $('#builder').data('basic-search-rules') @@ -153,8 +206,13 @@ class CIF.ClientAdvanceSearch assessmentSelectChange: -> self = @ + assessmentSelectValue = $('#assessment-select').find(':selected').val() + $("div[data-custom-assessment-setting-id='#{assessmentSelectValue}']").show() if $("#assessment-checkbox").is(":checked") + $('.main-report-builder .assessment-form-wrapper select').on 'select2-selecting', (element) -> - self.assessmentSelected = element.val + $(".custom-assessment-setting").hide() + $(".custom-assessment-setting input[type='checkbox']").iCheck("uncheck") + $("div[data-custom-assessment-setting-id='#{element.val}']").show() addCustomBuildersFields: (ids, url, loader=undefined) -> self = @ @@ -246,19 +304,31 @@ class CIF.ClientAdvanceSearch ruleFiltersSelect = $('.main-report-builder .rule-container .rule-filter-container select') ruleFiltersSelect.select2('destroy') ruleFiltersSelect.parents('.rule-container').find('.rule-header button').trigger('click') - self.assessmentSelected = '' + + $(".custom-assessment-setting input[type='checkbox']").iCheck("uncheck") + $('.assessment-column a.dropdown-toggle').addClass('disabled') + + $(".custom-assessment-setting").hide() + $('.assessment-form').hide() $('#builder').queryBuilder('removeFilter', ['assessment_condition_last_two','assessment_condition_first_last']) $('button[data-add="rule"]').trigger('click') - self.initSelect2() + return handleShowAssessmentSelect: -> self = @ if $('#assessment-checkbox').prop('checked') $('.assessment-form').show() + $('#assessment-checkbox').on 'ifChecked', -> $('.assessment-form').show() + assessmentSelectValue = $('#assessment-select').find(':selected').val() + + $('.assessment-column a.dropdown-toggle').removeClass('disabled') + # self.initSelect2() + + $("div[data-custom-assessment-setting-id='#{assessmentSelectValue}']").show() self.assessmentSelected = $('select.assessment-select').val() $.ajax url: self.PROGRAM_STREAM_URL @@ -300,6 +370,7 @@ class CIF.ClientAdvanceSearch assessmentSelectRemove: -> self = @ $('.main-report-builder .assessment-form-wrapper select').on 'select2-removed', (element) -> + $(".custom-assessment-setting").hide() $.map self.assessmentSelected, (val, i) -> if parseInt(val) == parseInt(element.val) then self.assessmentSelected.splice(i, 1) @@ -735,7 +806,7 @@ class CIF.ClientAdvanceSearch programStreamAssociation = $('.main-report-builder .program-association') $(programStreamAssociation).find('.i-checks').iCheck('uncheck') $(programStreamAssociation).hide() - + if self.programSelected.length == 0 self.removeActiveClientProgramOption() @@ -858,63 +929,87 @@ class CIF.ClientAdvanceSearch return ###################################################################################################################### + prepareSearchParams: (btnID) -> + self = @ + + if btnID == 'search' + builderElement = '#builder' + builderForm = '.main-report-builder' + programValues = if self.programSelected.length > 0 then "[#{self.programSelected}]" + customFormValues = if self.customFormSelected.length > 0 then "[#{self.customFormSelected}]" + else + builderElement = '#wizard-builder' + builderForm = '#report-builder-wizard' + programValues = if self.wizardProgramSelected.length > 0 then "[#{self.wizardProgramSelected}]" + customFormValues = if self.wizardCustomFormSelected.length > 0 then "[#{self.wizardCustomFormSelected}]" + + basicRules = $(builderElement).queryBuilder('getRules', { skip_empty: true, allow_invalid: true }) + + if $('#builder').queryBuilder('getSQL', false, true) + sql_sting = $('#builder').queryBuilder('getSQL', false, true).sql + $('#raw_sql').val(sql_sting) + + self.setValueToProgramAssociation() + $('#client_advanced_search_custom_form_selected').val(customFormValues) + $('#client_advanced_search_program_selected').val(programValues) + + if $('#quantitative-type-checkbox').prop('checked') then $('#client_advanced_search_quantitative_check').val(1) + if $('#wizard_quantitative_filter').prop('checked') then $('#client_advanced_search_wizard_quantitative_check').val(1) + if $('#wizard_custom_form_filter').prop('checked') then $('#client_advanced_search_wizard_custom_form_check').val(1) + if $('#wizard_program_stream_filter').prop('checked') then $('#client_advanced_search_wizard_program_stream_check').val(1) + if $('#wizard-enrollment-checkbox').prop('checked') then $('#client_advanced_search_wizard_enrollment_check').val(1) + if $('#wizard-tracking-checkbox').prop('checked') then $('#client_advanced_search_wizard_tracking_check').val(1) + if $('#wizard-exit-form-checkbox').prop('checked') then $('#client_advanced_search_wizard_exit_form_check').val(1) + $('#client_advanced_search_action_report_builder, #family_advanced_search_action_report_builder').val(builderElement) + + if (_.isEmpty(basicRules.rules) and !basicRules.valid) or (!(_.isEmpty(basicRules.rules)) and basicRules.valid) + $(builderElement).find('.has-error').removeClass('has-error') + $('#client_advanced_search_basic_rules').val(self.handleStringfyRules(basicRules)) + + true + else + false + handleSearch: -> self = @ $('#search, #wizard-search').on 'click', (e)-> btnID = e.currentTarget.id + if btnID == 'search' - builderElement = '#builder' builderForm = '.main-report-builder' - programValues = if self.programSelected.length > 0 then "[#{self.programSelected}]" - customFormValues = if self.customFormSelected.length > 0 then "[#{self.customFormSelected}]" - assessmentValues = if self.assessmentSelected.length > 0 then "[#{self.assessmentSelected}]" else - builderElement = '#wizard-builder' builderForm = '#report-builder-wizard' - programValues = if self.wizardProgramSelected.length > 0 then "[#{self.wizardProgramSelected}]" - customFormValues = if self.wizardCustomFormSelected.length > 0 then "[#{self.wizardCustomFormSelected}]" - - basicRules = $(builderElement).queryBuilder('getRules', { skip_empty: true, allow_invalid: true }) - - if $('#builder').queryBuilder('getSQL', false, true) - sql_sting = $('#builder').queryBuilder('getSQL', false, true).sql - $('#raw_sql').val(sql_sting) - - self.setValueToProgramAssociation() - $('#client_advanced_search_custom_form_selected').val(customFormValues) - $('#client_advanced_search_program_selected').val(programValues) - $('#client_advanced_search_assessment_selected').val(assessmentValues) - if $('#quantitative-type-checkbox').prop('checked') then $('#client_advanced_search_quantitative_check').val(1) - if $('#wizard_quantitative_filter').prop('checked') then $('#client_advanced_search_wizard_quantitative_check').val(1) - if $('#wizard_custom_form_filter').prop('checked') then $('#client_advanced_search_wizard_custom_form_check').val(1) - if $('#wizard_program_stream_filter').prop('checked') then $('#client_advanced_search_wizard_program_stream_check').val(1) - if $('#wizard-enrollment-checkbox').prop('checked') then $('#client_advanced_search_wizard_enrollment_check').val(1) - if $('#wizard-tracking-checkbox').prop('checked') then $('#client_advanced_search_wizard_tracking_check').val(1) - if $('#wizard-exit-form-checkbox').prop('checked') then $('#client_advanced_search_wizard_exit_form_check').val(1) - $('#client_advanced_search_action_report_builder, #family_advanced_search_action_report_builder').val(builderElement) - if (_.isEmpty(basicRules.rules) and !basicRules.valid) or (!(_.isEmpty(basicRules.rules)) and basicRules.valid) - $(builderElement).find('.has-error').removeClass('has-error') - $('#client_advanced_search_basic_rules').val(self.handleStringfyRules(basicRules)) + if self.prepareSearchParams(btnID) self.handleSelectFieldVisibilityCheckBox(builderForm) $('#advanced-search').submit() - handleFamilySearch: -> + + prepareFamilySearch: -> self = @ - $('#search').on 'click', -> - basicRules = $('#builder').queryBuilder('getRules', { skip_empty: true, allow_invalid: true }) + basicRules = $('#builder').queryBuilder('getRules', { skip_empty: true, allow_invalid: true }) # customFormValues = "[#{$('#family-advance-search-form').find('#custom-form-select').select2('val')}]" - customFormValues = if self.customFormSelected.length > 0 then "[#{self.customFormSelected}]" - programValues = if self.programSelected.length > 0 then "[#{self.programSelected}]" + customFormValues = if self.customFormSelected.length > 0 then "[#{self.customFormSelected}]" + programValues = if self.programSelected.length > 0 then "[#{self.programSelected}]" + + self.setValueToFamilyProgramAssociation() + $('#family_advanced_search_custom_form_selected').val(customFormValues) + $('#family_advanced_search_program_selected').val(programValues) + if $('#quantitative-type-checkbox').prop('checked') then $('#family_advanced_search_quantitative_check').val(1) + + if (_.isEmpty(basicRules.rules) and !basicRules.valid) or (!(_.isEmpty(basicRules.rules)) and basicRules.valid) + $('#builder').find('.has-error').removeClass('has-error') + console.log(self.handleStringfyRules(basicRules)) + $('#family_advanced_search_basic_rules').val(self.handleStringfyRules(basicRules)) + return true + else + return false - self.setValueToFamilyProgramAssociation() - $('#family_advanced_search_custom_form_selected').val(customFormValues) - $('#family_advanced_search_program_selected').val(programValues) - if $('#quantitative-type-checkbox').prop('checked') then $('#family_advanced_search_quantitative_check').val(1) + handleFamilySearch: -> + self = @ - if (_.isEmpty(basicRules.rules) and !basicRules.valid) or (!(_.isEmpty(basicRules.rules)) and basicRules.valid) - $('#builder').find('.has-error').removeClass('has-error') - $('#family_advanced_search_basic_rules').val(self.handleStringfyRules(basicRules)) + $('#search').on 'click', -> + if self.prepareFamilySearch() self.handleSelectFieldVisibilityCheckBox() $('#advanced-search').submit() diff --git a/app/assets/javascripts/clients/index.coffee b/app/assets/javascripts/clients/index.coffee index 8893923be4..f94cd92d4a 100644 --- a/app/assets/javascripts/clients/index.coffee +++ b/app/assets/javascripts/clients/index.coffee @@ -1,4 +1,4 @@ -CIF.ClientsIndex = do -> +CIF.ClientsIndex = CIF.ClientsWelcome = do -> _init = -> window.customGroup = {} content = $('#content').val() @@ -57,8 +57,9 @@ CIF.ClientsIndex = do -> _reloadFilter() _addTourTip(tour) _extendDataTableSort() + _loadStatisticsData() + _loadClientTableSummary() _addDataTableToAssessmentScoreData() - _addDataTableToTableSummary() _removeReferralDataColumnsInWizardClientColumn() _handleShowCustomFormSelect() _reOrderRuleContainer() @@ -66,22 +67,24 @@ CIF.ClientsIndex = do -> _initClientColumnFilter() _initClientColumnFilter = -> - searchBox = $('.client-column ul.columns-visibility #column-search-box') + searchBox = $('ul.columns-visibility .column-search-box') searchBox.keyup -> valThis = $(this).val().toLowerCase() + if valThis == '' - $('.client-column ul.columns-visibility > li').show() + $('ul.columns-visibility li').show() else - $('.client-column ul.columns-visibility > li:not(:first-child)').each -> - text = $(this).text().toLowerCase() + $('ul.columns-visibility li:not(:first-child)').each -> + text = $(this).find("label").text().toLowerCase().trim() + if text.indexOf(valThis) >= 0 then $(this).show() else $(this).hide() return return - $('.client-column ul.columns-visibility .btn-clear-text').click -> + $('ul.columns-visibility .btn-clear-text').click -> searchBox.val '' searchBox.focus() - $('.client-column ul.columns-visibility > li').show() + $('ul.columns-visibility li').show() return _reOrderRuleContainer = -> @@ -112,10 +115,56 @@ CIF.ClientsIndex = do -> 'formatted-num-desc': (a, b) -> b - a + _loadClientTableSummary = -> + if $("#client-table-summary-tab-content").length > 0 + advanceFilter = new CIF.ClientAdvanceSearch() + advanceFilter.prepareSearchParams("search") + + $.ajax + type: 'POST' + dataType: 'json' + url: "/clients/load_client_table_summary" + data: + cache_key: $("#cache-key").data("cacheKey") + basic_rules: $("#client_advanced_search_basic_rules").val() + success: (data) -> + $("#client-table-summary-tab-content").html(data.client_table_content) + _addDataTableToTableSummary() + + _loadStatisticsData = -> + if $("#program-statistic.searched").length > 0 + advanceFilter = new CIF.ClientAdvanceSearch() + advanceFilter.prepareSearchParams("search") + + $.ajax + type: 'POST' + dataType: 'json' + url: "/clients/load_statistics_data" + data: + cache_key: $("#cache-key").data("cacheKey") + basic_rules: $("#client_advanced_search_basic_rules").val() + success: (data) -> + $('#cis-domain-score').data 'csi-domain', data.csi_statistics + $('#program-statistic').data 'program-statistic', data.enrollments_statistics + + _handleCreateCsiDomainReport() + _handleCreateCaseReport() + _addDataTableToAssessmentScoreData = -> - fileName = $('.assessment-domain-score').data('filename') - _handleAjaxRequestToAssessment("#csi-assessment-score", fileName) if $("#csi-assessment-score").length - _handleAjaxRequestToAssessment("#custom-assessment-score", fileName) if $("#custom-assessment-score").length + if $("body#clients-welcome").length > 0 || $("body#families-welcome").length > 0 || !$("#assessment-checkbox").is(":checked") + return + + advanceFilter = new CIF.ClientAdvanceSearch() + advanceFilter.prepareSearchParams("search") + + _handleAjaxRequestToAssessment("#csi-assessment-score", $("#assessment-domain-score").data("filename")) + + $('#assessment-select option').each -> + $option = $(this) + + if $option.val() && $option.val() != 0 + _handleAjaxRequestToAssessment("#custom-assessment-score-#{$option.val()}", $("#custom-assessment-domain-score-#{$option.val()}").data("filename"), true) + $('.assessment-domain-score').on 'shown.bs.modal', (e) -> $($.fn.dataTable.tables(true)).DataTable().columns.adjust() return @@ -124,6 +173,8 @@ CIF.ClientsIndex = do -> fileName = $('.table-summary').data('filename') _handleDataTable("#table-summary-age", fileName) _handleDataTable("#table-summary-referral-category", fileName) + _handleDataTable("#table-summary-school", fileName) + _handleDataTable("#table-summary-location", fileName) $('.table-summary').on 'shown.bs.modal', (e) -> $($.fn.dataTable.tables(true)).DataTable().columns.adjust() return @@ -140,6 +191,9 @@ CIF.ClientsIndex = do -> sServerMethod: 'POST' ajax: url: url + data: + cache_key: $("#cache-key").data("cacheKey") + basic_rules: $("#client_advanced_search_basic_rules").val() error: (jqXHR, textStatus, errorThrown) -> console.log("Datatable Ajax Error:", errorThrown) oLanguage: { @@ -462,10 +516,10 @@ CIF.ClientsIndex = do -> $("button[data-target='#client-search-form']").trigger('click') _hideClientFilters = -> - dataFilters = $('#client-search-form .datagrid-filter') - displayColumns = '#client_grid_given_name, #client_grid_family_name, #client_grid_gender, #client_grid_slug, #client_grid_status, #client_grid_user_id' - $(dataFilters).hide() - $(dataFilters).children("#{displayColumns}").parents('.datagrid-filter').show() + # dataFilters = $('#client-search-form .datagrid-filter') + # displayColumns = '#client_grid_given_name, #client_grid_family_name, #client_grid_gender, #client_grid_slug, #client_grid_status, #client_grid_user_id' + # $(dataFilters).hide() + # $(dataFilters).children("#{displayColumns}").parents('.datagrid-filter').show() _toggleCollapseFilter = (tour) -> $('#client-search-form').on 'show.bs.collapse', -> @@ -488,6 +542,8 @@ CIF.ClientsIndex = do -> _hideClientFilters() _initAdavanceSearchFilter = -> + return unless $('#client-builder-fields').length > 0 + advanceFilter = new CIF.ClientAdvanceSearch() advanceFilter.initBuilderFilter('#client-builder-fields') advanceFilter.setValueToBuilderSelected() @@ -594,7 +650,7 @@ CIF.ClientsIndex = do -> report.lineChart() _enableSelect2 = -> - $('#clients-index select').select2 + $('select').select2 minimumInputLength: 0, allowClear: true @@ -611,8 +667,6 @@ CIF.ClientsIndex = do -> $('#client-statistic').click -> paramsAdvancedSearch = $('#params').val() if paramsAdvancedSearch != '' - _handleCreateCsiDomainReport() - _handleCreateCaseReport() _toggleCollapseOnOff() else if $('#cis-domain-score').is('[data-csi-domain]') && $('#program-statistic').is('[data-program-statistic]') diff --git a/app/assets/javascripts/clients/show.coffee b/app/assets/javascripts/clients/show.coffee index a50ae67732..e3b88fc81d 100644 --- a/app/assets/javascripts/clients/show.coffee +++ b/app/assets/javascripts/clients/show.coffee @@ -17,7 +17,6 @@ CIF.ClientsShow = do -> _initialEnterNGOAcceptedDate() _handleEnterNGOModalShow() - $('table.families').dataTable 'bPaginate': false 'bFilter': false diff --git a/app/assets/javascripts/common.coffee b/app/assets/javascripts/common.coffee index e00eb9e307..3b226936b0 100644 --- a/app/assets/javascripts/common.coffee +++ b/app/assets/javascripts/common.coffee @@ -13,6 +13,21 @@ CIF.Common = @iCheckClearOptionSelect() @printDiv() + @loadNotification() + @loadSideMenuCountBadge() + + loadNotification: -> + setTimeout (-> + if $('.lazy-load-notification').length > 0 + $.ajax(type: 'GET', url: '/dashboards/notification') + ), 1000 + + loadSideMenuCountBadge: -> + setTimeout (-> + if $('ul#side-menu').length > 0 + $.ajax(type: 'GET', url: '/dashboards/side_menu_data') + ), 1000 + preventEditOnDatePicker: -> $('.date-picker').datepicker autoclose: true, @@ -22,7 +37,7 @@ CIF.Common = startDate: '1899,01,01', orientation: 'bottom', todayBtn: true - .attr('readonly', 'true').css('background-color','#ffffff').keypress (e) -> + .attr('readonly', 'true').attr("autocomplete", "off").css('background-color','#ffffff').keypress (e) -> if e.keyCode == 8 e.preventDefault() return @@ -54,7 +69,8 @@ CIF.Common = $('#manage').trigger('click') if navThirdActive.length > 0 setTimeout (-> - $('#pro-nav').trigger('click') + if $(navThirdActive).closest(".nav-third-level").prev("a") + $(navThirdActive).closest(".nav-third-level").prev("a").trigger('click') ), 400 hideDynamicOperator: -> @@ -163,4 +179,4 @@ CIF.Common = $('.printable-button').on 'click', -> printableId = $(@).data('printable-id') $("##{printableId}").print() - return \ No newline at end of file + return diff --git a/app/assets/javascripts/communities/form.coffee b/app/assets/javascripts/communities/form.coffee index 0dfabd3b2f..6ebea27039 100644 --- a/app/assets/javascripts/communities/form.coffee +++ b/app/assets/javascripts/communities/form.coffee @@ -194,42 +194,25 @@ CIF.CommunitiesNew = CIF.CommunitiesCreate = CIF.CommunitiesEdit = CIF.Communiti $(e.currentTarget).trigger("validate") _ajaxChangeDistrict = -> - mainAddress = $('#community_province_id, #community_district_id, #community_commune_id') + mainAddress = $('#community_province_id, #community_city_id, #community_district_id, #community_commune_id') + resourceMapping = { cities: 'community_city_id', districts: 'community_district_id', subdistricts: 'community_subdistrict_id', communes: 'community_commune_id', villages: 'family_village_id' } mainAddress.on 'change', -> type = $(@).data('type') typeId = $(@).val() - subAddress = $(@).data('subaddress') + subAddresses = $(@).data('subaddresses') + subResource = subAddresses[0] - if type == 'provinces' - subResources = 'districts' - subAddress = switch subAddress - when 'district' then $('#community_district_id') - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() - else if type == 'districts' - subResources = 'communes' - subAddress = switch subAddress - when 'commune' then $('#community_commune_id') - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() - else if type == 'communes' - subResources = 'villages' - subAddress = switch subAddress - when 'village' then $('#community_village_id') - - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() + $(subAddresses || []).each (index, subAddress) => + $("##{resourceMapping[subAddress]}").val(null).trigger('change') + $("##{resourceMapping[subAddress]}").find('option[value!=""]').remove() if typeId != '' $.ajax method: 'GET' - url: "/api/#{type}/#{typeId}/#{subResources}" + url: "/api/#{type}/#{typeId}/#{subResource}" dataType: 'JSON' success: (response) -> for address in response.data - subAddress.append("") + $("##{resourceMapping[subResource]}").append("") { init: _init } diff --git a/app/assets/javascripts/communities/index.coffee b/app/assets/javascripts/communities/index.coffee index 7be98421ff..b83e576dbc 100644 --- a/app/assets/javascripts/communities/index.coffee +++ b/app/assets/javascripts/communities/index.coffee @@ -1,4 +1,4 @@ -CIF.CommunitiesIndex = do -> +CIF.CommunitiesIndex = CIF.CommunitiesWelcome = do -> _init = -> _initSelect2() _initCheckbox() diff --git a/app/assets/javascripts/custom_data/form.coffee b/app/assets/javascripts/custom_data/form.coffee new file mode 100644 index 0000000000..2f59c657c2 --- /dev/null +++ b/app/assets/javascripts/custom_data/form.coffee @@ -0,0 +1,52 @@ +CIF.Custom_dataNew = CIF.Custom_dataCreate = CIF.Custom_dataEdit = CIF.Custom_dataUpdate = do -> + _init = -> + _initFormBuilder() + + _initFormBuilder = -> + builderOption = new CIF.CustomFormBuilder() + specialCharacters = { '&': '&', '<': '<', '>': '>', "&qoute;": '"' } + fields = $('.build-wrap').data('fields') || [] + format = new CIF.FormatSpecialCharacters() + fields = format.formatSpecialCharacters(fields, specialCharacters) + + formBuilder = $('.build-wrap').formBuilder + templates: separateLine: (fieldData) -> + { field: '
' } + fields: builderOption.thematicBreak() + dataType: 'json' + formData: JSON.stringify(fields) + disableFields: ['autocomplete', 'header', 'hidden', 'button', 'checkbox'] + showActionButtons: false + messages: { + cannotBeEmpty: 'name_separated_with_underscore' + } + stickyControls: { + enable: true + offset: + top: 20, + right: 20, + left: 'auto' + } + + typeUserEvents: { + 'checkbox-group': builderOption.eventCheckboxOption() + date: builderOption.eventDateOption() + file: builderOption.eventFileOption() + number: builderOption.eventNumberOption() + 'radio-group': builderOption.eventRadioOption() + select: builderOption.eventSelectOption() + text: builderOption.eventTextFieldOption() + textarea: builderOption.eventTextAreaOption() + separateLine: builderOption.eventSeparateLineOption() + paragraph: builderOption.eventParagraphOption() + } + + $("#custom-data-submit").click (event) -> + labelFields = $('[name="label"].fld-label') + for labelField in labelFields + labelField.textContent = labelField.textContent.replace(/;/g, '') + + fields = format.formatSpecialCharacters(JSON.parse(formBuilder.actions.save()), specialCharacters) + $('#custom_data_fields').val(JSON.stringify(fields)) + + { init: _init } diff --git a/app/assets/javascripts/custom_fields/form.coffee b/app/assets/javascripts/custom_fields/form.coffee index 1e209d0136..900fc21ce1 100644 --- a/app/assets/javascripts/custom_fields/form.coffee +++ b/app/assets/javascripts/custom_fields/form.coffee @@ -180,6 +180,8 @@ CIF.Custom_fieldsNew = CIF.Custom_fieldsCreate = CIF.Custom_fieldsEdit = CIF.Cus $(parent).find('.del-button, .copy-button').remove() if $(parent).attr('class').includes('number-field') + return if $('form.simple_form').includes('is-admin') + $(parent).find('.fld-min, .fld-max').attr('readonly', 'true') else if $(parent).attr('class').includes('select-field') allSelectOption = $('#custom_field .select-field .sortable-options .ui-sortable-handle .option-label') diff --git a/app/assets/javascripts/dashboards/index.coffee b/app/assets/javascripts/dashboards/index.coffee index 305d2310c9..e95fc9be0d 100644 --- a/app/assets/javascripts/dashboards/index.coffee +++ b/app/assets/javascripts/dashboards/index.coffee @@ -10,7 +10,7 @@ CIF.DashboardsIndex = do -> _init = -> # _clientGenderChart() # _clientStatusChart() - _familyType() + loadFamilyTab() _resizeChart() # _clientProgramStreamByGender() _clientProgramStream() @@ -32,6 +32,18 @@ CIF.DashboardsIndex = do -> _search_client_date_logic_error() _familyInActiveProgramStream() + loadFamilyTab = -> + if $('.lazy-load-family-tab').length > 0 + $.ajax + type: 'GET' + url: '/dashboards/family_tab' + dataType: 'JSON' + success: (response) -> + $(".lazy-load-family-tab").html(response.data) + _familyType() + else + _familyType() + _handleFamilyProgramStreamChart() _loadModalReminder = -> if localStorage.getItem('from login') == 'true' @@ -510,7 +522,9 @@ CIF.DashboardsIndex = do -> $('.highcharts-credits').css('display', 'none') _familyInActiveProgramStream = () -> - $(document).on 'shown.bs.tab', 'a[aria-controls="family-tab"]', (e) -> + $(document).on 'shown.bs.tab', 'a[aria-controls="family-tab"]', _handleFamilyProgramStreamChart + + _handleFamilyProgramStreamChart = () -> url = '/api/program_streams/generate_family_program_stream' $.ajax type: 'GET' diff --git a/app/assets/javascripts/families/form.coffee b/app/assets/javascripts/families/form.coffee index e8044527bc..6ffa61ecfd 100644 --- a/app/assets/javascripts/families/form.coffee +++ b/app/assets/javascripts/families/form.coffee @@ -205,42 +205,25 @@ CIF.FamiliesNew = CIF.FamiliesCreate = CIF.FamiliesEdit = CIF.FamiliesUpdate = d $(e.currentTarget).trigger("validate") _ajaxChangeDistrict = -> - mainAddress = $('#family_province_id, #family_district_id, #family_commune_id') + mainAddress = $('#family_province_id, #family_city_id, #family_district_id, #family_commune_id') + resourceMapping = { cities: 'family_city_id', districts: 'family_district_id', subdistricts: 'family_subdistrict_id', communes: 'family_commune_id', villages: 'family_village_id' } mainAddress.on 'change', -> type = $(@).data('type') typeId = $(@).val() - subAddress = $(@).data('subaddress') + subAddresses = $(@).data('subaddresses') + subResource = subAddresses[0] - if type == 'provinces' - subResources = 'districts' - subAddress = switch subAddress - when 'district' then $('#family_district_id') - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() - else if type == 'districts' - subResources = 'communes' - subAddress = switch subAddress - when 'commune' then $('#family_commune_id') - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() - else if type == 'communes' - subResources = 'villages' - subAddress = switch subAddress - when 'village' then $('#family_village_id') - - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() + $(subAddresses || []).each (index, subAddress) => + $("##{resourceMapping[subAddress]}").val(null).trigger('change') + $("##{resourceMapping[subAddress]}").find('option[value!=""]').remove() if typeId != '' $.ajax method: 'GET' - url: "/api/#{type}/#{typeId}/#{subResources}" + url: "/api/#{type}/#{typeId}/#{subResource}" dataType: 'JSON' success: (response) -> for address in response.data - subAddress.append("") + $("##{resourceMapping[subResource]}").append("") { init: _init } diff --git a/app/assets/javascripts/families/index.coffee b/app/assets/javascripts/families/index.coffee index 00acc0391d..870c39d3a3 100644 --- a/app/assets/javascripts/families/index.coffee +++ b/app/assets/javascripts/families/index.coffee @@ -1,4 +1,4 @@ -CIF.FamiliesIndex = do -> +CIF.FamiliesIndex = CIF.FamiliesWelcome = do -> _init = -> _fixedHeaderTableColumns() _handleScrollTable() @@ -15,6 +15,28 @@ CIF.FamiliesIndex = do -> # _setDefaultCheckColumnVisibilityAll() _initCheckbox() _quantitativeCaesByQuantitativeType() + _initColumnFilter() + + _initColumnFilter = -> + searchBox = $('ul.columns-visibility .column-search-box') + searchBox.keyup -> + valThis = $(this).val().toLowerCase() + + if valThis == '' + $('ul.columns-visibility li').show() + else + $('ul.columns-visibility li:not(:first-child)').each -> + text = $(this).find("label").text().toLowerCase().trim() + + if text.indexOf(valThis) >= 0 then $(this).show() else $(this).hide() + return + return + + $('ul.columns-visibility .btn-clear-text').click -> + searchBox.val '' + searchBox.focus() + $('ul.columns-visibility li').show() + return _initCheckbox = -> $('.i-checks').iCheck @@ -22,6 +44,8 @@ CIF.FamiliesIndex = do -> radioClass: 'iradio_square-green' _initAdavanceSearchFilter = -> + return if $('#family-builder-fields').length == 0 + advanceFilter = new CIF.ClientAdvanceSearch() advanceFilter.initBuilderFilter('#family-builder-fields') advanceFilter.setValueToBuilderSelected() @@ -30,6 +54,7 @@ CIF.FamiliesIndex = do -> advanceFilter.handleShowCustomFormSelect() advanceFilter.customFormSelectChange() advanceFilter.customFormSelectRemove() + advanceFilter.assessmentSelectChange() advanceFilter.handleHideCustomFormSelect() advanceFilter.handleFamilyShowProgramStreamFilter() @@ -54,9 +79,79 @@ CIF.FamiliesIndex = do -> advanceFilter.handleSaveQuery() advanceFilter.validateSaveQuery() + $('.rule-operator-container').change -> advanceFilter.initSelect2() + advanceFilter.handleShowAssessmentSelect() + advanceFilter.handleHideAssessmentSelect() + _addDataTableToAssessmentScoreData() + + + _addDataTableToAssessmentScoreData = -> + advanceFilter = new CIF.ClientAdvanceSearch() + advanceFilter.prepareFamilySearch() + _handleAjaxRequestToAssessment("#custom-assessment-score-0", $("#custom-assessment-domain-score-0").data("filename")) + + $('.assessment-domain-score').on 'shown.bs.modal', (e) -> + $($.fn.dataTable.tables(true)).DataTable().columns.adjust() + return + + _handleAjaxRequestToAssessment = (tableId, fileName)-> + return if $(tableId).length == 0 + + url = $("#{tableId} .api-assessment-path").data('assessment-params') + columns = $("#{tableId} .assessment-domain-headers").data('headers') + + rules = $("#client_advanced_search_basic_rules").val() + if url.includes("family/assessments") + rules = $("#family_advanced_search_basic_rules").val() + + table = $(tableId).DataTable + autoWidth:true + bFilter: false + processing: true + serverSide: true + sServerMethod: 'POST' + ajax: + url: url + data: + basic_rules: rules + error: (jqXHR, textStatus, errorThrown) -> + console.log("Datatable Ajax Error:", errorThrown) + oLanguage: { + sProcessing: "" + } + scrollX: true + columnDefs: [{ type: 'formatted-num', targets: 0 }] + columns: columns + dom: 'lBrtip' + lengthMenu: [ + [ + 10 + 25 + -1 + ] + [ + 10 + 25 + 'All' + ] + ] + buttons: [ { + filename: fileName + extend: 'excel' + text: ' Excel Export' + exportOptions: modifier: + search: 'applied' + order: 'applied' + } + ], + 'drawCallback': (oSettings) -> + $('.dataTables_scrollHeadInner').css 'width': '100%' + $(tableId).css 'width': '100%' + return + _handleUncheckColumnVisibility = -> params = window.location.search.substr(1) diff --git a/app/assets/javascripts/referrals/form.coffee b/app/assets/javascripts/referrals/form.coffee index 8c9fab329f..6224378c8f 100644 --- a/app/assets/javascripts/referrals/form.coffee +++ b/app/assets/javascripts/referrals/form.coffee @@ -18,7 +18,14 @@ CIF.ReferralsNew = CIF.ReferralsCreate = CIF.ReferralsUpdate = CIF.ReferralsEdit _initExternalReferral() _initSelect2 = -> - $('select').select2() + $('select').select2().on 'select2-opening', (e) -> + return true if @.id == 'referral_level_of_risk' + + if $('#type-of-service').data('single-selected') && $(this).select2('val').length > 0 + e.preventDefault() + return + else + return true _initExternalReferral = -> referredTo = document.getElementById('referral_referred_to') diff --git a/app/assets/javascripts/referrals/show.coffee b/app/assets/javascripts/referrals/show.coffee new file mode 100644 index 0000000000..29391809cb --- /dev/null +++ b/app/assets/javascripts/referrals/show.coffee @@ -0,0 +1,18 @@ +CIF.ReferralsShow = do -> + _init = -> + $.fn.editable.defaults.ajaxOptions = {type: "put"} + $('.editable').editable + select2: + width: '250px' + dropdownAutoWidth: true + allowClear: true + viewseparator: ',' + ajaxOptions: + dataType: 'json' + error: (response, newValue) -> + if response.status == 500 + 'Service unavailable. Please try later.' + else + response.responseText + + { init: _init } diff --git a/app/assets/javascripts/settings/index.coffee b/app/assets/javascripts/settings/index.coffee index aaa3f61a6a..082bb42509 100644 --- a/app/assets/javascripts/settings/index.coffee +++ b/app/assets/javascripts/settings/index.coffee @@ -1,150 +1,150 @@ -CIF.SettingsIndex = CIF.SettingsEdit = CIF.SettingsUpdate = CIF.SettingsCreate = CIF.SettingsDefault_columns = do -> - _init = -> - _initSelect2() - _handleDefaultAssessmentCheckbox() - _ajaxChangeDistrict() - _initICheckBox() - _handleCustomAssessmentCheckbox() - _handleInitCocoonForCustomAssessmentSetting() - _toggleDeleteIncomplete() - - _initICheckBox = -> - $('.ichecks-radio_buttons').iCheck - checkboxClass: 'icheckbox_square-green' - radioClass: 'iradio_square-green' - - $('.i-checks').iCheck( - checkboxClass: 'icheckbox_square-green' - radioClass: 'iradio_square-green' - ).on('ifChecked', -> - currentSettingId = $(this).data('current-setting') - - if currentSettingId - $.ajax - type: 'PUT' - url: "settings/#{currentSettingId}" - data: { setting: { enable_custom_assessment: true } } - dataType: 'JSON' - success: (json) -> - return - - if $(this).attr("id") == "setting_use_screening_assessment" - $(".screening-assessment-form").removeClass("hidden") - - if $(this).attr("id") == "setting_disable_required_fields" - $("#care-plan-setting").removeClass('hidden') - ).on('ifUnchecked', -> - if $(this).attr("id") == "setting_use_screening_assessment" - $(".screening-assessment-form").addClass("hidden") - - if $(this).attr("id") == "setting_disable_required_fields" - $("#care-plan-setting").addClass('hidden') - ) - - _toggleDeleteIncomplete = -> - $("#setting_never_delete_incomplete_assessment").on "ifUnchecked", -> - $("#delete-incomplete-time").show() - $("#setting_never_delete_incomplete_assessment").on "ifChecked", -> - $("#delete-incomplete-time").hide() - - _initSelect2 = -> - $('select').select2() - $("[id*='_custom_assessment_frequency']").on 'select2-selected', (element) -> - prefixId = @.id.match(/.*\d\_/)[0] - maxCustomAssessment = $("##{prefixId}max_custom_assessment") - if @.value == 'unlimited' - maxCustomAssessment.val(0) - maxCustomAssessment.parent().removeClass('has-error') - maxCustomAssessment.siblings().hide() - maxCustomAssessment.prop('disabled', true) - else - maxCustomAssessment.prop('disabled', false) - - - _handleInitCocoonForCustomAssessmentSetting = -> - $('#custom_assessment_settings').off('cocoon:after-insert').on 'cocoon:after-insert', -> - _initICheckBox() - _handleCustomAssessmentCheckbox() - _initSelect2() - - _handleCustomAssessmentCheckbox = -> - _disableCustomAssessmentSetting() - $('#checkbox_custom_assessment_setting.i-checks').on 'ifUnchecked', -> - checkbox_index_val = event.target.previousSibling.name.split('setting').slice(-1)[0].split('[')[1].split(']')[0] - custom_assessment_name = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_name" - max_custom_assessment = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_max_custom_assessment" - custom_assessment_frequency = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_frequency" - custom_age = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_age" - - $(custom_assessment_name).prop('disabled', true) - $(max_custom_assessment).prop('disabled', true) - $(custom_assessment_frequency).prop('disabled', true) - $(custom_age).prop('disabled', true) - - $('#checkbox_custom_assessment_setting.i-checks').on 'ifChecked', -> - checkbox_index_val = event.target.previousSibling.name.split('setting').slice(-1)[0].split('[')[1].split(']')[0] - custom_assessment_name = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_name" - max_custom_assessment = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_max_custom_assessment" - custom_assessment_frequency = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_frequency" - custom_age = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_age" - - $(custom_assessment_name).prop('disabled', false) - $(max_custom_assessment).prop('disabled', false) - $(custom_assessment_frequency).prop('disabled', false) - $(custom_age).prop('disabled', false) - - _disableCustomAssessmentSetting = -> - $('#checkbox_custom_assessment_setting.i-checks').each (index) -> - if this.checked == false - checkbox_val = this.name.split('setting').slice(-1)[0].split('[')[1].split(']')[0] - custom_assessment_name = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_custom_assessment_name" - max_custom_assessment = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_max_custom_assessment" - custom_assessment_frequency = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_custom_assessment_frequency" - custom_age = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_custom_age" - - $(custom_assessment_name).prop('disabled', true) - $(max_custom_assessment).prop('disabled', true) - $(custom_assessment_frequency).prop('disabled', true) - $(custom_age).prop('disabled', true) - - _handleDefaultAssessmentCheckbox = -> - _disableAssessmentSetting() - $('#setting_enable_default_assessment.i-checks').on 'ifUnchecked', -> - $('#default-assessment-setting .panel-body').find('input, select').prop('disabled', true) - $('#setting_enable_default_assessment.i-checks').on 'ifChecked', -> - $('#default-assessment-setting .panel-body').find('input, select').prop('disabled', false) - - _disableAssessmentSetting = -> - disableDefaultAssessmentChecked = $('#setting_enable_default_assessment').is(':unchecked') - $('#default-assessment-setting .panel-body').find('input, select').prop('disabled', true) if disableDefaultAssessmentChecked - - _ajaxChangeDistrict = -> - mainAddress = $('#setting_province_id, #setting_district_id') - mainAddress.on 'change', -> - type = $(@).data('type') - typeId = $(@).val() - subAddress = $(@).data('subaddress') - - if type == 'provinces' && subAddress == 'district' - subResources = 'districts' - subAddress = $('#setting_district_id') - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() - else if type == 'districts' && subAddress == 'commune' - subResources = 'communes' - subAddress = $('#setting_commune_id') - - $(subAddress).val(null).trigger('change') - $(subAddress).find('option[value!=""]').remove() - - if typeId != '' - $.ajax - method: 'GET' - url: "/api/#{type}/#{typeId}/#{subResources}" - dataType: 'JSON' - success: (response) -> - for address in response.data - subAddress.append("") - - { init: _init } +CIF.SettingsIndex = CIF.SettingsScreening_forms = CIF.SettingsCare_plan = CIF.SettingsEdit = CIF.SettingsUpdate = CIF.SettingsCreate = CIF.SettingsDefault_columns = do -> + _init = -> + _initSelect2() + _handleDefaultAssessmentCheckbox() + _ajaxChangeDistrict() + _initICheckBox() + _handleCustomAssessmentCheckbox() + _handleInitCocoonForCustomAssessmentSetting() + _toggleDeleteIncomplete() + + _initICheckBox = -> + $('.ichecks-radio_buttons').iCheck + checkboxClass: 'icheckbox_square-green' + radioClass: 'iradio_square-green' + + $('.i-checks').iCheck( + checkboxClass: 'icheckbox_square-green' + radioClass: 'iradio_square-green' + ).on('ifChecked', -> + currentSettingId = $(this).data('current-setting') + + if currentSettingId + $.ajax + type: 'PUT' + url: "settings/#{currentSettingId}" + data: { setting: { enable_custom_assessment: true } } + dataType: 'JSON' + success: (json) -> + return + + if $(this).attr("id") == "setting_use_screening_assessment" + $(".screening-assessment-form").removeClass("hidden") + + if $(this).attr("id") == "setting_disable_required_fields" + $("#care-plan-setting").removeClass('hidden') + ).on('ifUnchecked', -> + if $(this).attr("id") == "setting_use_screening_assessment" + $(".screening-assessment-form").addClass("hidden") + + if $(this).attr("id") == "setting_disable_required_fields" + $("#care-plan-setting").addClass('hidden') + ) + + _toggleDeleteIncomplete = -> + $("#setting_never_delete_incomplete_assessment").on "ifUnchecked", -> + $("#delete-incomplete-time").show() + $("#setting_never_delete_incomplete_assessment").on "ifChecked", -> + $("#delete-incomplete-time").hide() + + _initSelect2 = -> + $('select').select2() + $("[id*='_custom_assessment_frequency']").on 'select2-selected', (element) -> + prefixId = @.id.match(/.*\d\_/)[0] + maxCustomAssessment = $("##{prefixId}max_custom_assessment") + if @.value == 'unlimited' + maxCustomAssessment.val(0) + maxCustomAssessment.parent().removeClass('has-error') + maxCustomAssessment.siblings().hide() + maxCustomAssessment.prop('disabled', true) + else + maxCustomAssessment.prop('disabled', false) + + + _handleInitCocoonForCustomAssessmentSetting = -> + $('#custom_assessment_settings').off('cocoon:after-insert').on 'cocoon:after-insert', -> + _initICheckBox() + _handleCustomAssessmentCheckbox() + _initSelect2() + + _handleCustomAssessmentCheckbox = -> + _disableCustomAssessmentSetting() + $('#checkbox_custom_assessment_setting.i-checks').on 'ifUnchecked', -> + checkbox_index_val = event.target.previousSibling.name.split('setting').slice(-1)[0].split('[')[1].split(']')[0] + custom_assessment_name = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_name" + max_custom_assessment = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_max_custom_assessment" + custom_assessment_frequency = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_frequency" + custom_age = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_age" + + $(custom_assessment_name).prop('disabled', true) + $(max_custom_assessment).prop('disabled', true) + $(custom_assessment_frequency).prop('disabled', true) + $(custom_age).prop('disabled', true) + + $('#checkbox_custom_assessment_setting.i-checks').on 'ifChecked', -> + checkbox_index_val = event.target.previousSibling.name.split('setting').slice(-1)[0].split('[')[1].split(']')[0] + custom_assessment_name = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_name" + max_custom_assessment = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_max_custom_assessment" + custom_assessment_frequency = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_assessment_frequency" + custom_age = "#setting_custom_assessment_settings_attributes_#{checkbox_index_val}_custom_age" + + $(custom_assessment_name).prop('disabled', false) + $(max_custom_assessment).prop('disabled', false) + $(custom_assessment_frequency).prop('disabled', false) + $(custom_age).prop('disabled', false) + + _disableCustomAssessmentSetting = -> + $('#checkbox_custom_assessment_setting.i-checks').each (index) -> + if this.checked == false + checkbox_val = this.name.split('setting').slice(-1)[0].split('[')[1].split(']')[0] + custom_assessment_name = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_custom_assessment_name" + max_custom_assessment = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_max_custom_assessment" + custom_assessment_frequency = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_custom_assessment_frequency" + custom_age = "#setting_custom_assessment_settings_attributes_#{checkbox_val}_custom_age" + + $(custom_assessment_name).prop('disabled', true) + $(max_custom_assessment).prop('disabled', true) + $(custom_assessment_frequency).prop('disabled', true) + $(custom_age).prop('disabled', true) + + _handleDefaultAssessmentCheckbox = -> + _disableAssessmentSetting() + $('#setting_enable_default_assessment.i-checks').on 'ifUnchecked', -> + $('#default-assessment-setting .panel-body').find('input, select').prop('disabled', true) + $('#setting_enable_default_assessment.i-checks').on 'ifChecked', -> + $('#default-assessment-setting .panel-body').find('input, select').prop('disabled', false) + + _disableAssessmentSetting = -> + disableDefaultAssessmentChecked = $('#setting_enable_default_assessment').is(':unchecked') + $('#default-assessment-setting .panel-body').find('input, select').prop('disabled', true) if disableDefaultAssessmentChecked + + _ajaxChangeDistrict = -> + mainAddress = $('#setting_province_id, #setting_district_id') + mainAddress.on 'change', -> + type = $(@).data('type') + typeId = $(@).val() + subAddress = $(@).data('subaddress') + + if type == 'provinces' && subAddress == 'district' + subResources = 'districts' + subAddress = $('#setting_district_id') + + $(subAddress).val(null).trigger('change') + $(subAddress).find('option[value!=""]').remove() + else if type == 'districts' && subAddress == 'commune' + subResources = 'communes' + subAddress = $('#setting_commune_id') + + $(subAddress).val(null).trigger('change') + $(subAddress).find('option[value!=""]').remove() + + if typeId != '' + $.ajax + method: 'GET' + url: "/api/#{type}/#{typeId}/#{subResources}" + dataType: 'JSON' + success: (response) -> + for address in response.data + subAddress.append("") + + { init: _init } diff --git a/app/assets/javascripts/settings/integration.coffee b/app/assets/javascripts/settings/integration.coffee index 4eb00fdbdc..7f4024cb4d 100644 --- a/app/assets/javascripts/settings/integration.coffee +++ b/app/assets/javascripts/settings/integration.coffee @@ -1,4 +1,4 @@ -CIF.SettingsIntegration = do -> +CIF.SettingsIntegration = CIF.SettingsFinance_dashboard = CIF.SettingsHeader_count = do -> _init = -> _initICheckBox() diff --git a/app/assets/javascripts/settings/research_module.coffee b/app/assets/javascripts/settings/research_module.coffee index a489c69c0f..714e507f2e 100644 --- a/app/assets/javascripts/settings/research_module.coffee +++ b/app/assets/javascripts/settings/research_module.coffee @@ -1,4 +1,4 @@ -CIF.SettingsResearch_module = do -> +CIF.SettingsResearch_module = CIF.SettingsInternal_referral_module = do -> _init = -> _initICheckBox() diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 0c52bc604a..43a4529593 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -32,7 +32,6 @@ @import "editable/bootstrap-editable"; // Components - @import "case/quarterly_reports/*"; @import "sessions/*"; @import "cases/*"; diff --git a/app/assets/stylesheets/assessments/index.scss b/app/assets/stylesheets/assessments/index.scss index 68359bedb0..efdec1fed5 100644 --- a/app/assets/stylesheets/assessments/index.scss +++ b/app/assets/stylesheets/assessments/index.scss @@ -1,4 +1,12 @@ +body[id=assessments-show], body[id=assessments-index] { + .draft { + margin-left: 5px; + } +} + +body[id=assessments-index] { + .button { min-width: 165px; } diff --git a/app/assets/stylesheets/case_notes/form.scss b/app/assets/stylesheets/case_notes/form.scss index bf7ae99493..73e7682f71 100644 --- a/app/assets/stylesheets/case_notes/form.scss +++ b/app/assets/stylesheets/case_notes/form.scss @@ -111,11 +111,11 @@ body[id=case_notes-create] { pointer-events: none; } - .panel-heading .popover-content { - color: black !important; + label.boolean { + font-weight: bold; + } - label.boolean { - font-weight: bold; - } + .panel-heading .popover-content { + color: black !important } } diff --git a/app/assets/stylesheets/client_advanced_searches/index.scss b/app/assets/stylesheets/client_advanced_searches/index.scss index 8c5996cbaa..561f0adae2 100644 --- a/app/assets/stylesheets/client_advanced_searches/index.scss +++ b/app/assets/stylesheets/client_advanced_searches/index.scss @@ -21,6 +21,7 @@ body[id='client_advanced_searches-index'] { border-color: #1ab394; color: #FFFFFF; } + button { margin-right: 5px; } @@ -40,9 +41,12 @@ body[id='client_advanced_searches-index'] { .rule-value-container { border-left: none; - select, input { + + select, + input { width: 180px; } + input.form-control { padding: 6px 12px; } @@ -53,20 +57,27 @@ body[id='client_advanced_searches-index'] { float: right; } - .basic-filter-error, .custom-form-error { + .basic-filter-error, + .custom-form-error { color: red; display: none; } - .custom-form, .program-stream, .selected-custom-form, .program-association, .assessment-form { + .custom-form, + .program-stream, + .selected-custom-form, + .program-association, + .assessment-form { display: none; } - .program-association, .program-stream { + .program-association, + .program-stream { margin-left: 16px; } - th.form-builder, td.form-builder { + th.form-builder, + td.form-builder { min-width: 480px; } @@ -83,14 +94,31 @@ body[id='client_advanced_searches-index'] { cursor: default; } - .csi-header, .referee-header, .carer-header, .type-of-service-header, .hotline-call-header, .care-plan-header { + .csi-header, + .referee-header, + .carer-header, + .type-of-service-header, + .hotline-call-header, + .care-plan-header, + .custom-assessment-devider { padding: 5px 16px; + + strong { + font-size: 13px; + } + } + + .custom-assessment-setting li.custom-assessment-devider { + padding-left: 15px !important; + padding-bottom: 5px !important; + strong { font-size: 13px; } } - th.domain-scores, td.domain-scores { + th.domain-scores, + td.domain-scores { min-width: 200px; } @@ -98,6 +126,7 @@ body[id='client_advanced_searches-index'] { .modal-footer { text-align: left; } + .btn-cancel { margin: 10px 10px 10px 0; } @@ -105,6 +134,7 @@ body[id='client_advanced_searches-index'] { .nav-tabs { margin-bottom: 10px; + li.active a { border-bottom-color: #fff; } diff --git a/app/assets/stylesheets/clients/client_grid.scss b/app/assets/stylesheets/clients/client_grid.scss index 3798543e34..1219c159be 100644 --- a/app/assets/stylesheets/clients/client_grid.scss +++ b/app/assets/stylesheets/clients/client_grid.scss @@ -1,4 +1,6 @@ body[id="clients-index"], +body[id="clients-welcome"], +body[id="families-welcome"], body[id="families-index"], body[id="partners-index"], body[id="families-show"], @@ -15,16 +17,19 @@ body[id="client_advanced_searches-index"] { @include hyphens(auto); font-size: 14px; height: 57px; + .showmore_content { position: relative; overflow: hidden; } + .showmore_trigger { width: 100%; text-align: center; height: 25px; cursor: pointer; } + .showmore_trigger span { display: block; } @@ -84,6 +89,7 @@ body[id="client_advanced_searches-index"] { min-width: 135px; } + th.assessment_created_at, th.date_of_assessments, th.assessment_completed_date, th.custom_completed_date, @@ -92,7 +98,7 @@ body[id="client_advanced_searches-index"] { } th.date_of_custom_assessments, - th.custom_assessment_created_date, + th.custom_assessment_created_at, th.custom_assessment { min-width: 250px; } @@ -143,6 +149,7 @@ body[id="client_advanced_searches-index"] { th.live_with, th.local_given_name, th.local_family_name, + th.care_plan_date, th.care_plan_completed_date, th.commune, th.district, @@ -208,7 +215,9 @@ body[id="client_advanced_searches-index"] { } th.all_csi_assessments, - th.all_custom_csi_assessments { + th.all_custom_csi_assessments, + th.has_disability, + th.has_hiv_or_aid { min-width: 260px; } @@ -225,7 +234,8 @@ body[id="client_advanced_searches-index"] { th.reason_for_family_separation, th.history_of_high_risk_behaviours, th.history_of_harm, - th.history_of_disability_and_or_illness { + th.history_of_disability_and_or_illness, + th.has_known_chronic_disease { min-width: 360px; } @@ -239,6 +249,12 @@ body[id="client_advanced_searches-index"] { min-width: 280px; } + th.level_of_risk, + th.date_of_risk_assessment { + text-align: center; + min-width: 175px; + } + td.manage { a { margin: 0 5px; @@ -246,14 +262,18 @@ body[id="client_advanced_searches-index"] { } } } + ul.check-columns-visibility { padding-left: 0; + li:first-child { padding: 0 8px 15px 8px; } + li { list-style: none; } + .columns-visibility { max-height: 250px; width: 390px; @@ -261,12 +281,15 @@ body[id="client_advanced_searches-index"] { padding-top: 10px; padding-bottom: 10px; } + .visibility { margin: 2px 0 2px 0; + label { font-weight: normal; } } + .all-visibility { margin: 2px 0 2px 0; } @@ -274,9 +297,11 @@ body[id="client_advanced_searches-index"] { table.clients { margin-bottom: 0; + th { border-bottom-width: 2px; } + tbody tr:hover { cursor: pointer; } diff --git a/app/assets/stylesheets/clients/form.scss b/app/assets/stylesheets/clients/form.scss index 4c6c9bac67..081d92b0dd 100644 --- a/app/assets/stylesheets/clients/form.scss +++ b/app/assets/stylesheets/clients/form.scss @@ -2,6 +2,11 @@ body[id='clients-new'], body[id='clients-create'], body[id='clients-edit'], body[id='clients-update'] { + + .filepond--credits { + display: none; + } + .wizard>.content>.body { #getting_started, @@ -1044,7 +1049,7 @@ body[id='clients-new'] .disabled, body[id='clients-create'] .disabled, body[id='clients-edit'] .disabled, body[id='clients-update'] .disabled { - color: #fff !important; + color: #333 !important; pointer-events: none; } diff --git a/app/assets/stylesheets/clients/index.scss b/app/assets/stylesheets/clients/index.scss index 167fba6df8..844ed80c59 100644 --- a/app/assets/stylesheets/clients/index.scss +++ b/app/assets/stylesheets/clients/index.scss @@ -1,9 +1,64 @@ -body[id='clients-index'] { +body[id='families-index'], +body[id='families-welcome'], +body[id='clients-index'], +body[id='clients-welcome'] { + .assessment-domain-score { + .modal-dialog { + width: 100%; + // height: 90%; + margin: 0 auto; + padding: 0; + display: flex; + align-items: center; + justify-content: center; + } + + .modal-content { + // height: 90%; + // min-height: 90%; + // max-height: 90%; + min-width: 90%; + border-radius: 0; + overflow: auto; + + .dataTables_processing { + z-index: 999; + background: none; + border: none; + } + } + + table.assessment-score-data { + width: 100% !important; + } + + .client-id, + .family-id, + .family-name, + .client-name, + .assessment-number, + .assessment-date { + min-width: 120px; + } + + .assessment-score { + min-width: 32px; + } + + .dt-buttons { + float: right; + } + } +} + + +body[id='clients-index'], +body[id='clients-welcome'] { @import 'iCheck/custom'; @import 'clients/client_grid'; - .pagination > { - .active > form { + .pagination> { + .active>form { background-color: #1ab394; border-color: #1ab394; color: white; @@ -11,21 +66,22 @@ body[id='clients-index'] { z-index: 2; } - li:first-child > form > input { + li:first-child>form>input { border-bottom-left-radius: 4px; border-top-left-radius: 4px; } - li:last-child > form > input { + li:last-child>form>input { border-bottom-right-radius: 4px; border-top-right-radius: 4px; } - li > form { + li>form { position: relative; float: left; color: #337ab7; background-color: #fff; + input { border: 1px solid #ddd; margin-left: -1px; @@ -33,6 +89,7 @@ body[id='clients-index'] { line-height: 1.42857143; background-color: transparent; } + &:hover { z-index: 2; color: #23527c; @@ -46,19 +103,23 @@ body[id='clients-index'] { th.date { min-width: 100px; } - th.action, th.load-query { + + th.action, + th.load-query { min-width: 70px; } } - #prevent_load_saved_searches{ + #prevent_load_saved_searches { width: 50%; } .loader { margin: auto; - border: 5px solid #f3f3f3; /* Light grey */ - border-top: 5px solid #3498db; /* Blue */ + border: 5px solid #f3f3f3; + /* Light grey */ + border-top: 5px solid #3498db; + /* Blue */ border-radius: 50%; width: 50px; height: 50px; @@ -69,11 +130,11 @@ body[id='clients-index'] { margin-top: 15px; } - .highcharts-legend-item path{ + .highcharts-legend-item path { cursor: pointer; } - #client-statistic-body{ + #client-statistic-body { display: none; margin-bottom: 0; } @@ -82,23 +143,26 @@ body[id='clients-index'] { margin-bottom: 16px; } - .datagrid-filter label{ + .datagrid-filter label { vertical-align: top; padding-top: 5px; } + .domain-filter { margin: 10px 0; } - #client-search-domain{ + + #client-search-domain { margin-bottom: 20px; } - .select2-container.dynamic_filter{ + .select2-container.dynamic_filter { width: 30%; float: left; margin-right: 5px; } - .dynamic_filter.value{ + + .dynamic_filter.value { width: 32%; float: left; } @@ -119,7 +183,7 @@ body[id='clients-index'] { margin-top: 4px; } - @media screen and (max-width: 700px){ + @media screen and (max-width: 700px) { .client-option { a { display: inline-block; @@ -127,6 +191,7 @@ body[id='clients-index'] { } } } + /////////////////////// client advance search //////////////////////////////// #client-advance-search-form { @@ -156,6 +221,7 @@ body[id='clients-index'] { border-color: #1ab394; color: #FFFFFF; } + button { margin-right: 5px; } @@ -175,9 +241,12 @@ body[id='clients-index'] { .rule-value-container { border-left: none; - select, input { + + select, + input { width: 180px; } + input.form-control { padding: 6px 12px; } @@ -188,21 +257,30 @@ body[id='clients-index'] { float: right; } - .basic-filter-error, .custom-form-error { + .basic-filter-error, + .custom-form-error { color: red; display: none; } - .client-column-picker, .custom-form, .program-stream, .selected-custom-form, .program-association, - #wizard-referral-data, #wizard-program-stream, #wizard-custom-form, .assessment-form { + .client-column-picker, + .custom-form, + .program-stream, + .selected-custom-form, + .program-association, + #wizard-referral-data, + #wizard-program-stream, + #wizard-custom-form, + .assessment-form { display: none; } - .program-association{ + .program-association { margin-left: 16px; } - th.form-builder, td.form-builder { + th.form-builder, + td.form-builder { min-width: 480px; } @@ -219,14 +297,22 @@ body[id='clients-index'] { cursor: default; } - .csi-header, .referee-header, .carer-header, .type-of-service-header, .hotline-call-header, .care-plan-header { + .csi-header, + .referee-header, + .carer-header, + .type-of-service-header, + .hotline-call-header, + .care-plan-header, + .custom-referral-data { padding: 5px 16px; + strong { font-size: 13px; } } - th.domain-scores, td.domain-scores { + th.domain-scores, + td.domain-scores { min-width: 200px; } @@ -234,6 +320,7 @@ body[id='clients-index'] { .modal-footer { text-align: left; } + .btn-cancel { margin: 10px 10px 10px 0; } @@ -241,6 +328,7 @@ body[id='clients-index'] { .nav-tabs { margin-bottom: 10px; + li.active a { border-bottom-color: #fff; } @@ -259,34 +347,40 @@ body[id='clients-index'] { margin-left: 0; } } + table.clients { th { position: relative; + form.all-values { position: absolute; right: 5px; top: 10px; color: #337ab7; - &:hover, &:focus { + + &:hover, + &:focus { color: #23527c; } + input[type="submit"] { padding: 0; border: none; background: none; } } + div.dataTables_sizing { display: none; } } } - .popover[class*="tour-"].orphan .arrow{ + .popover[class*="tour-"].orphan .arrow { display: inline-block; } - .tour-tour{ + .tour-tour { left: 0px !important; // top: 420px !important; width: 227px; @@ -296,7 +390,12 @@ body[id='clients-index'] { } .csi-group { - .btn-add-rule, .rule-actions, .drag-handle, .btn-custom-group, .btn-default-group { + + .btn-add-rule, + .rule-actions, + .drag-handle, + .btn-custom-group, + .btn-default-group { display: none; } } @@ -308,62 +407,20 @@ body[id='clients-index'] { border: none; } - .assessment-domain-score { - .modal-dialog { - width: 100%; - // height: 90%; - margin: 0 auto; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - } - - .modal-content { - // height: 90%; - // min-height: 90%; - // max-height: 90%; - min-width: 90%; - border-radius: 0; - overflow:auto; - .dataTables_processing { - z-index: 999; - background: none; - border: none; - } - } - - table.assessment-score-data { - width: 100% !important; - } - - .client-id, .client-name, .assessment-number, .assessment-date { - min-width: 120px; - } - - .assessment-score { - min-width: 32px; - } - - .dt-buttons { - float: right; - } - } - #report-builder-wizard-modal { .modal-lg { width: 90%; } - #report-builder-wizard.wizard > .content > .chose-columns-section.body input { + #report-builder-wizard.wizard>.content>.chose-columns-section.body input { display: inline-block; } - #report-builder-wizard.wizard > .content > .chose-columns-section.body ul { + #report-builder-wizard.wizard>.content>.chose-columns-section.body ul { padding-left: 15px; } - #report-builder-wizard.wizard > .content > .chose-columns-section.body ul > li { + #report-builder-wizard.wizard>.content>.chose-columns-section.body ul>li { list-style: inside; } @@ -412,15 +469,15 @@ body[id='clients-index'] { width: 90%; } - #report-builder-wizard.wizard > .content > .chose-columns-section.body input { + #report-builder-wizard.wizard>.content>.chose-columns-section.body input { display: inline-block; } - #report-builder-wizard.wizard > .content > .chose-columns-section.body ul { + #report-builder-wizard.wizard>.content>.chose-columns-section.body ul { padding-left: 15px; } - #report-builder-wizard.wizard > .content > .chose-columns-section.body ul > li { + #report-builder-wizard.wizard>.content>.chose-columns-section.body ul>li { list-style: inside; } @@ -475,18 +532,21 @@ body[id='clients-index'] { margin-bottom: 20px; } - .hotline-call-column { + .hotline-call-column, .assessment-column { a.disabled { color: #333333 !important; cursor: not-allowed; } } + .ladda-button { color: inherit; background: white; border: 1px solid #e7eaec; } - .care_plan_completed_date .td-content .showmore_content, .care_plan_completed_date .td-content { + + .care_plan_completed_date .td-content .showmore_content, + .care_plan_completed_date .td-content { &:first-child { height: 25px !important; margin-left: 20px; diff --git a/app/assets/stylesheets/clients/show.scss b/app/assets/stylesheets/clients/show.scss index e89bd0dd55..0d87bdb692 100644 --- a/app/assets/stylesheets/clients/show.scss +++ b/app/assets/stylesheets/clients/show.scss @@ -1,4 +1,9 @@ body[id='clients-show'] { + .refer-to-item { + margin-left: 25px; + } + + .case-history-detail { table tbody tr td:last-child { min-width: 150px; @@ -121,6 +126,10 @@ body[id='clients-show'] { td.spacing-first-col { width: 172px; + + @media screen and (min-width: 1500px) { + width: 330px; + } } .overflow-case { diff --git a/app/assets/stylesheets/common_index.scss b/app/assets/stylesheets/common_index.scss index 63f448e84a..bbeb9bd70e 100644 --- a/app/assets/stylesheets/common_index.scss +++ b/app/assets/stylesheets/common_index.scss @@ -60,6 +60,10 @@ border-top: 1px solid #86898c; } +.me-2 { + margin-right: 0.5rem !important; +} + .log-min { background: white; border: 3px solid white; diff --git a/app/assets/stylesheets/common_version.scss b/app/assets/stylesheets/common_version.scss index 89417e3d8f..978b2fff84 100644 --- a/app/assets/stylesheets/common_version.scss +++ b/app/assets/stylesheets/common_version.scss @@ -94,6 +94,10 @@ body[id="users-version"] { } } +.bg-grey { + background-color: #f5f5f6; +} + .usaid-logo { width: 262px; } diff --git a/app/assets/stylesheets/communities/index.scss b/app/assets/stylesheets/communities/index.scss index cdba68b069..895e15a6bb 100644 --- a/app/assets/stylesheets/communities/index.scss +++ b/app/assets/stylesheets/communities/index.scss @@ -1,4 +1,5 @@ -body[id="communities-index"] { +body[id="communities-index"], +body[id="communities-welcome"] { @import "iCheck/custom"; .communities-table { diff --git a/app/assets/stylesheets/custom_data.scss b/app/assets/stylesheets/custom_data.scss new file mode 100644 index 0000000000..f314a00442 --- /dev/null +++ b/app/assets/stylesheets/custom_data.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the CustomData controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/assets/stylesheets/domain_groups/index.scss b/app/assets/stylesheets/domain_groups/index.scss index 51d71e6461..ed89b9e86d 100644 --- a/app/assets/stylesheets/domain_groups/index.scss +++ b/app/assets/stylesheets/domain_groups/index.scss @@ -7,3 +7,16 @@ body[id='domain_groups-index'] { min-width: 100px; } } + + +body[id^='settings-'] { + label.default_assessment { + margin-bottom: 10px; + } +} + +#tablist-cms-tools { + margin-bottom: 20px; +} + + diff --git a/app/assets/stylesheets/families/index.scss b/app/assets/stylesheets/families/index.scss index 0bd5424a4d..71afd7de9d 100644 --- a/app/assets/stylesheets/families/index.scss +++ b/app/assets/stylesheets/families/index.scss @@ -1,3 +1,4 @@ +body[id="families-welcome"], body[id="families-index"] { .pagination > { .active > form { diff --git a/app/assets/stylesheets/family_advanced_searches/index.scss b/app/assets/stylesheets/family_advanced_searches/index.scss index 445c80f939..38d48e2756 100644 --- a/app/assets/stylesheets/family_advanced_searches/index.scss +++ b/app/assets/stylesheets/family_advanced_searches/index.scss @@ -1,3 +1,10 @@ +body[id='family_advanced_searches-index'], +body[id='families-index'] { + .assessment-form { + display: none; + } +} + body[id='family_advanced_searches-index'] { #family-advance-search-form { margin-top: 16px; diff --git a/app/assets/stylesheets/family_referrals/show.scss b/app/assets/stylesheets/family_referrals/show.scss index 46bd1a5e96..1fbe5e43a2 100644 --- a/app/assets/stylesheets/family_referrals/show.scss +++ b/app/assets/stylesheets/family_referrals/show.scss @@ -3,4 +3,7 @@ body[id='family-referrals-show']{ padding-left: 0; } } - \ No newline at end of file + + .download-referral-btn { + margin-right: 5px; + } \ No newline at end of file diff --git a/app/assets/stylesheets/form.scss b/app/assets/stylesheets/form.scss index c1572b0da5..96ad34a306 100644 --- a/app/assets/stylesheets/form.scss +++ b/app/assets/stylesheets/form.scss @@ -1,15 +1,18 @@ .datepicker-dropdown { z-index: 1060 !important; } + .input-group.date .input-group-addon { cursor: pointer; } + .datepicker table tr td span.disabled, .datepicker table tr td span.disabled:hover { background: none; color: #999999 !important; cursor: not-allowed; } + .datepicker table tr td.disabled, .datepicker table tr td.disabled:hover { background: none; @@ -25,9 +28,10 @@ color: #333333; } -#toast-container > .toast-warning { +#toast-container>.toast-warning { &:before { content: "\f071"; } + background-image: none !important; } diff --git a/app/assets/stylesheets/screening_assessments/form.scss b/app/assets/stylesheets/screening_assessments/form.scss index 7b460d588c..a520712c44 100644 --- a/app/assets/stylesheets/screening_assessments/form.scss +++ b/app/assets/stylesheets/screening_assessments/form.scss @@ -5,4 +5,12 @@ body[id='screening_assessments-update'] { .collection_radio_buttons { margin-left: 5px; } + + fieldset[data-developmental-marker-screening-assessment-name] { + .popover { + width: auto; + max-width: 420px; + min-width: 250px + } + } } diff --git a/app/assets/stylesheets/settings/field_setting.scss b/app/assets/stylesheets/settings/field_setting.scss index 8ee858b838..ff32807a75 100644 --- a/app/assets/stylesheets/settings/field_setting.scss +++ b/app/assets/stylesheets/settings/field_setting.scss @@ -16,4 +16,19 @@ .checkbox label { padding-left: 0; } + + .tab-content { + margin-top: 2rem; + } + + .row { + .text-muted { + font-size: 1.2rem; + } + } + + h4.heading { + font-size: 16px; + margin-top: 14px; + } } diff --git a/app/assets/stylesheets/settings/integration.scss b/app/assets/stylesheets/settings/integration.scss index 3b10ea535a..20b5863279 100644 --- a/app/assets/stylesheets/settings/integration.scss +++ b/app/assets/stylesheets/settings/integration.scss @@ -1,3 +1,4 @@ +#settings-finance_dashboard, #settings-integration { .integration { .radio { diff --git a/app/classes/ability.rb b/app/classes/ability.rb index e923d91f7d..793078646d 100644 --- a/app/classes/ability.rb +++ b/app/classes/ability.rb @@ -54,7 +54,7 @@ def initialize(user) can :manage, Enrollment can :manage, Community can :manage, EnrollmentTracking - can :manage, ScreeningAssessment, clients: { case_worker_clients: { user_id: user.id } } + can [:read, :create, :update], ScreeningAssessment family_ids = user.families.ids family_ids << CaseWorkerFamily.where(user_id: user.id).pluck(:family_id) @@ -95,7 +95,7 @@ def initialize(user) can :manage, Enrollment can :manage, Community can :manage, EnrollmentTracking - can :manage, ScreeningAssessment, clients: { case_worker_clients: { user_id: user.id } } + can [:read, :create, :update], ScreeningAssessment family_ids = user.families.ids family_ids += User.joins(:clients).where(id: subordinate_users).where.not(clients: { current_family_id: nil }).select('clients.current_family_id AS client_current_family_id').map(&:client_current_family_id) @@ -127,7 +127,7 @@ def initialize(user) cannot [:edit, :update], ReferralSource cannot :destroy, Client can :manage, Family - can :manage, ScreeningAssessment, clients: { case_worker_clients: { user_id: user.id } } + can [:read, :create, :update], ScreeningAssessment end cannot :read, Community if Setting.cache_first.hide_community? diff --git a/app/classes/active_enrollment_statistic.rb b/app/classes/active_enrollment_statistic.rb index 5af1ed3095..027d9f5ead 100644 --- a/app/classes/active_enrollment_statistic.rb +++ b/app/classes/active_enrollment_statistic.rb @@ -6,10 +6,12 @@ def initialize(clients) def statistic_data ordered_enrollments = @enrollments.order('enrollment_date') enrollment_dates = ordered_enrollments.map(&:short_enrollment_date).uniq - enrollments_by_program = ordered_enrollments.group_by(&:program_stream_id).reject{|ps| ps.nil? }.sort + enrollments_by_program = ordered_enrollments.group_by(&:program_stream_id).reject{|ps| ps.nil? } data_series = [] - enrollments_by_program.each do |program_id, enrollment| + programs = ProgramStream.where(id: enrollments_by_program.keys) + + enrollments_by_program.sort.each do |program_id, enrollment| enrollments_by_date = enrollment.group_by(&:short_enrollment_date) series = [] @@ -23,9 +25,10 @@ def statistic_data series << nil end end - program_name = ProgramStream.find_by(id: program_id).try(:name) - program_id = ProgramStream.find_by(id: program_id).id - data_series << { name: "#{program_name}", data: series } + + program = programs.find { |p| p.id == program_id } + + data_series << { name: "#{program&.name}", data: series } end [enrollment_dates, data_series] end diff --git a/app/classes/advanced_searches/advanced_search_fields.rb b/app/classes/advanced_searches/advanced_search_fields.rb index 5466e6f819..1b569bbc16 100644 --- a/app/classes/advanced_searches/advanced_search_fields.rb +++ b/app/classes/advanced_searches/advanced_search_fields.rb @@ -3,7 +3,7 @@ class AdvancedSearchFields attr_reader :group_label, :translations, :number_type_list, :text_type_list, :date_type_list, :dropdown_type_list def initialize(group_label, args) - @group_label = group_label + @group_label = group_label @translations = args.fetch(:translation) @text_type_list = args.fetch(:text_field) @date_type_list = args.fetch(:date_picker_field) @@ -24,8 +24,8 @@ def render private - def header_translation(key) - translations[key.to_sym] || '' - end + def header_translation(key) + translations[key.to_sym] || '' + end end end diff --git a/app/classes/advanced_searches/client_advanced_search.rb b/app/classes/advanced_searches/client_advanced_search.rb index 4f26d66307..0e998f7c4c 100644 --- a/app/classes/advanced_searches/client_advanced_search.rb +++ b/app/classes/advanced_searches/client_advanced_search.rb @@ -11,37 +11,37 @@ def filter rules = [] client_base_sql = AdvancedSearches::ClientBaseSqlBuilder.new(@clients, @basic_rules).generate query_array << client_base_sql[:sql_string] - client_base_sql[:values].each{ |v| query_array << v } + client_base_sql[:values].each { |v| query_array << v } if client_base_sql[:sql_string].first.present? - if @basic_rules["rules"].any?{ |param| param.has_key?('rules') } - rules << @basic_rules["rules"].first - rules << @basic_rules["rules"].last['rules'] + if @basic_rules['rules'].any? { |param| param.key?('rules') } + rules << @basic_rules['rules'].first + rules << @basic_rules['rules'].last['rules'] else - rules = @basic_rules["rules"].reject {|hash_value| hash_value["id"] != "active_program_stream" } + rules = @basic_rules['rules'].reject {|hash_value| hash_value['id'] != 'active_program_stream' } rules = rules.present? ? rules : @basic_rules end - if rules.compact.any?{|rule| !rule.is_a?(Array) && rule.has_key?('rules')} + if rules.compact.any? { |rule| !rule.is_a?(Array) && rule.key?('rules')} rule_hash = {} - rules = rules.compact.first.each {|k, v| rule_hash[k] = v if k == 'rules'} - operators = rule_hash['rules'].map{|value| value["operator"] }.uniq if rules.present? + rules = rules.compact.first.each { |k, v| rule_hash[k] = v if k == 'rules'} + operators = rule_hash['rules'].map { |value| value['operator'] }.uniq if rules.present? elsif rules.present? && rules.is_a?(Array) - operators = rules.flatten.compact.map{|value| value["operator"] }.uniq if rules.present? + operators = rules.flatten.compact.map { |value| value['operator'] }.uniq if rules.present? else - operators = @basic_rules["rules"].flatten.compact.map{|value| value["operator"] }.uniq if rules.present? + operators = @basic_rules['rules'].flatten.compact.map { |value| value['operator'] }.uniq if rules.present? end - if @basic_rules["condition"] == "AND" && rules.count > 1 && operators.presence.reject(&:nil?).sort == ["not_equal", "equal"].sort && @basic_rules['rules'].any?{|hash| hash['id'] == 'enrolled_program_stream' } - if rules.is_a?(Hash) && (rules.has_key?(:rules) || rules.has_key?("rules")) - excluded_client_ids = rules['rules'].flatten.map{|rule| rule['value'] if rule['operator'] == 'not_equal'} + if @basic_rules['condition'] == 'AND' && rules.count > 1 && operators.presence.reject(&:nil?).sort == ['not_equal', 'equal'].sort && @basic_rules['rules'].any?{|hash| hash['id'] == 'enrolled_program_stream' } + if rules.is_a?(Hash) && (rules.key?(:rules) || rules.key?('rules')) + excluded_client_ids = rules['rules'].flatten.map { |rule| rule['value'] if rule['operator'] == 'not_equal'} else - excluded_client_ids = rules.flatten.map{|rule| rule['value'] if rule['operator'] == 'not_equal'} + excluded_client_ids = rules.flatten.map { |rule| rule['value'] if rule['operator'] == 'not_equal'} end end end - @clients.where(query_array) + [@clients.where(query_array), query_array] end end end diff --git a/app/classes/advanced_searches/client_association_filter.rb b/app/classes/advanced_searches/client_association_filter.rb index 1b9c94da83..1b9164c085 100644 --- a/app/classes/advanced_searches/client_association_filter.rb +++ b/app/classes/advanced_searches/client_association_filter.rb @@ -5,6 +5,7 @@ class ClientAssociationFilter include AssessmentHelper include FormBuilderHelper include ClientsHelper + def initialize(clients, field, operator, values) @clients = clients @field = field @@ -14,6 +15,7 @@ def initialize(clients, field, operator, values) def get_sql sql_string = 'clients.id IN (?)' + case @field when 'user_id' values = user_id_field_query @@ -44,6 +46,8 @@ def get_sql values = @clients.where.not(id: values).ids when 'case_note_type' values = advanced_case_note_query + when 'assessment_created_at' + values = assessment_created_at_query(true) when 'date_of_assessments' values = date_of_assessments_query(true) when /assessment_completed|assessment_completed_date|^(completed_date)/ @@ -52,7 +56,9 @@ def get_sql values = search_custom_assessment when 'custom_completed_date' values = date_of_completed_assessments_query(false) - when 'custom_assessment_created_date' + when 'custom_assessment_created_at' + values = assessment_created_at_query(false) + when 'date_of_custom_assessments' values = date_of_assessments_query(false) when 'accepted_date' values = enter_ngo_accepted_date_query @@ -118,6 +124,8 @@ def get_sql values = care_plan_counter when 'care_plan_completed_date' values = date_query(Client, @clients, :care_plans, 'care_plans.created_at') + when 'care_plan_date' + values = date_query(Client, @clients, :care_plans, 'care_plans.care_plan_date') when 'number_client_referred_gatekeeping' values = number_client_referred_gatekeeping_query when 'number_client_billable' @@ -294,7 +302,7 @@ def exit_ngo_text_field_query(field) exit_ngos = ExitNgo.attached_with_clients case @operator when 'equal' - client_id = exit_ngos.find_by("lower(#{field}) = ?", @value.downcase.squish).try(:client_id) + client_id = exit_ngos.find_by("lower(#{field}) = ?", @value.downcase.squish)&.client_id client_ids = Array(client_id) when 'not_equal' client_ids = exit_ngos.where.not("lower(#{field}) = ?", @value.downcase.squish).pluck(:client_id) @@ -365,7 +373,7 @@ def enter_ngo_accepted_date_query clients.ids end - def date_of_assessments_query(type) + def assessment_created_at_query(type) custom_assessment_setting_id = find_custom_assessment_setting_id(type) if custom_assessment_setting_id clients = @clients.joins(:assessments).where(assessments: { default: type, custom_assessment_setting_id: custom_assessment_setting_id }) @@ -395,6 +403,36 @@ def date_of_assessments_query(type) clients.ids end + def date_of_assessments_query(type) + custom_assessment_setting_id = find_custom_assessment_setting_id(type) + if custom_assessment_setting_id + clients = @clients.joins(:assessments).where(assessments: { default: type, custom_assessment_setting_id: custom_assessment_setting_id }) + else + clients = @clients.joins(:assessments).where(assessments: { default: type }) + end + case @operator + when 'equal' + clients = clients.where('date(assessments.assessment_date) = ?', @value.to_date) + when 'not_equal' + clients = clients.where("date(assessments.assessment_date) != ? OR assessments.assessment_date IS NULL", @value.to_date) + when 'less' + clients = clients.where('date(assessments.assessment_date) < ?', @value.to_date) + when 'less_or_equal' + clients = clients.where('date(assessments.assessment_date) <= ?', @value.to_date) + when 'greater' + clients = clients.where('date(assessments.assessment_date) > ?', @value.to_date) + when 'greater_or_equal' + clients = clients.where('date(assessments.assessment_date) >= ?', @value.to_date) + when 'between' + clients = clients.where('date(assessments.assessment_date) BETWEEN ? AND ? ', @value[0].to_date, @value[1].to_date) + when 'is_empty' + clients = @clients.includes(:assessments).where(assessments: { assessment_date: nil , default: type}) + when 'is_not_empty' + clients = clients.where(assessments: { default: type }).where.not(assessments: { assessment_date: nil }) + end + clients.ids + end + def date_of_completed_assessments_query(type) custom_assessment_setting_id = find_custom_assessment_setting_id(type) if custom_assessment_setting_id @@ -429,9 +467,11 @@ def date_of_completed_assessments_query(type) def find_custom_assessment_setting_id(type) custom_assessment_setting_id = nil if !type && $param_rules['basic_rules'].present? - custom_assessment_setting_rule = JSON.parse($param_rules['basic_rules'])['rules'].select{|rule| rule['id'] == 'custom_assessment' }.try(:first) + basic_rules = $param_rules['basic_rules'].is_a?(Hash) ? $param_rules['basic_rules'] : JSON.parse($param_rules['basic_rules']).with_indifferent_access + custom_assessment_setting_rule = basic_rules.select { |rule| rule['id'] == 'custom_assessment' }.first custom_assessment_setting_id = custom_assessment_setting_rule['value'] if custom_assessment_setting_rule end + custom_assessment_setting_id end @@ -741,6 +781,39 @@ def search_custom_assessment end end + def ratanak_achievement_program_staff_field_query + clients = @clients.joins(:ratanak_achievement_program_staff_clients) + ids = clients.distinct.ids + case @operator + when 'equal' + client_ids = clients.where('achievement_program_staff_clients.user_id = ?', @value).distinct.ids + client_ids & ids + when 'not_equal' + @clients.includes(:achievement_program_staff_clients).where('achievement_program_staff_clients.user_id != ? OR achievement_program_staff_clients.user_id IS NULL', @value).distinct.ids + when 'is_empty' + @clients.where.not(id: ids).ids + when 'is_not_empty' + @clients.where(id: ids).ids + end + end + + def mo_savy_officials_field_query + clients = @clients.joins(:mo_savy_officials) + ids = clients.distinct.ids + + case @operator + when 'equal' + client_ids = clients.where('mo_savy_officials.id = ?', @value).distinct.ids + client_ids & ids + when 'not_equal' + @clients.includes(:mo_savy_officials).where('mo_savy_officials.id != ? OR mo_savy_officials.id IS NULL', @value).distinct.ids + when 'is_empty' + @clients.where.not(id: ids).ids + when 'is_not_empty' + @clients.where(id: ids).ids + end + end + def time_in_cps_query client_ids = [] clients = @clients.joins(:client_enrollments) @@ -1209,37 +1282,35 @@ def get_rejected_clients clients = client_ids end - def active_client_program_between(start_date, end_date, clientIds) - enrollments = ClientEnrollment.where(:client_id => clientIds) + def active_client_program_between(start_date, end_date, client_ids) + enrollments = ClientEnrollment.where(client_id: client_ids) client_ids = [] enrollments.each do |enrollment| enrollment_date = enrollment.enrollment_date if enrollment.leave_program.present? exit_date = enrollment.leave_program.exit_date - if enrollment_date < start_date || enrollment_date.between?(start_date, end_date) - client_ids << enrollment.client_id if exit_date.between?(start_date, end_date) || exit_date > end_date - end - else - client_ids << enrollment.client_id if enrollment_date.between?(start_date, end_date) || enrollment_date < start_date + client_ids << enrollment.client_id if (enrollment_date <= start_date || enrollment_date.between?(start_date, end_date)) && (exit_date.between?(start_date, end_date) || exit_date >= end_date) + elsif enrollment_date.between?(start_date, end_date) || enrollment_date <= start_date + client_ids << enrollment.client_id end end client_ids end def active_client_program_query - clientIds = [] + client_ids = [] JSON.parse($param_rules[:program_selected]).each do |program| - tmpClientIds = @clients.joins(:client_enrollments).where(:client_enrollments => {:status => 'Active', :program_stream_id => program}).ids - if clientIds.empty? - clientIds = tmpClientIds + tmp_client_ids = @clients.joins(:client_enrollments).where(client_enrollments: { status: 'Active', program_stream_id: program }).ids + if client_ids.empty? + client_ids = tmp_client_ids else - clientIds = clientIds & tmpClientIds + client_ids += tmp_client_ids end end condition = '' - start_date = @value.kind_of?(Array) ? @value[0].to_date : @value.to_date + start_date = @value.is_a?(Array) ? @value[0].to_date : @value.to_date case @operator when 'equal' @@ -1247,7 +1318,7 @@ def active_client_program_query when 'not_equal' condition = "date(client_enrollments.enrollment_date) != '#{start_date}'" when 'between' - condition = "date(client_enrollments.enrollment_date) <= '#{@value[1].to_date}'" + condition = "date(client_enrollments.enrollment_date) BETWEEN '#{@value[0].to_date}' AND '#{@value[1].to_date}'" when 'less' condition = "date(client_enrollments.enrollment_date) < '#{start_date}'" when 'less_or_equal' @@ -1262,19 +1333,18 @@ def active_client_program_query condition = "client_enrollments.enrollment_date IS NOT NULL" end - enrollments = ClientEnrollment.where(:client_id => clientIds).where(condition) + enrollments = ClientEnrollment.where(client_id: client_ids).where(condition) client_ids = [] enrollments.each do |enrollment| - if enrollment.leave_program.present? && start_date != nil + if enrollment.leave_program.present? && !start_date.nil? exit_date = enrollment.leave_program.exit_date client_ids << enrollment.client_id if exit_date >= start_date else client_ids << enrollment.client_id end end - client_ids - clients = client_ids.present? ? client_ids : [] + client_ids.present? ? client_ids : [] end def assessment_condition_last_two_query diff --git a/app/classes/advanced_searches/client_base_sql_builder.rb b/app/classes/advanced_searches/client_base_sql_builder.rb index 70827a92b1..4d733ebfd5 100644 --- a/app/classes/advanced_searches/client_base_sql_builder.rb +++ b/app/classes/advanced_searches/client_base_sql_builder.rb @@ -2,27 +2,29 @@ module AdvancedSearches class ClientBaseSqlBuilder include ProgramStreamHelper - ASSOCIATION_FIELDS = ['user_id', 'created_by', 'agency_name', 'donor_name', 'age', 'family', 'family_id', + ASSOCIATION_FIELDS = [ + 'user_id', 'created_by', 'agency_name', 'donor_name', 'age', 'family', 'family_id', 'active_program_stream', 'enrolled_program_stream', 'case_note_date', 'no_case_note_date', 'case_note_type', - 'date_of_assessments', 'date_of_custom_assessments', 'accepted_date', 'assessment_completed_date', - 'custom_assessment', 'custom_assessment_created_date', 'custom_completed_date', + 'assessment_created_at', 'date_of_assessments', 'date_of_custom_assessments', 'accepted_date', 'assessment_completed_date', + 'custom_assessment', 'custom_assessment_created_at', 'custom_completed_date', 'exit_date', 'exit_note', 'other_info_of_exit', 'protection_concern_id', 'necessity_id', 'exit_circumstance', 'exit_reasons', 'referred_to', 'referred_from', 'time_in_cps', 'time_in_ngo', - 'assessment_number', 'month_number', 'date_nearest', 'assessment_completed','date_of_referral', + 'assessment_number', 'month_number', 'date_nearest', 'assessment_completed', 'date_of_referral', 'referee_name', 'referee_phone', 'referee_email', 'carer_name', 'carer_phone', 'carer_email', 'client_phone', 'client_email_address', 'phone_owner', 'referee_relationship', 'active_clients', - 'care_plan_counter', 'care_plan_completed_date', 'completed_date', 'custom_completed_date', 'carer_relationship_to_client', - 'ratanak_achievement_program_staff_client_ids', 'mo_savy_officials', + 'care_plan_counter', 'care_plan_date', 'care_plan_completed_date', 'completed_date', 'custom_completed_date', + 'ratanak_achievement_program_staff_client_ids', 'mo_savy_officials', 'carer_relationship_to_client', 'referred_in', 'referred_out', 'family_type', 'active_client_program', 'number_client_referred_gatekeeping', 'number_client_billable', 'assessment_condition_last_two', 'assessment_condition_first_last', 'client_rejected', 'incomplete_care_plan' - ] + ].freeze BLANK_FIELDS = ['created_at', 'date_of_birth', 'initial_referral_date', 'follow_up_date', 'has_been_in_orphanage', 'has_been_in_government_care', 'province_id', 'referral_source_id', 'birth_province_id', 'received_by_id', 'followed_up_by_id', 'district_id', 'subdistrict_id', 'township_id', 'state_id', 'commune_id', 'village_id', 'referral_source_category_id', 'arrival_at'] SENSITIVITY_FIELDS = %w(given_name family_name local_given_name local_family_name kid_id code school_name school_grade street_number house_number village commune live_with relevant_referral_information telephone_number name_of_referee main_school_contact what3words address_type concern_address_type) SHARED_FIELDS = %w(given_name family_name local_given_name local_family_name gender birth_province_id date_of_birth live_with telephone_number) CALL_FIELDS = Call::FIELDS - OVERDUE_FIELDS = %w(has_overdue_assessment has_overdue_forms has_overdue_task no_case_note) + OVERDUE_FIELDS = %w[has_overdue_assessment has_overdue_forms has_overdue_task no_case_note].freeze + RISK_ASSESSMENTS = %w[level_of_risk date_of_risk_assessment has_disability has_hiv_or_aid has_known_chronic_disease].freeze def initialize(clients, basic_rules) @clients = clients @@ -40,6 +42,7 @@ def generate operator = rule['operator'] value = rule['value'] form_builder = field != nil ? field.split('__') : [] + if ASSOCIATION_FIELDS.include?(field) association_filter = AdvancedSearches::ClientAssociationFilter.new(@clients, field, operator, value).get_sql @sql_string << association_filter[:id] @@ -53,10 +56,11 @@ def generate @values << shared_client_filter[:values] elsif form_builder.first == 'formbuilder' if form_builder.last == 'Has This Form' - custom_form_value = CustomField.find_by(form_title: value, entity_type: 'Client').try(:id) + custom_form_value = CustomField.find_by(form_title: value, entity_type: 'Client')&.id + @sql_string << "Clients.id IN (?)" @values << @clients.joins(:custom_fields).where('custom_fields.id = ?', custom_form_value).uniq.ids - elsif rule['operator'] == 'is_empty' + elsif form_builder.last == 'Does Not Have This Form' client_ids = Client.joins(:custom_fields).where(custom_fields: { form_title: form_builder.second }).ids @sql_string << "clients.id NOT IN (?)" @values << client_ids @@ -121,23 +125,27 @@ def generate @sql_string << domain_scores[:id] @values << domain_scores[:values] elsif form_builder.first == 'type_of_service' - service_query = AdvancedSearches::ServiceSqlBuilder.new().get_sql + service_query = AdvancedSearches::ServiceSqlBuilder.new.get_sql @sql_string << service_query[:id] @values << service_query[:values] elsif CALL_FIELDS.include?(field) - service_query = AdvancedSearches::Hotline::CallSqlBuilder.new().get_sql + service_query = AdvancedSearches::Hotline::CallSqlBuilder.new.get_sql @sql_string << service_query[:id] @values << service_query[:values] elsif OVERDUE_FIELDS.include?(field) overdue_form = AdvancedSearches::OverdueFormSqlBuilder.new(@clients, field, operator, value).get_sql @sql_string << overdue_form[:id] @values << overdue_form[:values] - elsif field != nil && form_builder.first != 'type_of_service' + elsif RISK_ASSESSMENTS.include?(field) + results = AdvancedSearches::RiskAssessmentSqlBuilder.new(@clients, field, operator, value).generate_sql + @sql_string << results[:id] + @values << results[:values] + elsif !field.nil? && form_builder.first != 'type_of_service' base_sql(field, operator, value) else - nested_query = AdvancedSearches::ClientBaseSqlBuilder.new(@clients, rule).generate + nested_query = AdvancedSearches::ClientBaseSqlBuilder.new(@clients, rule).generate @sql_string << nested_query[:sql_string] - nested_query[:values].select{ |v| @values << v } + nested_query[:values].select { |v| @values << v } end end diff --git a/app/classes/advanced_searches/client_fields.rb b/app/classes/advanced_searches/client_fields.rb index b90548969c..a56354b98a 100644 --- a/app/classes/advanced_searches/client_fields.rb +++ b/app/classes/advanced_searches/client_fields.rb @@ -161,7 +161,7 @@ def case_history_dropdown_list ['enrolled_program_stream', enrolled_program_options], ['donor_name', donor_options], ['has_been_in_orphanage', yes_no_options], - ['has_been_in_government_care', yes_no_options], + ['has_been_in_government_care', yes_no_options] ] end @@ -221,12 +221,11 @@ def provinces end def birth_provinces - current_org = Organization.current.short_name - provinces = [] - Organization.switch_to 'shared' - Organization.pluck(:country).uniq.reject(&:blank?).each{ |country| provinces << Province.country_is(country).map{|p| { value: p.id.to_s, label: p.name, optgroup: country.titleize } } } - Organization.switch_to current_org - provinces.flatten + Apartment::Tenant.switch('shared') do + Organization.pluck(:country).uniq.reject(&:blank?).map do |country| + Province.cache_by_country(country).map{ |p| { value: p.id.to_s, label: p.name, optgroup: country.titleize } } + end.flatten + end end def districts @@ -277,7 +276,7 @@ def referral_from_options end def setting_country_fields - country = Setting.cache_first.try(:country_name) || 'cambodia' + country = Setting.cache_first.country_name || 'cambodia' case country when 'lesotho' { @@ -340,5 +339,9 @@ def get_sql_phone_owner def family_type_list Family.mapping_family_type_translation.to_h end + + def mo_savy_officials_options + MoSavyOfficial.cache_all.map { |item| { item.id.to_s => item.name } } + end end end diff --git a/app/classes/advanced_searches/custom_domain_score_fields.rb b/app/classes/advanced_searches/custom_domain_score_fields.rb index f28e01950f..10188295b1 100644 --- a/app/classes/advanced_searches/custom_domain_score_fields.rb +++ b/app/classes/advanced_searches/custom_domain_score_fields.rb @@ -3,12 +3,32 @@ class CustomDomainScoreFields extend AdvancedSearchHelper def self.render(domain_type = 'client') - address_translation - domain_score_group = format_header('custom_csi_domain_scores') - csi_domain_options = domain_options(domain_type).map { |item| number_filter_type(item, domain_score_format(item), domain_score_group) } - custom_assessments = ['custom_assessment'].map{ |item| drop_list_options(item, format_header(item), domain_score_group) } - assessment_completed_date = ['custom_completed_date'].map{ |item| date_picker_options(item, format_header(item), domain_score_group) } - date_of_assessments = ['custom_assessment_created_date'].map{ |item| date_picker_options(item, format_header(item), domain_score_group) } + domain_type == 'client' ? render_client_fields(domain_type) : render_family_fields(domain_type) + end + + def self.render_client_fields(domain_type) + domain_score_group = 'Custom Assessment' + custom_assessment_fields = [] + custom_assessment_fields += ['custom_assessment'].map { |item| drop_list_options(item, format_header(item, domain_type), domain_score_group) } + custom_assessment_fields += ['custom_completed_date'].map { |item| date_picker_options(item, format_header(item, domain_type), domain_score_group) } + custom_assessment_fields += ['custom_assessment_created_at', 'date_of_custom_assessments'].map { |item| date_picker_options(item, format_header(item, domain_type), domain_score_group) } + custom_assessment_fields += ['All Custom Domains'].map { |item| number_filter_type(item.downcase.gsub(' ', '_'), domain_score_format(item), domain_score_group) } + + CustomAssessmentSetting.cache_only_enable_custom_assessment.each do |cas| + domain_score_group = "#{format_header('custom_csi_domain_scores', domain_type)} | #{cas.custom_assessment_name}" + domain_options_ = Domain.custom_csi_domains.order_by_identity.where(custom_assessment_setting_id: cas.id).map { |domain| "domainscore__#{domain.id}__#{domain.identity}" } + custom_assessment_fields += domain_options_.map { |item| number_filter_type(item, domain_score_format(item), domain_score_group) } + end + + custom_assessment_fields.sort_by { |f| f[:label].downcase } + end + + def self.render_family_fields(domain_type) + domain_score_group = format_header('custom_csi_domain_scores', domain_type) + csi_domain_options = domain_options.map { |item| number_filter_type(item, domain_score_format(item), domain_score_group) } + custom_assessments = ['custom_assessment'].map { |item| drop_list_options(item, format_header(item, domain_type), domain_score_group) } + assessment_completed_date = ['custom_completed_date'].map { |item| date_picker_options(item, format_header(item, domain_type), domain_score_group) } + date_of_assessments = ['date_of_custom_assessments', 'custom_assessment_created_at'].map { |item| date_picker_options(item, format_header(item, domain_type), domain_score_group) } all_custom_domains = ['All Custom Domains'].map { |item| number_filter_type(item.downcase.gsub(' ', '_'), domain_score_format(item), domain_score_group) } (custom_assessments + date_of_assessments + assessment_completed_date + csi_domain_options + all_custom_domains).sort_by { |f| f[:label].downcase } end @@ -42,7 +62,7 @@ def self.date_picker_options(field_name, label, group) end def self.number_filter_type(field_name, label, group) - values = ('1'..'10').map{|s| { s => s } } + values = ('1'..'10').map {|s| { s => s } } { id: field_name, optgroup: group, @@ -56,7 +76,8 @@ def self.number_filter_type(field_name, label, group) end def self.drop_list_options(field_name, label, group) - values = CustomAssessmentSetting.all.pluck(:id, :custom_assessment_name).map{|k, v| { k => v } } + values = CustomAssessmentSetting.cache_all.map {|item| { item.id => item.custom_assessment_name } } + { id: field_name, field: label, diff --git a/app/classes/advanced_searches/custom_fields.rb b/app/classes/advanced_searches/custom_fields.rb index dd037811db..1a9b0d1684 100644 --- a/app/classes/advanced_searches/custom_fields.rb +++ b/app/classes/advanced_searches/custom_fields.rb @@ -21,8 +21,6 @@ def render drop_list_fields = @drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first.gsub('"', '&qoute;'), format_label(item.first) , item.last, format_optgroup(item.first)) } results = text_fields + drop_list_fields + number_fields + date_picker_fields - - results.sort_by { |f| f[:label].downcase } end def generate_field_by_type diff --git a/app/classes/advanced_searches/domain_score_fields.rb b/app/classes/advanced_searches/domain_score_fields.rb index 866261c622..86e03dabee 100644 --- a/app/classes/advanced_searches/domain_score_fields.rb +++ b/app/classes/advanced_searches/domain_score_fields.rb @@ -6,18 +6,19 @@ def self.render address_translation domain_score_group = format_header('csi_domain_scores') csi_domain_options = domain_options.map { |item| number_filter_type(item, domain_score_format(item), domain_score_group) } - date_of_assessments = [['date_of_assessments', I18n.t('clients.index.date_of_assessment', assessment: I18n.t('clients.show.assessment'))]].map{ |item| date_picker_options(item[0], item[1], domain_score_group) } - completed_date_assessments = [['completed_date', I18n.t('advanced_search.fields.assessment_completed_date', assessment: I18n.t('clients.show.assessment'))]].map{ |item| date_picker_options(item[0], item[1], domain_score_group) } + assessments_created_at = [['assessment_created_at', I18n.t('clients.index.assessment_created_at', assessment: I18n.t('clients.show.assessment'))]].map { |item| date_picker_options(item[0], item[1], domain_score_group) } + date_of_assessments = [['date_of_assessments', I18n.t('clients.index.date_of_assessment', assessment: I18n.t('clients.show.assessment'))]].map { |item| date_picker_options(item[0], item[1], domain_score_group) } + completed_date_assessments = [['completed_date', I18n.t('advanced_search.fields.assessment_completed_date', assessment: I18n.t('clients.show.assessment'))]].map { |item| date_picker_options(item[0], item[1], domain_score_group) } all_domains = ['All Domains'].map { |item| number_filter_type(item.downcase.gsub(' ', '_'), domain_score_format(item), domain_score_group) } drop_list_fields = dropdown_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, domain_score_group) } - assessment_completed = [['assessment_completed', I18n.t('clients.index.assessment_completed', assessment: I18n.t('clients.show.assessment'))]].map{ |item| date_between_only_options(item[0], item[1], domain_score_group) } - (csi_domain_options + date_of_assessments + completed_date_assessments + all_domains + drop_list_fields).sort_by { |f| f[:label].downcase } + # assessment_completed = [['assessment_completed', I18n.t('clients.index.assessment_completed', assessment: I18n.t('clients.show.assessment'))]].map { |item| date_between_only_options(item[0], item[1], domain_score_group) } + (csi_domain_options + assessments_created_at + date_of_assessments + completed_date_assessments + all_domains + drop_list_fields).sort_by { |f| f[:label].downcase } end - private - def self.domain_options - Domain.csi_domains.order_by_identity.map { |domain| "domainscore__#{domain.id}__#{domain.identity}" } + Rails.cache.fetch([Apartment::Tenant.current, 'Domain', 'csi_domains.order_by_identity', 'options']) do + Domain.csi_domains.order_by_identity.map { |domain| "domainscore__#{domain.id}__#{domain.identity}" } + end end def self.domain_score_format(label) @@ -43,7 +44,7 @@ def self.date_picker_options(field_name, label, group) end def self.number_filter_type(field_name, label, group) - values = ['1', '2', '3', '4'].map{ |s| { s => s } } + values = ['1', '2', '3', '4'].map { |s| { s => s } } { id: field_name, optgroup: group, diff --git a/app/classes/advanced_searches/domain_score_sql_builder.rb b/app/classes/advanced_searches/domain_score_sql_builder.rb index e29b74d229..86ea90df51 100644 --- a/app/classes/advanced_searches/domain_score_sql_builder.rb +++ b/app/classes/advanced_searches/domain_score_sql_builder.rb @@ -33,26 +33,24 @@ def return_dates(custom_domain, client) def domainscore_field_query assessments = [] domain = Domain.find(@domain_id) - custom_domain = domain.try(:custom_domain) + custom_domain = domain&.custom_domain identity = domain.identity clients = Client.includes(assessments: :assessment_domains).references(:assessments) - if $param_rules.nil? - clients.ids - else - basic_rules = $param_rules['basic_rules'] - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access - results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) - assessment_completed_sql, assessment_number = assessment_filter_values(results) - sql = "(assessments.completed = true #{assessment_completed_sql}) AND assessments.created_at = (SELECT created_at FROM assessments WHERE clients.id = assessments.client_id ORDER BY assessments.created_at limit 1 offset #{(assessment_number || 1) - 1})".squish + return clients.ids if $param_rules.nil? || $param_rules['basic_rules'].nil? - score = [@value].flatten.map(&:to_i).sum.zero? ? nil : [@value].flatten.map(&:to_i) - if assessment_completed_sql.present? && assessment_number.present? - clients.where(assessment_domains: { score: score, domain_id: @domain_id }).where(sql) - else - clients = domainscore_operator(clients, @operator, score, sql) - end - clients.ids + basic_rules = $param_rules['basic_rules'] + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) + assessment_completed_sql, assessment_number = assessment_filter_values(results) + sql = "(assessments.completed = true #{assessment_completed_sql}) AND assessments.created_at = (SELECT created_at FROM assessments WHERE clients.id = assessments.client_id ORDER BY assessments.created_at limit 1 offset #{(assessment_number || 1) - 1})".squish + + score = [@value].flatten.map(&:to_i).sum.zero? ? nil : [@value].flatten.map(&:to_i) + if assessment_completed_sql.present? && assessment_number.present? + clients.where(assessment_domains: { score: score, domain_id: @domain_id }).where(sql) + else + clients = domainscore_operator(clients, @operator, score, sql) end + clients.ids end def domainscore_operator(clients, operator, score, sql) @@ -84,7 +82,7 @@ def score_change_query return if @value.first == @value.last client_ids = [] between_date_value = @basic_rules.second['value'] - custom_domain = Domain.find(@domain_id).try(:custom_domain) + custom_domain = Domain.find(@domain_id)&.custom_domain case @operator when 'assessment_has_changed' @@ -424,7 +422,7 @@ def domainscore_query(operator) (scores.compact.sum.to_f / assessment.assessment_domains.size.to_f).round != @value.to_i end end - assessment.first.try(:client_id) + assessment.first&.client_id end client_ids.compact end @@ -526,7 +524,7 @@ def domainscore_query(operator) (scores.compact.sum.to_f / assessment.assessment_domains.size.to_f).round != @value.to_i end end - assessment.first.try(:client_id) + assessment.first&.client_id end client_ids.compact end diff --git a/app/classes/advanced_searches/enrollment_fields.rb b/app/classes/advanced_searches/enrollment_fields.rb index 9426c2c5a5..e2665a3973 100644 --- a/app/classes/advanced_searches/enrollment_fields.rb +++ b/app/classes/advanced_searches/enrollment_fields.rb @@ -23,7 +23,6 @@ def render drop_list_fields = @drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first.gsub('"', '&qoute;'), format_label(item.first) , item.last, format_optgroup(item.first)) } results = text_fields + drop_list_fields + number_fields + date_picker_fields - results.sort_by { |f| f[:label].downcase } @enrollment_data_list.map{ |item|results.unshift AdvancedSearches::FilterTypes.date_picker_options(item.gsub('"', '&qoute;'), format_label(item), format_optgroup(item)) } diff --git a/app/classes/advanced_searches/exit_program_fields.rb b/app/classes/advanced_searches/exit_program_fields.rb index 05ef4cd38a..84ea04b129 100644 --- a/app/classes/advanced_searches/exit_program_fields.rb +++ b/app/classes/advanced_searches/exit_program_fields.rb @@ -24,8 +24,6 @@ def render results = text_fields + drop_list_fields + number_fields + date_picker_fields - results.sort_by { |f| f[:label].downcase } - @exit_data_list.map{ |item|results.unshift AdvancedSearches::FilterTypes.date_picker_options(item.gsub('"', '&qoute;'), format_label(item), format_optgroup(item)) } results diff --git a/app/classes/advanced_searches/families/domain_score_sql_builder.rb b/app/classes/advanced_searches/families/domain_score_sql_builder.rb index e47b734866..3356385de9 100644 --- a/app/classes/advanced_searches/families/domain_score_sql_builder.rb +++ b/app/classes/advanced_searches/families/domain_score_sql_builder.rb @@ -27,15 +27,17 @@ def return_dates(custom_domain, family) else ordered_assessments = family.assessments.defaults.order(:created_at) end + dates = ordered_assessments.map(&:created_at).map{|date| date.strftime("%b, %Y") } end def domainscore_field_query assessments = [] domain = Domain.find(@domain_id) - custom_domain = domain.try(:custom_domain) + custom_domain = domain&.custom_domain identity = domain.identity families = Family.joins(assessments: :assessment_domains) + if $param_rules.nil? families.ids else @@ -43,13 +45,13 @@ def domainscore_field_query basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) assessment_completed_sql, assessment_number = assessment_filter_values(results) - sql = "(assessments.completed = true #{assessment_completed_sql}) AND assessments.created_at = (SELECT created_at FROM assessments WHERE families.id = assessments.client_id ORDER BY assessments.created_at limit 1 offset #{(assessment_number || 1) - 1})".squish + sql = "(assessments.completed = true #{assessment_completed_sql}) AND assessments.created_at = (SELECT created_at FROM assessments WHERE families.id = assessments.family_id ORDER BY assessments.created_at limit 1 offset #{(assessment_number || 1) - 1})".squish if assessment_completed_sql.present? && assessment_number.present? families = families.where(assessment_domains: { score: @value.to_i, domain_id: @domain_id }).where(sql) else family_ids = families.where(assessment_domains: { domain_id: @domain_id }).ids assessments = Assessment.where(family_id: family_ids) - return family_ids = assessment_filter_domainscore_query(assessments.to_a).presence || family_ids + return family_ids = assessment_filter_domainscore_query(assessments.to_a) end families.ids end @@ -59,7 +61,7 @@ def score_change_query return if @value.first == @value.last family_ids = [] between_date_value = @basic_rules.second['value'] - custom_domain = Domain.find(@domain_id).try(:custom_domain) + custom_domain = Domain.find(@domain_id)&.custom_domain case @operator when 'assessment_has_changed' @@ -182,12 +184,12 @@ def assessment_filter_domainscore_query(assessments) end when 'is_empty' assessments.compact.uniq.each do |id| - assessment_domains = AssessmentDomain.where(assessment_id: id).where('domain_id = ? and score = nil', @domain_id) + assessment_domains = AssessmentDomain.where(assessment_id: id).where('domain_id = ? and score IS NULL', @domain_id) family_ids << assessment_domains.map(&:family_id) if assessment_domains.any? end when 'is_not_empty' assessments.compact.uniq.each do |id| - assessment_domains = AssessmentDomain.where(assessment_id: id).where('domain_id = ? and score != nil', @domain_id) + assessment_domains = AssessmentDomain.where(assessment_id: id).where('domain_id = ? and score IS NOT NULL', @domain_id) family_ids << assessment_domains.map(&:family_id) if assessment_domains.any? end end @@ -196,7 +198,7 @@ def assessment_filter_domainscore_query(assessments) end def only_domainscore_field_query - assessments = Assessment.joins([:assessment_domains, :client]) + assessments = Assessment.joins([:assessment_domains, :family]) case @operator when 'equal' @@ -216,7 +218,7 @@ def only_domainscore_field_query assessments = assessments.where(assessment_domains: { domain_id: @domain_id, score: @value.first..@value.last }) when 'is_empty' assessments = assessments.where('assessment_domains.domain_id = ? and assessment_domains.score IS NOT NULL', @domain_id) - family_ids = Family.where.not(id: assessments.distinct.pluck(:client_id)).ids + family_ids = Family.where.not(id: assessments.distinct.pluck(:family_id)).ids when 'is_not_empty' assessments = assessments.where('assessment_domains.domain_id = ? and assessment_domains.score IS NOT NULL', @domain_id) when 'assessment_has_changed' @@ -266,7 +268,7 @@ def only_domainscore_field_query end return family_ids.flatten.uniq end - family_ids = assessments.uniq.pluck(:client_id) unless @operator == 'is_empty' + family_ids = assessments.uniq.pluck(:family_id) unless @operator == 'is_empty' end def all_domains_query @@ -391,7 +393,7 @@ def domainscore_query(operator) (scores.compact.sum.to_f / assessment.assessment_domains.size.to_f).round != @value.to_i end end - assessment.first.try(:client_id) + assessment.first.try(:family_id) end family_ids.compact end diff --git a/app/classes/advanced_searches/families/family_association_filter.rb b/app/classes/advanced_searches/families/family_association_filter.rb index 55358bc20f..891a494315 100644 --- a/app/classes/advanced_searches/families/family_association_filter.rb +++ b/app/classes/advanced_searches/families/family_association_filter.rb @@ -27,12 +27,35 @@ def get_sql values = advanced_case_note_query when 'date_of_birth' values = get_family_member_dob + when 'no_case_note_date' + values = advanced_case_note_query + values = @families.where.not(id: values).ids when 'active_families' values = get_active_families when /assessment_completed|assessment_completed_date|custom_completed_date/ values = date_of_completed_assessments_query(true) when 'date_of_custom_assessments' values = date_of_assessments_query(false) + when 'date_of_assessments' + values = date_of_assessments_query(true) + when 'assessment_created_at' + values = assessment_created_at_query(true) + when 'custom_assessment_created_at' + values = assessment_created_at_query(false) + when 'assessment_condition_last_two' + values = assessment_condition_last_two_query + when 'assessment_condition_first_last' + values = assessment_condition_first_last_query + when 'custom_assessment' + values = search_custom_assessment + when 'number_family_referred_gatekeeping' + values = number_family_referred_gatekeeping_query + when 'number_family_billable' + values = number_family_billable_query + when 'family_rejected' + values = get_rejected_families + when 'assessment_number' + values = assessment_number_query when 'relation' values = family_members when 'care_plan_completed_date' @@ -45,6 +68,214 @@ def get_sql private + def family_assessment_compare_first_last(compare, selectedAssessment) + family_ids = [] + families = @families.joins(:assessments).where(assessments: { completed: true }) + conditionString = "" + assessments = Assessment.completed.joins(:domains).where(family_id: families.ids).distinct + + assessments.group_by { |assessment| assessment.family_id }.each do |family_id, _assessments| + next if _assessments.size < 2 + + first_assessment = _assessments.sort_by(&:id).first + last_assessment = _assessments.sort_by(&:id).last + + first_assessment_domain_scores = first_assessment.assessment_domains.pluck(:score).sum.to_f + last_assessment_domain_scores = last_assessment.assessment_domains.pluck(:score).sum.to_f + + first_average_score = (first_assessment_domain_scores / first_assessment.assessment_domains.size).round + last_average_score = (last_assessment_domain_scores / last_assessment.assessment_domains.size).round + family_ids << family_id if last_average_score.public_send(compare, first_average_score) + end + + family_ids + end + + def family_assessment_compare_next_last(compare, selectedAssessment) + family_ids = [] + families = @families.joins(:assessments).where(assessments: { completed: true }) + conditionString = "" + + assessments = Assessment.completed.joins(:domains).where(family_id: families.ids).distinct + + assessments.group_by { |assessment| assessment.family_id }.each do |family_id, _assessments| + next if _assessments.size < 2 + + before_last_assessment = _assessments.sort_by(&:id).fetch(_assessments.size - 2) + last_assessment = _assessments.sort_by(&:id).last + + before_last_assessment_domain_scores = before_last_assessment.assessment_domains.pluck(:score).sum.to_f + last_assessment_domain_scores = last_assessment.assessment_domains.pluck(:score).sum.to_f + + before_last_assessment_average_score = (before_last_assessment_domain_scores / before_last_assessment.assessment_domains.size).round + last_average_score = (last_assessment_domain_scores / last_assessment.assessment_domains.size).round + family_ids << family_id if last_average_score.public_send(compare, before_last_assessment_average_score) + end + + family_ids + end + + def assessment_condition_last_two_query + case @value.downcase + when 'better' + family_ids = family_assessment_compare_next_last(:>, $param_rules[:assessment_selected]) + when 'same' + family_ids = family_assessment_compare_next_last(:==, $param_rules[:assessment_selected]) + when 'worse' + family_ids = family_assessment_compare_next_last(:<, $param_rules[:assessment_selected]) + end + families = family_ids.present? ? family_ids : [] + end + + def assessment_condition_first_last_query + case @value.downcase + when 'better' + family_ids = family_assessment_compare_first_last(:>, $param_rules[:assessment_selected]) + when 'same' + family_ids = family_assessment_compare_first_last(:==, $param_rules[:assessment_selected]) + when 'worse' + family_ids = family_assessment_compare_first_last(:<, $param_rules[:assessment_selected]) + end + families = family_ids.present? ? family_ids : [] + end + + def assessment_number_query + basic_rules = $param_rules['basic_rules'] + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) + assessment_completed_sql, assessment_number = assessment_filter_values(results) + sql = "(assessments.completed = true #{assessment_completed_sql}) AND ((SELECT COUNT(*) FROM assessments WHERE families.id = assessments.family_id #{assessment_completed_sql}) >= #{@value})".squish + @families.joins(:assessments).where(sql).ids + end + + def assessment_created_at_query(type) + custom_assessment_setting_id = find_custom_assessment_setting_id(type) + if custom_assessment_setting_id + families = @families.joins(:assessments).where(assessments: { default: type, custom_assessment_setting_id: custom_assessment_setting_id }) + else + families = @families.joins(:assessments).where(assessments: { default: type }) + end + case @operator + when 'equal' + families = families.where('date(assessments.created_at) = ?', @value.to_date) + when 'not_equal' + families = families.where("date(assessments.created_at) != ? OR assessments.created_at IS NULL", @value.to_date) + when 'less' + families = families.where('date(assessments.created_at) < ?', @value.to_date) + when 'less_or_equal' + families = families.where('date(assessments.created_at) <= ?', @value.to_date) + when 'greater' + families = families.where('date(assessments.created_at) > ?', @value.to_date) + when 'greater_or_equal' + families = families.where('date(assessments.created_at) >= ?', @value.to_date) + when 'between' + families = families.where('date(assessments.created_at) BETWEEN ? AND ? ', @value[0].to_date, @value[1].to_date) + when 'is_empty' + families = @families.includes(:assessments).where(assessments: { created_at: nil , default: type}) + when 'is_not_empty' + families = families.where(assessments: { default: type }).where.not(assessments: { created_at: nil }) + end + + families.ids + end + + def search_custom_assessment + families = @families.joins(:assessments).where(assessments: {default: false }) + case @operator + when 'equal' + family_ids = families.where(assessments: { custom_assessment_setting_id: @value }).distinct.ids + when 'not_equal' + family_ids = families.where.not(assessments: { custom_assessment_setting_id: @value }).distinct.ids + when 'is_empty' + family_ids = @families.includes(:assessments).group('families.id, assessments.id, assessments.custom_assessment_setting_id').having("COUNT(assessments.id) = 0").distinct.ids + when 'is_not_empty' + family_ids = @families.includes(:assessments).group('families.id, assessments.id, assessments.custom_assessment_setting_id').having("COUNT(assessments.id) > 0").distinct.ids + end + end + + def number_family_referred_gatekeeping_query + families = @families.where(referral_source_category_id: ReferralSource.gatekeeping_mechanism.ids).distinct + + case @operator + when 'equal' + family_ids = families.where('date(initial_referral_date) = ?', @value.to_date ).distinct.ids + when 'not_equal' + family_ids = families.where('date(initial_referral_date) != ?', @value.to_date ).distinct.ids + when 'between' + family_ids = families.where("date(initial_referral_date) BETWEEN ? AND ? ", @value[0].to_date, @value[1].to_date).distinct.ids + when 'less' + family_ids = families.where('date(initial_referral_date) < ?', @value.to_date ).distinct.ids + when 'less_or_equal' + family_ids = families.where('date(initial_referral_date) <= ?', @value.to_date ).distinct.ids + when 'greater' + family_ids = families.where('date(initial_referral_date) > ?', @value.to_date ).distinct.ids + when 'greater_or_equal' + family_ids = families.where('date(initial_referral_date) >= ?', @value.to_date ).distinct.ids + when 'is_empty' + family_ids = families.where('initial_referral_date IS NULL').distinct.ids + when 'is_not_empty' + family_ids = families.where('initial_referral_date IS NOT NULL').distinct.ids + end + + family_ids.present? ? family_ids : [] + end + + def number_family_billable_query + value = @value.kind_of?(Array) ? @value[0] : @value.to_date + families = @families.joins(:enter_ngos).includes(:exit_ngos).where('(exit_ngos.exit_date IS NULL OR date(exit_ngos.exit_date) >= ?)', value).distinct + + case @operator + when 'equal' + family_ids = families.where('date(enter_ngos.accepted_date) = ?', @value.to_date).distinct.ids + when 'not_equal' + family_ids = families.where('date(enter_ngos.accepted_date) != ?', @value.to_date).distinct.ids + when 'between' + family_ids = families.where("date(enter_ngos.accepted_date) <= ?", @value[1]).distinct.ids + when 'less' + family_ids = families.where('date(enter_ngos.accepted_date) < ?', @value.to_date).distinct.ids + when 'less_or_equal' + family_ids = families.where('date(enter_ngos.accepted_date) <= ?', @value.to_date).distinct.ids + when 'greater' + family_ids = families.where('date(enter_ngos.accepted_date) > ?', @value.to_date).distinct.ids + when 'greater_or_equal' + family_ids = families.where('date(enter_ngos.accepted_date) >= ?', @value.to_date).distinct.ids + when 'is_empty' + family_ids = families.where('enter_ngos.accepted_date IS NULL').distinct.ids + when 'is_not_empty' + family_ids = families.where('enter_ngos.accepted_date IS NOT NULL').distinct.ids + end + + family_ids.present? ? family_ids : [] + end + + def get_rejected_families + family_ids = [] + families = @families.joins(:exit_ngos).where(:exit_ngos => {:exit_circumstance => 'Rejected Referral'}).distinct + + case @operator + when 'equal' + family_ids = families.where('date(exit_ngos.exit_date) = ?', @value.to_date ).distinct.ids + when 'not_equal' + family_ids = families.where('date(exit_ngos.exit_date) != ?', @value.to_date ).distinct.ids + when 'between' + family_ids = families.where("date(exit_ngos.exit_date) BETWEEN ? AND ?", @value[0], @value[1]).distinct.ids + when 'less' + family_ids = families.where('date(exit_ngos.exit_date) < ?', @value.to_date ).distinct.ids + when 'less_or_equal' + family_ids = families.where('date(exit_ngos.exit_date) <= ?', @value.to_date ).distinct.ids + when 'greater' + family_ids = families.where('date(exit_ngos.exit_date) > ?', @value.to_date ).distinct.ids + when 'greater_or_equal' + family_ids = families.where('date(exit_ngos.exit_date) >= ?', @value.to_date ).distinct.ids + when 'is_empty' + family_ids = families.where('exit_ngos.exit_date IS NULL').distinct.ids + when 'is_not_empty' + family_ids = families.where('exit_ngos.exit_date IS NOT NULL').distinct.ids + end + + family_ids + end + def list_families families = @families case @operator @@ -69,9 +300,9 @@ def family_members when 'not_equal' families = Family.includes(:family_members).where("NOT EXISTS (SELECT 1 FROM family_members WHERE family_members.family_id = families.id AND relation = ?)", @value).references(:family_members) when 'is_empty' - families = Family.includes(:family_members).where(family_members: { relation: "" }).references(:family_members) + families = Family.includes(:family_members).references(:family_members).group(:id).having("COUNT(family_members.*) = 0") when 'is_not_empty' - families = Family.includes(:family_members).where.not(family_members: { relation: "" }).references(:family_members) + families = families.joins(:family_members).where.not(family_members: { relation: "" }) end families.ids @@ -231,7 +462,7 @@ def advanced_case_note_query results = [] @basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules basic_rules = @basic_rules.is_a?(Hash) ? @basic_rules : JSON.parse(@basic_rules).with_indifferent_access - results = mapping_allowed_param_value(basic_rules, ['case_note_date', 'case_note_type'], data_mapping=[]) + results = mapping_allowed_param_value(basic_rules, ['no_case_note_date', 'case_note_date', 'case_note_type'], data_mapping=[]) query_string = get_any_query_string(results, 'case_notes') sql = query_string.reject(&:blank?).map{|query| "(#{query})" }.join(" #{basic_rules[:condition]} ") families = Family.joins('LEFT OUTER JOIN case_notes ON case_notes.family_id = families.id') @@ -276,6 +507,15 @@ def active_program_stream_query @families.includes(enrollments: :program_stream).where(program_streams: { id: @value }).references(:program_streams).distinct.ids end end + + def find_custom_assessment_setting_id(type) + custom_assessment_setting_id = nil + if !type && $param_rules['basic_rules'].present? + custom_assessment_setting_rule = JSON.parse($param_rules['basic_rules'])['rules'].select{|rule| rule['id'] == 'custom_assessment' }.try(:first) + custom_assessment_setting_id = custom_assessment_setting_rule['value'] if custom_assessment_setting_rule + end + custom_assessment_setting_id + end end end end diff --git a/app/classes/advanced_searches/families/family_base_sql_builder.rb b/app/classes/advanced_searches/families/family_base_sql_builder.rb index 584d84f97f..08c3a36809 100644 --- a/app/classes/advanced_searches/families/family_base_sql_builder.rb +++ b/app/classes/advanced_searches/families/family_base_sql_builder.rb @@ -2,9 +2,10 @@ module AdvancedSearches module Families class FamilyBaseSqlBuilder ASSOCIATION_FIELDS = [ - 'client_id', 'case_workers', 'relation', 'gender', 'date_of_birth', 'date_of_custom_assessments', 'custom_completed_date', + 'client_id', 'case_workers', 'relation', 'gender', 'date_of_birth', 'date_of_custom_assessments', 'custom_completed_date', 'custom_assessment', 'assessment_completed_date', 'assessment_completed', 'case_note_date', 'case_note_type', 'active_families', 'care_plan_completed_date', - 'active_program_stream' + 'active_program_stream', 'number_family_referred_gatekeeping', 'number_family_billable', 'family_rejected', 'no_case_note_date', 'completed_date', + 'assessment_created_at', 'date_of_assessments', 'custom_assessment_created_at', 'assessment_number', 'assessment_condition_last_two', 'assessment_condition_first_last' ].freeze BLANK_FIELDS = %w(created_at contract_date household_income dependable_income female_children_count male_children_count female_adult_count male_adult_count province_id significant_family_member_count district_id commune_id village_id id referral_source_id) @@ -26,6 +27,7 @@ def generate operator = rule['operator'] value = rule['value'] form_builder = field != nil ? field.split('__') : [] + if ASSOCIATION_FIELDS.include?(field) association_filter = AdvancedSearches::Families::FamilyAssociationFilter.new(@families, field, operator, value).get_sql @sql_string << association_filter[:id] @@ -37,15 +39,19 @@ def generate elsif form_builder.first == 'formbuilder' if form_builder.last == 'Has This Form' custom_form_value = CustomField.find_by(form_title: value, entity_type: 'Family').try(:id) - @sql_string << "Families.id IN (?)" + @sql_string << "families.id IN (?)" @values << @families.joins(:custom_fields).where('custom_fields.id = ?', custom_form_value).uniq.ids + elsif form_builder.last == 'Does Not Have This Form' + client_ids = Family.joins(:custom_fields).where(custom_fields: { form_title: form_builder.second }).ids + @sql_string << "families.id NOT IN (?)" + @values << client_ids else custom_form = CustomField.find_by(form_title: form_builder.second, entity_type: 'Family') custom_field = AdvancedSearches::EntityCustomFormSqlBuilder.new(custom_form, rule, 'family').get_sql + @sql_string << custom_field[:id] @values << custom_field[:values] end - elsif form_builder.first == 'quantitative' quantitative_filter = AdvancedSearches::Families::QuantitativeCaseSqlBuilder.new(@families, rule).get_sql @sql_string << quantitative_filter[:id] diff --git a/app/classes/advanced_searches/families/family_fields.rb b/app/classes/advanced_searches/families/family_fields.rb index b16dde642b..641dd3ee18 100644 --- a/app/classes/advanced_searches/families/family_fields.rb +++ b/app/classes/advanced_searches/families/family_fields.rb @@ -18,13 +18,20 @@ def initialize(options = {}) def render group = family_header('family_basic_fields') + common_group = format_header('common_searches') + number_fields = number_type_list.map { |item| AdvancedSearches::FilterTypes.number_options(item, family_header(item), group) } text_fields = text_type_list.map { |item| AdvancedSearches::FilterTypes.text_options(item, family_header(item), group) } date_picker_fields = date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, family_header(item), group) } + date_picker_fields += common_search_date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, family_header(item), common_group) } + date_picker_fields += [['no_case_note_date', I18n.t('advanced_search.fields.no_case_note_date')]].map{ |item| AdvancedSearches::CsiFields.date_between_only_options(item[0], item[1], group) } drop_list_fields = drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, family_header(item.first), item.last, group) } date_picker_fields += mapping_care_plan_date_lable_translation unless current_setting.try(:hide_family_case_management_tool?) search_fields = text_fields + drop_list_fields + number_fields + date_picker_fields - custom_domain_scores_options = !current_setting.try(:hide_family_case_management_tool?) ? AdvancedSearches::CustomDomainScoreFields.render('family') : [] + + unless current_setting.hide_family_case_management_tool? + search_fields += current_setting.enable_custom_assessment? ? AdvancedSearches::CustomDomainScoreFields.render('family') : [] + end search_fields.select do |field| field_name = field[:id] @@ -48,7 +55,7 @@ def text_type_list end def date_type_list - ['created_at', 'date_of_birth', 'contract_date', !current_setting.try(:hide_family_case_management_tool?) ? 'case_note_date' : nil, 'active_families'].compact + ['created_at', 'date_of_birth', 'contract_date', !current_setting.try(:hide_family_case_management_tool?) ? 'case_note_date' : nil].compact end def drop_down_type_list @@ -78,6 +85,10 @@ def drop_down_type_list ] + case_management_tool_fields end + def common_search_date_type_list + ['number_family_referred_gatekeeping', 'number_family_billable', 'family_rejected', 'active_families'] + end + def case_note_type_options [CaseNote::INTERACTION_TYPE, I18n.t('case_notes.form.type_options').values].transpose.map { |k, v| { k => v } } end diff --git a/app/classes/advanced_searches/filter_types.rb b/app/classes/advanced_searches/filter_types.rb index d399b971bb..5e5e16bff7 100644 --- a/app/classes/advanced_searches/filter_types.rb +++ b/app/classes/advanced_searches/filter_types.rb @@ -78,10 +78,10 @@ def self.format_data(field_name, values) case field_name when 'birth_province_id' values.each do |value| - data << {value[:value] => value[:label]} + data << { value[:value] => value[:label] } end when 'gender', 'has_been_in_orphanage', 'has_been_in_government_care' - data = values.map{ |key, value| { key => value } } + data = values.map { |key, value| { key => value } } else data = values end diff --git a/app/classes/advanced_searches/has_this_form_fields.rb b/app/classes/advanced_searches/has_this_form_fields.rb index 46f6b27d79..66c44cd6d2 100644 --- a/app/classes/advanced_searches/has_this_form_fields.rb +++ b/app/classes/advanced_searches/has_this_form_fields.rb @@ -13,7 +13,7 @@ def initialize(custom_form_ids, attach_with = 'Client') def render drop_list_fields = @drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.has_this_form_drop_list_options(item.first.gsub('"', '&qoute;'), format_label(item.first), item.last, format_optgroup(item.first)) } - + results = drop_list_fields results.sort_by { |f| f[:label].downcase } results @@ -26,6 +26,11 @@ def generate_field_by_type drop_list_values << "formbuilder__#{custom_form.form_title}__Has This Form" drop_list_values << { custom_form.form_title => custom_form.form_title} @drop_down_type_list << drop_list_values + + drop_list_values = [] + drop_list_values << "formbuilder__#{custom_form.form_title}__Does Not Have This Form" + drop_list_values << { custom_form.form_title => custom_form.form_title} + @drop_down_type_list << drop_list_values end end diff --git a/app/classes/advanced_searches/overdue_form_sql_builder.rb b/app/classes/advanced_searches/overdue_form_sql_builder.rb index 1f188b76d8..0ea432fc91 100644 --- a/app/classes/advanced_searches/overdue_form_sql_builder.rb +++ b/app/classes/advanced_searches/overdue_form_sql_builder.rb @@ -28,8 +28,8 @@ def get_sql def no_case_note client_ids = [] setting = Setting.cache_first - max_case_note = setting.try(:max_case_note) || 30 - case_note_frequency = setting.try(:case_note_frequency) || 'day' + max_case_note = setting.max_case_note || 30 + case_note_frequency = setting.case_note_frequency || 'day' case_note_period = max_case_note.send(case_note_frequency).ago case_note_overdue_ids = CaseNote.no_case_note_in(case_note_period).ids diff --git a/app/classes/advanced_searches/risk_assessment_fields.rb b/app/classes/advanced_searches/risk_assessment_fields.rb new file mode 100644 index 0000000000..2d26d8c4ea --- /dev/null +++ b/app/classes/advanced_searches/risk_assessment_fields.rb @@ -0,0 +1,61 @@ +module AdvancedSearches + class RiskAssessmentFields + extend AdvancedSearchHelper + extend ApplicationHelper + + def self.render + address_translation + group = format_header('risk_assessment') + level_of_risks = ['level_of_risk'].map { |item| drop_list_options(item, map_level_of_risks, group) } + date_of_risk_assessment = ['date_of_risk_assessment'].map { |item| date_picker_options(item, item, group) } + protection_concern_lists = protection_concern_list.map { |k, v| drop_list_options(k, v, group) } + (level_of_risks + date_of_risk_assessment + protection_concern_lists).sort_by { |f| f[:label].downcase } + end + + def self.date_picker_options(field_name, _, group) + { + id: field_name, + optgroup: group, + label: I18n.t('risk_assessments._attr.assessment_date'), + type: 'date', + operators: ['equal', 'not_equal', 'less', 'less_or_equal', 'greater', 'greater_or_equal', 'between', 'is_empty', 'is_not_empty'], + plugin: 'datepicker', + plugin_config: { + format: 'yyyy-mm-dd', + todayBtn: 'linked', + todayHighlight: true, + autoclose: true + } + } + end + + def self.drop_list_options(field_name, options, group) + field_translation = field_name == 'level_of_risk' ? 'current_level_of_risk' : field_name + { + id: field_name, + optgroup: group, + label: I18n.t("risk_assessments._attr.#{field_translation}"), + field: I18n.t("risk_assessments._attr.#{field_translation}"), + type: 'string', + input: 'select', + plugin: 'select2', + values: options.to_h, + data: { values: options.to_h }, + operators: ['equal', 'not_equal', 'is_empty', 'is_not_empty'] + } + end + + def self.map_level_of_risks + [Referral::LEVEL_OF_RISK, I18n.t('risk_assessments._attr.level_of_risks').values].transpose + end + + def self.protection_concern_list + yes_no_options = { true: 'Yes', false: 'No' } + [ + ['has_hiv_or_aid', yes_no_options], + ['has_disability', yes_no_options], + ['has_known_chronic_disease', yes_no_options] + ] + end + end +end diff --git a/app/classes/advanced_searches/risk_assessment_sql_builder.rb b/app/classes/advanced_searches/risk_assessment_sql_builder.rb new file mode 100644 index 0000000000..d966d247b5 --- /dev/null +++ b/app/classes/advanced_searches/risk_assessment_sql_builder.rb @@ -0,0 +1,119 @@ +module AdvancedSearches + class RiskAssessmentSqlBuilder + def initialize(clients, field_name, operator, value) + @clients = clients + @field_name = field_name + @operator = operator + @value = value + end + + def generate_sql + sql = build_sql_queries + + client_ids = ActiveRecord::Base.connection.execute(sql).map { |row| row['id'] } + { id: 'clients.id IN (?)', values: @clients.where(id: client_ids).ids } + end + + private + + def build_sql_queries + case @field_name + when 'level_of_risk' + build_level_of_risk_sql(@field_name) + when 'date_of_risk_assessment' + build_level_of_risk_sql('assessment_date') + when 'has_known_chronic_disease' + build_protection_concern_sql(@field_name) + when 'has_disability' + build_protection_concern_sql(@field_name) + when 'has_hiv_or_aid' + build_protection_concern_sql(@field_name) + else + 'SELECT id FROM clients' + end + end + + def build_protection_concern_sql(field_name) + case @operator + when 'equal' + build_risk_assessment_protect_concern_sql("#{field_name} = #{@value}") + when 'not_equal' + build_risk_assessment_protect_concern_sql("#{field_name} != #{@value}") + when 'is_empty' + build_risk_assessment_protect_concern_sql("#{field_name} IS NULL") + when 'is_not_empty' + build_risk_assessment_protect_concern_sql("#{field_name} IS NOT NULL") + else + 'SELECT id FROM clients' + end + end + + def build_risk_assessment_protect_concern_sql(field_condition) + <<~SQL + SELECT clients.id + FROM clients + LEFT JOIN risk_assessments ON risk_assessments.client_id = clients.id + WHERE ( + risk_assessments.#{field_condition} AND risk_assessments.client_id = clients.id + ) + SQL + end + + # SQL builders + + def build_level_of_risk_sql(field_name = 'level_of_risk') + case @operator + when 'equal' + build_risk_assessment_level_of_risk_sql("#{field_name} = '#{@value}'") + when 'not_equal' + build_risk_assessment_level_of_risk_sql("#{field_name} != '#{@value}'") + when 'is_empty' + build_risk_assessment_level_of_risk_sql("#{field_name} IS NULL") + when 'is_not_empty' + build_risk_assessment_level_of_risk_sql("#{field_name} IS NOT NULL") + when 'between' + build_risk_assessment_level_of_risk_sql("#{field_name} BETWEEN '#{@value[0]}' AND '#{@value[1]}'") + when 'less' + build_risk_assessment_level_of_risk_sql("#{field_name} < '#{@value}'") + when 'less_or_equal' + build_risk_assessment_level_of_risk_sql("#{field_name} <= '#{@value}'") + when 'greater' + build_risk_assessment_level_of_risk_sql("#{field_name} > '#{@value}'") + when 'greater_or_equal' + build_risk_assessment_level_of_risk_sql("#{field_name} >= '#{@value}'") + else + '' + end + end + + def build_risk_assessment_level_of_risk_sql(level_of_risk_sql) + assessment_sql = <<~SQL + SELECT client_id, level_of_risk, assessment_date + FROM assessments + WHERE created_at = ( + SELECT MAX(created_at) + FROM assessments + WHERE client_id = clients.id AND level_of_risk IS NOT NULL + ) + SQL + + <<~SQL + SELECT clients.id + FROM clients + LEFT JOIN risk_assessments ON risk_assessments.client_id = clients.id + WHERE ( + EXISTS ( + #{assessment_sql} + AND #{level_of_risk_sql} + AND client_id = clients.id + ) + OR ( + NOT EXISTS (#{assessment_sql}) + AND risk_assessments.#{level_of_risk_sql} + AND risk_assessments.client_id = clients.id + ) + ) + SQL + end + end +end diff --git a/app/classes/advanced_searches/rule_fields.rb b/app/classes/advanced_searches/rule_fields.rb index 28c0fb7667..4909349e5d 100644 --- a/app/classes/advanced_searches/rule_fields.rb +++ b/app/classes/advanced_searches/rule_fields.rb @@ -1,5 +1,5 @@ module AdvancedSearches - class RuleFields + class RuleFields include AdvancedSearchHelper include ClientsHelper include ApplicationHelper @@ -11,16 +11,16 @@ def initialize(options = {}) end def render - group = format_header('basic_fields') - number_fields = number_type_list.map { |item| AdvancedSearches::FilterTypes.number_options(item, format_header(item), group) } - text_fields = text_type_list.map { |item| AdvancedSearches::FilterTypes.text_options(item, format_header(item), group) } - date_picker_fields = date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), group) } - drop_list_fields = drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, group) } + group = format_header('basic_fields') + number_fields = number_type_list.map { |item| AdvancedSearches::FilterTypes.number_options(item, format_header(item), group) } + text_fields = text_type_list.map { |item| AdvancedSearches::FilterTypes.text_options(item, format_header(item), group) } + date_picker_fields = date_type_list.map { |item| AdvancedSearches::FilterTypes.date_picker_options(item, format_header(item), group) } + drop_list_fields = drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first, format_header(item.first), item.last, group) } default_domain_scores_options = enable_default_assessment? ? AdvancedSearches::DomainScoreFields.render : [] custom_domain_scores_options = enable_custom_assessment? ? AdvancedSearches::CustomDomainScoreFields.render : [] - school_grade_options = AdvancedSearches::SchoolGradeFields.render + school_grade_options = AdvancedSearches::SchoolGradeFields.render - search_fields = text_fields + drop_list_fields + number_fields + date_picker_fields + search_fields = text_fields + drop_list_fields + number_fields + date_picker_fields search_fields.sort_by { |f| f[:label].downcase } + default_domain_scores_options + custom_domain_scores_options + school_grade_options end @@ -36,12 +36,12 @@ def text_type_list end def date_type_list - ['date_of_birth', 'initial_referral_date', 'follow_up_date', 'exit_date', 'accepted_date', 'case_note_date', 'created_at','date_of_referral'] + ['date_of_birth', 'initial_referral_date', 'follow_up_date', 'exit_date', 'accepted_date', 'case_note_date', 'created_at', 'date_of_referral'] end def drop_down_type_list [ - ['created_by', user_select_options ], + ['created_by', user_select_options], ['gender', gender_list], ['status', client_status], ['agency_name', agencies_options], @@ -69,11 +69,11 @@ def gender_list end def case_note_type_options - [CaseNote::INTERACTION_TYPE, I18n.t('.case_notes.form.type_options').values].transpose.map { |k, v| { k => v } } + [CaseNote::INTERACTION_TYPE, I18n.t('.case_notes.form.type_options').values].transpose.map { |k, v| { k => v } } end def exit_reasons_options - ExitNgo::EXIT_REASONS.map { |s| { s => s } } + ExitNgo::EXIT_REASONS.map { |s| { s => s } } end def client_status @@ -84,7 +84,7 @@ def birth_provinces current_org = Organization.current.short_name provinces = [] Organization.switch_to 'shared' - Organization.pluck(:country).uniq.reject(&:blank?).each{ |country| provinces << Province.country_is(country).map{|p| { value: p.id.to_s, label: p.name, optgroup: country.titleize } } } + Organization.pluck(:country).uniq.reject(&:blank?).each { |country| provinces << Province.country_is(country).map { |p| { value: p.id.to_s, label: p.name, optgroup: country.titleize } } } Organization.switch_to current_org provinces.flatten end @@ -127,7 +127,7 @@ def donor_options def referral_to_options orgs = Organization.oscar.map { |org| { org.short_name => org.full_name } } - orgs << { "external referral" => "I don't see the NGO I'm looking for" } + orgs << { 'external referral' => "I don't see the NGO I'm looking for" } end def referral_from_options @@ -135,7 +135,7 @@ def referral_from_options end def setting_country_fields - country = Setting.cache_first.try(:country_name) || 'cambodia' + country = Setting.cache_first.country_name || 'cambodia' case country when 'cambodia' { @@ -150,7 +150,7 @@ def setting_country_fields when 'thailand' { text_fields: ['plot', 'road', 'postal_code'], - drop_down_fields: [['province_id', provinces], ['district_id', districts], ['subdistrict_id', subdistricts], ['birth_province_id', birth_provinces]] + drop_down_fields: [['province_id', provinces], ['district_id', districts], ['subdistrict_id', subdistricts]] } when 'myanmar' { diff --git a/app/classes/advanced_searches/service_sql_builder.rb b/app/classes/advanced_searches/service_sql_builder.rb index a6ce8a0921..d48821f8b5 100644 --- a/app/classes/advanced_searches/service_sql_builder.rb +++ b/app/classes/advanced_searches/service_sql_builder.rb @@ -2,8 +2,8 @@ module AdvancedSearches class ServiceSqlBuilder include FormBuilderHelper - def initialize() - basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules + def initialize + basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules @basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access end @@ -15,10 +15,9 @@ def get_sql results = mapping_program_stream_service_param_value(@basic_rules) query_string = get_program_service_query_string(results) - client_services = clients.where(query_string.reject(&:blank?).join(" AND ")).references(:services) + client_services = clients.where(query_string.reject(&:blank?).join(' AND ')).references(:services) { id: sql_string, values: client_services.ids.uniq } end - end end diff --git a/app/classes/advanced_searches/tracking_fields.rb b/app/classes/advanced_searches/tracking_fields.rb index 47a050cded..f2cadb3b17 100644 --- a/app/classes/advanced_searches/tracking_fields.rb +++ b/app/classes/advanced_searches/tracking_fields.rb @@ -22,7 +22,6 @@ def render drop_list_fields = @drop_down_type_list.map { |item| AdvancedSearches::FilterTypes.drop_list_options(item.first.gsub('"', '&qoute;'), format_label(item.first) , item.last, format_optgroup(item.first)) } results = text_fields + drop_list_fields + number_fields + date_picker_fields - results.sort_by { |f| f[:label].downcase } end def generate_field_by_type diff --git a/app/classes/chi_haiti.rb b/app/classes/chi_haiti.rb index 9e83ccde07..606fc0c4d8 100644 --- a/app/classes/chi_haiti.rb +++ b/app/classes/chi_haiti.rb @@ -1,12 +1,12 @@ - module ChiHaiti +module ChiHaiti class Import attr_accessor :path, :headers, :workbook, :workbook_second_row - def initialize(path='', sheets=[]) - @path = path - @workbook = Roo::Excelx.new(path) - @headers = {} - @sheets = sheets + def initialize(path = '', sheets = []) + @path = path + @workbook = Roo::Excelx.new(path) + @headers = {} + @sheets = sheets @workbook_second_row = 2 end @@ -24,18 +24,18 @@ def users user_password = Devise.friendly_token.first(8) (workbook_second_row..workbook.last_row).each do |row_index| new_user = {} - new_user['first_name'] = workbook.row(row_index)[headers['First Name']]&.squish - new_user['last_name'] = workbook.row(row_index)[headers['Last Name']]&.squish - new_user['email'] = workbook.row(row_index)[headers['*Email']]&.squish - new_user['password'] = user_password - new_user['gender'] = workbook.row(row_index)[headers['*Gender']]&.squish - new_user['roles'] = workbook.row(row_index)[headers['*Permission Level']].downcase - manager_name = workbook.row(row_index)[headers['Manager']] || '' - new_user['manager_id'] = User.find_by(first_name: manager_name).try(:id) unless new_user['roles'].include?("manager") - new_user['manager_ids'] = [new_user['manager_id']] + new_user['first_name'] = workbook.row(row_index)[headers['First Name']]&.squish + new_user['last_name'] = workbook.row(row_index)[headers['Last Name']]&.squish + new_user['email'] = workbook.row(row_index)[headers['*Email']]&.squish + new_user['password'] = user_password + new_user['gender'] = workbook.row(row_index)[headers['*Gender']]&.squish + new_user['roles'] = workbook.row(row_index)[headers['*Permission Level']].downcase + manager_name = workbook.row(row_index)[headers['Manager']] || '' + new_user['manager_id'] = User.find_by(first_name: manager_name).try(:id) unless new_user['roles'].include?('manager') + new_user['manager_ids'] = [new_user['manager_id']] user = find_or_initialize_by(new_user) - user.save(validate:false) + user.save(validate: false) end end @@ -45,30 +45,30 @@ def find_or_initialize_by(attributes, &block) def families (workbook_second_row..workbook.last_row).each do |row_index| - new_family = {} - new_family['name'] = workbook.row(row_index)[headers['*Name']] - new_family['code'] = workbook.row(row_index)[headers['*Family ID']] + new_family = {} + new_family['name'] = workbook.row(row_index)[headers['*Name']] + new_family['code'] = workbook.row(row_index)[headers['*Family ID']] new_family['family_type'] = workbook.row(row_index)[headers['*Family Type']] - new_family['status'] = workbook.row(row_index)[headers['*Family Status']] - province_name = workbook.row(row_index)[headers['Province / City']]&.squish - province = find_province(province_name) + new_family['status'] = workbook.row(row_index)[headers['*Family Status']] + province_name = workbook.row(row_index)[headers['Province / City']]&.squish + province = find_province(province_name) new_family['province_id'] = province&.id pry_if_blank?(new_family['province_id'], province_name) - district_name = workbook.row(row_index)[headers['District / Khan']]&.squish - district = find_district(province, district_name) + district_name = workbook.row(row_index)[headers['District / Khan']]&.squish + district = find_district(province, district_name) new_family['district_id'] = district&.id pry_if_blank?(new_family['district_id'], district_name) - commune_name = workbook.row(row_index)[headers['Commune / Sangkat']]&.squish - commune = find_commune(district, commune_name) - new_family['commune_id'] = commune&.id - village_name = workbook.row(row_index)[headers['Village']]&.squish || '' - new_family['village_id'] = find_village(commune, village_name)&.id if commune + commune_name = workbook.row(row_index)[headers['Commune / Sangkat']]&.squish + commune = find_commune(district, commune_name) + new_family['commune_id'] = commune&.id + village_name = workbook.row(row_index)[headers['Village']]&.squish || '' + new_family['village_id'] = find_village(commune, village_name)&.id if commune new_family['house'] = workbook.row(row_index)[headers['House#']] || '' new_family['street'] = workbook.row(row_index)[headers['Street']] || '' family = find_family_or_initialize_by(new_family) - family.save(validate:false) + family.save(validate: false) end end @@ -78,60 +78,60 @@ def find_family_or_initialize_by(attributes, &block) def donors (workbook_second_row..workbook.last_row).each do |row_index| - new_donor = {} - new_donor['name'] = workbook.row(row_index)[headers['*Name']] - new_donor['code'] = workbook.row(row_index)[headers['*Donor ID']] + new_donor = {} + new_donor['name'] = workbook.row(row_index)[headers['*Name']] + new_donor['code'] = workbook.row(row_index)[headers['*Donor ID']] new_donor['description'] = workbook.row(row_index)[headers['Description']] donor = Donor.find_by(new_donor.slice('name')) || Donor.new(new_donor) - donor.save(validate:false) + donor.save(validate: false) end end def clients (workbook_second_row..workbook.last_row).each do |row_index| - new_client = {} - new_client['given_name'] = workbook.row(row_index)[headers['Given Name (English)']] - new_client['family_name'] = workbook.row(row_index)[headers['Family Name (English)']] - new_client['gender'] = workbook.row(row_index)[headers['* Gender']]&.downcase - donor_name = workbook.row(row_index)[headers['Donor ID']] - new_client['donor_id'] = Donor.find_by(name: donor_name).try(:id) - - new_client['date_of_birth'] = workbook.row(row_index)[headers['Date of Birth']].to_s + new_client = {} + new_client['given_name'] = workbook.row(row_index)[headers['Given Name (English)']] + new_client['family_name'] = workbook.row(row_index)[headers['Family Name (English)']] + new_client['gender'] = workbook.row(row_index)[headers['* Gender']]&.downcase + donor_name = workbook.row(row_index)[headers['Donor ID']] + new_client['donor_id'] = Donor.find_by(name: donor_name).try(:id) + + new_client['date_of_birth'] = workbook.row(row_index)[headers['Date of Birth']].to_s begin - new_client['initial_referral_date'] = headers['* Date of Referral'].present? && workbook.row(row_index)[headers['* Date of Referral']] && workbook.row(row_index)[headers['* Date of Referral']].to_s&.presence.to_date.strftime("%Y-%m-%d") || Time.now.to_s + new_client['initial_referral_date'] = headers['* Date of Referral'].present? && workbook.row(row_index)[headers['* Date of Referral']] && workbook.row(row_index)[headers['* Date of Referral']].to_s&.presence.to_date.strftime('%Y-%m-%d') || Time.now.to_s rescue Exception => e binding.pry end - referral_source_category_name = headers['*Referral Source Category'] && workbook.row(row_index)[headers['*Referral Source Category']] || 'Non-Government Organization' - referral_source_name = headers['Referral Source'] && workbook.row(row_index)[headers['Referral Source']] || 'Church' + referral_source_category_name = headers['*Referral Source Category'] && workbook.row(row_index)[headers['*Referral Source Category']] || 'Non-Government Organization' + referral_source_name = headers['Referral Source'] && workbook.row(row_index)[headers['Referral Source']] || 'Church' new_client['referral_source_category_id'] = ReferralSource.find_by(name_en: referral_source_category_name)&.id - new_client['referral_source_id'] = find_or_create_referral_source(referral_source_name, new_client['referral_source_category_id']) + new_client['referral_source_id'] = find_or_create_referral_source(referral_source_name, new_client['referral_source_category_id']) - referee_name = headers['* Name of Referee'] && workbook.row(row_index)[headers['* Name of Referee']] || 'Anonymous' - referee_phone = headers['Referee Phone Number'] && workbook.row(row_index)[headers['Referee Phone Number']] || '123456789' - new_client['referee_id'] = create_referee(name: referee_name, phone: referee_phone) + referee_name = headers['* Name of Referee'] && workbook.row(row_index)[headers['* Name of Referee']] || 'Anonymous' + referee_phone = headers['Referee Phone Number'] && workbook.row(row_index)[headers['Referee Phone Number']] || '123456789' + new_client['referee_id'] = create_referee(name: referee_name, phone: referee_phone) - new_client['rated_for_id_poor'] = workbook.row(row_index)[headers['Is the Client Rated for ID Poor?']] || '' + new_client['rated_for_id_poor'] = workbook.row(row_index)[headers['Is the Client Rated for ID Poor?']] || '' new_client['has_been_in_orphanage'] = workbook.row(row_index)[headers['Has the client lived in an orphanage?']]&.squish&.downcase == 'yes' ? true : false new_client['has_been_in_government_care'] = workbook.row(row_index)[headers['Has the client lived in government care?']]&.squish&.downcase == 'yes' ? true : false - new_client['relevant_referral_information'] = workbook.row(row_index)[headers['Relevant Referral Information / Notes']] || '' - new_client['name_of_referee'] = workbook.row(row_index)[headers['* Name of Referee']] - received_by_name = workbook.row(row_index)[headers['* Receiving Staff Member']] || 'Cindy' - received_by_attr = { first_name: received_by_name.squish } - new_client['received_by_id'] = create_user_received_by(received_by_attr) - followed_up_by_name = workbook.row(row_index)[headers['First Follow-Up By']] - new_client['followed_up_by_id'] = User.find_by(first_name: followed_up_by_name).try(:id) - new_client['follow_up_date'] = workbook.row(row_index)[headers['First Follow-Up Date']] - new_client['school_name'] = workbook.row(row_index)[headers['School Name']] + new_client['relevant_referral_information'] = workbook.row(row_index)[headers['Relevant Referral Information / Notes']] || '' + new_client['name_of_referee'] = workbook.row(row_index)[headers['* Name of Referee']] + received_by_name = workbook.row(row_index)[headers['* Receiving Staff Member']] || 'Cindy' + received_by_attr = { first_name: received_by_name.squish } + new_client['received_by_id'] = create_user_received_by(received_by_attr) + followed_up_by_name = workbook.row(row_index)[headers['First Follow-Up By']] + new_client['followed_up_by_id'] = User.find_by(first_name: followed_up_by_name).try(:id) + new_client['follow_up_date'] = workbook.row(row_index)[headers['First Follow-Up Date']] + new_client['school_name'] = workbook.row(row_index)[headers['School Name']] new_client['main_school_contact'] = workbook.row(row_index)[headers['Main School Contact']] - grade = workbook.row(row_index)[headers['School Grade']] - new_client['school_grade'] = [Client::GRADES, I18n.t('advanced_search.fields.school_grade_list').values].transpose.to_h[grade] + grade = workbook.row(row_index)[headers['School Grade']] + new_client['school_grade'] = [Client::GRADES, I18n.t('advanced_search.fields.school_grade_list').values].transpose.to_h[grade] - province_name = workbook.row(row_index)[headers['Address - Current Province']] - district_name = workbook.row(row_index)[headers['Address - District']] - commune_name = workbook.row(row_index)[headers['Address - Municipality']] - locality = workbook.row(row_index)[headers['Address - Locality']] + province_name = workbook.row(row_index)[headers['Address - Current Province']] + district_name = workbook.row(row_index)[headers['Address - District']] + commune_name = workbook.row(row_index)[headers['Address - Municipality']] + locality = workbook.row(row_index)[headers['Address - Locality']] if province_name province = find_province(province_name.squish) @@ -141,40 +141,39 @@ def clients new_client['district_id'] = district&.id pry_if_blank?(new_client['district_id'], district_name) binding.pry if district.nil? - commune = find_commune(district, commune_name.squish, new_client) + commune = find_commune(district, commune_name.squish, new_client) new_client['commune_id'] = commune&.id pry_if_blank?(new_client['commune_id'], commune_name) new_client['locality'] = locality end - birth_province_name = workbook.row(row_index)[headers['Client Birth Province']] + birth_province_name = workbook.row(row_index)[headers['Client Birth Province']] if birth_province_name - new_client['birth_province_id'] = find_province(birth_province_name.squish)&.id + new_client['birth_province_id'] = find_province(birth_province_name.squish)&.id pry_if_blank?(new_client['birth_province_id'], birth_province_name) end - new_client['house_number'] = workbook.row(row_index)[headers['Address - House Number']] - new_client['street_number'] = workbook.row(row_index)[headers['Address - Street']] - new_client['code'] = workbook.row(row_index)[headers['Custom ID Number 1']] - new_client['kid_id'] = workbook.row(row_index)[headers['Custom ID Number 2']] - case_worker_name = workbook.row(row_index)[headers['* Case Worker / Staff']] - new_client['user_id'] = User.find_by(first_name: case_worker_name.split(' ').first).try(:id) if case_worker_name - new_client['user_ids'] = [new_client['user_id']] - - carer_name = workbook.row(row_index)[headers['Primary Carer Name']] - carer_name = (carer_name && carer_name[/(\w+\:\s?(\w+\s)+)|((\w+\s?)+(\(\w+\))?)/]).presence || carer_name - carer_phone = workbook.row(row_index)[headers['Primary Carer Phone Number']] + new_client['house_number'] = workbook.row(row_index)[headers['Address - House Number']] + new_client['street_number'] = workbook.row(row_index)[headers['Address - Street']] + new_client['code'] = workbook.row(row_index)[headers['Custom ID Number 1']] + new_client['kid_id'] = workbook.row(row_index)[headers['Custom ID Number 2']] + case_worker_name = workbook.row(row_index)[headers['* Case Worker / Staff']] + new_client['user_id'] = User.find_by(first_name: case_worker_name.split(' ').first).try(:id) if case_worker_name + new_client['user_ids'] = [new_client['user_id']] + + carer_name = workbook.row(row_index)[headers['Primary Carer Name']] + carer_name = (carer_name && carer_name[/(\w+\:\s?(\w+\s)+)|((\w+\s?)+(\(\w+\))?)/]).presence || carer_name + carer_phone = workbook.row(row_index)[headers['Primary Carer Phone Number']] new_client['carer_id'] = create_carer(name: carer_name, phone: carer_phone) if carer_name begin client = Client.find_by(new_client.slice('given_name', 'family_name')) || Client.new(new_client) client.save! - rescue Exception => e binding.pry end - family_name = workbook.row(row_index)[headers['Family ID']] - family = find_family(family_name) + family_name = workbook.row(row_index)[headers['Family ID']] + family = find_family(family_name) if family.present? family.children << client.id @@ -190,8 +189,8 @@ def clients def create_referee(attributes) if attributes[:name] && attributes[:name].downcase != 'unknown' referee = Referee.find_or_create_by(name: attributes[:name]) do |ref| - ref.phone = attributes[:phone] - end + ref.phone = attributes[:phone] + end else referee = Referee.create(name: 'Anonymous', anonymous: true) end @@ -201,13 +200,13 @@ def create_referee(attributes) def create_user_received_by(attributes) attribute = attributes.with_indifferent_access user = User.find_or_create_by(first_name: attribute['first_name']) do |user| - user.password = Devise.friendly_token.first(8) - user.last_name = attribute['last_name'] || attribute['first_name'] - user.gender = attribute['gender'] || 'other' - user.email = "#{attribute['first_name']}@childhope.org" - user.roles = 'case worker' - user.save - end + user.password = Devise.friendly_token.first(8) + user.last_name = attribute['last_name'] || attribute['first_name'] + user.gender = attribute['gender'] || 'other' + user.email = "#{attribute['first_name']}@childhope.org" + user.roles = 'case worker' + user.save + end user&.id end @@ -215,8 +214,8 @@ def create_user_received_by(attributes) def create_carer(attributes) attribute = attributes.with_indifferent_access carer = Carer.find_or_create_by(name: attribute['name']) do |care| - care.phone = attribute['phone'] - end + care.phone = attribute['phone'] + end carer&.id end @@ -226,27 +225,27 @@ def find_or_create_referral_source(name, parent_id) end def find_province(name) - province = Province.where("name ILIKE ?", "%#{name}").first + province = Province.where('name ILIKE ?', "%#{name}").first end def find_district(province, name) - districts = province.districts.where("name ILIKE ?", "%#{name}") + districts = province.districts.where('name ILIKE ?', "%#{name}") district = nil if districts.count == 1 district = districts.first else - puts "Error: districts" if name && name.downcase != 'n/a' + puts 'Error: districts' if name && name.downcase != 'n/a' end district end - def find_commune(district, name, new_client={}) + def find_commune(district, name, new_client = {}) communes = district && district.communes.where(name_en: name) commune = nil if communes && communes.count == 1 commune = communes.first else - puts "Error: communes" if name && name.downcase != 'n/a' + puts 'Error: communes' if name && name.downcase != 'n/a' end commune end @@ -257,7 +256,7 @@ def find_village(commune, name) if villages && villages.count == 1 village = villages.first else - puts "Error: villages" if name && name.downcase != 'n/a' + puts 'Error: villages' if name && name.downcase != 'n/a' end village end @@ -266,7 +265,7 @@ def find_family(family_id) Family.find_by(code: family_id) end - def pry_if_blank?(address, name='') + def pry_if_blank?(address, name = '') puts "Error: address #{address}, name: #{name}" if (name.present? && name.downcase != 'n/a') && address.blank? end end diff --git a/app/classes/client_columns_visibility.rb b/app/classes/client_columns_visibility.rb index bc757cab91..7388880ef0 100644 --- a/app/classes/client_columns_visibility.rb +++ b/app/classes/client_columns_visibility.rb @@ -84,7 +84,7 @@ def columns_collection gender_: :gender, date_of_birth_: :date_of_birth, status_: :status, - **Client::HOTLINE_FIELDS.map{ |field| ["#{field}_".to_sym, field.to_sym] }.to_h, + **Client::HOTLINE_FIELDS.map { |field| ["#{field}_".to_sym, field.to_sym] }.to_h, birth_province_id_: :birth_province_id, initial_referral_date_: :initial_referral_date, # referral_phone_: :referral_phone, @@ -133,11 +133,13 @@ def columns_collection any_assessments_: :any_assessments, case_note_date_: :case_note_date, case_note_type_: :case_note_type, + assessment_created_at_: :assessment_created_at, date_of_assessments_: :date_of_assessments, assessment_completed_date_: :assessment_completed_date, custom_completed_date_: :custom_completed_date, completed_date_: :completed_date, all_csi_assessments_: :all_csi_assessments, + custom_assessment_created_at_: :custom_assessment_created_at, date_of_custom_assessments_: :date_of_custom_assessments, all_custom_csi_assessments_: :all_custom_csi_assessments, all_result_framework_assessments_: :all_result_framework_assessments, @@ -160,7 +162,7 @@ def columns_collection referee_name_: :referee_name, referee_phone_: :referee_phone, referee_email_: :referee_email, - **Call::FIELDS.map{ |field| ["#{field}_".to_sym, field.to_sym] }.to_h, + **Call::FIELDS.map { |field| ["#{field}_".to_sym, field.to_sym] }.to_h, call_count: :call_count, carer_name_: :carer_name, carer_phone_: :carer_phone, @@ -172,19 +174,26 @@ def columns_collection address_type_: :address_type, client_email_: :client_email, indirect_beneficiaries_: :indirect_beneficiaries, + care_plan_date_: :care_plan_date, care_plan_completed_date_: :care_plan_completed_date, care_plan_count_: :care_plan_count, arrival_at_: :arrival_at, flight_nb_: :flight_nb, ratanak_achievement_program_staff_client_ids_: :ratanak_achievement_program_staff_client_ids, - mosavy_official_: :mosavy_official - }.merge(label_translations.keys.map{ |field| ["#{field}_".to_sym, field.to_sym] }.to_h) + mosavy_official_: :mosavy_official, + level_of_risk_: :level_of_risk, + date_of_risk_assessment_: :date_of_risk_assessment, + has_hiv_or_aid_: :has_hiv_or_aid, + has_known_chronic_disease_: :has_known_chronic_disease, + has_disability_: :has_disability + }.merge(label_translations.keys.map { |field| ["#{field}_".to_sym, field.to_sym] }.to_h) end def visible_columns return [] if @grid.nil? @grid.column_names = [] - client_default_columns = Setting.cache_first.try(:client_default_columns) + client_default_columns = Setting.cache_first.client_default_columns + params = @params.keys.select{ |k| k.match(/\_$/) } if params.present? && client_default_columns.present? defualt_columns = params - client_default_columns @@ -205,9 +214,8 @@ def visible_columns def domain_score_columns columns = columns_collection Domain.cache_order_by_identity.each do |domain| - identity = domain.identity field = domain.custom_domain ? "custom_#{domain.convert_identity}" : domain.convert_identity - columns = columns.merge!("#{field}_": field.to_sym) + columns.merge!("#{field}_": field.to_sym) end columns end @@ -216,7 +224,7 @@ def quantitative_type_columns columns = domain_score_columns QuantitativeType.cach_by_visible_on('client').each do |quantitative_type| field = quantitative_type.name - columns = columns.merge!("#{field}_": field.to_sym) + columns.merge!("#{field}_": field.to_sym) end columns end @@ -226,7 +234,7 @@ def add_custom_builder_columns if @params[:column_form_builder].present? @params[:column_form_builder].each do |column| field = column['id'] - columns = columns.merge!("#{field}_": field.to_sym) + columns.merge!("#{field}_": field.to_sym) end end columns @@ -234,6 +242,7 @@ def add_custom_builder_columns def client_default(column, setting_client_default_columns) return false if setting_client_default_columns.nil? + setting_client_default_columns.include?(column.to_s) if @params.dig(:client_grid, :descending).present? || (@params[:client_advanced_search].present? && @params.dig(:client_grid, :descending).present?) || @params[:client_grid].nil? || @params[:client_advanced_search].nil? end end diff --git a/app/classes/community_columns_visibility.rb b/app/classes/community_columns_visibility.rb index 2d3fde1310..a780e2441f 100644 --- a/app/classes/community_columns_visibility.rb +++ b/app/classes/community_columns_visibility.rb @@ -10,7 +10,8 @@ def columns_collection def visible_columns @grid.column_names = [] - community_default_columns = Setting.cache_first.try(:community_default_columns) + community_default_columns = Setting.cache_first.community_default_columns + params = @params.keys.select { |k| k.match(/\_$/) } if params.present? && community_default_columns.present? defualt_columns = params - community_default_columns diff --git a/app/classes/csi_statistic.rb b/app/classes/csi_statistic.rb index 47a51729f9..1c80455abc 100644 --- a/app/classes/csi_statistic.rb +++ b/app/classes/csi_statistic.rb @@ -1,15 +1,15 @@ class CsiStatistic def initialize(clients) @clients = clients - @@setting = Setting.cache_first + @setting = Setting.cache_first end def assessment_domain_score - if @@setting.enable_default_assessment? && @@setting.enable_custom_assessment? + if @setting.enable_default_assessment? && @setting.enable_custom_assessment? fetch_all_assessment_domain_score - elsif @@setting.enable_default_assessment? + elsif @setting.enable_default_assessment? fetch_default_assessment_domain_score - elsif @@setting.enable_custom_assessment? + elsif @setting.enable_custom_assessment? fetch_custom_assessment_domain_score end end @@ -28,7 +28,7 @@ def fetch_all_assessment_domain_score assessment_by_value = [] assessments_by_index.each do |a_ids| - a_domain_score = domain.assessment_domains.where(assessment_id: a_ids).pluck(:score).compact + a_domain_score = domain.assessment_domains.where(assessment_id: a_ids.compact.uniq).pluck(:score).compact assessment_by_value << (a_domain_score.sum.to_f / a_domain_score.size).round(2) end series << { name: domain.name, data: assessment_by_value } @@ -38,14 +38,21 @@ def fetch_all_assessment_domain_score end def assessment_amount + return @assessment_amount if defined?(@assessment_amount) + data = [] return data unless @clients && @clients.any? - clients = @clients.joins(:assessments).order('assessments.created_at') - max_count = clients.map { |a| a.assessments.size }.max.to_i + + clients = @clients.includes(:assessments).where('assessments.client_id IS NOT NULL').order('assessments.created_at') + assessment_ids = clients.map { |a| a.assessments.map(&:id) } + + max_count = assessment_ids.map { |ids| ids.size }.max.to_i + max_count.times do |i| - data << clients.includes(:assessments).map { |c| c.assessments[i].id if c.assessments[i].present? } + data << assessment_ids.map { |ids| ids[i] } end - data + + @assessment_amount = data end def fetch_default_assessment_domain_score @@ -59,7 +66,7 @@ def fetch_default_assessment_domain_score assessments_by_index.each do |a_ids| domain_scores = AssessmentDomain.where(assessment_id: a_ids).pluck(:domain_id, :score) - domain_scores.each{|domain_id, score| assessment_domains[domain_id.to_s] << score } + domain_scores.each { |domain_id, score| assessment_domains[domain_id.to_s] << score } end Domain.csi_domains.pluck(:id, :name).each do |id, name| @@ -71,18 +78,16 @@ def fetch_default_assessment_domain_score def default_assessment_amount data = [] - return data unless (@clients && @clients.any?) + return data unless @clients && @clients.any? clients = @clients.joins(:assessments).where(assessments: { default: true }).order('assessments.created_at') assessments_count = Client.maximum('assessments_count') client = Client.find_by(assessments_count: assessments_count) - assessment_max_count = client.assessments.defaults.count + # assessment_max_count = client.assessments.defaults.count data = clients.includes(:assessments).map { |c| c.assessments.defaults.ids } end def fetch_custom_assessment_domain_score - assessments_by_index = custom_assessment_amount - assessments = [] series = [] @@ -90,10 +95,13 @@ def fetch_custom_assessment_domain_score assessment_domains = Hash.new { |h, k| h[k] = [] } - assessments_by_index.each do |a_ids| - domain_scores = AssessmentDomain.where(assessment_id: a_ids).pluck(:domain_id, :score) - domain_scores.each{|domain_id, score| assessment_domains[domain_id.to_s] << score } + domain_data = AssessmentDomain.where(assessment_id: custom_assessment_amount.flatten).pluck(:domain_id, :score) + + custom_assessment_amount.each.with_index do |_a_ids, index| + domain_scores = domain_data[index] + domain_scores.each { |domain_id, score| assessment_domains[domain_id.to_s] << score } end + Domain.custom_csi_domains.pluck(:id, :name).each do |id, name| series << { name: name, data: assessment_domains[id.to_s].map(&:to_f) } end @@ -102,12 +110,6 @@ def fetch_custom_assessment_domain_score end def custom_assessment_amount - data = [] - return data unless @clients.any? - clients = @clients.includes(:assessments).where(assessments: { default: false }).order('assessments.created_at') - assessments_count = Client.maximum('assessments_count') - client = Client.find_by(assessments_count: assessments_count) - assessment_max_count = client.assessments.customs.count - data = clients.includes(:assessments).map { |c| c.assessments.customs.ids } + @custom_assessment_amount ||= @clients.includes(:custom_assessments).where('assessments.client_id IS NOT NULL').order('assessments.created_at').map { |c| c.custom_assessments.map(&:id) } end end diff --git a/app/classes/dashboard.rb b/app/classes/dashboard.rb index 2fe6c0297b..169ef8e6dc 100644 --- a/app/classes/dashboard.rb +++ b/app/classes/dashboard.rb @@ -2,14 +2,17 @@ class Dashboard include Rails.application.routes.url_helpers attr_reader :clients - def initialize(clients) - @clients = clients + def initialize(clients, family_only: false) @families = Family.active - @partners = Partner.all - @agencies = Agency.all - @staff = User.all - @referral_sources = ReferralSource.child_referrals.all - @program_streams = ProgramStream.joins(:client_enrollments).where(client_enrollments: { status: 'Active' }).distinct + + unless family_only + @clients = clients.select(:id, :status, :user_id) + @partners = Partner.all + @agencies = Agency.all + @staff = User.all + @referral_sources = ReferralSource.child_referrals.all + @program_streams = ProgramStream.joins(:client_enrollments).where(client_enrollments: { status: 'Active' }).distinct + end end def client_program_stream @@ -31,6 +34,8 @@ def client_program_stream end def family_type_statistic + return @family_type_statistic if @family_type_statistic.present? + arr = [] arr << { name: 'Long Term Foster Care', y: foster_count, url: families_path('family_grid[family_type]': 'Long Term Foster Care', 'family_grid[status]': 'Active') } if foster_count > 0 arr << { name: "Extended Family / Kinship Care", y: kinship_count, url: families_path('family_grid[family_type]': "Extended Family / Kinship Care", 'family_grid[status]': 'Active') } if kinship_count > 0 @@ -42,7 +47,8 @@ def family_type_statistic arr << { name: 'Child-Headed Household', y: child_headed_household_count, url: families_path('family_grid[family_type]': 'Child-Headed Household', 'family_grid[status]': 'Active') } if child_headed_household_count > 0 arr << { name: 'No Family', y: no_family_count, url: families_path('family_grid[family_type]': 'No Family', 'family_grid[status]': 'Active') } if no_family_count > 0 arr << { name: 'Other', y: other_count, url: families_path('family_grid[family_type]': 'Other', 'family_grid[status]': 'Active') } if other_count > 0 - arr + + @family_type_statistic = arr end def program_stream_report_gender @@ -74,55 +80,55 @@ def program_stream_report_gender end def family_count - @families.size + @family_count ||= @families.size end def foster_count - @families.foster.size + @foster_count ||= @families.foster.size end def kinship_count - @families.kinship.size + @kinship_count ||= @families.kinship.size end def emergency_count - @families.emergency.size + @emergency_count ||= @families.emergency.size end def birth_family_both_parents_count - @families.birth_family_both_parents.size + @birth_family_both_parents_count ||= @families.birth_family_both_parents.size end def birth_family_only_mother_count - @families.birth_family_only_mother.size + @birth_family_only_mother_count ||= @families.birth_family_only_mother.size end def birth_family_only_father_count - @families.birth_family_only_father.size + @birth_family_only_father_count ||= @families.birth_family_only_father.size end def domestically_adopted_count - @families.domestically_adopted.size + @domestically_adopted_count ||= @families.domestically_adopted.size end def child_headed_household_count - @families.child_headed_household.size + @child_headed_household_count ||= @families.child_headed_household.size end def no_family_count - @families.no_family.size + @no_family_count ||= @families.no_family.size end def other_count - @families.other.size + @other_count ||= @families.other.size end def referral_source_count - @referral_sources.size + @referral_source_count ||= @referral_sources.size end def program_stream_count - @program_streams.size + @program_stream_count ||= @program_streams.size end private diff --git a/app/classes/risk_assessment_reducer.rb b/app/classes/risk_assessment_reducer.rb index 1f46e1cf20..05da8e6afd 100644 --- a/app/classes/risk_assessment_reducer.rb +++ b/app/classes/risk_assessment_reducer.rb @@ -1,5 +1,6 @@ class RiskAssessmentReducer attr_reader :type, :risk_assessment, :risk_assessment_params + def initialize(client, risk_assessment_params, type = 'create') @risk_assessment = client.risk_assessment.present? ? client.risk_assessment : client.build_risk_assessment(risk_assessment_params) @risk_assessment_params = risk_assessment_params diff --git a/app/classes/user_notification.rb b/app/classes/user_notification.rb index 0215d0106d..d157e77873 100644 --- a/app/classes/user_notification.rb +++ b/app/classes/user_notification.rb @@ -14,9 +14,7 @@ def initialize(user, clients) @partner_custom_field = @user.partner_custom_field_frequency_overdue_or_due_today @family_custom_field = @user.family_custom_field_frequency_overdue_or_due_today @client_forms_overdue_or_due_today = @user.client_forms_overdue_or_due_today - @case_notes_overdue_and_due_today = @user.case_note_overdue_and_due_today - @unsaved_referrals = get_referrals('new_referral') - @repeat_referrals = get_referrals('existing_client') + @case_notes_overdue_and_due_today = @user.case_notes_due_today_and_overdue @unsaved_family_referrals = get_family_referrals('new_referral') @repeat_family_referrals = get_family_referrals('existing_family') @upcoming_csi_assessments_count = 0 @@ -29,15 +27,13 @@ def upcoming_csi_assessments client_ids = [] custom_client_ids = [] clients = active_young_clients(@clients) - if @user.deactivated_at.present? && clients.any? - clients = clients.where('clients.created_at > ?', @user.activated_at) - end + clients = clients.where('clients.created_at > ?', @user.activated_at) if @user.deactivated_at.present? && clients.any? default_clients = clients_have_recent_default_assessments(clients) custom_assessment_clients = clients_have_recent_custom_assessments(clients) - upcoming_csi_assessments_count = default_clients.count - upcoming_custom_csi_assessments_count = custom_assessment_clients.count + # upcoming_csi_assessments_count = default_clients.count + # upcoming_custom_csi_assessments_count = custom_assessment_clients.count { clients: default_clients, custom_clients: custom_assessment_clients } end @@ -66,7 +62,7 @@ def review_program_streams client_ids = client_ids & @clients.ids clients = Client.active_accepted_status.where(id: client_ids) - clients_after_filter = AdvancedSearches::ClientAdvancedSearch.new(rules, clients).filter + clients_after_filter, _query = AdvancedSearches::ClientAdvancedSearch.new(rules, clients).filter if clients_after_filter.any? clients_change = clients.where.not(id: clients_after_filter.ids).ids @@ -95,7 +91,7 @@ def any_due_today_tasks? end def overdue_assessments_count - @assessments[:overdue_count] + @assessments[:overdue_count] || 0 end def any_overdue_assessments? @@ -103,7 +99,7 @@ def any_overdue_assessments? end def due_today_assessments_count - @assessments[:due_today_count] + @assessments[:due_today]&.size || 0 end def any_due_today_assessments? @@ -111,7 +107,7 @@ def any_due_today_assessments? end def overdue_custom_assessments_count - @assessments[:custom_overdue_count] + @assessments[:custom_overdue_count] || 0 end def any_overdue_custom_assessments? @@ -119,7 +115,7 @@ def any_overdue_custom_assessments? end def due_today_custom_assessments_count - @assessments[:custom_due_today_count] + @assessments[:custom_due_today]&.size || 0 end def any_due_today_custom_assessments? @@ -247,11 +243,11 @@ def client_case_note_due_today end def unsaved_referrals - @unsaved_referrals + get_referrals[1] end def unsaved_referrals_count - @unsaved_referrals.count + unsaved_referrals.count end def any_unsaved_referrals? @@ -259,11 +255,11 @@ def any_unsaved_referrals? end def repeat_referrals - @repeat_referrals + get_referrals[0] end def repeat_referrals_count - @repeat_referrals.count + repeat_referrals.count end def any_repeat_referrals? @@ -334,28 +330,29 @@ def program_streams_by_user ProgramStream.where(id: program_ids).where.not(rules: '{}') end - def get_referrals(referral_type) - existing_client_referrals = [] - new_client_referrals = [] + def get_referrals + return @get_referrals if @get_referrals.present? - if @user.deactivated_at.nil? - referrals = Referral.received.unsaved - else - referrals = Referral.received.unsaved.where('created_at > ?', @user.activated_at) - end + referrals = Referral.received.unsaved + referrals = referrals.where('created_at > ?', @user.activated_at) if @user.deactivated_at? + slugs = referrals.pluck(:slug).select(&:present?).uniq + clients = Client.where("slug IN (:slugs) OR archived_slug IN (:slugs)", slugs: slugs) + + existinngs = [] + news = [] referrals.each do |referral| - referral_slug = referral.slug - client = Client.find_by(slug: referral_slug) || Client.find_by(archived_slug: referral_slug) + client = clients.find { |c| c.slug == referral.slug || c.archived_slug == referral.slug } + if client.present? - existing_client_referrals << referral + existinngs << referral referral.update_column(:client_id, client.id) unless referral.client_id else - new_client_referrals << referral + news << referral end end - referral_type == 'new_referral' ? new_client_referrals : existing_client_referrals + @get_referrals = [existinngs, news] end def get_family_referrals(referral_type) diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index d99535dc96..d3547fed19 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -2,24 +2,25 @@ class AdminController < ApplicationController protect_from_forgery with: :exception before_action :authenticate_user! - before_action :notify_user, :set_sidebar_basic_info + before_action :notify_user protected def notify_user - clients = Client.accessible_by(current_ability).non_exited_ngo - @notification = UserNotification.new(current_user, clients) + if preload_notifications? + clients = Client.none.accessible_by(current_ability).non_exited_ngo + @notification = UserNotification.new(current_user, clients) + else + @lazy_load_notification = true + end end - def set_sidebar_basic_info - @client_count = Client.accessible_by(current_ability).count - @family_count = Family.accessible_by(current_ability).count - @community_count = Community.accessible_by(current_ability).count - @user_count = User.where(deleted_at: nil).accessible_by(current_ability).count - @partner_count = Partner.count - @agency_count = Agency.count - @calls_count = Call.count - @referees_count = Referee.count - @referral_source_count = ReferralSource.count + def preload_notifications? + controller_name == 'notifications' || + (dashboard_request? && (params[:user_id] || current_user.case_worker? || current_user.manager?)) + end + + def dashboard_request? + controller_name == 'dashboards' && action_name == 'index' end end diff --git a/app/controllers/advanced_search_save_queries_controller.rb b/app/controllers/advanced_search_save_queries_controller.rb index 38830c9266..8f30046fb7 100644 --- a/app/controllers/advanced_search_save_queries_controller.rb +++ b/app/controllers/advanced_search_save_queries_controller.rb @@ -5,15 +5,17 @@ class AdvancedSearchSaveQueriesController < AdminController def new @advanced_search = AdvancedSearch.new + @advanced_search.search_for = 'family' if request.referer.include?('families') end def create @advanced_search = AdvancedSearch.new(advanced_search_params) @advanced_search.user_id = current_user.id + if @advanced_search.save - redirect_to clients_path(save_search_params(@advanced_search.search_params).merge(advanced_search_id: @advanced_search.id)), notice: t('activerecord.create.successfully_created') + redirect_to url_for([@advanced_search.search_for.pluralize.to_sym, saved_search_params]), notice: t('activerecord.create.successfully_created') else - redirect_to clients_path, alert: t('activerecord.create.failed_create') + redirect_to url_for([@advanced_search.search_for.pluralize.to_sym]), alert: t('activerecord.create.failed_create') end end @@ -22,7 +24,7 @@ def edit def update if @advanced_search.update_attributes(advanced_search_params) - redirect_to clients_path(save_search_params(@advanced_search.search_params).merge(advanced_search_id: @advanced_search.id)), notice: t('activerecord.update.successfully_updated') + redirect_to url_for([@advanced_search.search_for.pluralize.to_sym, saved_search_params]), notice: t('activerecord.update.successfully_updated') else render :edit end @@ -30,13 +32,19 @@ def update def destroy @advanced_search.destroy - redirect_to clients_path, notice: t('activerecord.destroy.successfully_deleted') + redirect_to url_for([@advanced_search.search_for.pluralize.to_sym]), notice: t('activerecord.destroy.successfully_deleted') end private + def saved_search_params + result = save_search_params(@advanced_search.search_params).merge(advanced_search_id: @advanced_search.id) + result[:family_advanced_search] = result.delete(:client_advanced_search) if @advanced_search.search_for_family? + result + end + def advanced_search_params - params.require(:advanced_search).permit(:name, :description, :queries, :enrollment_check, :tracking_check, :exit_form_check, :hotline_check, :field_visible, :quantitative_check, :custom_forms, :program_streams) + params.require(:advanced_search).permit(:name, :description, :queries, :enrollment_check, :tracking_check, :search_for, :exit_form_check, :hotline_check, :field_visible, :quantitative_check, :custom_forms, :program_streams) end def find_advanced_search diff --git a/app/controllers/api/application_controller.rb b/app/controllers/api/application_controller.rb index b885b13b16..bad20a2db9 100644 --- a/app/controllers/api/application_controller.rb +++ b/app/controllers/api/application_controller.rb @@ -15,5 +15,9 @@ def field_settings def pundit_user UserContext.new(current_user, field_settings) end + + def searched_client_ids + @searched_client_ids ||= Rails.cache.read(params[:cache_key]) if params[:cache_key] + end end end diff --git a/app/controllers/api/cities_controller.rb b/app/controllers/api/cities_controller.rb new file mode 100644 index 0000000000..2264a051eb --- /dev/null +++ b/app/controllers/api/cities_controller.rb @@ -0,0 +1,8 @@ +module Api + class CitiesController < Api::ApplicationController + def index + data = Province.find(params[:province_id]).cities + render json: { data: data } + end + end +end diff --git a/app/controllers/api/client_advanced_searches_controller.rb b/app/controllers/api/client_advanced_searches_controller.rb index 3a46fca6c1..02c76c5b49 100644 --- a/app/controllers/api/client_advanced_searches_controller.rb +++ b/app/controllers/api/client_advanced_searches_controller.rb @@ -8,7 +8,7 @@ def get_basic_field def get_custom_field custom_form_ids = params[:ids] advanced_filter_custom_field = AdvancedSearches::CustomFields.new(custom_form_ids).render - advanced_filter_custom_field << AdvancedSearches::HasThisFormFields.new(custom_form_ids).render.first + advanced_filter_custom_field += AdvancedSearches::HasThisFormFields.new(custom_form_ids, attach_with).render render json: advanced_filter_custom_field.compact end @@ -36,5 +36,11 @@ def get_program_stream_search_field advanced_filter_common_field = AdvancedSearches::CommonFields.new(program_stream_ids, assessment_checked).render render json: advanced_filter_common_field end + + private + + def attach_with + request.referer.include?('families') ? 'Family' : 'Client' + end end end diff --git a/app/controllers/api/clients_controller.rb b/app/controllers/api/clients_controller.rb index abf9827f3c..4acdb64f48 100644 --- a/app/controllers/api/clients_controller.rb +++ b/app/controllers/api/clients_controller.rb @@ -1,14 +1,15 @@ module Api class ClientsController < Api::ApplicationController include ClientAdvancedSearchesConcern + include ClientsConcern def search_client - clients = Client.all.where("given_name ILIKE ? OR family_name ILIKE ? OR local_given_name ILIKE ? OR local_family_name ILIKE ? OR slug ILIKE ?", "%#{params[:q]}%", "%#{params[:q]}%", "%#{params[:q]}%", "%#{params[:q]}%", "%#{params[:q]}%").select(:id, :slug, :given_name, :family_name, :local_given_name, :local_family_name) + clients = Client.all.where('given_name ILIKE ? OR family_name ILIKE ? OR local_given_name ILIKE ? OR local_family_name ILIKE ? OR slug ILIKE ?', "%#{params[:q]}%", "%#{params[:q]}%", "%#{params[:q]}%", "%#{params[:q]}%", "%#{params[:q]}%").select(:id, :slug, :given_name, :family_name, :local_given_name, :local_family_name) render json: clients, serializer: false end def compare - render json: find_client_in_organization + render json: { similar_fields: Client.find_shared_client(params)[:similar_fields] } end def render_client_statistics @@ -18,12 +19,26 @@ def render_client_statistics def find_client_case_worker client = Client.find(params[:id]) user_ids = client.users.non_strategic_overviewers.where.not(id: params[:user_id]).ids - render json: { user_ids: user_ids } + render json: { user_ids: user_ids } end def assessments - @assessments_count ||= Assessment.joins(:client).where(default: params[:default], client_id: params[:client_ids].split('/')).count - render json: { recordsTotal: @assessments_count, recordsFiltered: @assessments_count, data: data } + $param_rules = params + + client_ids = if searched_client_ids.present? + searched_client_ids.split(',') + else + basic_rules = JSON.parse(params[:basic_rules] || '{}') + clients, _query = AdvancedSearches::ClientAdvancedSearch.new(basic_rules, Client.accessible_by(current_ability)).filter + clients.ids + end + + assessments = Assessment.joins(:client).where(default: params[:default], client_id: client_ids) + assessments = assessments.joins(:custom_assessment_setting).where(custom_assessment_settings: { id: params[:assessment_id] }) if params[:assessment_id].present? + + @assessments_count = assessments.count + + render json: { recordsTotal: @assessments_count, recordsFiltered: @assessments_count, data: data } end def create @@ -51,7 +66,6 @@ def create client.carer_id = carer.id client_saved = client.save end - if client_saved qtt_free_text_cases = params[:client_quantitative_free_text_cases] @@ -68,6 +82,9 @@ def create risk_assessment.store end + custom_data = CustomData.first + client.create_client_custom_data(custom_data_params.merge(custom_data_id: custom_data.id)) if custom_data && params.key?(:custom_data) + render json: { slug: client.slug, id: client.id }, status: :ok else render json: client.errors, status: :unprocessable_entity @@ -102,8 +119,17 @@ def update risk_assessment.store end + custom_data = CustomData.first + if custom_data && params.key?(:custom_data) + if client.client_custom_data&.persisted? + client.client_custom_data.update_attributes(custom_data_params) + else + client.create_client_custom_data(custom_data_params.merge(custom_data_id: custom_data.id)) + end + end + if params[:client][:assessment_id] - assessment = Assessment.find(params[:client][:assessment_id]) + Assessment.find(params[:client][:assessment_id]) else render json: { slug: client.slug }, status: :ok end @@ -126,13 +152,13 @@ def render_client_by_gender end def render_active_client_by_donor - data = Donor.includes(:clients).references(:clients).where(clients: { id: Client.accessible_by(current_ability).active_status.ids }).group("donors.name").count("clients.id") + data = Donor.includes(:clients).references(:clients).where(clients: { id: Client.accessible_by(current_ability).active_status.ids }).group('donors.name').count('clients.id') donors = Donor.pluck(:name, :id) donor_data = data.map do |donor_name, client_count| - url = { "condition"=>"AND", "rules"=> [ - {"id"=>"status", "field"=>"Status", "type"=>"string", "input"=>"select", "operator"=>"equal", "value"=>"Active", "data"=>{"values"=>[{"Accepted"=>"Accepted"}, {"Active"=>"Active"}, {"Exited"=>"Exited"}, {"Referred"=>"Referred"}], "isAssociation"=>false }}, - {"id"=>"donor_name", "field"=>"Donor", "type"=>"string", "input"=>"select", "operator"=>"equal", "value"=> donors.to_h[donor_name], "data"=> { "values"=> donors.reverse.to_h, "isAssociation"=> true }, "valid"=>true } - ]} + url = { 'condition' => 'AND', 'rules' => [ + { 'id' => 'status', 'field' => 'Status', 'type' => 'string', 'input' => 'select', 'operator' => 'equal', 'value' => 'Active', 'data' => { 'values' => [{ 'Accepted' => 'Accepted' }, { 'Active' => 'Active' }, { 'Exited' => 'Exited' }, { 'Referred' => 'Referred' }], 'isAssociation' => false } }, + { 'id' => 'donor_name', 'field' => 'Donor', 'type' => 'string', 'input' => 'select', 'operator' => 'equal', 'value' => donors.to_h[donor_name], 'data' => { 'values' => donors.reverse.to_h, 'isAssociation' => true }, 'valid' => true } + ] } { name: donor_name, @@ -161,96 +187,96 @@ def client_params end client_param = params.require(:client).permit( - :slug, :archived_slug, :code, :name_of_referee, :main_school_contact, :rated_for_id_poor, :what3words, :status, :country_origin, - :kid_id, :assessment_id, :given_name, :family_name, :local_given_name, :local_family_name, :gender, :date_of_birth, - :birth_province_id, :initial_referral_date, :referral_source_id, :telephone_number, - :referral_phone, :received_by_id, :followed_up_by_id, :current_family_id, - :follow_up_date, :school_grade, :school_name, :current_address, :locality, - :house_number, :street_number, :suburb, :description_house_landmark, :directions, :street_line1, :street_line2, :plot, :road, :postal_code, :district_id, :subdistrict_id, - :has_been_in_orphanage, :has_been_in_government_care, :shared_service_enabled, - :relevant_referral_information, :province_id, :global_id, :external_id, :external_id_display, :mosvy_number, - :state_id, :township_id, :rejected_note, :live_with, :profile, :remove_profile, - :gov_city, :gov_commune, :gov_district, :gov_date, :gov_village_code, :gov_client_code, - :gov_interview_village, :gov_interview_commune, :gov_interview_district, :gov_interview_city, - :gov_caseworker_name, :gov_caseworker_phone, :gov_carer_name, :gov_carer_relationship, :gov_carer_home, - :gov_carer_street, :gov_carer_village, :gov_carer_commune, :gov_carer_district, :gov_carer_city, :gov_carer_phone, - :gov_information_source, :gov_referral_reason, :gov_guardian_comment, :gov_caseworker_comment, :commune_id, :village_id, :referral_source_category_id, :referee_id, :carer_id, - :address_type, :phone_owner, :client_phone, :client_email, :referee_relationship, :outside, :outside_address, :location_description, - :presented_id, :legacy_brcs_id, :id_number, :whatsapp, :other_phone_whatsapp, :other_phone_number, :brsc_branch, :current_island, :current_street, - :current_po_box, :current_settlement, :current_resident_own_or_rent, :current_household_type, - :island2, :street2, :po_box2, :settlement2, :preferred_language, :resident_own_or_rent2, :household_type2, - :nickname, :relation_to_referee, :concern_is_outside, :concern_outside_address, - :concern_province_id, :concern_district_id, :concern_commune_id, :concern_village_id, - :concern_street, :concern_house, :concern_address, :concern_address_type, - :concern_phone, :concern_phone_owner, :concern_email, :concern_email_owner, :concern_location, - :national_id, :reason_for_referral, :for_testing, - :birth_cert, - :arrival_at, - :flight_nb, - :family_book, - :marital_status, - :nationality, - :ethnicity, - :location_of_concern, - :neighbor_name, - :neighbor_phone, - :dosavy_name, - :dosavy_phone, - :chief_commune_name, - :chief_commune_phone, - :chief_village_name, - :chief_village_phone, - :ccwc_name, - :ccwc_phone, - :legal_team_name, - :legal_representative_name, - :legal_team_phone, - :other_agency_name, - :other_representative_name, - :other_agency_phone, - :type_of_trafficking, - :education_background, - :department, - :passport, - :passport_number, - :national_id_number, - :travel_doc, - :referral_doc, - :local_consent, - :police_interview, - :other_legal_doc, - :remove_national_id_files, - :remove_birth_cert_files, - :remove_family_book_files, - :remove_passport_files, - :remove_travel_doc_files, - :remove_referral_doc_files, - :remove_local_consent_files, - :remove_police_interview_files, - :remove_other_legal_doc_files, - *legal_doc_params, - ratanak_achievement_program_staff_client_ids: [], - birth_cert_files: [], - family_book_files: [], - passport_files: [], - travel_doc_files: [], - local_consent_files: [], - police_interview_files: [], - other_legal_doc_files: [], - interviewee_ids: [], - client_type_ids: [], - user_ids: [], - agency_ids: [], - donor_ids: [], - quantitative_case_ids: [], - custom_field_ids: [], - family_ids: [], - mo_savy_officials_attributes: [:id, :name, :position, :_destroy], - family_member_attributes: [:id, :family_id, :_destroy], - tasks_attributes: [:name, :domain_id, :completion_date], - client_needs_attributes: [:id, :rank, :need_id], - client_problems_attributes: [:id, :rank, :problem_id] - ) + :slug, :archived_slug, :code, :name_of_referee, :main_school_contact, :rated_for_id_poor, :what3words, :status, :country_origin, + :kid_id, :assessment_id, :given_name, :family_name, :local_given_name, :local_family_name, :gender, :date_of_birth, + :birth_province_id, :initial_referral_date, :referral_source_id, :telephone_number, + :referral_phone, :received_by_id, :followed_up_by_id, :current_family_id, + :follow_up_date, :school_grade, :school_name, :current_address, :locality, + :house_number, :street_number, :suburb, :description_house_landmark, :directions, :street_line1, :street_line2, :plot, :road, :postal_code, :district_id, :subdistrict_id, + :has_been_in_orphanage, :has_been_in_government_care, :shared_service_enabled, + :relevant_referral_information, :province_id, :city_id, :global_id, :external_id, :external_id_display, :mosvy_number, + :state_id, :township_id, :rejected_note, :live_with, :profile, :remove_profile, + :gov_city, :gov_commune, :gov_district, :gov_date, :gov_village_code, :gov_client_code, + :gov_interview_village, :gov_interview_commune, :gov_interview_district, :gov_interview_city, + :gov_caseworker_name, :gov_caseworker_phone, :gov_carer_name, :gov_carer_relationship, :gov_carer_home, + :gov_carer_street, :gov_carer_village, :gov_carer_commune, :gov_carer_district, :gov_carer_city, :gov_carer_phone, + :gov_information_source, :gov_referral_reason, :gov_guardian_comment, :gov_caseworker_comment, :commune_id, :village_id, :referral_source_category_id, :referee_id, :carer_id, + :address_type, :phone_owner, :client_phone, :client_email, :referee_relationship, :outside, :outside_address, :location_description, + :presented_id, :legacy_brcs_id, :id_number, :whatsapp, :other_phone_whatsapp, :other_phone_number, :brsc_branch, :current_island, :current_street, + :current_po_box, :current_settlement, :current_resident_own_or_rent, :current_household_type, + :island2, :street2, :po_box2, :settlement2, :preferred_language, :resident_own_or_rent2, :household_type2, + :nickname, :relation_to_referee, :concern_is_outside, :concern_outside_address, + :concern_province_id, :concern_district_id, :concern_commune_id, :concern_village_id, + :concern_street, :concern_house, :concern_address, :concern_address_type, + :concern_phone, :concern_phone_owner, :concern_email, :concern_email_owner, :concern_location, + :national_id, :reason_for_referral, :for_testing, :from_referral_id, + :birth_cert, + :arrival_at, + :flight_nb, + :family_book, + :marital_status, + :nationality, + :ethnicity, + :location_of_concern, + :neighbor_name, + :neighbor_phone, + :dosavy_name, + :dosavy_phone, + :chief_commune_name, + :chief_commune_phone, + :chief_village_name, + :chief_village_phone, + :ccwc_name, + :ccwc_phone, + :legal_team_name, + :legal_representative_name, + :legal_team_phone, + :other_agency_name, + :other_representative_name, + :other_agency_phone, + :type_of_trafficking, + :education_background, + :department, + :passport, + :passport_number, + :national_id_number, + :travel_doc, + :referral_doc, + :local_consent, + :police_interview, + :other_legal_doc, + :remove_national_id_files, + :remove_birth_cert_files, + :remove_family_book_files, + :remove_passport_files, + :remove_travel_doc_files, + :remove_referral_doc_files, + :remove_local_consent_files, + :remove_police_interview_files, + :remove_other_legal_doc_files, + *legal_doc_params, + ratanak_achievement_program_staff_client_ids: [], + birth_cert_files: [], + family_book_files: [], + passport_files: [], + travel_doc_files: [], + local_consent_files: [], + police_interview_files: [], + other_legal_doc_files: [], + interviewee_ids: [], + client_type_ids: [], + user_ids: [], + agency_ids: [], + donor_ids: [], + quantitative_case_ids: [], + custom_field_ids: [], + family_ids: [], + mo_savy_officials_attributes: [:id, :name, :position, :_destroy], + family_member_attributes: [:id, :family_id, :_destroy], + tasks_attributes: [:name, :domain_id, :completion_date], + client_needs_attributes: [:id, :rank, :need_id], + client_problems_attributes: [:id, :rank, :problem_id] + ) field_settings.each do |field_setting| next if field_setting.group != 'client' || field_setting.required? || field_setting.visible? @@ -259,39 +285,34 @@ def client_params end if params[:family_member] - client_param[:family_member_attributes] = params[:family_member].permit([:id, :family_id]) + client_param[:family_member_attributes] = params[:family_member].permit(%i[id family_id]) - if client_param[:family_member_attributes].present? - client_param[:family_member_attributes][:_destroy] = 1 if client_param.dig(:family_member_attributes, :family_id).blank? - end + client_param[:family_member_attributes][:_destroy] = 1 if client_param[:family_member_attributes].present? && client_param.dig(:family_member_attributes, :family_id).blank? end client_param end - def referee_params - params.require(:referee).permit( - :name, :phone, :outside, :address_type, :commune_id, :current_address, :district_id, :email, :gender, :house_number, :outside_address, :province_id, :street_number, :village_id, :anonymous, - :state_id, :township_id, :subdistrict_id, :street_line1, :street_line2, :plot, :road, :postal_code, :suburb, :description_house_landmark, :directions, :locality - ) - end - - def carer_params - params.require(:carer).permit( - :name, :phone, :outside, :address_type, :current_address, :email, :gender, :house_number, :street_number, :outside_address, :commune_id, :district_id, :province_id, :village_id, :client_relationship, :same_as_client, - :state_id, :township_id, :subdistrict_id, :street_line1, :street_line2, :plot, :road, :postal_code, :suburb, :description_house_landmark, :directions, :locality - ) + def find_client_in_organization + results = [] + similar_fields = Client.find_shared_client(params) + { similar_fields: similar_fields } end - def risk_assessment_params - return if params.dig(:risk_assessment).nil? - params.require(:risk_assessment).permit( - :assessment_date, :other_protection_concern_specification, :client_perspective, :has_known_chronic_disease, - :has_disability, :has_hiv_or_aid, :known_chronic_disease_specification, :disability_specification, :hiv_or_aid_specification, - :relevant_referral_information, :level_of_risk, :history_of_disability_id, :history_of_harm_id, :history_of_high_risk_behaviour_id, - :history_of_family_separation_id, protection_concern: [], - tasks_attributes: [:id, :name, :expected_date, :client_id, :_destroy] - ) + def custom_data_params + if params.dig(:custom_data, :properties) + param_array = [] + params.dig(:custom_data, :properties).each { |k, v| param_array << [k, v.first.is_a?(Hash) ? v.first.keys : []] if v.is_a?(Array) } + property_keys = params.dig(:custom_data, :properties).try(:keys) + params.require(:custom_data).permit( + properties: property_keys << param_array.to_h, + form_builder_attachments_attributes: [:id, :name, { file: [] }] + ) + else + params.require(:custom_data).permit( + form_builder_attachments_attributes: [:id, :name, { file: [] }] + ) + end end def find_client_in_organization @@ -318,11 +339,10 @@ def data end client_hash = { slug: assessment.client.slug, - name: assessment.client.en_and_local_name, - 'assessment-number': assessment.client.assessments.where(default: params[:default]).count, - date: assessment.created_at.strftime('%d %B %Y'), - 'average-score': total == 0 ? nil : (total.fdiv(domain_scores.length())).round() - } + name: assessment.client.en_and_local_name, + 'assessment-number': assessment.client.assessments.where(default: params[:default]).count, + date: assessment.created_at.strftime('%d %B %Y'), + 'average-score': total == 0 ? nil : (total.fdiv(domain_scores.length())).round() } client_hash.merge!(domain_scores.to_h) client_data << client_hash end @@ -335,11 +355,11 @@ def assessment_data end def fetch_assessments - assessments = Assessment.joins(:client).where(default: params[:default], client_id: params[:client_ids].split('/')) - assessments = assessments.includes(:assessment_domains).order("#{sort_column} #{sort_direction}").references(:assessment_domains, :client) + basic_rules = JSON.parse(params[:basic_rules] || '{}') + clients, _query = AdvancedSearches::ClientAdvancedSearch.new(basic_rules, Client.accessible_by(current_ability)).filter - basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules - @basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules || "{}").with_indifferent_access + assessments = Assessment.joins(:client).where(default: params[:default], client_id: clients.ids) + assessments = assessments.includes(:assessment_domains).order("#{sort_column} #{sort_direction}").references(:assessment_domains, :client) assessment_data = params[:length] != '-1' ? assessments.page(page).per(per_page) : assessments end @@ -349,7 +369,7 @@ def domains end def page - params[:start].to_i/per_page + 1 + params[:start].to_i / per_page + 1 end def per_page @@ -357,21 +377,21 @@ def per_page end def sort_column - domains_fields = domains.map { |domain| "assessment_domains.score" } - columns = ["regexp_replace(clients.slug, '\\D*', '', 'g')::int", "clients.given_name", "clients.assessments_count", "assessments.created_at", *domains_fields] + domains_fields = domains.map { |domain| 'assessment_domains.score' } + columns = ["regexp_replace(clients.slug, '\\D*', '', 'g')::int", 'clients.given_name', 'clients.assessments_count', 'assessments.created_at', *domains_fields] columns[params[:order]['0']['column'].to_i] end def sort_direction - params[:order]['0']['dir'] == "desc" ? "desc" : "asc" + params[:order]['0']['dir'] == 'desc' ? 'desc' : 'asc' end def adule_client_gender_count(clients, type = :male) - clients.public_send(type).where("(EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) >= ?", 18).count + clients.public_send(type).where('(EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) >= ?', 18).count end def under_18_client_gender_count(clients, type = :male) - clients.public_send(type).where("(EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) < ?", 18).count + clients.public_send(type).where('(EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) < ?', 18).count end def other_client_gender_count(clients) diff --git a/app/controllers/api/districts_controller.rb b/app/controllers/api/districts_controller.rb index ef0aaa0442..f9b89be93e 100644 --- a/app/controllers/api/districts_controller.rb +++ b/app/controllers/api/districts_controller.rb @@ -1,7 +1,12 @@ module Api class DistrictsController < Api::ApplicationController def index - data = Province.find(params[:province_id]).districts + if Organization.current.country == 'indonesia' + data = City.find(params[:city_id]).districts + else + data = Province.find(params[:province_id]).districts + end + render json: { data: data } end end diff --git a/app/controllers/api/referrals_controller.rb b/app/controllers/api/referrals_controller.rb index 2b256050b6..5e7d909e3f 100644 --- a/app/controllers/api/referrals_controller.rb +++ b/app/controllers/api/referrals_controller.rb @@ -7,8 +7,17 @@ def compare render json: find_client_in_organization end + def update + referral = Referral.find(params[:id]) + if referral.update_attributes(params.require(:referral).permit(:referral_status)) + render json: { referral_status: referral.referral_status }, status: :ok + else + render json: referral.errors, status: :unprocessable_entity + end + end + def find_client_in_organization - if params[:org] == 'external referral' + if params[:org] == 'external referral' || params[:org] == 'external-referral' || params[:org] == 'mosvy-external-system' { text: 'create referral' } else Organization.switch_to params[:org] diff --git a/app/controllers/api/v1/assessments_controller.rb b/app/controllers/api/v1/assessments_controller.rb index 58971f529b..db64cc4d9f 100644 --- a/app/controllers/api/v1/assessments_controller.rb +++ b/app/controllers/api/v1/assessments_controller.rb @@ -1,6 +1,8 @@ module Api module V1 class AssessmentsController < Api::V1::BaseApiController + include AssessmentConcern + before_action :find_client def create @@ -15,8 +17,9 @@ def create def update params[:assessment][:assessment_domains_attributes].each do |assessment_domain| - add_more_attachments(assessment_domain.second[:attachments], assessment_domain.second[:id]) + add_more_attachments(assessment_domain[:attachments], assessment_domain[:id]) end + assessment = @client.assessments.find(params[:id]) if assessment.update_attributes(assessment_params) assessment.update(updated_at: DateTime.now) @@ -29,29 +32,19 @@ def update def destroy if params[:file_index].present? remove_attachment_at_index(params[:file_index].to_i) - head 204 end + + head 204 if Assessment.find(params[:id]).destroy end private def assessment_params - - default_params = params.require(:assessment).permit(:default, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal]) - default_params = params.require(:assessment).permit(:default, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, attachments: []]) if action_name == 'create' + default_params = params.require(:assessment).permit(:default, :assessment_date, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last]) + default_params = params.require(:assessment).permit(:default, :assessment_date, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last, attachments: []]) if action_name == 'create' default_params end - def add_more_attachments(new_file, assessment_domain_id) - if new_file.present? - assessment_domain = AssessmentDomain.find(assessment_domain_id) - files = assessment_domain.attachments - files += new_file - assessment_domain.attachments = files - assessment_domain.save - end - end - def remove_attachment_at_index(index) assessment_domain = AssessmentDomain.find(params[:assessment_domain]) remain_attachment = assessment_domain.attachments @@ -60,7 +53,6 @@ def remove_attachment_at_index(index) remain_attachment.empty? ? assessment_domain.remove_attachments! : (assessment_domain.attachments = remain_attachment ) message = t('.fail_delete_attachment') unless assessment_domain.save end - end end end diff --git a/app/controllers/api/v1/care_plans_controller.rb b/app/controllers/api/v1/care_plans_controller.rb new file mode 100644 index 0000000000..badd715346 --- /dev/null +++ b/app/controllers/api/v1/care_plans_controller.rb @@ -0,0 +1,61 @@ +module Api + module V1 + class CarePlansController < Api::V1::BaseApiController + include CreateNestedValue + + before_action :find_client + before_action :find_care_plan, except: [:index, :create] + + def index + care_plans = @client.care_plans + render json: care_plans + end + + def show + render json: @care_plan + end + + def create + care_plan = @client.care_plans.new(care_plan_params) + assessment = Assessment.find(care_plan.assessment_id) + if assessment.care_plan.nil? && care_plan.save + render json: care_plan + else + render json: care_plan.errors, status: :unprocessable_entity + end + end + + def update + if @care_plan.update_attributes(care_plan_params) + render json: @care_plan + else + render json: @care_plan.errors, status: :unprocessable_entity + end + end + + private + + def care_plan_params + params.require(:care_plan).permit( + :assessment_id, :client_id, :care_plan_date, :completed, + goals_attributes: [ + :id, :assessment_domain_id, :assessment_id, :description, :_destroy, + { + tasks_attributes: [ + :id, :domain_id, :name, :expected_date, :relation, :user_id, :client_id, :family_id, :previous_id, :goal_id, :_destroy + ] + } + ] + ) + end + + def find_client + @client = Client.find(params[:client_id]) + end + + def find_care_plan + @care_plan = @client.care_plans.find(params[:id]) + end + end + end +end diff --git a/app/controllers/api/v1/case_notes_controller.rb b/app/controllers/api/v1/case_notes_controller.rb index a26638c95c..a88819c3fe 100644 --- a/app/controllers/api/v1/case_notes_controller.rb +++ b/app/controllers/api/v1/case_notes_controller.rb @@ -2,16 +2,35 @@ module Api module V1 class CaseNotesController < Api::V1::BaseApiController include CaseNoteConcern + include CreateBulkTask + include GoogleCalendarServiceConcern before_action :find_client + def show + case_note = CaseNote.find(params[:id]) + render json: case_note + end + def create case_note = @client.case_notes.new(case_note_params) case_note.assessment = @client.assessments.custom_latest_record + case_note.meeting_date = "#{case_note.meeting_date.strftime("%Y-%m-%d")}, #{Time.now.strftime("%H:%M:%S")}" if case_note.save - case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) + case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) if params.dig(:case_note, :case_note_domain_groups_attributes) + create_bulk_task(params[:task], case_note) if params.key?(:task) + case_note.complete_screening_tasks(params) if params[:case_note].key?(:tasks_attributes) + + create_task_task_progress_notes render json: case_note else + if case_note_params[:custom] == 'true' + @custom_assessment_param = case_note_params[:custom] + case_note.assessment = @client.assessments.custom_latest_record + else + case_note.assessment = @client.assessments.default_latest_record + end + render json: case_note.errors, status: :unprocessable_entity end end @@ -20,10 +39,14 @@ def update case_note = @client.case_notes.find(params[:id]) if case_note.update_attributes(case_note_params) - params[:case_note][:case_note_domain_groups_attributes].each do |d| - add_more_attachments(d.second[:attachments], d.second[:id]) + if params.dig(:case_note, :case_note_domain_groups_attributes) + case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) end - case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) + create_bulk_task(params[:task], case_note) if params.key?(:task) + case_note.complete_screening_tasks(params) if params[:case_note].key?(:tasks_attributes) + # create_task_task_progress_notes + delete_events if session[:authorization] + render json: case_note else render json: case_note.errors, status: :unprocessable_entity @@ -33,38 +56,32 @@ def update def destroy if params[:file_index].present? remove_attachment_at_index(params[:file_index].to_i) - head 204 end - end - - private - def case_note_params - - default_params = params.require(:case_note).permit(:meeting_date, :attendee, :interaction_type, case_note_domain_groups_attributes: [:id, :note, :domain_group_id, :task_ids]) - default_params = params.require(:case_note).permit(:meeting_date, :attendee, :interaction_type, case_note_domain_groups_attributes: [:id, :note, :domain_group_id, :task_ids, attachments: []]) if action_name == 'create' - default_params = assign_params_to_case_note_domain_groups_params(default_params) - domain_group_ids = params.dig(:case_note, :domain_group_ids) || [] - default_params = default_params.merge(selected_domain_group_ids: domain_group_ids.compact.reject(&:blank?)) + head 204 if CaseNote.find(params[:id]).destroy end - def add_more_attachments(new_file, case_note_domain_group_id) - if new_file.present? - case_note_domain_group = CaseNoteDomainGroup.find(case_note_domain_group_id) - files = case_note_domain_group.attachments - files += new_file - case_note_domain_group.attachments = files - case_note_domain_group.save + def delete_attachment + case_note = CaseNote.find(params[:id]) + remove_attachment_at_index(case_note, params[:file_index].to_i) + if case_note.save + head 204 + else + render json: case_note.errors, status: :unprocessable_entity end end - def remove_attachment_at_index(index) - case_note_domain_group = CaseNoteDomainGroup.find(params[:case_note_domain_group_id]) - remain_attachment = case_note_domain_group.attachments - deleted_attachment = remain_attachment.delete_at(index) - deleted_attachment.try(:remove!) - remain_attachment.empty? ? case_note_domain_group.remove_attachments! : (case_note_domain_group.attachments = remain_attachment ) - message = t('.fail_delete_attachment') unless case_note_domain_group.save + private + + def remove_attachment_at_index(case_note, index) + remain_attachments = case_note.attachments + if index.zero? && case_note.attachments.size == 1 + case_note.remove_attachments! + else + deleted_attachment = remain_attachments.delete_at(index) + deleted_attachment.try(:remove!) + case_note.attachments = remain_attachments + end end end end diff --git a/app/controllers/api/v1/client_tasks/tasks_controller.rb b/app/controllers/api/v1/client_tasks/tasks_controller.rb index 4c41b238da..3127712b17 100644 --- a/app/controllers/api/v1/client_tasks/tasks_controller.rb +++ b/app/controllers/api/v1/client_tasks/tasks_controller.rb @@ -32,7 +32,7 @@ def destroy private def task_params - params.require(:task).permit(:domain_id, :name, :completion_date, :remind_at) + params.require(:task).permit(:domain_id, :name, :completion_date, :expected_date, :remind_at) end def find_task diff --git a/app/controllers/api/v1/clients/enter_ngos_controller.rb b/app/controllers/api/v1/clients/enter_ngos_controller.rb index 2e75cff977..0deaef4bec 100644 --- a/app/controllers/api/v1/clients/enter_ngos_controller.rb +++ b/app/controllers/api/v1/clients/enter_ngos_controller.rb @@ -5,7 +5,8 @@ class Clients::EnterNgosController < Api::V1::BaseApiController def create enter_ngo = @client.enter_ngos.new(enter_ngo_params) - if enter_ngo.save + + if !@client.accepted? && enter_ngo.save render json: @client else render json: @client.errors, status: :unprocessable_entity @@ -15,7 +16,8 @@ def create def update enter_ngo = @client.enter_ngos.find(params[:id]) authorize enter_ngo - if enter_ngo.update_attributes(enter_ngo_params) + + if !@client.accepted? && enter_ngo.update_attributes(enter_ngo_params) render json: @client else render json: @client.errors, status: :unprocessable_entity diff --git a/app/controllers/api/v1/clients_controller.rb b/app/controllers/api/v1/clients_controller.rb index 5eb20a95fb..5315fe7c52 100644 --- a/app/controllers/api/v1/clients_controller.rb +++ b/app/controllers/api/v1/clients_controller.rb @@ -1,13 +1,19 @@ module Api module V1 class ClientsController < Api::V1::BaseApiController - before_action :find_client, except: [:index, :create] + include ClientsConcern + before_action :find_client, except: [:index, :listing, :create] def index - clients = current_user.clients + clients = Client.accessible_by(current_ability) render json: clients end + def listing + clients = Client.accessible_by(current_ability) + render json: clients, each_serializer: ClientListingSerializer + end + def show render json: @client end @@ -22,10 +28,35 @@ def create end def update - if @client.update_attributes(client_params) - render json: @client + client = Client.find(params[:client][:id] || params[:id]) + if client + referee = Referee.find_or_create_by(id: params.dig(:referee, :id)) + referee.update_attributes(referee_params) if referee_params + client.referee_id = referee.id + carer = Carer.find_or_create_by(id: client.carer_id || params.dig(:carer, :id)) + carer.update_attributes(carer_params) if carer_params + client.carer_id = carer.id + client.current_family_id ? client_params : client_params.except(:family_ids) + end + + if client.update_attributes(client_params.except(:referee_id, :carer_id)) + qtt_free_text_cases = params[:client_quantitative_free_text_cases] + + if qtt_free_text_cases.present? + qtt_free_text_cases.select(&:present?).each do |client_qt_free_text_attr| + client_qt_free_text = client.client_quantitative_free_text_cases.find_or_initialize_by(quantitative_type_id: client_qt_free_text_attr[:quantitative_type_id]) + client_qt_free_text.content = client_qt_free_text_attr[:content] + client_qt_free_text.save + end + end + + if risk_assessment_params + risk_assessment = RiskAssessmentReducer.new(client, risk_assessment_params, 'update') + risk_assessment.store + end + render json: client else - render json: @client.errors, status: :unprocessable_entity + render json: client.errors, status: :unprocessable_entity end end @@ -48,33 +79,42 @@ def find_client end def client_params - params.require(:client) - .permit( - :code, :name_of_referee, :main_school_contact, :rated_for_id_poor, :what3words, :status, - :kid_id, :assessment_id, :given_name, :family_name, :local_given_name, :local_family_name, :gender, :date_of_birth, - :birth_province_id, :initial_referral_date, :referral_source_id, :telephone_number, - :referral_phone, :received_by_id, :followed_up_by_id, - :follow_up_date, :school_grade, :school_name, :current_address, - :house_number, :street_number, :suburb, :description_house_landmark, :directions, :street_line1, :street_line2, :plot, :road, :postal_code, :district_id, :subdistrict_id, :village_id, :commune_id, - :has_been_in_orphanage, :has_been_in_government_care, - :relevant_referral_information, :province_id, :profile, - :state_id, :township_id, :rejected_note, :live_with, :rated_for_id_poor, - :gov_city, :gov_commune, :gov_district, :gov_date, :gov_village_code, :gov_client_code, - :gov_interview_village, :gov_interview_commune, :gov_interview_district, :gov_interview_city, - :gov_caseworker_name, :gov_caseworker_phone, :gov_carer_name, :gov_carer_relationship, :gov_carer_home, - :gov_carer_street, :gov_carer_village, :gov_carer_commune, :gov_carer_district, :gov_carer_city, :gov_carer_phone, - :gov_information_source, :gov_referral_reason, :gov_guardian_comment, :gov_caseworker_comment, :referral_source_category_id, - interviewee_ids: [], - client_type_ids: [], - donor_ids: [], - user_ids: [], - agency_ids: [], - quantitative_case_ids: [], - custom_field_ids: [], - tasks_attributes: [:name, :domain_id, :completion_date], - client_needs_attributes: [:id, :rank, :need_id], - client_problems_attributes: [:id, :rank, :problem_id] - ) + permited_params = params.require(:client) + .permit( + :code, :name_of_referee, :main_school_contact, :rated_for_id_poor, :what3words, :status, + :kid_id, :assessment_id, :given_name, :family_name, :local_given_name, :local_family_name, :gender, :date_of_birth, + :birth_province_id, :initial_referral_date, :referral_source_id, :telephone_number, + :referral_phone, :received_by_id, :followed_up_by_id, :current_family_id, + :follow_up_date, :school_grade, :school_name, :current_address, :external_id, :external_id_display, + :house_number, :street_number, :suburb, :description_house_landmark, :directions, :street_line1, :street_line2, :plot, :road, :postal_code, :district_id, :subdistrict_id, :village_id, :commune_id, + :has_been_in_orphanage, :has_been_in_government_care, :phone_owner, + :relevant_referral_information, :province_id, :city_id, :profile, :client_phone, + :state_id, :township_id, :rejected_note, :live_with, :rated_for_id_poor, + :gov_city, :gov_commune, :gov_district, :gov_date, :gov_village_code, :gov_client_code, + :gov_interview_village, :gov_interview_commune, :gov_interview_district, :gov_interview_city, + :gov_caseworker_name, :gov_caseworker_phone, :gov_carer_name, :gov_carer_relationship, :gov_carer_home, + :gov_carer_street, :gov_carer_village, :gov_carer_commune, :gov_carer_district, :gov_carer_city, :gov_carer_phone, + :gov_information_source, :gov_referral_reason, :gov_guardian_comment, :gov_caseworker_comment, :referral_source_category_id, + :global_id, :referee_relationship, :client_email, :address_type, + interviewee_ids: [], + client_type_ids: [], + donor_ids: [], + user_ids: [], + agency_ids: [], + quantitative_case_ids: [], + custom_field_ids: [], + tasks_attributes: [:name, :domain_id, :completion_date], + client_needs_attributes: [:id, :rank, :need_id], + family_member_attributes: [:id, :family_id, :_destroy], + client_problems_attributes: [:id, :rank, :problem_id] + ) + + if params[:family_member] + permited_params[:family_member_attributes] = params[:family_member].permit(%i[id family_id]) + permited_params[:family_member_attributes][:_destroy] = 1 if permited_params[:family_member_attributes].present? && permited_params.dig(:family_member_attributes, :family_id).blank? + end + + permited_params end end end diff --git a/app/controllers/api/v1/custom_field_properties_controller.rb b/app/controllers/api/v1/custom_field_properties_controller.rb index 3e65518d68..446ab3a2cf 100644 --- a/app/controllers/api/v1/custom_field_properties_controller.rb +++ b/app/controllers/api/v1/custom_field_properties_controller.rb @@ -1,12 +1,15 @@ module Api module V1 class CustomFieldPropertiesController < Api::V1::BaseApiController + include CustomFieldPropertiesConcern include FormBuilderAttachments + before_action :find_entity before_action :find_custom_field_property, only: [:update, :destroy] def create custom_field_property = @custom_formable.custom_field_properties.new(custom_field_property_params) + custom_field_property.user_id = current_user.id if custom_field_property.save custom_field_property.form_builder_attachments.map do |c| custom_field_property.properties = custom_field_property.properties.merge({ c.name => c.file }) @@ -33,12 +36,16 @@ def destroy name = params[:file_name] index = params[:file_index].to_i if name.present? && index.present? - delete_form_builder_attachment(@custom_field_property, name, index) - render json: { error: "Failed deleting attachment" } unless @custom_field_property.save + if delete_form_builder_attachment(@custom_field_property, name, index) + head 204 if @custom_field_property.save + else + render json: { error: 'Failed deleting attachment' } + end + elsif @custom_field_property.destroy + head 204 else - @custom_field_property.destroy + render json: { error: 'Failed deleting custom field property' } end - head 204 end private @@ -48,22 +55,16 @@ def find_custom_field_property end def custom_field_property_params - custom_form_fields = CustomField.find(params[:custom_field_id]).fields.map{|c| [c['name'], c['label'], c['type']]} - custom_form_fields.each do |name, label, type| - if type == 'file' && attachment_params.present? - attachment_params.values.each do |attachment| - attachment['name'] = label if attachment['name'] == name - end - end - if type != 'file' && properties_params.present? - properties_params.keys.each do |key| - properties_params[label] = properties_params.delete key if key == name - end + if properties_params.present? + mappings = {} + properties_params.each do |k, _| + mappings[k] = k.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('%22', '"') end + formatted_params = properties_params.map { |k, v| [mappings[k], v] }.to_h + formatted_params.values.map { |v| v.delete('') if (v.is_a? Array) && v.size > 1 } end - properties_params.values.map{ |v| v.delete('') if (v.is_a?Array) && v.size > 1 } if properties_params.present? default_params = params.require(:custom_field_property).permit({}).merge(custom_field_id: params[:custom_field_id]) - default_params = default_params.merge(properties: properties_params) if properties_params.present? + default_params = default_params.merge(properties: formatted_params) if formatted_params.present? default_params = default_params.merge(form_builder_attachments_attributes: attachment_params) if action_name == 'create' && attachment_params.present? default_params end diff --git a/app/controllers/api/v1/families/enter_ngos_controller.rb b/app/controllers/api/v1/families/enter_ngos_controller.rb new file mode 100644 index 0000000000..1d9e97e47c --- /dev/null +++ b/app/controllers/api/v1/families/enter_ngos_controller.rb @@ -0,0 +1,36 @@ +module Api + module V1 + class Families::EnterNgosController < Api::V1::BaseApiController + before_action :find_family + + def create + enter_ngo = @family.enter_ngos.new(enter_ngo_params) + if enter_ngo.save + render json: @family.reload + else + render json: @family.errors, status: :unprocessable_entity + end + end + + def update + enter_ngo = @family.enter_ngos.find(params[:id]) + authorize enter_ngo + if enter_ngo.update_attributes(enter_ngo_params) + render json: @family.reload + else + render json: @family.errors, status: :unprocessable_entity + end + end + + private + + def find_family + @family = Family.accessible_by(current_ability).find(params[:family_id]) + end + + def enter_ngo_params + params.require(:enter_ngo).permit(:accepted_date, user_ids: []) + end + end + end +end diff --git a/app/controllers/api/v1/families/exit_ngos_controller.rb b/app/controllers/api/v1/families/exit_ngos_controller.rb new file mode 100644 index 0000000000..9b1cd0b0f9 --- /dev/null +++ b/app/controllers/api/v1/families/exit_ngos_controller.rb @@ -0,0 +1,50 @@ +module Api + module V1 + class Families::ExitNgosController < Api::V1::BaseApiController + before_action :find_family + + def create + exit_ngo = @family.exit_ngos.new(exit_ngo_params) + if exit_ngo.save + # send_reject_referral_family_email + render json: @family.reload + else + render json: @family.errors, status: :unprocessable_entity + end + end + + def update + exit_ngo = @family.exit_ngos.find(params[:id]) + authorize exit_ngo + if exit_ngo.update_attributes(exit_ngo_params) + render json: @family.reload + else + render json: @family.errors, status: :unprocessable_entity + end + end + + private + + def find_family + @family = Family.accessible_by(current_ability).find(params[:family_id]) + end + + def exit_ngo_params + remove_blank_exit_reasons + params.require(:exit_ngo).permit(:exit_note, :exit_circumstance, :other_info_of_exit, :exit_date, exit_reasons: []) + end + + def remove_blank_exit_reasons + return if params[:exit_ngo][:exit_reasons].blank? + params[:exit_ngo][:exit_reasons].reject!(&:blank?) + end + + def send_reject_referral_family_email + return unless @family.referrals.received.present? && @exit_ngo.exit_circumstance == 'Rejected Referral' + referral = @family.referrals.received.last + current_org = current_organization.full_name + RejectReferralFamilyWorker.perform_async(current_user.name, current_org, referral.id) + end + end + end +end diff --git a/app/controllers/api/v1/families_controller.rb b/app/controllers/api/v1/families_controller.rb index 179f2267e3..2082b1cf74 100644 --- a/app/controllers/api/v1/families_controller.rb +++ b/app/controllers/api/v1/families_controller.rb @@ -1,11 +1,20 @@ module Api module V1 class FamiliesController < Api::V1::BaseApiController - def index render json: current_user.families end + def listing + families = Family.accessible_by(current_ability) + render json: families, each_serializer: FamilyListingSerializer + end + + def show + family = find_family + render json: family + end + def create family = Family.new(family_params) if family.save @@ -16,6 +25,7 @@ def create end def update + # @family.case_management_record = !current_setting.hide_family_case_management_tool? family = Family.find(params[:id]) if family.update_attributes(family_params) render json: family @@ -26,16 +36,38 @@ def update private + def find_family + Family.find(params[:id]) + end + def family_params - params.require(:family).permit( - :name, :code, :case_history, :caregiver_information, - :significant_family_member_count, :household_income, - :dependable_income, :female_children_count, - :male_children_count, :female_adult_count, - :male_adult_count, :family_type, :status, :contract_date, - :address, :province_id, :district_id, :commune_id, :village_id, - :house, :street, children: [] - ) + permitted_params = params.require(:family).permit( + :name, :code, + :dependable_income, :family_type, :status, :contract_date, + :address, :province_id, :city_id, :district_id, :house, :street, + :commune_id, :village_id, :slug, + :followed_up_by_id, :follow_up_date, :name_en, :phone_number, :id_poor, :referral_source_id, + :referee_phone_number, :relevant_information, + :received_by_id, :initial_referral_date, :referral_source_category_id, + donor_ids: [], community_ids: [], + case_worker_ids: [], + custom_field_ids: [], + quantitative_case_ids: [], + documents: [], + community_member_attributes: [:id, :community_id, :_destroy], + family_quantitative_free_text_cases_attributes: [ + :id, :content, :quantitative_type_id + ], + family_members_attributes: [ + :monthly_income, :client_id, + :id, :gender, :note, :adult_name, :date_of_birth, + :occupation, :relation, :guardian, :_destroy + ] + ) + + permitted_params[:community_member_attributes][:_destroy] = 1 if permitted_params[:community_member_attributes].present? && permitted_params.dig(:community_member_attributes, :community_id).blank? + + permitted_params end end end diff --git a/app/controllers/api/v1/organizations_controller.rb b/app/controllers/api/v1/organizations_controller.rb index a804494337..91125c9474 100644 --- a/app/controllers/api/v1/organizations_controller.rb +++ b/app/controllers/api/v1/organizations_controller.rb @@ -13,7 +13,7 @@ def index def clients sql = '' bulk_clients = [] - external_system_name = ExternalSystem.find_by(token: @current_user.email)&.name || '' + external_system_id, external_system_name = ExternalSystem.fetch_external_system_name(@current_user.email) date_time_param = Time.parse(params[:since_date]) if params[:since_date].present? end_date_param = Time.parse(params[:end_date]) if params[:end_date].present? Organization.only_integrated.pluck(:short_name).map do |short_name| @@ -32,23 +32,23 @@ def clients end def create - if org = Organization.create_and_build_tenant(organization_params) - OrganizationWorker.perform_async(org.id, org.referral_source_category_name) + org = Organization.new(organization_params) + if org.save + OrganizationWorker.perform_async(org.id) + render json: org, status: :ok else render json: { msg: org.errors }, status: :unprocessable_entity end - rescue => e - render json: e.message, status: :unprocessable_entity end def upsert if params[:organization].present? && clients_params['organization_name'].present? if clients_params['global_id'].present? && GlobalIdentity.find_by(ulid: clients_params['global_id']) Apartment::Tenant.switch! clients_params[:organization_name] - create_referral if clients_params[:is_referred].present? && clients_params[:is_referred] + object_saved = create_referral if clients_params[:is_referred].present? && clients_params[:is_referred] - find_client_global_identiy + find_client_global_identiy(object_saved) else find_referral end @@ -58,9 +58,11 @@ def upsert end end - def find_client_global_identiy - if GlobalIdentity.exists?(clients_params['global_id']) + def find_client_global_identiy(object_saved) + if (object_saved.nil? && GlobalIdentity.exists?(clients_params['global_id'])) || object_saved.valid? && GlobalIdentity.exists?(clients_params['global_id']) render_client_data + elsif object_saved.errors.present? + render json: { external_id: clients_params['external_id'], message: object_saved.errors }, status: :unprocessable_entity else render json: { global_id: clients_params['global_id'], message: 'Record not found.' }, status: '404' end @@ -74,8 +76,12 @@ def render_client_data Organization.switch_to short_name || clients_params[:organization_name] client = Client.find_by(global_id: clients_params['global_id']) attributes = Client.get_client_attribute(clients_params, client.referral_source_category_id) if client - if client && client.update_attributes(attributes) - render json: { external_id: client.external_id, message: 'Record saved.' } + if client && client.update_attributes(attributes.except(:global_id)) + if clients_params['referral_status'] + check_referral_status(client, clients_params['referral_status']) + else + render json: { external_id: client.external_id, message: 'Record saved.' } + end else render json: { external_id: clients_params[:external_id], message: client.errors }, status: :unprocessable_entity end @@ -100,15 +106,16 @@ def transaction def update_link if params[:data].present? data = params[:data] - global_ids = data.map(&:values).map(&:last) - data_hash = data.map{ |pay_load| [pay_load[:global_id], [pay_load[:external_id], pay_load[:external_id_display]] ] }.to_h + global_ids = data.map { |hash| hash['global_id'] } + data_hash = data.map { |pay_load| [pay_load['global_id'], [pay_load['external_id'], pay_load['external_id_display']] ] }.to_h client_organizations = GlobalIdentityOrganization.where(global_id: global_ids).pluck(:global_id, :organization_id, :client_id).group_by(&:second) + client_organizations.each do |ngo_id, client_ngos| ngo = Organization.find(ngo_id) - Client.delay(queue: :priority).update_external_ids(ngo.short_name, client_ngos.map(&:last), data_hash) + Client.update_external_ids(ngo.short_name, client_ngos.map(&:last), data_hash) end - Apartment::Tenant.switch!('public') + Apartment::Tenant.switch('public') render json: { message: 'Record saved.' }, root: :data else render json: { error: client.errors, message: 'Record error. Please check OSCaR logs for details.' }, root: :data, status: :unprocessable_entity @@ -119,12 +126,12 @@ def update if @organization.update_attributes(organization_params) render json: @organization, status: :ok else - render json: { msg: org.errors }, status: :unprocessable_entity + render json: { msg: @organization.errors }, status: :unprocessable_entity end end def destroy - head 204 if @organization.destroy + 33054 end def check_duplication @@ -144,6 +151,34 @@ def check_duplication render json: { similar_fields: result ? 'Record was Found' : 'Record was not found' } end + def update_referral_status + data = params[:data] + data.each do |pay_load| + global_id, referral_id, status = [pay_load['client_global_id'], pay_load['referral_id'], pay_load['referral_status']] + + global_identity_organization = GlobalIdentityOrganization.find_by(global_id: global_id) + if global_identity_organization + ngo = Organization.find(global_identity_organization.organization_id) + else + raise ActiveRecord::RecordNotFound + end + Apartment::Tenant.switch! ngo.short_name + referral = Referral.find(referral_id) + if referral + external_system_id, external_system_name = ExternalSystem.fetch_external_system_name(params['uid']) + next if referral.update_attributes(referral_status: status) + raise ActiveRecord::RecordNotFound, (referral.errors.full_messages << "Referral status must be one of ['Accepted', 'Exited', 'Referred'].").join(". ") + else + raise ActiveRecord::RecordNotFound + end + end + + Apartment::Tenant.switch!('public') + render json: { message: 'Record saved.' }, root: :data + rescue ActiveRecord::RecordNotFound => e + render json: { error: e.message, message: 'Record error. Please check OSCaR logs for details.' }, root: :data, status: :unprocessable_entity + end + private def organization_params @@ -161,7 +196,7 @@ def clients_params :address_current_village_code, :reason_for_referral, :reason_for_exiting, :organization_id, :organization_name, :external_case_worker_name, :external_case_worker_id, :external_case_worker_mobile, :external_case_worker_email, - :level_of_risk, :is_referred, + :level_of_risk, :is_referred, :referral_status, services: [:uuid, :name] ) end @@ -172,9 +207,7 @@ def find_referral referral_attributes = Referral.get_referral_attribute(clients_params) referral = Referral.find_by(external_id: clients_params[:external_id]) if referral.nil? - external_system = ExternalSystem.find_by(token: @current_user.email) - external_system_id = external_system&.id - external_system_name = external_system&.name + external_system_id, external_system_name = ExternalSystem.fetch_external_system_name(@current_user.email) referral = Referral.new(referral_attributes.merge(ngo_name: external_system_name, referred_from: external_system_name)) if referral.save global_identity = GlobalIdentity.find_by(ulid: referral_attributes[:client_global_id]) @@ -187,39 +220,54 @@ def find_referral else render json: { external_id: clients_params[:external_id], message: referral.errors }, status: :unprocessable_entity end + elsif referral.present? && referral.client.nil? + external_system_id, external_system_name = ExternalSystem.fetch_external_system_name(@current_user.email) + referral = Referral.new(referral_attributes.merge(ngo_name: external_system_name, referred_from: external_system_name, client_global_id: referral.client_global_id)) + if referral.save + render json: { external_id: clients_params[:external_id], message: 'Record saved.' } + else + render json: { external_id: clients_params[:external_id], message: referral.errors }, status: :unprocessable_entity + end else - render json: { external_id: clients_params[:external_id], message: 'Record saved.' } + message = {} + message['global_id'] = "global_id must exist." if clients_params['global_id'].blank? + message['referral_status'] = "referral_status must be present." if clients_params['global_id'].blank? + + render json: { external_id: clients_params[:external_id], message: 'Record was found.', errors: message }, status: :unprocessable_entity end end def create_referral - external_system = ExternalSystem.find_by(token: @current_user.email) - external_system_id = external_system&.id - external_system_name = external_system&.name + external_system_id, external_system_name = ExternalSystem.fetch_external_system_name(@current_user.email) referral_attributes = Referral.get_referral_attribute(clients_params) client = Client.find_by(global_id: referral_attributes[:client_global_id]) - user = client.users.last - referral = Referral.new( - referral_attributes.merge( - ngo_name: external_system_name, - referred_from: external_system_name, - slug: client&.slug, - referee_id: user.id + if client + referee = client.referee || client.received_by || client.users.last + referral = Referral.new( + referral_attributes.merge( + ngo_name: external_system_name, + referred_from: external_system_name, + slug: client&.slug, + referee_id: referee.id + ) ) - ) - if referral.save - global_identity = GlobalIdentity.find_by(ulid: referral_attributes[:client_global_id]) - global_identity.external_system_global_identities.find_or_create_by( - external_system_id: external_system_id, - external_id: referral_attributes[:external_id], - organization_name: clients_params[:organization_name] - ) + if ['Accepted', 'Exited', 'Referred'].include?(clients_params['referral_status']) && referral.save + global_identity = GlobalIdentity.find_by(ulid: referral_attributes[:client_global_id]) + global_identity.external_system_global_identities.find_or_create_by( + external_system_id: external_system_id, + external_id: referral_attributes[:external_id], + organization_name: clients_params[:organization_name] + ) + global_identity + else + referral.save + referral + end end end - def authenticate_admin_user! authenticate_or_request_with_http_token do |token, _options| @current_user = AdminUser.find_by(token: token) @@ -231,6 +279,7 @@ def set_current_aut_user end def get_sql_and_client_data(external_system_name, since_date) + conditional_sql = "(TRIM(CONCAT(clients.given_name, clients.local_given_name)) != '' AND TRIM(CONCAT(clients.family_name, clients.local_family_name)) != '') AND clients.gender != '' AND clients.date_of_birth IS NOT NULL" sql = " SELECT clients.*, districts.code district_code, communes.code commune_code, villages.code village_code FROM clients @@ -238,22 +287,22 @@ def get_sql_and_client_data(external_system_name, since_date) LEFT OUTER JOIN districts ON districts.id = clients.district_id LEFT OUTER JOIN communes ON communes.id = clients.commune_id LEFT OUTER JOIN villages ON villages.id = clients.village_id - + WHERE (#{conditional_sql}) ".squish clients = [] if params.dig(:since_date).present? - clients = Client.referred_external(external_system_name).where('clients.created_at >= ? OR clients.updated_at >= ?', since_date, since_date).order('clients.updated_at DESC') + clients = Client.referred_external(external_system_name).where("#{conditional_sql} AND (clients.created_at >= ? OR clients.updated_at >= ?)", since_date, since_date).order('clients.updated_at DESC') referred_clients = JSON.parse ActiveModel::ArraySerializer.new(clients.distinct.to_a, each_serializer: OrganizationClientSerializer, context: current_user).to_json if clients.present? - sql << " WHERE (DATE(clients.created_at) >= '#{since_date}' OR DATE(clients.updated_at) >= '#{since_date}') AND clients.id NOT IN (#{clients.ids.join(', ')}) ORDER BY clients.updated_at DESC" + sql << " AND (DATE(clients.created_at) >= '#{since_date}' OR DATE(clients.updated_at) >= '#{since_date}') AND clients.id NOT IN (#{clients.ids.join(', ')}) ORDER BY clients.updated_at DESC" else - sql << " WHERE (DATE(clients.created_at) >= '#{since_date}' OR DATE(clients.updated_at) >= '#{since_date}') ORDER BY clients.updated_at DESC" + sql << " AND (DATE(clients.created_at) >= '#{since_date}' OR DATE(clients.updated_at) >= '#{since_date}') ORDER BY clients.updated_at DESC" end else - clients = Client.referred_external(external_system_name).order('clients.updated_at DESC') + clients = Client.referred_external(external_system_name).where(conditional_sql).order('clients.updated_at DESC') referred_clients = JSON.parse ActiveModel::ArraySerializer.new(clients.distinct.to_a, each_serializer: OrganizationClientSerializer, context: current_user).to_json if clients.present? - sql << " WHERE clients.id NOT IN (#{clients.ids.join(', ')}) ORDER BY clients.updated_at DESC" + sql << " AND clients.id NOT IN (#{clients.ids.join(', ')}) ORDER BY clients.updated_at DESC" else sql << ' ORDER BY clients.updated_at DESC' end @@ -269,22 +318,31 @@ def find_historical_clients(external_system_name, since_date, end_date) LEFT OUTER JOIN districts ON districts.id = clients.district_id LEFT OUTER JOIN communes ON communes.id = clients.commune_id LEFT OUTER JOIN villages ON villages.id = clients.village_id - + WHERE ((TRIM(CONCAT(clients.given_name, clients.local_given_name)) != '' AND TRIM(CONCAT(clients.family_name, clients.local_family_name)) != '') AND clients.gender != '' AND clients.date_of_birth IS NOT NULL) AND ".squish clients = [] - sql << " WHERE clients.created_at BETWEEN '#{since_date}' AND '#{end_date}' ORDER BY clients.created_at asc" + sql << " clients.created_at BETWEEN '#{since_date}' AND '#{end_date}' ORDER BY clients.created_at asc" clients = Client.find_by_sql(sql) JSON.parse ActiveModel::ArraySerializer.new(clients.to_a.uniq, each_serializer: ClientShareExternalSerializer, context: current_user).to_json end def create_second_referral - external_system = ExternalSystem.find_by(token: @current_user.email) - external_system_id = external_system&.id - external_system_name = external_system&.name + external_system_id, external_system_name = ExternalSystem.fetch_external_system_name(@current_user.email) referral = Referral.new(referral_attributes.merge(referred_from: external_system_name)) end + def check_referral_status(client, status) + if ['Accepted', 'Exited', 'Referred'].include?(status) + external_system_id, external_system_name = ExternalSystem.fetch_external_system_name(@current_user.email) + client.referrals.received.get_external_systems(external_system_name).last&.update_referral_status(status) + client.referrals.delivered.get_external_systems(external_system_name).last&.update_referral_status(status) + render json: { external_id: client.external_id, message: 'Record saved.' } + else + render json: { external_id: client.external_id, message: "Referral status must be one of ['Accepted', 'Exited', 'Referred']." }, status: :unprocessable_entity + end + end + end end end diff --git a/app/controllers/api/v1/program_streams_controller.rb b/app/controllers/api/v1/program_streams_controller.rb index 6db1c3f628..0c06c44e91 100644 --- a/app/controllers/api/v1/program_streams_controller.rb +++ b/app/controllers/api/v1/program_streams_controller.rb @@ -1,9 +1,8 @@ module Api module V1 class ProgramStreamsController < Api::V1::BaseApiController - def index - render json: ProgramStream.complete.ordered + render json: ProgramStream.complete.ordered, scope: view_context end end end diff --git a/app/controllers/api/v1/referees_controller.rb b/app/controllers/api/v1/referees_controller.rb new file mode 100644 index 0000000000..a630be253e --- /dev/null +++ b/app/controllers/api/v1/referees_controller.rb @@ -0,0 +1,9 @@ +module Api + module V1 + class RefereesController < Api::V1::BaseApiController + def index + render json: Referee.order(:name) + end + end + end +end diff --git a/app/controllers/api/v1/release_notes_controller.rb b/app/controllers/api/v1/release_notes_controller.rb new file mode 100644 index 0000000000..aee3480726 --- /dev/null +++ b/app/controllers/api/v1/release_notes_controller.rb @@ -0,0 +1,21 @@ +module Api + module V1 + class ReleaseNotesController < Api::V1::BaseApiController + skip_before_action :authenticate_user! + before_action :authenticate_admin_user! + + def upload_attachments + release_note = ReleaseNote.find(params[:id]) + release_note.update_attributes(attachments: params[:attachments]) + + render json: { success: true } + end + + def authenticate_admin_user! + authenticate_or_request_with_http_token do |token, _options| + @current_user = AdminUser.find_by(token: token) + end + end + end + end +end diff --git a/app/controllers/api/v1/settings_controller.rb b/app/controllers/api/v1/settings_controller.rb index 10c5788849..7ddd1554b2 100644 --- a/app/controllers/api/v1/settings_controller.rb +++ b/app/controllers/api/v1/settings_controller.rb @@ -1,9 +1,8 @@ module Api module V1 class SettingsController < Api::V1::BaseApiController - def index - render json: Setting.cache_first + render json: Setting.first end end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3fa2e9fb45..69504c4f50 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base protect_from_forgery with: :null_session, except: :index, if: proc { |c| c.request.format == 'application/json' } before_action :store_user_location!, if: :storable_location? before_action :configure_permitted_parameters, if: :devise_controller? - before_action :find_association, if: :devise_controller? + before_action :find_association, if: :registration? before_action :set_locale, :override_translation before_action :set_paper_trail_whodunnit, :current_setting before_action :prevent_routes @@ -17,10 +17,10 @@ class ApplicationController < ActionController::Base end helper_method :current_organization, :current_setting - helper_method :field_settings + helper_method :field_settings, :cache_keys_base rescue_from CanCan::AccessDenied do |exception| - if exception.subject.inspect.include?("Client") && (exception.action).to_s.include?("show") + if exception.subject.inspect.include?('Client') && (exception.action).to_s.include?('show') flash[:notice] = t('unauthorized.case_worker_unauthorized') else flash[:alert] = t('unauthorized.default') @@ -37,11 +37,11 @@ class ApplicationController < ActionController::Base end def current_organization - Organization.current + @current_organization ||= Organization.current end def current_setting - @current_setting = Setting.cache_first + @current_setting ||= Setting.cache_first end def field_settings @@ -53,8 +53,26 @@ def pundit_user UserContext.new(current_user, field_settings) end + def cache_keys_base + [current_organization, I18n.locale] + end + protected + def override_translation + return if I18n::Backend::Custom::ReloadChecker.last_reload_at > (FieldSetting.maximum(:updated_at) || Time.now) + + I18n.backend.reload! + rescue ArgumentError => e + # Caused by FieldSetting zero + # Ignore + Rails.logger.error e.message + end + + def registration? + controller_name == 'registrations' + end + def address_translation @address_translation = view_context.address_translation('client') end @@ -86,15 +104,11 @@ def configure_permitted_parameters def find_association @department = Department.order(:name) - @province = Province.cached_order_name - end - - def override_translation - I18n.backend.reload! if request.get? && request.format.html? + @province = Province.cached_order_name end def default_url_options(options = {}) - country = Setting.cache_first.try(:country_name) || params[:country] || 'cambodia' + country = Setting.cache_first.try(:country_name) || current_organization.country || params[:country] || 'cambodia' local = params[:locale] if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym) { locale: local || I18n.locale, country: country }.merge(options) end @@ -120,9 +134,9 @@ def store_user_location! end def prevent_routes - if current_setting.try(:enable_hotline) == false && params[:controller] == "calls" + if current_setting.try(:enable_hotline) == false && params[:controller] == 'calls' redirect_to root_path, notice: t('unauthorized.you_cannot_access_this_page') - elsif current_setting.try(:enable_client_form) == false && params[:controller] == "clients" + elsif current_setting.try(:enable_client_form) == false && params[:controller] == 'clients' redirect_to root_path, notice: t('unauthorized.you_cannot_access_this_page') end end @@ -137,4 +151,12 @@ def set_raven_context Raven.user_context(ip: request.ip) end end + + def save_draft? + request.format.json? && params[:draft].present? + end + + def searched_client_ids + @searched_client_ids ||= Rails.cache.read(params[:cache_key]) if params[:cache_key] + end end diff --git a/app/controllers/assessments_controller.rb b/app/controllers/assessments_controller.rb index 716951a53f..a5126a0213 100644 --- a/app/controllers/assessments_controller.rb +++ b/app/controllers/assessments_controller.rb @@ -5,30 +5,30 @@ class AssessmentsController < AdminController include AssessmentHelper before_action :find_client, :list_all_case_conferences - before_action :find_assessment, only: [:edit, :update, :show, :destroy] - before_action :authorize_client, only: [:new, :create] + before_action :find_assessment, only: [:edit, :update, :show, :destroy, :upload_attachment] + before_action :authorize_client, only: [:new, :create, :upload_attachment] before_action :authorize_assessment, only: [:show, :edit, :update] before_action :fetch_available_custom_domains, only: :index def index @default_assessment = @client.assessments.new - @custom_assessment = @client.assessments.new(default: false) + @custom_assessment = @client.assessments.new(default: false) @assessmets = AssessmentDecorator.decorate_collection(@client.assessments.order(:created_at)) @custom_assessment_settings = CustomAssessmentSetting.all.where(enable_custom_assessment: true) end def new @from_controller = params[:from] - @prev_assessment = @client.assessments.last @custom_assessment_setting = find_custom_assessment_setting custom_assessment_setting_id = @custom_assessment_setting.try(:id) - @assessment = @client.assessments.new(default: default?, case_conference_id: params[:case_conference], custom_assessment_setting_id: custom_assessment_setting_id ) + @assessment = @client.assessments.new(default: default?, case_conference_id: params[:case_conference], custom_assessment_setting_id: custom_assessment_setting_id) authorize(@assessment, :new?, @custom_assessment_setting.try(:id)) if current_organization.try(:aht) == false if @custom_assessment_setting.present? && !policy(@assessment).create?(custom_assessment_setting_id) - redirect_to client_assessments_path(@client), alert: "#{I18n.t('assessments.index.next_review')} of #{@custom_assessment_setting.custom_assessment_name}: #{date_format(@client.custom_next_assessment_date(nil, @custom_assessment_setting.id))}" + redirect_to client_assessments_path(@client), alert: "#{I18n.t("assessments.index.next_review")} of #{@custom_assessment_setting.custom_assessment_name}: #{date_format(@client.custom_next_assessment_date(nil, @custom_assessment_setting.id))}" else - @assessment.populate_notes(params[:default], params[:custom_name]) + routes_params = params.to_unsafe_h.slice("default", "custom_name", "case_conference", "from_controller") + redirect_to(edit_client_assessment_path(@client, routes_params.merge(id: :draft))) end end @@ -39,9 +39,9 @@ def create case_conference = CaseConference.find(assessment_params[:case_conference_id]) if case_conference.assessment.nil? && @assessment.save(validate: false) if params[:from_controller] == "dashboards" - redirect_to root_path, notice: t('.successfully_created') + redirect_to root_path, notice: t(".successfully_created") else - redirect_to client_path(@client), notice: t('.successfully_created') + redirect_to client_path(@client), notice: t(".successfully_created") end elsif case_conference.assessment params[:assessment][:assessment_domains_attributes].each do |assessment_domain| @@ -49,15 +49,15 @@ def create end assessment = case_conference.assessment.reload - assessment_domains_attributes = assessment_params[:assessment_domains_attributes].select {|k, v| v['score'].present? } + assessment_domains_attributes = assessment_params[:assessment_domains_attributes].select { |k, v| v["score"].present? } assessment.update(updated_at: DateTime.now) assessment.assessment_domains.update_all(assessment_id: assessment.id) assessment_domains_attributes.each do |_, v| - attr = v.slice('domain_id', 'score') - assessment.assessment_domains.reload.find_by(domain_id: attr['domain_id']).update_attributes(attr) + attr = v.slice("domain_id", "score") + assessment.assessment_domains.reload.find_by(domain_id: attr["domain_id"]).update_attributes(attr) end - redirect_to client_assessment_path(@client, assessment), notice: t('.successfully_updated') + redirect_to client_assessment_path(@client, assessment), notice: t(".successfully_updated") else render :new end @@ -66,9 +66,9 @@ def create authorize @assessment, :create?, css.try(:id) if @assessment.save if params[:from_controller] == "dashboards" - redirect_to root_path, notice: t('.successfully_created') + redirect_to root_path, notice: t(".successfully_created") else - redirect_to client_path(@client), notice: t('.successfully_created') + redirect_to client_assessment_path(@client, @assessment), notice: t(".successfully_created") end else flash[:alert] = @assessment.errors.full_messages @@ -81,33 +81,46 @@ def show end def edit - @assessment.repopulate_notes + @prev_assessment = @client.assessments.last end def update - params[:assessment][:assessment_domains_attributes].each do |assessment_domain| - add_more_attachments(assessment_domain.second[:attachments], assessment_domain.second[:id]) - end - if @assessment.update_attributes(assessment_params) - @assessment.update(updated_at: DateTime.now) - @assessment.assessment_domains.update_all(assessment_id: @assessment.id) + attributes = assessment_params.merge(last_auto_save_at: DateTime.now) + + saved = if save_draft? + @assessment.assign_attributes(attributes) + PaperTrail.without_tracking { @assessment.save(validate: false) } + + true + else + @assessment.update_attributes(attributes.merge(draft: false)) + end + + if saved create_bulk_task(params[:task], @assessment) if params.has_key?(:task) - redirect_to client_assessment_path(@client, @assessment), notice: t('.successfully_updated') + + respond_to do |format| + format.html { redirect_to client_assessment_path(@client, @assessment), notice: t(".successfully_updated") } + format.json { render json: { resource: @assessment, edit_url: edit_client_assessment_path(@client, @assessment) }, status: "200" } + end else - render :edit + respond_to do |format| + format.html { render :edit } + format.json { render json: @assessment.errors, status: 422 } + end end end def destroy if params[:file_index].present? remove_attachment_at_index(params[:file_index].to_i) - message ||= t('.successfully_deleted') + message ||= t(".successfully_deleted") respond_to do |f| - f.json { render json: { message: message }, status: '200' } + f.json { render json: { message: message }, status: "200" } end elsif @assessment.present? if @assessment.destroy - redirect_to client_assessments_path(@assessment.client), notice: t('.successfully_deleted_assessment') + redirect_to client_assessments_path(@assessment.client), notice: t(".successfully_deleted_assessment") else messages = @assessment.errors.full_messages.uniq.join('\n') redirect_to [@client, @assessment], alert: messages @@ -115,6 +128,23 @@ def destroy end end + def upload_attachment + assessment_domain = @assessment.assessment_domains.find_or_initialize_by(domain_id: params[:domain_id]) + assessment_domain.save(validate: false) + attachments = params.dig("assessment", "assessment_domains_attributes").map do |_index, assessment_domain_attributes| + assessment_domain_attributes[:attachments] + end.flatten.compact + + if attachments.any? + files = assessment_domain.attachments + files += attachments + assessment_domain.attachments = files + assessment_domain.save(validate: false) + end + + render json: { message: t(".successfully_uploaded") }, status: "200" + end + private def find_client @@ -122,7 +152,14 @@ def find_client end def find_assessment - @assessment = @client.assessments.find(params[:id]).decorate + @assessment = Assessment.unscoped do + if params[:id] == "draft" + @custom_assessment_setting = find_custom_assessment_setting + @client.find_or_create_assessment(default: default?, case_conference_id: params[:case_conference], custom_assessment_setting_id: @custom_assessment_setting.try(:id)) + else + @client.assessments.find(params[:id]) + end + end.decorate end def authorize_client @@ -134,8 +171,8 @@ def authorize_assessment end def assessment_params - default_params = params.require(:assessment).permit(:default, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last]) - default_params = params.require(:assessment).permit(:default, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last, attachments: []]) if action_name == 'create' + default_params = params.require(:assessment).permit(:default, :assessment_date, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last]) + default_params = params.require(:assessment).permit(:default, :assessment_date, :case_conference_id, :custom_assessment_setting_id, :level_of_risk, :description, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last, attachments: []]) if action_name == "create" default_params end @@ -144,22 +181,12 @@ def remove_attachment_at_index(index) remain_attachment = assessment_domain.attachments deleted_attachment = remain_attachment.delete_at(index) deleted_attachment.try(:remove_images!) - remain_attachment.try(:empty?) ? assessment_domain.remove_attachments! : (assessment_domain.attachments = remain_attachment ) - message = t('.fail_delete_attachment') unless assessment_domain.save - end - - def add_more_attachments(new_file, assessment_domain_id) - if new_file.present? - assessment_domain = AssessmentDomain.find(assessment_domain_id) - files = assessment_domain.attachments - files += new_file - assessment_domain.attachments = files - assessment_domain.save - end + remain_attachment.try(:empty?) ? assessment_domain.remove_attachments! : (assessment_domain.attachments = remain_attachment) + message = t(".fail_delete_attachment") unless assessment_domain.save end def default? - params[:default] == 'true' + params[:default] == "true" end def fetch_available_custom_domains diff --git a/app/controllers/calls_controller.rb b/app/controllers/calls_controller.rb index 5543fa561e..c7a1f091e5 100644 --- a/app/controllers/calls_controller.rb +++ b/app/controllers/calls_controller.rb @@ -1,5 +1,6 @@ class CallsController < AdminController load_and_authorize_resource find_by: :id + include ApplicationHelper before_action :set_association, only: [:new, :show] before_action :country_address_fields, only: [:new] @@ -118,20 +119,6 @@ def set_association @referral_source_category = referral_source_name(ReferralSource.parent_categories) end - def referral_source_name(referral_source) - if I18n.locale == :km - referral_source.map{|ref| [ref.name, ref.id] } - else - referral_source.map do |ref| - if ref.name_en.blank? - [ref.name, ref.id] - else - [ref.name_en, ref.id] - end - end - end - end - def country_address_fields selected_country = Setting.cache_first.try(:country_name) || params[:country] current_org = Organization.current.short_name @@ -161,9 +148,6 @@ def country_address_fields end def exited_clients(user_ids) - sql = user_ids.map do |user_id| - "versions.object_changes ILIKE '%user_id:\n- \n- #{user_id}\n%'" - end.join(" OR ") client_ids = CaseWorkerClient.where(id: PaperTrail::Version.where(item_type: 'CaseWorkerClient', event: 'create').joins(:version_associations).where(version_associations: { foreign_key_name: 'user_id', foreign_key_id: user_ids }).distinct.map(&:item_id)).pluck(:client_id).uniq Client.where(id: client_ids, status: 'Exited').ids end diff --git a/app/controllers/care_plans_controller.rb b/app/controllers/care_plans_controller.rb index 21d11233c4..f158c3c9ca 100644 --- a/app/controllers/care_plans_controller.rb +++ b/app/controllers/care_plans_controller.rb @@ -3,6 +3,7 @@ class CarePlansController < AdminController load_and_authorize_resource before_action :set_client, :find_all_assessments + before_action :find_previou_assessment_and_care_plan, only: [:new, :create, :edit] before_action :set_care_plan, :find_assessment, only: [:edit, :update] def index @@ -13,18 +14,13 @@ def index end def new - @assessment = @client.assessments.find_by(id: params[:assessment]) - @prev_care_plan = @client.care_plans.last - @care_plan = Setting.cache_first.try(:use_previous_care_plan) && @prev_care_plan || @client.care_plans.new() + @care_plan = @client.care_plans.new end def create @care_plan = @client.care_plans.new(care_plan_params) assessment = Assessment.find(@care_plan.assessment_id) - if assessment.care_plan.nil? && @care_plan.save(validate: false) || assessment.care_plan.reload.update_attributes(care_plan_params) - params[:care_plan][:goals_attributes].each do |goal| - create_nested_value(assessment.care_plan || @care_plan, goal) - end + if assessment.care_plan.nil? && (current_setting.disable_required_fields? ? @care_plan.save(validate: false) : @care_plan.save) redirect_to client_care_plans_path(@client), notice: t('.successfully_created', care_plan: t('clients.care_plan')) else render :new @@ -36,16 +32,10 @@ def show end def edit - # unless current_user.admin? || current_user.strategic_overviewer? - # redirect_to root_path, alert: t('unauthorized.default') unless current_user.permission.care_plans_editable - # end end def update - if @care_plan.update_attributes(care_plan_params) && @care_plan.save - care_plan_update_params[:goals_attributes].each do |goal| - update_nested_value(goal) - end + if @care_plan.update_attributes(care_plan_params) redirect_to client_care_plans_path(@client), notice: t('.successfully_updated', care_plan: t('clients.care_plan')) else render :edit @@ -55,9 +45,7 @@ def update def destroy if @care_plan.present? @care_plan.goals.each do |goal| - goal.tasks.each do |task| - task.destroy_fully! - end + goal.tasks(&:destroy_fully!) goal.reload.destroy end @care_plan.reload.destroy @@ -68,7 +56,17 @@ def destroy private def care_plan_params - params.require(:care_plan).permit(:assessment_id, :client_id, :completed) + params.require(:care_plan).permit( + :assessment_id, :client_id, :care_plan_date, :completed, + goals_attributes: [ + :id, :assessment_domain_id, :assessment_id, :description, :_destroy, + { + tasks_attributes: [ + :id, :domain_id, :name, :expected_date, :relation, :user_id, :client_id, :family_id, :previous_id, :goal_id, :_destroy + ] + } + ] + ) end def care_plan_update_params @@ -91,5 +89,8 @@ def set_care_plan @care_plan = @client.care_plans.find(params[:id]) end - + def find_previou_assessment_and_care_plan + @assessment = @client.assessments.find_by(id: params[:assessment]) + @prev_care_plan = @client.care_plans.last + end end diff --git a/app/controllers/case_notes_controller.rb b/app/controllers/case_notes_controller.rb index 7e832382c9..9acb609edf 100644 --- a/app/controllers/case_notes_controller.rb +++ b/app/controllers/case_notes_controller.rb @@ -1,118 +1,109 @@ - class CaseNotesController < AdminController - load_and_authorize_resource +class CaseNotesController < AdminController + load_and_authorize_resource only: :destroy + include CreateBulkTask include CaseNoteConcern include GoogleCalendarServiceConcern before_action :set_client - before_action :set_custom_assessment_setting, only: [:new, :create, :edit, :update] - before_action :set_case_note, only: [:edit, :update] - before_action :fetch_domain_group, only: [:new, :create, :update, :edit] - before_action :authorize_client, only: [:new, :create] + before_action :set_case_note, only: [:edit, :update, :upload_attachment] + before_action :fetch_domain_group, only: [:update, :edit] + before_action :authorize_client, only: [:new] before_action :authorize_case_note, only: [:edit, :update] - before_action -> { case_notes_permission('readable') }, only: [:index] - before_action -> { case_notes_permission('editable') }, except: [:index] + before_action -> { case_notes_permission("readable") }, only: [:index] + before_action -> { case_notes_permission("editable") }, except: [:index] def index unless current_user.admin? || current_user.strategic_overviewer? - redirect_to root_path, alert: t('unauthorized.default') unless current_user.permission.case_notes_readable + redirect_to root_path, alert: t("unauthorized.default") unless current_user.permission.case_notes_readable end + @case_notes = @client.case_notes.recent_meeting_dates.page(params[:page]) @custom_assessment_settings = CustomAssessmentSetting.all.where(enable_custom_assessment: true) end def new - @from_controller = params[:from] - if params[:custom] == 'true' - @case_note = @client.case_notes.new(custom: true, custom_assessment_setting_id: @custom_assessment_setting&.id) - @case_note.assessment = @client.assessments.custom_latest_record if @current_setting.enable_default_assessment - @case_note.populate_notes(@case_note.custom_assessment_setting_id, params[:custom]) - else - @case_note = @client.case_notes.new() - @case_note.assessment = @client.assessments.default_latest_record - @case_note.populate_notes(nil, 'false') - end - end - - def create - @case_note = @client.case_notes.new(case_note_params) - @case_note.meeting_date = "#{@case_note.meeting_date.strftime("%Y-%m-%d")}, #{Time.now.strftime("%H:%M:%S")}" - if @case_note.save - add_more_attachments(params[:case_note][:attachments]) if params.dig(:case_note, :attachments) - @case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) if params.dig(:case_note, :case_note_domain_groups_attributes) - create_bulk_task(params[:task], @case_note) if params.has_key?(:task) - @case_note.complete_screening_tasks(params) if params[:case_note].has_key?(:tasks_attributes) - - create_task_task_progress_notes - if params[:from_controller] == "dashboards" - redirect_to root_path, notice: t('.successfully_created') - else - redirect_to client_case_notes_path(@client), notice: t('.successfully_created') - end - else - if case_note_params[:custom] == 'true' - @custom_assessment_param = case_note_params[:custom] - @case_note.assessment = @client.assessments.custom_latest_record - else - @case_note.assessment = @client.assessments.default_latest_record - end - @case_note_domain_group_note = params.dig(:additional_fields, :note) - render :new - end + routes_params = params.to_unsafe_h.slice("from", "custom", "custom_name") + redirect_to(edit_client_case_note_path(@client, routes_params.merge(id: :draft))) end def show - @case_note = @client.case_notes.find(params[:id]) + @case_note = CaseNote.unscoped { @client.case_notes.find(params[:id]) } end def edit authorize @case_note, :edit? if Organization.ratanak? + unless current_user.admin? || current_user.strategic_overviewer? - redirect_to root_path, alert: t('unauthorized.default') unless current_user.permission.case_notes_editable + redirect_to root_path, alert: t("unauthorized.default") if !@case_note.draft? && !current_user.permission.case_notes_editable end end def update - if @case_note.update_attributes(case_note_params) + attributes = case_note_params.merge(last_auto_save_at: Time.current) + + saved = if save_draft? + @case_note.assign_attributes(attributes) + PaperTrail.without_tracking { @case_note.save(validate: false) } + + true + else + @case_note.update_attributes(case_note_params.merge(draft: false)) + end + + if saved if params.dig(:case_note, :case_note_domain_groups_attributes) - add_more_attachments(params[:case_note][:attachments]) if params.dig(:case_note, :attachments) @case_note.complete_tasks(params[:case_note][:case_note_domain_groups_attributes], current_user.id) end - create_bulk_task(params[:task], @case_note) if params.has_key?(:task) - @case_note.complete_screening_tasks(params) if params[:case_note].has_key?(:tasks_attributes) + create_bulk_task(params[:task], @case_note) if params.key?(:task) + @case_note.complete_screening_tasks(params) if params[:case_note].key?(:tasks_attributes) create_task_task_progress_notes delete_events if session[:authorization] - redirect_to client_case_notes_path(@client), notice: t('.successfully_updated') + + respond_to do |format| + format.html do + if params[:from_controller] == "dashboards" + redirect_to root_path, notice: t(".successfully_created") + else + redirect_to(client_case_notes_path(@client), notice: t(".successfully_updated")) + end + end + + format.json { render json: { resource: @case_note, edit_url: edit_client_case_note_url(@client, @case_note) }, status: 200 } + end else - render :edit + respond_to do |format| + format.html { render :edit } + format.json { render json: @case_note.errors, status: 422 } + end end end + def upload_attachment + files = @case_note.attachments + files += params.dig(:case_note, :attachments) + @case_note.attachments = files + @case_note.save(validate: false) + + render json: { message: t(".successfully_uploaded") }, status: "200" + end + def destroy if params[:file_index].present? remove_attachment_at_index(params[:file_index].to_i) - message ||= t('.successfully_deleted') + message ||= t(".successfully_deleted") respond_to do |f| - f.json { render json: { message: message }, status: '200' } + f.json { render json: { message: message }, status: "200" } end elsif @case_note.present? @case_note.case_note_domain_groups.delete_all @case_note.reload.destroy - redirect_to client_case_notes_path(@case_note.client), notice: t('.successfully_deleted_case_note') + redirect_to client_case_notes_path(@case_note.client), notice: t(".successfully_deleted_case_note") end end private - def case_note_params - default_params = permit_case_note_params - default_params = params.require(:case_note).permit(:meeting_date, :attendee, :interaction_type, :custom, :note, :custom_assessment_setting_id, case_note_domain_groups_attributes: [:id, :note, :domain_group_id, :task_ids, attachments: []]) if action_name == 'create' - default_params = assign_params_to_case_note_domain_groups_params(default_params) if default_params.dig(:case_note, :domain_group_ids) - default_params = default_params.merge(selected_domain_group_ids: params.dig(:case_note, :domain_group_ids).reject(&:blank?)) - meeting_date = "#{default_params[:meeting_date]} #{Time.now.strftime("%T %z")}" - default_params = default_params.merge(meeting_date: meeting_date) - end - def add_more_attachments(new_files) if new_files.present? case_note_domain_group = @case_note.case_note_domain_groups.first @@ -123,22 +114,21 @@ def add_more_attachments(new_files) end end - def remove_attachment_at_index(index, case_note_domain_group_id = '') - case_note_domain_group_id = params[:case_note_domain_group_id] || case_note_domain_group_id - case_note_domain_group = CaseNoteDomainGroup.find(case_note_domain_group_id) - remain_attachment = case_note_domain_group.attachments - deleted_attachment = remain_attachment.delete_at(index) - deleted_attachment.try(:remove_images!) - remain_attachment.empty? ? case_note_domain_group.remove_attachments! : (case_note_domain_group.attachments = remain_attachment ) - message = t('.fail_delete_attachment') unless case_note_domain_group.save - end - def set_client @client = Client.accessible_by(current_ability).friendly.find(params[:client_id]) end def set_case_note - @case_note = @client.case_notes.find(params[:id]) + @case_note = CaseNote.unscoped do + if params[:id] == "draft" + @client.find_or_create_draft_case_note( + custom_assessment_setting_id: set_custom_assessment_setting&.id, + custom: params[:custom], + ) + else + @client.case_notes.find(params[:id]) + end + end end def set_custom_assessment_setting @@ -151,16 +141,17 @@ def authorize_case_note def authorize_client return true if current_user.admin? + authorize @client, :create? end def case_notes_permission(permission) - unless current_user.admin? || current_user.strategic_overviewer? - if permission == 'readable' - redirect_to root_path, alert: t('unauthorized.default') unless current_user.permission.case_notes_readable - else - redirect_to root_path, alert: t('unauthorized.default') unless current_user.permission.case_notes_editable - end + return if current_user.admin? || current_user.strategic_overviewer? + + if permission == "readable" + redirect_to root_path, alert: t("unauthorized.default") unless current_user.permission.case_notes_readable + else + redirect_to root_path, alert: t("unauthorized.default") unless current_user.permission.case_notes_editable end end @@ -169,10 +160,11 @@ def permit_case_note_params # :id, :name, :completion_date, :completed, :completed_by_id, :_destroy, # task_progress_notes_attributes: [:id, :progress_note, :task_id, :_destroy] # ] - params.require(:case_note).permit(:meeting_date, :attendee, :interaction_type, :custom, :note, :custom_assessment_setting_id, + params.require(:case_note).permit( + :meeting_date, :attendee, :interaction_type, :custom, :note, :custom_assessment_setting_id, case_note_domain_groups_attributes: [ - :id, :note, :domain_group_id, :task_ids - ] + :id, :note, :domain_group_id, :task_ids, + ], ) end end diff --git a/app/controllers/client/enter_ngos_controller.rb b/app/controllers/client/enter_ngos_controller.rb index 5b2ea0ce8a..71ceb6b0ec 100644 --- a/app/controllers/client/enter_ngos_controller.rb +++ b/app/controllers/client/enter_ngos_controller.rb @@ -4,7 +4,8 @@ class Client::EnterNgosController < AdminController def create @enter_ngo = @client.enter_ngos.new(enter_ngo_params) - if @enter_ngo.save + + if !@client.accepted? && @enter_ngo.save redirect_to @client, notice: t('.successfully_created') else redirect_to @client, alert: t('.failed_create') @@ -14,7 +15,8 @@ def create def update @enter_ngo = @client.enter_ngos.find(params[:id]) authorize @enter_ngo - if @enter_ngo.update_attributes(enter_ngo_params) + + if !@client.accepted? && @enter_ngo.update_attributes(enter_ngo_params) redirect_to @client, notice: t('.successfully_updated') else redirect_to @client, alert: t('.failed_update') diff --git a/app/controllers/client_enrollments_controller.rb b/app/controllers/client_enrollments_controller.rb index aa8d379537..8b87d2f1bc 100644 --- a/app/controllers/client_enrollments_controller.rb +++ b/app/controllers/client_enrollments_controller.rb @@ -29,7 +29,7 @@ def new end authorize(@client) && authorize(@client_enrollment) @client_enrollment = @client.client_enrollments.new(program_stream_id: @program_stream.id) - @attachment = @client_enrollment.form_builder_attachments.build + @attachment = @client_enrollment.form_builder_attachments.build end def edit @@ -87,18 +87,18 @@ def program_stream_order_by_enrollment end all_programs = params[:family_id] ? all_programs.attached_with('Family') : all_programs.attached_with('Client') - client_enrollments_exited = all_programs.inactive_enrollments(@client).complete - client_enrollments_inactive = all_programs.without_status_by(@client).complete + client_enrollments_exited = all_programs.inactive_enrollments(@client).complete + client_enrollments_inactive = all_programs.without_status_by(@client).complete + @active_enrollments = all_programs.active_enrollments(@client).complete - program_streams = client_enrollments_exited + client_enrollments_inactive + program_streams = (client_enrollments_exited + client_enrollments_inactive + @active_enrollments).uniq end - def find_client_histories enter_ngos = @client.enter_ngos - exit_ngos = @client.exit_ngos + exit_ngos = @client.exit_ngos cps_enrollments = @client.client_enrollments - cps_leave_programs = LeaveProgram.joins(:client_enrollment).where("client_enrollments.client_id = ?", @client.id) + cps_leave_programs = LeaveProgram.joins(:client_enrollment).where('client_enrollments.client_id = ?', @client.id) referrals = @client.referrals @case_histories = (enter_ngos + exit_ngos + cps_enrollments + cps_leave_programs + referrals).sort { |current_record, next_record| -([current_record.created_at, current_record.new_date] <=> [next_record.created_at, next_record.new_date]) } end diff --git a/app/controllers/clients_controller.rb b/app/controllers/clients_controller.rb index 0bbfc8cb09..5771ed93b7 100644 --- a/app/controllers/clients_controller.rb +++ b/app/controllers/clients_controller.rb @@ -1,6 +1,6 @@ class ClientsController < AdminController - load_and_authorize_resource find_by: :slug, except: :quantitative_case - + load_and_authorize_resource find_by: :slug, except: [:quantitative_case, :destroy, :restore] + include ApplicationHelper include ClientAdvancedSearchesConcern include ClientGridOptions include CacheHelper @@ -8,42 +8,61 @@ class ClientsController < AdminController before_action :assign_active_client_prams, only: :index before_action :format_search_params, only: [:index] before_action :get_quantitative_fields, :get_hotline_fields, :hotline_call_column, only: [:index] - before_action :find_params_advanced_search, :get_custom_form, :get_program_streams, :get_assessments, only: [:index] + before_action :find_params_advanced_search, :get_custom_form, :get_program_streams, only: [:index] before_action :get_custom_form_fields, :program_stream_fields, :custom_form_fields, :client_builder_fields, only: [:index] before_action :basic_params, if: :has_params?, only: [:index] before_action :build_advanced_search, only: [:index] before_action :fetch_advanced_search_queries, only: [:index] - before_action :find_client, only: [:show, :edit, :update, :destroy] + before_action :find_client, only: [:show, :edit, :update, :custom_fields] before_action :assign_client_attributes, only: [:show, :edit] - before_action :set_association, except: [:index, :destroy, :version] + before_action :set_association, except: [:index, :destroy, :restore, :archive, :archived, :version, :welcome, :load_client_table_summary, :load_statistics_data] before_action :choose_grid, only: [:index] before_action :quantitative_type_editable, only: [:edit, :update, :new, :create] before_action :quantitative_type_readable before_action :validate_referral, only: [:new, :edit] + def welcome + choose_grid + end + + def archived + @clients = Client.only_deleted.accessible_by(current_ability).includes(:archived_by) + end + + def custom_fields + if current_user.admin? || current_user.strategic_overviewer? + @available_editable_forms = CustomField.all + @readable_forms = @client.custom_field_properties + else + @available_editable_forms = CustomField.where(id: current_user.custom_field_permissions.where(editable: true).pluck(:custom_field_id)) + @readable_forms = @client.custom_field_properties.where(custom_field_id: current_user.custom_field_permissions.where(readable: true).pluck(:custom_field_id)) + end + end + def index - @client_default_columns = Setting.cache_first.try(:client_default_columns) + @client_default_columns = Setting.cache_first.client_default_columns if params[:advanced_search_id] current_advanced_search = AdvancedSearch.find(params[:advanced_search_id]) @visible_fields = current_advanced_search.field_visible end + if has_params? || params[:advanced_search_id].present? || params[:client_advanced_search].present? advanced_search else - columns_visibility + client_columns_visibility respond_to do |f| f.html do - next unless params['commit'].present? # @client_grid is invoked from ClientGridOptions#choose_grid - client_grid = @client_grid.scope { |scope| scope.accessible_by(current_ability) } - @results = client_grid.assets - $client_data = @clients - @client_grid = @client_grid.scope { |scope| scope.accessible_by(current_ability).order(:id).page(params[:page]).per(20) } + client_grid = @client_grid.scope { |scope| scope.accessible_by(current_ability) } + @results = client_grid.assets + $client_data = @clients + @client_grid = @client_grid.scope { |scope| scope.accessible_by(current_ability).order(:id).page(params[:page]).per(20) } end f.xls do - next unless params['commit'].present? @client_grid.scope { |scope| scope.accessible_by(current_ability) } + @client_grid.params = params.to_unsafe_h.dup.deep_symbolize_keys + export_client_reports send_data @client_grid.to_xls, filename: "client_report-#{Time.now}.xls" end @@ -54,45 +73,46 @@ def index def show respond_to do |format| format.html do - @referees = Referee.none_anonymouse.pluck(:id, :name).map{|id, name| { value: id, text: name } } - @current_provinces = Province.pluck(:id, :name).map{|id, name| { value: id, text: name } } - @birth_provinces = @birth_provinces.map{|parent, children| children.map{|t, v| { value: v, text: t } } }.flatten - custom_field_ids = @client.custom_field_properties.pluck(:custom_field_id) + Referral.where(id: params[:referral_id]).update_all(client_id: @client.id, saved: true) if params[:referral_id].present? + + @referees = Referee.cache_none_anonymous.map { |referee| { value: referee.id, text: referee.name } } + @current_provinces = Province.pluck(:id, :name).map { |id, name| { value: id, text: name } } + @birth_provinces = @birth_provinces.map { |_, children| children.map { |t, v| { value: v, text: t } } }.flatten + + custom_field_ids = @client.custom_field_properties.pluck(:custom_field_id) if current_user.admin? || current_user.strategic_overviewer? - available_editable_forms = CustomField.all - readable_forms = @client.custom_field_properties.includes(:custom_field) + available_editable_forms = CustomField.all else - available_editable_forms = CustomField.where(id: current_user.custom_field_permissions.where(editable: true).pluck(:custom_field_id)) - readable_forms = @client.custom_field_properties.where(custom_field_id: current_user.custom_field_permissions.where(readable: true).pluck(:custom_field_id)) + available_editable_forms = CustomField.where(id: current_user.custom_field_permissions.where(editable: true).pluck(:custom_field_id)) end - @free_client_forms = available_editable_forms.client_forms.where(hidden: false).not_used_forms(custom_field_ids).order_by_form_title - @group_client_custom_fields = readable_forms.sort_by{ |c| c.custom_field.form_title }.group_by(&:custom_field_id) + @free_client_forms = available_editable_forms.client_forms.where(hidden: false).not_used_forms(custom_field_ids).order_by_form_title + initial_visit_client enter_ngos = @client.enter_ngos - exit_ngos = @client.exit_ngos + exit_ngos = @client.exit_ngos cps_enrollments = @client.client_enrollments.includes(:leave_program, :program_stream) - cps_leave_programs = LeaveProgram.joins(:client_enrollment).where("client_enrollments.client_id = ?", @client.id) + cps_leave_programs = LeaveProgram.joins(:client_enrollment).where('client_enrollments.client_id = ?', @client.id) referrals = @client.referrals @case_histories = (enter_ngos + exit_ngos + cps_enrollments + cps_leave_programs + referrals).sort { |current_record, next_record| -([current_record.new_date, current_record.created_at] <=> [next_record.new_date, next_record.created_at]) } @internal_referrals = @client.internal_referrals.joins(:program_streams).select('DISTINCT ON (internal_referrals.id, program_streams.id) internal_referrals.id, internal_referrals.referral_date, internal_referrals.client_id, program_streams.name program_name, internal_referrals.created_at') end format.pdf do - form = params[:form] - form_title = t(".government_form_#{form}") + form = params[:form] + form_title = t(".government_form_#{form}") client_name = @client.en_and_local_name - pdf_name = "#{client_name} - #{form_title}" - render pdf: pdf_name, - template: 'clients/show.pdf.haml', - page_size: 'A4', - layout: 'pdf_design.html.haml', - show_as_html: params.key?('debug'), - header: { html: { template: 'government_reports/pdf/header.pdf.haml' } }, - footer: { html: { template: 'government_reports/pdf/footer.pdf.haml' }, right: '[page] of [topage]' }, - margin: { left: 0, right: 0, top: 10 }, - dpi: '72', - disposition: 'inline' + pdf_name = "#{client_name} - #{form_title}" + render pdf: pdf_name, + template: 'clients/show.pdf.haml', + page_size: 'A4', + layout: 'pdf_design.html.haml', + show_as_html: params.key?('debug'), + header: { html: { template: 'government_reports/pdf/header.pdf.haml' } }, + footer: { html: { template: 'government_reports/pdf/footer.pdf.haml' }, right: '[page] of [topage]' }, + margin: { left: 0, right: 0, top: 10 }, + dpi: '72', + disposition: 'inline' end end end @@ -102,23 +122,34 @@ def new current_org = Organization.current find_referral_by_params referral_source_id = find_referral_source_by_referral - + referral_attr = @referral.attributes + attributes = {} Organization.switch_to 'shared' - attributes = SharedClient.find_by(archived_slug: @referral.slug).try(:attributes) || SharedClient.find_by(slug: @referral.slug).try(:attributes) + attributes = SharedClient.find_by(archived_slug: referral_attr['slug'])&.attributes || SharedClient.find_by(slug: referral_attr['slug'])&.attributes if attributes.present? attributes = attributes.except('id', 'duplicate_checker') - attributes = fetch_referral_attibutes(attributes, referral_source_id) + attributes = fetch_referral_attibutes(attributes, referral_source_id, referral_attr) else - attributes + attributes.present? ? attributes.symbolize_keys : attributes end Organization.switch_to current_org.short_name if @referral - client_name = @referral.client_name.split(' ') - client_attr = { given_name: client_name.first, family_name: client_name.last, - gender: @referral.client_gender, reason_for_referral: @referral.referral_reason, - date_of_birth: @referral.client_date_of_birth - } - attributes = Client.get_client_attribute(@referral.attributes.merge(client_attr)) if attributes.nil? + client_names = @referral.client_name.split(' ') + given_name, family_name = [(client_names[0] || ''), (client_names[1] || '')] + local_family_name, local_given_name = (@referral.client_name.scan(/\(((?:[^\)\(]++))\)/).first && @referral.client_name.scan(/\(((?:[^\)\(]++))\)/).first.split(' ')) || ['', ''] + client_attr = { given_name: given_name, family_name: family_name, + local_given_name: '', local_family_name: '', + gender: @referral.client_gender, reason_for_referral: @referral.referral_reason, + date_of_birth: @referral.client_date_of_birth, + referral_source_id: referral_source_id, + initial_referral_date: @referral.date_of_referral, + from_referral_id: @referral.id } + + if attributes.present? + attributes = Client.get_client_attribute(@referral.attributes).merge(client_attr).merge(attributes) + else + attributes = Client.get_client_attribute(@referral.attributes).merge(client_attr) + end end @client = Client.new(attributes) else @@ -132,6 +163,9 @@ def new @risk_assessment = @client.build_risk_assessment @risk_assessment.tasks.build end + @custom_data = CustomData.first + @client_custom_data = @client.client_custom_data + @referral_source_category = referral_source_name(ReferralSource.parent_categories, @client) end def edit @@ -145,6 +179,15 @@ def edit end @risk_assessment = @client.risk_assessment || @client.build_risk_assessment + @custom_data = CustomData.first + client_custom_data = @client.client_custom_data + if client_custom_data + form_builder_attachments = client_custom_data.try(:form_builder_attachments).map do |form_builder_attachment| + form_builder_attachment.file.map(&:to_json) + [form_builder_attachment.name, { id: form_builder_attachment.id, files: form_builder_attachment.file.map(&:to_json).map { |file| JSON.parse(file) } }] + end + @client_custom_data_properties = (client_custom_data.properties || {}).merge(form_builder_attachments.to_h) + end end def create @@ -174,9 +217,17 @@ def update end end + def restore + client = Client.only_deleted.friendly.find(params[:id]) + client.recover + redirect_to client, notice: t('.successfully_restored') + end + def destroy + @client = Client.only_deleted.friendly.find(params[:id]) + ActiveRecord::Base.transaction do - if !@client.current_family_id? && @client.destroy + if @client.destroy begin EnterNgo.with_deleted.where(client_id: @client.id).each(&:destroy_fully!) ClientEnrollment.with_deleted.where(client_id: @client.id).delete_all @@ -184,15 +235,28 @@ def destroy CaseWorkerClient.with_deleted.where(client_id: @client.id).each(&:destroy_fully!) Task.with_deleted.where(client_id: @client.id).each(&:destroy_fully!) ExitNgo.with_deleted.where(client_id: @client.id).each(&:destroy_fully!) - redirect_to clients_url, notice: t('.successfully_deleted') + + redirect_to archived_clients_path, notice: t('.successfully_deleted') rescue => exception raise ActiveRecord::Rollback end else messages = "Can't delete client because the client is still attached with family" - redirect_to @client, alert: messages + redirect_to archived_clients_path, alert: messages end end + rescue ActiveRecord::Rollback => exception + redirect_to archived_clients_path, alert: exception + end + + def archive + if @client.current_family_id + redirect_to @client, alert: "Can't delete client because the client is still attached with family" + else + # Not using deestroy to avoid callbacks + @client.update_columns(deleted_at: Time.current, archived_by_id: current_user.id) + redirect_to clients_url, notice: t('.successfully_archived') + end rescue ActiveRecord::Rollback => exception redirect_to @client, alert: exception end @@ -207,10 +271,45 @@ def quantitative_case def version page = params[:per_page] || 20 - @client = Client.accessible_by(current_ability).friendly.find(params[:client_id]).decorate + @client = Client.accessible_by(current_ability).friendly.find(params[:client_id]).decorate @versions = @client.versions.reorder(created_at: :desc).page(params[:page]).per(page) end + def load_client_table_summary + $param_rules = params + + if searched_client_ids.present? + @results = @clients_by_user = Client.where(id: searched_client_ids.split(',')) + else + choose_grid + $param_rules = params + basic_rules = JSON.parse(params[:basic_rules] || '{}') + _clients, query = AdvancedSearches::ClientAdvancedSearch.new(basic_rules, Client.accessible_by(current_ability)).filter + @results = @clients_by_user = @client_grid.scope { |scope| scope.where(query).accessible_by(current_ability) }.assets + end + + render json: { + client_table_content: render_to_string(partial: 'clients/client_table_summary_content') + } + end + + def load_statistics_data + clients = if searched_client_ids.present? + Client.where(id: searched_client_ids.split(',')) + else + choose_grid + $param_rules = params + basic_rules = JSON.parse(params[:basic_rules] || '{}') + _clients, query = AdvancedSearches::ClientAdvancedSearch.new(basic_rules, Client.accessible_by(current_ability)).filter + clients = @client_grid.scope { |scope| scope.where(query).accessible_by(current_ability) }.assets + end + + render json: { + csi_statistics: CsiStatistic.new(clients).assessment_domain_score, + enrollments_statistics: ActiveEnrollmentStatistic.new(clients).statistic_data + } + end + private def find_client @@ -238,36 +337,36 @@ def assign_client_attributes def client_params remove_blank_exit_reasons client_params = params.require(:client) - .permit( - :slug, :archived_slug, :code, :name_of_referee, :main_school_contact, :rated_for_id_poor, :what3words, :status, :country_origin, - :kid_id, :assessment_id, :given_name, :family_name, :local_given_name, :local_family_name, :gender, :date_of_birth, - :birth_province_id, :initial_referral_date, :referral_source_id, :telephone_number, - :referral_phone, :received_by_id, :followed_up_by_id, :global_id, :shared_service_enabled, - :follow_up_date, :school_grade, :school_name, :current_address, :locality, - :house_number, :street_number, :suburb, :description_house_landmark, :directions, :street_line1, :street_line2, :plot, :road, :postal_code, :district_id, :subdistrict_id, - :has_been_in_orphanage, :has_been_in_government_care, :external_id, :external_id_display, :mosvy_number, - :relevant_referral_information, :province_id, :current_family_id, :reason_for_referral, - :state_id, :township_id, :rejected_note, :live_with, :profile, :remove_profile, - :gov_city, :gov_commune, :gov_district, :gov_date, :gov_village_code, :gov_client_code, - :gov_interview_village, :gov_interview_commune, :gov_interview_district, :gov_interview_city, - :gov_caseworker_name, :gov_caseworker_phone, :gov_carer_name, :gov_carer_relationship, :gov_carer_home, - :gov_carer_street, :gov_carer_village, :gov_carer_commune, :gov_carer_district, :gov_carer_city, :gov_carer_phone, - :gov_information_source, :gov_referral_reason, :gov_guardian_comment, :gov_caseworker_comment, :commune_id, :village_id, :referral_source_category_id, :referee_id, :carer_id, - :presented_id, :legacy_brcs_id, :id_number, :whatsapp, :other_phone_number, :brsc_branch, :current_island, :current_street, - :current_po_box, :current_settlement, :current_resident_own_or_rent, :current_household_type, - :island2, :street2, :po_box2, :settlement2, :resident_own_or_rent2, :household_type2, - interviewee_ids: [], - client_type_ids: [], - user_ids: [], - agency_ids: [], - donor_ids: [], - quantitative_case_ids: [], - custom_field_ids: [], - family_ids: [], - tasks_attributes: [:name, :domain_id, :completion_date], - client_needs_attributes: [:id, :rank, :need_id], - client_problems_attributes: [:id, :rank, :problem_id] - ) + .permit( + :slug, :archived_slug, :code, :name_of_referee, :main_school_contact, :rated_for_id_poor, :what3words, :status, :country_origin, + :kid_id, :assessment_id, :given_name, :family_name, :local_given_name, :local_family_name, :gender, :date_of_birth, + :birth_province_id, :initial_referral_date, :referral_source_id, :telephone_number, + :referral_phone, :received_by_id, :followed_up_by_id, :global_id, :shared_service_enabled, + :follow_up_date, :school_grade, :school_name, :current_address, :locality, :phone_owner, + :house_number, :street_number, :suburb, :description_house_landmark, :directions, :street_line1, :street_line2, :plot, :road, :postal_code, :district_id, :subdistrict_id, + :has_been_in_orphanage, :has_been_in_government_care, :external_id, :external_id_display, :mosvy_number, + :relevant_referral_information, :province_id, :city_id, :current_family_id, :reason_for_referral, + :state_id, :township_id, :rejected_note, :live_with, :profile, :remove_profile, + :gov_city, :gov_commune, :gov_district, :gov_date, :gov_village_code, :gov_client_code, + :gov_interview_village, :gov_interview_commune, :gov_interview_district, :gov_interview_city, + :gov_caseworker_name, :gov_caseworker_phone, :gov_carer_name, :gov_carer_relationship, :gov_carer_home, + :gov_carer_street, :gov_carer_village, :gov_carer_commune, :gov_carer_district, :gov_carer_city, :gov_carer_phone, + :gov_information_source, :gov_referral_reason, :gov_guardian_comment, :gov_caseworker_comment, :commune_id, :village_id, :referral_source_category_id, :referee_id, :carer_id, + :presented_id, :legacy_brcs_id, :id_number, :whatsapp, :other_phone_number, :brsc_branch, :current_island, :current_street, + :current_po_box, :current_settlement, :current_resident_own_or_rent, :current_household_type, + :island2, :street2, :po_box2, :settlement2, :resident_own_or_rent2, :household_type2, + interviewee_ids: [], + client_type_ids: [], + user_ids: [], + agency_ids: [], + donor_ids: [], + quantitative_case_ids: [], + custom_field_ids: [], + family_ids: [], + tasks_attributes: [:name, :domain_id, :completion_date], + client_needs_attributes: [:id, :rank, :need_id], + client_problems_attributes: [:id, :rank, :problem_id] + ) field_settings.each do |field_setting| next if field_setting.group != 'client' || field_setting.required? || field_setting.visible? @@ -280,17 +379,18 @@ def client_params def remove_blank_exit_reasons return if params[:client][:exit_reasons].blank? + params[:client][:exit_reasons].reject!(&:blank?) end def set_association - @agencies = Agency.cached_order_name - @donors = Donor.cached_order_name - @users = User.without_deleted_users.non_strategic_overviewers.order(:first_name, :last_name) - @interviewees = Interviewee.cached_order_created_at - @client_types = ClientType.cached_order_created_at - @needs = Need.cached_order_created_at - @problems = Problem.cached_order_created_at + @agencies = Agency.cached_order_name + @donors = Donor.cached_order_name + @users = User.without_deleted_users.non_strategic_overviewers.order(:first_name, :last_name) + @interviewees = Interviewee.cached_order_created_at + @client_types = ClientType.cached_order_created_at + @needs = Need.cached_order_created_at + @problems = Problem.cached_order_created_at subordinate_users = User.where('manager_ids && ARRAY[:user_id] OR id = :user_id', { user_id: current_user.id }).map(&:id) if current_user.admin? || current_user.hotline_officer? @@ -309,49 +409,68 @@ def set_association @caller_relationships = Client::RELATIONSHIP_TO_CALLER.map { |relationship| { label: relationship, value: relationship.downcase } } @address_types = Client::ADDRESS_TYPES.map { |type| { label: type, value: type.downcase } } @phone_owners = Client::PHONE_OWNERS.map { |owner| { label: owner, value: owner.downcase } } - @referral_source = @client && @client.referral_source.present? ? ReferralSource.where(id: @client.referral_source_id).map { |r| [r.try(:name), r.id] } : [] - @referral_source_category = referral_source_name(ReferralSource.parent_categories) - country_address_fields if @client + @referral_source = @client && @client.referral_source.present? ? ReferralSource.where(id: @client.referral_source_id).map { |r| [r&.name, r.id] } : [] + @referral_source_category = referral_source_name(ReferralSource.parent_categories, @client) if @client && @client.persisted? + country_address_fields(@client.instance_of?(::ClientDecorator) ? @client.object : @client) if @client end - def country_address_fields - selected_country = Setting.cache_first.try(:country_name) || params[:country] + def country_address_fields(client) + selected_country = Setting.cache_first.country_name || params[:country] current_org = Organization.current.short_name Organization.switch_to 'shared' @birth_provinces = [] - Organization.pluck(:country).uniq.reject(&:blank?).map{ |country| @birth_provinces << [country.titleize, Province.country_is(country).map{|p| [p.name, p.id] }] } + Organization.pluck(:country).uniq.reject(&:blank?).map { |country| @birth_provinces << [country.titleize, Province.country_is(country).map { |p| [p.name, p.id] }] } Organization.switch_to current_org if selected_country&.downcase == 'thailand' - @current_provinces = Province.order(:name).where.not("name ILIKE ?", "%/%") - @districts = @client.province.present? ? @client.province.cached_districts : [] - @subdistricts = @client.district.present? ? @client.district.cached_subdistricts : [] - - @referee_districts = @client.referee&.province.present? ? @client.referee.province.cached_districts : [] - @referee_subdistricts = @client.referee.try(:district).present? ? @client.referee.district.cached_subdistricts : [] + @current_provinces = Province.order(:name).where.not('name ILIKE ?', '%/%') + @cities = client.province_id.present? ? client.province.cached_cities : [] + @districts = client.province_id.present? ? client.province.cached_districts : [] + @subdistricts = client.district_id.present? ? client.district.cached_subdistricts : [] - @carer_districts = @client.carer&.province.present? ? @client.carer.province.cached_districts : [] - @carer_subdistricts = @client.carer.try(:district).present? ? @client.carer.district.cached_subdistricts : [] + @referee_districts = client.referee&.province_id.present? ? client.referee.province.cached_districts : [] + @referee_subdistricts = client.referee&.district_id.present? ? client.referee.district.cached_subdistricts : [] + @carer_districts = client.carer&.province_id.present? ? client.carer.province.cached_districts : [] + @carer_subdistricts = client.carer&.district_id.present? ? client.carer.district.cached_subdistricts : [] elsif selected_country&.downcase == 'myanmar' - @states = State.order(:name) - @townships = @client.state.present? ? @client.state.townships.order(:name) : [] - - @referee_townships = @client.referee&.state.present? ? @client.referee.state.townships.order(:name) : [] - @carer_townships = @client.carer&.state.present? ? @client.carer.state.townships.order(:name) : [] + @states = State.order(:name) + @townships = client.state_id.present? ? client.state.townships.order(:name) : [] + + @referee_townships = client.referee&.state_id.present? ? client.referee.state.townships.order(:name) : [] + @carer_townships = client.carer&.state_id.present? ? client.carer.state.townships.order(:name) : [] + elsif selected_country&.downcase == 'indonesia' + @current_provinces = Province.order(:name).where.not('name ILIKE ?', '%/%') + @cities = client.province_id.present? ? client.province.cached_cities : [] + @districts = client.city_id.present? ? client.city.cached_districts : [] + @subdistricts = client.district_id.present? ? client.district.cached_subdistricts : [] + + @referee_cities = client.referee&.province_id.present? ? client.referee.province&.cached_cities : [] + @referee_districts = client.referee&.city_id.present? ? client.referee.city.cached_districts : [] + @referee_subdistricts = client.referee&.district_id.present? ? client.referee.district.cached_subdistricts : [] + + if @client.carer&.same_as_client + @carer_cities = client.province_id.present? ? client.province.cached_cities : [] + @carer_districts = client.city_id.present? ? client.city.cached_districts : [] + @carer_subdistricts = client.district_id.present? ? client.district.cached_subdistricts : [] + else + @carer_cities = client.carer&.province_id.present? ? client.carer.province&.cached_cities : [] + @carer_districts = client.carer&.city_id.present? ? client.carer.city.cached_districts : [] + @carer_subdistricts = client.carer&.district_id.present? ? client.carer.district.cached_subdistricts : [] + end else - @current_provinces = Province.cached_order_name - @districts = @client.province.present? ? @client.province.cached_districts : [] - @communes = @client.district.present? ? @client.district.cached_communes : [] - @villages = @client.commune.present? ? @client.commune.cached_villages : [] - - @referee_districts = @client.referee.try(:province).present? ? @client.referee.province.cached_districts : [] - @referee_communes = @client.referee.try(:district).present? ? @client.referee.district.cached_communes : [] - @referee_villages = @client.referee.try(:commune).present? ? @client.referee.commune.cached_villages : [] - - @carer_districts = @client.carer.try(:province).present? ? @client.carer.province.cached_districts : [] - @carer_communes = @client.carer.try(:district).present? ? @client.carer.district.cached_communes : [] - @carer_villages = @client.carer.try(:commune).present? ? @client.carer.commune.cached_villages : [] + @current_provinces = Province.cached_order_name + @districts = client.province_id.present? ? client.province.cached_districts : [] + @communes = client.district_id.present? ? client.district.cached_communes : [] + @villages = client.commune_id.present? ? client.commune.cached_villages : [] + + @referee_districts = client.referee&.province_id.present? ? client.referee.province.cached_districts : [] + @referee_communes = client.referee&.district_id.present? ? client.referee.district.cached_communes : [] + @referee_villages = client.referee&.commune_id.present? ? client.referee.commune.cached_villages : [] + + @carer_districts = client.carer&.province_id.present? ? client.carer.province.cached_districts : [] + @carer_communes = client.carer&.district_id.present? ? client.carer.district.cached_communes : [] + @carer_villages = client.carer&.commune_id.present? ? client.carer.commune.cached_villages : [] end end @@ -381,18 +500,18 @@ def find_referral_by_params def find_referral_source_by_referral referral_source_org = Organization.find_by(short_name: @referral.referred_from)&.full_name if referral_source_org - ReferralSource.find_by(name: "#{referral_source_org} - OSCaR Referral").try(:id) + ReferralSource.child_referrals.find_by(name: "#{referral_source_org} - OSCaR Referral")&.id else - ReferralSource.find_by(name: @referral.referred_from)&.id + ReferralSource.child_referrals.find_by(name: @referral.referred_from)&.id end end - def fetch_referral_attibutes(attributes, referral_source_id) + def fetch_referral_attibutes(attributes, referral_source_id, referral_attr = {}) attributes.merge!({ - initial_referral_date: @referral.date_of_referral, - referral_phone: @referral.referral_phone, - relevant_referral_information: @referral.referral_reason, - name_of_referee: @referral.name_of_referee, + initial_referral_date: referral_attr['date_of_referral'], + referral_phone: referral_attr['referral_phone'], + relevant_referral_information: referral_attr['referral_reason'], + name_of_referee: referral_attr['name_of_referee'], referral_source_id: referral_source_id }) end diff --git a/app/controllers/communities_controller.rb b/app/controllers/communities_controller.rb index 6bacb03bd4..2833d5e6f1 100644 --- a/app/controllers/communities_controller.rb +++ b/app/controllers/communities_controller.rb @@ -12,6 +12,10 @@ class CommunitiesController < AdminController before_action :find_community, only: [:show, :edit, :update, :destroy] before_action :load_quantative_types, only: [:new, :edit, :create, :update] + def welcome + choose_grid + end + def index if has_params? advanced_search @@ -49,8 +53,8 @@ def create end def show - custom_field_ids = @community.custom_field_properties.pluck(:custom_field_id) - @free_community_forms = CustomField.community_forms.not_used_forms(custom_field_ids).order_by_form_title + custom_field_ids = @community.custom_field_properties.pluck(:custom_field_id) + @free_community_forms = CustomField.community_forms.not_used_forms(custom_field_ids).order_by_form_title @group_community_custom_fields = @community.custom_field_properties.group_by(&:custom_field_id) end @@ -75,14 +79,14 @@ def destroy def version page = params[:per_page] || 20 - @community = Community.find(params[:family_id]) + @community = Community.find(params[:family_id]) @versions = @community.versions.reorder(created_at: :desc).page(params[:page]).per(page) end private def load_quantative_types - @quantitative_types = QuantitativeType.where('visible_on LIKE ?', "%community%") + @quantitative_types = QuantitativeType.where('visible_on LIKE ?', '%community%') end def community_params @@ -95,7 +99,9 @@ def community_params :name_en, :formed_date, :province_id, + :city_id, :district_id, + :subdistrict_id, :commune_id, :village_id, :representative_name, @@ -120,9 +126,15 @@ def community_params def find_association @provinces = Province.cached_order_name - @districts = @community&.province.present? ? @community.province.cached_districts : [] - @communes = @community&.district.present? ? @community.district.cached_communes : [] - @villages = @community&.commune.present? ? @community.commune.cached_villages : [] + if current_organization.country == 'indonesia' + @cities = @community&.province_id.present? ? @community.province.cached_cities : [] + @districts = @community&.city_id.present? ? @community.city.cached_districts : [] + @subdistricts = @community&.subdistrict_id.present? ? @community.district.cached_subdistricts : [] + else + @districts = @community&.province_id.present? ? @community.province.cached_districts : [] + @communes = @community&.district_id.present? ? @community.district.cached_communes : [] + @villages = @community&.commune_id.present? ? @community.commune.cached_villages : [] + end end def find_community diff --git a/app/controllers/concerns/assessment_concern.rb b/app/controllers/concerns/assessment_concern.rb index ace0a29f00..59df884354 100644 --- a/app/controllers/concerns/assessment_concern.rb +++ b/app/controllers/concerns/assessment_concern.rb @@ -2,4 +2,28 @@ module AssessmentConcern def find_custom_assessment_setting @custom_assessment_setting = CustomAssessmentSetting.find_by(custom_assessment_name: params[:custom_name]) end -end \ No newline at end of file + + def add_more_attachments(new_file, assessment_domain_id) + return unless new_file.present? + + assessment_domain = AssessmentDomain.find(assessment_domain_id) + files = assessment_domain.attachments + files += new_file + assessment_domain.attachments = files + assessment_domain.save + end + + def fix_assessment_domains_attributes + # assign id to assessment_domain as simply autosave via ajax without updating the form + return if params.dig(:assessment, :assessment_domains_attributes).blank? + + params[:assessment][:assessment_domains_attributes].each do |index, assessment_domain_attributes| + domain_id = assessment_domain_attributes[:domain_id] + assessment_domain = @assessment.assessment_domains.find_by(domain_id: domain_id) + + if assessment_domain + params[:assessment][:assessment_domains_attributes][index] = assessment_domain_attributes.merge(id: assessment_domain.id) + end + end + end +end diff --git a/app/controllers/concerns/case_note_concern.rb b/app/controllers/concerns/case_note_concern.rb index c16b69e266..0f379a34a2 100644 --- a/app/controllers/concerns/case_note_concern.rb +++ b/app/controllers/concerns/case_note_concern.rb @@ -1,21 +1,44 @@ module CaseNoteConcern + def case_note_params + default_params = permit_case_note_params + default_params = params.require(:case_note).permit(:meeting_date, :attendee, :interaction_type, :custom, :note, :custom_assessment_setting_id, attachments: [], case_note_domain_groups_attributes: [:id, :note, :domain_group_id, :task_ids, attachments: []]) if action_name == "create" + default_params = assign_params_to_case_note_domain_groups_params(default_params) if default_params.dig(:case_note, :domain_group_ids) + default_params = default_params.merge(selected_domain_group_ids: params.dig(:case_note, :domain_group_ids).reject(&:blank?)) + meeting_date = "#{default_params[:meeting_date]} #{Time.now.strftime("%T %z")}" + default_params.merge(meeting_date: meeting_date) + end + + def permit_case_note_params + # tasks_attributes: [ + # :id, :name, :completion_date, :completed, :completed_by_id, :_destroy, + # task_progress_notes_attributes: [:id, :progress_note, :task_id, :_destroy] + # ] + params.require(:case_note).permit( + :meeting_date, :attendee, :interaction_type, :custom, :note, :custom_assessment_setting_id, + case_note_domain_groups_attributes: [ + :id, :note, :domain_group_id, :task_ids, + ], + ) + end + def assign_params_to_case_note_domain_groups_params(default_params) - note = params.dig(:additional_fields, :note) + # note = params.dig(:additional_fields, :note) attachments = params.dig(:case_note, :attachments) || [] domain_group_ids = params.dig(:case_note, :domain_group_ids)&.reject(&:blank?) || [] case_note_domain_groups = default_params[:case_note_domain_groups_attributes] - selected_case_note_domain_groups = case_note_domain_groups.select{|key, value| domain_group_ids.include? value["domain_group_id"]} + selected_case_note_domain_groups = case_note_domain_groups.select { |_, value| domain_group_ids.include? value["domain_group_id"] } value = selected_case_note_domain_groups.values.first - value['attachments'] = attachments if params[:action] == 'create' && value + value["attachments"] = attachments if params[:action] == "create" && value + + non_selected_case_note_domain_groups = case_note_domain_groups.select { |_, c_value| domain_group_ids.exclude? c_value["domain_group_id"] } + non_selected_case_note_domain_groups.values.each do |c_value| + next if params[:action] == "create" - non_selected_case_note_domain_groups = case_note_domain_groups.select{|key, value| domain_group_ids.exclude? value["domain_group_id"]} - non_selected_case_note_domain_groups.values.each do |value| - next if params[:action] == 'create' - cndg_id = value['id'].to_i + cndg_id = c_value["id"].to_i cndg_attachments = CaseNoteDomainGroup.find(cndg_id).attachments - cndg_attachments.each_with_index do |attachment, index| + cndg_attachments.each_with_index do |_, index| remove_attachment_at_index(index, cndg_id) end end @@ -24,35 +47,116 @@ def assign_params_to_case_note_domain_groups_params(default_params) def fetch_domain_group @domain_groups = [] - if params[:action].in? ['edit', 'update'] + + if params[:action].in?(["edit", "update"]) if @case_note.domain_groups.present? @domain_groups = @case_note.domain_groups else @domain_groups = DomainGroup.joins(:domains).where(id: @case_note.selected_domain_group_ids) end else - if (@case_note.custom_assessment_setting_id.present?) || (params[:custom] == 'true' && @custom_assessment_setting&.id.present?) + if @case_note.custom_assessment_setting_id.present? || (params[:custom] == "true" && @custom_assessment_setting&.id.present?) if @case_note.custom_assessment_setting_id.present? domain_group_ids = Domain.custom_csi_domains.where(custom_assessment_setting_id: @case_note.custom_assessment_setting_id).pluck(:domain_group_id).uniq else domain_group_ids = Domain.custom_csi_domains.where(custom_assessment_setting_id: @custom_assessment_setting&.id).pluck(:domain_group_id).uniq end - @domain_groups = DomainGroup.where(id: domain_group_ids) else domain_group_ids = Domain.csi_domains.pluck(:domain_group_id).uniq - @domain_groups = DomainGroup.where(id: domain_group_ids) end + @domain_groups = DomainGroup.where(id: domain_group_ids) end case_note_domain_groups = CaseNoteDomainGroup.where(case_note: @case_note, domain_group: @domain_groups) - @case_note_domain_group_note = case_note_domain_groups.where.not(note: '').map do |cndg| + @case_note_domain_group_note = case_note_domain_groups.where.not(note: "").map do |cndg| if !@case_note.custom - group_name = cndg.domains(@case_note).map(&:identity).join(', ') - "#{group_name}\n#{cndg.note}" + group_name = cndg.domains(@case_note).map(&:identity).join(", ") else group_name = cndg.domain_group.custom_domain_identities(@custom_assessment_setting&.id || @case_note.custom_assessment_setting_id) - "#{group_name}\n#{cndg.note}" end + "#{group_name}\n#{cndg.note}" end.join("\n\n").html_safe end + + def create_task_task_progress_notes + (params[:case_note]["case_note_domain_groups_attributes"].try(:values) || []).each do |case_note_domain_groups_attributes| + case_note_domain_groups_attr = case_note_domain_groups_attributes + # case_note_domain_group_id = case_note_domain_groups_attr['id'] + tasks_attributes = case_note_domain_groups_attr["tasks_attributes"] + tasks_attributes = tasks_attributes&.values || [] + tasks_attributes.each do |tasks_attr| + task_id = tasks_attr["id"] + next unless task_id.present? + + task = Task.find(task_id) + task_progress_notes_attributes = [] + next if tasks_attr["task_progress_notes_attributes"].nil? + + tasks_attr["task_progress_notes_attributes"].each do |_, v| + next if v["task_id"].present? + + task_progress_notes_attributes << v.select { |h| h["progress_note"] } + end + task.task_progress_notes.create(task_progress_notes_attributes) if task_progress_notes_attributes.present? + end + end + end + + def clean_duplicate_case_note_domain_groups + return unless save_draft? + + domain_group_ids = params.dig(:case_note, :domain_group_ids).select(&:present?) + + if domain_group_ids.present? + domain_groups = DomainGroup.where(id: domain_group_ids) + domain_group_ids = domain_groups.map do |domain_group| + domain_group.domains(@case_note).ids + end.flatten + end + + case_note_domain_groups = @case_note.case_note_domain_groups.where.not(domain_group_id: domain_group_ids) + case_note_domain_groups = @case_note.case_note_domain_groups if domain_group_ids.blank? + + case_note_domain_groups.each do |case_note_domain_group| + case_note_domain_group.tasks.destroy_all + case_note_domain_group.destroy + end + + id_mapping = {} + @case_note.case_note_domain_groups.reload.each do |case_note_domain_group| + if id_mapping[case_note_domain_group.domain_group_id].present? + case_note_domain_group.tasks.destroy_all + case_note_domain_group.destroy + else + id_mapping[case_note_domain_group.domain_group_id] = case_note_domain_group.id + end + end + end + + def remove_attachment_at_index(index, case_note_domain_group_id = "") + case_note_domain_group_id = params[:case_note_domain_group_id] || case_note_domain_group_id + case_note_domain_group = CaseNoteDomainGroup.find(case_note_domain_group_id) + remain_attachment = case_note_domain_group.attachments + deleted_attachment = remain_attachment.delete_at(index) + deleted_attachment.try(:remove_images!) + remain_attachment.empty? ? case_note_domain_group.remove_attachments! : (case_note_domain_group.attachments = remain_attachment) + t(".fail_delete_attachment") unless case_note_domain_group.save + end + + def clean_case_note_domain_groups_attributes + case_note_domain_groups_attributes = params.dig(:case_note, :case_note_domain_groups_attributes) + + return if case_note_domain_groups_attributes.blank? + + case_note_domain_groups_attributes.each do |index, case_note_domain_group_attributes| + id = case_note_domain_group_attributes[:id] + + unless CaseNoteDomainGroup.exists?(id) + case_note_domain_group_attributes.delete(:id) + case_note_domain_groups_attributes[index] = case_note_domain_group_attributes + end + end + + params[:case_note][:case_note_domain_groups_attributes] = case_note_domain_groups_attributes + end end diff --git a/app/controllers/concerns/client_advanced_searches_concern.rb b/app/controllers/concerns/client_advanced_searches_concern.rb index b258deb403..3c6da99127 100644 --- a/app/controllers/concerns/client_advanced_searches_concern.rb +++ b/app/controllers/concerns/client_advanced_searches_concern.rb @@ -8,28 +8,29 @@ def advanced_search else basic_rules = JSON.parse @basic_filter_params || @wizard_basic_filter_params || "{}" end + $param_rules = find_params_advanced_search - clients = AdvancedSearches::ClientAdvancedSearch.new(basic_rules, Client.accessible_by(current_ability)) + _clients, query = AdvancedSearches::ClientAdvancedSearch.new(basic_rules, Client.accessible_by(current_ability)).filter + + @results = @clients_by_user = @client_grid.scope { |scope| scope.where(query).accessible_by(current_ability) }.assets + cache_client_ids - @clients_by_user = clients.filter - columns_visibility + client_columns_visibility custom_form_column program_stream_column respond_to do |f| f.html do begin - @csi_statistics = CsiStatistic.new(@client_grid.scope.where(id: @clients_by_user.ids).accessible_by(current_ability)).assessment_domain_score.to_json - @enrollments_statistics = ActiveEnrollmentStatistic.new(@client_grid.scope.where(id: @clients_by_user.ids).accessible_by(current_ability)).statistic_data.to_json - clients = @client_grid.scope { |scope| scope.where(id: @clients_by_user.ids).accessible_by(current_ability) }.assets - @results = clients - @client_grid = @client_grid.scope { |scope| scope.where(id: @clients_by_user.ids).accessible_by(current_ability).page(params[:page]).per(20) } + @client_grid = @client_grid.scope { |scope| scope.where(query).accessible_by(current_ability).page(params[:page]).per(20) } rescue NoMethodError - redirect_to clients_path + redirect_to welcome_clients_path end end f.xls do - @client_grid.scope { |scope| scope.where(id: @clients_by_user.ids).accessible_by(current_ability) } + @client_grid.scope { |scope| scope.where(query).accessible_by(current_ability) } + @client_grid.params = params.to_unsafe_h.dup.deep_symbolize_keys + export_client_reports send_data @client_grid.to_xls, filename: "client_report-#{Time.now}.xls" end @@ -50,19 +51,19 @@ def build_advanced_search def fetch_advanced_search_queries @my_advanced_searches = current_user.cache_advance_saved_search - @other_advanced_searches = Rails.cache.fetch(user_cache_id << "other_advanced_search_queries") do - AdvancedSearch.includes(:user).non_of(current_user).order(:name).to_a + @other_advanced_searches = Rails.cache.fetch(user_cache_id << "other_advanced_search_queries") do + AdvancedSearch.for_client.includes(:user).non_of(current_user).to_a end end def custom_form_column - @custom_form_columns = custom_form_fields.group_by{ |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#builder' - @wizard_custom_form_columns = custom_form_fields.group_by{ |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#wizard-builder' + @custom_form_columns = custom_form_fields.group_by { |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#builder' + @wizard_custom_form_columns = custom_form_fields.group_by { |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#wizard-builder' end def program_stream_column - @program_stream_columns = program_stream_fields.group_by{ |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#builder' - @wizard_program_stream_columns = program_stream_fields.group_by{ |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#wizard-builder' + @program_stream_columns = program_stream_fields.group_by { |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#builder' + @wizard_program_stream_columns = program_stream_fields.group_by { |field| field[:optgroup] } if params.dig(:client_advanced_search, :action_report_builder) == '#wizard-builder' end def get_custom_form @@ -91,7 +92,7 @@ def client_builder_fields @builder_fields = @builder_fields + custom_form_fields if @advanced_search_params[:wizard_custom_form_check].present? @builder_fields = @builder_fields + @quantitative_fields if @advanced_search_params[:wizard_quantitative_check].present? else - @builder_fields = get_client_basic_fields + custom_form_fields + program_stream_fields + get_common_fields + @builder_fields = @builder_fields + custom_form_fields + program_stream_fields + get_common_fields + render_risk_assessment_fields @builder_fields = @builder_fields + @quantitative_fields if quantitative_check? end end @@ -111,7 +112,8 @@ def get_client_basic_fields def get_common_fields fields = program_stream_values.empty? ? [] : AdvancedSearches::CommonFields.new(program_stream_values).render fields += assessment_values.empty? ? [] : AdvancedSearches::CommonFields.new(program_stream_values, true).render - fields + + fields.uniq end def get_hotline_fields @@ -182,19 +184,26 @@ def get_quantitative_fields def get_enrollment_fields return [] if program_stream_values.empty? || !enrollment_check? + AdvancedSearches::EnrollmentFields.new(program_stream_values).render end def get_tracking_fields return [] if program_stream_values.empty? || !tracking_check? + AdvancedSearches::TrackingFields.new(program_stream_values).render end def get_exit_program_fields return [] if program_stream_values.empty? || !exit_program_check? + AdvancedSearches::ExitProgramFields.new(program_stream_values).render end + def render_risk_assessment_fields + @render_risk_assessment_fields ||= AdvancedSearches::RiskAssessmentFields.render + end + def program_stream_value? @advanced_search_params.present? && @advanced_search_params[:program_selected].present? end @@ -227,10 +236,6 @@ def assessment_values assessment_value? ? eval(@advanced_search_params[:assessment_selected]) : [] end - def get_assessments - @assessments = (Setting.cache_first.enable_default_assessment? ? [[0, Setting.cache_first.default_assessment]] : []) + CustomAssessmentSetting.all.where(enable_custom_assessment: true).pluck(:id, :custom_assessment_name).to_a - end - def has_params? @advanced_search_params.present? && @advanced_search_params[:basic_rules].present? end @@ -306,4 +311,9 @@ def legal_doc_params letter_from_immigration_police_files: [] ] end + + def cache_client_ids + @cache_key = "cache_client_ids_#{current_user.id}_#{Time.current.to_i}" + Rails.cache.write(@cache_key, @results.ids.join(','), expires_in: 10.minutes) + end end diff --git a/app/controllers/concerns/client_enrollment_concern.rb b/app/controllers/concerns/client_enrollment_concern.rb index 6a9d15823e..7d8471c348 100644 --- a/app/controllers/concerns/client_enrollment_concern.rb +++ b/app/controllers/concerns/client_enrollment_concern.rb @@ -19,7 +19,10 @@ def client_enrollment_index_path end def client_filtered - @client_filter ||= AdvancedSearches::ClientAdvancedSearch.new(@program_stream.rules, Client.all).filter + return @client_filter if defined?(@client_filter) + + @client_filter, _query = AdvancedSearches::ClientAdvancedSearch.new(@program_stream.rules, Client.all).filter + @client_filter end def ordered_program diff --git a/app/controllers/concerns/client_grid_options.rb b/app/controllers/concerns/client_grid_options.rb index 37a5cd3f76..be4b4d334b 100644 --- a/app/controllers/concerns/client_grid_options.rb +++ b/app/controllers/concerns/client_grid_options.rb @@ -13,8 +13,9 @@ def choose_grid end end - def columns_visibility + def client_columns_visibility return if params['commit'].blank? + if params[:advanced_search_id] advanced_search = AdvancedSearch.find(params[:advanced_search_id]) @client_columns = ClientColumnsVisibility.new(@client_grid, params.merge(advanced_search.field_visible).merge(column_form_builder: column_form_builder)) @@ -36,12 +37,16 @@ def export_client_reports program_stream_report program_enrollment_date_report program_exit_date_report + default_assessment_created_at default_date_of_assessments default_date_of_completed_assessments + care_plan_date care_plan_completed_date care_plan_count + custom_assessment_created_at custom_date_of_assessments default_date_of_completed_custom_assessments + export_risk_assessment_columns case_note_date_report case_note_type_report accepted_date_report @@ -56,7 +61,7 @@ def exit_reasons_report return unless @client_columns.visible_columns[:exit_reasons_].present? if params[:data].presence == 'recent' @client_grid.column(:exit_reasons, header: I18n.t('datagrid.columns.clients.exit_reasons')) do |client| - client.exit_ngos.most_recents.first.try(:exit_reasons).join(', ') if client.exit_ngos.any? + client.exit_ngos.most_recents.first&.exit_reasons.join(', ') if client.exit_ngos.any? end else @client_grid.column(:exit_reasons, header: I18n.t('datagrid.columns.clients.exit_reasons')) do |client| @@ -64,7 +69,7 @@ def exit_reasons_report reasons = [ExitNgo::EXIT_REASONS.sort, I18n.t('client.exit_ngos.form.exit_reason_options').values].transpose.to_h results = '' client.exit_ngos.most_recents.each do |exit_ngo| - results = exit_ngo.exit_reasons.map{ |reason| reasons[reason] }.join(', ') if exit_ngo.exit_reasons.present? + results = exit_ngo.exit_reasons.map { |reason| reasons[reason] }.join(', ') if exit_ngo.exit_reasons.present? end results end @@ -76,7 +81,7 @@ def exit_circumstance_report return unless @client_columns.visible_columns[:exit_circumstance_].present? if params[:data].presence == 'recent' @client_grid.column(:exit_circumstance, header: I18n.t('datagrid.columns.clients.exit_circumstance')) do |client| - client.exit_ngos.most_recents.first.try(:exit_circumstance) + client.exit_ngos.most_recents.first&.exit_circumstance end else @client_grid.column(:exit_circumstance, header: I18n.t('datagrid.columns.clients.exit_circumstance')) do |client| @@ -89,7 +94,7 @@ def other_info_of_exit_report return unless @client_columns.visible_columns[:other_info_of_exit_].present? if params[:data].presence == 'recent' @client_grid.column(:other_info_of_exit, header: I18n.t('datagrid.columns.clients.other_info_of_exit')) do |client| - client.exit_ngos.most_recents.first.try(:other_info_of_exit) + client.exit_ngos.most_recents.first&.other_info_of_exit end else @client_grid.column(:other_info_of_exit, header: I18n.t('datagrid.columns.clients.other_info_of_exit')) do |client| @@ -102,7 +107,7 @@ def exit_note_report return unless @client_columns.visible_columns[:exit_note_].present? if params[:data].presence == 'recent' @client_grid.column(:exit_note, header: I18n.t('datagrid.columns.clients.exit_note')) do |client| - client.exit_ngos.most_recents.first.try(:exit_note) + client.exit_ngos.most_recents.first&.exit_note end else @client_grid.column(:exit_note, header: I18n.t('datagrid.columns.clients.exit_note')) do |client| @@ -115,11 +120,11 @@ def exit_date_report return unless @client_columns.visible_columns[:exit_date_].present? if params[:data].presence == 'recent' @client_grid.column(:exit_date, header: I18n.t('datagrid.columns.clients.ngo_exit_date')) do |client| - client.exit_ngos.most_recents.first.try(:exit_date) + client.exit_ngos.most_recents.first&.exit_date end else @client_grid.column(:exit_date, header: I18n.t('datagrid.columns.clients.ngo_exit_date')) do |client| - date_filter(client.exit_ngos.most_recents, 'exit_date').map{|date| date.exit_date }.select(&:present?).join(', ') if client.exit_ngos.any? + date_filter(client.exit_ngos.most_recents, 'exit_date').map { |date| date.exit_date }.select(&:present?).join(', ') if client.exit_ngos.any? end end end @@ -128,11 +133,11 @@ def accepted_date_report return unless @client_columns.visible_columns[:accepted_date_].present? if params[:data].presence == 'recent' @client_grid.column(:accepted_date, header: I18n.t('datagrid.columns.clients.ngo_accepted_date')) do |client| - client.enter_ngos.most_recents.first.try(:accepted_date) + client.enter_ngos.most_recents.first&.accepted_date end else @client_grid.column(:accepted_date, header: I18n.t('datagrid.columns.clients.ngo_accepted_date')) do |client| - date_filter(client.enter_ngos.most_recents, 'accepted_date').map{|date| date.accepted_date }.select(&:present?).join(', ') if client.enter_ngos.any? + date_filter(client.enter_ngos.most_recents, 'accepted_date').map { |date| date.accepted_date }.select(&:present?).join(', ') if client.enter_ngos.any? end end end @@ -141,11 +146,11 @@ def program_stream_report return unless @client_columns.visible_columns[:program_streams_].present? if params[:data].presence == 'recent' @client_grid.column(:program_streams, header: I18n.t('datagrid.columns.clients.program_streams')) do |client| - client.client_enrollments.active.last.try(:program_stream).try(:name) + client.client_enrollments.active.last&.program_stream&.name end else @client_grid.column(:program_streams, header: I18n.t('datagrid.columns.clients.program_streams')) do |client| - client.client_enrollments.active.map{ |c| c.program_stream.try(:name) }.uniq.join(', ') + client.client_enrollments.active.map { |c| c.program_stream&.name }.uniq.join(', ') end end end @@ -159,7 +164,7 @@ def program_enrollment_date_report end else @client_grid.column(:program_enrollment_date, header: I18n.t('datagrid.columns.clients.program_enrollment_date')) do |client| - client.client_enrollments.active.map{|a| a.enrollment_date }.join(', ') + client.client_enrollments.active.map { |a| a.enrollment_date }.join(', ') end end end @@ -173,7 +178,7 @@ def program_exit_date_report end else @client_grid.column(:program_exit_date, header: I18n.t('datagrid.columns.clients.program_exit_date')) do |client| - client.client_enrollments.inactive.joins(:leave_program).map{|a| a.leave_program.exit_date }.join(', ') + client.client_enrollments.inactive.joins(:leave_program).map { |a| a.leave_program.exit_date }.join(', ') end end end @@ -182,20 +187,21 @@ def case_note_date_report return unless @client_columns.visible_columns[:case_note_date_].present? if params[:data].presence == 'recent' @client_grid.column(:case_note_date, header: I18n.t('datagrid.columns.clients.case_note_date')) do |client| - date_format(client.case_notes.most_recents.order(meeting_date: :desc).first.try(:meeting_date)) + date_format(client.case_notes.most_recents.order(meeting_date: :desc).first&.meeting_date) end else @client_grid.column(:case_note_date, header: I18n.t('datagrid.columns.clients.case_note_date')) do |client| - case_note_query(client.case_notes.most_recents, 'case_note_date').map{|date| date_format(date.meeting_date) }.select(&:present?).join(', ') if client.case_notes.any? + case_note_query(client.case_notes.most_recents, 'case_note_date').map { |date| date_format(date.meeting_date) }.select(&:present?).join(', ') if client.case_notes.any? end end end def case_note_type_report return unless @client_columns.visible_columns[:case_note_type_].present? + if params[:data].presence == 'recent' @client_grid.column(:case_note_type, header: I18n.t('datagrid.columns.clients.case_note_type')) do |client| - client.case_notes.most_recents.order(meeting_date: :desc).first.try(:interaction_type) + client.case_notes.most_recents.order(meeting_date: :desc).first&.interaction_type end else @client_grid.column(:case_note_type, header: I18n.t('datagrid.columns.clients.case_note_type')) do |client| @@ -204,26 +210,70 @@ def case_note_type_report end end + def default_assessment_created_at + return unless @client_columns.visible_columns[:assessment_created_at_].present? + + assessment_created_at('default') + end + def default_date_of_assessments return unless @client_columns.visible_columns[:date_of_assessments_].present? + date_of_assessments('default') end def default_date_of_completed_assessments return unless @client_columns.visible_columns[:completed_date_].present? + date_of_completed_assessments end def default_date_of_completed_custom_assessments return unless @client_columns.visible_columns[:custom_completed_date_].present? + date_of_completed_cusotm_assessments end + def custom_assessment_created_at + return unless @client_columns.visible_columns[:custom_assessment_created_at_].present? + + assessment_created_at('custom') + end + def custom_date_of_assessments - return unless @client_columns.visible_columns[:custom_assessment_created_date_].present? + return unless @client_columns.visible_columns[:date_of_assessments_].present? + date_of_assessments('custom') end + def assessment_created_at(type) + case type + when 'default' + records = 'client.assessments.defaults' + column = 'assessment_created_at' + when 'custom' + records = 'client.assessments.customs' + column = 'custom_assessment_created_at' + end + + header_translation = I18n.t("datagrid.columns.clients.#{column}", assessment: I18n.t('clients.show.assessment')) + if params[:data].presence == 'recent' + @client_grid.column(column.to_sym, preload: :assessments, header: header_translation) do |client| + assessment = eval(records).latest_record + next unless assessment.presence? + + assessment.created_at.to_date.to_formatted_s + end + else + @client_grid.column(column.to_sym, preload: :assessments, header: header_translation) do |client| + assessments = eval(records).most_recents + next unless assessments.any? + + date_filter(assessments, column).map { |a| a.created_at.to_date.to_formatted_s }.join(', ') + end + end + end + def date_of_assessments(type) case type when 'default' @@ -231,18 +281,18 @@ def date_of_assessments(type) column = 'date_of_assessments' when 'custom' records = 'client.assessments.customs' - column = 'custom_assessment_created_date' + column = 'date_of_custom_assessments' end - header = type == 'default' ? I18n.t("datagrid.columns.clients.#{column}", assessment: I18n.t('clients.show.assessment')) : I18n.t('datagrid.columns.clients.custom_assessment_created_date', assessment: I18n.t('clients.show.assessment')) + header = I18n.t("datagrid.columns.clients.#{column}", assessment: I18n.t('clients.show.assessment')) if params[:data].presence == 'recent' @client_grid.column(column.to_sym, preload: :assessments, header: header) do |client| - eval(records).latest_record.try(:created_at).to_date.to_formatted_s if eval(records).any? + eval(records).latest_record&.assessment_date.to_date.to_formatted_s if eval(records).any? end else @client_grid.column(column.to_sym, preload: :assessments, header: header) do |client| - date_filter(eval(records).most_recents, "#{column}").map{ |a| a.created_at.to_date.to_formatted_s }.join(', ') if eval(records).any? + date_filter(eval(records).most_recents, "#{column}").map { |a| a.created_at.to_date.to_formatted_s }.join(', ') if eval(records).any? end end end @@ -253,21 +303,21 @@ def date_of_completed_assessments if params[:data].presence == 'recent' @client_grid.column(column.to_sym, header: I18n.t("datagrid.columns.clients.assessment_completed_date", assessment: I18n.t('clients.show.assessment'))) do |client| - eval(records).latest_record.try(:completed_date).to_date.to_formatted_s if eval(records).any? + eval(records).latest_record&.completed_date.to_date.to_formatted_s if eval(records).any? end else @client_grid.column(column.to_sym, header: I18n.t("datagrid.columns.clients.assessment_completed_date", assessment: I18n.t('clients.show.assessment'))) do |client| assessments = [] if $param_rules basic_rules = $param_rules['basic_rules'] - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) - query_string = get_assessment_query_string(results, 'completed_date', '', client.id, basic_rules) + query_string = get_assessment_query_string("client_id", results, 'completed_date', '', client.id, basic_rules) assessments = client.assessments.defaults.completed.where(query_string) else assessments = client.assessments.defaults.completed end - date_filter(assessments, 'completed_date').map{ |a| a.completed_date.to_date.to_formatted_s }.join(', ') if assessments.any? + date_filter(assessments, 'completed_date').map { |a| a.completed_date.to_date.to_formatted_s }.join(', ') if assessments.any? end end end @@ -278,7 +328,7 @@ def date_of_completed_cusotm_assessments if params[:data].presence == 'recent' @client_grid.column(column.to_sym, header: I18n.t("datagrid.columns.clients.assessment_custom_completed_date", assessment: I18n.t('clients.show.assessment'))) do |client| - eval(records).latest_record.try(:completed_date).to_date.to_formatted_s if eval(records).any? + eval(records).latest_record&.completed_date.to_date.to_formatted_s if eval(records).any? end else @client_grid.column(column.to_sym, header: I18n.t("datagrid.columns.clients.assessment_custom_completed_date", assessment: I18n.t('clients.show.assessment'))) do |client| @@ -287,12 +337,12 @@ def date_of_completed_cusotm_assessments basic_rules = $param_rules['basic_rules'] basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) - query_string = get_assessment_query_string(results, 'completed_date', '', client.id, basic_rules) + query_string = get_assessment_query_string("client_id", results, 'completed_date', '', client.id, basic_rules) assessments = client.assessments.customs.completed.where(query_string) else assessments = client.assessments.customs.completed end - date_filter(assessments, 'completed_date').map{ |a| a.completed_date.to_date.to_formatted_s }.join(', ') if assessments.any? + date_filter(assessments, 'completed_date').map { |a| a.completed_date.to_date.to_formatted_s }.join(', ') if assessments.any? end end end @@ -343,9 +393,28 @@ def csi_domain_score_report assessment_results = map_assessment_and_score(client, identity, domain.id) assessments = domain.custom_domain ? assessment_results.customs : assessment_results assessment_domains = assessments.includes(:assessment_domains).map { |assessment| assessment.assessment_domains.joins(:domain).where(domains: { identity: identity }) }.flatten.uniq - assessment_domains.map{|assessment_domain| assessment_domain.try(:score) }.join(', ') + + assessment_domains.compact.map { |assessment_domain| assessment_domain.score }.compact.join(', ') + end + end + end + + def export_risk_assessment_columns + if @client_columns && @client_columns.visible_columns[:level_of_risk_].present? + @client_grid.column(:level_of_risk, header: t('risk_assessments._attr.level_of_risk')) do |client| + risk_assessment = client.risk_assessment + assessments = [risk_assessment && "#{risk_assessment.level_of_risk.titleize} (PC)", *client.assessments.client_risk_assessments.pluck(:level_of_risk).map(&:titleize)].compact + assessments.join(', ') end end + + return unless @client_columns && @client_columns.visible_columns[:date_of_risk_assessment_].present? + + @client_grid.column(:date_of_risk_assessment, header: t('risk_assessments._attr.assessment_date')) do |client| + risk_assessment = client.risk_assessment + assessments = [risk_assessment && "#{date_format(risk_assessment.assessment_date)} (PC)", *client.assessments.client_risk_assessments.pluck(:assessment_date).map { |assessment_date| date_format(assessment_date) }].compact + assessments.join(', ') + end end def custom_referral_data_report @@ -379,7 +448,7 @@ def form_builder_report if fields.last == 'Has This Form' properties = client.custom_field_properties.joins(:custom_field).where(custom_fields: { form_title: fields.second, entity_type: 'Client'}).count else - properties = client.custom_field_properties.joins(:custom_field).where(custom_fields: { form_title: fields.second, entity_type: 'Client'}).order(created_at: :desc).first.try(:properties) + properties = client.custom_field_properties.joins(:custom_field).where(custom_fields: { form_title: fields.second, entity_type: 'Client'}).order(created_at: :desc).first&.properties properties = property_filter(properties, format_field_value) properties = format_array_value(properties[format_field_value]) if properties.present? end @@ -393,7 +462,7 @@ def form_builder_report basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_form_builder_param_value(basic_rules, 'formbuilder') query_string = get_query_string(results, 'formbuilder', 'custom_field_properties.properties') - sql = query_string.reverse.reject(&:blank?).map{|sql| "(#{sql})" }.join(" AND ") + sql = query_string.reverse.reject(&:blank?).map { |sql| "(#{sql})" }.join(" AND ") custom_field_properties = client.custom_field_properties.where(custom_field_id: custom_field_id).where(sql).properties_by(format_field_value) custom_field_properties = custom_field_properties.blank? ? custom_form_with_has_form(client, fields).properties_by(format_field_value) : custom_field_properties @@ -401,57 +470,57 @@ def form_builder_report custom_field_properties = client.custom_field_properties.joins(:custom_field).where(custom_fields: { form_title: fields.second, entity_type: 'Client'}).properties_by(format_field_value) end custom_field_properties = property_filter(custom_field_properties, format_field_value) - custom_field_properties.map{ |properties| check_is_string_date?(properties) }.join(', ') + custom_field_properties.map { |properties| check_is_string_date?(properties) }.join(', ') end end elsif fields.first == 'enrollmentdate' if data == 'recent' - properties = client.client_enrollments.joins(:program_stream).where(program_streams: { name: fields.second }).order(enrollment_date: :desc).first.try(:enrollment_date) + properties = client.client_enrollments.joins(:program_stream).where(program_streams: { name: fields.second }).order(enrollment_date: :desc).first&.enrollment_date else - properties = date_filter(client.client_enrollments.joins(:program_stream).where(program_streams: { name: fields.second }), fields.join('__')).map{|date| date.enrollment_date } + properties = date_filter(client.client_enrollments.joins(:program_stream).where(program_streams: { name: fields.second }), fields.join('__')).map { |date| date.enrollment_date } properties = property_filter(properties, format_field_value) properties.join(', ') end elsif fields.first == 'enrollment' if data == 'recent' - enrollment_properties = client.client_enrollments.joins(:program_stream).where(program_streams: { name: fields.second }).order(enrollment_date: :desc).first.try(:properties) + enrollment_properties = client.client_enrollments.joins(:program_stream).where(program_streams: { name: fields.second }).order(enrollment_date: :desc).first&.properties enrollment_properties = property_filter(enrollment_properties, format_field_value) enrollment_properties = format_array_value(enrollment_properties[format_field_value]) if enrollment_properties.present? else enrollment_properties = client.client_enrollments.joins(:program_stream).where(program_streams: { name: fields.second }).properties_by(format_field_value) enrollment_properties = property_filter(enrollment_properties, format_field_value) - enrollment_properties.map{ |properties| check_is_string_date?(properties) }.join(' | ') + enrollment_properties.map { |properties| check_is_string_date?(properties) }.join(' | ') end elsif fields.first == 'tracking' ids = client.client_enrollments.ids if data == 'recent' - enrollment_tracking_properties = ClientEnrollmentTracking.joins(:tracking).where(trackings: { name: fields.third }, client_enrollment_trackings: { client_enrollment_id: ids }).order(created_at: :desc).first.try(:properties) + enrollment_tracking_properties = ClientEnrollmentTracking.joins(:tracking).where(trackings: { name: fields.third }, client_enrollment_trackings: { client_enrollment_id: ids }).order(created_at: :desc).first&.properties enrollment_tracking_properties = format_array_value(enrollment_tracking_properties[format_field_value]) if enrollment_tracking_properties.present? else client_enrollment_trackings = ClientEnrollmentTracking.joins(:tracking).where(trackings: { name: fields.third }, client_enrollment_trackings: { client_enrollment_id: ids }) properties = form_builder_query(client_enrollment_trackings, fields.first, field[:id].gsub('&qoute;', '"')).properties_by(format_field_value, client_enrollment_trackings) - properties.map{ |properties| check_is_string_date?(properties) }.join(', ') + properties.map { |properties| check_is_string_date?(properties) }.join(', ') end elsif fields.first == 'exitprogramdate' ids = client.client_enrollments.inactive.ids if data == 'recent' - properties = LeaveProgram.joins(:program_stream).where(program_streams: { name: fields.second }, leave_programs: { client_enrollment_id: ids }).order(exit_date: :desc).first.try(:exit_date) + properties = LeaveProgram.joins(:program_stream).where(program_streams: { name: fields.second }, leave_programs: { client_enrollment_id: ids }).order(exit_date: :desc).first&.exit_date else - properties = date_filter(LeaveProgram.joins(:program_stream).where(program_streams: { name: fields.second }, leave_programs: { client_enrollment_id: ids }), fields.join('__')).map{|date| date.exit_date } + properties = date_filter(LeaveProgram.joins(:program_stream).where(program_streams: { name: fields.second }, leave_programs: { client_enrollment_id: ids }), fields.join('__')).map { |date| date.exit_date } properties = property_filter(properties, format_field_value) properties.join(', ') end elsif fields.first == 'exitprogram' ids = client.client_enrollments.inactive.ids if data == 'recent' - leave_program_properties = LeaveProgram.joins(:program_stream).where(program_streams: { name: fields.second }, leave_programs: { client_enrollment_id: ids }).order(exit_date: :desc).first.try(:properties) + leave_program_properties = LeaveProgram.joins(:program_stream).where(program_streams: { name: fields.second }, leave_programs: { client_enrollment_id: ids }).order(exit_date: :desc).first&.properties leave_program_properties = property_filter(leave_program_properties, format_field_value) leave_program_properties = format_array_value(leave_program_properties[format_field_value]) if leave_program_properties.present? else leave_program_properties = LeaveProgram.joins(:program_stream).where(program_streams: { name: fields.second }, leave_programs: { client_enrollment_id: ids }).properties_by(format_field_value) leave_program_properties = property_filter(leave_program_properties, format_field_value) - leave_program_properties.map{ |properties| check_is_string_date?(properties) }.join(', ') + leave_program_properties.map { |properties| check_is_string_date?(properties) }.join(', ') end end end @@ -460,22 +529,28 @@ def form_builder_report def admin_client_grid data = params[:data].presence + if params.dig(:client_grid, :quantitative_types).present? quantitative_types = params[:client_grid][:quantitative_types] @client_grid = ClientGrid.new(params.fetch(:client_grid, {}).merge!(current_user: current_user, qType: quantitative_types, dynamic_columns: column_form_builder, param_data: data)) else @client_grid = ClientGrid.new(params.fetch(:client_grid, {}).merge!(current_user: current_user, dynamic_columns: column_form_builder, param_data: data)) end + + @client_grid.assessment_setting_id = assessment_setting_id end def non_admin_client_grid data = params[:data].presence + if params.dig(:client_grid, :quantitative_types).present? quantitative_types = params[:client_grid][:quantitative_types] @client_grid = ClientGrid.new(params.fetch(:client_grid, {}).merge!(current_user: current_user, qType: quantitative_types, dynamic_columns: column_form_builder, param_data: data)) else @client_grid = ClientGrid.new(params.fetch(:client_grid, {}).merge!(current_user: current_user, dynamic_columns: column_form_builder, param_data: data)) end + + @client_grid.assessment_setting_id = assessment_setting_id end def column_form_builder @@ -498,4 +573,8 @@ def column_form_builder def form_builder_params params[:form_builder].present? ? nil : column_form_builder end + + def assessment_setting_id + params.dig(:client_advanced_search, :assessment_selected)&.gsub("[", "")&.gsub("]", "") + end end diff --git a/app/controllers/concerns/clients_concern.rb b/app/controllers/concerns/clients_concern.rb new file mode 100644 index 0000000000..67512978f5 --- /dev/null +++ b/app/controllers/concerns/clients_concern.rb @@ -0,0 +1,31 @@ +module ClientsConcern + def referee_params + return if params[:referee].nil? + + params.require(:referee).permit( + :name, :phone, :outside, :address_type, :commune_id, :current_address, :district_id, :email, :gender, :house_number, :outside_address, :province_id, :city_id, :street_number, :village_id, :anonymous, + :state_id, :township_id, :subdistrict_id, :street_line1, :street_line2, :plot, :road, :postal_code, :suburb, :description_house_landmark, :directions, :locality + ) + end + + def carer_params + return if params[:carer].nil? + + params.require(:carer).permit( + :name, :phone, :outside, :address_type, :current_address, :email, :gender, :house_number, :street_number, :outside_address, :commune_id, :district_id, :province_id, :city_id, :village_id, :client_relationship, :same_as_client, + :state_id, :township_id, :subdistrict_id, :street_line1, :street_line2, :plot, :road, :postal_code, :suburb, :description_house_landmark, :directions, :locality + ) + end + + def risk_assessment_params + return if params[:risk_assessment].nil? + + params.require(:risk_assessment).permit( + :assessment_date, :other_protection_concern_specification, :client_perspective, :has_known_chronic_disease, + :has_disability, :has_hiv_or_aid, :known_chronic_disease_specification, :disability_specification, :hiv_or_aid_specification, + :relevant_referral_information, :level_of_risk, :history_of_disability_id, :history_of_harm_id, :history_of_high_risk_behaviour_id, + :history_of_family_separation_id, protection_concern: [], + tasks_attributes: [:id, :name, :expected_date, :client_id, :_destroy] + ) + end +end diff --git a/app/controllers/concerns/community_grid_options.rb b/app/controllers/concerns/community_grid_options.rb index 2dc471ab48..a7a8c6ac9e 100644 --- a/app/controllers/concerns/community_grid_options.rb +++ b/app/controllers/concerns/community_grid_options.rb @@ -248,7 +248,7 @@ def date_of_completed_assessments basic_rules = $param_rules['basic_rules'] basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) - query_string = get_assessment_query_string(results, 'assessment_completed_date', '', client.id, basic_rules) + query_string = get_assessment_query_string("community_id", results, 'assessment_completed_date', '', client.id, basic_rules) assessments = client.assessments.defaults.completed.where(query_string) else assessments = client.assessments.defaults.completed diff --git a/app/controllers/concerns/create_bulk_task.rb b/app/controllers/concerns/create_bulk_task.rb index 344e9e34b4..665d335361 100644 --- a/app/controllers/concerns/create_bulk_task.rb +++ b/app/controllers/concerns/create_bulk_task.rb @@ -3,41 +3,23 @@ module CreateBulkTask def create_bulk_task(task_in_params, parent = nil) case_note = parent.class.to_s =~ /decorator/i ? parent.object : parent - task_attr = task_in_params.map do |task| - task_attr = JSON.parse(task) + task_attr = task_in_params.map do |task_param| + task_attr = task_param.is_a?(String) ? JSON.parse(task_param) : task_param.to_a.to_h task_attr['name'] = task_attr['name'].gsub('qout', '"').gsub('apos', "'") task_attr['taskable_id'] = parent.id task_attr['taskable_type'] = case_note.class.to_s task_attr['expected_date'] = task_attr['expected_date'] - - task_attr.merge('case_note_id' => parent.id.to_s, user_id: current_user.id, domain_group_identity: task_attr['domain_group_identity'].to_s) + case_note_domain_group_id = case_note.case_note_domain_groups.find_by(domain_group_id: task_attr['domain_group_identity']).try(:id) + task_attr.merge( + 'case_note_id' => parent.id.to_s, + user_id: current_user.id, + case_note_domain_group_id: case_note_domain_group_id, + domain_group_identity: task_attr['domain_group_identity'].to_s + ) end tasks = case_note.parent.tasks.create(task_attr) tasks.each { |task| Calendar.populate_tasks(task) } create_events if session[:authorization] end - - def create_task_task_progress_notes - (params.dig(:case_note)['case_note_domain_groups_attributes'].try(:values) || []).each do |case_note_domain_groups_attributes| - case_note_domain_groups_attr = case_note_domain_groups_attributes - case_note_domain_group_id = case_note_domain_groups_attr['id'] - tasks_attributes = case_note_domain_groups_attr['tasks_attributes'] - tasks_attributes = tasks_attributes&.values || [] - tasks_attributes.each do |tasks_attr| - task_id = tasks_attr['id'] - if task_id.present? - task = Task.find(task_id) - task_progress_notes_attributes = [] - next if tasks_attr['task_progress_notes_attributes'].nil? - - tasks_attr['task_progress_notes_attributes'].each do |k,v| - next if v['task_id'].present? - task_progress_notes_attributes << v.select{|h| h['progress_note'] } - end - task.task_progress_notes.create(task_progress_notes_attributes) if task_progress_notes_attributes.present? - end - end - end - end end diff --git a/app/controllers/concerns/create_nested_value.rb b/app/controllers/concerns/create_nested_value.rb index bbb7328088..9ba0cb0f40 100644 --- a/app/controllers/concerns/create_nested_value.rb +++ b/app/controllers/concerns/create_nested_value.rb @@ -15,15 +15,14 @@ def create_nested_value(care_plan, goal_in_params) previous_id = task.last[:id] domain_id = task.last[:domain_id] name = task.last[:name] - expected_date = task.last[:expected_date] - relation = task.last[:relation] + expected_date = task.last[:expected_date] + relation = task.last[:relation] goal_id = goal.id - task_attr = Task.new(domain_id: domain_id, name: name, previous_id: previous_id, expected_date: expected_date, relation: relation, goal_id: goal_id, client_id: @care_plan.client_id, user_id: current_user.id, family_id: @care_plan.family&.id).attributes + task_attr = Task.new(domain_id: domain_id, name: name, previous_id: previous_id, expected_date: expected_date, relation: relation, goal_id: goal_id, client_id: care_plan.client_id, user_id: current_user.id, family_id: care_plan.family&.id).attributes goal.tasks.create(task_attr) create_goal_tasks(goal.tasks) end end - set_care_plan_completed(care_plan) end def update_nested_value(goal_in_params) @@ -64,24 +63,6 @@ def update_nested_value(goal_in_params) update_goal_attributes(goal, goal_in_params) end end - set_care_plan_completed(@care_plan) - end - - def set_care_plan_completed(care_plan) - required_assessment_domains = [] - - care_plan.assessment.assessment_domains.each do |assessment_domain| - required_assessment_domains << assessment_domain if assessment_domain[:score] == 1 || assessment_domain[:score] == 2 - end - - required_assessment_domains.each do |ad| - if care_plan.goals.where(assessment_domain_id: ad.id).empty? || (care_plan.goals.where(assessment_domain_id: ad.id).present? && care_plan.goals.where(assessment_domain_id: ad.id).first.tasks.empty?) - care_plan.update_attributes(completed: false) - return true - end - end - - care_plan.update_attributes(completed: true) end def update_goal_attributes(goal, goal_in_params) diff --git a/app/controllers/concerns/custom_field_properties_concern.rb b/app/controllers/concerns/custom_field_properties_concern.rb new file mode 100644 index 0000000000..ec5e337df5 --- /dev/null +++ b/app/controllers/concerns/custom_field_properties_concern.rb @@ -0,0 +1,15 @@ +module CustomFieldPropertiesConcern + def find_entity + if params[:client_id].present? + @custom_formable = Client.includes(custom_field_properties: [:custom_field]).accessible_by(current_ability).friendly.find(params[:client_id]) + elsif params[:family_id].present? + @custom_formable = Family.includes(custom_field_properties: [:custom_field]).find(params[:family_id]) + elsif params[:partner_id].present? + @custom_formable = Partner.includes(custom_field_properties: [:custom_field]).find(params[:partner_id]) + elsif params[:user_id].present? + @custom_formable = User.includes(custom_field_properties: [:custom_field]).find(params[:user_id]) + elsif params[:community_id].present? + @custom_formable = Community.includes(custom_field_properties: [:custom_field]).find(params[:community_id]) + end + end +end diff --git a/app/controllers/concerns/family_advanced_searches_concern.rb b/app/controllers/concerns/family_advanced_searches_concern.rb index 42efd05a51..99a385710b 100644 --- a/app/controllers/concerns/family_advanced_searches_concern.rb +++ b/app/controllers/concerns/family_advanced_searches_concern.rb @@ -6,7 +6,12 @@ module FamilyAdvancedSearchesConcern include CarePlanHelper def advanced_search - basic_rules = JSON.parse @basic_filter_params + basic_rules = if params[:advanced_search_id] + AdvancedSearch.find(params[:advanced_search_id]).queries + else + JSON.parse @basic_filter_params || @wizard_basic_filter_params || "{}" + end + $param_rules = nil $param_rules = find_params_advanced_search @families = AdvancedSearches::Families::FamilyAdvancedSearch.new(basic_rules, Family.accessible_by(current_ability)).filter @@ -65,7 +70,7 @@ def get_custom_form end def family_builder_fields - @builder_fields = get_family_basic_fields + custom_form_fields + program_stream_fields + @builder_fields = get_family_basic_fields + custom_form_fields + program_stream_fields + get_common_fields @builder_fields = @builder_fields + @quantitative_fields if quantitative_check? end @@ -270,6 +275,21 @@ def program_stream_fields @program_stream_fields = get_enrollment_fields + get_tracking_fields + get_exit_program_fields end + def get_common_fields + fields = program_stream_values.empty? ? [] : AdvancedSearches::CommonFields.new(program_stream_values).render + fields += assessment_values.empty? ? [] : AdvancedSearches::CommonFields.new(program_stream_values, true).render + + fields.uniq + end + + def assessment_values + assessment_value? ? eval(@advanced_search_params[:assessment_selected]) : [] + end + + def assessment_value? + @advanced_search_params.present? && @advanced_search_params[:assessment_selected].present? + end + def get_enrollment_fields return [] if program_stream_values.empty? || !enrollment_check? AdvancedSearches::EnrollmentFields.new(program_stream_values).render diff --git a/app/controllers/concerns/form_builder_attachments.rb b/app/controllers/concerns/form_builder_attachments.rb index 559839b67c..106eb91a9b 100644 --- a/app/controllers/concerns/form_builder_attachments.rb +++ b/app/controllers/concerns/form_builder_attachments.rb @@ -1,6 +1,7 @@ module FormBuilderAttachments def add_more_attachments(resource) return unless attachment_params.present? + attachment_params.each do |_k, attachment| name = attachment['name'] if name.present? && attachment['file'].present? @@ -29,15 +30,15 @@ def delete_form_builder_attachment(resource, name, index) end def attachment_params - if ['client_enrollments','client_enrolled_programs'].include?(controller_name) + if ['client_enrollments', 'client_enrolled_programs'].include?(controller_name) params[:client_enrollment][:form_builder_attachments_attributes] elsif ['client_enrollment_trackings', 'client_enrolled_program_trackings', 'client_trackings'].include?(controller_name) params[:client_enrollment_tracking][:form_builder_attachments_attributes] - elsif ['leave_programs','leave_enrolled_programs'].include?(controller_name) + elsif ['leave_programs', 'leave_enrolled_programs'].include?(controller_name) params[:leave_program][:form_builder_attachments_attributes] elsif ['custom_field_properties', 'client_custom_fields'].include?(controller_name) params[:custom_field_property][:form_builder_attachments_attributes] - elsif ['enrollments','enrolled_programs'].include?(controller_name) + elsif ['enrollments', 'enrolled_programs'].include?(controller_name) params[:enrollment][:form_builder_attachments_attributes] elsif ['enrollment_trackings', 'enrolled_program_trackings', 'trackings'].include?(controller_name) params[:enrollment_tracking][:form_builder_attachments_attributes] @@ -45,11 +46,11 @@ def attachment_params end def properties_params - if ['client_enrollments','client_enrolled_programs'].include?(controller_name) + if ['client_enrollments', 'client_enrolled_programs'].include?(controller_name) params[:client_enrollment][:properties] elsif ['client_enrollment_trackings', 'client_enrolled_program_trackings', 'client_trackings'].include?(controller_name) params[:client_enrollment_tracking][:properties] - elsif ['leave_programs','leave_enrolled_programs'].include?(controller_name) + elsif ['leave_programs', 'leave_enrolled_programs'].include?(controller_name) params[:leave_program][:properties] elsif ['custom_field_properties', 'client_custom_fields'].include?(controller_name) params[:custom_field_property][:properties] @@ -57,9 +58,9 @@ def properties_params end def entity_properties_params - if ['enrollments','enrolled_programs'].include?(controller_name) + if ['enrollments', 'enrolled_programs'].include?(controller_name) params[:enrollment][:properties] - elsif ['enrollment_trackings','enrolled_program_trackings', 'trackings'].include?(controller_name) + elsif ['enrollment_trackings', 'enrolled_program_trackings', 'trackings'].include?(controller_name) params[:enrollment_tracking][:properties] end end diff --git a/app/controllers/concerns/locale_concern.rb b/app/controllers/concerns/locale_concern.rb index 1fa501f735..26b14ed921 100644 --- a/app/controllers/concerns/locale_concern.rb +++ b/app/controllers/concerns/locale_concern.rb @@ -1,6 +1,6 @@ module LocaleConcern def set_locale - local = I18n.locale + old_locale, local = I18n.locale local = params[:locale] if params[:locale] && I18n.available_locales.include?(params[:locale].to_sym) if detect_browser.present? @@ -9,6 +9,8 @@ def set_locale end I18n.locale = local + + I18n.backend.reload! if old_locale != I18n.locale end def detect_browser diff --git a/app/controllers/concerns/organization_serializer_concern.rb b/app/controllers/concerns/organization_serializer_concern.rb index 4d245f3ae8..3b25181a3d 100644 --- a/app/controllers/concerns/organization_serializer_concern.rb +++ b/app/controllers/concerns/organization_serializer_concern.rb @@ -7,18 +7,22 @@ def related_services program_name: ps.name, enrollment_date: enrollment_date, uuid: service.uuid, - name: service.name + name: service.name, } end end.compact.flatten.uniq - Service.where(id: list_referrals.map(&:service_ids).flatten || []).map do |service| - service_types << { - program_name: nil, - enrollment_date: nil, - uuid: service.uuid, - name: service.name - } + list_referrals.each do |referral| + referral.services.distinct.each do |service| + service_types << { + program_name: nil, + enrollment_date: nil, + uuid: service.uuid, + name: service.name, + referral_id: referral.id, + referral_status: referral.referral_status + } + end end service_types end diff --git a/app/controllers/custom_data_controller.rb b/app/controllers/custom_data_controller.rb new file mode 100644 index 0000000000..3bb86693f2 --- /dev/null +++ b/app/controllers/custom_data_controller.rb @@ -0,0 +1,42 @@ +class CustomDataController < AdminController + before_action :find_custom_data, only: %i[edit update] + def index + @custom_data = CustomData.first + end + + def new + redirect_to custom_data_path if CustomData.first&.persisted? + + @custom_data = CustomData.new + end + + def create + @custom_data = CustomData.new(custom_data_params) + if @custom_data.save + redirect_to custom_data_path, notice: t('successfully_created', klass: 'Custom Data') + else + render :new + end + end + + def edit + end + + def update + if @custom_data.update_attributes(custom_data_params) + redirect_to custom_data_path, notice: t('successfully_updated', klass: 'Custom Data') + else + render :edit + end + end + + private + + def custom_data_params + params.require(:custom_data).permit(:fields) + end + + def find_custom_data + @custom_data = CustomData.find(params[:id]) + end +end diff --git a/app/controllers/custom_field_properties_controller.rb b/app/controllers/custom_field_properties_controller.rb index ca56eb3cd4..85a7eafb13 100644 --- a/app/controllers/custom_field_properties_controller.rb +++ b/app/controllers/custom_field_properties_controller.rb @@ -1,6 +1,7 @@ class CustomFieldPropertiesController < AdminController load_and_authorize_resource + include CustomFieldPropertiesConcern include FormBuilderAttachments before_action :find_entity, :find_custom_field @@ -11,7 +12,7 @@ class CustomFieldPropertiesController < AdminController before_action -> { check_user_permission('readable') }, only: [:show, :index] def index - @custom_field_properties = @custom_formable.custom_field_properties.accessible_by(current_ability).by_custom_field(@custom_field).most_recents.page(params[:page]).per(4) + @custom_field_properties = @custom_formable.custom_field_properties.includes(:custom_formable).accessible_by(current_ability).by_custom_field(@custom_field).most_recents.page(params[:page]).per(4) end def new @@ -62,11 +63,11 @@ def destroy def custom_field_property_params if properties_params.present? mappings = {} - properties_params.each do |k, v| + properties_params.each do |k, _| mappings[k] = k.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('%22', '"') end - formatted_params = properties_params.map {|k, v| [mappings[k], v] }.to_h - formatted_params.values.map{ |v| v.delete('') if (v.is_a?Array) && v.size > 1 } + formatted_params = properties_params.map { |k, v| [mappings[k], v] }.to_h + formatted_params.values.map { |v| v.delete('') if (v.is_a? Array) && v.size > 1 } end default_params = params.require(:custom_field_property).permit({}).merge(custom_field_id: params[:custom_field_id]) default_params = default_params.merge(properties: formatted_params) if formatted_params.present? @@ -100,20 +101,6 @@ def find_custom_field raise ActionController::RoutingError.new('Not Found') if @custom_field.nil? end - def find_entity - if params[:client_id].present? - @custom_formable = Client.includes(custom_field_properties: [:custom_field]).accessible_by(current_ability).friendly.find(params[:client_id]) - elsif params[:family_id].present? - @custom_formable = Family.includes(custom_field_properties: [:custom_field]).find(params[:family_id]) - elsif params[:partner_id].present? - @custom_formable = Partner.includes(custom_field_properties: [:custom_field]).find(params[:partner_id]) - elsif params[:user_id].present? - @custom_formable = User.includes(custom_field_properties: [:custom_field]).find(params[:user_id]) - elsif params[:community_id].present? - @custom_formable = Community.includes(custom_field_properties: [:custom_field]).find(params[:community_id]) - end - end - def check_user_permission(permission) unless current_user.admin? || current_user.strategic_overviewer? permission_set = current_user.custom_field_permissions.find_by(custom_field_id: @custom_field)[permission] diff --git a/app/controllers/dashboards_controller.rb b/app/controllers/dashboards_controller.rb index 000fa62a1d..e05f6b7927 100644 --- a/app/controllers/dashboards_controller.rb +++ b/app/controllers/dashboards_controller.rb @@ -2,6 +2,7 @@ class DashboardsController < AdminController include CsiConcern before_action :task_of_user, :find_overhaul_task_params, :find_tasks, only: [:index] + skip_before_action :notify_user, :set_sidebar_basic_info, only: [:notification, :family_tab, :side_menu_data] def index @program_streams = ProgramStream.includes(:program_stream_services, :services).where(program_stream_services: { service_id: nil }).attached_with('Client') @@ -29,6 +30,30 @@ def client_data_validation @client_grid = ClientGrid.new({ column_names: [:id, :slug, :given_name, :family_name, :local_given_name, :local_family_name, :status, :gender]}).scope { clients } end + def family_tab + @dashboard = Dashboard.new(Client.none, family_only: true) + + render json: { data: render_to_string(partial: 'family') } + end + + def notification + clients = Client.none.accessible_by(current_ability).non_exited_ngo + @notification = UserNotification.new(current_user, clients) + end + + def side_menu_data + @client_count = Client.accessible_by(current_ability).count + @family_count = Family.accessible_by(current_ability).count + @community_count = Community.accessible_by(current_ability).count + @user_count = User.where(deleted_at: nil).accessible_by(current_ability).count + @partner_count = Partner.count + @agency_count = Agency.count + @calls_count = Call.count + @referees_count = Referee.count + @referral_source_count = ReferralSource.count + @archived_count = Client.only_deleted.accessible_by(current_ability).count + end + private def find_overhaul_task_params @@ -52,13 +77,11 @@ def find_users end def find_clients - clients_overdue = [] - clients_duetoday = [] - clients_upcoming = [] clients = [] @setting = Setting.cache_first - _clients = Client.accessible_by(current_ability).active_accepted_status.distinct - eligible_clients = active_young_clients(_clients, @setting) + user_ability = Ability.new(@user) + accepted_clients = Client.accessible_by(user_ability).active_accepted_status.distinct + eligible_clients = active_young_clients(accepted_clients, @setting) eligible_clients.each do |client| overdue_tasks = [] today_tasks = [] @@ -108,6 +131,7 @@ def find_clients end end end + clients << [client, { overdue_forms: overdue_forms.uniq, today_forms: today_forms.uniq, upcoming_forms: upcoming_forms.uniq, overdue_trackings: overdue_trackings.uniq, today_trackings: today_trackings.uniq, upcoming_trackings: upcoming_trackings.uniq, overdue_tasks: overdue_tasks.flatten.uniq, @@ -130,6 +154,7 @@ def fetch_data_logic_error SQL if current_user.case_worker? || current_user.manager? + # sql += ' LEFT OUTER JOIN case_worker_clients ON case_worker_clients.client_id = clients.id' clients_error = Client.accessible_by(current_ability).joins(sql).group('clients.id, case_worker_clients.id').having(sub_sql_min_max) else clients_error = Client.accessible_by(current_ability).joins(sql).group('clients.id').having(sub_sql_min_max) diff --git a/app/controllers/data_trackers_controller.rb b/app/controllers/data_trackers_controller.rb index f25a2077bf..8d90990893 100644 --- a/app/controllers/data_trackers_controller.rb +++ b/app/controllers/data_trackers_controller.rb @@ -33,9 +33,8 @@ def find_item_type end def filter_custom_field_versions - PaperTrail::Version - .where(item_type: @item_type) - .where("object ILIKE '%custom_formable_type: #{@form_type}%' OR object_changes ILIKE '%custom_formable_type:\n- \n- #{@form_type}%'") + PaperTrail::Version.where(item_type: @item_type) + .where_object(custom_formable_type: @form_type) + .or(PaperTrail::Version.where_object_changes(custom_formable_type: @form_type)) end - end diff --git a/app/controllers/families/assessments_controller.rb b/app/controllers/families/assessments_controller.rb index f246799689..7538fb4741 100644 --- a/app/controllers/families/assessments_controller.rb +++ b/app/controllers/families/assessments_controller.rb @@ -103,8 +103,8 @@ def authorize_client end def assessment_params - default_params = params.require(:assessment).permit(:default, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last]) - default_params = params.require(:assessment).permit(:default, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last, attachments: []]) if action_name == 'create' + default_params = params.require(:assessment).permit(:default, :assessment_date, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last]) + default_params = params.require(:assessment).permit(:default, :assessment_date, assessment_domains_attributes: [:id, :domain_id, :score, :reason, :goal, :goal_required, :required_task_last, attachments: []]) if action_name == 'create' default_params end diff --git a/app/controllers/families_controller.rb b/app/controllers/families_controller.rb index 546ce3516b..09df9eb3ce 100644 --- a/app/controllers/families_controller.rb +++ b/app/controllers/families_controller.rb @@ -2,19 +2,24 @@ class FamiliesController < AdminController load_and_authorize_resource except: :show include FamilyAdvancedSearchesConcern - before_action :redirect_to_index, except: :index + before_action :redirect_to_index, except: [:index, :assessments] before_action :assign_active_family_prams, :format_search_params, only: [:index] before_action :find_params_advanced_search, :get_custom_form, :get_program_streams, only: [:index] + before_action :find_params_advanced_search, :get_custom_form, only: [:index] before_action :get_custom_form_fields, :get_quantitative_fields, :family_builder_fields, only: [:index] before_action :custom_form_fields, :program_stream_fields, only: [:index] before_action :basic_params, if: :has_params?, only: [:index] before_action :build_advanced_search, only: [:index] - before_action :find_association, except: [:index, :destroy, :version] + before_action :find_association, except: [:index, :destroy, :version, :welcome, :assessments] before_action :find_family, only: [:show, :edit, :update, :destroy] before_action :find_case_histories, only: :show - before_action :quantitative_type_readable, except: :destroy + before_action :quantitative_type_readable, except: [:index, :assessments] before_action :load_quantative_types, only: [:new, :edit, :create, :update] + def welcome + @family_grid = FamilyGrid.new + end + def index @default_columns = Setting.cache_first.try(:family_default_columns) @family_grid = FamilyGrid.new(params.fetch(:family_grid, {}).merge!(dynamic_columns: column_form_builder)) @@ -72,9 +77,9 @@ def create end def show - custom_field_ids = @family.custom_field_properties.pluck(:custom_field_id) - @free_family_forms = CustomField.family_forms.not_used_forms(custom_field_ids).order_by_form_title - @group_family_custom_fields = @family.custom_field_properties.group_by(&:custom_field_id) + custom_field_ids = @family.custom_field_properties.pluck(:custom_field_id) + @free_family_forms = CustomField.family_forms.not_used_forms(custom_field_ids).order_by_form_title + @group_family_custom_fields = @family.custom_field_properties.includes(:custom_field).group_by(&:custom_field_id) client_ids = @family.current_clients.ids if client_ids.present? @client_grid = ClientGrid.new(params[:client_grid]) @@ -120,22 +125,32 @@ def destroy def version page = params[:per_page] || 20 - @family = Family.find(params[:family_id]) + @family = Family.find(params[:family_id]) @versions = @family.versions.reorder(created_at: :desc).page(params[:page]).per(page) end + def assessments + basic_rules = JSON.parse(params[:basic_rules] || '{}') + families = AdvancedSearches::FamilyAdvancedSearch.new(basic_rules, Family.accessible_by(current_ability)) + assessments = Assessment.joins(:family).where(default: false, family_id: families.filter.ids) + + @assessments_count = assessments.count + + render json: { recordsTotal: @assessments_count, recordsFiltered: @assessments_count, data: data } + end + private def load_quantative_types - @quantitative_types = QuantitativeType.where('visible_on LIKE ?', "%family%") + @quantitative_types = QuantitativeType.where('visible_on LIKE ?', '%family%') end def family_params permitted_params = params.require(:family).permit( :name, :code, :dependable_income, :family_type, :status, :contract_date, - :address, :province_id, :district_id, :house, :street, - :commune_id, :village_id, :slug, + :address, :province_id, :city_id, :district_id, :house, :street, + :subdistrict_id, :commune_id, :village_id, :slug, :road, :plot, :postal_code, :followed_up_by_id, :follow_up_date, :name_en, :phone_number, :id_poor, :referral_source_id, :referee_phone_number, :relevant_information, :received_by_id, :initial_referral_date, :referral_source_category_id, @@ -155,28 +170,34 @@ def family_params ] ) - if permitted_params[:community_member_attributes].present? - permitted_params[:community_member_attributes][:_destroy] = 1 if permitted_params.dig(:community_member_attributes, :community_id).blank? - end + permitted_params[:community_member_attributes][:_destroy] = 1 if permitted_params[:community_member_attributes].present? && permitted_params.dig(:community_member_attributes, :community_id).blank? permitted_params end def find_association + @users = User.without_deleted_users.non_strategic_overviewers.order(:first_name, :last_name) return if @family.nil? - @users = User.without_deleted_users.non_strategic_overviewers.order(:first_name, :last_name) + @provinces = Province.cached_order_name - @districts = @family.province.present? ? @family.province.cached_districts : [] - @communes = @family.district.present? ? @family.district.cached_communes : [] - @villages = @family.commune.present? ? @family.commune.cached_villages : [] + if current_organization.country == 'indonesia' || current_organization.country == 'thailand' + @cities = @family.province_id.present? ? @family.province.cached_cities : [] + @districts = @family.city_id.present? ? @family.city.cached_districts : [] + @subdistricts = @family.subdistrict_id.present? ? @family.district.cached_subdistricts : [] + else + @districts = @family.province_id.present? ? @family.province.cached_districts : [] + @communes = @family.district_id.present? ? @family.district.cached_communes : [] + @villages = @family.commune_id.present? ? @family.commune.cached_villages : [] + end + if action_name.in?(['edit', 'update']) client_ids = Family.where.not(id: @family).pluck(:children).flatten.uniq - @family.children else client_ids = Family.where.not(id: @family).pluck(:children).flatten.uniq end - client_ids = Client.where("current_family_id = ? OR id NOT IN (?) OR current_family_id IS NULL", @family.id, Client.joins(:families).ids).ids - @clients = Client.accessible_by(current_ability).where(id: client_ids).order(:given_name, :family_name) + client_ids = Client.where('current_family_id = ? OR id NOT IN (?) OR current_family_id IS NULL', @family.id, Client.joins(:families).ids).ids + @clients = Client.accessible_by(current_ability).where(id: client_ids).order(:given_name, :family_name) end def find_family @@ -185,9 +206,9 @@ def find_family def find_case_histories enter_ngos = @family.enter_ngos - exit_ngos = @family.exit_ngos + exit_ngos = @family.exit_ngos cps_enrollments = @family.enrollments - cps_leave_programs = LeaveProgram.joins(:enrollment).where("enrollments.programmable_id = ?", @family.id) + cps_leave_programs = LeaveProgram.joins(:enrollment).where('enrollments.programmable_id = ?', @family.id) @case_histories = (enter_ngos + exit_ngos + cps_enrollments + cps_leave_programs).sort { |current_record, next_record| -([current_record.created_at, current_record.new_date] <=> [next_record.created_at, next_record.new_date]) } end @@ -198,21 +219,20 @@ def find_referral_by_params def fetch_family_attibutes(family_slug, current_org) attributes = Family.find_by(slug: family_slug).try(:attributes) - referee_phone_number = @family_referral.referral_phone if attributes.present? province_name = Province.find_by(id: attributes['province_id']).try(:name) - district_code = District.find_by(id: attributes['district_id']).try(:code) - village_code = Village.find_by(id: attributes['village_id']).try(:code) - commune_code = Commune.find_by(id: attributes['commune_id']).try(:code) + district_name = District.find_by(id: attributes['district_id'], province_id: attributes['province_id']).try(:name) + commune_name_en = Commune.find_by(id: attributes['commune_id'], district_id: attributes['district_id']).try(:name_en) + village_name_en = Village.find_by(id: attributes['village_id'], commune_id: attributes['commune_id']).try(:name_en) Organization.switch_to current_org.short_name province_id = Province.find_by(name: province_name).try(:id) - district_id = District.find_by(code: district_code).try(:id) - village_id = Village.find_by(code: village_code).try(:id) - commune_id = Commune.find_by(code: commune_code).try(:id) + district_id = District.find_by(name: district_name, province_id: province_id).try(:id) + commune_id = Commune.find_by(name_en: commune_name_en, district_id: district_id).try(:id) + village_id = Village.find_by(name_en: village_name_en, commune_id: commune_id).try(:id) - attributes = attributes.slice('name', 'name_en', 'house', 'street', 'slug', 'initial_referral_date').merge!({province_id: province_id, district_id: district_id, commune_id: commune_id, village_id: village_id, referee_phone_number: referee_phone_number}) + attributes = attributes.slice('name', 'name_en', 'house', 'street', 'slug', 'initial_referral_date', 'referee_phone_number').merge!({ province_id: province_id, district_id: district_id, commune_id: commune_id, village_id: village_id }) @family.province = Province.find_by(id: province_id) @family.district = District.find_by(id: district_id) @family.commune = Commune.find_by(id: commune_id) @@ -220,10 +240,11 @@ def fetch_family_attibutes(family_slug, current_org) @provinces = Province.order(:name) @districts = @family.province.present? ? @family.province.cached_districts : [] - @communes = @family.district.present? ? @family.district.cached_communes : [] - @villages = @family.commune.present? ? @family.commune.cached_villages : [] + @communes = @family.district.present? ? @family.district.cached_communes : [] + @villages = @family.commune.present? ? @family.commune.cached_villages : [] end @family = Family.new(attributes) + # @family.family_members.new @selected_children = params[:children] end diff --git a/app/controllers/family/assessments_controller.rb b/app/controllers/family/assessments_controller.rb new file mode 100644 index 0000000000..5f52dbb8af --- /dev/null +++ b/app/controllers/family/assessments_controller.rb @@ -0,0 +1,86 @@ +class Family::AssessmentsController < Api::ApplicationController + include FamilyAdvancedSearchesConcern + + def index + $param_rules = params + basic_rules = JSON.parse(params[:basic_rules] || '{}') + families = AdvancedSearches::Families::FamilyAdvancedSearch.new(basic_rules, Family.accessible_by(current_ability)).filter + assessments = Assessment.joins(:family).where(default: false, family_id: families.ids) + @assessments_count = assessments.count + + render json: { recordsTotal: @assessments_count, recordsFiltered: @assessments_count, data: data } + end + + private + + def data + assessment_domain_hash = {} + client_data = [] + assessment_data.each do |assessment| + assessment_domain_hash = AssessmentDomain.where(assessment_id: assessment.id).pluck(:domain_id, :score).to_h if assessment.assessment_domains.present? + domain_scores = domains.map { |domain| assessment_domain_hash.present? ? ["domain_#{domain.id}", assessment_domain_hash[domain.id]] : ["domain_#{domain.id}", ''] } + total = 0 + assessment_domain_hash.each do |index, value| + total += value || 0 + end + + client_hash = { + id: assessment.family_id, + name: assessment.family.name, + 'assessment-number': assessment.family.assessments.count, + date: assessment.created_at.strftime('%d %B %Y'), + 'average-score': total.zero? ? nil : total.fdiv(domain_scores.length).round + } + client_hash.merge!(domain_scores.to_h) + client_data << client_hash + end + + client_data + end + + def assessment_data + @assessments ||= fetch_assessments + end + + def fetch_assessments + basic_rules = JSON.parse(params[:basic_rules] || '{}') + families = AdvancedSearches::Families::FamilyAdvancedSearch.new(basic_rules, Family.accessible_by(current_ability)).filter + assessments = Assessment.joins(:family).where(default: false, family_id: families.ids) + + assessment_data = params[:length] != '-1' ? assessments.page(page).per(per_page) : assessments + end + + def domains + Domain.family_custom_csi_domains.order_by_identity + end + + def page + params[:start].to_i / per_page + 1 + end + + def per_page + params[:length].to_i > 0 ? params[:length].to_i : 10 + end + + def sort_column + domains_fields = domains.map { |domain| 'assessment_domains.score' } + columns = ["regexp_replace(clients.slug, '\\D*', '', 'g')::int", 'clients.given_name', 'clients.assessments_count', 'assessments.created_at', *domains_fields] + columns[params[:order]['0']['column'].to_i] + end + + def sort_direction + params[:order]['0']['dir'] == 'desc' ? 'desc' : 'asc' + end + + def adule_client_gender_count(clients, type = :male) + clients.public_send(type).where('(EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) >= ?', 18).count + end + + def under_18_client_gender_count(clients, type = :male) + clients.public_send(type).where('(EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) < ?', 18).count + end + + def other_client_gender_count(clients) + clients.where("gender IS NULL OR (gender NOT IN ('male', 'female'))").count + end +end diff --git a/app/controllers/field_settings_controller.rb b/app/controllers/field_settings_controller.rb index 47b3999615..df17cca62c 100644 --- a/app/controllers/field_settings_controller.rb +++ b/app/controllers/field_settings_controller.rb @@ -1,11 +1,21 @@ class FieldSettingsController < AdminController def index - @field_settings = FieldSetting.where('for_instances IS NULL OR for_instances iLIKE ?', "#{Apartment::Tenant.current}").includes(:translations).order(:group, :name) + @field_settings = FieldSetting.where('for_instances IS NULL OR for_instances iLIKE ?', "#{Apartment::Tenant.current}").includes(:translations).order(:form_group_1, :name) end def bulk_update params.require(:field_setting).each do |id, attributes| - FieldSetting.update(id, attributes.permit(:label, :visible, :required)) + I18n.with_locale(:en) do + FieldSetting.update(id, label: attributes[:label], visible: attributes[:visible] || 0) + end + + local_locale = Organization.current.local_language + + next unless local_locale.present? + + I18n.with_locale(local_locale) do + FieldSetting.update(id, label: attributes[:local_label], visible: attributes[:visible] || 0) + end end I18n.backend.reload! diff --git a/app/controllers/finance_reports_controller.rb b/app/controllers/finance_reports_controller.rb new file mode 100644 index 0000000000..39f82c564d --- /dev/null +++ b/app/controllers/finance_reports_controller.rb @@ -0,0 +1,17 @@ +class FinanceReportsController < AdminController + def index + @reports = BillableReport.recent.by_current_instance.page(params[:page]).per(12) + end + + def show + respond_to do |format| + report = BillableReport.find(params[:id]) + + format.xls do + filename = "tmp/billable-report-#{report.organization_short_name}-#{Date.today.strftime("%Y-%m-%d")}.xls" + BillableReportExportHandler.call(report, filename) + send_file filename, disposition: :attachment + end + end + end +end diff --git a/app/controllers/form_builder/custom_fields_controller.rb b/app/controllers/form_builder/custom_fields_controller.rb index 82789333f3..4b48f12956 100644 --- a/app/controllers/form_builder/custom_fields_controller.rb +++ b/app/controllers/form_builder/custom_fields_controller.rb @@ -12,9 +12,9 @@ def index def new ngo_name = params[:ngo_name] - original_custom_field = get_custom_field(params[:custom_field_id], ngo_name) + original_custom_field = get_custom_field(params[:custom_field_id], ngo_name) if ngo_name.present? && original_custom_field - @custom_field = CustomField.new(original_custom_field.attributes.merge(id: nil)) + @custom_field = CustomField.new(original_custom_field.attributes.merge(id: nil)) else @custom_field = CustomField.new end diff --git a/app/controllers/goals_controller.rb b/app/controllers/goals_controller.rb index bbfe11aca6..8dece353cf 100644 --- a/app/controllers/goals_controller.rb +++ b/app/controllers/goals_controller.rb @@ -88,4 +88,3 @@ class GoalsController < AdminController # end end - \ No newline at end of file diff --git a/app/controllers/organizations_controller.rb b/app/controllers/organizations_controller.rb index 23aaa852ba..ae901f156b 100644 --- a/app/controllers/organizations_controller.rb +++ b/app/controllers/organizations_controller.rb @@ -4,12 +4,12 @@ def index if user_signed_in? redirect_to dashboards_path(subdomain: Apartment::Tenant.current) else - redirect_to root_url(subdomain: 'start') unless request.subdomain == 'start' || request.subdomain == 'mho' + redirect_to root_url(subdomain: "start") unless request.subdomain == "start" || request.subdomain == "mho" end end def robots robots = File.read(Rails.root + "config/robots/#{Rails.env}.txt") - render text: robots, layout: false, content_type: 'text/plain' + render text: robots, layout: false, content_type: "text/plain" end end diff --git a/app/controllers/overrides/sessions_controller.rb b/app/controllers/overrides/sessions_controller.rb index 90f2a1bb43..cfb5cdcf61 100644 --- a/app/controllers/overrides/sessions_controller.rb +++ b/app/controllers/overrides/sessions_controller.rb @@ -9,7 +9,7 @@ def create private def switch_to_public! - Organization.switch_to 'public' if request.subdomain == 'start' || request.subdomain.blank? + Organization.switch_to 'public' if request.subdomain.blank? || request.subdomain.in?(['start', 'interoperability']) end end end diff --git a/app/controllers/program_streams_controller.rb b/app/controllers/program_streams_controller.rb index fb776faa79..567a1cf2f3 100644 --- a/app/controllers/program_streams_controller.rb +++ b/app/controllers/program_streams_controller.rb @@ -64,7 +64,7 @@ def update end def destroy - if @program_stream.client_enrollments.size > 0 + if @program_stream.client_enrollments.with_deleted.size.positive? @program_stream.destroy else @program_stream.destroy_fully! diff --git a/app/controllers/referral_sources_controller.rb b/app/controllers/referral_sources_controller.rb index b80e68230f..61776bf263 100644 --- a/app/controllers/referral_sources_controller.rb +++ b/app/controllers/referral_sources_controller.rb @@ -4,8 +4,8 @@ class ReferralSourcesController < AdminController before_action :find_referral_source, only: [:update, :destroy] def index - @referral_sources = ReferralSource.child_referrals.order(:name).page(params[:page]).per(10) @results = ReferralSource.count + @referral_sources = ReferralSource.child_referrals.order(:name).page(params[:page]).per(10) end def create diff --git a/app/controllers/referrals_controller.rb b/app/controllers/referrals_controller.rb index 2a3960d332..093fd800e0 100644 --- a/app/controllers/referrals_controller.rb +++ b/app/controllers/referrals_controller.rb @@ -8,7 +8,7 @@ def index if params[:referral_type].presence == 'referred_to' @referrals = @client.referrals.delivered.most_recents else - @referrals = @client.referrals.received_and_saved.most_recents + @referrals = @client.referrals.received.most_recents end end @@ -65,6 +65,12 @@ def update end end + def destroy + @referral = Referral.find(params[:id]) + @referral.dec_client_referral_count! + @referral.destroy + end + private def find_referral diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index 98454580c6..d73f83c933 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -1,5 +1,5 @@ class RegistrationsController < Devise::RegistrationsController - before_action :notify_user, :set_sidebar_basic_info, only: [:edit, :update] + before_action :notify_user, only: [:edit] before_action :set_paper_trail_whodunnit def new @@ -60,11 +60,6 @@ def after_update_path_for(resource) private def notify_user - clients = Client.accessible_by(current_ability) - @notification = UserNotification.new(current_user, clients) - end - - def set_sidebar_basic_info - @dashboard = Dashboard.new(current_user) + @lazy_load_notification = true end end diff --git a/app/controllers/release_notes_controller.rb b/app/controllers/release_notes_controller.rb new file mode 100644 index 0000000000..7366a5a002 --- /dev/null +++ b/app/controllers/release_notes_controller.rb @@ -0,0 +1,7 @@ +class ReleaseNotesController < AdminController + def index + @release_notes = ReleaseNote.order('published_at DESC').published.page(params[:page]).per(1) + @release_note = @release_notes.first + current_user.notifications.relase_note.unread.where(notifiable: @release_note).update_all(seen_at: Time.now) + end +end diff --git a/app/controllers/screening_assessments_controller.rb b/app/controllers/screening_assessments_controller.rb index dc5880c21d..decf0df93c 100644 --- a/app/controllers/screening_assessments_controller.rb +++ b/app/controllers/screening_assessments_controller.rb @@ -1,5 +1,5 @@ -class ScreeningAssessmentsController < AdminController - load_and_authorize_resource params: :screening_assessment_params +class ScreeningAssessmentsController < AdminController + load_and_authorize_resource :ScreeningAssessment before_action :find_screening_assessment, except: [:index, :new, :create] before_action :find_client before_action :find_previous_screening_assessment, only: [:new, :create, :edit, :update] @@ -70,15 +70,18 @@ def authorize_screening_assessment(screening_assessment) end def screening_assessment_params - params.require(:screening_assessment).permit( - :screening_assessment_date, :client_age, :visitor, :client_milestone_age, :note, - :smile_back_during_interaction, :follow_object_passed_midline, :turn_head_to_sound, - :head_up_45_degree, :screening_type, :client_id, attachments: [], - developmental_marker_screening_assessments_attributes: [ - :id, :developmental_marker_id, :question_1, :question_2, :question_3, :question_4, :_destroy - ], - tasks_attributes: [:id, :client_id, :name, :expected_date, :completion_date, :taskable_id, :taskable_type, :relation, :_destroy] - ) + params.require(:screening_assessment) + .permit( + :screening_assessment_date, :client_age, :visitor, :client_milestone_age, :note, + :smile_back_during_interaction, :follow_object_passed_midline, :turn_head_to_sound, + :head_up_45_degree, :screening_type, :client_id, + attachments: [], + developmental_marker_screening_assessments_attributes: + [ + :id, :developmental_marker_id, :question_1, :question_2, :question_3, :question_4, :_destroy + ], + tasks_attributes: [:id, :client_id, :name, :expected_date, :completion_date, :taskable_id, :taskable_type, :relation, :_destroy] + ) end def find_screening_assessment @@ -90,6 +93,6 @@ def find_client end def find_previous_screening_assessment - @previous_screening_assessment = ScreeningAssessment.where(client_id: @client.id).where.not(id: @screening_assessment.id).last + @previous_screening_assessment = ScreeningAssessment.where(client_id: @client.id).where.not(id: @screening_assessment.id).last if @screening_assessment end end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 2cd785aecc..0aee91f5b5 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -1,6 +1,7 @@ class SessionsController < Devise::SessionsController include LocaleConcern - before_action :set_whodunnit, :set_current_ngo, :detect_browser + + before_action :set_whodunnit, :detect_browser after_action :increase_visit_count, only: :create skip_before_action :set_locale, only: :create @@ -12,12 +13,7 @@ def set_whodunnit end end - def set_current_ngo - @current_ngo = Organization.current - end - def increase_visit_count Visit.create(user: current_user) end - end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index a7633b3cbd..54678d2555 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -9,6 +9,9 @@ class SettingsController < AdminController def index end + def screening_forms; end + def care_plan; end + def create @setting = Setting.new(setting_params) if @setting.save @@ -28,8 +31,7 @@ def edit end def update - @setting = @setting - if params[:setting].has_key?(:org_form) + if params[:setting].key?(:org_form) if @setting.update_attributes(setting_params) redirect_to :back, notice: t('.successfully_updated') else @@ -41,7 +43,7 @@ def update if @setting.update_attributes(setting_params) redirect_to :back, notice: t('.successfully_updated') else - flash[:alert] = @setting.errors.full_messages.join(", ") + flash[:alert] = @setting.errors.full_messages.join(', ') render :index end end @@ -63,6 +65,9 @@ def default_columns def research_module end + def internal_referral_module + end + def custom_labels end @@ -76,11 +81,38 @@ def family_case_management end def integration - attribute = params[:setting] - if attribute && current_organization.update_attributes(integrated: attribute[:integrated]) - redirect_to integration_settings_path, notice: t('.successfully_updated') + @current_organization = Organization.find_by(short_name: Apartment::Tenant.current) + if request.put? + @current_organization.integrated = params.dig(:setting, :integrated) + @current_organization.last_integrated_date = Date.current if @current_organization.integrated? + + if @current_organization.save + redirect_to integration_settings_path, notice: t('.successfully_updated') + else + render :integration + end + end + end + + def finance_dashboard + @setting = Setting.cache_first + + if request.put? + if @setting.update_attributes(finance_dashboard: params.dig(:setting, :finance_dashboard)) + redirect_to finance_dashboard_settings_path, notice: t('successfully_updated', klass: 'Setting') + else + render :finance_dashboard + end + end + end + + def header_count + return unless request.put? + + if @setting.update_attributes(setting_params) + redirect_to :back, notice: t('.successfully_updated') else - render :integration + render :header_count end end @@ -103,7 +135,7 @@ def risk_assessment if attribute && @setting.update_attributes(setting_params) redirect_to :back, notice: t('successfully_updated', klass: t('settings.update.successfully_updated')) else - flash[:alert] = @setting.errors.full_messages.join(", ") if @setting.errors.full_messages.any? + flash[:alert] = @setting.errors.full_messages.join(', ') if @setting.errors.full_messages.any? render :risk_assessment end end @@ -117,7 +149,7 @@ def redirect_to_default def country_address_fields @provinces = Province.cached_order_name @districts = Setting.cache_first.province.present? ? Setting.cache_first.province.districts.order(:name) : [] - @communes = Setting.cache_first.district.present? ? Setting.cache_first.district.communes.order(:name_kh, :name_en) : [] + @communes = Setting.cache_first.district.present? ? Setting.cache_first.district.communes.order(:name_kh, :name_en) : [] end def setting_params @@ -132,10 +164,11 @@ def setting_params :enable_hotline, :enable_client_form, :assessment_score_order, :disable_required_fields, :hide_family_case_management_tool, :hide_community, :case_conference_limit, :case_conference_frequency, :internal_referral_limit, :internal_referral_frequency, :case_note_edit_limit, :case_note_edit_frequency, - :tracking_form_edit_limit, :tracking_form_edit_frequency, :disabled_future_completion_date, :disabled_task_date_field, - :disabled_add_service_received, :custom_field_limit, :custom_field_frequency, :test_client, :required_case_note_note, - :hide_case_note_note, :cbdmat_one_off, :cbdmat_ongoing, :enabled_risk_assessment, :assessment_type_name, - :level_of_risk_guidance, + :disabled_future_completion_date, :cbdmat_one_off, :cbdmat_ongoing, :enabled_internal_referral, + :tracking_form_edit_limit, :tracking_form_edit_frequency, :disabled_add_service_received, + :custom_field_limit, :custom_field_frequency, :test_client, :disabled_task_date_field, + :required_case_note_note, :hide_case_note_note, :enabled_risk_assessment, :assessment_type_name, + :level_of_risk_guidance, :organization_type, :enabled_header_count, client_default_columns: [], family_default_columns: [], community_default_columns: [], partner_default_columns: [], user_default_columns: [], selected_domain_ids: [], custom_assessment_settings_attributes: [:id, :custom_assessment_name, :max_custom_assessment, :custom_assessment_frequency, :custom_age, :enable_custom_assessment, :_destroy]) @@ -151,15 +184,15 @@ def find_setting def client_default_columns columns = [] - sub_columns = %w(carer_name_ carer_phone_ carer_email_ time_in_cps_ time_in_ngo_ rejected_note_ exit_reasons_ exit_circumstance_ other_info_of_exit_ exit_note_ what3words_ main_school_contact_ rated_for_id_poor_ name_of_referee_ - family_ family_id_ case_note_date_ case_note_type_ date_of_assessments_ assessment_completed_date_ all_csi_assessments_ date_of_custom_assessments_ custom_assessment_ custom_completed_date_ custom_assessment_ created_date_ all_custom_csi_assessments_ manage_ changelog_ type_of_service_ indirect_beneficiaries_) - sub_columns += Client::HOTLINE_FIELDS.map{ |field| "#{field}_" } - sub_columns += Call::FIELDS.map{ |field| "#{field}_" } - filter_columns = ClientGrid.new.filters.map(&:name).select{ |field_name| policy(Client).show?(field_name) } + sub_columns = %w[carer_name_ carer_phone_ carer_email_ time_in_cps_ time_in_ngo_ rejected_note_ exit_reasons_ exit_circumstance_ other_info_of_exit_ exit_note_ what3words_ main_school_contact_ rated_for_id_poor_ name_of_referee + family_ family_id_ case_note_date_ case_note_type_ date_of_assessments_ assessment_completed_date_ all_csi_assessments_ date_of_custom_assessments_ custom_assessment_ custom_completed_date_ custom_assessment_ created_date_ all_custom_csi_assessments_ manage_ changelog_ type_of_service_ indirect_beneficiaries_] + sub_columns += Client::HOTLINE_FIELDS.map { |field| "#{field}_" } + sub_columns += Call::FIELDS.map { |field| "#{field}_" } + filter_columns = ClientGrid.new.filters.map(&:name).select { |field_name| policy(Client).show?(field_name) } filter_columns_not_used = [:has_date_of_birth, :quantitative_data, :quantitative_types, :all_domains, :domain_1a, :domain_1b, :domain_2a, :domain_2b, :domain_3a, - :domain_3b, :domain_4a, :domain_4b, :domain_5a, :domain_5b, :domain_6a, :domain_6b, :assessments_due_to, :no_case_note, :overdue_task, :overdue_forms, :province_id, :birth_province_id, :commune, :house_number, :village, :street_number, :district] + :domain_3b, :domain_4a, :domain_4b, :domain_5a, :domain_5b, :domain_6a, :domain_6b, :assessments_due_to, :no_case_note, :overdue_task, :overdue_forms, :province_id, :city_id, :birth_province_id, :commune, :house_number, :village, :street_number, :district] columns_name = filter_columns - filter_columns_not_used - columns = columns_name.map { |name| "#{name.to_s}_" } + columns = columns_name.map { |name| "#{name}_" } Domain.client_domians.order_by_identity.each do |domain| columns << "#{domain.convert_identity}_" end @@ -172,10 +205,10 @@ def client_default_columns def family_default_columns columns = [] - sub_columns = %w(member_count_ clients_ case_workers_ manage_ direct_beneficiaries_ changelog_) - columns = FamilyGrid.new.filters.map{|f| "#{f.name.to_s}_" } + sub_columns = %w[member_count_ clients_ case_workers_ manage_ direct_beneficiaries_ changelog_] + columns = FamilyGrid.new.filters.map { |f| "#{f.name.to_s}_" } unless current_setting.hide_family_case_management_tool? - sub_columns += %w(case_note_date_ case_note_type_ assessment_completed_date_ date_of_custom_assessments_ all_custom_csi_assessments_) + sub_columns += %w[case_note_date_ case_note_type_ assessment_completed_date_ date_of_custom_assessments_ all_custom_csi_assessments_] Domain.family_custom_csi_domains.order_by_identity.each do |domain| columns << "#{domain.convert_custom_identity}_" end @@ -185,14 +218,14 @@ def family_default_columns def community_default_columns columns = [] - sub_columns = %w(manage_ changelog_) - columns = community_grid_columns.map{ |k, _| "#{k}_" } + sub_columns = %w[manage_ changelog_] + columns = community_grid_columns.map { |k, _| "#{k}_" } columns.push(sub_columns).flatten end def partner_default_columns columns = [] - sub_columns = %w(manage_ changelog_) + sub_columns = %w[manage_ changelog_] columns = PartnerGrid.new.filters.map { |f| "#{f.name}_" } columns.push(sub_columns).flatten end @@ -201,15 +234,15 @@ def international_address_columns country = Setting.cache_first.try(:country_name) || params[:country] case country when 'thailand' - %w(province_id_ birth_province_id_ district_ subdistrict_ postal_code_ plot_ road_) + %w[province_id_ birth_province_id_ district_ subdistrict_ postal_code_ plot_ road_] when 'lesotho' - %w(suburb_ directions_ description_house_landmark_) + %w[suburb_ directions_ description_house_landmark_] when 'myanmar' - %w(street_line1_ street_line2_ township_ state_) + %w[street_line1_ street_line2_ township_ state_] when 'uganda' - %w(province_id_ birth_province_id_ district_ commune_ house_number_ village_ street_number_) + %w[province_id_ birth_province_id_ district_ commune_ house_number_ village_ street_number_] else - %w(province_id_ birth_province_id_ district_ commune_ house_number_ village_ street_number_) + %w[province_id_ birth_province_id_ district_ commune_ house_number_ village_ street_number_] end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 85da9e2d60..b0ded057e8 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -45,7 +45,7 @@ def show @free_user_forms = CustomField.user_forms.not_used_forms(custom_field_ids).order_by_form_title @group_user_custom_fields = @user.custom_field_properties.group_by(&:custom_field_id) - @client_grid = ClientGrid.new(params.fetch(:client_grid, {}).merge!(current_user: @user)) + @client_grid = ClientGrid.new(params.fetch(:client_grid, { column_names: [:id, :slug, :given_name, :family_name, :local_given_name, :local_family_name, :status, :gender, :manage] }).merge!(current_user: @user)) @results = @client_grid.scope { |scope| scope.of_case_worker(@user.id) }.assets.size @client_grid.scope do |scope| @@ -103,7 +103,6 @@ def restore end end - private def user_params diff --git a/app/decorators/client_decorator.rb b/app/decorators/client_decorator.rb index 3406923fb5..1c1d74effe 100644 --- a/app/decorators/client_decorator.rb +++ b/app/decorators/client_decorator.rb @@ -28,9 +28,9 @@ def birth_province def time_in_ngo if model.time_in_ngo.present? time_in_ngo = model.time_in_ngo - years = h.t('.time_in_care_around.year', count: time_in_ngo[:years]) if time_in_ngo[:years] > 0 - months = h.t('.time_in_care_around.month', count: time_in_ngo[:months]) if time_in_ngo[:months] > 0 - days = h.t('.time_in_care_around.day', count: time_in_ngo[:days]) if time_in_ngo[:days] > 0 + years = h.t('clients.show.time_in_care_around.year', count: time_in_ngo[:years]) if time_in_ngo[:years] > 0 + months = h.t('clients.show.time_in_care_around.month', count: time_in_ngo[:months]) if time_in_ngo[:months] > 0 + days = h.t('clients.show.time_in_care_around.day', count: time_in_ngo[:days]) if time_in_ngo[:days] > 0 [years, months, days].join(' ') end end diff --git a/app/decorators/custom_datum_decorator.rb b/app/decorators/custom_datum_decorator.rb new file mode 100644 index 0000000000..5f6be819e6 --- /dev/null +++ b/app/decorators/custom_datum_decorator.rb @@ -0,0 +1,13 @@ +class CustomDatumDecorator < Draper::Decorator + delegate_all + + # Define presentation-specific methods here. Helpers are accessed through + # `helpers` (aka `h`). You can override attributes, for example: + # + # def created_at + # helpers.content_tag :span, class: 'time' do + # object.created_at.strftime("%a %m/%d/%y") + # end + # end + +end diff --git a/app/grids/client_grid.rb b/app/grids/client_grid.rb index 8ab34611d5..f08882457a 100644 --- a/app/grids/client_grid.rb +++ b/app/grids/client_grid.rb @@ -5,11 +5,11 @@ class ClientGrid < BaseGrid include FormBuilderHelper include AssessmentHelper - attr_accessor :current_user, :qType, :dynamic_columns, :param_data + attr_accessor :current_user, :qType, :dynamic_columns, :param_data, :assessment_setting_id, :params COUNTRY_LANG = { "cambodia" => "(Khmer)", "thailand" => "(Thai)", "myanmar" => "(Burmese)", "lesotho" => "(Sesotho)", "uganda" => "(Swahili)" } scope do - Client + Client.includes(:village, :commune, :district, :province, :family_member) end %w(given_name family_name local_given_name local_family_name).each do |field_name| @@ -178,7 +178,7 @@ def user_select_options end def case_worker_options - User.has_clients.map { |user| ["#{user.first_name} #{user.last_name}", user.id] } + User.cach_has_clients_case_worker_options end filter(:donor_name, :enum, select: :donor_select_options, header: -> { I18n.t('datagrid.columns.clients.donor') }) @@ -512,6 +512,18 @@ def client_hotline_fields end end + dynamic do + quantitative_type_readable_ids = current_user.quantitative_type_permissions.readable.pluck(:quantitative_type_id) unless current_user.nil? + + QuantitativeType.cach_free_text_fields_by_visible_on("client").each do |qqt_free_text| + if current_user.nil? || quantitative_type_readable_ids.include?(qqt_free_text.id) + column(qqt_free_text.name.to_sym, class: 'quantitative-type', header: -> { qqt_free_text.name }, html: true) do |object| + object.client_quantitative_free_text_cases.where("quantitative_type_id = ?", qqt_free_text.id).pluck(:content).join(', ') + end + end + end + end + dynamic do quantitative_type_readable_ids = current_user.quantitative_type_permissions.readable.pluck(:quantitative_type_id) unless current_user.nil? quantitative_types = QuantitativeType.cached_quantitative_cases @@ -546,7 +558,7 @@ def client_hotline_fields render partial: 'clients/active_client_enrollments', locals: { active_programs: client_enrollments } end - column(:received_by, order: proc { |object| object.joins(:received_by).order('users.first_name, users.last_name')}, html: true, header: -> { I18n.t('datagrid.columns.clients.received_by') }) do |object| + column(:received_by, preload: :received_by, order: proc { |object| object.joins(:received_by).order('users.first_name, users.last_name')}, html: true, header: -> { I18n.t('datagrid.columns.clients.received_by') }) do |object| render partial: 'clients/users', locals: { object: object.received_by } if object.received_by end @@ -586,31 +598,31 @@ def call_fields end end - column(:referee_name, header: -> { I18n.t('datagrid.columns.clients.referee_name') }) do |object| - object.referee && object.referee.name + column(:referee_name, preload: :referee, header: -> { I18n.t('datagrid.columns.clients.referee_name') }) do |object| + object.referee&.name end - column(:referee_phone, header: -> { I18n.t('datagrid.columns.clients.referee_phone') }) do |object| - object.referee && object.referee.phone + column(:referee_phone, preload: :referee, header: -> { I18n.t('datagrid.columns.clients.referee_phone') }) do |object| + object.referee&.phone end - column(:referee_email, header: -> { I18n.t('datagrid.columns.clients.referee_email') }) do |object| - object.referee && object.referee.email + column(:referee_email, preload: :referee, header: -> { I18n.t('datagrid.columns.clients.referee_email') }) do |object| + object.referee&.email end - column(:carer_name, header: -> { I18n.t('activerecord.attributes.carer.name') }) do |object| - object.carer && object.carer.name + column(:carer_name, preload: :carer, header: -> { I18n.t('activerecord.attributes.carer.name') }) do |object| + object.carer&.name end - column(:carer_phone, header: -> { I18n.t('activerecord.attributes.carer.phone') }) do |object| - object.carer && object.carer.phone + column(:carer_phone, preload: :carer, header: -> { I18n.t('activerecord.attributes.carer.phone') }) do |object| + object.carer&.phone end - column(:carer_email, header: -> { I18n.t('activerecord.attributes.carer.email') }) do |object| - object.carer && object.carer.email + column(:carer_email, preload: :carer, header: -> { I18n.t('activerecord.attributes.carer.email') }) do |object| + object.carer&.email end - column(:carer_relationship_to_client, header: -> { I18n.t('datagrid.columns.clients.carer_relationship_to_client') }) do |object| + column(:carer_relationship_to_client, preload: :carer, header: -> { I18n.t('datagrid.columns.clients.carer_relationship_to_client') }) do |object| object.carer&.client_relationship end @@ -651,8 +663,8 @@ def call_fields object.followed_up_by.try(:name) end - column(:referred_to, order: false, header: -> { I18n.t('datagrid.columns.clients.referred_to') }) do |object| - short_names = object.referrals.pluck(:referred_to) + column(:referred_to, preload: :referrals, order: false, header: -> { I18n.t('datagrid.columns.clients.referred_to') }) do |object| + short_names = object.referrals.map(&:referred_to) org_names = Organization.cached_organization_short_names(short_names) if short_names.include?('external referral') org_names << "I don't see the NGO I'm looking for" @@ -662,40 +674,31 @@ def call_fields org_names.join(', ') end - column(:referred_from, order: false, header: -> { I18n.t('datagrid.columns.clients.referred_from') }) do |object| - short_names = object.referrals.pluck(:referred_from) + column(:referred_from, preload: :referrals, order: false, header: -> { I18n.t('datagrid.columns.clients.referred_from') }) do |object| + short_names = object.referrals.map(&:referred_from) org_names = Organization.cached_organization_short_names(short_names) org_names << "MoSVY External System" if short_names.include?("MoSVY External System") org_names.join(', ') end - column(:referred_in, order: false, header: -> { I18n.t('advanced_search.fields.referred_in') }) do |object| - object.referrals.received.count + column(:referred_in, preload: :referrals, order: false, header: -> { I18n.t('advanced_search.fields.referred_in') }) do |object| + object.referrals.to_a.count(&:received?) end - column(:referred_out, order: false, header: -> { I18n.t('advanced_search.fields.referred_out') }) do |object| - object.referrals.delivered.count + column(:referred_out, preload: :referrals, order: false, header: -> { I18n.t('advanced_search.fields.referred_out') }) do |object| + object.referrals.to_a.count(&:delivered?) end - column(:agency, order: false, header: -> { I18n.t('datagrid.columns.clients.agencies_involved') }) do |object| - object.agencies.pluck(:name).join(', ') - end - - column(:date_of_birth, html: true, header: -> { I18n.t('datagrid.columns.clients.date_of_birth') }) do |object| - current_org = Organization.current - Organization.switch_to 'shared' - date_of_birth = SharedClient.cached_shared_client_date_of_birth(object.slug) - Organization.switch_to current_org.short_name - date_of_birth.present? ? date_of_birth.strftime("%d %B %Y") : '' + column(:agency, preload: :agencies, order: false, header: -> { I18n.t('datagrid.columns.clients.agencies_involved') }) do |object| + object.agencies.map(&:name).join(', ') end - column(:date_of_birth, html: false, header: -> { I18n.t('datagrid.columns.clients.date_of_birth') }) do |object| - current_org = Organization.current - Organization.switch_to 'shared' - date_of_birth = SharedClient.cached_shared_client_date_of_birth(object.slug) - Organization.switch_to current_org.short_name - date_of_birth.present? ? date_of_birth : '' + column(:date_of_birth, header: -> { I18n.t('datagrid.columns.clients.date_of_birth') }) do |object| + Apartment::Tenant.switch('shared') do + date_of_birth = SharedClient.cached_shared_client_date_of_birth(object.slug) + date_of_birth&.strftime("%d %B %Y") + end end column(:age, header: -> { I18n.t('datagrid.columns.clients.age') }, order: 'clients.date_of_birth desc') do |object| @@ -739,11 +742,9 @@ def call_fields end column(:birth_province_id, html: true, header: -> { I18n.t('datagrid.columns.clients.birth_province') }) do |object| - current_org = Organization.current - Organization.switch_to 'shared' - birth_province = SharedClient.cached_shared_client_birth_province_name(object.slug) - Organization.switch_to current_org.short_name - birth_province + Apartment::Tenant.switch('shared') do + SharedClient.cached_shared_client_birth_province_name(object.slug) + end end if I18n.locale == :km @@ -915,9 +916,10 @@ def call_fields column(:relevant_referral_information, header: -> { I18n.t('datagrid.columns.clients.relevant_referral_information') }) - column(:referral_source_id, order: proc { |object| Client.cached_client_referral_source_name(object) }, header: -> { I18n.t('datagrid.columns.clients.referral_source') }) do |object| - object.referral_source.try(:name) + column(:referral_source_id, preload: :referral_source, order: proc { |object| Client.cached_client_referral_source_name(object) }, header: -> { I18n.t('datagrid.columns.clients.referral_source') }) do |object| + object.referral_source&.name end + column(:referral_source_category_id, order: proc { |object| Client.cached_client_referral_source_name(object) }, header: -> { I18n.t('datagrid.columns.clients.referral_source_category') }) do |object| if I18n.locale == :km ReferralSource.cached_referral_source_try_name(object.referral_source_category_id) @@ -926,30 +928,36 @@ def call_fields end end - column(:accepted_date, order: false, header: -> { I18n.t('datagrid.columns.clients.ngo_accepted_date') }, html: true) do |object| - render partial: 'clients/accepted_dates', locals: { object: object } + column(:accepted_date, preload: :enter_ngos, order: false, header: -> { I18n.t('datagrid.columns.clients.ngo_accepted_date') }, html: true) do |object| + enter_ngos = object.enter_ngos.sort_by(&:created_at).reverse + render partial: 'clients/accepted_dates', locals: { enter_ngos: enter_ngos } end - column(:exit_date, order: false, header: -> { I18n.t('datagrid.columns.clients.ngo_exit_date') }, html: true) do |object| - render partial: 'clients/exit_dates', locals: { object: object } + column(:exit_date, preload: :exit_ngos, order: false, header: -> { I18n.t('datagrid.columns.clients.ngo_exit_date') }, html: true) do |object| + exit_ngos = object.exit_ngos.sort_by(&:created_at).reverse + render partial: 'clients/exit_dates', locals: { exit_ngos: exit_ngos, client: object } end column(:rejected_note, header: -> { I18n.t('datagrid.columns.clients.rejected_note') }) - column(:exit_circumstance, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.exit_circumstance') }) do |object| - render partial: 'clients/exit_circumstances', locals: { object: object } + column(:exit_circumstance, preload: :exit_ngos, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.exit_circumstance') }) do |object| + exit_ngos = object.exit_ngos.sort_by(&:created_at).reverse + render partial: 'clients/exit_circumstances', locals: { exit_ngos: exit_ngos, client: object } end - column(:exit_reasons, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.exit_reasons') }) do |object| - render partial: 'clients/exit_reasons', locals: { object: object } + column(:exit_reasons, preload: :exit_ngos, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.exit_reasons') }) do |object| + exit_ngos = object.exit_ngos.sort_by(&:created_at).reverse + render partial: 'clients/exit_reasons', locals: { exit_ngos: exit_ngos, client: object } end - column(:other_info_of_exit, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.other_info_of_exit') }) do |object| - render partial: 'clients/other_info_of_exits', locals: { object: object } + column(:other_info_of_exit, preload: :exit_ngos, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.other_info_of_exit') }) do |object| + exit_ngos = object.exit_ngos.sort_by(&:created_at).reverse + render partial: 'clients/other_info_of_exits', locals: { exit_ngos: exit_ngos, client: object } end - column(:exit_note, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.exit_note') }) do |object| - render partial: 'clients/exit_notes', locals: { object: object } + column(:exit_note, preload: :exit_ngos, order: false, html: true, header: -> { I18n.t('datagrid.columns.clients.exit_note') }) do |object| + exit_ngos = object.exit_ngos.sort_by(&:created_at).reverse + render partial: 'clients/exit_notes', locals: { exit_ngos: exit_ngos, client: object } end column(:what3words, header: -> { I18n.t('datagrid.columns.clients.what3words') }) do |object| @@ -964,37 +972,37 @@ def call_fields object.rated_for_id_poor end - column(:user_id, order: false, header: -> { I18n.t('datagrid.columns.clients.case_worker') }) do |object| - object.users.pluck(:first_name, :last_name).map{ |case_worker| "#{case_worker.first} #{case_worker.last}".squish }.join(', ') + column(:user_id, preload: :users, order: false, header: -> { I18n.t('datagrid.columns.clients.case_worker') }) do |object| + object.users.uniq.map{ |case_worker| "#{case_worker.first_name} #{case_worker.last_name}".squish }.join(', ') end - column(:donor_name, order: false, header: -> { I18n.t('datagrid.columns.clients.donor')}) do |object| - object.donors.pluck(:name).join(', ') + column(:donor_name, preload: :donors, order: false, header: -> { I18n.t('datagrid.columns.clients.donor')}) do |object| + object.donors.uniq.map(&:name).join(', ') end column(:arrival_at, header: -> { I18n.t('clients.form.arrival_at')}) do |object| - object.arrival_at.present? ? object.arrival_at.strftime("%Y-%m-%d %H:%M") : '' + object.arrival_at&.strftime("%Y-%m-%d %H:%M") end column(:flight_nb, order: false, header: -> { I18n.t('clients.form.flight_nb')}) column(:ratanak_achievement_program_staff_client_ids, order: false, header: -> { I18n.t('clients.form.ratanak_achievement_program_staff_client_ids')}) do |object| - object.ratanak_achievement_program_staff_clients.pluck(:first_name, :last_name).map{ |case_worker| "#{case_worker.first} #{case_worker.last}".squish }.join(', ') + object.ratanak_achievement_program_staff_clients.distinct.map{ |case_worker| "#{case_worker.first_name} #{case_worker.last_name}".squish }.join(', ') end column(:mo_savy_officials, order: false, header: -> { I18n.t('clients.form.mosavy_official')}) do |object| object.mo_savy_officials.map{ |mo_savy_official| "#{mo_savy_official.name} #{mo_savy_official.position}".squish }.join(', ') end - column(:family_id, order: false, header: -> { I18n.t('advanced_search.fields.family_id') }) do |object| - object.family.try(:id) + column(:family_id, preload: :family, order: false, header: -> { I18n.t('advanced_search.fields.family_id') }) do |object| + object.family&.id end - column(:family, order: false, header: -> { I18n.t('datagrid.columns.clients.placements.family') }) do |object| - object.family.try(:name) + column(:family, preload: :family, order: false, header: -> { I18n.t('datagrid.columns.clients.placements.family') }) do |object| + object.family&.name end - column(:family_type, order: false, header: -> { I18n.t('datagrid.columns.families.family_type') }) do |object| - object.family.try(:family_type) + column(:family_type, preload: :family, order: false, header: -> { I18n.t('datagrid.columns.families.family_type') }) do |object| + object.family&.family_type end column(:case_note_date, header: -> { I18n.t('datagrid.columns.clients.case_note_date')}, html: true) do |object| @@ -1005,8 +1013,12 @@ def call_fields render partial: 'clients/case_note_type', locals: { object: object } end + column(:assessment_created_at, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.assessment_created_at', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + render partial: 'clients/assessments', locals: { object: object.assessments.defaults.order(:created_at), assessment_field_name: nil } + end + column(:date_of_assessments, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.date_of_assessments', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| - render partial: 'clients/assessments', locals: { object: object.assessments.defaults.order(:created_at) } + render partial: 'clients/assessments', locals: { object: object.assessments.defaults.order(:assessment_date), assessment_field_name: 'assessment_date' } end column(:completed_date, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.assessment_completed_date', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| @@ -1041,8 +1053,12 @@ def call_fields render partial: 'clients/referral', locals: { object: object } end - column(:custom_assessment_created_date, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.custom_assessment_created_date', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| - render partial: 'clients/assessments', locals: { object: object.assessments.customs.order(:created_at) } + column(:custom_assessment_created_at, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.custom_assessment_created_at', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + render partial: 'clients/assessments', locals: { object: object.assessments.customs.order(:created_at), assessment_field_name: nil } + end + + column(:date_of_custom_assessments, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.date_of_custom_assessments', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + render partial: 'clients/assessments', locals: { object: object.assessments.customs.order(:assessment_date), assessment_field_name: 'assessment_date' } end column(:custom_assessment, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.custom_assessment', assessment: I18n.t('clients.show.assessment')) }) do |object| @@ -1081,6 +1097,10 @@ def call_fields render partial: 'clients/completed_assessments', locals: { object: assessments } end + column(:care_plan_date, header: -> { I18n.t('care_plans.care_plan_date') }, html: true) do |object| + render partial: 'shared/care_plans/care_plan_date', locals: { object: object.care_plans } + end + column(:care_plan_completed_date, header: -> { I18n.t('datagrid.columns.clients.care_plan_completed_date') }, html: true) do |object| render partial: 'shared/care_plans/care_plans', locals: { object: object.care_plans } end @@ -1132,7 +1152,8 @@ def call_fields column(:all_csi_assessments, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.all_csi_assessments', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| render partial: 'clients/all_csi_assessments', locals: { object: object.assessments.defaults } end - Domain.csi_domains.order_by_identity.each do |domain| + + Domain.cache_order_by_identity.select(&:client_csi?).each do |domain| domain_id = domain.id identity = domain.identity column(domain.convert_identity.to_sym, class: 'domain-scores', header: identity, html: true) do |client| @@ -1250,10 +1271,38 @@ def call_fields end end + column(:level_of_risk, preload: [:risk_assessment, :assessments], class: 'text-center', html: true, header: -> { I18n.t('risk_assessments._attr.level_of_risk') }) do |object| + risk_assessment = object.risk_assessment + assessments = [risk_assessment, *object.assessments.select(&:client_risk_assessment?)] + render partial: 'clients/level_of_risk_list', locals: { assessments: assessments.compact } + end + + column(:date_of_risk_assessment, preload: [:risk_assessment, :assessments], class: 'text-center', html: true, header: -> { I18n.t('risk_assessments._attr.assessment_date') }) do |object| + risk_assessment = object.risk_assessment + assessments = [risk_assessment, *object.assessments.select(&:client_risk_assessment?)] + render partial: 'clients/risk_assessment_list', locals: { assessments: assessments.compact } + end + + column(:has_disability, preload: :risk_assessment, class: 'text-center', header: -> { I18n.t('risk_assessments._attr.has_disability') }) do |object| + risk_assessment = object.risk_assessment + format(risk_assessment&.has_disability ? 'Yes' : 'No') + end + + column(:has_hiv_or_aid, preload: :risk_assessment, class: 'text-center', header: -> { I18n.t('risk_assessments._attr.has_hiv_or_aid') }) do |object| + risk_assessment = object.risk_assessment + format(risk_assessment&.has_hiv_or_aid ? 'Yes' : 'No') + end + + column(:has_known_chronic_disease, preload: :risk_assessment, class: 'text-center', header: -> { I18n.t('risk_assessments._attr.has_known_chronic_disease') }) do |object| + risk_assessment = object.risk_assessment + format(risk_assessment&.has_known_chronic_disease ? 'Yes' : 'No') + end + dynamic do column(:manage, html: true, class: 'text-center', header: -> { I18n.t('datagrid.columns.clients.manage') }) do |object| render partial: 'clients/actions', locals: { object: object } end + column(:changelog, html: true, class: 'text-center', header: -> { I18n.t('datagrid.columns.clients.changelogs') }) do |object| link_to t('datagrid.columns.clients.view'), client_version_path(object) end @@ -1262,4 +1311,8 @@ def call_fields def custom_form_with_has_form(object, fields) [object.custom_field_properties.joins(:custom_field).where(custom_fields: { form_title: fields.second, entity_type: 'Client'}).count] end + + def custom_assessment_setting + @custom_assessment_setting ||= CustomAssessmentSetting.find_by(id: assessment_setting_id) + end end diff --git a/app/grids/family_grid.rb b/app/grids/family_grid.rb index b5f4f40ee6..2b960fe7ca 100644 --- a/app/grids/family_grid.rb +++ b/app/grids/family_grid.rb @@ -127,6 +127,16 @@ def family_id_poor scope.caregiver_information_like(value) end + filter(:program_streams, :enum, multiple: true, select: :program_stream_options, header: -> { I18n.t('datagrid.columns.families.program_streams') }) do |name, scope| + program_stream_ids = ProgramStream.name_like(name).ids + ids = Family.joins(:enrollments).where(enrollments: { program_stream_id: program_stream_ids } ).pluck(:id).uniq + scope.where(id: ids) + end + + def program_stream_options + ProgramStream.joins(:enrollments).complete.ordered.pluck(:name).uniq + end + filter(:referral_source_id, :enum, select: :referral_source_options, header: -> { I18n.t('datagrid.columns.families.referral_source_id') }) filter(:referral_source_category_id, :enum, select: :referral_source_category_options, header: -> { I18n.t('datagrid.columns.families.referral_source_category_id') }) @@ -142,16 +152,6 @@ def referral_source_category_options end end - filter(:program_streams, :enum, multiple: true, select: :program_stream_options, header: -> { I18n.t('datagrid.columns.families.program_streams') }) do |name, scope| - program_stream_ids = ProgramStream.name_like(name).ids - ids = Family.joins(:enrollments).where(enrollments: { program_stream_id: program_stream_ids } ).pluck(:id).uniq - scope.where(id: ids) - end - - def program_stream_options - ProgramStream.joins(:enrollments).complete.ordered.pluck(:name).uniq - end - def filer_section(filter_name) { street: :address, @@ -197,18 +197,18 @@ def filer_section(filter_name) column(:code, header: -> { I18n.t('datagrid.columns.families.code') }) - column(:name, html: true, order: 'LOWER(name)', header: -> { I18n.t('datagrid.columns.families.name') }) do |object| - link_to entity_name(object), family_path(object) + column(:name, order: 'LOWER(name)', header: -> { I18n.t('datagrid.columns.families.name') }) do |object| + format(object.name) do |value| + link_to entity_name(object), family_path(object) if value.present? + end end column(:name_en, order: 'LOWER(name_en)', header: -> { I18n.t('datagrid.columns.families.name_en') }) do |object| - format(object.name_en) do |value| link_to value, family_path(object) if value.present? end end - column(:name, html: false, header: -> { I18n.t('datagrid.columns.families.name') }) column(:family_type, header: -> { I18n.t('datagrid.columns.families.family_type') }) do |object| object.family_type @@ -394,6 +394,10 @@ def filer_section(filter_name) render partial: 'families/active_family_enrollments', locals: { active_programs: family_enrollments } end + column(:direct_beneficiaries, header: -> { I18n.t('datagrid.columns.families.direct_beneficiaries') }) do |object| + object.member_count + end + dynamic do next unless dynamic_columns.present? dynamic_columns.each do |column_builder| @@ -483,32 +487,105 @@ def filer_section(filter_name) end end - dynamic do - if !Setting.cache_first.hide_family_case_management_tool? - column(:all_custom_csi_assessments, header: -> { I18n.t('datagrid.columns.all_custom_csi_assessments', assessment: t('families.family_assessment')) }, html: true) do |object| - render partial: 'families/all_csi_assessments', locals: { object: object.assessments.customs } + column(:assessment_created_at, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.assessment_created_at', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + render partial: 'clients/assessments', locals: { object: object.assessments.defaults.order(:created_at), assessment_field_name: nil } + end + + column(:date_of_assessments, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.date_of_assessments', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + render partial: 'clients/assessments', locals: { object: object.assessments.defaults.order(:assessment_date), assessment_field_name: 'assessment_date' } + end + + column(:completed_date, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.assessment_completed_date', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + if $param_rules + basic_rules = $param_rules['basic_rules'] + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) + assessment_completed_sql, assessment_number = assessment_filter_values(results) + sql = "(assessments.completed = true)".squish + if assessment_number.present? && assessment_completed_sql.present? + assessments = Family.cached_family_assessment_number_completed_date(object, sql, assessment_number) + elsif assessment_completed_sql.present? + sql = assessment_completed_sql[/assessments\.completed_date.*/] + assessments = Family.cached_family_sql_assessment_completed_date(object, sql) + else + rule = basic_rules['rules'].select {|h| h['id'] == 'date_of_assessments' }.first + if rule.present? + date_of_assessments_query = date_of_assessments_query_string(rule[:id], rule['field'], rule['operator'], rule['value']) + assessments = object.assessments.defaults.where(date_of_assessments_query) + else + assessments = object.assessments.defaults + end + assessments = Family.cached_family_sql_assessment_completed_date(object, sql) end + else + assessments = Family.cached_family_assessment_order_completed_date(object) + end + render partial: 'clients/completed_assessments', locals: { object: assessments } + end - Domain.family_custom_csi_domains.order_by_identity.each do |domain| - domain_id = domain.id - identity = domain.identity - column("#{domain.convert_custom_identity}".to_sym, class: 'domain-scores', header: identity, html: true) do |family| - assessments = map_assessment_and_score(family, identity, domain_id) - assessment_domains = assessments.includes(:assessment_domains).map { |assessment| assessment.assessment_domains.joins(:domain).where(domains: { id: domain_id }) }.flatten.uniq - render partial: 'families/list_domain_score', locals: { assessment_domains: assessment_domains } + column(:date_of_referral, header: -> { I18n.t('datagrid.columns.clients.date_of_referral') }, html: true) do |object| + render partial: 'clients/referral', locals: { object: object } + end + + column(:custom_assessment_created_at, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.custom_assessment_created_at', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + render partial: 'clients/assessments', locals: { object: object.assessments.customs.order(:created_at), assessment_field_name: nil } + end + + column(:date_of_custom_assessments, preload: :assessments, header: -> { I18n.t('datagrid.columns.date_of_family_assessment', assessment: I18n.t('clients.show.assessment')) }, html: true) do |object| + render partial: 'clients/assessments', locals: { object: object.assessments.customs.order(:assessment_date), assessment_field_name: 'assessment_date' } + end + + column(:custom_assessment, preload: :assessments, header: -> { I18n.t('datagrid.columns.clients.custom_assessment', assessment: I18n.t('clients.show.assessment')) }) do |object| + custom_assessment_names = object.assessments.customs.joins(domains: :custom_assessment_setting).order(:created_at).distinct.pluck('custom_assessment_settings.custom_assessment_name', 'assessments.created_at') + custom_assessment_names = custom_assessment_names.map{|custom_assessment_name, assessment_date| "#{custom_assessment_name} (#{assessment_date.strftime("%d %B %Y")})" } + format(custom_assessment_names.join(', ')) do |values| + unorderred_list(values.split(', ')) + end + end + + column(:custom_completed_date, preload: :assessments, header: -> { I18n.t('datagrid.columns.assessment_completed_date', assessment: I18n.t('families.family_assessment')) }, html: true) do |object| + if $param_rules + basic_rules = $param_rules['basic_rules'] + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_assessment_query_rules(basic_rules).reject(&:blank?) + assessment_completed_sql, assessment_number = assessment_filter_values(results) + sql = "(assessments.completed = true)".squish + if assessment_number.present? && assessment_completed_sql.present? + assessments = Family.cached_family_assessment_custom_number_completed_date(object, sql, assessment_number) + elsif assessment_completed_sql.present? + sql = assessment_completed_sql[/assessments\.completed_date.*/] + assessments = Family.cached_family_sql_assessment_custom_completed_date(object, sql) + else + rule = basic_rules['rules'].select {|h| h['id'] == 'date_of_assessments' }.first + if rule.present? + date_of_assessments_query = date_of_assessments_query_string(rule[:id], rule['field'], rule['operator'], rule['value']) + assessments = object.assessments.customs.where(date_of_assessments_query) + else + assessments = object.assessments.customs end + assessments = Family.cached_family_sql_assessment_custom_completed_date(object, sql) end + else + assessments = Family.cached_family_assessment_custom_order_completed_date(object) end + render partial: 'clients/completed_assessments', locals: { object: assessments } end - column(:date_of_custom_assessments, header: -> { I18n.t('datagrid.columns.date_of_family_assessment', assessment: I18n.t('families.show.assessment')) }, html: true) do |object| - assessments = map_assessment_and_score(object, '', nil) - render partial: 'families/assessments', locals: { object: assessments } - end + dynamic do + if Setting.cache_first.enable_custom_assessment? + column(:all_custom_csi_assessments, preload: :assessments, header: -> { I18n.t('datagrid.columns.all_custom_csi_assessments', assessment: t('families.show.assessment')) }, html: true) do |object| + render partial: 'clients/all_csi_assessments', locals: { object: object.assessments.customs } + end - column(:custom_completed_date, header: -> { I18n.t('datagrid.columns.assessment_completed_date', assessment: I18n.t('families.show.assessment')) }, html: true) do |object| - assessments = map_assessment_and_score(object, '', nil) - render partial: 'families/assessments/assessment_completed_dates', locals: { object: assessments } + Domain.family_custom_csi_domains.order_by_identity.each do |domain| + identity = domain.identity + column("custom_#{domain.convert_identity}".to_sym, class: 'domain-scores', header: identity, html: true) do |object| + assessments = map_assessment_and_score(object, identity, domain.id) + assessment_domains = assessments.map { |assessment| assessment.assessment_domains.joins(:domain).where(domains: { identity: identity }) }.flatten.uniq + render partial: 'clients/list_domain_score', locals: { assessment_domains: assessment_domains } + end + end + end end dynamic do diff --git a/app/helpers/addresses_helper.rb b/app/helpers/addresses_helper.rb new file mode 100644 index 0000000000..a45b32beef --- /dev/null +++ b/app/helpers/addresses_helper.rb @@ -0,0 +1,74 @@ +module AddressesHelper + def selected_country + country = Organization.current.country || Setting.cache_first.try(:country_name) || params[:country].presence + country.nil? ? 'cambodia' : country + end + + def country_address_field(object) + country = selected_country + current_address = [] + current_address << translate_address_field(object, 'house_number') + current_address << translate_address_field(object, 'street_number') + + case country + when 'thailand' + current_address << object.plot if object.plot.present? + current_address << object.road if object.road.present? + current_address << object.subdistrict_name if object.subdistrict.present? + current_address << object.district_name if object.district.present? + current_address << object.province_name if object.province.present? + current_address << object.postal_code if object.postal_code.present? + current_address << 'Thailand' + when 'lesotho' + current_address << object.suburb if object.suburb.present? + current_address << object.description_house_landmark if object.description_house_landmark.present? + current_address << object.directions if object.directions.present? + current_address << 'Lesotho' + when 'myanmar' + current_address << object.street_line1 if object.street_line1.present? + current_address << object.street_line2 if object.street_line2.present? + current_address << object.township_name if object.township.present? + current_address << object.state_name if object.state.present? + current_address << 'Myanmar' + when 'uganda' + current_address = merged_address(object) + when 'indonesia' + current_address << object.subdistrict_name if object.subdistrict.present? + current_address << object.district_name if object.district.present? + current_address << object.city_name if object.city.present? + current_address << object.province_name if object.province.present? + current_address << object.postal_code if object.try(:postal_code).present? + current_address << 'Indonesia' + else + current_address = merged_address(object) + end + current_address.compact.join(', ') + end + + def merged_address(object) + current_address = [] + current_address << translate_address_field(object, 'house_number') + current_address << translate_address_field(object, 'street_number') + current_address << translate_address_field(object, 'village') + current_address << translate_address_field(object, 'commune') + if I18n.locale.to_s == 'km' + current_address << object.district_name.split(' / ').first if object.district.present? + current_address << object.province_name.split(' / ').first if object.province.present? + current_address << 'កម្ពុជា' if Organization.current.short_name != 'brc' + else + current_address << object.district_name.split(' / ').last if object.district.present? + current_address << object.province_name.split(' / ').last if object.province.present? + current_address << 'Cambodia' if Organization.current.short_name != 'brc' + end + current_address + end + + def translate_address_field(object, field) + klass_name = (object.class.name[/Decorator/] ? object.object : object).class.name.downcase.pluralize + if I18n.locale.to_s == 'km' + "#{I18n.t("datagrid.columns.#{klass_name}.#{field}")} #{object.public_send(field).try(:name_kh) || object.public_send(field)}" if object.public_send(field).present? + elsif object.methods.include?(field) && object.public_send(field).present? + "#{I18n.t("datagrid.columns.#{klass_name}.#{field}")} #{object.public_send(field).try(:name_en) || object.public_send(field)}" + end + end +end diff --git a/app/helpers/advanced_search_field_helper.rb b/app/helpers/advanced_search_field_helper.rb index 46f137a081..8c46f0652c 100644 --- a/app/helpers/advanced_search_field_helper.rb +++ b/app/helpers/advanced_search_field_helper.rb @@ -22,13 +22,10 @@ def created_by_options(klass_name = 'Client') def referral_source_category_options(klass_name = 'Client') return [] if klass_name.constantize.count.zero? ref_cat_ids = klass_name.constantize.pluck(:referral_source_category_id).compact.uniq - if I18n.locale == :km - ref_cat_kh_names = ReferralSource.where(id: ref_cat_ids).pluck(:name, :id) - ref_cat_kh_names.sort.map { |s| { s[1].to_s => s[0] } } - else - ref_cat_en_names = ReferralSource.where(id: ref_cat_ids).pluck(:name_en, :id) - ref_cat_en_names.sort.map { |s| { s[1].to_s => s[0] } } - end + + ReferralSource.cache_all.map do |item| + { item.id.to_s => I18n.locale == :km ? item.name : item.name_en } if item.id.in?(ref_cat_ids) + end.compact.sort_by { |h| h.values.first } end def referral_source_options(klass_name = 'Client') @@ -42,6 +39,6 @@ def mapping_care_plan_date_lable_translation end def care_plan_date_fields - ['care_plan_completed_date'] + ['care_plan_date', 'care_plan_completed_date'] end end diff --git a/app/helpers/advanced_search_helper.rb b/app/helpers/advanced_search_helper.rb index 635a1d4df9..26048c8b98 100644 --- a/app/helpers/advanced_search_helper.rb +++ b/app/helpers/advanced_search_helper.rb @@ -167,6 +167,8 @@ def format_header(key, group_name = 'client') assessment_number: I18n.t('advanced_search.fields.assessment_number', assessment: I18n.t('clients.show.assessment')), assessment_completed_date: I18n.t('advanced_search.fields.assessment_completed_date', assessment: I18n.t('clients.show.assessment')), custom_completed_date: I18n.t('advanced_search.fields.assessment_custom_completed_date', assessment: I18n.t('clients.show.assessment')), + date_of_custom_assessments: I18n.t('datagrid.columns.clients.date_of_custom_assessments', assessment: I18n.t('clients.show.assessment')), + custom_assessment_created_at: I18n.t('datagrid.columns.clients.custom_assessment_created_at', assessment: I18n.t('clients.show.assessment')), completed_date: I18n.t('advanced_search.fields.assessment_completed_date', assessment: I18n.t('clients.show.assessment')), month_number: I18n.t('advanced_search.fields.month_number'), custom_csi_group: I18n.t('advanced_search.fields.custom_csi_group'), @@ -181,6 +183,7 @@ def format_header(key, group_name = 'client') ratanak_achievement_program_staff_client_ids: I18n.t('clients.form.ratanak_achievement_program_staff_client_ids'), mo_savy_officials: I18n.t('clients.form.mosavy_official'), **overdue_translations, + **custom_assessment_field_traslation_mapping, **address_translation(group_name), number_client_referred_gatekeeping: I18n.t('advanced_search.fields.number_client_referred_gatekeeping'), number_client_billable: I18n.t('advanced_search.fields.number_client_billable'), @@ -189,13 +192,21 @@ def format_header(key, group_name = 'client') client_rejected: I18n.t('advanced_search.fields.client_rejected'), incomplete_care_plan: I18n.t('advanced_search.fields.incomplete_care_plan'), case_history: I18n.t('default_family_fields.case_history'), - family: I18n.t('advanced_search.fields.family'), case_note: I18n.t('dashboards.case_note_tab.case_note'), other: I18n.t('advanced_search.fields.other'), - common_searches: I18n.t('advanced_search.fields.common_searches') + common_searches: I18n.t('advanced_search.fields.common_searches'), + risk_assessment: I18n.t('risk_assessments._attr.risk_assessment') } translations = label_translations(address_translation(group_name)).merge(translations) + + if group_name == 'family' + translations[:custom_assessment_created_at] = I18n.t('datagrid.columns.family_assessment_created_at') + translations[:date_of_custom_assessments] = I18n.t('datagrid.columns.date_of_family_assessment') + translations[:custom_completed_date] = I18n.t('datagrid.columns.assessment_completed_date', assessment: I18n.t('families.family_assessment')) + translations[:custom_csi_domain_scores] = I18n.t('advanced_search.fields.family_assessment_domain_scores') + end + translations[key.to_sym] || '' end @@ -206,7 +217,6 @@ def family_header(key) def community_header(key) translations = { - initial_referral_date: I18n.t('advanced_search.fields.initial_referral_date'), name: I18n.t('activerecord.attributes.community.name'), name_en: I18n.t('activerecord.attributes.community.name_en'), status: I18n.t('activerecord.attributes.community.status'), @@ -289,7 +299,7 @@ def custom_id_translation(type) end def user_select_options - User.non_strategic_overviewers.order(:first_name, :last_name).map { |user| { user.id.to_s => user.name } } + User.cached_user_select_options end def concern_translation(hotline_field) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 5fd67f3efb..a8043057ce 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,10 @@ module ApplicationHelper Thredded::ApplicationHelper + def setting + Setting.cache_first + end + def asset_data_base64(path) if Rails.configuration.assets.compile asset = Rails.application.assets.find_asset(path) @@ -8,8 +12,8 @@ def asset_data_base64(path) asset = Rails.application.assets_manifest.assets[path] end throw "Could not find asset '#{path}'" if asset.nil? - base64 = Base64.encode64(asset.to_s).gsub(/\s/, "") - content_type = asset.try(:content_type) || "application/x-font-ttf" + base64 = Base64.encode64(asset.to_s).gsub(/\s/, '') + content_type = asset.try(:content_type) || 'application/x-font-ttf' "data:#{content_type};base64,#{Rack::Utils.escape(base64)}" end @@ -34,7 +38,7 @@ def flash_alert end def show_family_CRD? - @show_family_CRD ||= QuantitativeType.where('visible_on LIKE ?', "%family%").any? + @show_family_CRD ||= QuantitativeType.where('visible_on LIKE ?', '%family%').any? end def notification_client_exit(day) @@ -81,11 +85,11 @@ def current_url(new_params) def remove_link(object, associated_objects = {}, btn_size = 'btn-xs', custom_assessment_setting_id = nil, tab_name = nil) btn_status = associated_objects.values.sum.zero? ? nil : 'disabled' if object.class.name.downcase == 'domain' - link_to(domain_path(object, custom_assessment_setting_id: custom_assessment_setting_id, tab: tab_name || params[:tab]), method: 'delete', data: { confirm: t('are_you_sure') }, class: "btn btn-outline btn-danger #{btn_size} #{btn_status}") do + link_to(domain_path(object, custom_assessment_setting_id: custom_assessment_setting_id, tab: tab_name || params[:tab]), method: 'delete', data: { confirm: t('are_you_sure') }, class: "btn btn-outline btn-danger #{btn_size} #{btn_status}") do fa_icon('trash') end else - link_to(object, method: 'delete', data: { confirm: t('are_you_sure') }, class: "btn btn-outline btn-danger #{btn_size} #{btn_status}") do + link_to(object, method: 'delete', data: { confirm: t('are_you_sure') }, class: "btn btn-outline btn-danger #{btn_size} #{btn_status}") do fa_icon('trash') end end @@ -93,7 +97,7 @@ def remove_link(object, associated_objects = {}, btn_size = 'btn-xs', custom_ass def is_active_controller(controller_name, class_name = nil) if params[:controller] =~ /#{controller_name}/i - class_name == nil ? "active" : class_name + class_name == nil ? 'active' : class_name else nil end @@ -152,12 +156,13 @@ def active_menu(name, alter_name = '') controller_name == name || controller_name == alter_name ? 'active' : nil end - def settings_menu_active(name, action_names) - action = ['index' ,'update' ,'create'].include?(action_name) ? 'index' : action_name - 'active' if (controller_name == name && action_names == action) + def settings_menu_active(name, *action_names) + action = ['index', 'update', 'create'].include?(action_name) ? 'index' : action_name + + 'active' if controller_name == name && action_names.include?(action) end - def hidden_class(tasks, assessment_domain=false) + def hidden_class(tasks, assessment_domain = false) 'hidden' if tasks.blank? && !assessment_domain end @@ -239,24 +244,28 @@ def government_forms_visible? def program_stream_readable?(value) return true if current_user.admin? || current_user.strategic_overviewer? + current_user.program_stream_permissions.find_by(program_stream_id: value).readable end def program_permission_editable?(value) return true if current_user.admin? return false if current_user.strategic_overviewer? + current_user.program_stream_permissions.find_by(program_stream_id: value).editable end def custom_field_editable?(value) return true if current_user.admin? return false if current_user.strategic_overviewer? + current_user.custom_field_permissions.find_by(custom_field_id: value).editable end def custom_field_readable?(value) return true if current_user.admin? return false if current_user.strategic_overviewer? + current_user.custom_field_permissions.find_by(custom_field_id: value).readable end @@ -271,7 +280,7 @@ def convert_bracket(value, properties = {}) end def default_setting(column, setting_default_columns) - key_columns = params.keys.select{ |k| k.match(/\_$/) } + key_columns = params.keys.select { |k| k.match(/_$/) } return false if setting_default_columns.nil? || (key_columns.present? && key_columns.exclude?(column)) return false unless params.dig(:client_grid, :descending).present? || (params[:client_advanced_search].present? && params.dig(:client_grid, :descending).present?) || params[:client_grid].nil? || params[:client_advanced_search].nil? return false unless params.dig(:family_grid, :descending).present? || (params[:family_advanced_search].present? && params.dig(:family_grid, :descending).present?) || params[:family_grid].nil? || params[:family_advanced_search].nil? @@ -294,13 +303,13 @@ def assessments_notification_label if @notification.any_overdue_assessments? && @notification.any_due_today_assessments? overdue_count = @notification.overdue_assessments_count due_today_count = @notification.due_today_assessments_count - "#{I18n.t('layouts.notification.assessments_count', count: overdue_count)} #{Setting.cache_first.default_assessment} #{I18n.t('layouts.notification.overdue_assessments', count: overdue_count)} #{I18n.t('layouts.notification.overdue_and_due_today_count', count: due_today_count)}" + "#{I18n.t('layouts.notification.assessments_count', count: overdue_count)} #{setting.default_assessment} #{I18n.t('layouts.notification.overdue_assessments', count: overdue_count)} #{I18n.t('layouts.notification.overdue_and_due_today_count', count: due_today_count)}" elsif @notification.any_overdue_assessments? count = @notification.overdue_assessments_count - "#{I18n.t('layouts.notification.assessments_count', count: count)} #{Setting.cache_first.default_assessment} #{I18n.t('layouts.notification.overdue_assessments', count: count)}" + "#{I18n.t('layouts.notification.assessments_count', count: count)} #{setting.default_assessment} #{I18n.t('layouts.notification.overdue_assessments', count: count)}" else count = @notification.due_today_assessments_count - "#{I18n.t('layouts.notification.assessments_count', count: count)} #{Setting.cache_first.default_assessment} #{I18n.t('layouts.notification.due_today_assessments', count: count)}" + "#{I18n.t('layouts.notification.assessments_count', count: count)} #{setting.default_assessment} #{I18n.t('layouts.notification.due_today_assessments', count: count)}" end end @@ -321,14 +330,14 @@ def customized_assessments_notification_label def forms_notification_label if @notification.any_client_forms_overdue? && @notification.any_client_forms_due_today? "#{I18n.t('layouts.notification.due_today_forms_count', count: @notification.client_enrollment_tracking_frequency_overdue_count)} #{I18n.t('layouts.notification.overdue_and_due_today_count', count: @notification.client_enrollment_tracking_frequency_due_today_count)}" - elsif @notification.any_client_forms_overdue? + elsif @notification.any_client_forms_overdue? I18n.t('layouts.notification.overdue_forms_count', count: @notification.client_enrollment_tracking_frequency_overdue_count) else I18n.t('layouts.notification.due_today_forms_count', count: @notification.client_enrollment_tracking_frequency_due_today_count) end end - def whodunnit(type, id, event='create') + def whodunnit(type, id, event = 'create') user_id = PaperTrail::Version.find_by(event: event, item_type: type, item_id: id).try(:whodunnit) if user_id.blank? || (user_id.present? && user_id.include?('@rotati')) object = type.constantize.find(id) @@ -370,25 +379,45 @@ def enable_any_csi_tools? end def enable_default_assessment? - Setting.cache_first.try(:enable_default_assessment) + setting.try(:enable_default_assessment) end def enable_custom_assessment? - CustomAssessmentSetting.where(enable_custom_assessment: true).present? + CustomAssessmentSetting.cache_only_enable_custom_assessment.any? end - def enable_any_csi_tools? - enable_default_assessment? || enable_custom_assessment? + def assessment_options + options = CustomAssessmentSetting.cache_only_enable_custom_assessment.map do |item| + [ + item.id, + item.custom_assessment_name, + { 'data-select-group' => "#{t('advanced_search.fields.custom_csi_domain_scores')} | #{item.custom_assessment_name}" } + ] + end + + options = options.unshift([0, setting.default_assessment, { 'data-type' => :default, 'data-select-group' => t('advanced_search.fields.csi_domain_scores') }]) if setting.enable_default_assessment? + options + end + + def family_assessment_options + [ + [ + 0, + t('families.family_assessment'), + { 'data-type' => :default, 'data-select-group' => t('advanced_search.fields.family_assessment_domain_scores') } + ] + ] end def country_langauge return 'Swahili' if current_organization.short_name == 'cccu' - country = current_setting.try(:country_name) + country = setting.try(:country_name) case country when 'cambodia' then 'Khmer' when 'myanmar' then 'Burmese' when 'thailand' then 'Thai' when 'lesotho' then 'English' + when 'indonesia' then 'Bahasa' end end @@ -396,15 +425,17 @@ def supported_languages_data { en: { label: t('.english'), flag_file_name: 'United-Kingdom.png' }, km: { label: t('.khmer'), flag_file_name: 'Cambodia.png' }, - my: { label: t('.burmese'), flag_file_name: 'Myanamar-icon.png' } + my: { label: t('.burmese'), flag_file_name: 'Myanamar-icon.png' }, + in: { label: t('.bahasa'), flag_file_name: 'indonesia.png' } } end - def referral_source_name(referral_source) + def referral_source_name(referral_source, client = nil) + values = [] if I18n.locale == :km - referral_source.map{|ref| [ref.name, ref.id] } + values = referral_source.map { |ref| [ref.name, ref.id] } else - referral_source.map do |ref| + values = referral_source.map do |ref| if ref.name_en.blank? [ref.name, ref.id] else @@ -412,6 +443,14 @@ def referral_source_name(referral_source) end end end + + if client && client.external_id.present? + referral_source = ReferralSource.find_by(name: 'MoSVY External System') + values << [referral_source.name, referral_source.id] + else + values + end + values.uniq end def ref_cat_name(referral_source_cat) @@ -421,35 +460,39 @@ def ref_cat_name(referral_source_cat) def select_ngos current_short_name = Apartment::Tenant.current if current_short_name == 'demo' || current_short_name == 'tutorials' - Organization.test_ngos.exclude_current.order(:full_name).map{|org| [org.full_name, org.short_name] } + Organization.test_ngos.exclude_current.order(:full_name).map { |org| [org.full_name, org.short_name] } elsif current_short_name == 'cif' || current_short_name == 'newsmile' - Organization.exclude_current.visible_only_cif.where(demo: false).order(:full_name).map{|org| [org.full_name, org.short_name] } + Organization.exclude_current.visible_only_cif.where(demo: false).order(:full_name).map { |org| [org.full_name, org.short_name] } else - Organization.exclude_current.oscar.order(:full_name).map{|org| [org.full_name, org.short_name] } + Organization.exclude_current.oscar.order(:full_name).map { |org| [org.full_name, org.short_name] } end end def mapping_ngos(ngos) if controller_name == 'clients' - ExternalSystem.all.each.map{ |external_system| ngos << [external_system.name, "external referral"] } - ngos << ["I don't see the NGO I'm looking for...", "external referral"] + ExternalSystem.all.each.map { |external_system| ngos << [external_system.name, external_system.name] } + ngos << ["I don't see the NGO I'm looking for...", 'external referral'] elsif controller_name == 'family_referrals' - ngos << ["MoSVY External System", "MoSVY External System"] - ngos << ["I don't see the NGO I'm looking for...", "external referral", disabled: @referral&.referred_to != 'external referral'] + ngos << ['MoSVY External System', 'MoSVY External System'] + ngos << ["I don't see the NGO I'm looking for...", 'external referral', disabled: @referral&.referred_to != 'external referral'] else - ngos << ["MoSVY External System", "MoSVY External System", disabled: @referral&.referred_to != 'external referral'] - ngos << ["I don't see the NGO I'm looking for...", "external referral", disabled: @referral&.referred_to != 'external referral'] + ngos << ['MoSVY External System', 'MoSVY External System', disabled: @referral&.referred_to != 'MoSVY External System'] if is_ngo_share_to_external? + ngos << ["I don't see the NGO I'm looking for...", 'external referral', disabled: @referral&.referred_to != 'external referral'] end ngos end + def is_ngo_share_to_external? + current_organization.integrated? + end + def initial_referral_date_picker_format(entity) "#{entity.initial_referral_date&.year}, #{entity.initial_referral_date&.month}, #{entity.initial_referral_date&.day}" end def advanced_search_url_dynamic routes = Rails.application.routes.url_helpers - routes.public_send("advanced_search_#{params["controller"]}_path") + routes.public_send("advanced_search_#{params['controller']}_path") end def has_service_delivery? @@ -457,12 +500,11 @@ def has_service_delivery? end def request_method - (['clients', 'families'].include?(params[:controller]) && params[:action] == 'index') ? 'Post' : 'Get' + (['clients', 'families'].include?(params[:controller]) && params[:action].in?(%w(index welcome))) ? 'Post' : 'Get' end def age_in_hash(dob) now = Time.now.utc distance_of_time_in_words_hash(now, dob) end - end diff --git a/app/helpers/assessment_helper.rb b/app/helpers/assessment_helper.rb index 8f17ce54d4..f45ba4a275 100644 --- a/app/helpers/assessment_helper.rb +++ b/app/helpers/assessment_helper.rb @@ -32,9 +32,10 @@ def assessment_destroy_link(client, assessment) end def order_assessment(assessment) - assessment_domains = assessment.persisted? ? assessment.assessment_domains.includes(:domain) : assessment.assessment_domains - if assessment_domains.all?{|ad| ad.domain.name[/\d+/]&.to_i } - assessment_domains.sort_by{ |ad| ad.domain.name[/\d+/]&.to_i || ad.domain.name } + assessment_domains = (assessment.persisted? && !assessment.draft?) ? assessment.assessment_domains.includes(:domain) : assessment.assessment_domains + + if assessment_domains.all? { |ad| ad.domain.name[/\d+/]&.to_i } + assessment_domains.sort_by { |ad| [ad.domain.name[/\d+/]&.to_i, ad.domain.name, ad.domain_id] } else assessment_domains.sort_by(&:domain_id) end @@ -77,7 +78,7 @@ def score_definition(definition, score) definition.present? ? simple_format(definition) : score end - def get_domains(case_note_domain, custom_assessment_setting_id=nil) + def get_domains(case_note_domain, custom_assessment_setting_id = nil) if params[:custom] == 'true' if case_note_domain.object.family_id case_note_domain.object.domain_group.family_custom_domain_identities @@ -98,18 +99,18 @@ def domain_translation_header(ad) if I18n.locale == :km && !ad.domain.custom_domain text = ad.domain.local_description[/.*<\/strong>/].gsub(/|<\/strong>/, '') domain_number = text[/[^\(.*]*/] - domain_name = text[/\(.*/] + domain_name = text[/\(.*/] content_tag(:nil) do - content_tag(:td, content_tag(:b, "#{domain_number}:"), class: "no-padding-bottom") + content_tag(:td, content_tag(:b, domain_name), class: "no-padding-bottom") + content_tag(:td, content_tag(:b, "#{domain_number}:"), class: 'no-padding-bottom') + content_tag(:td, content_tag(:b, domain_name), class: 'no-padding-bottom') end else - content_tag(:td, content_tag(:b, "#{I18n.t('.domains.domain_list.domains')} #{ad.domain.name}:"), class: "no-padding-bottom") + content_tag(:td, content_tag(:b, ad.domain.identity), class: "no-padding-bottom") + content_tag(:td, content_tag(:b, "#{I18n.t('.domains.domain_list.domains')} #{ad.domain.name}:"), class: 'no-padding-bottom') + content_tag(:td, content_tag(:b, ad.domain.identity), class: 'no-padding-bottom') end end - def assess_header_mapping(default=true) - domains = default ? Domain.csi_domains.map{ |domain| ["domain_#{domain.id}", domain.name] } : Domain.custom_csi_domains.map{ |domain| ["domain_#{domain.id}", domain.name] } + def assess_header_mapping + domains = Domain.cache_order_by_identity.select(&:client_csi?).map { |domain| ["domain_#{domain.id}", domain.name] } domain_ids, domain_headers = domains.map(&:first), domains.map(&:last) assessment_headers = [t('.client_id'), t('.client_name'), t('.assessment_number', assessment: t('clients.show.assessment')), t('.assessment_date', assessment: t('clients.show.assessment')), t('.average_score', assessment: t('clients.show.assessment'))] @@ -122,26 +123,63 @@ def assess_header_mapping(default=true) end end + def custom_assessment_header_mapping + return @custom_assessment_header_mapping if defined?(@custom_assessment_header_mapping) + + @custom_assessment_header_mapping = {} + + CustomAssessmentSetting.where(enable_custom_assessment: true).includes(:domains).each do |custom_csi_setting| + domains = custom_csi_setting.domains.map { |domain| ["domain_#{domain.id}", domain.name] } + domain_ids, domain_headers = domains.map(&:first), domains.map(&:last) + + assessment_headers = [t('.client_id'), t('.client_name'), t('.assessment_number', assessment: t('clients.show.assessment')), t('.assessment_date', assessment: t('clients.show.assessment')), t('.average_score', assessment: t('clients.show.assessment'))] + + assessment_domain_headers = ['slug', 'name', 'assessment-number', 'date', 'average-score'] + classNames = ['client-id', 'client-name', 'assessment-number text-center', 'assessment-date', 'average-score text-center', 'assessment-score text-center'] + + @custom_assessment_header_mapping[custom_csi_setting.id] = [*assessment_domain_headers, *domain_ids].zip(classNames, [*assessment_headers, *domain_headers]).map do |field_header, class_name, header_name| + { title: header_name, data: field_header, className: class_name ? class_name : 'assessment-score text-center' } + end + end + + @custom_assessment_header_mapping + end + + def family_assessment_header_mapping + domains = Domain.family_custom_csi_domains.order_by_identity.map { |domain| ["domain_#{domain.id}", domain.name] } + domain_ids, domain_headers = domains.map(&:first), domains.map(&:last) + + assessment_headers = [t('families.show.id'), t('families.show.name'), t('client_advanced_searches.custom_assessment_domain_score.assessment_number', assessment: t('clients.show.assessment')), t('client_advanced_searches.custom_assessment_domain_score.assessment_date', assessment: t('clients.show.assessment')), t('client_advanced_searches.custom_assessment_domain_score.average_score', assessment: t('clients.show.assessment'))] + + assessment_domain_headers = ['id', 'name', 'assessment-number', 'date', 'average-score'] + classNames = ['family-id', 'family-name', 'assessment-number text-center', 'assessment-date', 'average-score text-center', 'assessment-score text-center'] + + [*assessment_domain_headers, *domain_ids].zip(classNames, [*assessment_headers, *domain_headers]).map do |field_header, class_name, header_name| + { title: header_name, data: field_header, className: class_name ? class_name : 'assessment-score text-center' } + end + end + def map_assessment_and_score(object, identity, domain_id) sub_query_string = [] if $param_rules.nil? assessments = object.assessments.joins(:assessment_domains).distinct else basic_rules = $param_rules['basic_rules'] - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_assessment_query_rules(basic_rules, identity).reject(&:blank?) assessment_completed_sql, assessment_number = assessment_filter_values(results) if results.present? assessments = [] - sql = "(assessments.completed = true)".squish + sql = '(assessments.completed = true)'.squish if assessment_number.present? && assessment_completed_sql.present? assessments = object.assessments.where(sql).limit(1).offset(assessment_number - 1).order('created_at') elsif assessment_completed_sql.present? sql = assessment_completed_sql[/assessments\.created_at.*/] assessments = object.assessments.completed.where(sql).order('created_at') end - sub_query_string = get_assessment_query_string([results[0].reject { |arr| arr[:field] != identity }], identity, domain_id, object.id) + + sub_query_string = get_assessment_query_string("#{object.class.name.downcase}_id", [results[0].reject { |arr| arr[:field] != identity }], identity, domain_id, object.id) assessments = assessments.joins(:domains).where(sub_query_string.reject(&:blank?).join(' AND ')).where(domains: { identity: identity }) else rule = basic_rules['rules'].select { |h| h['id'] == 'date_of_assessments' || h['id'] == 'completed_date' }.first @@ -157,11 +195,11 @@ def map_assessment_and_score(object, identity, domain_id) end end - def mapping_assessment_query_rules(data, field_name=nil, data_mapping=[]) + def mapping_assessment_query_rules(data, field_name = nil, data_mapping = []) rule_array = [] data[:rules].each_with_index do |h, index| if h.has_key?(:rules) - mapping_assessment_query_rules(h, field_name=nil, data_mapping) + mapping_assessment_query_rules(h, field_name = nil, data_mapping) end if field_name.nil? next if h[:id] !~ /^(domainscore|assessment_completed|assessment_completed_date|completed_date|assessment_number|month_number|date_nearest)/i @@ -174,7 +212,7 @@ def mapping_assessment_query_rules(data, field_name=nil, data_mapping=[]) data_mapping << rule_array end - def get_assessment_query_string(results, identity, domain_id, client_id=nil, basic_rules=nil) + def get_assessment_query_string(object_id_field, results, identity, domain_id, client_id = nil, basic_rules = nil) results.map do |result| condition = '' result.map do |h| @@ -192,30 +230,30 @@ def get_assessment_query_string(results, identity, domain_id, client_id=nil, bas if basic_rules assessment_completed_result = mapping_assessment_query_rules(basic_rules, 'assessment_completed') - assessment_only_query_string = get_assessment_query_string(assessment_completed_result, identity, domain_id, client_id) + assessment_only_query_string = get_assessment_query_string(object_id_field, assessment_completed_result, identity, domain_id, client_id) assessment_completed_date = " #{assessment_only_query_string.first} AND " if assessment_only_query_string.first.present? end - beginning_of_month = "SELECT DATE(date_trunc('month', created_at)) FROM assessments WHERE#{assessment_completed_date || ''} assessments.client_id = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" - end_of_month = "SELECT (date_trunc('month', created_at) + interval '1 month' - interval '1 day')::date FROM assessments WHERE assessments.client_id = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" + beginning_of_month = "SELECT DATE(date_trunc('month', created_at)) FROM assessments WHERE#{assessment_completed_date || ''} assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" + end_of_month = "SELECT (date_trunc('month', created_at) + interval '1 month' - interval '1 day')::date FROM assessments WHERE assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" - "(DATE(assessments.created_at) between (#{beginning_of_month}) AND (#{end_of_month})) AND (SELECT COUNT(*) FROM assessments WHERE assessments.client_id = #{client_id ? client_id : 'clients.id'}) >= #{h[:value]}" + "(DATE(assessments.created_at) between (#{beginning_of_month}) AND (#{end_of_month})) AND (SELECT COUNT(*) FROM assessments WHERE assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'}) >= #{h[:value]}" elsif h[:field] == 'month_number' value = h[:value] == 0 ? 1 : h[:value] value = value.try(:to_i).present? ? h[:value] : 1 - beginning_of_month = "SELECT DATE(date_trunc('month', created_at)) FROM assessments WHERE assessments.client_id = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" - end_of_month = "SELECT (date_trunc('month', created_at) + interval '1 month' - interval '1 day')::date FROM assessments WHERE assessments.client_id = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" + beginning_of_month = "SELECT DATE(date_trunc('month', created_at)) FROM assessments WHERE assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" + end_of_month = "SELECT (date_trunc('month', created_at) + interval '1 month' - interval '1 day')::date FROM assessments WHERE assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'} ORDER BY assessments.created_at LIMIT 1 OFFSET #{value} - 1" "DATE(assessments.created_at) between (#{beginning_of_month}) AND (#{end_of_month})" elsif h[:field] == identity && h[:operator] == 'assessment_has_changed' # limit_assessments = client.assessments.order(:created_at).offset(@value.first.to_i - 1).limit(@value.last.to_i - (@value.first.to_i - 1)) - "(SELECT COUNT(*) FROM assessments WHERE (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score = #{h[:value].first} AND assessment_domains.score = #{h[:value].second}) AND assessments.client_id = #{client_id ? client_id : 'clients.id'}) > 0" + "(SELECT COUNT(*) FROM assessments WHERE (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score = #{h[:value].first} AND assessment_domains.score = #{h[:value].second}) AND assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'}) > 0" elsif h[:field] == identity && h[:operator] == 'assessment_has_not_changed' - "(SELECT COUNT(*) FROM assessments WHERE ((assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score = assessment_domains.score) OR (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score = #{h[:value].first} AND assessment_domains.score != #{h[:value].last})) AND assessments.client_id = #{client_id ? client_id : 'clients.id'}) > 0" + "(SELECT COUNT(*) FROM assessments WHERE ((assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score = assessment_domains.score) OR (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score = #{h[:value].first} AND assessment_domains.score != #{h[:value].last})) AND assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'}) > 0" elsif h[:field] == identity && h[:operator] == 'month_has_changed' - "(SELECT COUNT(*) FROM assessments WHERE (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score != assessment_domains.score) AND assessments.client_id = #{client_id ? client_id : 'clients.id'}) > 1" + "(SELECT COUNT(*) FROM assessments WHERE (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score != assessment_domains.score) AND assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'}) > 1" elsif h[:field] == identity && h[:operator] == 'month_has_not_changed' - "(SELECT COUNT(*) FROM assessments WHERE (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score IS NULL OR assessment_domains.previous_score = assessment_domains.score) AND assessments.client_id = #{client_id ? client_id : 'clients.id'}) > 1" + "(SELECT COUNT(*) FROM assessments WHERE (assessment_domains.domain_id = #{domain_id} AND assessment_domains.previous_score IS NULL OR assessment_domains.previous_score = assessment_domains.score) AND assessments.#{object_id_field} = #{client_id ? client_id : 'clients.id'}) > 1" elsif h[:field] == 'date_nearest' "date(assessments.created_at) <= '#{h[:value]}'" end @@ -240,9 +278,9 @@ def date_of_assessments_query_string(id, field, operator, value) when 'between' "(date(assessments.created_at) BETWEEN '#{value[0].to_date}' AND '#{value[1].to_date}')" when 'is_empty' - "assessments.created_at IS NULL" + 'assessments.created_at IS NULL' when 'is_not_empty' - "assessments.created_at IS NOT NULL" + 'assessments.created_at IS NOT NULL' end end @@ -263,9 +301,9 @@ def date_of_completed_assessments_query_string(id, field, operator, value, type, when 'between' "assessments.completed = true AND (date(assessments.completed_date) BETWEEN '#{value[0].to_date}' AND '#{value[1].to_date}')" when 'is_empty' - "assessments.completed = true AND assessments.completed_date IS NULL" + 'assessments.completed = true AND assessments.completed_date IS NULL' when 'is_not_empty' - "assessments.completed = true AND assessments.completed_date IS NOT NULL" + 'assessments.completed = true AND assessments.completed_date IS NOT NULL' end end @@ -286,9 +324,9 @@ def assessment_score_query_string(id, field, operator, value, type, input_type, when 'between' "assessment_domains.domain_id = #{domain_id} AND assessment_domains.score IN (#{value.first..value.last})" when 'is_empty' - "assessment_domains.domain_id IS NULL OR assessment_domains.score IS NULL" + 'assessment_domains.domain_id IS NULL OR assessment_domains.score IS NULL' when 'is_not_empty' - "assessment_domains.domain_id IS NOT NULL OR assessment_domains.score IS NOT NULL" + 'assessment_domains.domain_id IS NOT NULL OR assessment_domains.score IS NOT NULL' end end @@ -328,12 +366,12 @@ def domain_name_for_aht(ad, index = 0) end content_tag(:nil) do - content_tag(:td, content_tag(:b, domain_header.gsub(' ៖', '៖').html_safe), class: "no-padding-bottom") + content_tag(:td, content_tag(:b, domain_header.gsub(' ៖', '៖').html_safe), class: 'no-padding-bottom') end else content_tag(:nil) do domain_identity = t("dimensions.dimensions_identies.#{ad.domain.identity}")[/translation_missing/] ? ad.domain.identity : t("dimensions.dimensions_identies.#{ad.domain.identity}") - content_tag(:td, content_tag(:b, "#{t('dimensions.dimension_list.dimensions')}: "), class: "no-padding-bottom") + content_tag(:td, content_tag(:b, domain_identity, class: "no-padding-bottom")) + content_tag(:td, content_tag(:b, "#{t('dimensions.dimension_list.dimensions')}: "), class: 'no-padding-bottom') + content_tag(:td, content_tag(:b, domain_identity, class: 'no-padding-bottom')) end end end @@ -363,4 +401,17 @@ def calculate_domain_selected_domain_score(assessment) (sum.to_f / current_setting.selected_domain_ids.compact.size).round end + + def check_setting_assessment_type_name_selected(assessment) + setting_assessment_type_id = Setting.cache_first.assessment_type_name + + if assessment.default + true + elsif assessment.custom_assessment_setting.blank? + false + else + return assessment.object.custom_assessment_setting.id.to_s == setting_assessment_type_id if assessment.instance_of?(::AssessmentDecorator) + assessment.custom_assessment_setting.id.to_s == setting_assessment_type_id + end + end end diff --git a/app/helpers/call_helper.rb b/app/helpers/call_helper.rb index 290cb48503..f5ec51b1cd 100644 --- a/app/helpers/call_helper.rb +++ b/app/helpers/call_helper.rb @@ -45,15 +45,15 @@ def true_false_to_yes_no(value) end class << self def referee_id - Referee.where(anonymous: false).pluck(:name, :id).map{ |name, id| { id => name } } + Referee.cache_none_anonymous.map { |referee| { referee.id => referee.name } } end def receiving_staff_id - User.case_workers.map { |user| { user.id => user.name } } + User.cache_case_workers.map { |user| { user.id => user.name } } end def phone_call_id - Call.pluck(:phone_call_id).map { |phone_call_id| { phone_call_id => phone_call_id } } + Call.cache_all.map { |phone_call| { phone_call.id => phone_call.id } } end def call_type @@ -94,11 +94,11 @@ def childsafe_agent end def protection_concerns - ProtectionConcern.dropdown_list_option + ProtectionConcern.cache_all.map { |protection_concern| { protection_concern.id => protection_concern.content } } end - + def necessities - Necessity.dropdown_list_option + Necessity.cache_all.map { |necessity| { necessity.id => necessity.content } } end def not_a_phone_call diff --git a/app/helpers/care_plan_helper.rb b/app/helpers/care_plan_helper.rb index 5e0469c4f0..3ca1477924 100644 --- a/app/helpers/care_plan_helper.rb +++ b/app/helpers/care_plan_helper.rb @@ -50,9 +50,15 @@ def care_plan_label(care_plan) care_plan.completed? ? 'label label-primary' : 'label label-danger' end + def care_plan_date + grid_object.column(:care_plan_date, header: -> { I18n.t('care_plans.care_plan_date') }) do |object| + date_filter(object.care_plans, 'care_plan_date').map { |care_plan| date_format(care_plan.care_plan_date) }.join(', ') + end + end + def care_plan_completed_date grid_object.column(:care_plan_completed_date, header: -> { I18n.t('datagrid.columns.clients.care_plan_completed_date') }) do |object| - date_filter(object.care_plans, 'care_plan_completed_date').map{ |care_plan| date_format(care_plan.created_at) }.join(", ") + date_filter(object.care_plans, 'care_plan_completed_date').map { |care_plan| date_format(care_plan.created_at) }.join(', ') end end diff --git a/app/helpers/case_note_helper.rb b/app/helpers/case_note_helper.rb index 79d5c28cbd..b5fe58543e 100644 --- a/app/helpers/case_note_helper.rb +++ b/app/helpers/case_note_helper.rb @@ -43,6 +43,24 @@ def new_link(obj=@client) end end + def new_draft_case_note_link(custom_assessment_name = nil) + if custom_assessment_name && case_notes_editable? && policy(@client).create? + link_to edit_client_case_note_path(@client, id: :draft, custom: true, custom_name: custom_assessment_name) do + custom_assessment_name + end + elsif custom_assessment_name.blank? && case_notes_editable? && (policy(@client).create? || policy(CaseNote).create?) + link_to edit_client_case_note_path(@client, id: :draft) do + @current_setting.default_assessment + end + else + link_to_if false, '' do + content_tag :a, class: 'disabled' do + custom_assessment_name + end + end + end + end + def new_custom_link(custom_assessment_name, obj=@client) if case_notes_editable? && policy(obj).create? link_to new_polymorphic_path([obj, 'case_note'], custom: true, custom_name: custom_assessment_name) do diff --git a/app/helpers/client_by_gender_count_helper.rb b/app/helpers/client_by_gender_count_helper.rb new file mode 100644 index 0000000000..aadb6c98a6 --- /dev/null +++ b/app/helpers/client_by_gender_count_helper.rb @@ -0,0 +1,37 @@ +module ClientByGenderCountHelper + def adule_client_gender_count(clients, type = :male, referrals = nil) + if referrals + age_sql_string = <<-SQL.squish + (CASE WHEN (EXTRACT(year FROM age(current_date, referrals.client_date_of_birth)) :: int) >= 0 THEN (EXTRACT(year FROM age(current_date, referrals.client_date_of_birth)) :: int) ELSE 0 END) + SQL + referrals.where("referrals.client_gender = ? AND #{age_sql_string} >= ?", type.to_s, 18).count + else + age_sql_string = <<-SQL.squish + (CASE WHEN (EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) >= 0 THEN (EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) ELSE 0 END) + SQL + clients.public_send(type).where("#{age_sql_string} >= ?", 18).count + end + end + + def under_18_client_gender_count(clients, type = :male, referrals = nil) + if referrals + age_sql_string = <<-SQL.squish + (CASE WHEN (EXTRACT(year FROM age(current_date, referrals.client_date_of_birth)) :: int) >= 0 THEN (EXTRACT(year FROM age(current_date, referrals.client_date_of_birth)) :: int) ELSE 0 END) + SQL + referrals.where("referrals.client_gender = ? AND #{age_sql_string} < ?", type.to_s, 18).count + else + age_sql_string = <<-SQL.squish + (CASE WHEN (EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) >= 0 THEN (EXTRACT(year FROM age(current_date, clients.date_of_birth)) :: int) ELSE 0 END) + SQL + clients.public_send(type).where("#{age_sql_string} < ?", 18).count + end + end + + def other_client_gender_count(clients, referrals = nil) + if referrals + referrals.where("client_gender IS NOT NULL AND (client_gender NOT IN ('male', 'female') OR client_date_of_birth IS NULL)").count + else + clients.where("gender IS NULL OR (gender IS NOT NULL AND gender NOT IN ('male', 'female')) OR (gender NOT IN ('male', 'female') AND date_of_birth IS NULL)").count + end + end +end diff --git a/app/helpers/client_enrollment_helper.rb b/app/helpers/client_enrollment_helper.rb index bd14fcc0ee..fe143a2155 100644 --- a/app/helpers/client_enrollment_helper.rb +++ b/app/helpers/client_enrollment_helper.rb @@ -1,6 +1,6 @@ module ClientEnrollmentHelper def view_report_link(program_stream) - if program_stream.client_enrollments.enrollments_by(@client.id).order(:created_at).last.try(:status) == 'Exited' + if program_stream.client_enrollments.enrollments_by(@client.id).any? link_to t('.view'), report_client_client_enrollments_path(@client, program_stream_id: program_stream) end end diff --git a/app/helpers/clients_helper.rb b/app/helpers/clients_helper.rb index eb69c3c01a..73a8fdcdc4 100644 --- a/app/helpers/clients_helper.rb +++ b/app/helpers/clients_helper.rb @@ -5,21 +5,20 @@ def client_form_data { translation: rails_i18n_translations, inlineHelpTranslation: JSON.parse(I18n.t('inline_help').to_json), internationalReferredClient: international_referred_client, selectedCountry: selected_country, - client: - { + client: { client: @client, ratanak_achievement_program_staff_client_ids: @client.ratanak_achievement_program_staff_client_ids, user_ids: @client.user_ids, quantitative_case_ids: @client.quantitative_case_ids, agency_ids: @client.agency_ids, donor_ids: @client.donor_ids, isTestClient: current_setting.test_client?, isForTesting: @client.for_testing? }, client_quantitative_free_text_cases: get_or_build_client_quantitative_free_text_cases, family_member: (@client.family_member || {}), moSAVYOfficials: @client.mo_savy_officials, - referee: @referee.as_json(methods: [:existing_referree]), carer: @carer , users: case_workers_option(@client.id), + referee: @referee.as_json(methods: [:existing_referree]), carer: @carer, users: case_workers_option(@client.id), referralSourceCategory: @referral_source_category, referralSource: ReferralSource.all, birthProvinces: @birth_provinces, - currentProvinces: @current_provinces || get_address('province'), districts: @districts.presence || get_address('district'), + currentProvinces: @current_provinces || get_address('province'), cities: @cities, districts: @districts.presence || get_address('district'), subDistricts: @subdistricts, communes: @communes.presence || get_address('commune'), villages: @villages.presence || get_address('village'), - currentStates: @states, currentTownships: @townships, refereeTownships: @referee_townships, carerTownships: @carer_townships, + currentStates: @states, currentTownships: @townships, refereeTownships: @referee_townships, carerTownships: @carer_townships, refereeCities: @referee_cities, refereeDistricts: @referee_districts, refereeSubdistricts: @referee_subdistricts, refereeCommunes: @referee_communes, - refereeVillages: @referee_villages, carerDistricts: @carer_districts, carerSubdistricts: @carer_subdistricts, carerCommunes: @carer_communes, + refereeVillages: @referee_villages, carerCities: @carer_cities, carerDistricts: @carer_districts, carerSubdistricts: @carer_subdistricts, carerCommunes: @carer_communes, carerVillages: @carer_villages, donors: @donors, agencies: @agencies, quantitativeType: QuantitativeType.cach_by_visible_on('client'), quantitativeCase: QuantitativeCase.cache_all, ratePoor: [ @@ -42,27 +41,36 @@ def client_form_data reasonForFamilySeparations: reason_for_family_separations, historyOfDisabilities: history_of_disabilities, isRiskAssessmentEnabled: current_setting.enabled_risk_assessment, riskAssessment: { + has_assessment_level_of_risk: client_has_assessment_level_of_risk?(@client), **@risk_assessment.try(:attributes).try(:symbolize_keys) || {}, labels: { **I18n.t('risk_assessments._attr'), **I18n.t('tasks') }, tasks_attributes: @risk_assessment.try(:tasks) || [] - } + }, + customData: @custom_data&.fields || [], + clientCustomFields: @client_custom_data_properties || {} } end + def client_has_assessment_level_of_risk?(client) + client.assessments.client_risk_assessments.any? + end + def get_or_build_client_quantitative_free_text_cases QuantitativeType.where(field_type: 'free_text').map do |qtt| @client.client_quantitative_free_text_cases.find_or_initialize_by(quantitative_type_id: qtt.id) end end - def xeditable? client = nil + def xeditable?(client = nil) + return true if client.class.name != 'Client' + (can?(:manage, client&.object) || can?(:edit, client&.object) || can?(:rud, client&.object)) ? true : false end - def user(user, editable_input=false) + def user(user, editable_input = false) if !editable_input if can? :read, User link_to user.name, user_path(user) if user.present? @@ -182,6 +190,7 @@ def report_options(title, yaxis_title) def label_translations(address_translation = {}) labels = { + family_type: I18n.t('datagrid.columns.families.family_type'), legal_documents: I18n.t('clients.show.legal_documents'), passport_number: I18n.t('datagrid.columns.clients.passport_number'), national_id_number: I18n.t('datagrid.columns.clients.national_id_number'), @@ -192,87 +201,92 @@ def label_translations(address_translation = {}) type_of_trafficking: I18n.t('datagrid.columns.clients.type_of_trafficking'), education_background: I18n.t('datagrid.columns.clients.education_background'), department: I18n.t('datagrid.columns.clients.department'), - slug: I18n.t('datagrid.columns.clients.id'), - kid_id: custom_id_translation('custom_id2'), - code: custom_id_translation('custom_id1'), - age: I18n.t('datagrid.columns.clients.age'), - presented_id: I18n.t('datagrid.columns.clients.presented_id'), - id_number: I18n.t('datagrid.columns.clients.id_number'), - legacy_brcs_id: I18n.t('datagrid.columns.clients.legacy_brcs_id'), - whatsapp: I18n.t('datagrid.columns.clients.whatsapp'), - preferred_language: I18n.t('datagrid.columns.clients.preferred_language'), - other_phone_number: I18n.t('datagrid.columns.clients.other_phone_number'), - brsc_branch: I18n.t('datagrid.columns.clients.brsc_branch'), - current_island: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_island')), - current_street: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_street')), - current_po_box: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_po_box')), - current_settlement: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_settlement')), - current_resident_own_or_rent: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_resident_own_or_rent')), - current_household_type: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_household_type')), - island2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.island2')), - street2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.street2')), - po_box2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.po_box2')), - settlement2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.settlement2')), - resident_own_or_rent2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.resident_own_or_rent2')), - household_type2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.household_type2')), - given_name: I18n.t('datagrid.columns.clients.given_name'), - family_name: I18n.t('datagrid.columns.clients.family_name'), - local_given_name: I18n.t('datagrid.columns.clients.local_given_name'), - local_family_name: I18n.t('datagrid.columns.clients.local_family_name'), - gender: I18n.t('datagrid.columns.clients.gender'), - date_of_birth: I18n.t('datagrid.columns.clients.date_of_birth'), - status: I18n.t('datagrid.columns.clients.status'), - received_by_id: I18n.t('datagrid.columns.clients.received_by'), - followed_up_by_id: I18n.t('datagrid.columns.clients.follow_up_by'), - initial_referral_date: I18n.t('datagrid.columns.clients.initial_referral_date'), - referral_phone: I18n.t('datagrid.columns.clients.referral_phone'), - referral_source_id: I18n.t('datagrid.columns.clients.referral_source'), - follow_up_date: I18n.t('datagrid.columns.clients.follow_up_date'), - agencies_name: I18n.t('datagrid.columns.clients.agencies_involved'), - donor_name: I18n.t('datagrid.columns.clients.donor'), - current_address: I18n.t('datagrid.columns.clients.current_address'), - house_number: I18n.t('datagrid.columns.clients.house_number'), - street_number: I18n.t('datagrid.columns.clients.street_number'), - school_name: I18n.t('datagrid.columns.clients.school_name'), - school_grade: I18n.t('datagrid.columns.clients.school_grade'), - able_state: I18n.t('datagrid.columns.clients.able_state'), - has_been_in_orphanage: I18n.t('datagrid.columns.clients.has_been_in_orphanage'), - has_been_in_government_care: I18n.t('datagrid.columns.clients.has_been_in_government_care'), + slug: I18n.t('datagrid.columns.clients.id'), + kid_id: custom_id_translation('custom_id2'), + code: custom_id_translation('custom_id1'), + age: I18n.t('datagrid.columns.clients.age'), + presented_id: I18n.t('datagrid.columns.clients.presented_id'), + id_number: I18n.t('datagrid.columns.clients.id_number'), + legacy_brcs_id: I18n.t('datagrid.columns.clients.legacy_brcs_id'), + whatsapp: I18n.t('datagrid.columns.clients.whatsapp'), + preferred_language: I18n.t('datagrid.columns.clients.preferred_language'), + other_phone_number: I18n.t('datagrid.columns.clients.other_phone_number'), + brsc_branch: I18n.t('datagrid.columns.clients.brsc_branch'), + current_island: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_island')), + current_street: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_street')), + current_po_box: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_po_box')), + current_settlement: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_settlement')), + current_resident_own_or_rent: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_resident_own_or_rent')), + current_household_type: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_household_type')), + island2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.island2')), + street2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.street2')), + po_box2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.po_box2')), + settlement2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.settlement2')), + resident_own_or_rent2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.resident_own_or_rent2')), + household_type2: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.household_type2')), + given_name: I18n.t('datagrid.columns.clients.given_name'), + family_name: I18n.t('datagrid.columns.clients.family_name'), + local_given_name: I18n.t('datagrid.columns.clients.local_given_name'), + local_family_name: I18n.t('datagrid.columns.clients.local_family_name'), + gender: I18n.t('datagrid.columns.clients.gender'), + date_of_birth: I18n.t('datagrid.columns.clients.date_of_birth'), + status: I18n.t('datagrid.columns.clients.status'), + received_by_id: I18n.t('datagrid.columns.clients.received_by'), + followed_up_by_id: I18n.t('datagrid.columns.clients.follow_up_by'), + initial_referral_date: I18n.t('datagrid.columns.clients.initial_referral_date'), + referral_phone: I18n.t('datagrid.columns.clients.referral_phone'), + referral_source_id: I18n.t('datagrid.columns.clients.referral_source'), + follow_up_date: I18n.t('datagrid.columns.clients.follow_up_date'), + agencies_name: I18n.t('datagrid.columns.clients.agencies_involved'), + donor_name: I18n.t('datagrid.columns.clients.donor'), + current_address: I18n.t('datagrid.columns.clients.current_address'), + house_number: I18n.t('datagrid.columns.clients.house_number'), + street_number: I18n.t('datagrid.columns.clients.street_number'), + school_name: I18n.t('datagrid.columns.clients.school_name'), + school_grade: I18n.t('datagrid.columns.clients.school_grade'), + able_state: I18n.t('datagrid.columns.clients.able_state'), + has_been_in_orphanage: I18n.t('datagrid.columns.clients.has_been_in_orphanage'), + has_been_in_government_care: I18n.t('datagrid.columns.clients.has_been_in_government_care'), relevant_referral_information: I18n.t('datagrid.columns.clients.relevant_referral_information'), - user_id: I18n.t('datagrid.columns.clients.case_worker'), - state: I18n.t('datagrid.columns.clients.state'), - family_id: I18n.t('datagrid.columns.clients.family_id'), - family: I18n.t('datagrid.columns.clients.family'), - any_assessments: I18n.t('datagrid.columns.clients.assessments'), - case_note_date: I18n.t('datagrid.columns.clients.case_note_date'), - case_note_type: I18n.t('datagrid.columns.clients.case_note_type'), - date_of_assessments: I18n.t('datagrid.columns.clients.date_of_assessments', assessment: I18n.t('clients.show.assessment')), - completed_date: I18n.t('datagrid.columns.calls.assessment_completed_date', assessment: I18n.t('clients.show.assessment')), - date_of_referral: I18n.t('datagrid.columns.clients.date_of_referral'), - date_of_custom_assessments: I18n.t('datagrid.columns.clients.date_of_custom_assessments', assessment: I18n.t('clients.show.assessment')), - changelog: I18n.t('datagrid.columns.clients.changelog'), - live_with: I18n.t('datagrid.columns.clients.live_with'), - program_streams: I18n.t('datagrid.columns.clients.program_streams'), - program_enrollment_date: I18n.t('datagrid.columns.clients.program_enrollment_date'), - program_exit_date: I18n.t('datagrid.columns.clients.program_exit_date'), - accepted_date: I18n.t('datagrid.columns.clients.ngo_accepted_date'), - telephone_number: I18n.t('datagrid.columns.clients.telephone_number'), - exit_date: I18n.t('datagrid.columns.clients.ngo_exit_date'), - created_at: I18n.t('datagrid.columns.clients.created_at'), - created_by: I18n.t('datagrid.columns.clients.created_by'), - referred_to: I18n.t('datagrid.columns.clients.referred_to'), - referred_from: I18n.t('datagrid.columns.clients.referred_from'), - referral_source_category_id: I18n.t('datagrid.columns.clients.referral_source_category'), - type_of_service: I18n.t('datagrid.columns.type_of_service'), - hotline: I18n.t('datagrid.columns.calls.hotline'), + user_id: I18n.t('datagrid.columns.clients.case_worker'), + state: I18n.t('datagrid.columns.clients.state'), + family_id: I18n.t('datagrid.columns.clients.family_id'), + family: I18n.t('datagrid.columns.clients.family'), + any_assessments: I18n.t('datagrid.columns.clients.assessments'), + case_note_date: I18n.t('datagrid.columns.clients.case_note_date'), + case_note_type: I18n.t('datagrid.columns.clients.case_note_type'), + assessment_created_at: I18n.t('datagrid.columns.clients.assessment_created_at', assessment: I18n.t('clients.show.assessment')), + date_of_assessments: I18n.t('datagrid.columns.clients.date_of_assessments', assessment: I18n.t('clients.show.assessment')), + completed_date: I18n.t('datagrid.columns.calls.assessment_completed_date', assessment: I18n.t('clients.show.assessment')), + date_of_referral: I18n.t('datagrid.columns.clients.date_of_referral'), + date_of_custom_assessments: I18n.t('datagrid.columns.clients.date_of_custom_assessments', assessment: I18n.t('clients.show.assessment')), + custom_assessment_created_at: I18n.t('datagrid.columns.clients.custom_assessment_created_at', assessment: I18n.t('clients.show.assessment')), + changelog: I18n.t('datagrid.columns.clients.changelog'), + live_with: I18n.t('datagrid.columns.clients.live_with'), + program_streams: I18n.t('datagrid.columns.clients.program_streams'), + program_enrollment_date: I18n.t('datagrid.columns.clients.program_enrollment_date'), + program_exit_date: I18n.t('datagrid.columns.clients.program_exit_date'), + accepted_date: I18n.t('datagrid.columns.clients.ngo_accepted_date'), + telephone_number: I18n.t('datagrid.columns.clients.telephone_number'), + exit_date: I18n.t('datagrid.columns.clients.ngo_exit_date'), + created_at: I18n.t('datagrid.columns.clients.created_at'), + created_by: I18n.t('datagrid.columns.clients.created_by'), + referred_to: I18n.t('datagrid.columns.clients.referred_to'), + referred_from: I18n.t('datagrid.columns.clients.referred_from'), + referral_source_category_id: I18n.t('datagrid.columns.clients.referral_source_category'), + type_of_service: I18n.t('datagrid.columns.type_of_service'), + hotline: I18n.t('datagrid.columns.calls.hotline'), + care_plan_date: I18n.t('care_plans.care_plan_date'), + care_plan_completed_date: I18n.t('datagrid.columns.clients.care_plan_completed_date'), + care_plan_count: I18n.t('datagrid.columns.clients.care_plan_count'), **overdue_translations, - **Client::HOTLINE_FIELDS.map{ |field| [field.to_sym, I18n.t("datagrid.columns.clients.#{field}")] }.to_h, - **legal_doc_fields.map{|field| [field.to_sym, I18n.t("clients.show.#{field}")] }.to_h, + **Client::HOTLINE_FIELDS.map { |field| [field.to_sym, I18n.t("datagrid.columns.clients.#{field}")] }.to_h, + **legal_doc_fields.map { |field| [field.to_sym, I18n.t("clients.show.#{field}")] }.to_h, **@address_translation, **custom_assessment_field_traslation_mapping } - lable_translation_uderscore.map{|k, v| [k.to_s.gsub(/(\_)$/, '').to_sym, v] }.to_h.merge(labels) + lable_translation_uderscore.map { |k, v| [k.to_s.gsub(/(\_)$/, '').to_sym, v] }.to_h.merge(labels) end def lable_translation_uderscore @@ -284,25 +298,25 @@ def lable_translation_uderscore type_of_trafficking_: I18n.t('datagrid.columns.clients.type_of_trafficking'), education_background_: I18n.t('datagrid.columns.clients.education_background'), department_: I18n.t('datagrid.columns.clients.department'), - presented_id_: I18n.t('datagrid.columns.clients.presented_id'), - id_number_: I18n.t('datagrid.columns.clients.id_number'), - legacy_brcs_id_: I18n.t('datagrid.columns.clients.legacy_brcs_id'), - whatsapp_: I18n.t('datagrid.columns.clients.whatsapp'), - preferred_language_: I18n.t('datagrid.columns.clients.preferred_language'), - other_phone_number_: I18n.t('datagrid.columns.clients.other_phone_number'), - brsc_branch_: I18n.t('datagrid.columns.clients.brsc_branch'), - current_island_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_island')), - current_street_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_street')), - current_po_box_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_po_box')), - current_settlement_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_settlement')), - current_resident_own_or_rent_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_resident_own_or_rent')), - current_household_type_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_household_type')), - island2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.island2')), - street2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.street2')), - po_box2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.po_box2')), - settlement2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.settlement2')), - resident_own_or_rent2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.resident_own_or_rent2')), - household_type2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.household_type2')), + presented_id_: I18n.t('datagrid.columns.clients.presented_id'), + id_number_: I18n.t('datagrid.columns.clients.id_number'), + legacy_brcs_id_: I18n.t('datagrid.columns.clients.legacy_brcs_id'), + whatsapp_: I18n.t('datagrid.columns.clients.whatsapp'), + preferred_language_: I18n.t('datagrid.columns.clients.preferred_language'), + other_phone_number_: I18n.t('datagrid.columns.clients.other_phone_number'), + brsc_branch_: I18n.t('datagrid.columns.clients.brsc_branch'), + current_island_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_island')), + current_street_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_street')), + current_po_box_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_po_box')), + current_settlement_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_settlement')), + current_resident_own_or_rent_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_resident_own_or_rent')), + current_household_type_: I18n.t('datagrid.columns.current_address', column: I18n.t('datagrid.columns.clients.current_household_type')), + island2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.island2')), + street2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.street2')), + po_box2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.po_box2')), + settlement2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.settlement2')), + resident_own_or_rent2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.resident_own_or_rent2')), + household_type2_: I18n.t('datagrid.columns.other_address', column: I18n.t('datagrid.columns.clients.household_type2')), exit_reasons_: I18n.t('datagrid.columns.clients.exit_reasons'), exit_circumstance_: I18n.t('datagrid.columns.clients.exit_circumstance'), other_info_of_exit_: I18n.t('datagrid.columns.clients.other_info_of_exit'), @@ -352,10 +366,12 @@ def lable_translation_uderscore family_id_: I18n.t('datagrid.columns.families.code'), case_note_date_: I18n.t('datagrid.columns.clients.case_note_date'), case_note_type_: I18n.t('datagrid.columns.clients.case_note_type'), + assessment_created_at_: I18n.t('datagrid.columns.clients.assessment_created_at', assessment: I18n.t('clients.show.assessment')), date_of_assessments_: I18n.t('datagrid.columns.clients.date_of_assessments', assessment: I18n.t('clients.show.assessment')), date_of_referral_: I18n.t('datagrid.columns.clients.date_of_referral'), all_csi_assessments_: I18n.t('datagrid.columns.clients.all_csi_assessments'), date_of_custom_assessments_: I18n.t('datagrid.columns.clients.date_of_custom_assessments', assessment: I18n.t('clients.show.assessment')), + custom_assessment_created_at_: I18n.t('datagrid.columns.clients.custom_assessment_created_at', assessment: I18n.t('clients.show.assessment')), all_custom_csi_assessments_: I18n.t('datagrid.columns.clients.all_custom_csi_assessments', assessment: I18n.t('clients.show.assessment')), manage_: I18n.t('datagrid.columns.clients.manage'), changelog_: I18n.t('datagrid.columns.changelog'), @@ -390,12 +406,12 @@ def lable_translation_uderscore carer_relationship_to_client_: I18n.t('datagrid.columns.clients.carer_relationship_to_client'), province_id_: FieldSetting.cache_by_name_klass_name_instance('current_province', 'client') || I18n.t('datagrid.columns.clients.current_province'), birth_province_id_: FieldSetting.cache_by_name_klass_name_instance('birth_province', 'client') || I18n.t('datagrid.columns.clients.birth_province'), - **overdue_translations.map{ |k, v| ["#{k}_".to_sym, v] }.to_h + **overdue_translations.map { |k, v| ["#{k}_".to_sym, v] }.to_h } end def columns_visibility(column) - label_column = label_translations.map{ |k, v| ["#{k}".to_sym, v] }.to_h + label_column = label_translations.map { |k, v| [k.to_s.to_sym, v] }.to_h Client::STACKHOLDER_CONTACTS_FIELDS.each do |field| label_column[field] = I18n.t("datagrid.columns.clients.#{field}") @@ -405,12 +421,10 @@ def columns_visibility(column) def overdue_translations { - has_overdue_assessment: I18n.t("datagrid.form.has_overdue_assessment", assessment: I18n.t('clients.show.assessment')), - has_overdue_forms: I18n.t("datagrid.form.has_overdue_forms"), - has_overdue_task: I18n.t("datagrid.form.has_overdue_task"), - no_case_note: I18n.t("datagrid.form.no_case_note"), - care_plan_completed_date: I18n.t('datagrid.columns.clients.care_plan_completed_date'), - care_plan_count: I18n.t('datagrid.columns.clients.care_plan_count') + has_overdue_assessment: I18n.t('datagrid.form.has_overdue_assessment', assessment: I18n.t('clients.show.assessment')), + has_overdue_forms: I18n.t('datagrid.form.has_overdue_forms'), + has_overdue_task: I18n.t('datagrid.form.has_overdue_task'), + no_case_note: I18n.t('datagrid.form.no_case_note') } end @@ -418,14 +432,14 @@ def custom_assessment_field_traslation_mapping { custom_assessment: I18n.t('datagrid.columns.clients.custom_assessment', assessment: I18n.t('clients.show.assessment')), custom_completed_date: I18n.t('datagrid.columns.clients.assessment_custom_completed_date', assessment: I18n.t('clients.show.assessment')), - custom_assessment_created_date: I18n.t('datagrid.columns.clients.custom_assessment_created_date', assessment: I18n.t('clients.show.assessment')) + custom_assessment_created_at: I18n.t('datagrid.columns.clients.custom_assessment_created_at', assessment: I18n.t('clients.show.assessment')) } end def local_name_label(name_type = :local_given_name) custom_field = FieldSetting.cache_by_name(name_type.to_s, 'client') label = I18n.t("datagrid.columns.clients.#{name_type}") - label = "#{label} #{country_scope_label_translation}" if custom_field.blank? || custom_field.blank? + label = "#{label} #{country_scope_label_translation}" if custom_field.blank? label end @@ -453,25 +467,6 @@ def client_custom_fields_list(object) end end - def merged_address(client) - current_address = [] - current_address << "#{t('datagrid.columns.clients.house_number')} #{client.house_number}" if client.house_number.present? - current_address << "#{t('datagrid.columns.clients.street_number')} #{client.street_number}" if client.street_number.present? - - if I18n.locale.to_s == 'km' - current_address << "#{t('datagrid.columns.clients.village')} #{client.village.name_kh}" if client.village.present? - current_address << "#{t('datagrid.columns.clients.commune')} #{client.commune.name_kh}" if client.commune.present? - current_address << client.district_name.split(' / ').first if client.district.present? - current_address << client.province_name.split(' / ').first if client.province.present? - else - current_address << "#{t('datagrid.columns.clients.village')} #{client.village.name_en}" if client.village.present? - current_address << "#{t('datagrid.columns.clients.commune')} #{client.commune.name_en}" if client.commune.present? - current_address << client.district_name.split(' / ').last if client.district.present? - current_address << client.province_name.split(' / ').last if client.province.present? - end - current_address << selected_country.titleize - end - def concern_merged_address(client) current_address = [] current_address << "#{t('datagrid.columns.clients.concern_house')} #{client.concern_house}" if client.concern_house.present? @@ -496,7 +491,7 @@ def format_array_value(value) end def check_is_array_date?(properties) - properties.is_a?(Array) && properties.flatten.all?{|value| DateTime.strptime(value, '%Y-%m-%d') rescue nil } ? properties.map{|value| date_format(value.to_date) } : properties + properties.is_a?(Array) && properties.flatten.all? { |value| DateTime.strptime(value, '%Y-%m-%d') rescue nil } ? properties.map { |value| date_format(value.to_date) } : properties end def check_is_string_date?(property) @@ -504,7 +499,7 @@ def check_is_string_date?(property) end def format_properties_value(value) - value.is_a?(Array) ? check_is_array_date?(value.delete_if(&:empty?).map{|c| c.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('&qoute;', '"')}).join(' , ') : check_is_string_date?(value.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('&qoute;', '"')) + value.is_a?(Array) ? check_is_array_date?(value.delete_if(&:empty?).map { |c| c.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('&qoute;', '"') }).join(' , ') : check_is_string_date?(value.gsub('&', '&').gsub('<', '<').gsub('>', '>').gsub('&qoute;', '"')) end def field_not_blank?(value) @@ -520,22 +515,22 @@ def form_builder_format(value) end def form_builder_format_header(value) - entities = { formbuilder: 'Custom form', exitprogram: 'Exit program', tracking: 'Tracking', enrollment: 'Enrollment', enrollmentdate: 'Enrollment', exitprogramdate: 'Exit program' } - key_word = value.first - entity = entities[key_word.to_sym] - value = value - [key_word] - result = value << entity + entities = { formbuilder: 'Custom form', exitprogram: 'Exit program', tracking: 'Tracking', enrollment: 'Enrollment', enrollmentdate: 'Enrollment', exitprogramdate: 'Exit program' } + key_word = value.first + entity = entities[key_word.to_sym] + value = value - [key_word] + result = value << entity result.join(' | ') end def group_entity_by(value) - value.group_by{ |field| field.split('_').first} + value.group_by { |field| field.split('_').first } end def format_class_header(value) values = value.split('|') - name = values.first.strip - label = values.last.strip + name = values.first.strip + label = values.last.strip keyword = "#{name} #{label}" keyword.downcase.parameterize.gsub('-', '__') end @@ -576,44 +571,8 @@ def status_exited?(value) value == 'Exited' end - def selected_country - country = Setting.cache_first.try(:country_name) || params[:country].presence - country.nil? ? 'cambodia' : country - end - - def country_address_field(client) - country = selected_country - current_address = [] - case country - when 'thailand' - current_address << client.plot if client.plot.present? - current_address << client.road if client.road.present? - current_address << client.subdistrict_name if client.subdistrict.present? - current_address << client.district_name if client.district.present? - current_address << client.province_name if client.province.present? - current_address << client.postal_code if client.postal_code.present? - current_address << 'Thailand' - when 'lesotho' - current_address << client.suburb if client.suburb.present? - current_address << client.description_house_landmark if client.description_house_landmark.present? - current_address << client.directions if client.directions.present? - current_address << 'Lesotho' - when 'myanmar' - current_address << client.street_line1 if client.street_line1.present? - current_address << client.street_line2 if client.street_line2.present? - current_address << client.township_name if client.township.present? - current_address << client.state_name if client.state.present? - current_address << 'Myanmar' - when 'uganda' - current_address = merged_address(client) - else - current_address = merged_address(client) - end - current_address.compact.join(', ') - end - def default_columns_visibility(column) - label_column = label_translations.map{ |k, v| ["#{k}_".to_sym, v] }.to_h + label_column = label_translations.map { |k, v| ["#{k}_".to_sym, v] }.to_h (Client::HOTLINE_FIELDS + Call::FIELDS).each do |field_name| label_column["#{field_name}_".to_sym] = I18n.t("datagrid.columns.clients.#{field_name}") @@ -624,7 +583,7 @@ def default_columns_visibility(column) field = domain.convert_identity label_column = label_column.merge!("#{field}_": identity) end - QuantitativeType.joins(:quantitative_cases).where('quantitative_types.visible_on LIKE ?', "%client%").uniq.each do |quantitative_type| + QuantitativeType.joins(:quantitative_cases).where('quantitative_types.visible_on LIKE ?', '%client%').uniq.each do |quantitative_type| field = quantitative_type.name label_column = label_column.merge!("#{field}_": quantitative_type.name) end @@ -651,15 +610,15 @@ def client_advanced_search_data(object, rule) return object unless $param_rules.present? @data = $param_rules['basic_rules'].is_a?(String) ? JSON.parse($param_rules['basic_rules']).with_indifferent_access : $param_rules['basic_rules'] - @data[:rules].reject{ |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } + @data[:rules].reject { |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } end def mapping_query_string(object, hashes, association, rule) param_values = [] - sql_string = [] - hashes[rule].each do |rule| - rule.keys.each do |key| - values = rule[key] + sql_string = [] + hashes[rule].each do |value| + rule.each_key do |key| + values = value[key] case key when 'equal' sql_string << "#{association} = ?" @@ -681,24 +640,25 @@ def mapping_query_string(object, hashes, association, rule) def program_stream_name(object, rule) properties_field = 'client_enrollment_trackings.properties' - basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules + basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules return object if basic_rules.nil? - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access - results = mapping_form_builder_param_value(basic_rules, rule) - query_string = get_query_string(results, rule, properties_field) + + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_form_builder_param_value(basic_rules, rule) + query_string = get_query_string(results, rule, properties_field) default_value_param = params['all_values'] if default_value_param object elsif rule == 'tracking' - properties_result = object.joins(:client_enrollment_trackings).where(query_string.reject(&:blank?).join(" #{basic_rules[:condition]} ")).distinct + object.joins(:client_enrollment_trackings).where(query_string.reject(&:blank?).join(" #{basic_rules[:condition]} ")).distinct elsif rule == 'active_program_stream' mew_query_string = query_string.reject(&:blank?).join(" #{basic_rules[:condition]} ") program_stream_ids = mew_query_string&.scan(/program_streams\.id = (\d+)/)&.flatten || [] if program_stream_ids.size >= 2 - sql_partial = mew_query_string.gsub(/program_streams\.id = \d+/, "program_streams.id IN (#{program_stream_ids.join(", ")})") - properties_result = object.includes(client: :program_streams).where(sql_partial).references(:program_streams).distinct + sql_partial = mew_query_string.gsub(/program_streams\.id = \d+/, "program_streams.id IN (#{program_stream_ids.join(', ')})") + object.includes(client: :program_streams).where(sql_partial).references(:program_streams).distinct else - properties_result = object.includes(client: :program_streams).where(query_string.reject(&:blank?).join(" #{basic_rules[:condition]} ")).references(:program_streams).distinct + object.includes(client: :program_streams).where(query_string.reject(&:blank?).join(" #{basic_rules[:condition]} ")).references(:program_streams).distinct end else object @@ -708,13 +668,13 @@ def program_stream_name(object, rule) def mapping_sub_query_array(object, association, rule) sub_query_array = [] if @data[:rules] - sub_rule_index = @data[:rules].index { |param| param.key?(:condition)} + sub_rule_index = @data[:rules].index { |param| param.key?(:condition) } if sub_rule_index.present? - sub_hashes = Hash.new { |h, k| h[k] = [] } - sub_results = @data[:rules][sub_rule_index] - sub_result_hash = sub_results[:rules].reject{ |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } + sub_hashes = Hash.new { |h, k| h[k] = [] } + sub_results = @data[:rules][sub_rule_index] + sub_result_hash = sub_results[:rules].reject { |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } sub_result_hash.each { |k, o, v| sub_hashes[k] << { o => v } } - sub_sql_hash = mapping_query_string(object, sub_hashes, association, rule) + sub_sql_hash = mapping_query_string(object, sub_hashes, association, rule) sub_query_array = mapping_query_string_with_query_value(sub_sql_hash, sub_results[:condition]) end end @@ -722,16 +682,13 @@ def mapping_sub_query_array(object, association, rule) end def case_note_query(object, rule) - return object unless params[:client_advanced_search].present? - data = {} - rules = %w( case_note_date case_note_type ) - return object if params[:client_advanced_search][:basic_rules].nil? - data = JSON.parse(params[:client_advanced_search][:basic_rules]).with_indifferent_access + return object unless params[:client_advanced_search].present? && params[:client_advanced_search][:basic_rules].present? - result1 = mapping_param_value(data, 'case_note_date') - result2 = mapping_param_value(data, 'case_note_type') + data = JSON.parse(params[:client_advanced_search][:basic_rules]).with_indifferent_access + result1 = mapping_param_value(data, 'case_note_date') + result2 = mapping_param_value(data, 'case_note_type') - default_value_param = params['all_values'] + default_value_param = params['all_values'] if default_value_param == 'case_note_date' return case_note_date_all_value(object, data, result2, rule, default_value_param) @@ -739,8 +696,8 @@ def case_note_query(object, rule) return case_note_type_all_value(object, data, result1, rule, default_value_param) end - case_note_date_hashes = mapping_query_result(result1) - case_note_type_hashes = Hash.new { |h, k| h[k] = [] } + case_note_date_hashes = mapping_query_result(result1) + case_note_type_hashes = Hash.new { |h, k| h[k] = [] } result2.each { |k, o, v| case_note_type_hashes[k] << { o => v } } sub_case_note_date_query, sub_case_note_type_query = sub_query_results(object, data) @@ -748,62 +705,58 @@ def case_note_query(object, rule) sql_case_note_date_hash = mapping_query_date(object, case_note_date_hashes, 'case_notes.meeting_date') sql_case_note_type_hash = mapping_query_string(object, case_note_type_hashes, 'case_notes.interaction_type', 'case_note_type') - case_note_date_query = mapping_query_string_with_query_value(sql_case_note_date_hash, data[:condition]) - case_note_type_query = mapping_query_string_with_query_value(sql_case_note_type_hash, data[:condition]) + case_note_date_query = mapping_query_string_with_query_value(sql_case_note_date_hash, data[:condition]) + case_note_type_query = mapping_query_string_with_query_value(sql_case_note_type_hash, data[:condition]) if case_note_date_query.present? && case_note_type_query.blank? object = object.where(case_note_date_query).where(sub_case_note_date_query) elsif case_note_type_query.present? && case_note_date_query.blank? object = object.where(case_note_type_query).where(sub_case_note_type_query) + elsif data[:condition] == 'AND' + object = object.where(case_note_date_query).where(case_note_type_query).where(sub_case_note_type_query).where(sub_case_note_date_query) + elsif sub_case_note_type_query.first.blank? && sub_case_note_date_query.first.blank? + object = case_note_query_results(object, case_note_date_query, case_note_type_query) + elsif sub_case_note_date_query.first.present? && sub_case_note_type_query.first.blank? + object = case_note_query_results(object, case_note_date_query, case_note_type_query).or(object.where(sub_case_note_date_query)) + elsif sub_case_note_type_query.first.present? && sub_case_note_date_query.first.blank? + object = case_note_query_results(object, case_note_date_query, case_note_type_query).or(object.where(sub_case_note_type_query)) else - if data[:condition] == 'AND' - object = object.where(case_note_date_query).where(case_note_type_query).where(sub_case_note_type_query).where(sub_case_note_date_query) - else - if sub_case_note_type_query.first.blank? && sub_case_note_date_query.first.blank? - object = case_note_query_results(object, case_note_date_query, case_note_type_query) - elsif sub_case_note_date_query.first.present? && sub_case_note_type_query.first.blank? - object = case_note_query_results(object, case_note_date_query, case_note_type_query).or(object.where(sub_case_note_date_query)) - elsif sub_case_note_type_query.first.present? && sub_case_note_date_query.first.blank? - object = case_note_query_results(object, case_note_date_query, case_note_type_query).or(object.where(sub_case_note_type_query)) - else - object = case_note_query_results(object, case_note_date_query, case_note_type_query).or(object.where(sub_case_note_type_query)).or(object.where(sub_case_note_date_query)) - end - end + object = case_note_query_results(object, case_note_date_query, case_note_type_query).or(object.where(sub_case_note_type_query)).or(object.where(sub_case_note_date_query)) end object.present? ? object : [] end - def form_builder_query(object, form_type, field_name, properties_field=nil) + def form_builder_query(object, form_type, field_name, properties_field = nil) return object if params['all_values'].present? properties_field = properties_field.present? ? properties_field : 'client_enrollment_trackings.properties' selected_program_stream = $param_rules['program_selected'].presence ? JSON.parse($param_rules['program_selected']) : [] - basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access - results = mapping_form_builder_param_value(basic_rules, form_type) + basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_form_builder_param_value(basic_rules, form_type) return object if results.flatten.blank? - query_string = get_query_string(results, form_type, properties_field) + query_string = get_query_string(results, form_type, properties_field) if form_type == 'formbuilder' - properties_result = object.where(query_string.reject(&:blank?).join(" #{basic_rules['condition']} ")) + object.where(query_string.reject(&:blank?).join(" #{basic_rules['condition']} ")) else - properties_result = object.joins(:client_enrollment).where(client_enrollments: { program_stream_id: selected_program_stream }).where(query_string.reject(&:blank?).join(" #{basic_rules['condition']} ")) + object.joins(:client_enrollment).where(client_enrollments: { program_stream_id: selected_program_stream }).where(query_string.reject(&:blank?).join(" #{basic_rules['condition']} ")) end end - def family_form_builder_query(object, form_type, field_name, properties_field=nil) + def family_form_builder_query(object, form_type, field_name, properties_field = nil) return object if $param_rules['all_values'].present? properties_field = properties_field.present? ? properties_field : 'enrollment_trackings.properties' selected_program_stream = $param_rules['program_selected'].presence ? JSON.parse($param_rules['program_selected']) : [] - basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access - results = mapping_form_builder_param_value(basic_rules, form_type) + basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_form_builder_param_value(basic_rules, form_type) return object if results.flatten.blank? - query_string = get_query_string(results, form_type, properties_field) + query_string = get_query_string(results, form_type, properties_field) if form_type == 'formbuilder' properties_result = object.where(query_string.reject(&:blank?).join(" #{basic_rules['condition']} ")) else @@ -827,20 +780,20 @@ def sub_query_results(object, data) sub_case_note_date_query = [''] sub_case_note_type_query = [''] if data[:rules] - sub_rule_index = data[:rules].index { |param| param.key?(:condition)} + sub_rule_index = data[:rules].index { |param| param.key?(:condition) } if sub_rule_index.present? - sub_case_note_date_results = data[:rules][sub_rule_index] + sub_case_note_date_results = data[:rules][sub_rule_index] sub_case_note_date_result_hash = mapping_param_value(sub_case_note_date_results, 'case_note_date') - sub_case_note_date_hashes = mapping_query_result(sub_case_note_date_result_hash) - sub_case_note_date_sql_hash = mapping_query_date(object, sub_case_note_date_hashes, 'case_notes.meeting_date') - sub_case_note_date_query = mapping_query_string_with_query_value(sub_case_note_date_sql_hash, sub_case_note_date_results[:condition]) + sub_case_note_date_hashes = mapping_query_result(sub_case_note_date_result_hash) + sub_case_note_date_sql_hash = mapping_query_date(object, sub_case_note_date_hashes, 'case_notes.meeting_date') + sub_case_note_date_query = mapping_query_string_with_query_value(sub_case_note_date_sql_hash, sub_case_note_date_results[:condition]) - sub_case_note_type_hashes = Hash.new { |h, k| h[k] = [] } - sub_case_note_type_results = data[:rules][sub_rule_index] + sub_case_note_type_hashes = Hash.new { |h, k| h[k] = [] } + sub_case_note_type_results = data[:rules][sub_rule_index] sub_case_note_type_result_hash = mapping_param_value(sub_case_note_type_results, 'case_note_type') sub_case_note_type_result_hash.each { |k, o, v| sub_case_note_type_hashes[k] << { o => v } } - sub_case_note_type_sql_hash = mapping_query_string(object, sub_case_note_type_hashes, 'case_notes.interaction_type', 'case_note_type') - sub_case_note_type_query = mapping_query_string_with_query_value(sub_case_note_type_sql_hash, data[:condition]) + sub_case_note_type_sql_hash = mapping_query_string(object, sub_case_note_type_hashes, 'case_notes.interaction_type', 'case_note_type') + sub_case_note_type_query = mapping_query_string_with_query_value(sub_case_note_type_sql_hash, data[:condition]) end end [sub_case_note_date_query, sub_case_note_type_query] @@ -852,10 +805,10 @@ def case_note_date_all_value(object, data, results, rule, default_value_param) return object else sub_case_note_type_query = [''] - case_note_type_hashes = Hash.new { |h, k| h[k] = [] } + case_note_type_hashes = Hash.new { |h, k| h[k] = [] } results.each { |k, o, v| case_note_type_hashes[k] << { o => v } } - sql_case_note_type_hash = mapping_query_string(object, case_note_type_hashes, 'case_notes.interaction_type', 'case_note_type') - case_note_type_query = mapping_query_string_with_query_value(sql_case_note_type_hash, data[:condition]) + sql_case_note_type_hash = mapping_query_string(object, case_note_type_hashes, 'case_notes.interaction_type', 'case_note_type') + case_note_type_query = mapping_query_string_with_query_value(sql_case_note_type_hash, data[:condition]) sub_case_note_type_query = sub_query_results(object, data).last if data[:condition] == 'AND' if sub_case_note_type_query.first.blank? @@ -878,9 +831,9 @@ def case_note_type_all_value(object, data, results, rule, default_value_param) return if default_value_param.blank? sub_case_note_date_query = [''] - case_note_date_hashes = mapping_query_result(results) - sql_case_note_date_hash = mapping_query_date(object, case_note_date_hashes, 'case_notes.meeting_date') - case_note_date_query = mapping_query_string_with_query_value(sql_case_note_date_hash, data[:condition]) + case_note_date_hashes = mapping_query_result(results) + sql_case_note_date_hash = mapping_query_date(object, case_note_date_hashes, 'case_notes.meeting_date') + case_note_date_query = mapping_query_string_with_query_value(sql_case_note_date_hash, data[:condition]) sub_case_note_date_query = sub_query_results(object, data).first if data[:condition] == 'AND' if sub_case_note_date_query.first.blank? @@ -899,10 +852,10 @@ def case_note_type_all_value(object, data, results, rule, default_value_param) end def mapping_param_value(data, rule) - data[:rules].reject{ |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } + data[:rules].reject { |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } end - def mapping_form_builder_param_value(data, form_type, field_name=nil, data_mapping=[]) + def mapping_form_builder_param_value(data, form_type, field_name = nil, data_mapping = []) rule_array = [] data[:rules].each_with_index do |h, index| if h.has_key?(:rules) @@ -920,20 +873,23 @@ def mapping_form_builder_param_value(data, form_type, field_name=nil, data_mappi end def date_filter(object, rule) - query_array = [] - sub_query_array = [] - field_name = '' - results = client_advanced_search_data(object, rule) + query_array = [] + sub_query_array = [] + field_name = '' + results = client_advanced_search_data(object, rule) return object if return_default_filter(object, rule, results) - klass_name = { exit_date: 'exit_ngos', accepted_date: 'enter_ngos', meeting_date: 'case_notes', case_note_type: 'case_notes', created_at: 'assessments', completed_date: 'assessments', date_of_referral: 'referrals', care_plan_completed_date: 'care_plans' }.with_indifferent_access + klass_name = { exit_date: 'exit_ngos', accepted_date: 'enter_ngos', meeting_date: 'case_notes', case_note_type: 'case_notes', created_at: 'assessments', completed_date: 'assessments', date_of_referral: 'referrals', care_plan_completed_date: 'care_plans', care_plan_date: 'care_plans' }.with_indifferent_access if rule == 'case_note_date' field_name = 'meeting_date' elsif rule == 'completed_date' field_name = 'completed_date' - elsif rule.in?(['date_of_assessments', 'date_of_custom_assessments', 'care_plan_completed_date', 'custom_assessment_created_date']) + elsif rule.in? ['assessment_created_at', 'custom_assessment_created_at', 'care_plan_completed_date'] field_name = 'created_at' + elsif rule.in?(['date_of_assessments', 'date_of_custom_assessments']) + klass_name = { date_of_assessments: 'assessments', date_of_custom_assessments: 'assessments', assessment_date: 'assessments' } + field_name = 'assessment_date' elsif rule[/^(exitprogramdate)/i].present? || object.class.to_s[/^(leaveprogram)/i] klass_name.merge!(rule => 'leave_programs') field_name = 'exit_date' @@ -947,17 +903,19 @@ def date_filter(object, rule) relation = rule[/^(enrollmentdate)|^(exitprogramdate)|^(care_plan_completed_date)/i] ? "#{klass_name[rule]}.#{field_name}" : "#{klass_name[field_name.to_sym]}.#{field_name}" relation = object.first&.class&.name == 'Enrollment' ? "enrollments.#{field_name}" : relation - hashes = mapping_query_result(results) + hashes = mapping_query_result(results) sql_hash = mapping_query_date(object, hashes, relation) if @data[:rules] - sub_rule_index = @data[:rules].index { |param| param.key?(:condition)} + sub_rule_index = @data[:rules].index { |param| param.key?(:condition) } if sub_rule_index.present? - sub_results = @data[:rules][sub_rule_index] - sub_result_hash = sub_results[:rules].reject{ |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } - sub_hashes = mapping_query_result(sub_result_hash) - sub_sql_hash = mapping_query_date(object, sub_hashes, relation) - sub_query_array = mapping_query_string_with_query_value(sub_sql_hash, sub_results[:condition]) + sub_results = @data[:rules][sub_rule_index] + if sub_results[:rules].present? + sub_result_hash = sub_results[:rules].reject { |h| h[:id] != rule }.map { |value| [value[:id], value[:operator], value[:value]] } + sub_hashes = mapping_query_result(sub_result_hash) + sub_sql_hash = mapping_query_date(object, sub_hashes, relation) + sub_query_array = mapping_query_string_with_query_value(sub_sql_hash, sub_results[:condition]) + end end end @@ -965,7 +923,7 @@ def date_filter(object, rule) if rule == 'date_of_assessments' sql_string = object.where(query_array).where(default: true).where(sub_query_array) - elsif rule == 'date_of_custom_assessments' || rule == 'custom_assessment_created_date' + elsif rule == 'date_of_custom_assessments' || rule == 'custom_assessment_created_at' sql_string = object.where(query_array).where(default: false).where(sub_query_array) else if object.is_a?(Array) @@ -981,11 +939,12 @@ def date_filter(object, rule) def header_counter(grid, column) return column.header.truncate(65) if grid.class.to_s != 'ClientGrid' || @clients_by_user.blank? count = 0 - class_name = header_classes(grid, column) - class_name = class_name == "call-field" ? column.name.to_s : class_name + class_name = header_classes(grid, column) + class_name = class_name == 'call-field' ? column.name.to_s : class_name + if Client::HEADER_COUNTS.include?(class_name) || class_name[/^(enrollmentdate)/i] || class_name[/^(exitprogramdate)/i] || class_name[/^(formbuilder)/i] || class_name[/^(tracking)/i] association = "#{class_name}_count" - klass_name = { exit_date: 'exit_ngos', accepted_date: 'enter_ngos', case_note_date: 'case_notes', case_note_type: 'case_notes', date_of_assessments: 'assessments', date_of_custom_assessments: 'assessments', formbuilder__Client: 'custom_field_properties' } + klass_name = { exit_date: 'exit_ngos', accepted_date: 'enter_ngos', case_note_date: 'case_notes', case_note_type: 'case_notes', date_of_assessments: 'assessments', date_of_custom_assessments: 'assessments', formbuilder__Client: 'custom_field_properties' } if class_name[/^(exitprogramdate)/i].present? || class_name[/^(leaveprogram)/i] klass = 'leave_programs' @@ -1005,7 +964,7 @@ def header_counter(grid, column) count += date_filter(object, class_name).flatten.count else basic_rules = $param_rules['basic_rules'] - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access results = mapping_exit_program_date_param_value(basic_rules) query_string = get_exit_program_date_query_string(results) object = LeaveProgram.joins(:program_stream).where(program_streams: { name: column.header.split('|').first.squish }, leave_programs: { client_enrollment_id: ids }).where(query_string) @@ -1036,7 +995,7 @@ def header_counter(grid, column) end count += data_filter.present? ? data_filter.flatten.count : 0 - elsif class_name[/^(date_of_custom_assessments|custom_assessment_created_date)/i].present? + elsif class_name[/^(date_of_custom_assessments|custom_assessment_created_at)/i].present? if params['all_values'] == class_name data_filter = date_filter(client.assessments.customs, "#{class_name}") else @@ -1045,9 +1004,10 @@ def header_counter(grid, column) end elsif class_name[/^(formbuilder)/i].present? if fields.last == 'Has This Form' - count += client.custom_field_properties.joins(:custom_field).where(custom_fields: { form_title: fields.second, entity_type: 'Client'}).count + count += client.custom_field_properties.joins(:custom_field).where(custom_fields: { form_title: fields.second, entity_type: 'Client' }).count else - properties = form_builder_query(client.custom_field_properties, fields.first, column.name.to_s.gsub('&qoute;', '"'), 'custom_field_properties.properties').properties_by(format_field_value) + custom_field_id = client.custom_fields.cached_client_custom_field_find_by(client, fields.second) + properties = form_builder_query(client.custom_field_properties.where(custom_field_id: custom_field_id), fields.first, column.name.to_s.gsub('&qoute;', '"'), 'custom_field_properties.properties').properties_by(format_field_value) count += property_filter(properties, format_field_value).size end elsif class_name[/^(tracking)/i] @@ -1056,7 +1016,7 @@ def header_counter(grid, column) properties = form_builder_query(client_enrollment_trackings, 'tracking', column.name.to_s.gsub('&qoute;', '"')).properties_by(format_field_value) count += property_filter(properties, format_field_value).size elsif class_name == 'quantitative-type' - quantitative_type_values = client.quantitative_cases.joins(:quantitative_type).where(quantitative_types: {name: column.header }).pluck(:value) + quantitative_type_values = client.quantitative_cases.joins(:quantitative_type).where(quantitative_types: { name: column.header }).pluck(:value) quantitative_type_values = property_filter(quantitative_type_values, column.header.split('|').third.try(:strip) || column.header.strip) count += quantitative_type_values.count elsif class_name == 'type_of_service' @@ -1076,9 +1036,8 @@ def header_counter(grid, column) class_name = class_name =~ /^(formbuilder)/i ? column.name.to_s : class_name link_all = params['all_values'] != class_name ? button_to('All', advanced_search_clients_path, params: params.merge(all_values: class_name), remote: false, form_class: 'all-values') : '' [column.header.truncate(65), - content_tag(:span, count, class: 'label label-info'), - link_all - ].join(' ').html_safe + content_tag(:span, count, class: 'label label-info'), + link_all].join(' ').html_safe else column.header.truncate(65) end @@ -1089,7 +1048,7 @@ def header_counter(grid, column) def family_counter return unless controller_name == 'clients' - count = @results.joins("INNER JOIN families on families.id = clients.current_family_id").distinct.count("clients.current_family_id") + count = @results.joins('INNER JOIN families on families.id = clients.current_family_id').distinct.count('clients.current_family_id') content_tag(:span, count, class: 'label label-info') end @@ -1101,11 +1060,11 @@ def care_plan_counter def case_note_count(client) results = [] - @basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules + @basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules if @basic_rules.present? - basic_rules = @basic_rules.is_a?(Hash) ? @basic_rules : JSON.parse(@basic_rules).with_indifferent_access - results = mapping_allowed_param_value(basic_rules, ['case_note_date', 'case_note_type'], data_mapping=[]) - query_string = get_any_query_string(results, 'case_notes') + basic_rules = @basic_rules.is_a?(Hash) ? @basic_rules : JSON.parse(@basic_rules).with_indifferent_access + results = mapping_allowed_param_value(basic_rules, ['case_note_date', 'case_note_type'], data_mapping = []) + query_string = get_any_query_string(results, 'case_notes') client.case_notes.where(query_string) else client.case_notes @@ -1114,7 +1073,7 @@ def case_note_count(client) def case_history_label(value) label = case value.class.table_name - when 'enter_ngos' then I18n.t("accepted_date") + when 'enter_ngos' then I18n.t('accepted_date') when 'exit_ngos' then I18n.t('clients.case_history_detail.exit_date') when 'client_enrollments', 'enrollments' then "#{value.program_stream.try(:name)} Entry" when 'leave_programs' then "#{value.program_stream.name} Exit" @@ -1134,7 +1093,7 @@ def international_referred_client end def mapping_query_result(results) - hashes = values = Hash.new { |h, k| h[k] = [] } + hashes = values = Hash.new { |h, k| h[k] = [] } results.each do |k, o, v| values[o] << v hashes[k] << values @@ -1149,10 +1108,10 @@ def mapping_query_result(results) end def mapping_query_date(object, hashes, relation) - sql_string = [] - param_values = [] + sql_string = [] + param_values = [] hashes.keys.each do |key| - values = hashes[key].flatten + values = hashes[key].flatten case key when 'between' sql_string << "date(#{relation}) BETWEEN ? AND ?" @@ -1178,7 +1137,6 @@ def mapping_query_date(object, hashes, relation) param_values << values when 'is_empty' sql_string << "date(#{relation}) IS NULL" - when 'is_not_empty' sql_string << "date(#{relation}) IS NOT NULL" else @@ -1200,12 +1158,18 @@ def return_default_filter(object, rule, results) rule[/^(#{$param_rules && $param_rules['all_values']})/i].present? || object.blank? || results.blank? || results.class.name[/activerecord/i].present? end - def case_workers_option(client_id, editable_input=false) - @users.map do |user| - tasks = user.tasks.incomplete.where(client_id: client_id) + def editable_case_worker_options + @editable_case_worker_options ||= case_workers_option(@client.id, true) + end + + def case_workers_option(client_id, editable_input = false) + users = @users.includes(:incomplete_tasks).to_a + users.map do |user| + tasks = user.incomplete_tasks.select { |task| task.client_id == client_id } + if !editable_input if tasks.any? - [user.name, user.id, { locked: 'locked'} ] + [user.name, user.id, { locked: 'locked' }] else [user.name, user.id] end @@ -1274,23 +1238,29 @@ def date_condition_filter(rule, properties) if rule && properties.present? case rule[:operator] when 'equal' - properties = properties.select{|value| value.to_date == rule[:value].to_date } + properties = properties.select { |value| value.to_date == rule[:value].to_date } when 'not_equal' - properties = properties.select{|value| value.to_date != rule[:value].to_date } + properties = properties.select { |value| value.to_date != rule[:value].to_date } when 'less' - properties = properties.select{|value| value.to_date < rule[:value].to_date } + properties = properties.select { |value| value.to_date < rule[:value].to_date } when 'less_or_equal' - properties = properties.select{|value| value.to_date <= rule[:value].to_date } + properties = properties.select { |value| value.to_date <= rule[:value].to_date } when 'greater' - properties = properties.select{|value| value.to_date > rule[:value].to_date } + properties = properties.select { |value| value.to_date > rule[:value].to_date } when 'greater_or_equal' - properties = properties.select{|value| value.to_date >= rule[:value].to_date } + properties = properties.select { |value| value.to_date >= rule[:value].to_date } when 'is_empty' properties = [] when 'is_not_empty' properties when 'between' - properties = properties.is_a?(Array) ? properties.select { |value| value.to_date >= rule[:value].first.to_date && value.to_date <= rule[:value].last.to_date } : [properties].flatten.compact + properties = if properties.is_a?(Array) + properties.select do |value| + value.to_s[/\d{4}-\d{2}-\d{2}/].present? && value.to_date >= rule[:value].first.to_date && value.to_date <= rule[:value].last.to_date + end + else + [properties].flatten.compact + end end end properties || [] @@ -1306,23 +1276,23 @@ def property_filter(properties, field_name) elsif rule.presence results = string_condition_filter(rule, properties.flatten) end - results = results.presence ? results : properties + results.presence || properties end def string_condition_filter(rule, properties) case rule[:operator] when 'equal' - properties = rule[:type] != 'integer' ? properties.select{|value| value == rule[:value].strip } : properties.select{|value| value.to_i == rule[:value] } + properties = rule[:type] != 'integer' ? properties.select { |value| value == rule[:value].strip } : properties.select { |value| value.to_i == rule[:value] } when 'not_equal' - properties = rule[:type] != 'integer' ? properties.select{|value| value != rule[:value].strip } : properties.select{|value| value.to_i != rule[:value] } + properties = rule[:type] != 'integer' ? properties.select { |value| value != rule[:value].strip } : properties.select { |value| value.to_i != rule[:value] } when 'less' - properties = rule[:type] != 'integer' ? properties.select{|value| value < rule[:value].strip } : properties.select{|value| value.to_i < rule[:value] } + properties = rule[:type] != 'integer' ? properties.select { |value| value < rule[:value].strip } : properties.select { |value| value.to_i < rule[:value] } when 'less_or_equal' - properties = rule[:type] != 'integer' ? properties.select{|value| value <= rule[:value].strip } : properties.select{|value| value.to_i <= rule[:value] } + properties = rule[:type] != 'integer' ? properties.select { |value| value <= rule[:value].strip } : properties.select { |value| value.to_i <= rule[:value] } when 'greater' - properties = rule[:type] != 'integer' ? properties.select{|value| value > rule[:value].strip } : properties.select{|value| value.to_i > rule[:value] } + properties = rule[:type] != 'integer' ? properties.select { |value| value > rule[:value].strip } : properties.select { |value| value.to_i > rule[:value] } when 'greater_or_equal' - properties = rule[:type] != 'integer' ? properties.select{|value| value >= rule[:value].strip } : properties.select{|value| value.to_i >= rule[:value] } + properties = rule[:type] != 'integer' ? properties.select { |value| value >= rule[:value].strip } : properties.select { |value| value.to_i >= rule[:value] } when 'contains' properties.include?(rule[:value].strip) when 'not_contains' @@ -1332,7 +1302,7 @@ def string_condition_filter(rule, properties) when 'is_not_empty' properties when 'between' - properties = rule[:type] != 'integer' ? properties.select{|value| value.to_i >= rule[:value].first.strip && value.to_i <= rule[:value].last.strip } : properties.select{|value| value.to_i >= rule[:value].first && value.to_i <= rule[:value].last } + properties = rule[:type] != 'integer' ? properties.select { |value| value.to_i >= rule[:value].first.strip && value.to_i <= rule[:value].last.strip } : properties.select { |value| value.to_i >= rule[:value].first && value.to_i <= rule[:value].last } end properties end @@ -1344,11 +1314,11 @@ def select_condition_filter(rule, properties) if rule[:data][:values].is_a?(Hash) value == rule[:data][:values][rule[:value].to_sym] else - value == rule[:data][:values].map{ |hash| hash[rule[:value].to_sym] }.compact.first + value == rule[:data][:values].map { |hash| hash[rule[:value].to_sym] }.compact.first end end when 'not_equal' - properties = properties.select{|value| value != rule[:data][:values].map{|hash| hash[rule[:value].to_sym] }.compact.first } + properties = properties.select { |value| value != rule[:data][:values].map { |hash| hash[rule[:value].to_sym] }.compact.first } when 'is_empty' properties = [] when 'is_not_empty' @@ -1364,7 +1334,7 @@ def get_rule(params, field) index = find_rules_index(rules, field) if rules.presence - rule = rules[index] if index.presence + rule = rules[index] if index.presence end def find_rules_index(rules, field) @@ -1377,40 +1347,26 @@ def find_rules_index(rules, field) end end - def referral_source_name(referral_source) - if I18n.locale == :km - referral_source.map{|ref| [ref.name, ref.id] } - else - referral_source.map do |ref| - if ref.name_en.blank? - [ref.name, ref.id] - else - [ref.name_en, ref.id] - end - end - end - end - def group_client_associations [*@assessments, *@case_notes, *@tasks, *@client_enrollment_leave_programs, *@client_enrollment_trackings, *@client_enrollments, *@case_histories, *@custom_field_properties, *@calls].group_by do |association| class_name = association.class.name.downcase if class_name == 'clientenrollment' || class_name == 'leaveprogram' || class_name == 'casenote' created_date = association.created_at date_field = if class_name == 'clientenrollment' - association.enrollment_date - elsif class_name == 'leaveprogram' - association.exit_date - elsif class_name == 'casenote' - association.meeting_date - elsif class_name == 'call' - association.date_of_call - end + association.enrollment_date + elsif class_name == 'leaveprogram' + association.exit_date + elsif class_name == 'casenote' + association.meeting_date + elsif class_name == 'call' + association.date_of_call + end distance_between_dates = (date_field.to_date - created_date.to_date).to_i created_date + distance_between_dates.day else association.created_at end - end.sort_by{|k, v| k }.reverse.to_h + end.sort_by { |k, v| k }.reverse.to_h end def referral_source_category(id) @@ -1457,7 +1413,7 @@ def get_quantitative_types if current_organization.short_name != 'brc' QuantitativeType.all else - QuantitativeType.unscoped.where('quantitative_types.visible_on LIKE ?', "%client%").order("substring(quantitative_types.name, '^[0-9]+')::int, substring(quantitative_types.name, '[^0-9]*$')") + QuantitativeType.unscoped.where('quantitative_types.visible_on LIKE ?', '%client%').order("substring(quantitative_types.name, '^[0-9]+')::int, substring(quantitative_types.name, '[^0-9]*$')") end end @@ -1465,8 +1421,13 @@ def get_address(address_name) @client.public_send("#{address_name}") ? [@client.public_send("#{address_name}").slice('id', 'name')] : [] end + def in_used_custom_field?(custom_field) + @readable_forms.map(&:custom_field_id).include?(custom_field.id) + end + def saved_search_column_visibility(field_key) - default_setting(field_key, @client_default_columns) || params[field_key.to_sym].present? || (@visible_fields && @visible_fields[field_key]).present? + client_default_columns ||= Setting.cache_first.client_default_columns + default_setting(field_key, client_default_columns) || params[field_key.to_sym].present? || (@visible_fields && @visible_fields[field_key]).present? end def legal_doc_fields @@ -1484,7 +1445,7 @@ def if_date_of_birth_blank(client) end def has_of_warning_model_if_dob_blank(client) - return { "data-target": "#screening-tool-warning", "data-toggle": "modal" } if client.date_of_birth.blank? + return { "data-target": '#screening-tool-warning', "data-toggle": 'modal' } if client.date_of_birth.blank? {} end end diff --git a/app/helpers/custom_field_properties_helper.rb b/app/helpers/custom_field_properties_helper.rb index 763909c2b7..db3058244a 100644 --- a/app/helpers/custom_field_properties_helper.rb +++ b/app/helpers/custom_field_properties_helper.rb @@ -54,7 +54,7 @@ def client_custom_field? end def remove_field_prop_unicode(field_props) - field = field_props['label'].gsub(/\>\;|\<\;|\&\;|\"/, '<' => '<', '>' => '>', '&' => '&', '"' => '%22') + field_props['label'].gsub(/\>\;|\<\;|\&\;|\"/, '<' => '<', '>' => '>', '&' => '&', '"' => '%22') end def remove_local_field_prop_unicode(field_props) @@ -70,9 +70,14 @@ def mapping_custom_field_values(field_props) end def display_custom_formable_name(klass_object) - return klass_object.display_name if klass_object.class.name.downcase == 'family' - - klass_object.en_and_local_name + case klass_object.class.name.downcase + when 'family', 'community' + klass_object.display_name + when 'user' + klass_object.name + else + klass_object.en_and_local_name + end end def display_custom_formable_lebel(klass_object) @@ -139,5 +144,4 @@ def form_builder_options_custom_form(custom_field) def is_custom_field_property_editable?(custom_field_property) Organization.ratanak? && !current_user.admin? ? custom_field_editable?(@custom_field) && custom_field_property.is_editable? : custom_field_editable?(@custom_field) end - end diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index 407407e06d..6f46e92dcb 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -7,6 +7,10 @@ def checkbox_forms end end + def family_tab? + params[:tab] == 'family' + end + def checkbox_tasks if @default_params 'true' @@ -63,12 +67,18 @@ def upcoming_custom_assessments_any?(client) client.custom_next_assessment_date(@user.activated_at).between?(Date.tomorrow, 3.months.from_now) if client.custom_next_assessment_date(@user.activated_at).present? end + # No longer used, moved to client.custom_next_assessment_date2 def client_custom_next_assessment_date(client, activated_at=nil) - custom_assessment_setting_ids = client_custom_assessment_setting(client) - CustomAssessmentSetting.only_enable_custom_assessment.where(id: custom_assessment_setting_ids).map do |custom_assessment| + return @client_custom_next_assessment_date if @client_custom_next_assessment_date.present? + + ids = client_custom_assessment_setting(client) + + @client_custom_next_assessment_date = CustomAssessmentSetting.only_enable_custom_assessment.where(id: ids).map do |custom_assessment| next if client.eligible_custom_csi?(custom_assessment) client.custom_next_assessment_date(activated_at, custom_assessment&.id) end.compact + + @client_custom_next_assessment_date end def skipped_overdue_tasks?(tasks) @@ -83,7 +93,7 @@ def skipped_overdue_tasks?(tasks) end def skipped_overdue_forms?(forms, client) - skipped_forms = overdue_forms_empty?(forms) || client.user_ids.exclude?(@user.id) + skipped_forms = overdue_forms_empty?(forms) || client.users.cached_user_ids.exclude?(@user.id) skipped_forms ? true : false end @@ -91,13 +101,13 @@ def skipped_overdue_assessments?(client) skipped_assessments = nil CustomAssessmentSetting.only_enable_custom_assessment.each do |custom_assessment| if @setting.enable_custom_assessment? && @setting.enable_default_assessment - skipped_assessments = (!overdue_assessments_any?(client) && !overdue_custom_assessments_any?(client)) || client.user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) + skipped_assessments = (!overdue_assessments_any?(client) && !overdue_custom_assessments_any?(client)) || client.cached_user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) elsif @setting.enable_default_assessment - skipped_assessments = !overdue_assessments_any?(client) || client.user_ids.exclude?(@user.id) || !client.eligible_default_csi? + skipped_assessments = !overdue_assessments_any?(client) || client.cached_user_ids.exclude?(@user.id) || !client.eligible_default_csi? else - skipped_assessments = !overdue_custom_assessments_any?(client) || client.user_ids.exclude?(@user.id) || !client.eligible_custom_csi?(custom_assessment) + skipped_assessments = !overdue_custom_assessments_any?(client) || client.cached_user_ids.exclude?(@user.id) || !client.eligible_custom_csi?(custom_assessment) end - skipped_assessments = client.user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) + skipped_assessments = client.cached_user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) end if skipped_assessments @@ -121,29 +131,25 @@ def skipped_duetoday_tasks?(tasks) end def skipped_duetoday_forms?(forms, client) - skipped_forms = duetoday_forms_empty?(forms) || client.user_ids.exclude?(@user.id) + skipped_forms = duetoday_forms_empty?(forms) || client.cached_user_ids.exclude?(@user.id) skipped_forms ? true : false end def skipped_duetoday_assessments?(client) - skipped_assessments = nil + return @skipped_duetoday_assessments if @skipped_duetoday_assessments.present? + CustomAssessmentSetting.all.each do |custom_assessment| if @setting.enable_custom_assessment? && @setting.enable_default_assessment - skipped_assessments = (!duetoday_assessments_any?(client) && !duetoday_custom_assessments_any?(client)) || client.user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) + @skipped_duetoday_assessments = (!duetoday_assessments_any?(client) && !duetoday_custom_assessments_any?(client)) || client.cached_user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) elsif @setting.enable_default_assessment - skipped_assessments = !duetoday_assessments_any?(client) || client.user_ids.exclude?(@user.id) || !client.eligible_default_csi? + @skipped_duetoday_assessments = !duetoday_assessments_any?(client) || client.cached_user_ids.exclude?(@user.id) || !client.eligible_default_csi? else - skipped_assessments = !duetoday_custom_assessments_any?(client) || client.user_ids.exclude?(@user.id) || !client.eligible_custom_csi?(custom_assessment) + @skipped_duetoday_assessments = !duetoday_custom_assessments_any?(client) || client.cached_user_ids.exclude?(@user.id) || !client.eligible_custom_csi?(custom_assessment) end end - if skipped_assessments - true - elsif @assessment_params - false - else - true - end + @skipped_duetoday_assessments = !@assessment_params unless @skipped_duetoday_assessments + @skipped_duetoday_assessments end def skipped_upcoming_tasks?(tasks) @@ -158,28 +164,25 @@ def skipped_upcoming_tasks?(tasks) end def skipped_upcoming_forms?(forms, client) - skipped_forms = upcoming_forms_empty?(forms) || client.user_ids.exclude?(@user.id) + skipped_forms = upcoming_forms_empty?(forms) || client.cached_user_ids.exclude?(@user.id) skipped_forms ? true : false end def skipped_upcoming_assessments?(client) - skipped_assessments = nil - CustomAssessmentSetting.all.each do |custom_assessment| + return @skipped_upcoming_assessments if @skipped_upcoming_assessments.present? + + CustomAssessmentSetting.find_each do |custom_assessment| if @setting.enable_custom_assessment? && @setting.enable_default_assessment - skipped_assessments = (!upcoming_assessments_any?(client) && !upcoming_custom_assessments_any?(client)) || client.user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) + @skipped_upcoming_assessments = (!upcoming_assessments_any?(client) && !upcoming_custom_assessments_any?(client)) || client.cached_user_ids.exclude?(@user.id) || (!client.eligible_default_csi? && !client.eligible_custom_csi?(custom_assessment)) elsif @setting.enable_default_assessment - skipped_assessments = !upcoming_assessments_any?(client) || client.user_ids.exclude?(@user.id) || !client.eligible_default_csi? + @skipped_upcoming_assessments = !upcoming_assessments_any?(client) || client.cached_user_ids.exclude?(@user.id) || !client.eligible_default_csi? else - skipped_assessments = !upcoming_custom_assessments_any?(client) || client.user_ids.exclude?(@user.id) || !client.eligible_custom_csi?(custom_assessment) + @skipped_upcoming_assessments = !upcoming_custom_assessments_any?(client) || client.cached_user_ids.exclude?(@user.id) || !client.eligible_custom_csi?(custom_assessment) end end - if skipped_assessments - true - elsif @assessment_params - false - else - true - end + + @skipped_upcoming_assessments = !@assessment_params unless @skipped_upcoming_assessments + @skipped_upcoming_assessments end def just_sign_in? @@ -187,6 +190,6 @@ def just_sign_in? end def client_custom_assessment_setting(client) - custom_assessment_setting_ids = client.assessments.customs.map{|ca| ca.domains.pluck(:custom_assessment_setting_id ) }.flatten.uniq + custom_assessment_setting_ids = client.custom_assessment_domains.map(&:custom_assessment_setting_id).flatten.uniq end end diff --git a/app/helpers/families_helper.rb b/app/helpers/families_helper.rb index 2873059b25..44c543e52f 100644 --- a/app/helpers/families_helper.rb +++ b/app/helpers/families_helper.rb @@ -1,6 +1,6 @@ module FamiliesHelper def get_or_build_family_quantitative_free_text_cases - @quantitative_types.where(field_type: 'free_text').map do |qtt| + @quantitative_types.map do |qtt| @family.family_quantitative_free_text_cases.find_or_initialize_by(quantitative_type_id: qtt.id) end end @@ -27,6 +27,22 @@ def family_member_list(object) end end + def readable_family_quantitative_free_text_cases + @readable_family_quantitative_free_text_cases ||= @family.family_quantitative_free_text_cases.map do |qtt_free_text| + next if qtt_free_text.content.blank? + next unless quantitative_type_readable?(qtt_free_text.quantitative_type_id) + + qtt_free_text + end.compact + end + + def readable_viewable_quantitative_cases + @readable_viewable_quantitative_cases ||= @family.viewable_quantitative_cases.group_by(&:quantitative_type).map do |qtypes| + next unless quantitative_type_readable?(qtypes.first.id) + qtypes + end.compact + end + def family_clients_list(object) content_tag(:ul, class: 'family-clients-list') do object.family_members.joins(:client).each do |memeber| @@ -60,7 +76,7 @@ def family_case_history(object) def additional_columns unless Setting.cache_first.try(:hide_family_case_management_tool?) { - date_of_custom_assessments: I18n.t('datagrid.columns.date_of_custom_assessments', assessment: I18n.t('families.show.assessment')), + date_of_custom_assessments: I18n.t('datagrid.columns.date_of_family_assessment'), all_custom_csi_assessments: I18n.t('datagrid.columns.all_custom_csi_assessments', assessment: I18n.t('families.show.assessment')), assessment_completed_date: I18n.t('datagrid.columns.assessment_completed_date', assessment: I18n.t('families.show.assessment')), custom_completed_date: I18n.t('datagrid.columns.assessment_completed_date', assessment: I18n.t('families.show.assessment')), @@ -84,55 +100,60 @@ def default_family_columns_visibility(column) def map_family_field_labels { - active_families: I18n.t('datagrid.columns.families.active_families'), - active_program_stream: I18n.t('datagrid.columns.families.program_streams'), - care_plan: I18n.t('advanced_search.fields.care_plan'), - name: I18n.t('datagrid.columns.families.name'), - name_en: I18n.t('datagrid.columns.families.name_en'), - id: I18n.t('datagrid.columns.families.id'), - code: I18n.t('datagrid.columns.families.code'), - id_poor: I18n.t('datagrid.columns.families.id_poor'), - family_type: I18n.t('datagrid.columns.families.family_type'), - status: I18n.t('datagrid.columns.families.status'), - gender: I18n.t('activerecord.attributes.family_member.gender'), - date_of_birth: I18n.t('datagrid.columns.families.date_of_birth'), - follow_up_date: I18n.t('datagrid.columns.families.follow_up_date'), - case_history: I18n.t('datagrid.columns.families.case_history'), - address: I18n.t('datagrid.columns.families.address'), - phone_number: I18n.t('datagrid.columns.families.phone_number'), - significant_family_member_count: I18n.t('datagrid.columns.families.significant_family_member_count'), - male_children_count: I18n.t('datagrid.columns.families.male_children_count'), - received_by: I18n.t('datagrid.columns.families.received_by'), - received_by_id: I18n.t('datagrid.columns.families.received_by_id'), - followed_up_by_id: I18n.t('datagrid.columns.families.followed_up_by_id'), - referral_source_id: I18n.t('datagrid.columns.families.referral_source_id'), - referral_source_category_id: I18n.t('datagrid.columns.families.referral_source_category_id'), - street: I18n.t('datagrid.columns.families.street'), - house: I18n.t('datagrid.columns.families.house'), - dependable_income: I18n.t('datagrid.columns.families.dependable_income'), - male_adult_count: I18n.t('datagrid.columns.families.male_adult_count'), - household_income: I18n.t('datagrid.columns.families.household_income'), - created_at: I18n.t('advanced_search.fields.created_at'), - user_id: I18n.t('advanced_search.fields.created_by'), - contract_date: I18n.t('datagrid.columns.families.contract_date'), - initial_referral_date: I18n.t('datagrid.columns.families.initial_referral_date'), - caregiver_information: I18n.t('datagrid.columns.families.caregiver_information'), - changelog: I18n.t('datagrid.columns.families.changelogs'), - case_workers: I18n.t('datagrid.columns.families.case_worker_name'), - case_note_date: I18n.t('advanced_search.fields.case_note_date'), - case_note_type: I18n.t('advanced_search.fields.case_note_type'), - female_children_count: I18n.t('datagrid.columns.families.female_children_count'), - female_adult_count: I18n.t('datagrid.columns.families.female_adult_count'), - male_children_count: I18n.t('datagrid.columns.families.male_children_count'), - clients: I18n.t('datagrid.columns.families.clients'), - client_id: I18n.t('datagrid.columns.families.client'), - manage: I18n.t('datagrid.columns.families.manage'), - program_streams: I18n.t('datagrid.columns.families.program_streams'), - program_enrollment_date: I18n.t('datagrid.columns.clients.program_enrollment_date'), - program_exit_date: I18n.t('datagrid.columns.clients.program_exit_date'), - direct_beneficiaries: I18n.t('datagrid.columns.families.direct_beneficiaries'), - relation: I18n.t('families.family_member_fields.relation'), - member_count: I18n.t('datagrid.columns.families.member_count'), + active_families: I18n.t('datagrid.columns.families.active_families'), + no_case_note_date: I18n.t('advanced_search.fields.no_case_note_date'), + family_rejected: I18n.t('datagrid.columns.families.family_rejected'), + number_family_billable: I18n.t('datagrid.columns.families.number_family_billable'), + number_family_referred_gatekeeping: I18n.t('datagrid.columns.families.number_family_referred_gatekeeping'), + active_program_stream: I18n.t('datagrid.columns.families.program_streams'), + care_plan: I18n.t('advanced_search.fields.care_plan'), + name: I18n.t('datagrid.columns.families.name'), + name_en: I18n.t('datagrid.columns.families.name_en'), + id: I18n.t('datagrid.columns.families.id'), + code: I18n.t('datagrid.columns.families.code'), + id_poor: I18n.t('datagrid.columns.families.id_poor'), + family_type: I18n.t('datagrid.columns.families.family_type'), + status: I18n.t('datagrid.columns.families.status'), + gender: I18n.t('activerecord.attributes.family_member.gender'), + date_of_birth: I18n.t('datagrid.columns.families.date_of_birth'), + follow_up_date: I18n.t('datagrid.columns.families.follow_up_date'), + case_history: I18n.t('datagrid.columns.families.case_history'), + address: I18n.t('datagrid.columns.families.address'), + phone_number: I18n.t('datagrid.columns.families.phone_number'), + significant_family_member_count: I18n.t('datagrid.columns.families.significant_family_member_count'), + male_children_count: I18n.t('datagrid.columns.families.male_children_count'), + received_by: I18n.t('datagrid.columns.families.received_by'), + received_by_id: I18n.t('datagrid.columns.families.received_by_id'), + followed_up_by_id: I18n.t('datagrid.columns.families.followed_up_by_id'), + referral_source_id: I18n.t('datagrid.columns.families.referral_source_id'), + referral_source_category_id: I18n.t('datagrid.columns.families.referral_source_category_id'), + street: I18n.t('datagrid.columns.families.street'), + house: I18n.t('datagrid.columns.families.house'), + dependable_income: I18n.t('datagrid.columns.families.dependable_income'), + male_adult_count: I18n.t('datagrid.columns.families.male_adult_count'), + household_income: I18n.t('datagrid.columns.families.household_income'), + created_at: I18n.t('advanced_search.fields.created_at'), + user_id: I18n.t('advanced_search.fields.created_by'), + contract_date: I18n.t('datagrid.columns.families.contract_date'), + initial_referral_date: I18n.t('datagrid.columns.families.initial_referral_date'), + caregiver_information: I18n.t('datagrid.columns.families.caregiver_information'), + changelog: I18n.t('datagrid.columns.families.changelogs'), + case_workers: I18n.t('datagrid.columns.families.case_worker_name'), + case_note_date: I18n.t('advanced_search.fields.case_note_date'), + case_note_type: I18n.t('advanced_search.fields.case_note_type'), + female_children_count: I18n.t('datagrid.columns.families.female_children_count'), + female_adult_count: I18n.t('datagrid.columns.families.female_adult_count'), + clients: I18n.t('datagrid.columns.families.clients'), + client_id: I18n.t('datagrid.columns.families.client'), + manage: I18n.t('datagrid.columns.families.manage'), + program_streams: I18n.t('datagrid.columns.families.program_streams'), + program_enrollment_date: I18n.t('datagrid.columns.clients.program_enrollment_date'), + program_exit_date: I18n.t('datagrid.columns.clients.program_exit_date'), + direct_beneficiaries: I18n.t('datagrid.columns.families.direct_beneficiaries'), + relation: I18n.t('families.family_member_fields.relation'), + member_count: I18n.t('datagrid.columns.families.member_count'), + date_of_custom_assessments: I18n.t('datagrid.columns.date_of_family_assessment'), + custom_assessment_created_at: I18n.t('datagrid.columns.family_assessment_created_at'), **additional_columns, **family_address_translation } @@ -152,60 +173,16 @@ def family_address_translation(group_name = 'family') translations end - def merged_address_family(object) - current_address = [] - current_address << "#{I18n.t('datagrid.columns.families.house')} #{object.house}" if object.house.present? - current_address << "#{I18n.t('datagrid.columns.families.street')} #{object.street}" if object.street.present? - - if I18n.locale.to_s == 'km' - current_address << "#{I18n.t('datagrid.columns.families.village')} #{object.village.name_kh}" if object.village.present? - current_address << "#{I18n.t('datagrid.columns.families.commune')} #{object.commune.name_kh}" if object.commune.present? - current_address << object.district_name.split(' / ').first if object.district.present? - current_address << object.province_name.split(' / ').first if object.province.present? - current_address << 'កម្ពុជា' if Organization.current.short_name != 'brc' - - else - current_address << "#{I18n.t('datagrid.columns.families.village')} #{object.village.name_en}" if object.village.present? - current_address << "#{I18n.t('datagrid.columns.families.commune')} #{object.commune.name_en}" if object.commune.present? - current_address << object.district_name.split(' / ').last if object.district.present? - current_address << object.province_name.split(' / ').last if object.province.present? - current_address << 'Cambodia' if Organization.current.short_name != 'brc' - end - - current_address.join(', ') - end - - def merged_address_community(object) - current_address = [] - - if I18n.locale.to_s == 'km' - current_address << "#{I18n.t('datagrid.columns.families.village')} #{object.village.name_kh}" if object.village.present? - current_address << "#{I18n.t('datagrid.columns.families.commune')} #{object.commune.name_kh}" if object.commune.present? - current_address << object.district_name.split(' / ').first if object.district.present? - current_address << object.province_name.split(' / ').first if object.province.present? - current_address << 'កម្ពុជា' if Organization.current.short_name != 'brc' - - else - current_address << "#{I18n.t('datagrid.columns.families.village')} #{object.village.name_en}" if object.village.present? - current_address << "#{I18n.t('datagrid.columns.families.commune')} #{object.commune.name_en}" if object.commune.present? - current_address << object.district_name.split(' / ').last if object.district.present? - current_address << object.province_name.split(' / ').last if object.province.present? - current_address << 'Cambodia' if Organization.current.short_name != 'brc' - end - - current_address.join(', ') - end - def drop_down_relation locale = self.class.name && self.class.name[/FamilyFields/].present? ? I18n.locale.to_s : params[:locale] relationship_values = case locale - when 'km' - FamilyMember::KM_RELATIONS - when 'my' - FamilyMember::MY_RELATIONS - else - FamilyMember::EN_RELATIONS - end + when 'km' + FamilyMember::KM_RELATIONS + when 'my' + FamilyMember::MY_RELATIONS + else + FamilyMember::EN_RELATIONS + end [FamilyMember::EN_RELATIONS, relationship_values].transpose end @@ -216,13 +193,17 @@ def family_type_translation(type) end def selected_clients - @family.id ? @clients.where("current_family_id = ?", @family.id).ids : @selected_children + @family.id ? @clients.where('current_family_id = ?', @family.id).ids : @selected_children end def children_exist? @results && !@results.zero? end + def name_km_en + @family.name_en? ? "#{@family.name} - #{@family.name_en}" : "#{@family.name}" + end + def family_exit_circumstance_value @family.status == 'Accepted' ? 'Exited Family' : 'Rejected Referral' end @@ -281,8 +262,7 @@ def family_header_counter(grid, column) if count > 0 class_name = column.name.to_s [column.header.truncate(65), - content_tag(:span, count, class: 'label label-info') - ].join(' ').html_safe + content_tag(:span, count, class: 'label label-info')].join(' ').html_safe else column.header.truncate(65) end @@ -310,11 +290,11 @@ def list_family_fields def family_program_stream_name(object, rule) properties_field = 'enrollment_trackings.properties' - basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules + basic_rules = $param_rules.present? && $param_rules[:basic_rules] ? $param_rules[:basic_rules] : $param_rules return object if basic_rules.nil? - basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access - results = mapping_form_builder_param_value(basic_rules, rule) - query_string = get_query_string(results, rule, properties_field) + basic_rules = basic_rules.is_a?(Hash) ? basic_rules : JSON.parse(basic_rules).with_indifferent_access + results = mapping_form_builder_param_value(basic_rules, rule) + query_string = get_query_string(results, rule, properties_field) default_value_param = params['all_values'] if default_value_param object @@ -324,7 +304,7 @@ def family_program_stream_name(object, rule) mew_query_string = query_string.reject(&:blank?).join(" #{basic_rules[:condition]} ") program_stream_ids = mew_query_string&.scan(/program_streams\.id = (\d+)/)&.flatten || [] if program_stream_ids.size >= 2 - sql_partial = mew_query_string.gsub(/program_streams\.id = \d+/, "program_streams.id IN (#{program_stream_ids.join(", ")})") + sql_partial = mew_query_string.gsub(/program_streams\.id = \d+/, "program_streams.id IN (#{program_stream_ids.join(', ')})") # properties_result = object.includes(programmable: :program_streams).where(sql_partial).references(:program_streams).distinct properties_result = object.includes(:program_stream)..references(:program_streams).where(sql_partial) else @@ -337,7 +317,6 @@ def family_program_stream_name(object, rule) end def has_family_active_program_streams? - ProgramStream.joins(:families).group("program_streams.id, enrollments.status").having("enrollments.status = 'Active'").any? + ProgramStream.joins(:families).group('program_streams.id, enrollments.status').having("enrollments.status = 'Active'").any? end - end diff --git a/app/helpers/form_builder_helper.rb b/app/helpers/form_builder_helper.rb index 5c88fed60a..e0fc3f1787 100644 --- a/app/helpers/form_builder_helper.rb +++ b/app/helpers/form_builder_helper.rb @@ -109,13 +109,13 @@ def tracking_query_string(id, field, operator, value, type, input_type, properti "NOT(#{properties_field} -> '#{field}' ? '#{value}')" end when 'less' - "(#{properties_field} ->> '#{field}')#{'::numeric' if integer?(type) } < '#{value}' AND #{properties_field} ->> '#{field}' != ''" + "(#{properties_field} ->> '#{field}')#{'::numeric' if integer?(type)} < '#{value}' AND #{properties_field} ->> '#{field}' != ''" when 'less_or_equal' - "(#{properties_field} ->> '#{field}')#{ '::numeric' if integer?(type) } <= '#{value}' AND #{properties_field} ->> '#{field}' != ''" + "(#{properties_field} ->> '#{field}')#{'::numeric' if integer?(type)} <= '#{value}' AND #{properties_field} ->> '#{field}' != ''" when 'greater' - "(#{properties_field} ->> '#{field}')#{ '::numeric' if integer?(type) } > '#{value}' AND #{properties_field} ->> '#{field}' != ''" + "(#{properties_field} ->> '#{field}')#{'::numeric' if integer?(type)} > '#{value}' AND #{properties_field} ->> '#{field}' != ''" when 'greater_or_equal' - "(#{properties_field} ->> '#{field}')#{ '::numeric' if integer?(type) } >= '#{value}' AND #{properties_field} ->> '#{field}' != ''" + "(#{properties_field} ->> '#{field}')#{'::numeric' if integer?(type)} >= '#{value}' AND #{properties_field} ->> '#{field}' != ''" when 'contains' "#{properties_field} ->> '#{field}' ILIKE '%#{value.squish}%'" when 'not_contains' @@ -166,17 +166,9 @@ def form_builder_query_string(id, field, operator, value, type, input_type, prop when 'not_contains' "#{properties_field} ->> '#{field}' NOT ILIKE '%#{value.squish}%'" when 'is_empty' - if type == 'checkbox' - "#{properties_field} -> '#{field}' ? ''" - else - "#{properties_field} -> '#{field}' ? '' OR (#{properties_field} -> '#{field}') IS NULL" - end + "(#{properties_field} ->> '#{field}') IS NULL OR (#{properties_field} ->> '#{field}') = '' OR (#{properties_field} ->> '#{field}') = '[\"\"]'" when 'is_not_empty' - if type == 'checkbox' - "NOT(#{properties_field} -> '#{field}' ? '')" - else - "(NOT(#{properties_field} -> '#{field}' ? '') OR NOT(#{properties_field} -> '#{field}') IS NULL)" - end + "(#{properties_field} ->> '#{field}') IS NOT NULL AND (#{properties_field} ->> '#{field}') <> '' AND (#{properties_field} ->> '#{field}') <> '[\"\"]'" when 'between' "(#{properties_field} ->> '#{field}')#{ '::numeric' if integer?(type) } BETWEEN '#{value.first}' AND '#{value.last}' AND #{properties_field} ->> '#{field}' != ''" end diff --git a/app/helpers/referrals_helper.rb b/app/helpers/referrals_helper.rb index 41cb53ebfb..3cecfbe69b 100644 --- a/app/helpers/referrals_helper.rb +++ b/app/helpers/referrals_helper.rb @@ -41,5 +41,4 @@ def ngo_hash_mapping def find_repeated_referred_client(referral) Client.find_by(global_id: referral.client_global_id) end - end diff --git a/app/helpers/risk_assessment_helper.rb b/app/helpers/risk_assessment_helper.rb index 48b181e986..2a2ae5e139 100644 --- a/app/helpers/risk_assessment_helper.rb +++ b/app/helpers/risk_assessment_helper.rb @@ -178,7 +178,8 @@ def history_of_disabilities def display_level_of_risk(level_of_risk) return '' unless level_of_risk - color_hash = {'high' => 'danger', 'medium' => 'warning', 'low' => 'primary', 'no action' => 'success', 'pending_assessment' => 'default' } + + color_hash = { 'high' => 'danger', 'medium' => 'warning', 'low' => 'primary', 'no action' => 'success', 'pending_assessment' => 'default' } content_tag(:a, class: "btn btn-#{color_hash[level_of_risk]}") do level_of_risk.titleize end diff --git a/app/helpers/saved_search_helper.rb b/app/helpers/saved_search_helper.rb index 6a322cd524..f4359e3131 100644 --- a/app/helpers/saved_search_helper.rb +++ b/app/helpers/saved_search_helper.rb @@ -7,7 +7,7 @@ def prevent_load_saved_searches(advanced_search) end elsif advanced_search.program_streams.present? if !(@program_streams.map(&:id) & class_eval(advanced_search.program_streams)).empty? - link_to clients_path(save_search_params(advanced_search.search_params).merge(advanced_search_id: advanced_search.id, commit: 'commit')), class: 'btn btn-xs btn-success btn-outline dany', data: { "save-search-#{advanced_search.id}": advanced_search.queries.to_json } do + link_to url_for(["#{advanced_search.search_for.pluralize.to_sym}", polymorphic_saved_search_params(advanced_search).merge(advanced_search_id: advanced_search.id, commit: 'commit')]), class: 'btn btn-xs btn-success btn-outline dany', data: { "save-search-#{advanced_search.id}": advanced_search.queries.to_json } do fa_icon 'clipboard' end else @@ -17,7 +17,7 @@ def prevent_load_saved_searches(advanced_search) end elsif advanced_search.custom_forms.present? if !(@custom_fields.map(&:id) & class_eval(advanced_search.custom_forms)).empty? - link_to clients_path(save_search_params(advanced_search.search_params).merge(advanced_search_id: advanced_search.id, commit: 'commit')), class: 'btn btn-xs btn-success btn-outline dany', data: { "save-search-#{advanced_search.id}": advanced_search.queries.to_json } do + link_to url_for(["#{advanced_search.search_for.pluralize.to_sym}", polymorphic_saved_search_params(advanced_search).merge(advanced_search_id: advanced_search.id, commit: 'commit')]), class: 'btn btn-xs btn-success btn-outline dany', data: { "save-search-#{advanced_search.id}": advanced_search.queries.to_json } do fa_icon 'clipboard' end else @@ -39,12 +39,18 @@ def blank_save_search(advanced_search) fa_icon 'clipboard' end else - link_to clients_path(save_search_params(advanced_search.search_params).merge(advanced_search_id: advanced_search.id, commit: 'commit')), class: 'btn btn-xs btn-success btn-outline dany', data: { "save-search-#{advanced_search.id}": advanced_search.queries.to_json } do + link_to url_for(["#{advanced_search.search_for.pluralize.to_sym}", polymorphic_saved_search_params(advanced_search).merge(advanced_search_id: advanced_search.id, commit: 'commit')]), class: 'btn btn-xs btn-success btn-outline dany', data: { "save-search-#{advanced_search.id}": advanced_search.queries.to_json } do fa_icon 'clipboard' end end end + def polymorphic_saved_search_params(search) + search_params = save_search_params(search.search_params) + search_params[:family_advanced_search] = search_params.delete(:client_advanced_search) if search.try(:search_for_family?) + search_params + end + def prevent_edit_load_saved_searches(advanced_search) if advanced_search.program_streams.present? if !(@program_streams.map(&:id) & class_eval(advanced_search.program_streams)).empty? diff --git a/app/helpers/screening_assessment_helper.rb b/app/helpers/screening_assessment_helper.rb index 37d9fc01bf..df08c18336 100644 --- a/app/helpers/screening_assessment_helper.rb +++ b/app/helpers/screening_assessment_helper.rb @@ -16,4 +16,12 @@ def date_of_birth_in_words(date_of_birth, locale = :en) "No Date of Birth" end end + + def by_age_translation(developmental_marker_name) + developmental_marker_name = '1 year' if developmental_marker_name.match(/12 months/) + developmental_marker_name = '1.5 years' if developmental_marker_name.match(/18 months/) + developmental_marker_name = developmental_marker_name.downcase.gsub(" ", "_").gsub(".", "_") + + t("inline_help.cb_dmat.by_age_#{developmental_marker_name}").html_safe + end end diff --git a/app/helpers/spreadsheet_helper.rb b/app/helpers/spreadsheet_helper.rb new file mode 100644 index 0000000000..b2bdce0cdf --- /dev/null +++ b/app/helpers/spreadsheet_helper.rb @@ -0,0 +1,29 @@ +module SpreadsheetHelper + def header_format + Spreadsheet::Format.new( + horizontal_align: :center, + vertical_align: :center, + shrink: true, + border: :thin, + size: 12, + text_wrap: true + ) + end + + def column_format + Spreadsheet::Format.new( + shrink: true, + border: :thin, + size: 11 + ) + end + + def column_date_format + Spreadsheet::Format.new( + shrink: true, + border: :thin, + size: 11, + number_format: 'mmmm d, yyyy' + ) + end +end diff --git a/app/javascript/components/Addresses/IndonesianAddress.js b/app/javascript/components/Addresses/IndonesianAddress.js new file mode 100644 index 0000000000..e0f0b47475 --- /dev/null +++ b/app/javascript/components/Addresses/IndonesianAddress.js @@ -0,0 +1,309 @@ +import React, { useState, useEffect } from "react"; +import { TextInput, SelectInput, TextArea } from "../Commons/inputs"; + +export default (props) => { + const { + onChange, + disabled, + outside, + data: { + client, + objectKey, + objectData, + addressTypes, + currentProvinces, + currentCities, + currentDistricts, + subDistricts, + T + } + } = props; + + const [provinces, setProvinces] = useState( + currentProvinces.map((province) => ({ + label: province.name, + value: province.id + })) + ); + + const [cities, setCities] = useState( + currentCities.map((city) => ({ label: city.name, value: city.id })) + ); + + const [districts, setDistricts] = useState( + currentDistricts.map((district) => ({ + label: district.name, + value: district.id + })) + ); + const [subdistricts, setSubDistricts] = useState( + subDistricts.map((subDistrict) => ({ + label: subDistrict.name, + value: subDistrict.id + })) + ); + // const [referee_districts, setRefereeDistricts] = useState( + // refereeDistricts.map((district) => ({ + // label: district.name, + // value: district.id + // })) + // ); + // const [referee_subdistricts, setRefereeSubDistricts] = useState( + // refereeSubdistricts.map((subdistrict) => ({ + // label: subdistrict.name, + // value: subdistrict.id + // })) + // ); + + // const [carer_districts, setCarerDistricts] = useState( + // carerDistricts.map((district) => ({ + // label: district.name, + // value: district.id + // })) + // ); + // const [carer_subdistricts, setCarerSubdistricts] = useState( + // carerSubdistricts.map((subdistrict) => ({ + // label: subdistrict.name, + // value: subdistrict.id + // })) + // ); + + const typeOfAddress = addressTypes.map((type) => ({ + label: T.translate("addressType." + type.label), + value: type.value + })); + + useEffect(() => { + setCities( + currentCities.map((city) => ({ + label: city.name, + value: city.id + })) + ); + + setDistricts( + currentDistricts.map((district) => ({ + label: district.name, + value: district.id + })) + ); + + setSubDistricts( + subDistricts.map((subDistrict) => ({ + label: subDistrict.name && subDistrict.name, + value: subDistrict.id + })) + ); + }, [currentCities, currentDistricts, currentProvinces]); + + const updateValues = (object) => { + const { parent, child, field, obj, data } = object; + + const parentConditions = { + provinces: { + fieldsToBeUpdate: { + city_id: null, + district_id: null, + subdistrict_id: null, + [field]: data + }, + optionsToBeResets: [setCities, setDistricts, setSubDistricts] + }, + cities: { + fieldsToBeUpdate: { + district_id: null, + subdistrict_id: null, + [field]: data + }, + optionsToBeResets: [setDistricts, setSubDistricts] + }, + districts: { + fieldsToBeUpdate: { subdistrict_id: null, [field]: data }, + optionsToBeResets: [setSubDistricts] + }, + subdistricts: { + fieldsToBeUpdate: { [field]: data }, + optionsToBeResets: [] + } + }; + + onChange( + obj, + parentConditions[parent].fieldsToBeUpdate + )({ type: "select" }); + + if (data === null) + parentConditions[parent].optionsToBeResets.forEach((func) => func([])); + }; + + const onChangeParent = + (object) => + ({ data }) => { + const { parent, child, obj } = object; + + updateValues({ ...object, data }); + + if (parent !== "subdistricts" && data !== null) { + $.ajax({ + type: "GET", + url: `/api/${parent}/${data}/${child}` + }) + .success((res) => { + let dataState = {}; + const formatedData = res.data.map((data) => ({ + label: data.name, + value: data.id + })); + + dataState = { + cities: setCities, + districts: setDistricts, + subdistricts: setSubDistricts + }; + + dataState[child](formatedData); + }) + .error((res) => { + onerror(res.responseText); + }); + } + }; + + const handleDistrictOptions = (obj, district) => { + const is_district = district == "district"; + // switch (obj) { + // case "referee": + // return is_district ? referee_districts : referee_subdistricts; + // break; + // case "carer": + // return is_district ? carer_districts : carer_subdistricts; + // break; + // default: + // return is_district ? districts : subdistricts; + // } + return is_district ? districts : subdistricts; + }; + + return outside == true ? ( +