Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 33823a77

Von Bernd Bleßmann vor mehr als 3 Jahren hinzugefügt

  • ID 33823a7743de188f6e37802716ee5bd877a3ec5f
  • Vorgänger 22f2c3e8
  • Nachfolger 78edb322

Zeiterfassung: Datum/Dauer statt Start/Ende wählbar (Benutzereinstellung)

Unterschiede anzeigen:

SL/AM.pm
54 54
use SL::GenericTranslations;
55 55
use SL::Helper::UserPreferences::PositionsScrollbar;
56 56
use SL::Helper::UserPreferences::PartPickerSearch;
57
use SL::Helper::UserPreferences::TimeRecording;
57 58
use SL::Helper::UserPreferences::UpdatePositions;
58 59

  
59 60
use strict;
......
546 547
  SL::Helper::UserPreferences::UpdatePositions->new()->get_show_update_button();
547 548
}
548 549

  
550
sub time_recording_use_duration {
551
  SL::Helper::UserPreferences::TimeRecording->new()->get_use_duration();
552
}
553

  
549 554
sub save_preferences {
550 555
  $main::lxdebug->enter_sub();
551 556

  
......
583 588
  if (exists $form->{positions_show_update_button}) {
584 589
    SL::Helper::UserPreferences::UpdatePositions->new()->store_show_update_button($form->{positions_show_update_button})
585 590
  }
591
  if (exists $form->{time_recording_use_duration}) {
592
    SL::Helper::UserPreferences::TimeRecording->new()->store_use_duration($form->{time_recording_use_duration})
593
  }
586 594

  
587 595
  $main::lxdebug->leave_sub();
588 596

  
SL/Controller/TimeRecording.pm
14 14
use SL::DB::Part;
15 15
use SL::DB::TimeRecording;
16 16
use SL::DB::TimeRecordingArticle;
17
use SL::Helper::Flash qw(flash);
18
use SL::Helper::UserPreferences::TimeRecording;
17 19
use SL::Locale::String qw(t8);
18 20
use SL::ReportGenerator;
19 21

  
20 22
use Rose::Object::MakeMethods::Generic
21 23
(
22 24
# scalar                  => [ qw() ],
23
 'scalar --get_set_init' => [ qw(time_recording models all_employees all_time_recording_articles can_view_all can_edit_all) ],
25
 'scalar --get_set_init' => [ qw(time_recording models all_employees all_time_recording_articles can_view_all can_edit_all use_duration) ],
24 26
);
25 27

  
26 28

  
......
65 67

  
66 68
  $::request->{layout}->use_javascript("${_}.js") for qw(kivi.TimeRecording ckeditor/ckeditor ckeditor/adapters/jquery kivi.Validator);
67 69

  
70
  if ($self->use_duration) {
71
    flash('warning', t8('This entry is using start and end time. This information will be overwritten on saving.')) if !$self->time_recording->is_duration_used;
72
  } else {
73
    flash('warning', t8('This entry is using date and duration. This information will be overwritten on saving.'))  if $self->time_recording->is_duration_used;
74
  }
75

  
68 76
  if ($self->time_recording->start_time) {
69 77
    $self->{start_date} = $self->time_recording->start_time->to_kivitendo;
70 78
    $self->{start_time} = $self->time_recording->start_time->to_kivitendo_time;
......
84 92
sub action_save {
85 93
  my ($self) = @_;
86 94

  
95
  if ($self->use_duration) {
96
    $self->time_recording->start_date(undef);
97
    $self->time_recording->end_date(undef);
98
  }
99

  
87 100
  my @errors = $self->time_recording->validate;
88 101
  if (@errors) {
89 102
    $::form->error(t8('Saving the time recording entry failed: #1', join '<br>', @errors));
......
107 120
}
108 121

  
109 122
sub init_time_recording {
123
  my ($self) = @_;
124

  
110 125
  my $is_new         = !$::form->{id};
111
  my $time_recording = $is_new ? SL::DB::TimeRecording->new(start_time => DateTime->now_local)
112
                               : SL::DB::TimeRecording->new(id => $::form->{id})->load;
126
  my $time_recording = !$is_new            ? SL::DB::TimeRecording->new(id => $::form->{id})->load
127
                     : $self->use_duration ? SL::DB::TimeRecording->new(date => DateTime->today_local)
128
                     :                       SL::DB::TimeRecording->new(start_time => DateTime->now_local);
113 129

  
114 130
  my %attributes = %{ $::form->{time_recording} || {} };
115 131

  
116
  foreach my $type (qw(start end)) {
117
    if ($::form->{$type . '_date'}) {
118
      my $date = DateTime->from_kivitendo($::form->{$type . '_date'});
119
      $attributes{$type . '_time'} = $date->clone;
120
      if ($::form->{$type . '_time'}) {
121
        my ($hour, $min) = split ':', $::form->{$type . '_time'};
122
        $attributes{$type . '_time'}->set_hour($hour)  if $hour;
123
        $attributes{$type . '_time'}->set_minute($min) if $min;
132
  if (!$self->use_duration) {
133
    foreach my $type (qw(start end)) {
134
      if ($::form->{$type . '_date'}) {
135
        my $date = DateTime->from_kivitendo($::form->{$type . '_date'});
136
        $attributes{$type . '_time'} = $date->clone;
137
        if ($::form->{$type . '_time'}) {
138
          my ($hour, $min) = split ':', $::form->{$type . '_time'};
139
          $attributes{$type . '_time'}->set_hour($hour)  if $hour;
140
          $attributes{$type . '_time'}->set_minute($min) if $min;
141
        }
124 142
      }
125 143
    }
126 144
  }
127 145

  
128
  # do not overwright staff member if you do not have the right
146
  # do not overwrite staff member if you do not have the right
129 147
  delete $attributes{staff_member_id} if !$_[0]->can_edit_all;
130 148
  $attributes{staff_member_id} = SL::DB::Manager::Employee->current->id if $is_new;
131 149

  
......
178 196
  return $res;
179 197
}
180 198

  
199
sub init_use_duration {
200
  return SL::Helper::UserPreferences::TimeRecording->new()->get_use_duration();
201
}
202

  
181 203
sub check_auth {
182 204
  $::auth->assert('time_recording');
183 205
}
......
255 277
  my $staff_member = $filter->{staff_member_id} ? SL::DB::Employee->new(id => $filter->{staff_member_id})->load->safe_name : '';
256 278

  
257 279
  my @filters = (
258
    [ $filter->{"start_time:date::ge"},                        t8('From Start')      ],
259
    [ $filter->{"start_time:date::le"},                        t8('To Start')        ],
280
    [ $filter->{"date:date::ge"},                              t8('From Date')      ],
281
    [ $filter->{"date:date::le"},                              t8('To Date')        ],
260 282
    [ $filter->{"customer"}->{"name:substr::ilike"},           t8('Customer')        ],
261 283
    [ $filter->{"customer"}->{"customernumber:substr::ilike"}, t8('Customer Number') ],
262 284
    [ $staff_member,                                           t8('Mitarbeiter')     ],
SL/DB/TimeRecording.pm
33 33

  
34 34
  my @errors;
35 35

  
36
  push @errors, t8('Start time must not be empty.')                            if !$self->start_time;
37 36
  push @errors, t8('Customer must not be empty.')                              if !$self->customer_id;
38 37
  push @errors, t8('Staff member must not be empty.')                          if !$self->staff_member_id;
39 38
  push @errors, t8('Employee must not be empty.')                              if !$self->employee_id;
......
109 108
  return;
110 109
}
111 110

  
111
sub is_duration_used {
112
  return !$_[0]->start_time;
113
}
114

  
112 115
sub displayable_times {
113 116
  my ($self) = @_;
114 117

  
SL/Helper/UserPreferences/TimeRecording.pm
1
package SL::Helper::UserPreferences::TimeRecording;
2

  
3
use strict;
4
use parent qw(Rose::Object);
5

  
6
use Carp;
7
use List::MoreUtils qw(none);
8

  
9
use SL::Helper::UserPreferences;
10

  
11
use Rose::Object::MakeMethods::Generic (
12
  'scalar --get_set_init' => [ qw(user_prefs) ],
13
);
14

  
15
sub get_use_duration {
16
  !!$_[0]->user_prefs->get('use_duration');
17
}
18

  
19
sub store_use_duration {
20
  $_[0]->user_prefs->store('use_duration', $_[1]);
21
}
22

  
23
sub init_user_prefs {
24
  SL::Helper::UserPreferences->new(
25
    namespace => $_[0]->namespace,
26
  )
27
}
28

  
29
# read only stuff
30
sub namespace     { 'TimeRecording' }
31
sub version       { 1 }
32

  
33
1;
34

  
35
__END__
36

  
37
=pod
38

  
39
=encoding utf-8
40

  
41
=head1 NAME
42

  
43
SL::Helper::UserPreferences::TimeRecording - preferences intended
44
to store user settings for using the time recording functionality.
45

  
46
=head1 SYNOPSIS
47

  
48
  use SL::Helper::UserPreferences::TimeRecording;
49
  my $prefs = SL::Helper::UserPreferences::TimeRecording->new();
50

  
51
  $prefs->store_use_duration(1);
52
  my $value = $prefs->get_use_duration;
53

  
54
=head1 DESCRIPTION
55

  
56
This module manages storing the user's choise for settings for
57
the time recording controller.
58
For now it can be choosen if an entry is done by entering start and
59
end time or a date and a duration.
60

  
61
=head1 BUGS
62

  
63
None yet :)
64

  
65
=head1 AUTHOR
66

  
67
Bernd Bleßmann E<lt>bernd@kivitendo-premium.deE<gt>
68

  
69
=cut
bin/mozilla/am.pl
664 664
  $form->{purchase_search_makemodel}        = AM->purchase_search_makemodel();
665 665
  $form->{sales_search_customer_partnumber} = AM->sales_search_customer_partnumber();
666 666
  $form->{positions_show_update_button}     = AM->positions_show_update_button();
667
  $form->{time_recording_use_duration}      = AM->time_recording_use_duration();
667 668

  
668 669
  $myconfig{show_form_details} = 1 unless (defined($myconfig{show_form_details}));
669 670
  $form->{CAN_CHANGE_PASSWORD} = $main::auth->can_change_password();
locale/de/all
1542 1542
  'Fristsetzung'                => 'Fristsetzung',
1543 1543
  'From'                        => 'Von',
1544 1544
  'From Date'                   => 'Von',
1545
  'From Start'                  => 'Ab Start',
1546 1545
  'From bin'                    => 'Ausgelagert',
1547 1546
  'From shop "#1" :  #2 '       => 'Shop #1 : #2',
1548 1547
  'From shop #1 :  #2 shoporders have been fetched.' => 'Es wurden #2 Bestellungen von #1 geholt.',
......
3137 3136
  'Start the correction assistant' => 'Korrekturassistenten starten',
3138 3137
  'Start time'                  => 'Startzeit',
3139 3138
  'Start time must be earlier than end time.' => 'Startzeit muss vor der Endzeit liegen.',
3140
  'Start time must not be empty.' => 'Startzeit darf nicht leer sein.',
3141 3139
  'Startdate method'            => 'Methode zur Ermittlung des Startdatums',
3142 3140
  'Startdate_coa'               => 'Gültig ab',
3143 3141
  'Starting Balance'            => 'Eröffnungsbilanzwerte',
......
3694 3692
  'This discount is only valid in purchase documents' => 'Dieser Rabatt ist nur in Einkaufsdokumenten gültig',
3695 3693
  'This discount is only valid in records with customer or vendor' => 'Dieser Rabatt ist nur in Dokumenten mit Kunde oder Lieferant gültig',
3696 3694
  'This discount is only valid in sales documents' => 'Dieser Rabatt ist nur in Verkaufsdokumenten gültig',
3695
  'This entry is using date and duration. This information will be overwritten on saving.' => 'Dieser Eintrag verwendet Datum und Dauer. Diese Information wird beim Speichern überschrieben.',
3696
  'This entry is using start and end time. This information will be overwritten on saving.' => 'Dieser Eintrag verwendet Start- und End-Zeit. Diese Information wird beim Speichern überschrieben.',
3697 3697
  'This export will include all records in the given time range and all supplicant information from checked entities. You will receive a single zip file. Please extract this file onto the data medium requested by your auditor.' => 'Dieser Export umfasst alle Belege im gewählten Zeitrahmen und die dazugehörgen Informationen aus den gewählten Blöcken. Sie erhalten eine einzelne Zip-Datei. Bitte entpacken Sie diese auf das Medium das Ihr Steuerprüfer wünscht.',
3698 3698
  'This feature especially prevents mistakes by mixing up prior tax and sales tax.' => 'Dieses Feature vermeidet insbesondere Verwechslungen von Umsatz- und Vorsteuer.',
3699 3699
  'This field must not be empty.' => 'Dieses Feld darf nicht leer sein.',
......
3770 3770
  'To (email)'                  => 'An',
3771 3771
  'To (time)'                   => 'Bis',
3772 3772
  'To Date'                     => 'Bis',
3773
  'To Start'                    => 'Bis Start',
3774 3773
  'To continue please change the taxkey 0 to another value.' => 'Um fortzufahren, ändern Sie bitte den Steuerschlüssel 0 auf einen anderen Wert.',
3775 3774
  'To import'                   => 'Zu importieren',
3776 3775
  'To upload images: Please create shoppart first' => 'Um Bilder hochzuladen bitte Shopartikel zuerst anlegen',
......
3945 3944
  'Use a text field to enter (new) contact titles if enabled. Otherwise, only a drop down box is offered.' => 'Textfeld zusätzlich zur Eingabe (neuer) Titel von Ansprechpersonen verwenden. Sonst wird nur eine Auswahlliste angezeigt.',
3946 3945
  'Use a text field to enter (new) greetings if enabled. Otherwise, only a drop down box is offered.' => 'Textfeld zusätzlich zur Eingabe (neuer) Anreden verwenden. Sonst wird nur eine Auswahlliste angezeigt.',
3947 3946
  'Use as new'                  => 'Als neu verwenden',
3947
  'Use date and duration for time recordings' => 'Datum und Dauer für Zeiterfassung verwenden',
3948 3948
  'Use default booking group because setting is \'all\'' => 'Standardbuchungsgruppe wird verwendet',
3949 3949
  'Use default booking group because wanted is missing' => 'Fehlende Buchungsgruppe, deshalb Standardbuchungsgruppe',
3950 3950
  'Use default warehouse for assembly transfer' => 'Zum Fertigen Standardlager des Bestandteils verwenden',
......
4269 4269
  'http'                        => 'http',
4270 4270
  'https'                       => 'https',
4271 4271
  'imported'                    => 'Importiert',
4272
  'in minutes'                  => 'in Minuten',
4272 4273
  'inactive'                    => 'inaktiv',
4273 4274
  'income'                      => 'Einnahmen-Überschuß-Rechnung',
4274 4275
  'internal error (see details)' => 'Interner Fehler (siehe Details)!',
locale/en/all
1542 1542
  'Fristsetzung'                => '',
1543 1543
  'From'                        => '',
1544 1544
  'From Date'                   => '',
1545
  'From Start'                  => '',
1546 1545
  'From bin'                    => '',
1547 1546
  'From shop "#1" :  #2 '       => '',
1548 1547
  'From shop #1 :  #2 shoporders have been fetched.' => '',
......
3136 3135
  'Start the correction assistant' => '',
3137 3136
  'Start time'                  => '',
3138 3137
  'Start time must be earlier than end time.' => '',
3139
  'Start time must not be empty.' => '',
3140 3138
  'Startdate method'            => '',
3141 3139
  'Startdate_coa'               => '',
3142 3140
  'Starting Balance'            => '',
......
3692 3690
  'This discount is only valid in purchase documents' => '',
3693 3691
  'This discount is only valid in records with customer or vendor' => '',
3694 3692
  'This discount is only valid in sales documents' => '',
3693
  'This entry is using date and duration. This information will be overwritten on saving.' => '',
3694
  'This entry is using start and end time. This information will be overwritten on saving.' => '',
3695 3695
  'This export will include all records in the given time range and all supplicant information from checked entities. You will receive a single zip file. Please extract this file onto the data medium requested by your auditor.' => '',
3696 3696
  'This feature especially prevents mistakes by mixing up prior tax and sales tax.' => '',
3697 3697
  'This field must not be empty.' => '',
......
3768 3768
  'To (email)'                  => '',
3769 3769
  'To (time)'                   => '',
3770 3770
  'To Date'                     => '',
3771
  'To Start'                    => '',
3772 3771
  'To continue please change the taxkey 0 to another value.' => '',
3773 3772
  'To import'                   => '',
3774 3773
  'To upload images: Please create shoppart first' => '',
......
3943 3942
  'Use a text field to enter (new) contact titles if enabled. Otherwise, only a drop down box is offered.' => '',
3944 3943
  'Use a text field to enter (new) greetings if enabled. Otherwise, only a drop down box is offered.' => '',
3945 3944
  'Use as new'                  => '',
3945
  'Use date and duration for time recordings' => '',
3946 3946
  'Use default booking group because setting is \'all\'' => '',
3947 3947
  'Use default booking group because wanted is missing' => '',
3948 3948
  'Use default warehouse for assembly transfer' => '',
......
4267 4267
  'http'                        => '',
4268 4268
  'https'                       => '',
4269 4269
  'imported'                    => '',
4270
  'in minutes'                  => '',
4270 4271
  'inactive'                    => '',
4271 4272
  'income'                      => 'GUV and BWA',
4272 4273
  'internal error (see details)' => '',
templates/webpages/am/config.html
87 87
        </td>
88 88
      </tr>
89 89

  
90
     <tr>
91
      <th align="right">[% 'Use date and duration for time recordings' | $T8 %]</th>
92
      <td>
93
        [% L.yes_no_tag('time_recording_use_duration', time_recording_use_duration) %]
94
      </td>
95
     </tr>
96

  
90 97
    </table>
91 98
   </div>
92 99

  
templates/webpages/time_recording/form.html
15 15
  <table>
16 16
    <thead class="listheading">
17 17
      <tr>
18
       [%- IF SELF.use_duration %]
19
        <th>[% 'Date'     | $T8 %]</th>
20
        <th>[% 'Duration' | $T8 %] ([% 'in minutes' | $T8 %])</th>
21
       [%- ELSE %]
18 22
        <th>[% 'Start' | $T8 %]</th>
19
        <th>[% 'End' | $T8 %]</th>
23
        <th>[% 'End'   | $T8 %]</th>
24
       [%- END %]
20 25
        <th>[% 'Customer' | $T8 %]</th>
21 26
        <th>[% 'Article' | $T8 %]</th>
22 27
        <th>[% 'Project' | $T8 %]</th>
......
26 31
    </thead>
27 32
    <tbody valign="top">
28 33
      <tr>
34
       [%- IF SELF.use_duration %]
35
        <td>
36
          [% P.date_tag('time_recording.date_as_date', SELF.time_recording.date_as_date, "data-validate"="required", "data-title"=LxERP.t8('Date')) %]<br>
37
        </td>
38
        <td>
39
          [% P.input_tag('time_recording.duration', SELF.time_recording.duration, size=15) %]
40
        </td>
41
       [%- ELSE %]
29 42
        <td>
30 43
          [% P.date_tag('start_date',  SELF.start_date, "data-validate"="required", "data-title"=LxERP.t8('Start date'), onchange='kivi.TimeRecording.set_end_date()') %]<br>
31 44
          [% P.input_tag('start_time', SELF.start_time, type="time", "data-validate"="required", "data-title"=LxERP.t8('Start time')) %]
......
36 49
          [% P.input_tag('end_time', SELF.end_time, type="time") %]
37 50
          [% P.button_tag('kivi.TimeRecording.set_current_date_time("end")', LxERP.t8('now')) %]
38 51
        </td>
52
       [%- END %]
39 53
        <td>[% P.customer_vendor.picker('time_recording.customer_id', SELF.time_recording.customer_id, type='customer', style='width: 300px', "data-validate"="required", "data-title"=LxERP.t8('Customer')) %]</td>
40 54
        <td>[% P.select_tag('time_recording.part_id', SELF.all_time_recording_articles, default=SELF.time_recording.part_id, with_empty=1, value_key='id', title_key='description') %]</td>
41 55
        <td>[% P.project.picker('time_recording.project_id', SELF.time_recording.project_id, style='width: 300px') %]</td>

Auch abrufbar als: Unified diff