Skip to content

Commit a25c708

Browse files
committed
[#68705] When project is copied, work packages with empty mandatory custom fields are not copied
https://community.openproject.org/work_packages/68705
1 parent 8fc651f commit a25c708

File tree

2 files changed

+57
-28
lines changed

2 files changed

+57
-28
lines changed

app/contracts/work_packages/copy_project_contract.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ class CopyProjectContract < CopyContract
4242
delegate :to_s,
4343
to: :model
4444

45+
def validate_model? = false
46+
4547
private
4648

4749
def validate_version_is_assignable; end

spec/workers/copy_project_job_spec.rb

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -31,38 +31,31 @@
3131
require "spec_helper"
3232

3333
RSpec.describe CopyProjectJob, type: :model, with_good_job_batches: [CopyProjectJob, SendCopyProjectStatusEmailJob] do
34+
shared_let(:admin) { create(:admin) }
35+
shared_let(:user_de) { create(:admin, language: :de) }
3436
let(:params) { { name: "Copy", identifier: "copy" } }
35-
let(:user_de) { create(:admin, language: :de) }
3637
let(:mail_double) { double("Mail::Message", deliver: true) } # rubocop:disable RSpec/VerifiedDoubles
3738

3839
before { allow(mail_double).to receive(:deliver_later) }
3940

4041
describe "copy project succeeds with errors" do
41-
let(:admin) { create(:admin) }
4242
let(:source_project) { create(:project, types: [type]) }
4343

44-
let!(:work_package) { create(:work_package, project: source_project, type:) }
44+
let!(:work_package) { create(:work_package, :skip_validations, done_ratio: 101, project: source_project, type:) }
4545

4646
let(:type) { create(:type_bug) }
47-
let(:custom_field) do
48-
create(:work_package_custom_field, name: "required_field", field_format: "text", is_required: true, is_for_all: true)
49-
end
50-
5147
let(:job_args) do
5248
{
5349
target_project_params: params,
5450
associations_to_copy: [:work_packages]
5551
}
5652
end
5753

58-
let(:params) { { name: "Copy", identifier: "copy", type_ids: [type.id], work_package_custom_field_ids: [custom_field.id] } }
54+
let(:params) { { name: "Copy", identifier: "copy", type_ids: [type.id] } }
5955
let(:expected_error_message) do
60-
"#{WorkPackage.model_name.human} '#{work_package.type.name} ##{work_package.id}: #{work_package.subject}': #{custom_field.name} #{I18n.t('errors.messages.blank')}."
61-
end
62-
63-
before do
64-
source_project.work_package_custom_fields << custom_field
65-
type.custom_fields << custom_field
56+
"#{WorkPackage.model_name.human} '#{work_package.type.name} ##{work_package.id}: " \
57+
"#{work_package.subject}': % Complete " \
58+
"#{I18n.t('activerecord.errors.models.work_package.attributes.done_ratio.inclusion')}"
6659
end
6760

6861
it "copies the project", :aggregate_failures do
@@ -94,13 +87,59 @@
9487
GoodJob.perform_inline
9588
batch.reload
9689

97-
msg = /Arbeitspaket 'Bug #\d+: WorkPackage No. \d+': required_field muss ausgefüllt werden\./
90+
msg = /Arbeitspaket 'Bug #\d+: WorkPackage No. \d+': % abgeschlossen muss zwischen 0 und 100 liegen\./
9891
expect(batch.properties[:errors].first).to match(msg)
9992
end
10093
end
10194

95+
describe "copy project succeeds with invalid custom fields" do
96+
let(:source_project) { create(:project, types: [type]) }
97+
98+
let!(:work_package) { create(:work_package, project: source_project, type:) }
99+
100+
let(:type) { create(:type_bug) }
101+
let(:custom_field) do
102+
create(:work_package_custom_field, name: "required_field", field_format: "text", is_required: true, is_for_all: true)
103+
end
104+
105+
let(:job_args) do
106+
{
107+
target_project_params: params,
108+
associations_to_copy: [:work_packages]
109+
}
110+
end
111+
112+
let(:params) { { name: "Copy", identifier: "copy", type_ids: [type.id], work_package_custom_field_ids: [custom_field.id] } }
113+
114+
before do
115+
source_project.work_package_custom_fields << custom_field
116+
type.custom_fields << custom_field
117+
end
118+
119+
it "copies the project", :aggregate_failures do
120+
copy_job = nil
121+
batch = GoodJob::Batch.enqueue(user: admin, source_project:) do
122+
copy_job = described_class.perform_later(**job_args)
123+
end
124+
GoodJob.perform_inline
125+
batch.reload
126+
127+
copied_project = Project.find_by(identifier: params[:identifier])
128+
129+
expect(copied_project).to eq(batch.properties[:target_project])
130+
expect(batch.properties[:errors]).to be_empty
131+
132+
# expect to create a status
133+
expect(copy_job.job_status).to be_present
134+
expect(copy_job.job_status[:status]).to eq "success"
135+
expect(copy_job.job_status[:payload]["redirect"]).to include "/projects/copy"
136+
137+
expected_link = { "href" => "/api/v3/projects/#{copied_project.id}", "title" => copied_project.name }
138+
expect(copy_job.job_status[:payload]["_links"]["project"]).to eq(expected_link)
139+
end
140+
end
141+
102142
describe "project has an invalid repository" do
103-
let(:admin) { create(:admin) }
104143
let(:source_project) do
105144
project = create(:project)
106145

@@ -136,9 +175,7 @@
136175
end
137176

138177
describe "copy project fails with internal error" do
139-
let(:admin) { create(:admin) }
140178
let(:source_project) { create(:project) }
141-
let(:params) { { name: "Copy", identifier: "copy" } }
142179

143180
before do
144181
allow(User).to receive(:current).and_return(admin)
@@ -174,9 +211,6 @@
174211
set_factory_default(:project_with_types, source_project)
175212
end
176213

177-
let(:admin) { create(:admin) }
178-
let(:params) { { name: "Copy", identifier: "copy" } }
179-
180214
let_work_packages(<<~TABLE)
181215
hierarchy | work | remaining work | start date | end date | scheduling mode
182216
parent | 1h | 0h | 2024-01-23 | 2024-01-26 | automatic
@@ -235,7 +269,6 @@
235269
end
236270

237271
describe "subproject" do
238-
let(:params) { { name: "Copy", identifier: "copy" } }
239272
let(:subproject) do
240273
create(:project, parent: project).tap do |p|
241274
create(:member, principal: user, roles: [role], project: p)
@@ -328,9 +361,6 @@
328361
set_factory_default(:project_with_types, source_project)
329362
end
330363

331-
let(:admin) { create(:admin) }
332-
let(:params) { { name: "Copy", identifier: "copy" } }
333-
334364
let_work_packages(<<~TABLE)
335365
hierarchy | start date | end date | scheduling mode
336366
automatic_parent | 2024-01-23 | 2024-01-26 | automatic
@@ -362,13 +392,10 @@
362392
# do it.
363393
describe "sending notifications" do
364394
shared_let(:project) { create(:project) }
365-
shared_let(:admin) { create(:admin) }
366395
shared_let(:user) { create(:user) }
367396
shared_let(:roles) { [create(:project_role)] }
368397
shared_let(:member) { create(:member, user:, project:, roles:) }
369398

370-
let(:params) { { name: "Copy", identifier: "copy" } }
371-
372399
def perform_the_job
373400
batch = GoodJob::Batch.enqueue(user: admin, source_project: project) do
374401
described_class.perform_later(target_project_params: params, associations_to_copy: [:members])

0 commit comments

Comments
 (0)