Chore/rename timestamp on time entry (#8754)

* rename timestamps on time entry

* add updated_at filter/order for time entries

* rename on cost entries as well

This will make handling in the cost query easier

* adapt specs

* linting

* adapt project activity

* update references to updated_on
pull/8866/head
ulferts 4 years ago committed by GitHub
parent bbd29438a0
commit 7b31311713
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      db/migrate/20201001184404_rename_timestamp_on_time_and_cost_entry.rb
  2. 379
      docs/api/apiv3/endpoints/time_entries.apib
  3. 2
      frontend/src/app/modules/fields/edit/field-types/te-work-package-edit-field.component.ts
  4. 3
      modules/costs/app/models/queries/time_entries.rb
  5. 2
      modules/costs/app/models/queries/time_entries/filters/created_at_filter.rb
  6. 35
      modules/costs/app/models/queries/time_entries/filters/updated_at_filter.rb
  7. 2
      modules/costs/app/models/queries/time_entries/orders/default_order.rb
  8. 17
      modules/costs/lib/api/v3/cost_entries/cost_entry_representer.rb
  9. 6
      modules/costs/lib/api/v3/time_entries/time_entry_representer.rb
  10. 2
      modules/costs/lib/costs/engine.rb
  11. 2
      modules/costs/spec/factories/cost_entry_factory.rb
  12. 4
      modules/costs/spec/lib/api/v3/cost_entries/cost_entry_representer_spec.rb
  13. 0
      modules/costs/spec/lib/api/v3/time_entries/schemas/time_entry_schema_representer_spec.rb
  14. 0
      modules/costs/spec/lib/api/v3/time_entries/time_entries_activity_representer_rendering_spec.rb
  15. 4
      modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_parsing_spec.rb
  16. 8
      modules/costs/spec/lib/api/v3/time_entries/time_entry_representer_rendering_spec.rb
  17. 4
      modules/costs/spec/models/queries/time_entries/filters/created_at_filter_spec.rb
  18. 50
      modules/costs/spec/models/queries/time_entries/filters/updated_at_filter_spec.rb
  19. 4
      modules/reporting/app/models/cost_query/filter/created_on.rb
  20. 4
      modules/reporting/app/models/cost_query/filter/updated_on.rb
  21. 8
      modules/reporting/app/models/cost_query/sql_statement.rb
  22. 96
      modules/reporting/spec/models/cost_query/filter_spec.rb
  23. 6
      spec/models/projects/activity_spec.rb
  24. 1
      spec/services/groups/add_users_service_integration_spec.rb
  25. 16
      spec_legacy/fixtures/time_entries.yml

@ -0,0 +1,16 @@
class RenameTimestampOnTimeAndCostEntry < ActiveRecord::Migration[6.0]
def change
alter_name_and_defaults(:time_entries)
alter_name_and_defaults(:cost_entries)
end
private
def alter_name_and_defaults(table)
rename_column table, :created_on, :created_at
rename_column table, :updated_on, :updated_at
change_column_default table, :created_at, from: nil, to: -> { 'CURRENT_TIMESTAMP' }
change_column_default table, :updated_at, from: nil, to: -> { 'CURRENT_TIMESTAMP' }
end
end

@ -33,7 +33,7 @@ Time entries are either linked to a work package or to a project. If they are li
Depending on custom fields defined for time entries, additional properties might exist.
## Time entry [/api/v3/time_entries/{id}]
## View time entry [/api/v3/time_entries/{id}]
+ Model
+ Body
@ -106,7 +106,7 @@ Depending on custom fields defined for time entries, additional properties might
+ Response 200 (application/hal+json)
[Time entry][]
[View time entry][]
+ Response 404 (application/hal+json)
@ -122,6 +122,183 @@ Depending on custom fields defined for time entries, additional properties might
"message": "The requested resource could not be found."
}
## Create time entry [/api/v3/time_entries]
## Create Time entry [POST]
Creates a new time entry applying the attributes provided in the body. Please note that while there is a fixed set of attributes, custom fields can extend a time entries' attributes and are accepted by the endpoint.
+ Request Create time entry
+ Body
{
"_links": {
"project": {
"href": "/api/v3/projects/34"
},
"activity": {
"href": "/api/v3/time_entries/activities/18"
},
"workPackage": {
"href": "/api/v3/work_packages/5"
},
"customField4": {
"href": "/api/v3/users/5"
},
"customField51": {
"href": "/api/v3/custom_options/11"
}
},
"hours": 'PT5H',
"comment": {
"raw": "Some comment"
},
"spentOn": "2017-07-28",
"customField1": {
"raw": "some text custom field value"
},
"customField8": 5
}
+ Response 201
[View time entry][]
+ Response 400 (application/hal+json)
Occurs when the client did not send a valid JSON object in the request body.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not a single JSON object."
}
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** Log time
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not authorized to access this resource."
}
+ Response 422 (application/hal+json)
Returned if:
* a constraint for a property was violated (`PropertyConstraintViolation`)
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation",
"message": "Work package is invalid.",
"_embedded": {
"details": {
"attribute": "workPackage"
}
}
}
## Update time entry [/api/v3/time_entries/{id}]
## Update Time entry [PATCH]
Updates the given time entry by applying the attributes provided in the body. Please note that while there is a fixed set of attributes, custom fields can extend a time entries' attributes and are accepted by the endpoint.
+ Parameters
+ id (required, integer, `1`) ... Time entry id
+ Request Update time entry
+ Body
{
"_links": {
"activity": {
"href": "/api/v3/time_entries/activities/18"
},
"workPackage": {
"href": "/api/v3/work_packages/5"
},
"customField4": {
"href": "/api/v3/users/5"
},
"customField51": {
"href": "/api/v3/custom_options/11"
}
},
"hours": "PT5H",
"comment": {
"raw": "Some comment"
},
"spentOn": "2017-07-28",
"customField1": {
"raw": "some text custom field value"
},
"customField8": 5
}
+ Response 200
[View time entry][]
+ Response 400 (application/hal+json)
Occurs when the client did not send a valid JSON object in the request body.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not a single JSON object."
}
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** Edit (own) time entries, depending on what time entry is being modified.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not authorized to access this resource."
}
+ Response 422 (application/hal+json)
Returned if:
* a constraint for a property was violated (`PropertyConstraintViolation`)
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation",
"message": "Work package is invalid.",
"_embedded": {
"details": {
"attribute": "workPackage"
}
}
}
## Delete time entry [/api/v3/time_entries/{id}]
## Delete time entry [DELETE]
@ -163,7 +340,7 @@ Permanently deletes the specified time entry.
}
## Time entries [/api/v3/time_entries{?offset,pageSize,filters,sortBy}]
## List time entries [/api/v3/time_entries{?offset,pageSize,filters,sortBy}]
+ Model
+ Body
@ -280,7 +457,7 @@ Permanently deletes the specified time entry.
}
}
## List Time entries [GET]
## List time entries [GET]
Lists time entries. The time entries returned depend on the filters provided and also on the permission of the requesting user.
@ -294,7 +471,8 @@ Lists time entries. The time entries returned depend on the filters provided and
+ id: Sort by primary key
+ hours: Sort by logged hours
+ spent_on: Sort by spent on date
+ created_on: Sort by time entry creation datetime
+ created_at: Sort by time entry creation datetime
+ updated_at: Sort by the time the time entry was updated last
+ filters (optional, string, `[{ "work_package": { "operator": "=", "values": ["1", "2"] } }, { "project": { "operator": "=", "values": ["1"] } }]`) ... JSON specifying filter conditions.
Accepts the same format as returned by the [queries](#queries) endpoint. Currently supported filters are:
@ -302,12 +480,13 @@ Lists time entries. The time entries returned depend on the filters provided and
+ project: Filter time entries by project
+ user: Filter time entries by users
+ spent_on: Filter time entries by spent on date
+ created_on: Filter time entries by creation datetime
+ created_at: Filter time entries by creation datetime
+ updated_at: Filter time entries by the last time they where updated
+ activity: Filter time entries by time entry activity
+ Response 200 (application/hal+json)
[Time entries][]
[List time entries][]
+ Response 400 (application/hal+json)
@ -335,180 +514,7 @@ Lists time entries. The time entries returned depend on the filters provided and
"message": "You are not authorized to view this resource."
}
## Create Time entry [POST]
Creates a new time entry applying the attributes provided in the body. Please note that while there is a fixed set of attributes, custom fields can extend a time entries' attributes and are accepted by the endpoint.
+ Parameters
+ Request Create time entry
+ Body
{
"_links": {
"project": {
"href": "/api/v3/projects/34"
},
"activity": {
"href": "/api/v3/time_entries/activities/18"
},
"workPackage": {
"href": "/api/v3/work_packages/5"
},
"customField4": {
"href": "/api/v3/users/5"
},
"customField51": {
"href": "/api/v3/custom_options/11"
}
},
"hours": 'PT5H',
"comment": {
"raw": "Some comment"
},
"spentOn": "2017-07-28",
"customField1": {
"raw": "some text custom field value"
},
"customField8": 5
}
+ Response 201
[Time entry][]
+ Response 400 (application/hal+json)
Occurs when the client did not send a valid JSON object in the request body.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not a single JSON object."
}
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** Log time
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not authorized to access this resource."
}
+ Response 422 (application/hal+json)
Returned if:
* a constraint for a property was violated (`PropertyConstraintViolation`)
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation",
"message": "Work package is invalid.",
"_embedded": {
"details": {
"attribute"=>"workPackage"
}
}
}
## Update Time entry [PATCH]
Updates the given time entry by applying the attributes provided in the body. Please note that while there is a fixed set of attributes, custom fields can extend a time entries' attributes and are accepted by the endpoint.
+ Parameters
+ Request Update time entry
+ Body
{
"_links": {
"activity": {
"href": "/api/v3/time_entries/activities/18"
},
"workPackage": {
"href": "/api/v3/work_packages/5"
},
"customField4": {
"href": "/api/v3/users/5"
},
"customField51": {
"href": "/api/v3/custom_options/11"
}
},
"hours": "PT5H",
"comment": {
"raw": "Some comment"
},
"spentOn": "2017-07-28",
"customField1": {
"raw": "some text custom field value"
},
"customField8": 5
}
+ Response 200
[Time entry][]
+ Response 400 (application/hal+json)
Occurs when the client did not send a valid JSON object in the request body.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:InvalidRequestBody",
"message": "The request body was not a single JSON object."
}
+ Response 403 (application/hal+json)
Returned if the client does not have sufficient permissions.
**Required permission:** Edit (own) time entries, depending on what time entry is being modified.
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:MissingPermission",
"message": "You are not authorized to access this resource."
}
+ Response 422 (application/hal+json)
Returned if:
* a constraint for a property was violated (`PropertyConstraintViolation`)
+ Body
{
"_type": "Error",
"errorIdentifier": "urn:openproject-org:api:v3:errors:PropertyConstraintViolation",
"message": "Work package is invalid.",
"_embedded": {
"details": {
"attribute"=>"workPackage"
}
}
}
## Time entry schema [/api/v3/time_entries/schema]
## View time entry schema [/api/v3/time_entries/schema]
+ Model
+ Body
@ -609,7 +615,7 @@ Updates the given time entry by applying the attributes provided in the body. Pl
+ Response 200 (application/hal+json)
[Time entry schema][]
[View time entry schema][]
+ Response 403 (application/hal+json)
@ -909,6 +915,9 @@ For more details and all possible responses see the general specification of [Fo
## Time entry update form [POST]
+ Parameters
+ id (required, integer, `1`) ... time entries activity id
+ Request Create time entry form
+ Body
@ -1257,7 +1266,7 @@ None
| default | Flag to signal whether this activity is the default activity | Boolean | | READ |   |
## Time entries activity [/api/v3/time_entries/activity/{id}]
## View time entries activity [/api/v3/time_entries/activity/{id}]
+ Model
+ Body
@ -1291,14 +1300,14 @@ None
}
}
## View time entries activity[GET]
## View time entries activity [GET]
+ Parameters
+ id (required, integer, `1`) ... time entries activity id
+ Response 200 (application/hal+json)
[Time entries activity][]
[View time entries activity][]
+ Response 404 (application/hal+json)

