erp_work_effort 4.0.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/api/v1/projects_controller.rb +25 -0
- data/app/controllers/api/v1/time_entries_controller.rb +313 -0
- data/app/controllers/api/v1/transportation_routes_controller.rb +9 -0
- data/app/controllers/api/v1/work_effort_associations_controller.rb +102 -0
- data/app/controllers/api/v1/work_effort_party_assignments_controller.rb +136 -0
- data/app/controllers/api/v1/work_effort_types_controller.rb +120 -0
- data/app/controllers/api/v1/work_efforts_controller.rb +284 -0
- data/app/models/associated_transportation_route.rb +8 -5
- data/app/models/cal_evt_party_role.rb +9 -0
- data/app/models/calendar_event.rb +46 -0
- data/app/models/calendar_invite.rb +10 -0
- data/app/models/candidate_submission.rb +37 -0
- data/app/models/experience.rb +11 -0
- data/app/models/extensions/biz_txn_events.rb +35 -0
- data/app/models/extensions/finacial_txns.rb +27 -0
- data/app/models/extensions/order_line_item.rb +12 -0
- data/app/models/extensions/party.rb +204 -0
- data/app/models/party_skill.rb +2 -0
- data/app/models/pay_period.rb +59 -0
- data/app/models/position.rb +8 -0
- data/app/models/position_fulfillment.rb +8 -0
- data/app/models/position_type.rb +12 -0
- data/app/models/project.rb +59 -0
- data/app/models/requirement.rb +2 -0
- data/app/models/resume.rb +11 -0
- data/app/models/shift.rb +22 -0
- data/app/models/skill_type.rb +8 -0
- data/app/models/staffing_position.rb +9 -0
- data/app/models/time_entry.rb +260 -0
- data/app/models/timesheet.rb +194 -0
- data/app/models/timesheet_party_role.rb +21 -0
- data/app/models/transportation_route.rb +103 -18
- data/app/models/transportation_route_segment.rb +44 -0
- data/app/models/transportation_route_stop.rb +19 -0
- data/app/models/wc_code.rb +7 -0
- data/app/models/work_effort.rb +512 -30
- data/app/models/work_effort_association.rb +7 -0
- data/app/models/work_effort_association_type.rb +5 -0
- data/app/models/work_effort_biz_txn_event.rb +22 -0
- data/app/models/work_effort_party_assignment.rb +140 -3
- data/app/models/work_effort_type.rb +5 -0
- data/config/routes.rb +54 -11
- data/db/data_migrations/20150709053041_add_skill_types.rb +27 -0
- data/db/data_migrations/20150709055922_add_position_types.rb +27 -0
- data/db/data_migrations/20150711220000_add_task_tracked_statuses.rb +25 -0
- data/db/data_migrations/20150712081804_add_work_effort_types.rb +23 -0
- data/db/data_migrations/20150718052204_add_project_tracked_statuses.rb +24 -0
- data/db/data_migrations/20150718054404_add_project_party_role_types.rb +14 -0
- data/db/data_migrations/20150812150320_add_work_effort_dependency_types.rb +35 -0
- data/db/migrate/20100220000000_base_work_efforts.rb +310 -89
- data/db/migrate/20150227174108_create_staffing_positions.rb +11 -0
- data/db/migrate/20150305194158_create_wc_codes.rb +24 -0
- data/db/migrate/20150313134411_create_shifts.rb +28 -0
- data/db/migrate/20150325195749_create_candidate_submissions.rb +22 -0
- data/db/migrate/20150327115910_resumes.rb +15 -0
- data/db/migrate/20150401060938_add_resume_parser_statuses.rb +14 -0
- data/db/migrate/20150607181734_create_calendar_events.rb +24 -0
- data/db/migrate/20150616174228_create_cal_evt_party_roles.rb +19 -0
- data/db/migrate/20150707164520_create_calendar_invites.rb +21 -0
- data/db/migrate/20150718052404_create_projects.rb +20 -0
- data/db/migrate/20150812191812_update_work_efforts.rb +59 -0
- data/db/migrate/20150824152639_add_sequence_to_work_effort.rb +9 -0
- data/db/migrate/20150830133951_add_work_effort_biz_txn_events.rb +21 -0
- data/db/migrate/20150908200612_update_time_entries.rb +70 -0
- data/db/migrate/20151115180427_add_defaults_for_work_effort.rb +36 -0
- data/db/migrate/20151218195330_update_transportation_routes.rb +72 -0
- data/db/migrate/20160310163052_add_created_by_updated_by_to_erp_work_effort.rb +63 -0
- data/db/migrate/20160418115227_add_created_by_updated_by_to_skill_type.rb +34 -0
- data/lib/erp_work_effort.rb +3 -0
- data/lib/erp_work_effort/config.rb +33 -0
- data/lib/erp_work_effort/engine.rb +0 -4
- data/lib/erp_work_effort/services/unit_converter.rb +284 -0
- data/lib/erp_work_effort/version.rb +1 -1
- data/lib/tasks/populate_model_data.rake +19 -0
- data/lib/tasks/resume_parser.rake +18 -0
- metadata +80 -16
- data/app/controllers/erp_work_effort/erp_app/organizer/tasks/base_controller.rb +0 -13
- data/app/controllers/erp_work_effort/erp_app/organizer/tasks/work_efforts_controller.rb +0 -128
- data/db/data_migrations/20131213151309_create_tasks_organizer_application.rb +0 -14
- data/db/migrate/20130829153419_base_routes.rb +0 -93
- data/db/migrate/20131213140617_add_work_effort_role_assignments.rb +0 -16
- data/db/migrate/20131213144223_add_work_item_to_work_effort.rb +0 -8
- data/db/migrate/20140106184615_update_work_effort_item_id_to_int.rb +0 -27
@@ -13,4 +13,11 @@ class WorkEffortAssociation < ActiveRecord::Base
|
|
13
13
|
belongs_to :from_role, :class_name => "RoleType", :foreign_key => "role_type_id_from"
|
14
14
|
belongs_to :to_role, :class_name => "RoleType", :foreign_key => "role_type_id_to"
|
15
15
|
|
16
|
+
def to_data_hash
|
17
|
+
to_hash({
|
18
|
+
only: [:id, :work_effort_id_from, :work_effort_id_to, :created_at, :updated_at],
|
19
|
+
work_effort_association_type: try(:work_effort_association_type).try(:to_data_hash)
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
16
23
|
end
|
@@ -6,9 +6,14 @@
|
|
6
6
|
class WorkEffortAssociationType < ActiveRecord::Base
|
7
7
|
attr_protected :created_at, :updated_at
|
8
8
|
|
9
|
+
acts_as_erp_type
|
9
10
|
acts_as_nested_set
|
10
11
|
include ErpTechSvcs::Utils::DefaultNestedSetMethods
|
11
12
|
|
12
13
|
has_many :work_effort_associations
|
13
14
|
|
15
|
+
def to_data_hash
|
16
|
+
to_hash only: [:id, :description, :internal_identifier, :external_identifier, :created_at, :updated_at]
|
17
|
+
end
|
18
|
+
|
14
19
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#### Table Definition ###########################
|
2
|
+
# create_table :work_effort_biz_txn_events do |t|
|
3
|
+
# t.references :work_effort
|
4
|
+
# t.references :biz_txn_event
|
5
|
+
#
|
6
|
+
# t.timestamps
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
# add_index :work_effort_biz_txn_events, :biz_txn_event_id, name: 'bzt_we_biz_txn_event_idx'
|
10
|
+
# add_index :work_effort_biz_txn_events, :work_effort_id, name: 'bzt_we_work_effort_idx'
|
11
|
+
#################################################
|
12
|
+
|
13
|
+
class WorkEffortBizTxnEvent < ActiveRecord::Base
|
14
|
+
attr_protected :created_at, :updated_at
|
15
|
+
|
16
|
+
belongs_to :work_effort
|
17
|
+
belongs_to :biz_txn_event
|
18
|
+
|
19
|
+
validates :work_effort_id, presence: true
|
20
|
+
validates :biz_txn_event_id, presence: true
|
21
|
+
|
22
|
+
end
|
@@ -3,10 +3,147 @@
|
|
3
3
|
## work_effort_party_assignments
|
4
4
|
## this is straight entity_party_role pattern with from and thru dates, but we are keeping
|
5
5
|
## the DMRB name for this entity.
|
6
|
+
|
7
|
+
# creat e_table :work_effort_party_assignments do |t|
|
8
|
+
# foreign key references
|
9
|
+
# t.references :work_effort
|
10
|
+
# t.references :role_type
|
11
|
+
# t.references :party
|
12
|
+
#
|
13
|
+
# t.datetime :assigned_from
|
14
|
+
# t.datetime :assigned_thru
|
15
|
+
#
|
16
|
+
# t.text :comments
|
17
|
+
#
|
18
|
+
# t.integer :resource_allocation
|
19
|
+
#
|
20
|
+
# t.timestamps
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# add_index :work_effort_party_assignments, :assigned_from
|
24
|
+
# add_index :work_effort_party_assignments, :assigned_thru
|
25
|
+
# add_index :work_effort_party_assignments, :work_effort_id
|
26
|
+
# add_index :work_effort_party_assignments, :party_id
|
27
|
+
|
6
28
|
class WorkEffortPartyAssignment < ActiveRecord::Base
|
7
29
|
attr_protected :created_at, :updated_at
|
8
30
|
|
9
|
-
belongs_to
|
10
|
-
belongs_to
|
11
|
-
belongs_to
|
31
|
+
belongs_to :work_effort
|
32
|
+
belongs_to :party
|
33
|
+
belongs_to :role_type
|
34
|
+
|
35
|
+
has_tracked_status
|
36
|
+
tracks_created_by_updated_by
|
37
|
+
|
38
|
+
class << self
|
39
|
+
|
40
|
+
# Filter records
|
41
|
+
#
|
42
|
+
# @param filters [Hash] a hash of filters to be applied,
|
43
|
+
# @param statement [ActiveRecord::Relation] the query being built
|
44
|
+
# @return [ActiveRecord::Relation] the query being built
|
45
|
+
def apply_filters(filters, statement)
|
46
|
+
# filter by project
|
47
|
+
unless filters[:project_id].blank?
|
48
|
+
statement = statement.scope_by_project(filters[:project_id])
|
49
|
+
end
|
50
|
+
|
51
|
+
# filter by work_effort
|
52
|
+
unless filters[:work_effort_id].blank?
|
53
|
+
statement = statement.scope_by_work_effort(filters[:work_effort_id])
|
54
|
+
end
|
55
|
+
|
56
|
+
# filter by status
|
57
|
+
unless filters[:status].blank?
|
58
|
+
statement = statement.with_current_status(filters[:status].split(','))
|
59
|
+
end
|
60
|
+
|
61
|
+
# filter by parties
|
62
|
+
unless filters[:parties].blank?
|
63
|
+
data = JSON.parse(filters[:parties])
|
64
|
+
|
65
|
+
statement = statement.scope_by_party(data['party_ids'].split(','),
|
66
|
+
{role_types: RoleType.where('internal_identifier' => data['role_types'].split(','))})
|
67
|
+
end
|
68
|
+
|
69
|
+
statement
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# scoping helpers
|
74
|
+
#
|
75
|
+
|
76
|
+
# scope by dba organization
|
77
|
+
#
|
78
|
+
# @param dba_organization [Party] dba organization to scope by
|
79
|
+
#
|
80
|
+
# @return [ActiveRecord::Relation]
|
81
|
+
def scope_by_dba_organization(dba_organization)
|
82
|
+
scope_by_party(dba_organization, {role_types: ['dba_org']})
|
83
|
+
end
|
84
|
+
|
85
|
+
alias scope_by_dba scope_by_dba_organization
|
86
|
+
|
87
|
+
# scope by project
|
88
|
+
#
|
89
|
+
# @param project [Integer | Project | Array] either a id of Project record, a Project record, an array of Project records
|
90
|
+
# or an array of Project ids
|
91
|
+
#
|
92
|
+
# @return [ActiveRecord::Relation]
|
93
|
+
def scope_by_project(project)
|
94
|
+
joins(:work_effort).where('work_efforts.project_id' => project)
|
95
|
+
end
|
96
|
+
|
97
|
+
# scope by work_effort
|
98
|
+
#
|
99
|
+
# @param work_effort [Integer | WorkEffort | Array] either a id of WorkEffort record, a WorkEffort record, an array of WorkEffort records
|
100
|
+
# or an array of WorkEffort ids
|
101
|
+
#
|
102
|
+
# @return [ActiveRecord::Relation]
|
103
|
+
def scope_by_work_effort(work_effort)
|
104
|
+
where('work_effort_id' => work_effort)
|
105
|
+
end
|
106
|
+
|
107
|
+
# scope by party
|
108
|
+
#
|
109
|
+
# @param party [Integer | Party | Array] either a id of Party record, a Party record, an array of Party records
|
110
|
+
# or an array of Party ids
|
111
|
+
# @param options [Hash] options to apply to this scope
|
112
|
+
# @option options [Array] :role_types role types to include in the scope
|
113
|
+
#
|
114
|
+
# @return [ActiveRecord::Relation]
|
115
|
+
def scope_by_party(party, options={})
|
116
|
+
table_alias = String.random
|
117
|
+
|
118
|
+
statement = joins(:work_effort)
|
119
|
+
|
120
|
+
if options[:role_types]
|
121
|
+
statement = statement.joins("inner join entity_party_roles as #{table_alias} on #{table_alias}.entity_record_type = 'WorkEffort'
|
122
|
+
and #{table_alias}.entity_record_id = work_efforts.id and
|
123
|
+
#{table_alias}.role_type_id in (#{RoleType.find_child_role_types(options[:role_types]).collect(&:id).join(',')})
|
124
|
+
and #{table_alias}.party_id in (#{Party.select('id').where(id: party).to_sql})")
|
125
|
+
|
126
|
+
else
|
127
|
+
statement = statement.joins("inner join entity_party_roles as #{table_alias} on #{table_alias}.entity_record_type = 'WorkEffort'
|
128
|
+
and #{table_alias}.entity_record_id = work_efforts.id
|
129
|
+
and #{table_alias}.party_id in (#{Party.select('id').where(id: party).to_sql})")
|
130
|
+
end
|
131
|
+
|
132
|
+
statement
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# converts this record a hash data representation
|
137
|
+
#
|
138
|
+
# @return [Hash] data of record
|
139
|
+
def to_data_hash
|
140
|
+
data = to_hash(only: [:id, :resource_allocation])
|
141
|
+
|
142
|
+
data[:status] = self.try(:current_status_application).try(:to_data_hash)
|
143
|
+
data[:party] = self.try(:party).try(:to_data_hash)
|
144
|
+
data[:work_effort] = self.try(:work_effort).try(:to_data_hash)
|
145
|
+
|
146
|
+
data
|
147
|
+
end
|
148
|
+
|
12
149
|
end
|
@@ -1,9 +1,14 @@
|
|
1
1
|
class WorkEffortType < ActiveRecord::Base
|
2
2
|
attr_protected :created_at, :updated_at
|
3
3
|
|
4
|
+
acts_as_erp_type
|
4
5
|
acts_as_nested_set
|
5
6
|
include ErpTechSvcs::Utils::DefaultNestedSetMethods
|
6
7
|
|
7
8
|
has_many :work_efforts
|
8
9
|
|
10
|
+
def to_data_hash
|
11
|
+
to_hash only: [:id, :description, :internal_identifier, :created_at, :updated_at]
|
12
|
+
end
|
13
|
+
|
9
14
|
end
|
data/config/routes.rb
CHANGED
@@ -1,22 +1,65 @@
|
|
1
|
-
|
1
|
+
Rails.application.routes.draw do
|
2
2
|
|
3
|
-
namespace :
|
4
|
-
namespace :
|
5
|
-
namespace :tasks do
|
3
|
+
namespace :api do
|
4
|
+
namespace :v1 do
|
6
5
|
|
7
|
-
|
6
|
+
# projects and its nested resources
|
7
|
+
resources :projects, :defaults => {:format => 'json'} do
|
8
|
+
resources :work_efforts, :defaults => {:format => 'json'}
|
9
|
+
resources :work_effort_party_assignments, :defaults => {:format => 'json'}
|
10
|
+
resources :work_effort_associations, :defaults => {:format => 'json'}
|
11
|
+
end
|
8
12
|
|
13
|
+
# work efforts and its nested resources
|
14
|
+
resources :work_efforts, :defaults => {:format => 'json'} do
|
15
|
+
member do
|
16
|
+
get :time_entries_allowed
|
17
|
+
end
|
18
|
+
|
19
|
+
resources :work_effort_party_assignments, :defaults => {:format => 'json'}
|
20
|
+
resources :time_entries, :defaults => {:format => 'json'} do
|
21
|
+
collection do
|
22
|
+
post :start
|
23
|
+
get :totals
|
24
|
+
get :open
|
25
|
+
end
|
26
|
+
|
27
|
+
member do
|
28
|
+
put :stop
|
29
|
+
end
|
30
|
+
end
|
31
|
+
resources :transportation_routes, :defaults => {:format => 'json'} do
|
9
32
|
collection do
|
10
|
-
|
11
|
-
get :
|
12
|
-
get :task_count
|
33
|
+
post :start
|
34
|
+
get :open
|
13
35
|
end
|
14
36
|
|
37
|
+
member do
|
38
|
+
put :stop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
resources :work_effort_party_assignments, :defaults => {:format => 'json'}
|
44
|
+
resources :work_effort_associations, :defaults => {:format => 'json'}
|
45
|
+
|
46
|
+
# types
|
47
|
+
resources :work_effort_types, :defaults => {:format => 'json'}
|
48
|
+
|
49
|
+
# time entries
|
50
|
+
resources :time_entries, :defaults => {:format => 'json'} do
|
51
|
+
collection do
|
52
|
+
post :start
|
53
|
+
get :totals
|
54
|
+
get :open
|
55
|
+
end
|
15
56
|
|
57
|
+
member do
|
58
|
+
put :stop
|
16
59
|
end
|
60
|
+
end
|
17
61
|
|
18
|
-
|
19
|
-
|
20
|
-
end #erp_app
|
62
|
+
end
|
63
|
+
end
|
21
64
|
|
22
65
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class AddSkillTypes
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
%w{programming project_management program_management business_development
|
5
|
+
business_analysis infrastructure_engineering network_operations web_design
|
6
|
+
mobile_design mobile_development quality_assurance uncategorized
|
7
|
+
}.each do |skill_type|
|
8
|
+
unless SkillType.iid(skill_type)
|
9
|
+
SkillType.create(
|
10
|
+
description: skill_type.titleize,
|
11
|
+
internal_identifier: skill_type
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
%w{programming project_management program_management business_development
|
19
|
+
business_analysis infrastructure_engineering network_operations web_design
|
20
|
+
mobile_design mobile_development quality_assurance uncategorized
|
21
|
+
}.each do |skill_type|
|
22
|
+
existing_skill_type = SkillType.iid(skill_type)
|
23
|
+
existing_skill_type.destroy if existing_skill_type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class AddPositionTypes
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
%w{executive_management software_developer infrastructure_engineer project_manager
|
5
|
+
program_manager network_operations_manager network_engineer
|
6
|
+
quality_assurance_teste uncategorized
|
7
|
+
}.each do |position_type|
|
8
|
+
unless PositionType.iid(position_type)
|
9
|
+
PositionType.create(
|
10
|
+
description: position_type.titleize,
|
11
|
+
internal_identifier: position_type
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
%w{executive_management software_developer infrastructure_engineer project_manager
|
19
|
+
program_manager network_operations_manager network_engineer
|
20
|
+
quality_assurance_teste uncategorized
|
21
|
+
}.each do |position_type|
|
22
|
+
existing_position_type = PositionType.iid(position_type)
|
23
|
+
existing_position_type.destroy if existing_position_type
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class AddTaskTrackedStatuses
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
|
5
|
+
task_statuses = TrackedStatusType.create(internal_identifier: 'task_statuses', description: 'Task Statuses')
|
6
|
+
|
7
|
+
[
|
8
|
+
['task_status_not_started', 'Not Started'],
|
9
|
+
['task_status_in_progress', 'In Progress'],
|
10
|
+
['task_status_complete', 'Complete'],
|
11
|
+
['task_status_hold', 'Hold'],
|
12
|
+
['task_status_canceled', 'Cancelled']
|
13
|
+
].each do |data|
|
14
|
+
status = TrackedStatusType.create(internal_identifier: data[0], description: data[1])
|
15
|
+
status.move_to_child_of(task_statuses)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.down
|
21
|
+
task_statuses = TrackedStatusType.find_by_internal_identifier('task_statuses')
|
22
|
+
task_statuses.destroy
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class AddWorkEffortTypes
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
%w{ bug_fix enhancement design business_development system_admin business_admin
|
5
|
+
}.each do |type|
|
6
|
+
unless WorkEffortType.iid(type)
|
7
|
+
WorkEffortType.create(
|
8
|
+
description: type.titleize,
|
9
|
+
internal_identifier: type
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.down
|
16
|
+
%w{ bug_fix enhancement design business_development system_admin business_admin
|
17
|
+
}.each do |type|
|
18
|
+
existing_type = WorkEffortType.iid(type)
|
19
|
+
existing_type.destroy if existing_type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class AddProjectTrackedStatuses
|
2
|
+
|
3
|
+
def self.up
|
4
|
+
|
5
|
+
project_statuses = TrackedStatusType.create(internal_identifier: 'project_statuses', description: 'Project Statuses')
|
6
|
+
|
7
|
+
[
|
8
|
+
['active', 'Active'],
|
9
|
+
['hold', 'Hold'],
|
10
|
+
['completed', 'Completed'],
|
11
|
+
['canceled', 'Cancelled']
|
12
|
+
].each do |data|
|
13
|
+
status = TrackedStatusType.create(internal_identifier: data[0], description: data[1])
|
14
|
+
status.move_to_child_of(project_statuses)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
project_statuses = TrackedStatusType.find_by_internal_identifier('project_statuses')
|
21
|
+
project_statuses.destroy
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# This migration comes from erp_work_effort (originally 20150718054404)
|
2
|
+
class AddProjectPartyRoleTypes
|
3
|
+
|
4
|
+
def self.up
|
5
|
+
RoleType.find_or_create("project_assignee", "Project Assignee", RoleType.iid("application_composer"))
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
project_role_type = RoleType.find_or_create("project_assignee", "Project", RoleType.iid("application_composer"))
|
10
|
+
project_role_type.destroy
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|