Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Soft delete timesheet entries #1801

Merged
merged 5 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ def update

def destroy
timesheet_entries = policy_scope(TimesheetEntry)
if timesheet_entries.where(id: ids_params).destroy_all
timesheet_entries_discarded = timesheet_entries.where(id: ids_params).discard_all
if timesheet_entries_discarded
render json: { notice: I18n.t("timesheet_entry.destroy.message") }
else
render json: { notice: "Some of the timesheet entries were failed to delete" }
end
end

Expand Down
4 changes: 2 additions & 2 deletions app/controllers/internal_api/v1/timesheet_entry_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def update

def destroy
authorize current_timesheet_entry
render json: { notice: I18n.t("timesheet_entry.destroy.message") } if current_timesheet_entry.destroy
render json: { notice: I18n.t("timesheet_entry.destroy.message") } if current_timesheet_entry.discard!
end

private
Expand All @@ -44,7 +44,7 @@ def current_project
end

def current_timesheet_entry
@_current_timesheet_entry ||= current_company.timesheet_entries.find(params[:id])
@_current_timesheet_entry ||= current_company.timesheet_entries.kept.find(params[:id])
end

def timesheet_entry_params
Expand Down
12 changes: 8 additions & 4 deletions app/models/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ def reindex_projects
end

def total_hours_logged(time_frame = "week")
timesheet_entries.where(work_date: DateRangeService.new(timeframe: time_frame).process)
.sum(:duration)
timesheet_entries.where(
work_date: DateRangeService.new(timeframe: time_frame).process,
discarded_at: nil
).sum(:duration)
end

