Pflichtenhefte: Kopieren (clonen) generell und Löschen aus Kontextmenü implementiert
[kivitendo-erp.git] / SL / DB / RequirementSpec.pm
1 package SL::DB::RequirementSpec;
2
3 use strict;
4
5 use Carp;
6 use Rose::DB::Object::Helpers;
7
8 use SL::DB::MetaSetup::RequirementSpec;
9 use SL::DB::Manager::RequirementSpec;
10 use SL::Locale::String;
11
12 __PACKAGE__->meta->add_relationship(
13   items          => {
14     type         => 'one to many',
15     class        => 'SL::DB::RequirementSpecItem',
16     column_map   => { id => 'requirement_spec_id' },
17   },
18   text_blocks    => {
19     type         => 'one to many',
20     class        => 'SL::DB::RequirementSpecTextBlock',
21     column_map   => { id => 'requirement_spec_id' },
22   },
23 );
24
25 __PACKAGE__->meta->initialize;
26
27 __PACKAGE__->before_save('_before_save_initialize_not_null_columns');
28
29 sub validate {
30   my ($self) = @_;
31
32   my @errors;
33   push @errors, t8('The title is missing.') if !$self->title;
34
35   return @errors;
36 }
37
38 sub _before_save_initialize_not_null_columns {
39   my ($self) = @_;
40
41   $self->previous_section_number(0) if !defined $self->previous_section_number;
42   $self->previous_fb_number(0)      if !defined $self->previous_fb_number;
43
44   return 1;
45 }
46
47 sub text_blocks_for_position {
48   my ($self, $output_position) = @_;
49
50   return [ sort { $a->position <=> $b->position } grep { $_->output_position == $output_position } @{ $self->text_blocks } ];
51 }
52
53 sub sections {
54   my ($self, @rest) = @_;
55
56   croak "This sub is not a writer" if @rest;
57
58   return [ sort { $a->position <=> $b->position } grep { !$_->parent_id } @{ $self->items } ];
59 }
60
61 sub displayable_name {
62   my ($self) = @_;
63
64   return sprintf('%s: "%s"', $self->type->description, $self->title);
65 }
66
67 sub create_copy {
68   my ($self, %params) = @_;
69
70   return $self->_create_copy(%params) if $self->db->in_transaction;
71
72   my $copy;
73   if (!$self->db->do_transaction(sub { $copy = $self->_create_copy(%params) })) {
74     $::lxdebug->message(LXDebug->WARN(), "create_copy failed: " . join("\n", (split(/\n/, $self->db->error))[0..2]));
75     return undef;
76   }
77
78   return $copy;
79 }
80
81 sub _create_copy {
82   my ($self, %params) = @_;
83
84   my $copy = Rose::DB::Object::Helpers::clone_and_reset($self);
85   $copy->assign_attributes(%params);
86
87   # Clone text blocks.
88   $copy->text_blocks(map { Rose::DB::Object::Helpers::clone_and_reset($_) } @{ $self->text_blocks });
89
90   # Save new object -- we need its ID for the items.
91   $copy->save;
92
93   my %id_to_clone;
94
95   # Clone items.
96   my $clone_item;
97   $clone_item = sub {
98     my ($item) = @_;
99     my $cloned = Rose::DB::Object::Helpers::clone_and_reset($item);
100     $cloned->requirement_spec_id($copy->id);
101     $cloned->children(map { $clone_item->($_) } @{ $item->children });
102
103     $id_to_clone{ $item->id } = $cloned;
104
105     return $cloned;
106   };
107
108   $copy->items(map { $clone_item->($_) } @{ $self->sections });
109
110   # Save the items -- need to do that before setting dependencies.
111   $copy->save;
112
113   # Set dependencies.
114   foreach my $item (@{ $self->items }) {
115     next unless @{ $item->dependencies };
116     $id_to_clone{ $item->id }->update_attributes(dependencies => [ map { $id_to_clone{$_->id} } @{ $item->dependencies } ]);
117   }
118
119   return $copy;
120 }
121
122 1;