@ -87,7 +87,7 @@ export class TimeEntryWorkPackageEditFieldComponent extends WorkPackageEditField
return this
.apiV3Service
.time_entries
.list({ filters: [['user_id', '=', ['me']]], sortBy: [["updated_on", "desc"]], pageSize: RECENT_TIME_ENTRIES_MAGIC_NUMBER })
.list({ filters: [['user_id', '=', ['me']]], sortBy: [["updated_at", "desc"]], pageSize: RECENT_TIME_ENTRIES_MAGIC_NUMBER })
.toPromise()
.then(collection => {
this.recentWorkPackageIds = collection

@ -35,7 +35,8 @@ module Queries::TimeEntries
Queries::Register.filter query, Queries::TimeEntries::Filters::WorkPackageFilter
Queries::Register.filter query, Queries::TimeEntries::Filters::ProjectFilter
Queries::Register.filter query, Queries::TimeEntries::Filters::SpentOnFilter
Queries::Register.filter query, Queries::TimeEntries::Filters::CreatedOnFilter
Queries::Register.filter query, Queries::TimeEntries::Filters::CreatedAtFilter
Queries::Register.filter query, Queries::TimeEntries::Filters::UpdatedAtFilter
Queries::Register.filter query, Queries::TimeEntries::Filters::ActivityFilter
Queries::Register.order query, Queries::TimeEntries::Orders::DefaultOrder

@ -28,7 +28,7 @@
# See docs/COPYRIGHT.rdoc for more details.
#++
class Queries::TimeEntries::Filters::CreatedOnFilter < Queries::TimeEntries::Filters::TimeEntryFilter
class Queries::TimeEntries::Filters::CreatedAtFilter < Queries::TimeEntries::Filters::TimeEntryFilter
def type
:datetime_past
end

@ -0,0 +1,35 @@
#-- encoding: UTF-8
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2020 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
class Queries::TimeEntries::Filters::UpdatedAtFilter < Queries::TimeEntries::Filters::TimeEntryFilter
def type
:datetime_past
end
end

@ -32,6 +32,6 @@ class Queries::TimeEntries::Orders::DefaultOrder < Queries::BaseOrder
self.model = TimeEntry
def self.key
/\A(id|hours|spent_on|created_on|updated_on)\z/
/\A(id|hours|spent_on|created_at|updated_at)\z/
end
end

@ -31,6 +31,7 @@ module API
module CostEntries
class CostEntryRepresenter < ::API::Decorators::Single
include API::Decorators::LinkedResource
include API::Decorators::DateProperty
self_link title_getter: ->(*) { nil }
associated_resource :project
@ -44,17 +45,11 @@ module API
property :id, render_nil: true
property :units, as: :spentUnits
property :spent_on,
exec_context: :decorator,
getter: ->(*) { datetime_formatter.format_date(represented.spent_on) }
property :created_on,
as: 'createdAt',
exec_context: :decorator,
getter: ->(*) { datetime_formatter.format_datetime(represented.created_on) }
property :updated_on,
as: 'updatedAt',
exec_context: :decorator,
getter: ->(*) { datetime_formatter.format_datetime(represented.updated_on) }
date_property :spent_on
date_time_property :created_at
date_time_property :updated_at
def _type
'CostEntry'

@ -88,10 +88,8 @@ module API
datetime_formatter.format_duration_from_hours(represented.hours) if represented.hours
end
date_time_property :created_on,
as: 'createdAt'
date_time_property :updated_on,
as: 'updatedAt'
date_time_property :created_at
date_time_property :updated_at
associated_resource :project

@ -248,7 +248,7 @@ module Costs
initializer 'costs.register_latest_project_activity' do
Project.register_latest_project_activity on: 'TimeEntry',
attribute: :updated_on
attribute: :updated_at
end
config.to_prepare do

@ -35,8 +35,6 @@ FactoryBot.define do
spent_on { Date.today }
units { 1 }
comments { '' }
created_on { Time.now }
updated_on { Time.now }
before(:create) do |ce|
ce.work_package.project = ce.project

@ -83,12 +83,12 @@ describe ::API::V3::CostEntries::CostEntryRepresenter do
end
it_behaves_like 'has UTC ISO 8601 date and time' do
let(:date) { cost_entry.created_on }
let(:date) { cost_entry.created_at }
let(:json_path) { 'createdAt' }
end
it_behaves_like 'has UTC ISO 8601 date and time' do
let(:date) { cost_entry.updated_on }
let(:date) { cost_entry.updated_at }
let(:json_path) { 'updatedAt' }
end
end

@ -35,8 +35,8 @@ describe ::API::V3::TimeEntries::TimeEntryRepresenter, 'rendering' do
FactoryBot.build_stubbed(:time_entry,
comments: 'blubs',
spent_on: Date.today - 3.days,
created_on: DateTime.now - 6.hours,
updated_on: DateTime.now - 3.hours,
created_at: DateTime.now - 6.hours,
updated_at: DateTime.now - 3.hours,
activity: activity,
project: project,
user: user)

@ -35,8 +35,8 @@ describe ::API::V3::TimeEntries::TimeEntryRepresenter, 'rendering' do
FactoryBot.build_stubbed(:time_entry,
comments: 'blubs',
spent_on: Date.today,
created_on: DateTime.now - 6.hours,
updated_on: DateTime.now - 3.hours,
created_at: DateTime.now - 6.hours,
updated_at: DateTime.now - 3.hours,
hours: hours,
activity: activity,
project: project,
@ -243,11 +243,11 @@ describe ::API::V3::TimeEntries::TimeEntryRepresenter, 'rendering' do
end
it_behaves_like 'datetime property', :createdAt do
let(:value) { time_entry.created_on }
let(:value) { time_entry.created_at }
end
it_behaves_like 'datetime property', :updatedAt do
let(:value) { time_entry.updated_on }
let(:value) { time_entry.updated_at }
end
context 'custom value' do

@ -28,10 +28,10 @@
require 'spec_helper'
describe Queries::TimeEntries::Filters::CreatedOnFilter, type: :model do
describe Queries::TimeEntries::Filters::CreatedAtFilter, type: :model do
it_behaves_like 'basic query filter' do
let(:type) { :datetime_past }
let(:class_key) { :created_on }
let(:class_key) { :created_at }
describe '#available?' do
it 'is true' do

@ -0,0 +1,50 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2020 the OpenProject GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2017 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See docs/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe Queries::TimeEntries::Filters::UpdatedAtFilter, type: :model do
it_behaves_like 'basic query filter' do
let(:type) { :datetime_past }
let(:class_key) { :updated_at }
describe '#available?' do
it 'is true' do
expect(instance).to be_available
end
end
describe '#allowed_values' do
it 'is nil' do
expect(instance.allowed_values).to be_nil
end
end
it_behaves_like 'non ar filter'
end
end

@ -27,10 +27,10 @@
#++
class CostQuery::Filter::CreatedOn < Report::Filter::Base
db_field 'entries.created_on'
db_field 'entries.created_at'
use :time_operators
def self.label
WorkPackage.human_attribute_name(:created_on)
WorkPackage.human_attribute_name(:created_at)
end
end

@ -27,10 +27,10 @@
#++
class CostQuery::Filter::UpdatedOn < Report::Filter::Base
db_field 'entries.updated_on'
db_field 'entries.updated_at'
use :time_operators
def self.label
WorkPackage.human_attribute_name(:updated_on)
WorkPackage.human_attribute_name(:updated_at)
end
end

@ -29,7 +29,7 @@
class CostQuery::SqlStatement < Report::SqlStatement
COMMON_FIELDS = %w[
user_id project_id work_package_id rate_id
comments spent_on created_on updated_on tyear tmonth tweek
comments spent_on created_at updated_at tyear tmonth tweek
costs overridden_costs type
]
@ -53,7 +53,7 @@ class CostQuery::SqlStatement < Report::SqlStatement
#
# Mapping for direct fields:
#
# Result | Time Entires | Cost entries
# Result | Time Entries | Cost entries
# --------------------------|--------------------------|--------------------------
# id | id | id
# user_id | user_id | user_id
@ -62,8 +62,8 @@ class CostQuery::SqlStatement < Report::SqlStatement
# rate_id | rate_id | rate_id
# comments | comments | comments
# spent_on | spent_on | spent_on
# created_on | created_on | created_on
# updated_on | updated_on | updated_on
# created_at | created_at | created_at
# updated_at | updated_at | updated_at
# tyear | tyear | tyear
# tmonth | tmonth | tmonth
# tweek | tweek | tweek

@ -38,9 +38,9 @@ describe CostQuery, type: :model, reporting_query_helper: true do
def create_work_package_with_entry(entry_type, work_package_params={}, entry_params = {})
work_package_params = {project: project}.merge!(work_package_params)
work_package = FactoryBot.create(:work_package, work_package_params)
entry_params = {work_package: work_package,
project: work_package_params[:project],
user: user}.merge!(entry_params)
entry_params = { work_package: work_package,
project: work_package_params[:project],
user: user }.merge!(entry_params)
FactoryBot.create(entry_type, entry_params)
work_package
end
@ -79,18 +79,27 @@ describe CostQuery, type: :model, reporting_query_helper: true do
let!(:non_matching_entry) { FactoryBot.create(:cost_entry) }
let!(:object) { send(object_name) }
let!(:author) { FactoryBot.create(:user, member_in_project: project) }
let!(:work_package) { FactoryBot.create(:work_package, project: project,
author: author) }
let!(:work_package) do
FactoryBot.create(:work_package,
project: project,
author: author)
end
let!(:cost_type) { FactoryBot.create(:cost_type) }
let!(:cost_entry) { FactoryBot.create(:cost_entry, work_package: work_package,
user: user,
project: project,
cost_type: cost_type) }
let!(:cost_entry) do
FactoryBot.create(:cost_entry,
work_package: work_package,
user: user,
project: project,
cost_type: cost_type)
end
let!(:activity) { FactoryBot.create(:time_entry_activity) }
let!(:time_entry) { FactoryBot.create(:time_entry, work_package: work_package,
user: user,
project: project,
activity: activity) }
let!(:time_entry) do
FactoryBot.create(:time_entry,
work_package: work_package,
user: user,
project: project,
activity: activity)
end
it "should only return entries from the given #{filter.to_s}" do
@query.filter field, value: object.id
@ -125,18 +134,27 @@ describe CostQuery, type: :model, reporting_query_helper: true do
describe CostQuery::Filter::AuthorId do
let!(:non_matching_entry) { FactoryBot.create(:cost_entry) }
let!(:author) { FactoryBot.create(:user, member_in_project: project) }
let!(:work_package) { FactoryBot.create(:work_package, project: project,
author: author) }
let!(:work_package) do
FactoryBot.create(:work_package,
project: project,
author: author)
end
let!(:cost_type) { FactoryBot.create(:cost_type) }
let!(:cost_entry) { FactoryBot.create(:cost_entry, work_package: work_package,
user: user,
project: project,
cost_type: cost_type) }
let!(:cost_entry) do
FactoryBot.create(:cost_entry,
work_package: work_package,
user: user,
project: project,
cost_type: cost_type)
end
let!(:activity) { FactoryBot.create(:time_entry_activity) }
let!(:time_entry) { FactoryBot.create(:time_entry, work_package: work_package,
user: user,
project: project,
activity: activity) }
let!(:time_entry) do
FactoryBot.create(:time_entry,
work_package: work_package,
user: user,
project: project,
activity: activity)
end
it "should only return entries from the given CostQuery::Filter::AuthorId" do
@query.filter 'author_id', value: author.id
@ -172,16 +190,16 @@ describe CostQuery, type: :model, reporting_query_helper: true do
expect(@query.result.count).to eq(Entry.all.select { |e| e.spent_on.cweek == TimeEntry.all.first.spent_on.cweek }.count)
end
it "filters created_on" do
it "filters created_at" do
@query.filter :created_on, operator: 't'
# we assume that some of our fixtures set created_on to Time.now
expect(@query.result.count).to eq(Entry.all.select { |e| e.created_on.to_date == Date.today }.count)
# we assume that some of our fixtures set created_at to Time.now
expect(@query.result.count).to eq(Entry.all.select { |e| e.created_at.to_date == Date.today }.count)
end
it "filters updated_on" do
it "filters updated_at" do
@query.filter :updated_on, value: Date.today.years_ago(20), operator: '>d'
# we assume that our were updated in the last 20 years
expect(@query.result.count).to eq(Entry.all.select { |e| e.updated_on.to_date > Date.today.years_ago(20) }.count)
expect(@query.result.count).to eq(Entry.all.select { |e| e.updated_at.to_date > Date.today.years_ago(20) }.count)
end
it "filters user_id" do
@ -271,7 +289,6 @@ describe CostQuery, type: :model, reporting_query_helper: true do
matching_work_package = create_work_package_with_time_entry(start_date: start_date)
@query.filter :start_date, operator: '=d', value: start_date
expect(@query.result.count).to eq(1)
#Entry.all.select { |e| e.work_package.start_date == WorkPackage.all(:order => "id ASC").first.start_date }.count
end
it "filters due date" do
@ -279,7 +296,6 @@ describe CostQuery, type: :model, reporting_query_helper: true do
matching_work_package = create_work_package_with_time_entry(due_date: due_date)
@query.filter :due_date, operator: '=d', value: due_date
expect(@query.result.count).to eq(1)
#Entry.all.select { |e| e.work_package.due_date == WorkPackage.all(:order => "id ASC").first.due_date }.count
end
it "raises an error if operator is not supported" do
@ -337,15 +353,15 @@ describe CostQuery, type: :model, reporting_query_helper: true do
describe CostQuery::Filter::CustomFieldEntries do
let!(:custom_field) do
cf = FactoryBot.create(:work_package_custom_field,
name: 'My custom field')
name: 'My custom field')
clear_cache
cf
end
let(:custom_field2) do
FactoryBot.build(:work_package_custom_field, name: 'Database',
field_format: "list",
possible_values: ['value'])
field_format: "list",
possible_values: ['value'])
end
after(:all) do
@ -422,19 +438,19 @@ describe CostQuery, type: :model, reporting_query_helper: true do
def create_searchable_fields_and_values
searchable_field = FactoryBot.create(:work_package_custom_field,
field_format: "text",
name: "Searchable Field")
field_format: "text",
name: "Searchable Field")
2.times do
work_package = create_work_package_with_entry(:cost_entry)
FactoryBot.create(:work_package_custom_value,
custom_field: searchable_field,
customized: work_package,
value: "125")
custom_field: searchable_field,
customized: work_package,
value: "125")
end
work_package = create_work_package_with_entry(:cost_entry)
FactoryBot.create(:custom_value,
custom_field: searchable_field,
value: "non-matching value")
custom_field: searchable_field,
value: "non-matching value")
clear_cache
end