def project_details(time_frame = "week")
Expand All @@ -72,8 +74,10 @@ def project_details(time_frame = "week")
name: project.name,
billable: project.billable,
team: project.project_member_full_names,
minutes_spent: project.timesheet_entries.where(work_date: DateRangeService.new(timeframe: time_frame).process)
.sum(:duration)
minutes_spent: project.timesheet_entries.where(
work_date: DateRangeService.new(timeframe: time_frame).process,
discarded_at: nil
).sum(:duration)
}
end
end
Expand Down
1 change: 0 additions & 1 deletion app/models/company.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class Company < ApplicationRecord
# Associations
has_many :employments, dependent: :destroy
has_many :users, -> { kept }, through: :employments
has_many :timesheet_entries, through: :users
has_many :clients, dependent: :destroy
has_many :projects, through: :clients, dependent: :destroy
has_many :current_workspace_users, foreign_key: "current_workspace_id", class_name: "User", dependent: :nullify
Expand Down
2 changes: 1 addition & 1 deletion app/models/concerns/project_sql_queries.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def project_members_snippet_sql(date_range)
FROM (
SELECT user_id, SUM(duration) AS total_duration
FROM timesheet_entries
WHERE project_id = #{id} AND work_date BETWEEN '#{date_range.first}' AND '#{date_range.last}'
WHERE project_id = #{id} AND discarded_at IS NULL AND work_date BETWEEN '#{date_range.first}' AND '#{date_range.last}'
GROUP BY user_id
) te
RIGHT JOIN (
Expand Down
2 changes: 1 addition & 1 deletion app/models/invoice.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def recently_sent_mail?

def update_timesheet_entry_status!
timesheet_entry_ids = invoice_line_items.pluck(:timesheet_entry_id)
TimesheetEntry.where(id: timesheet_entry_ids).update!(bill_status: :billed)
TimesheetEntry.kept.where(id: timesheet_entry_ids).update!(bill_status: :billed)
end

def create_checkout_session!(success_url:, cancel_url:)
Expand Down
6 changes: 3 additions & 3 deletions app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def project_members_snippet(time_frame)
end

def total_logged_duration(time_frame)
@_total_logged_duration = timesheet_entries.joins(
@_total_logged_duration = timesheet_entries.kept.joins(
"RIGHT JOIN project_members ON project_members.user_id = timesheet_entries.user_id"
).where(
project_members: { project_id: id },
Expand All @@ -85,7 +85,7 @@ def project_member_full_names

def overdue_and_outstanding_amounts
currency = client.company.base_currency
timesheet_entries_ids = timesheet_entries.ids
timesheet_entries_ids = timesheet_entries.kept.ids
invoices = Invoice
.joins(:invoice_line_items)
.where(
Expand All @@ -107,7 +107,7 @@ def overdue_and_outstanding_amounts
end

def minutes_spent
timesheet_entries.sum(:duration)
timesheet_entries.kept.sum(:duration)
end

private
Expand Down
32 changes: 18 additions & 14 deletions app/models/timesheet_entry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@
#
# Table name: timesheet_entries
#
# id :bigint not null, primary key
# bill_status :integer not null
# duration :float not null
# note :text default("")
# work_date :date not null
# created_at :datetime not null
# updated_at :datetime not null
# project_id :bigint not null
# user_id :bigint not null
# id :bigint not null, primary key
# bill_status :integer not null
# discarded_at :datetime
# duration :float not null
# note :text default("")
# work_date :date not null
# created_at :datetime not null
# updated_at :datetime not null
# project_id :bigint not null
# user_id :bigint not null
#
# Indexes
#
# index_timesheet_entries_on_bill_status (bill_status)
# index_timesheet_entries_on_project_id (project_id)
# index_timesheet_entries_on_user_id (user_id)
# index_timesheet_entries_on_work_date (work_date)
# index_timesheet_entries_on_bill_status (bill_status)
# index_timesheet_entries_on_discarded_at (discarded_at)
# index_timesheet_entries_on_project_id (project_id)
# index_timesheet_entries_on_user_id (user_id)
# index_timesheet_entries_on_work_date (work_date)
#
# Foreign Keys
#
Expand All @@ -28,6 +30,7 @@
#

class TimesheetEntry < ApplicationRecord
include Discard::Model
extend Pagy::Searchkick
enum bill_status: [:non_billable, :unbilled, :billed]

Expand Down Expand Up @@ -71,7 +74,8 @@ def search_data
client_name: project.client.name,
bill_status:,
duration: duration.to_i,
created_at: created_at.to_time
created_at: created_at.to_time,
discarded_at:
}
end

Expand Down
4 changes: 2 additions & 2 deletions app/policies/timesheet_entry_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ def initialize(user, scope)

def resolve
if user_owner_role? || user_admin_role?
scope = user.current_workspace.timesheet_entries
scope = user.current_workspace.timesheet_entries.kept
else
scope = user.timesheet_entries.in_workspace(user.current_workspace)
scope = user.timesheet_entries.kept.in_workspace(user.current_workspace)
end
end
end
Expand Down
26 changes: 8 additions & 18 deletions app/services/generate_invoice/new_line_items_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def process
# Sending team members list for filter dropdown options
def team_members_of_projects
@team_members_of_projects ||= User.where(
id: TimesheetEntry.where(project_id: @projects).pluck(:user_id)
id: TimesheetEntry.kept.where(project_id: @projects).pluck(:user_id)
)
end

Expand All @@ -35,27 +35,17 @@ def filtered_ids
discarded_invoice_ids = Invoice.kept.pluck(:id)
@filtered_ids ||= params[:selected_entries].to_a | InvoiceLineItem.joins(:timesheet_entry)
.where(invoice_id: discarded_invoice_ids)
.where(timesheet_entries: { bill_status: "unbilled" })
.where(timesheet_entries: { bill_status: "unbilled", discarded_at: nil })
.pluck(:timesheet_entry_id)
end

def unselected_time_entries_filter
{ id: { not: filtered_ids } }
end

def project_filter
{ project_id: @projects.pluck(:id) }
end

def unbilled_status_filter
{ bill_status: "unbilled" }
end

def where_clause
project_filter
.merge(unselected_time_entries_filter)
.merge(unbilled_status_filter)
.merge(TimeEntries::Filters.process(params))
{
project_id: @projects.pluck(:id),
id: { not: filtered_ids },
bill_status: "unbilled",
discarded_at: nil
}.merge(TimeEntries::Filters.process(params))
end

def search_term
Expand Down
2 changes: 1 addition & 1 deletion app/services/projects/search_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize(query, current_company, client_id = nil, user_id = nil, billable
end

def process
minutes_spent = @current_company.timesheet_entries.group(:project_id).sum(:duration)
minutes_spent = @current_company.timesheet_entries.kept.group(:project_id).sum(:duration)
project_list = project_list_query.ransack({ name_or_client_name_cont: @query }).result
project_ids = project_list.ids.uniq

Expand Down
2 changes: 1 addition & 1 deletion app/services/reports/time_entries/filter_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def es_filter_for_pagination
end

def set_default_pagination_data
@es_filter = { id: current_company.timesheet_entries.pluck(:id) }
@es_filter = { id: current_company.timesheet_entries.kept.pluck(:id) }
end

def team_member_filter
Expand Down
2 changes: 1 addition & 1 deletion app/services/reports/time_entries/report_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def group_by_total_duration
raise ArgumentError, "Unsupported group_by: #{group_by}"
end

grouped_durations = TimesheetEntry.where(where_conditions)
grouped_durations = TimesheetEntry.kept.where(where_conditions)
.joins(joins_clause)
.reorder("")
.group(group_field)
Expand Down
2 changes: 1 addition & 1 deletion app/services/time_tracking_index_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def format_entries
end

def fetch_timesheet_entries
user.timesheet_entries.includes([:project, :user])
user.timesheet_entries.kept.includes([:project, :user])
.in_workspace(current_company)
.during(from, to)
end
Expand Down
2 changes: 1 addition & 1 deletion app/services/weekly_reminder_for_missed_entries_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,6 @@ def send_mail(recipients:, name:, start_date:, end_date:, company_name:)
end

def get_entries_for_period(user:, company:, start_date:, end_date:)
user.timesheet_entries.in_workspace(company).during(start_date, end_date) +
user.timesheet_entries.kept.in_workspace(company).during(start_date, end_date) +
user.timeoff_entries.during(start_date, end_date)
end
10 changes: 10 additions & 0 deletions db/migrate/20240411174949_add_discarded_at_to_timesheet_entries.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class AddDiscardedAtToTimesheetEntries < ActiveRecord::Migration[7.0]
disable_ddl_transaction!

def change
add_column :timesheet_entries, :discarded_at, :datetime
add_index :timesheet_entries, :discarded_at, algorithm: :concurrently
end
end
4 changes: 3 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
it "deletes the timesheet entries for the selected ids" do
expect(response).to be_successful
expect(json_response["notice"]).to match("Timesheet deleted")
expect(TimesheetEntry.where(id: [timesheet_entry1.id, timesheet_entry2.id]).count).to eq(0)
expect(TimesheetEntry.where(id: timesheet_entry3.id).count).to eq(1)
expect(TimesheetEntry.where(id: [timesheet_entry1.id, timesheet_entry2.id]).kept.count).to eq(0)
expect(TimesheetEntry.where(id: timesheet_entry3.id).kept.count).to eq(1)
end
end
end
Loading