[1489] | 1 | package LATMOS::Accounts::Bases::Sql::Employment; |
---|
| 2 | |
---|
| 3 | use 5.010000; |
---|
| 4 | use strict; |
---|
| 5 | use warnings; |
---|
| 6 | |
---|
| 7 | use base qw(LATMOS::Accounts::Bases::Sql::objects); |
---|
[1500] | 8 | use LATMOS::Accounts::Log; |
---|
[1551] | 9 | use LATMOS::Accounts::I18N; |
---|
[1500] | 10 | use Date::Parse; |
---|
| 11 | use DateTime; |
---|
[1623] | 12 | use Date::Calc; |
---|
[1489] | 13 | |
---|
| 14 | our $VERSION = (q$Rev: 594 $ =~ /^Rev: (\d+) /)[0]; |
---|
| 15 | |
---|
| 16 | =head1 NAME |
---|
| 17 | |
---|
| 18 | LATMOS::Accounts::Bases::Sql::Address - Physical office Adress Support |
---|
| 19 | |
---|
| 20 | =head1 DESCRIPTION |
---|
| 21 | |
---|
| 22 | C<Address> objects allow to store user's several office addresses. |
---|
| 23 | |
---|
| 24 | Notice most of other bases (Ldap, ...) support only one address. |
---|
| 25 | |
---|
| 26 | =cut |
---|
| 27 | |
---|
| 28 | sub stringify { |
---|
| 29 | my ($self) = @_; |
---|
| 30 | |
---|
| 31 | my $user = $self->base->get_object('user', $self->_get_c_field('user')) |
---|
| 32 | or return $self->id; |
---|
| 33 | |
---|
| 34 | return join(', ', grep { $_ } |
---|
| 35 | ( |
---|
| 36 | $user, |
---|
[1500] | 37 | $self->get_c_field('firstday'), |
---|
[1489] | 38 | ) |
---|
| 39 | ); |
---|
| 40 | } |
---|
| 41 | |
---|
| 42 | sub _object_table { 'employment' } |
---|
| 43 | |
---|
| 44 | sub _key_field { 'name' } |
---|
| 45 | |
---|
| 46 | sub _has_extended_attributes { 1 } |
---|
| 47 | |
---|
| 48 | sub _get_attr_schema { |
---|
| 49 | my ($class, $base) = @_; |
---|
| 50 | |
---|
[1516] | 51 | my $attrs = { |
---|
| 52 | name => { inline => 1, }, |
---|
| 53 | exported => { inline => 1, }, |
---|
| 54 | user => { inline => 1, |
---|
| 55 | reference => 'user', |
---|
[1550] | 56 | label => l('User'), |
---|
[1516] | 57 | }, |
---|
[1550] | 58 | description => { |
---|
| 59 | label => l('Description'), |
---|
| 60 | }, |
---|
[1516] | 61 | firstday => { |
---|
| 62 | inline => 1, |
---|
| 63 | formtype => 'DATE', |
---|
| 64 | monitored => 1, |
---|
[1620] | 65 | label => l('Contract start'), |
---|
[1516] | 66 | }, |
---|
| 67 | lastday => { |
---|
| 68 | inline => 1, |
---|
| 69 | formtype => 'DATE', |
---|
| 70 | monitored => 1, |
---|
[1620] | 71 | label => l('Contract end'), |
---|
[1516] | 72 | }, |
---|
[1623] | 73 | length => { |
---|
| 74 | ro => 1, |
---|
| 75 | managed => 1, |
---|
| 76 | get => sub { |
---|
| 77 | my ($self) = @_; |
---|
| 78 | my $lastday = $self->object->get_attributes('lastday') || DateTime->now->ymd('-'); |
---|
| 79 | my $firstday = $self->object->get_attributes('firstday'); |
---|
| 80 | |
---|
| 81 | my @fd = split('-', $firstday); |
---|
| 82 | my @ld = split('-', $lastday); |
---|
| 83 | |
---|
| 84 | return Date::Calc::Delta_Days(@fd, @ld) +1; |
---|
| 85 | }, |
---|
| 86 | label => l('Length'), |
---|
| 87 | }, |
---|
| 88 | lengthText => { |
---|
| 89 | ro => 1, |
---|
| 90 | managed => 1, |
---|
| 91 | get => sub { |
---|
| 92 | my ($self) = @_; |
---|
| 93 | my $lastday = $self->object->get_attributes('lastday')|| DateTime->now->ymd('-'); |
---|
| 94 | { |
---|
| 95 | my $dtlast = DateTime->from_epoch(epoch => str2time($lastday)); |
---|
| 96 | $dtlast->add(days => 1); |
---|
| 97 | $lastday = $dtlast->ymd('-'); |
---|
| 98 | } |
---|
| 99 | my $firstday = $self->object->get_attributes('firstday'); |
---|
| 100 | |
---|
[1647] | 101 | return if ($firstday gt $lastday); |
---|
| 102 | |
---|
[1646] | 103 | my @fd = split('-', $firstday) or return; |
---|
| 104 | my @ld = split('-', $lastday) or return; |
---|
[1623] | 105 | |
---|
| 106 | my ($Dy,$Dm,$Dd) = Date::Calc::N_Delta_YMD(@fd, @ld); |
---|
| 107 | return join(', ', |
---|
| 108 | ($Dy ? l('%d years', $Dy) : ()), |
---|
| 109 | ($Dm ? l('%d months', $Dm) : ()), |
---|
| 110 | ($Dd ? l('%d days', $Dd) : ()), |
---|
| 111 | ); |
---|
| 112 | }, |
---|
| 113 | label => l('Length'), |
---|
| 114 | }, |
---|
[1516] | 115 | 'state' => { |
---|
| 116 | managed => 1, |
---|
| 117 | ro => 1, |
---|
| 118 | get => sub { |
---|
| 119 | my ($self) = @_; |
---|
| 120 | my $now = DateTime->now; |
---|
| 121 | if ($now->epoch < str2time($self->object->get_attributes('firstday'))) { |
---|
| 122 | return 1; |
---|
| 123 | } elsif ( my $end = $self->object->get_attributes('lastday') ) { |
---|
| 124 | my $eend = str2time($end) + 86400; |
---|
| 125 | if ($now->epoch > $eend) { |
---|
| 126 | return -1; |
---|
[1832] | 127 | } else { |
---|
| 128 | return 0; |
---|
[1500] | 129 | } |
---|
[1516] | 130 | } else { |
---|
| 131 | return 0; |
---|
| 132 | } |
---|
[1500] | 133 | }, |
---|
[1550] | 134 | label => l('State'), |
---|
[1516] | 135 | }, |
---|
| 136 | contratType => { |
---|
| 137 | reference => 'group', |
---|
| 138 | can_values => sub { |
---|
| 139 | $base->search_objects('group', 'sutype=contrattype') |
---|
[1489] | 140 | }, |
---|
[1516] | 141 | monitored => 1, |
---|
[1550] | 142 | label => l('Type of contract'), |
---|
[1516] | 143 | }, |
---|
| 144 | managerContact => { |
---|
| 145 | delayed => 1, |
---|
| 146 | can_values => sub { |
---|
| 147 | my %uniq = map { $_ => 1 } grep { $_ } |
---|
| 148 | ($_[1] ? $_[1]->get_attributes('managerContact') : ()), |
---|
| 149 | $base->search_objects('user', 'active=*'); |
---|
| 150 | sort keys %uniq; |
---|
[1500] | 151 | }, |
---|
[1516] | 152 | reference => 'user', |
---|
[1621] | 153 | label => l('Direct manager'), |
---|
[1516] | 154 | }, |
---|
| 155 | department => { |
---|
| 156 | reference => 'group', |
---|
| 157 | can_values => sub { |
---|
| 158 | $base->search_objects('group', 'sutype=dpmt') |
---|
[1500] | 159 | }, |
---|
[1516] | 160 | monitored => 1, |
---|
[1550] | 161 | label => l('Department'), |
---|
[1516] | 162 | }, |
---|
[1550] | 163 | company => { |
---|
| 164 | label => l('Company'), |
---|
| 165 | }, |
---|
[1860] | 166 | employer => { |
---|
| 167 | label => l('Employer'), |
---|
| 168 | }, |
---|
[1550] | 169 | endcircuit => { |
---|
| 170 | formtype => 'DATE', |
---|
| 171 | monitored => 1, |
---|
[1620] | 172 | label => l('End of entrance circuit'), |
---|
[1550] | 173 | }, |
---|
[1589] | 174 | hosted => { |
---|
| 175 | formtype => 'CHECKBOX', |
---|
| 176 | label => l('Hosted'), |
---|
| 177 | }, |
---|
[2114] | 178 | requestId => { |
---|
| 179 | label => l('Request id') |
---|
[2116] | 180 | }, |
---|
[1516] | 181 | previous => { |
---|
| 182 | ro => 1, |
---|
| 183 | managed => 1, |
---|
| 184 | get => sub { |
---|
| 185 | my ($self) = @_; |
---|
| 186 | my $find = $self->object->base->db->prepare_cached(q{ |
---|
| 187 | SELECT name from employment where "user" = ? |
---|
| 188 | and (lastday is not null and lastday < ?) |
---|
| 189 | order by lastday desc |
---|
| 190 | }); |
---|
| 191 | $find->execute( |
---|
| 192 | $self->object->get_field('user'), |
---|
| 193 | $self->object->get_field('firstday') |
---|
| 194 | ); |
---|
| 195 | my $res = $find->fetchrow_hashref; |
---|
| 196 | $find->finish; |
---|
| 197 | return $res->{name}; |
---|
[1511] | 198 | }, |
---|
[1550] | 199 | label => l('Previous'), |
---|
[1516] | 200 | }, |
---|
[2116] | 201 | 'next' => { |
---|
[1516] | 202 | ro => 1, |
---|
| 203 | managed => 1, |
---|
| 204 | get => sub { |
---|
| 205 | my ($self) = @_; |
---|
| 206 | my $find = $self->object->base->db->prepare_cached(q{ |
---|
| 207 | SELECT name from employment where "user" = ? |
---|
| 208 | and firstday > ? |
---|
| 209 | order by firstday asc |
---|
| 210 | }); |
---|
| 211 | $find->execute( |
---|
| 212 | $self->object->get_field('user'), |
---|
| 213 | $self->object->get_field('lastday') |
---|
| 214 | ); |
---|
| 215 | my $res = $find->fetchrow_hashref; |
---|
| 216 | $find->finish; |
---|
| 217 | return $res->{name}; |
---|
[1511] | 218 | }, |
---|
[1550] | 219 | label => l('Next'), |
---|
[1516] | 220 | }, |
---|
[1537] | 221 | minFirstDay => { |
---|
| 222 | ro => 1, |
---|
| 223 | hidden => 1, |
---|
| 224 | managed => 1, |
---|
| 225 | formtype => 'DATE', |
---|
| 226 | get => sub { |
---|
| 227 | my ($attr) = @_; |
---|
| 228 | my $self = $attr->object; |
---|
| 229 | |
---|
| 230 | my $find = $self->base->db->prepare_cached(q{ |
---|
| 231 | SELECT max(lastday) as lastday FROM employment where "user" = ? |
---|
| 232 | and lastday is not NULL and lastday < ? |
---|
| 233 | }); |
---|
| 234 | |
---|
| 235 | my $first = $self->get_field('firstday'); |
---|
| 236 | |
---|
| 237 | $find->execute( |
---|
| 238 | $self->get_field('user'), |
---|
| 239 | $first |
---|
| 240 | ); |
---|
| 241 | my $res = $find->fetchrow_hashref; |
---|
| 242 | $find->finish; |
---|
| 243 | |
---|
| 244 | if ($res && $res->{lastday}) { |
---|
| 245 | my $dt = DateTime->from_epoch( epoch => str2time($res->{lastday})); |
---|
| 246 | $dt->set_time_zone( DateTime::TimeZone->new( name => 'local' ) ); |
---|
| 247 | $dt->add(days => 1); |
---|
| 248 | if ($first eq $dt->ymd('-')) { |
---|
[1540] | 249 | return $first; |
---|
[1537] | 250 | } else { |
---|
| 251 | return $dt->ymd('-'); |
---|
| 252 | } |
---|
| 253 | } else { |
---|
[1540] | 254 | return; |
---|
[1537] | 255 | } |
---|
| 256 | }, |
---|
[1550] | 257 | label => l('Minimal first day'), |
---|
[1537] | 258 | }, |
---|
| 259 | maxLastDay => { |
---|
| 260 | ro => 1, |
---|
| 261 | hidden => 1, |
---|
| 262 | managed => 1, |
---|
| 263 | formtype => 'DATE', |
---|
| 264 | get => sub { |
---|
| 265 | my ($attr) = @_; |
---|
| 266 | my $self = $attr->object; |
---|
| 267 | |
---|
| 268 | my $find = $self->base->db->prepare_cached(q{ |
---|
| 269 | SELECT min(firstday) as firstday FROM employment where "user" = ? |
---|
| 270 | and firstday > ? |
---|
| 271 | }); |
---|
| 272 | |
---|
| 273 | my $last = $self->get_field('lastday') or do { |
---|
| 274 | # This contract is last then... |
---|
[1540] | 275 | return; |
---|
[1537] | 276 | }; |
---|
| 277 | |
---|
| 278 | $find->execute( |
---|
| 279 | $self->get_field('user'), |
---|
| 280 | $last |
---|
| 281 | ); |
---|
| 282 | my $res = $find->fetchrow_hashref; |
---|
| 283 | $find->finish; |
---|
| 284 | |
---|
| 285 | if ($res && $res->{firstday}) { |
---|
| 286 | my $dt = DateTime->from_epoch( epoch => str2time($res->{firstday})); |
---|
| 287 | $dt->set_time_zone( DateTime::TimeZone->new( name => 'local' ) ); |
---|
| 288 | $dt->subtract(days => 1); |
---|
| 289 | if ($last eq $dt->ymd('-')) { |
---|
[1540] | 290 | return $last; |
---|
[1537] | 291 | } else { |
---|
| 292 | return $dt->ymd('-'); |
---|
| 293 | } |
---|
| 294 | } else { |
---|
[1540] | 295 | return; |
---|
[1537] | 296 | } |
---|
| 297 | }, |
---|
[1550] | 298 | label => l('Maximal last day'), |
---|
[1537] | 299 | }, |
---|
[1516] | 300 | }; |
---|
| 301 | |
---|
[1834] | 302 | if (! $base->config("allow_pasted_employment")) { |
---|
[1516] | 303 | # Completed contract are RO, we allow to still set lastday |
---|
[1860] | 304 | foreach (qw(endcircuit firstday contratType department managerContact company employer)) { |
---|
[1834] | 305 | $attrs->{$_}{ro} = sub { |
---|
| 306 | my ($self) = $_[0]; |
---|
| 307 | $self or return 0; |
---|
| 308 | my $st = $self->get_attributes('state') || '0'; |
---|
| 309 | return $st < 0 ? 1 : 0; |
---|
| 310 | }; |
---|
| 311 | } |
---|
[1516] | 312 | } |
---|
| 313 | $class->SUPER::_get_attr_schema($base, $attrs); |
---|
[1489] | 314 | } |
---|
| 315 | |
---|
| 316 | sub _create { |
---|
| 317 | my ($class, $base, $id, %data) = @_; |
---|
| 318 | $data{user} or return; |
---|
| 319 | my $user = $base->get_object('user', $data{user}); |
---|
| 320 | $user or return; |
---|
[1945] | 321 | my $res = $class->SUPER::_create($base, $id, %data); |
---|
[1949] | 322 | $user->applyCurrentEmployment; |
---|
[1945] | 323 | $res; |
---|
[1489] | 324 | } |
---|
| 325 | |
---|
[1636] | 326 | sub _delete { |
---|
| 327 | my ($class, $base, $id) = @_; |
---|
| 328 | |
---|
| 329 | my $obj = $base->get_object($class->type, $id) |
---|
| 330 | or return; |
---|
| 331 | |
---|
| 332 | my $user = $obj->_get_attributes('user'); |
---|
| 333 | |
---|
| 334 | my $res = $class->SUPER::_delete($base, $id); |
---|
| 335 | if ($res) { |
---|
| 336 | my $ouser = $base->get_object('user', $user); |
---|
[1949] | 337 | $ouser->applyCurrentEmployment; |
---|
[1636] | 338 | } |
---|
| 339 | |
---|
| 340 | $res |
---|
| 341 | } |
---|
| 342 | |
---|
[2075] | 343 | sub _set_c_fields { |
---|
[1945] | 344 | my ($self, %data) = @_; |
---|
| 345 | |
---|
[2075] | 346 | my $res = $self->SUPER::_set_c_fields(%data); |
---|
[1945] | 347 | |
---|
[2075] | 348 | if ($res) { |
---|
| 349 | my $user = $self->base->get_object('user', $self->get_attributes('user')) or do { |
---|
| 350 | $self->base->log(LA_ERR, "Cannot fetch user %s to apply employment", $self->get_attributes('user')); |
---|
| 351 | return; |
---|
| 352 | }; |
---|
[2076] | 353 | |
---|
| 354 | $user->applyCurrentEmployment; |
---|
[2075] | 355 | } |
---|
[1500] | 356 | |
---|
[1950] | 357 | return $res; |
---|
[1500] | 358 | } |
---|
| 359 | |
---|
| 360 | sub checkValues { |
---|
| 361 | my ($class, $base, $obj, %changes) = @_; |
---|
| 362 | |
---|
| 363 | my $user = $changes{user} || $obj->get_attributes('user'); |
---|
| 364 | my $id = ref $obj ? $obj->id : $obj; |
---|
| 365 | |
---|
[1994] | 366 | my $firstday = exists($changes{firstday}) |
---|
| 367 | ? $changes{firstday} : |
---|
[2007] | 368 | ref $obj ? $obj->get_attributes('firstday') : undef; |
---|
[1994] | 369 | my $lastday = exists($changes{lastday}) |
---|
| 370 | ? $changes{lastday} : |
---|
[2007] | 371 | ref $obj ? $obj->get_attributes('lastday') : undef; |
---|
[1787] | 372 | |
---|
| 373 | if ($lastday) { |
---|
[1500] | 374 | my $sth = $base->db->prepare_cached(q{ |
---|
[1787] | 375 | select name, firstday, lastday from employment where "user" = ? and name != ? |
---|
| 376 | and |
---|
| 377 | ( |
---|
| 378 | (firstday <= ? and (lastday is NULL or lastday >= ?)) |
---|
| 379 | or |
---|
| 380 | ((lastday is NOT NULL and lastday <= ?) and firstday >= ?) |
---|
| 381 | ) |
---|
[1500] | 382 | }); |
---|
[1787] | 383 | $sth->execute($user, $id, $lastday, $firstday, $lastday, $firstday); |
---|
[1500] | 384 | my $res = $sth->fetchrow_hashref; |
---|
| 385 | $sth->finish; |
---|
[1787] | 386 | |
---|
[1500] | 387 | if ($res) { |
---|
[1787] | 388 | $base->log(LA_ERR, "The change will overlap contrat %s (%s - %s)", $res->{name}, $res->{firstday}, $res->{lastday} || ''); |
---|
[1500] | 389 | return; |
---|
| 390 | } |
---|
[1994] | 391 | } elsif (!$firstday) { |
---|
| 392 | $base->log(LA_ERR, "No firstday given"); |
---|
| 393 | return; |
---|
[1787] | 394 | } else { |
---|
[1500] | 395 | my $sth = $base->db->prepare_cached(q{ |
---|
[1787] | 396 | select * from employment where "user" = ? and name != ? |
---|
[1811] | 397 | and (lastday is NULL OR lastday >= ?) |
---|
[1500] | 398 | limit 1 |
---|
| 399 | }); |
---|
[1787] | 400 | $sth->execute($user, $id, $firstday); |
---|
[1500] | 401 | my $res = $sth->fetchrow_hashref; |
---|
| 402 | if ($res && $res->{name}) { |
---|
| 403 | if ($id ne $res->{name}) { |
---|
| 404 | $base->log(LA_ERR, "Another contract has no ending (%s)", $res->{name} || ''); |
---|
| 405 | return; |
---|
| 406 | } |
---|
| 407 | } |
---|
| 408 | } |
---|
| 409 | |
---|
| 410 | return 1; |
---|
| 411 | } |
---|
| 412 | |
---|
[1489] | 413 | 1; |
---|
| 414 | |
---|
| 415 | __END__ |
---|
| 416 | |
---|
| 417 | =head1 SEE ALSO |
---|
| 418 | |
---|
| 419 | L<LATMOS::Accounts::Bases::Sql> |
---|
| 420 | |
---|
| 421 | =head1 AUTHOR |
---|
| 422 | |
---|
| 423 | Olivier Thauvin, E<lt>olivier.thauvin@latmos.ipsl.frE<gt> |
---|
| 424 | |
---|
| 425 | =head1 COPYRIGHT AND LICENSE |
---|
| 426 | |
---|
| 427 | Copyright (C) 2008, 2009 CNRS SA/CETP/LATMOS |
---|
| 428 | |
---|
| 429 | This library is free software; you can redistribute it and/or modify |
---|
| 430 | it under the same terms as Perl itself, either Perl version 5.10.0 or, |
---|
| 431 | at your option, any later version of Perl 5 you may have available. |
---|
| 432 | |
---|
| 433 | |
---|
| 434 | =cut |
---|