Revision 13fbd336
Von Moritz Bunkus vor mehr als 10 Jahren hinzugefügt
SL/Controller/RequirementSpec.pm | ||
---|---|---|
192 | 192 |
|
193 | 193 |
my $versioned_copy = SL::DB::RequirementSpec->new(id => $::form->{versioned_copy_id})->load; |
194 | 194 |
|
195 |
$self->requirement_spec->copy_from( |
|
196 |
$versioned_copy, |
|
197 |
version_id => $versioned_copy->version_id, |
|
198 |
); |
|
195 |
$self->requirement_spec->copy_from($versioned_copy); |
|
196 |
my $version = $versioned_copy->versions->[0]; |
|
197 |
$version->update_attributes(working_copy_id => $self->requirement_spec->id); |
|
199 | 198 |
|
200 | 199 |
flash_later('info', t8('The requirement spec has been reverted to version #1.', $self->requirement_spec->version->version_number)); |
201 | 200 |
$self->js->redirect_to($self->url_for(action => 'show', id => $self->requirement_spec->id))->render($self); |
... | ... | |
410 | 409 |
sub => sub { $_[0]->project_id ? $_[0]->project->projectnumber : '' } }, |
411 | 410 |
status => { sub => sub { $_[0]->status->description } }, |
412 | 411 |
type => { sub => sub { $_[0]->type->description } }, |
413 |
version => { sub => sub { $_[0]->version_id ? $_[0]->version->version_number : t8('Working copy without version') } },
|
|
412 |
version => { sub => sub { $_[0]->version ? $_[0]->version->version_number : t8('Working copy without version') } }, |
|
414 | 413 |
); |
415 | 414 |
} |
416 | 415 |
|
SL/Controller/RequirementSpecVersion.pm | ||
---|---|---|
17 | 17 |
|
18 | 18 |
use Rose::Object::MakeMethods::Generic |
19 | 19 |
( |
20 |
'scalar --get_set_init' => [ qw(requirement_spec version js versioned_copies) ],
|
|
20 |
'scalar --get_set_init' => [ qw(requirement_spec version js) ], |
|
21 | 21 |
); |
22 | 22 |
|
23 | 23 |
__PACKAGE__->run_before('check_auth'); |
... | ... | |
117 | 117 |
$self->js(SL::ClientJS->new); |
118 | 118 |
} |
119 | 119 |
|
120 |
sub init_versioned_copies { |
|
121 |
my ($self) = @_; |
|
122 |
$self->versioned_copies([ |
|
123 |
sort { $b->mtime <=> $a->mtime } @{ $self->requirement_spec->versioned_copies } |
|
124 |
]); |
|
125 |
} |
|
126 |
|
|
127 | 120 |
sub has_item_changed { |
128 | 121 |
my ($previous, $current) = @_; |
129 | 122 |
croak "Missing previous/current" if !$previous || !$current; |
SL/DB/MetaSetup/RequirementSpec.pm | ||
---|---|---|
22 | 22 |
time_estimation => { type => 'numeric', default => '0', not_null => 1, precision => 2, scale => 12 }, |
23 | 23 |
title => { type => 'text', not_null => 1 }, |
24 | 24 |
type_id => { type => 'integer' }, |
25 |
version_id => { type => 'integer' }, |
|
26 | 25 |
working_copy_id => { type => 'integer' }, |
27 | 26 |
); |
28 | 27 |
|
... | ... | |
51 | 50 |
key_columns => { type_id => 'id' }, |
52 | 51 |
}, |
53 | 52 |
|
54 |
version => { |
|
55 |
class => 'SL::DB::RequirementSpecVersion', |
|
56 |
key_columns => { version_id => 'id' }, |
|
57 |
}, |
|
58 |
|
|
59 | 53 |
working_copy => { |
60 | 54 |
class => 'SL::DB::RequirementSpec', |
61 | 55 |
key_columns => { working_copy_id => 'id' }, |
SL/DB/MetaSetup/RequirementSpecVersion.pm | ||
---|---|---|
9 | 9 |
__PACKAGE__->meta->table('requirement_spec_versions'); |
10 | 10 |
|
11 | 11 |
__PACKAGE__->meta->columns( |
12 |
comment => { type => 'text' }, |
|
13 |
description => { type => 'text', not_null => 1 }, |
|
14 |
id => { type => 'serial', not_null => 1 }, |
|
15 |
itime => { type => 'timestamp', default => 'now()' }, |
|
16 |
mtime => { type => 'timestamp' }, |
|
17 |
version_number => { type => 'integer' }, |
|
12 |
comment => { type => 'text' }, |
|
13 |
description => { type => 'text', not_null => 1 }, |
|
14 |
id => { type => 'serial', not_null => 1 }, |
|
15 |
itime => { type => 'timestamp', default => 'now()' }, |
|
16 |
mtime => { type => 'timestamp' }, |
|
17 |
requirement_spec_id => { type => 'integer', not_null => 1 }, |
|
18 |
version_number => { type => 'integer' }, |
|
19 |
working_copy_id => { type => 'integer' }, |
|
18 | 20 |
); |
19 | 21 |
|
20 | 22 |
__PACKAGE__->meta->primary_key_columns([ 'id' ]); |
21 | 23 |
|
22 | 24 |
__PACKAGE__->meta->allow_inline_column_values(1); |
23 | 25 |
|
26 |
__PACKAGE__->meta->foreign_keys( |
|
27 |
requirement_spec => { |
|
28 |
class => 'SL::DB::RequirementSpec', |
|
29 |
key_columns => { requirement_spec_id => 'id' }, |
|
30 |
}, |
|
31 |
|
|
32 |
working_copy => { |
|
33 |
class => 'SL::DB::RequirementSpec', |
|
34 |
key_columns => { working_copy_id => 'id' }, |
|
35 |
}, |
|
36 |
); |
|
37 |
|
|
24 | 38 |
1; |
25 | 39 |
; |
SL/DB/RequirementSpec.pm | ||
---|---|---|
27 | 27 |
class => 'SL::DB::RequirementSpec', |
28 | 28 |
column_map => { id => 'working_copy_id' }, |
29 | 29 |
}, |
30 |
versions => { |
|
31 |
type => 'one to many', |
|
32 |
class => 'SL::DB::RequirementSpecVersion', |
|
33 |
column_map => { id => 'requirement_spec_id' }, |
|
34 |
}, |
|
35 |
working_copy_versions => { |
|
36 |
type => 'one to many', |
|
37 |
class => 'SL::DB::RequirementSpecVersion', |
|
38 |
column_map => { id => 'working_copy_id' }, |
|
39 |
}, |
|
30 | 40 |
orders => { |
31 | 41 |
type => 'one to many', |
32 | 42 |
class => 'SL::DB::RequirementSpecOrder', |
... | ... | |
56 | 66 |
return 1; |
57 | 67 |
} |
58 | 68 |
|
69 |
sub version { |
|
70 |
my ($self) = @_; |
|
71 |
|
|
72 |
croak "Not a writer" if scalar(@_) > 1; |
|
73 |
|
|
74 |
return $self->is_working_copy ? $self->working_copy_versions->[0] : $self->versions->[0]; |
|
75 |
} |
|
76 |
|
|
59 | 77 |
sub text_blocks_sorted { |
60 | 78 |
my ($self, %params) = _hashify(1, @_); |
61 | 79 |
|
... | ... | |
222 | 240 |
sub next_version_number { |
223 | 241 |
my ($self) = @_; |
224 | 242 |
|
225 |
return max(0, map { $_->version->version_number } @{ $self->versioned_copies }) + 1; |
|
243 |
return 1 if !$self->id; |
|
244 |
|
|
245 |
my ($max_number) = $self->db->dbh->selectrow_array(<<SQL, {}, $self->id, $self->id); |
|
246 |
SELECT MAX(v.version_number) |
|
247 |
FROM requirement_spec_versions v |
|
248 |
WHERE v.requirement_spec_id IN ( |
|
249 |
SELECT rs.id |
|
250 |
FROM requirement_specs rs |
|
251 |
WHERE (rs.id = ?) |
|
252 |
OR (rs.working_copy_id = ?) |
|
253 |
) |
|
254 |
SQL |
|
255 |
|
|
256 |
return ($max_number // 0) + 1; |
|
226 | 257 |
} |
227 | 258 |
|
228 | 259 |
sub create_version { |
... | ... | |
234 | 265 |
my $ok = $self->db->with_transaction(sub { |
235 | 266 |
delete $attributes{version_number}; |
236 | 267 |
|
237 |
$version = SL::DB::RequirementSpecVersion->new(%attributes, version_number => $self->next_version_number)->save; |
|
238 |
$copy = $self->create_copy; |
|
239 |
$copy->update_attributes(version_id => $version->id, working_copy_id => $self->id); |
|
240 |
$self->update_attributes(version_id => $version->id); |
|
268 |
SL::DB::Manager::RequirementSpecVersion->update_all( |
|
269 |
set => [ working_copy_id => undef ], |
|
270 |
where => [ requirement_spec_id => $self->id ], |
|
271 |
); |
|
272 |
|
|
273 |
$copy = $self->create_copy(working_copy_id => $self->id); |
|
274 |
$version = SL::DB::RequirementSpecVersion->new(%attributes, version_number => $self->next_version_number, requirement_spec_id => $copy->id, working_copy_id => $self->id)->save; |
|
241 | 275 |
|
242 | 276 |
1; |
243 | 277 |
}); |
... | ... | |
250 | 284 |
|
251 | 285 |
croak "Cannot work on a versioned copy" if $self->working_copy_id; |
252 | 286 |
|
253 |
return if !$self->id || !$self->version_id; |
|
254 |
$self->update_attributes(version_id => undef); |
|
287 |
return if !$self->id; |
|
288 |
|
|
289 |
SL::DB::Manager::RequirementSpecVersion->update_all( |
|
290 |
set => [ working_copy_id => undef ], |
|
291 |
where => [ working_copy_id => $self->id ], |
|
292 |
); |
|
255 | 293 |
} |
256 | 294 |
|
257 | 295 |
1; |
... | ... | |
271 | 309 |
important thing is how working copy/versions are handled. |
272 | 310 |
|
273 | 311 |
The table contains three important columns: C<id> (which is also the |
274 |
primary key), C<working_copy_id> and C<version_id>. C<working_copy_id> |
|
275 |
is a self-referencing column: it can be C<NULL>, but if it isn't then |
|
276 |
it contains another requirement spec C<id>. C<version_id> on the other |
|
277 |
hand references the table C<requirement_spec_versions>. |
|
312 |
primary key) and C<working_copy_id>. C<working_copy_id> is a |
|
313 |
self-referencing column: it can be C<NULL>, but if it isn't then it |
|
314 |
contains another requirement spec C<id>. |
|
315 |
|
|
316 |
Versions are represented similarly. The C<requirement_spec_versions> |
|
317 |
table has three important columns: C<id> (the primary key), |
|
318 |
C<requirement_spec_id> (references C<requirement_specs.id> and must |
|
319 |
not be C<NULL>) and C<working_copy_id> (references |
|
320 |
C<requirement_specs.id> as well but can be |
|
321 |
C<NULL>). C<working_copy_id> points to the working copy if and only if |
|
322 |
the working copy is currently equal to a versioned copy. |
|
278 | 323 |
|
279 | 324 |
The design is as follows: |
280 | 325 |
|
... | ... | |
289 | 334 |
in time it was created. Each versioned copy refers back to the working |
290 | 335 |
copy it belongs to: each has its C<working_copy_id> set. |
291 | 336 |
|
292 |
=item * Each versioned copy must reference an entry in the table
|
|
293 |
C<requirement_spec_versions>. Meaning: for each versioned copy
|
|
294 |
C<version_id> must not be C<NULL>.
|
|
337 |
=item * Each versioned copy must be referenced from an entry in the
|
|
338 |
table C<requirement_spec_versions> via
|
|
339 |
C<requirement_spec_id>.
|
|
295 | 340 |
|
296 | 341 |
=item * Directly after creating a versioned copy even the working copy |
297 |
itself points to a certain version via its C<version_id> column: to
|
|
298 |
the same version that the versioned copy just created points
|
|
299 |
to. However, any modification that will be visible to the customer
|
|
300 |
(text, positioning etc but not internal things like time/cost
|
|
301 |
estimation changes) will cause the working copy to be set to 'no
|
|
302 |
version' again. This is achieved via before save hooks in Perl.
|
|
342 |
itself is referenced from a version via that table's
|
|
343 |
C<working_copy_id> column. However, any modification that will be
|
|
344 |
visible to the customer (text, positioning etc but not internal things
|
|
345 |
like time/cost estimation changes) will cause the version to be
|
|
346 |
disassociated from the working copy. This is achieved via before save
|
|
347 |
hooks in Perl. |
|
303 | 348 |
|
304 | 349 |
=back |
305 | 350 |
|
... | ... | |
359 | 404 |
This function can be used for resetting a working copy to a specific |
360 | 405 |
version. Example: |
361 | 406 |
|
362 |
my $requirement_spec = SL::DB::RequirementSpec->new(id => $::form->{id})->load; |
|
363 |
my $versioned_copy = SL::DB::RequirementSpec->new(id => $::form->{versioned_copy_id})->load; |
|
407 |
my $requirement_spec = SL::DB::RequirementSpec->new(id => $::form->{id})->load;
|
|
408 |
my $versioned_copy = SL::DB::RequirementSpec->new(id => $::form->{versioned_copy_id})->load;
|
|
364 | 409 |
|
365 |
$requirement_spec->copy_from( |
|
366 |
$versioned_copy, |
|
367 |
version_id => $versioned_copy->version_id, |
|
368 |
); |
|
410 |
$requirement_spec->copy_from($versioned_copy); |
|
411 |
$versioned_copy->version->update_attributes(working_copy_id => $requirement_spec->id); |
|
369 | 412 |
|
370 | 413 |
=item C<create_copy> |
371 | 414 |
|
... | ... | |
385 | 428 |
=item 1. The next version number is calculated using |
386 | 429 |
L</next_version_number>. |
387 | 430 |
|
388 |
=item 2. An instance of L<SL::DB::RequirementSpecVersion> is |
|
431 |
=item 2. A copy of C<$self> is created with L</create_copy>. |
|
432 |
|
|
433 |
=item 3. An instance of L<SL::DB::RequirementSpecVersion> is |
|
389 | 434 |
created. Its attributes are copied from C<%attributes> save for the |
390 | 435 |
version number which is taken from step 1. |
391 | 436 |
|
392 |
=item 3. A copy of C<$self> is created with L</create_copy>. |
|
393 |
|
|
394 |
=item 4. The version instance created in step is assigned to the copy |
|
395 |
from step 3. |
|
396 |
|
|
397 |
=item 5. The C<version_id> in C<$self> is set to the copy's ID from |
|
398 |
step 3. |
|
437 |
=item 4. The version instance created in step 3 is referenced to the |
|
438 |
the copy from step 2 via C<requirement_spec_id> and to the working |
|
439 |
copy for which the version was created via C<working_copy_id>. |
|
399 | 440 |
|
400 | 441 |
=back |
401 | 442 |
|
... | ... | |
424 | 465 |
Prerequisites: C<$self> must be a working copy (see the overview), |
425 | 466 |
not a versioned copy. |
426 | 467 |
|
427 |
Sets the C<version_id> field to C<undef> and saves C<$self>. |
|
468 |
Sets any C<working_copy_id> field in the C<requirement_spec_versions> |
|
469 |
table containing C<$self-E<gt>id> to C<undef>. |
|
428 | 470 |
|
429 | 471 |
=item C<is_working_copy> |
430 | 472 |
|
SL/DB/RequirementSpecItem.pm | ||
---|---|---|
66 | 66 |
sub _before_save_invalidate_requirement_spec_version { |
67 | 67 |
my ($self, %params) = @_; |
68 | 68 |
|
69 |
return 1 if !$self->requirement_spec_id; |
|
69 |
return 1 if !$self->requirement_spec_id || $self->requirement_spec->working_copy_id;
|
|
70 | 70 |
|
71 | 71 |
my %changed_columns = map { $_ => 1 } (Rose::DB::Object::Helpers::dirty_columns($self)); |
72 | 72 |
my $has_changed = !Rose::DB::Object::Util::is_in_db($self); |
SL/DB/RequirementSpecTextBlock.pm | ||
---|---|---|
30 | 30 |
sub _before_save_invalidate_requirement_spec_version { |
31 | 31 |
my ($self, %params) = @_; |
32 | 32 |
|
33 |
|
|
34 |
return 1 if !$self->requirement_spec_id; |
|
33 |
return 1 if !$self->requirement_spec_id || $self->requirement_spec->working_copy_id; |
|
35 | 34 |
|
36 | 35 |
my %changed_columns = map { $_ => 1 } (Rose::DB::Object::Helpers::dirty_columns($self)); |
37 | 36 |
|
sql/Pg-upgrade2/requirement_spec_delete_trigger_fix2.sql | ||
---|---|---|
1 |
-- @tag: requirement_spec_delete_trigger_fix2 |
|
2 |
-- @description: Fixes für Delete-Trigger bei Pflichtenheften |
|
3 |
-- @depends: requirement_spec_delete_trigger_fix |
|
4 |
|
|
5 |
-- requirement_spec_id: link to requirement specs (the versioned |
|
6 |
-- document) working_copy_id: link to requirement spec working copy |
|
7 |
-- (only set if working copy is currently at a version level) |
|
8 |
ALTER TABLE requirement_spec_versions ADD COLUMN requirement_spec_id INTEGER; |
|
9 |
ALTER TABLE requirement_spec_versions ADD COLUMN working_copy_id INTEGER; |
|
10 |
|
|
11 |
UPDATE requirement_spec_versions ver |
|
12 |
SET requirement_spec_id = ( |
|
13 |
SELECT MAX(rs.id) |
|
14 |
FROM requirement_specs rs |
|
15 |
WHERE rs.version_id = ver.id |
|
16 |
); |
|
17 |
|
|
18 |
UPDATE requirement_spec_versions ver |
|
19 |
SET working_copy_id = ( |
|
20 |
SELECT rs.id |
|
21 |
FROM requirement_specs rs |
|
22 |
WHERE (rs.version_id = ver.id) |
|
23 |
AND (rs.working_copy_id IS NULL) |
|
24 |
); |
|
25 |
|
|
26 |
ALTER TABLE requirement_spec_versions ALTER COLUMN requirement_spec_id SET NOT NULL; |
|
27 |
ALTER TABLE requirement_spec_versions ADD FOREIGN KEY (requirement_spec_id) REFERENCES requirement_specs (id) ON DELETE CASCADE; |
|
28 |
ALTER TABLE requirement_spec_versions ADD FOREIGN KEY (working_copy_id) REFERENCES requirement_specs (id) ON DELETE CASCADE; |
|
29 |
|
|
30 |
ALTER TABLE requirement_specs DROP COLUMN version_id; |
|
31 |
ALTER TABLE requirement_specs DROP CONSTRAINT requirement_specs_working_copy_id_fkey; |
|
32 |
ALTER TABLE requirement_specs ADD FOREIGN KEY (working_copy_id) REFERENCES requirement_specs (id) ON DELETE CASCADE; |
|
33 |
|
|
34 |
ALTER TABLE requirement_spec_items DROP CONSTRAINT requirement_spec_items_requirement_spec_id_fkey; |
|
35 |
ALTER TABLE requirement_spec_items ADD FOREIGN KEY (requirement_spec_id) REFERENCES requirement_specs (id) ON DELETE CASCADE; |
|
36 |
|
|
37 |
ALTER TABLE requirement_spec_item_dependencies DROP CONSTRAINT requirement_spec_item_dependencies_depended_item_id_fkey; |
|
38 |
ALTER TABLE requirement_spec_item_dependencies ADD FOREIGN KEY (depended_item_id) REFERENCES requirement_spec_items (id) ON DELETE CASCADE; |
|
39 |
ALTER TABLE requirement_spec_item_dependencies DROP CONSTRAINT requirement_spec_item_dependencies_depending_item_id_fkey; |
|
40 |
ALTER TABLE requirement_spec_item_dependencies ADD FOREIGN KEY (depending_item_id) REFERENCES requirement_spec_items (id) ON DELETE CASCADE; |
|
41 |
|
|
42 |
ALTER TABLE requirement_spec_text_blocks DROP CONSTRAINT requirement_spec_text_blocks_requirement_spec_id_fkey; |
|
43 |
ALTER TABLE requirement_spec_text_blocks ADD FOREIGN KEY (requirement_spec_id) REFERENCES requirement_specs (id) ON DELETE CASCADE; |
|
44 |
|
|
45 |
-- Trigger for deleting depending stuff if a requirement spec is deleted. |
|
46 |
CREATE OR REPLACE FUNCTION requirement_spec_delete_trigger() RETURNS trigger AS $$ |
|
47 |
BEGIN |
|
48 |
IF TG_WHEN = 'AFTER' THEN |
|
49 |
DELETE FROM trigger_information WHERE (key = 'deleting_requirement_spec') AND (value = CAST(OLD.id AS TEXT)); |
|
50 |
|
|
51 |
RETURN OLD; |
|
52 |
END IF; |
|
53 |
|
|
54 |
RAISE DEBUG 'before delete trigger on %', OLD.id; |
|
55 |
|
|
56 |
INSERT INTO trigger_information (key, value) VALUES ('deleting_requirement_spec', CAST(OLD.id AS TEXT)); |
|
57 |
|
|
58 |
RAISE DEBUG ' Converting items into sections items for %', OLD.id; |
|
59 |
UPDATE requirement_spec_items SET item_type = 'section', parent_id = NULL WHERE requirement_spec_id = OLD.id; |
|
60 |
|
|
61 |
RAISE DEBUG ' And we out for %', OLD.id; |
|
62 |
|
|
63 |
RETURN OLD; |
|
64 |
END; |
|
65 |
$$ LANGUAGE plpgsql; |
|
66 |
|
|
67 |
-- Trigger for deleting depending stuff if a requirement spec item is deleted. |
|
68 |
CREATE OR REPLACE FUNCTION requirement_spec_item_before_delete_trigger() RETURNS trigger AS $$ |
|
69 |
BEGIN |
|
70 |
RAISE DEBUG 'delete trig RSitem old id %', OLD.id; |
|
71 |
INSERT INTO trigger_information (key, value) VALUES ('deleting_requirement_spec_item', CAST(OLD.id AS TEXT)); |
|
72 |
DELETE FROM requirement_spec_items WHERE (parent_id = OLD.id); |
|
73 |
DELETE FROM trigger_information WHERE (key = 'deleting_requirement_spec_item') AND (value = CAST(OLD.id AS TEXT)); |
|
74 |
RAISE DEBUG 'delete trig END %', OLD.id; |
|
75 |
RETURN OLD; |
|
76 |
END; |
|
77 |
$$ LANGUAGE plpgsql; |
templates/print/Standard/requirement_spec.tex | ||
---|---|---|
4 | 4 |
$( USE P )$ |
5 | 5 |
\documentclass{scrartcl} |
6 | 6 |
|
7 |
\usepackage[reqspeclogo,$( IF !rspec.version_id )$draftlogo$( ELSE )$secondpagelogo$( END )$]{kivitendo}
|
|
7 |
\usepackage[reqspeclogo,$( IF !rspec.version )$draftlogo$( ELSE )$secondpagelogo$( END )$]{kivitendo} |
|
8 | 8 |
|
9 | 9 |
\kivitendobgsettings |
10 | 10 |
|
... | ... | |
15 | 15 |
\parbox{12cm}{% |
16 | 16 |
\defaultfont\scriptsize% |
17 | 17 |
$( LxLatex.filter(rspec.displayable_name) )$\\ |
18 |
$( !rspec.version_id ? "Arbeitskopie ohne Version" : "Version " _ rspec.version.version_number _ " vom " _ rspec.version.itime.to_kivitendo(precision='minute') )$
|
|
18 |
$( !rspec.version ? "Arbeitskopie ohne Version" : "Version " _ rspec.version.version_number _ " vom " _ rspec.version.itime.to_kivitendo(precision='minute') )$ |
|
19 | 19 |
|
20 | 20 |
\vspace*{0.2cm}% |
21 | 21 |
Seite \thepage% |
... | ... | |
44 | 44 |
\Large |
45 | 45 |
$( LxLatex.filter(rspec.title) )$ |
46 | 46 |
\normalsize |
47 |
%$( IF rspec.version_id )$
|
|
47 |
%$( IF rspec.version )$ |
|
48 | 48 |
|
49 | 49 |
Version $( LxLatex.filter(rspec.version.version_number) )$ |
50 | 50 |
%$( END )$ |
... | ... | |
66 | 66 |
\vspace*{0.7cm} |
67 | 67 |
|
68 | 68 |
%$( SET working_copy = rspec.working_copy_id ? rspec.working_copy : rspec )$ |
69 |
%$( SET versioned_copies = rspec.version_id ? working_copy.versioned_copies_sorted(max_version_number = rspec.version.version_number) : working_copy.versioned_copies_sorted )$
|
|
69 |
%$( SET versioned_copies = rspec.version ? working_copy.versioned_copies_sorted(max_version_number = rspec.version.version_number) : working_copy.versioned_copies_sorted )$ |
|
70 | 70 |
%$( IF !versioned_copies.size )$ |
71 | 71 |
Bisher wurden noch keine Versionen angelegt. |
72 | 72 |
%$( ELSE )$ |
templates/webpages/requirement_spec/_version.html | ||
---|---|---|
1 | 1 |
[%- USE L -%][%- USE LxERP -%][%- USE HTML -%] |
2 |
[% L.hidden_tag('current_version_id', requirement_spec.version_id) %]
|
|
2 |
[% L.hidden_tag('current_version_id', requirement_spec.version.id) %]
|
|
3 | 3 |
[% LxERP.t8("Current version") %]: |
4 |
[% IF !requirement_spec.version_id %]
|
|
4 |
[% IF !requirement_spec.version.id %]
|
|
5 | 5 |
[% LxERP.t8("Working copy without version") %] |
6 | 6 |
[% ELSE %] |
7 | 7 |
[% LxERP.t8("Version") %] [% HTML.escape(requirement_spec.version.version_number) %] |
templates/webpages/requirement_spec_version/list.html | ||
---|---|---|
12 | 12 |
|
13 | 13 |
<tbody> |
14 | 14 |
<tr class="listrow versioned-copy-context-menu"> |
15 |
[%- IF SELF.requirement_spec.version_id %]
|
|
16 |
[% L.hidden_tag('versioned_copy_id', SELF.requirement_spec.version_id, no_id=1) %] |
|
15 |
[%- IF SELF.requirement_spec.version %] |
|
16 |
[% L.hidden_tag('versioned_copy_id', SELF.requirement_spec.version.requirement_spec_id, no_id=1) %]
|
|
17 | 17 |
<td>[%- LxERP.t8("Working copy identical to version number #1", SELF.requirement_spec.version.version_number) %]</td> |
18 | 18 |
[%- ELSE %] |
19 | 19 |
<td>[%- LxERP.t8("Working copy without version") %]</td> |
... | ... | |
23 | 23 |
<td>[% SELF.requirement_spec.mtime.to_kivitendo(precision='minute') %]</td> |
24 | 24 |
</tr> |
25 | 25 |
|
26 |
[%- FOREACH versioned = SELF.versioned_copies %] |
|
26 |
[%- FOREACH versioned_copy = SELF.requirement_spec.versioned_copies_sorted %] |
|
27 |
[%- SET version = versioned_copy.version %] |
|
27 | 28 |
<tr class="listrow versioned-copy-context-menu"> |
28 |
[% L.hidden_tag('versioned_copy_id', versioned.id, no_id=1) %] |
|
29 |
<td>[% HTML.escape(versioned.version.version_number) %]</td>
|
|
30 |
<td>[% HTML.escape(P.truncate(versioned.description)) %]</td>
|
|
31 |
<td>[% HTML.escape(P.truncate(versioned.comment)) %]</td>
|
|
32 |
<td>[% versioned.mtime.to_kivitendo(precision='minute') %]</td>
|
|
29 |
[% L.hidden_tag('versioned_copy_id', versioned_copy.id, no_id=1) %]
|
|
30 |
<td>[% HTML.escape(version.version_number) %]</td> |
|
31 |
<td>[% HTML.escape(P.truncate(version.description)) %]</td> |
|
32 |
<td>[% HTML.escape(P.truncate(version.comment)) %]</td> |
|
33 |
<td>[% version.itime.to_kivitendo(precision='minute') %]</td>
|
|
33 | 34 |
</tr> |
34 | 35 |
[%- END %] |
35 | 36 |
</tbody> |
Auch abrufbar als: Unified diff
Pflichtenheftversionen: Datenbankstruktur zu Pflichtenheften geändert
requirement_specs.version_id wurde durch
requirement_spec_versions.requirement_spec_id und
requirement_spec_versions.working_copy_id ersetzt.