source: trunk/LATMOS-Accounts/lib/LATMOS/Accounts/Bases/Sql/Employment.pm @ 1904

Last change on this file since 1904 was 1860, checked in by nanardon, 8 years ago

add employer attribute to employment/user

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