diff --git a/.env.sample b/.env.sample index 548350fb..2d0924f7 100644 --- a/.env.sample +++ b/.env.sample @@ -2,6 +2,7 @@ SECRET_KEY_BASE= SENTRY_KEY= SENDGRID_API_KEY= HTTP_HOST=localhost:3000 +RAILS_FORCE_SSL=false RAILS_LOG_LEVEL= WEB_PORT=3000 REDIS_PORT=6379 diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index 9b911ea3..86662451 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -3,12 +3,7 @@ module V1 class ReportsController < BaseController def index authorize! - scope = authorized_scope(TimeReg, type: :relation) - scope = scope.between_dates(params[:start_date], params[:end_date]) if params[:start_date] && params[:end_date] - scope = scope.by_clients(params[:client_ids]) if params[:client_ids] - scope = scope.by_projects(params[:project_ids]) if params[:project_ids] - scope = scope.by_users(params[:user_ids]) if params[:user_ids] - scope = scope.by_tasks(params[:task_ids]) if params[:task_ids] + scope = filtered_scope @total_minutes = scope.sum(:minutes) @total_entries = scope.count @@ -23,6 +18,30 @@ def index .group("users.id", "users.first_name", "users.last_name") .select("users.id AS user_id, users.first_name, users.last_name, SUM(time_regs.minutes) AS total_minutes, COUNT(time_regs.id) AS total_entries") end + + def detailed + authorize! + entries = filtered_scope + .includes(:user, assigned_task: [ :task, { project: :client } ]) + .order(date_worked: :desc, created_at: :desc) + .to_a + + @total_minutes = entries.sum(&:minutes) + @total_billable_minutes = entries.select { |tr| tr.assigned_task.project&.billable }.sum(&:minutes) + @entries_by_date = entries.group_by(&:date_worked) + end + + private + + def filtered_scope + scope = authorized_scope(TimeReg, type: :relation) + scope = scope.between_dates(params[:start_date], params[:end_date]) if params[:start_date] && params[:end_date] + scope = scope.by_clients(params[:client_ids]) if params[:client_ids] + scope = scope.by_projects(params[:project_ids]) if params[:project_ids] + scope = scope.by_users(params[:user_ids]) if params[:user_ids] + scope = scope.by_tasks(params[:task_ids]) if params[:task_ids] + scope + end end end end diff --git a/app/views/api/v1/reports/detailed.json.jbuilder b/app/views/api/v1/reports/detailed.json.jbuilder new file mode 100644 index 00000000..bbb76d25 --- /dev/null +++ b/app/views/api/v1/reports/detailed.json.jbuilder @@ -0,0 +1,24 @@ +json.total_minutes @total_minutes +json.total_billable_minutes @total_billable_minutes + +json.dates @entries_by_date do |date, time_regs| + json.date date + json.time_regs time_regs do |time_reg| + assigned_task = time_reg.assigned_task + project = assigned_task.project + + json.id time_reg.id + json.date_worked time_reg.date_worked + json.minutes time_reg.minutes + json.notes time_reg.notes + json.user_id time_reg.user_id + json.user_name time_reg.user.name + json.client_name project.client&.name + json.project_id project&.id + json.project_name project&.name + json.project_billable project&.billable + json.task_name assigned_task.task&.name + json.rate assigned_task.rate.positive? ? assigned_task.rate : project.rate + json.billed_amount time_reg.billed_amount + end +end diff --git a/config/environments/production.rb b/config/environments/production.rb index 81d532a4..82318356 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -50,7 +50,7 @@ # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - config.force_ssl = true + config.force_ssl = ENV.fetch("RAILS_FORCE_SSL", "true") == "true" # Log to STDOUT by default config.logger = ActiveSupport::Logger.new(STDOUT) diff --git a/config/routes.rb b/config/routes.rb index fd5134ea..97c75442 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,7 +31,9 @@ get :me, on: :collection end resource :api_token, only: :update - resources :reports, only: %i[index] + resources :reports, only: %i[index] do + get :detailed, on: :collection + end end end diff --git a/docker-compose.yml b/docker-compose.yml index 05855abd..1e8509b6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,11 +34,15 @@ services: condition: service_healthy redis: condition: service_started + env_file: + - path: .env + required: false environment: RAILS_ENV: production DATABASE_URL: postgres://postgres:postgres@db:5432/stemplin_development REDIS_URL: redis://redis:6379/0 SECRET_KEY_BASE: ${SECRET_KEY_BASE:-change_this_to_a_secure_secret_key} + HTTP_HOST: ${HTTP_HOST:-localhost:3000} stdin_open: true tty: true @@ -52,11 +56,15 @@ services: condition: service_healthy redis: condition: service_started + env_file: + - path: .env + required: false environment: RAILS_ENV: production DATABASE_URL: postgres://postgres:postgres@db:5432/stemplin_development REDIS_URL: redis://redis:6379/0 SECRET_KEY_BASE: ${SECRET_KEY_BASE:-change_this_to_a_secure_secret_key} + HTTP_HOST: ${HTTP_HOST:-localhost:3000} volumes: postgres_data: diff --git a/test/controllers/api/v1/reports_controller_test.rb b/test/controllers/api/v1/reports_controller_test.rb index a544856b..0a6c2e40 100644 --- a/test/controllers/api/v1/reports_controller_test.rb +++ b/test/controllers/api/v1/reports_controller_test.rb @@ -23,4 +23,35 @@ class Api::V1::ReportsControllerTest < Api::V1::BaseTest ), headers: api_headers(@user) assert_response :success end + + test "detailed returns entries grouped by date" do + get detailed_api_v1_reports_path, headers: api_headers(@user) + assert_response :success + + assert json_response.key?("total_minutes") + assert json_response.key?("total_billable_minutes") + assert json_response.key?("dates") + + first_date_group = json_response["dates"].first + assert first_date_group.key?("date") + assert first_date_group.key?("time_regs") + + entry = first_date_group["time_regs"].first + assert entry.key?("id") + assert entry.key?("minutes") + assert entry.key?("user_name") + assert entry.key?("client_name") + assert entry.key?("project_name") + assert entry.key?("task_name") + assert entry.key?("rate") + assert entry.key?("billed_amount") + end + + test "detailed filters by date range" do + get detailed_api_v1_reports_path( + start_date: 1.week.ago.to_date.to_s, + end_date: Date.today.to_s + ), headers: api_headers(@user) + assert_response :success + end end