Berechtigung, Verkaufsrechnungen persönlich zugeordneter Projekte einzusehen
[kivitendo-erp.git] / SL / DB / Project.pm
1 package SL::DB::Project;
2
3 use strict;
4
5 use List::MoreUtils qw(any);
6
7 use SL::DB::MetaSetup::Project;
8 use SL::DB::Manager::Project;
9
10 use SL::DB::Helper::CustomVariables(
11   module      => 'Projects',
12   cvars_alias => 1,
13 );
14
15 __PACKAGE__->meta->add_relationship(
16   employee_invoice_permissions  => {
17     type       => 'many to many',
18     map_class  => 'SL::DB::EmployeeProjectInvoices',
19   },
20 );
21
22 __PACKAGE__->meta->initialize;
23
24 sub validate {
25   my ($self) = @_;
26
27   my @errors;
28   push @errors, $::locale->text('The project number is missing.')        if !$self->projectnumber;
29   push @errors, $::locale->text('The project number is already in use.') if !$self->is_projectnumber_unique;
30   push @errors, $::locale->text('The description is missing.')           if !$self->description;
31
32   return @errors;
33 }
34
35 sub is_used {
36   my ($self) = @_;
37
38   # Unsaved projects are never referenced.
39   return 0 unless $self->id;
40
41   return any {
42     my $column = $SL::DB::Manager::Project::project_id_column_prefixes{$_} . 'project_id';
43     $self->db->dbh->selectrow_arrayref(qq|SELECT EXISTS(SELECT * FROM ${_} WHERE ${column} = ?)|, undef, $self->id)->[0]
44   } @SL::DB::Manager::Project::tables_with_project_id_cols;
45 }
46
47 sub is_projectnumber_unique {
48   my ($self) = @_;
49
50   return 1 unless $self->projectnumber;
51
52   my @filter = (projectnumber => $self->projectnumber);
53   @filter    = (and => [ @filter, '!id' => $self->id ]) if $self->id;
54
55   return !SL::DB::Manager::Project->get_first(where => \@filter);
56 }
57
58 sub displayable_name {
59   my ($self) = @_;
60
61   return join ' ', grep $_, $self->projectnumber, $self->description;
62 }
63
64 sub full_description {
65   my ($self, %params) = @_;
66
67   $params{style} ||= 'both';
68   my $description;
69
70   if ($params{style} =~ m/number/) {
71     $description = $self->projectnumber;
72
73   } elsif ($params{style} =~ m/description/) {
74     $description = $self->description;
75
76   } elsif (($params{style} =~ m/full/) && $self->customer) {
77     $description = $self->projectnumber;
78     if ($self->description && do { my $desc = quotemeta $self->description; $self->projectnumber !~ m/$desc/ }) {
79       $description .= ' ' . $self->description;
80     }
81
82     $description = $self->customer->name . " (${description})";
83
84   } else {
85     $description = $self->projectnumber;
86     if ($self->description && do { my $desc = quotemeta $self->description; $self->projectnumber !~ m/$desc/ }) {
87       $description .= ' (' . $self->description . ')';
88     }
89   }
90
91   return $description;
92 }
93
94 sub may_employee_view_project_invoices {
95   my ($self, $employee) = @_;
96
97   return undef if !$self->id;
98
99   my $employee_id = ref($employee) ? $employee->id : $employee * 1;
100   my $query       = <<EOSQL;
101     SELECT project_id
102     FROM employee_project_invoices
103     WHERE (employee_id = ?)
104       AND (project_id  = ?)
105     LIMIT 1
106 EOSQL
107
108   return !!$self->db->dbh->selectrow_arrayref($query, undef, $employee_id, $self->id)->[0];
109 }
110
111 1;
112
113 __END__
114
115 =pod
116
117 =head1 NAME
118
119 SL::DB::Project: Model for the 'project' table
120
121 =head1 SYNOPSIS
122
123 This is a standard Rose::DB::Object based model and can be used as one.
124
125 =head1 FUNCTIONS
126
127 =over 4
128
129 =item C<validate>
130
131 Checks whether or not all fields are set to valid values so that the
132 object can be saved. If valid returns an empty list. Returns an array
133 of translated error message otherwise.
134
135 =item C<is_used>
136
137 Checks whether or not the project is referenced from any other
138 database table. Returns a boolean value.
139
140 =item C<is_projectnumber_unique>
141
142 Returns trueish if the project number is not used for any other
143 project in the database. Also returns trueish if no project number has
144 been set yet.
145
146 =item C<displayable_name>
147
148 Returns a human-readable description of the project, consisting of projectnumber
149 and description.
150
151 =item C<full_description %params>
152
153 Returns a full description for the project which can consist of the
154 project number, its description or both. This is determined by the
155 parameter C<style> which defaults to C<both>:
156
157 =over 2
158
159 =item C<both>
160
161 Returns the project's number followed by its description in
162 parenthesis (e.g. "12345 (Secret Combinations)"). If the project's
163 description is already part of the project's number then it will not
164 be appended.
165
166 =item C<projectnumber> (or simply C<number>)
167
168 Returns only the project's number.
169
170 =item C<projectdescription> (or simply C<description>)
171
172 Returns only the project's description.
173
174 =item C<full>
175
176 Returns the customer name followed by the project number and project
177 description in parenthesis (e.g. "Evil Corp (12345 World
178 domination)"). If the project's description is already part of the
179 project's number then it will not be appended.
180
181 If this project isn't linked to a customer then the style C<both> is
182 used instead.
183
184 =back
185
186 =back
187
188 =head1 AUTHOR
189
190 Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
191
192 =cut