@ -169,12 +169,12 @@ describe Projects::Activity, type: :model do
it 'is the latest time_entry update' do
work_package.update_attribute(:updated_at, initial_time - 60.seconds)
time_entry.update_attribute(:updated_on, initial_time - 10.seconds)
time_entry2.update_attribute(:updated_on, initial_time - 20.seconds)
time_entry.update_attribute(:updated_at, initial_time - 10.seconds)
time_entry2.update_attribute(:updated_at, initial_time - 20.seconds)
time_entry.reload
time_entry2.reload
expect(latest_activity).to eql time_entry.updated_on
expect(latest_activity).to eql time_entry.updated_at
end
it 'takes the time stamp of the latest activity across models' do

@ -51,7 +51,6 @@ describe Groups::AddUsersService, 'integration', type: :model do
subject { instance.call(user_ids) }
context 'as an admin user' do
#using_shared_fixtures :admin
let(:current_user) { admin }
it 'adds the users to the group and project' do

@ -28,12 +28,12 @@
---
time_entries_001:
created_on: 2007-03-23 12:54:18 +01:00
created_at: 2007-03-23 12:54:18 +01:00
tweek: 12
tmonth: 3
project_id: 1
comments: My hours
updated_on: 2007-03-23 12:54:18 +01:00
updated_at: 2007-03-23 12:54:18 +01:00
activity_id: 9
spent_on: 2007-03-23
work_package_id: 1
@ -42,12 +42,12 @@ time_entries_001:
user_id: 2
tyear: 2007
time_entries_002:
created_on: 2007-03-23 14:11:04 +01:00
created_at: 2007-03-23 14:11:04 +01:00
tweek: 11
tmonth: 3
project_id: 1
comments: ""
updated_on: 2007-03-23 14:11:04 +01:00
updated_at: 2007-03-23 14:11:04 +01:00
activity_id: 9
spent_on: 2007-03-12
work_package_id: 1
@ -56,12 +56,12 @@ time_entries_002:
user_id: 1
tyear: 2007
time_entries_003:
created_on: 2007-04-21 12:20:48 +02:00
created_at: 2007-04-21 12:20:48 +02:00
tweek: 16
tmonth: 4
project_id: 1
comments: ""
updated_on: 2007-04-21 12:20:48 +02:00
updated_at: 2007-04-21 12:20:48 +02:00
activity_id: 9
spent_on: 2007-04-21
work_package_id: 3
@ -70,12 +70,12 @@ time_entries_003:
user_id: 1
tyear: 2007
time_entries_004:
created_on: 2007-04-22 12:20:48 +02:00
created_at: 2007-04-22 12:20:48 +02:00
tweek: 16
tmonth: 4
project_id: 3
comments: Time spent on a subproject
updated_on: 2007-04-22 12:20:48 +02:00
updated_at: 2007-04-22 12:20:48 +02:00
activity_id: 10
spent_on: 2007-04-22
work_package_id:

Loading…
Cancel
Save