Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision bc182129

Von Moritz Bunkus vor etwa 5 Jahren hinzugefügt

  • ID bc18212984364980013862cc5515a125ccff6e6d
  • Vorgänger 4ad4574f

Berechtigung, Rechnungen persönlich zugeordneter Projekte einzusehen

Man kann nun Mitarbeiter*innen zu Projekten zuordnen, indem man sie in
den Projektstammdaten hinzufügt.

Ist eine Mitarbeiter*in zu einem Projekt zugeordnet, so darf sie alle
Rechnungen ansehen, die über die Projektnummer der Rechnung (nicht der
Positionen) dem Projekt zugeordnet sind, auch dann, wenn sie nicht das
allgemeine Recht zum Erstellen und Ansehen von Rechnungen hat.

Verändern oder Ausdrucken der Rechnungen ist nicht gestattet.

Die Verwaltung dieser Projektberechtigungen ist über ein neues
Gruppenrecht eingeschränkt.

Unterschiede anzeigen:

SL/AR.pm
516 516

  
517 517
  my $where = "1 = 1";
518 518

  
519
  unless ( $::auth->assert('show_ar_transactions', 1) ) {
520
    $where .= " AND NOT invoice = 'f' ";  # remove ar transactions from Sales -> Reports -> Invoices
521
  };
519
  # Permissions:
520
  # - Always return invoices & AR transactions for projects the employee has "view invoices" permissions for, no matter what the other rules say.
521
  # - Exclude AR transactions if no permissions for them exist.
522
  # - Limit to own invoices unless may edit all invoices.
523
  # - If may edit all, allow filtering by employee/salesman.
524
  my (@permission_where, @permission_values);
525

  
526
  if (!$::auth->assert('show_ar_transactions', 1) ) {
527
    push @permission_where, "NOT invoice = 'f'";  # remove ar transactions from Sales -> Reports -> Invoices
528
  }
529

  
530
  if (!$::auth->assert('sales_all_edit', 1)) {
531
    # only show own invoices
532
    push @permission_where,  "a.employee_id = ?";
533
    push @permission_values, SL::DB::Manager::Employee->current->id;
534

  
535
  } else {
536
    if ($form->{employee_id}) {
537
      push @permission_where,  "a.employee_id = ?";
538
      push @permission_values, conv_i($form->{employee_id});
539
    }
540
    if ($form->{salesman_id}) {
541
      push @permission_where,  "a.salesman_id = ?";
542
      push @permission_values, conv_i($form->{salesman_id});
543
    }
544
  }
545

  
546
  if (@permission_where) {
547
    my $permission_where_str = "OR (" . join(" AND ", map { "($_)" } @permission_where) . ")";
548
    $where .= qq|
549
      AND (   (a.globalproject_id IN (
550
               SELECT epi.project_id
551
               FROM employee_project_invoices epi
552
               WHERE epi.employee_id = ?))
553
           $permission_where_str)
554
    |;
555
    push @values, SL::DB::Manager::Employee->current->id, @permission_values;
556
  }
522 557

  
523 558
  if ($form->{customer}) {
524 559
    $where .= " AND c.name ILIKE ?";
......
578 613
    }
579 614
  }
580 615

  
581
  if (!$main::auth->assert('sales_all_edit', 1)) {
582
    # only show own invoices
583
    $where .= " AND a.employee_id = (select id from employee where login= ?)";
584
    push (@values, $::myconfig{login});
585
  } else {
586
    if ($form->{employee_id}) {
587
      $where .= " AND a.employee_id = ?";
588
      push @values, conv_i($form->{employee_id});
589
    }
590
    if ($form->{salesman_id}) {
591
      $where .= " AND a.salesman_id = ?";
592
      push @values, conv_i($form->{salesman_id});
593
    }
594
  };
595

  
596 616
  if ($form->{parts_partnumber}) {
597 617
    $where .= <<SQL;
598 618
      AND EXISTS (
SL/Controller/Project.pm
12 12
use SL::CVar;
13 13
use SL::DB::Customer;
14 14
use SL::DB::DeliveryOrder;
15
use SL::DB::Employee;
15 16
use SL::DB::Invoice;
16 17
use SL::DB::Order;
17 18
use SL::DB::Project;
......
29 30
use Rose::Object::MakeMethods::Generic
30 31
(
31 32
 scalar => [ qw(project) ],
32
 'scalar --get_set_init' => [ qw(models customers project_types project_statuses projects linked_records) ],
33
 'scalar --get_set_init' => [ qw(models customers project_types project_statuses projects linked_records employees may_edit_invoice_permissions) ],
33 34
);
34 35

  
35 36
__PACKAGE__->run_before('check_auth',   except => [ qw(ajax_autocomplete) ]);
36 37
__PACKAGE__->run_before('load_project', only   => [ qw(edit update destroy) ]);
38
__PACKAGE__->run_before('use_multiselect_js', only => [ qw(new create edit update) ]);
37 39

  
38 40
#
39 41
# actions
......
166 168

  
167 169
sub init_project_statuses { SL::DB::Manager::ProjectStatus->get_all_sorted }
168 170
sub init_project_types    { SL::DB::Manager::ProjectType->get_all_sorted   }
171
sub init_employees        { SL::DB::Manager::Employee->get_all_sorted   }
172
sub init_may_edit_invoice_permissions { $::auth->assert('project_edit_view_invoices_permission', 1) }
169 173

  
170 174
sub init_linked_records {
171 175
  my ($self) = @_;
......
223 227
  return SL::DB::Manager::Customer->get_all_sorted(where => [ or => [ obsolete => 0, obsolete => undef, @customer_id ]]);
224 228
}
225 229

  
230
sub use_multiselect_js {
231
  $::request->layout->use_javascript("${_}.js") for qw(jquery.selectboxes jquery.multiselect2side);
232
}
233

  
226 234
sub display_form {
227 235
  my ($self, %params) = @_;
228 236

  
......
246 254
  my $is_new = !$self->project->id;
247 255
  my $params = delete($::form->{project}) || { };
248 256

  
257
  if (!$self->may_edit_invoice_permissions) {
258
    delete $params->{employee_invoice_permissions};
259
  } elsif (!$params->{employee_invoice_permissions}) {
260
    $params->{employee_invoice_permissions} = [];
261
  }
262

  
249 263
  delete $params->{id};
250 264
  $self->project->assign_attributes(%{ $params });
251 265

  
SL/DB/Employee.pm
5 5
use SL::DB::MetaSetup::Employee;
6 6
use SL::DB::Manager::Employee;
7 7

  
8
__PACKAGE__->meta->add_relationship(
9
  project_invoice_permissions  => {
10
    type       => 'many to many',
11
    map_class  => 'SL::DB::EmployeeProjectInvoices',
12
  },
13
);
14

  
8 15
__PACKAGE__->meta->initialize;
9 16

  
10 17
sub has_right {
SL/DB/EmployeeProjectInvoices.pm
1
package SL::DB::EmployeeProjectInvoices;
2

  
3
use strict;
4

  
5
use SL::DB::MetaSetup::EmployeeProjectInvoices;
6
use SL::DB::Manager::EmployeeProjectInvoices;
7

  
8
__PACKAGE__->meta->initialize;
9

  
10
1;
SL/DB/Helper/ALL.pm
52 52
use SL::DB::EmailJournal;
53 53
use SL::DB::EmailJournalAttachment;
54 54
use SL::DB::Employee;
55
use SL::DB::EmployeeProjectInvoices;
55 56
use SL::DB::Exchangerate;
56 57
use SL::DB::File;
57 58
use SL::DB::Finanzamt;
SL/DB/Helper/Mappings.pm
136 136
  email_journal                  => 'EmailJournal',
137 137
  email_journal_attachments      => 'EmailJournalAttachment',
138 138
  employee                       => 'employee',
139
  employee_project_invoices      => 'EmployeeProjectInvoices',
139 140
  exchangerate                   => 'exchangerate',
140 141
  files                          => 'file',
141 142
  finanzamt                      => 'finanzamt',
SL/DB/Manager/EmployeeProjectInvoices.pm
1
package SL::DB::Manager::EmployeeProjectInvoices;
2

  
3
use strict;
4

  
5
use parent qw(SL::DB::Helper::Manager);
6

  
7
sub object_class { 'SL::DB::EmployeeProjectInvoices' }
8

  
9
__PACKAGE__->make_manager_methods;
10

  
11
1;
SL/DB/MetaSetup/EmployeeProjectInvoices.pm
1
# This file has been auto-generated. Do not modify it; it will be overwritten
2
# by rose_auto_create_model.pl automatically.
3
package SL::DB::EmployeeProjectInvoices;
4

  
5
use strict;
6

  
7
use parent qw(SL::DB::Object);
8

  
9
__PACKAGE__->meta->table('employee_project_invoices');
10

  
11
__PACKAGE__->meta->columns(
12
  employee_id => { type => 'integer', not_null => 1 },
13
  project_id  => { type => 'integer', not_null => 1 },
14
);
15

  
16
__PACKAGE__->meta->primary_key_columns([ 'employee_id', 'project_id' ]);
17

  
18
__PACKAGE__->meta->foreign_keys(
19
  employee => {
20
    class       => 'SL::DB::Employee',
21
    key_columns => { employee_id => 'id' },
22
  },
23

  
24
  project => {
25
    class       => 'SL::DB::Project',
26
    key_columns => { project_id => 'id' },
27
  },
28
);
29

  
30
1;
31
;
SL/DB/Project.pm
12 12
  cvars_alias => 1,
13 13
);
14 14

  
15
__PACKAGE__->meta->add_relationship(
16
  employee_invoice_permissions  => {
17
    type       => 'many to many',
18
    map_class  => 'SL::DB::EmployeeProjectInvoices',
19
  },
20
);
21

  
15 22
__PACKAGE__->meta->initialize;
16 23

  
17 24
sub validate {
......
84 91
  return $description;
85 92
}
86 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

  
87 111
1;
88 112

  
89 113
__END__
bin/mozilla/ar.pl
89 89
# $locale->text('Nov')
90 90
# $locale->text('Dec')
91 91

  
92
sub _may_view_or_edit_this_invoice {
93
  return 1 if  $::auth->assert('ar_transactions', 1); # may edit all invoices
94
  return 0 if !$::form->{id};                         # creating new invoices isn't allowed without invoice_edit
95
  return 0 if !$::form->{globalproject_id};           # existing records without a project ID are not allowed
96
  return SL::DB::Project->new(id => $::form->{globalproject_id})->load->may_employee_view_project_invoices(SL::DB::Manager::Employee->current);
97
}
98

  
99
sub _assert_access {
100
  my $cache = $::request->cache('ar.pl::_assert_access');
101

  
102
  $cache->{_may_view_or_edit_this_invoice} = _may_view_or_edit_this_invoice()                              if !exists $cache->{_may_view_or_edit_this_invoice};
103
  $::form->show_generic_error($::locale->text("You do not have the permissions to access this function.")) if !       $cache->{_may_view_or_edit_this_invoice};
104
}
105

  
92 106
sub load_record_template {
93 107
  $::auth->assert('ar_transactions');
94 108

  
......
249 263
sub edit {
250 264
  $main::lxdebug->enter_sub();
251 265

  
252
  $main::auth->assert('ar_transactions');
266
  # Delay access check to after the invoice's been loaded in
267
  # "create_links" so that project-specific invoice rights can be
268
  # evaluated.
253 269

  
254 270
  my $form     = $main::form;
255 271

  
......
268 284
sub display_form {
269 285
  $main::lxdebug->enter_sub();
270 286

  
271
  $main::auth->assert('ar_transactions');
287
  _assert_access();
272 288

  
273 289
  my $form     = $main::form;
274 290

  
......
287 303
sub create_links {
288 304
  $main::lxdebug->enter_sub();
289 305

  
290
  $main::auth->assert('ar_transactions');
306
  # Delay access check to after the invoice's been loaded so that
307
  # project-specific invoice rights can be evaluated.
291 308

  
292 309
  my %params   = @_;
293 310
  my $form     = $main::form;
......
296 313
  $form->create_links("AR", \%myconfig, "customer");
297 314
  $form->{invoice_obj} = _retrieve_invoice_object();
298 315

  
316
  _assert_access();
317

  
299 318
  my %saved;
300 319
  if (!$params{dont_save}) {
301 320
    %saved = map { ($_ => $form->{$_}) } qw(direct_debit id taxincluded);
......
329 348
sub form_header {
330 349
  $main::lxdebug->enter_sub();
331 350

  
332
  $main::auth->assert('ar_transactions');
351
  _assert_access();
333 352

  
334 353
  my $form     = $main::form;
335 354
  my %myconfig = %main::myconfig;
......
528 547
sub form_footer {
529 548
  $main::lxdebug->enter_sub();
530 549

  
531
  $main::auth->assert('ar_transactions');
550
  _assert_access();
532 551

  
533 552
  my $form     = $main::form;
534 553
  my %myconfig = %main::myconfig;
......
913 932
sub search {
914 933
  $main::lxdebug->enter_sub();
915 934

  
916
  $main::auth->assert('invoice_edit');
917

  
918 935
  my $form     = $main::form;
919 936
  my %myconfig = %main::myconfig;
920 937
  my $locale   = $main::locale;
......
969 986
sub ar_transactions {
970 987
  $main::lxdebug->enter_sub();
971 988

  
972
  $main::auth->assert('invoice_edit');
973

  
974 989
  my $form     = $main::form;
975 990
  my %myconfig = %main::myconfig;
976 991
  my $locale   = $main::locale;
......
1254 1269

  
1255 1270
  my $is_storno               = IS->is_storno(\%::myconfig, $::form, 'ar', $::form->{id});
1256 1271
  my $has_storno              = IS->has_storno(\%::myconfig, $::form, 'ar');
1272
  my $may_edit_create         = $::auth->assert('ar_transactions', 1);
1257 1273

  
1258 1274
  for my $bar ($::request->layout->get('actionbar')) {
1259 1275
    $bar->add(
......
1262 1278
        submit    => [ '#form', { action => "update" } ],
1263 1279
        id        => 'update_button',
1264 1280
        checks    => [ 'kivi.validate_form' ],
1281
        disabled  => !$may_edit_create ? t8('You must not change this AR transaction.') : undef,
1265 1282
        accesskey => 'enter',
1266 1283
      ],
1267 1284

  
......
1270 1287
          t8('Post'),
1271 1288
          submit   => [ '#form', { action => "post" } ],
1272 1289
          checks   => [ 'kivi.validate_form', 'kivi.AR.check_fields_before_posting' ],
1273
          disabled => $is_closed                                  ? t8('The billing period has already been locked.')
1290
          disabled => !$may_edit_create                           ? t8('You must not change this AR transaction.')
1291
                    : $is_closed                                  ? t8('The billing period has already been locked.')
1274 1292
                    : $is_storno                                  ? t8('A canceled invoice cannot be posted.')
1275 1293
                    : ($::form->{id} && $change_never)            ? t8('Changing invoices has been disabled in the configuration.')
1276 1294
                    : ($::form->{id} && $change_on_same_day_only) ? t8('Invoices can only be changed on the day they are posted.')
......
1279 1297
        action => [
1280 1298
          t8('Post Payment'),
1281 1299
          submit   => [ '#form', { action => "post_payment" } ],
1282
          disabled => !$::form->{id} ? t8('This invoice has not been posted yet.') : undef,
1300
          disabled => !$may_edit_create ? t8('You must not change this AR transaction.')
1301
                    : !$::form->{id}    ? t8('This invoice has not been posted yet.')
1302
                    :                     undef,
1283 1303
        ],
1284 1304
        action => [ t8('Mark as paid'),
1285 1305
          submit   => [ '#form', { action => "mark_as_paid" } ],
1286 1306
          confirm  => t8('This will remove the invoice from showing as unpaid even if the unpaid amount does not match the amount. Proceed?'),
1287
          disabled => !$::form->{id} ? t8('This invoice has not been posted yet.') : undef,
1307
          disabled => !$may_edit_create ? t8('You must not change this AR transaction.')
1308
                    : !$::form->{id}    ? t8('This invoice has not been posted yet.')
1309
                    :                     undef,
1288 1310
          only_if  => $::instance_conf->get_is_show_mark_as_paid,
1289 1311
        ],
1290 1312
      ], # end of combobox "Post"
......
1294 1316
          submit   => [ '#form', { action => "storno" } ],
1295 1317
          checks   => [ 'kivi.validate_form', 'kivi.AR.check_fields_before_posting' ],
1296 1318
          confirm  => t8('Do you really want to cancel this invoice?'),
1297
          disabled => !$::form->{id}         ? t8('This invoice has not been posted yet.')
1298
                      : $has_storno          ? t8('This invoice has been canceled already.')
1299
                      : $is_storno           ? t8('Reversal invoices cannot be canceled.')
1300
                      : $::form->{totalpaid} ? t8('Invoices with payments cannot be canceled.')
1301
                      :                        undef,
1319
          disabled => !$may_edit_create    ? t8('You must not change this AR transaction.')
1320
                    : !$::form->{id}       ? t8('This invoice has not been posted yet.')
1321
                    : $has_storno          ? t8('This invoice has been canceled already.')
1322
                    : $is_storno           ? t8('Reversal invoices cannot be canceled.')
1323
                    : $::form->{totalpaid} ? t8('Invoices with payments cannot be canceled.')
1324
                    :                        undef,
1302 1325
        ],
1303 1326
        action => [ t8('Delete'),
1304 1327
          submit   => [ '#form', { action => "delete" } ],
1305 1328
          confirm  => t8('Do you really want to delete this object?'),
1306
          disabled => !$::form->{id}           ? t8('This invoice has not been posted yet.')
1329
          disabled => !$may_edit_create        ? t8('You must not change this AR transaction.')
1330
                    : !$::form->{id}           ? t8('This invoice has not been posted yet.')
1307 1331
                    : $change_never            ? t8('Changing invoices has been disabled in the configuration.')
1308 1332
                    : $change_on_same_day_only ? t8('Invoices can only be changed on the day they are posted.')
1309 1333
                    : $is_closed               ? t8('The billing period has already been locked.')
......
1319 1343
          t8('Use As New'),
1320 1344
          submit   => [ '#form', { action => "use_as_new" } ],
1321 1345
          checks   => [ 'kivi.validate_form' ],
1322
          disabled => !$::form->{id} ? t8('This invoice has not been posted yet.') : undef,
1346
          disabled => !$may_edit_create ? t8('You must not change this AR transaction.')
1347
                    : !$::form->{id} ? t8('This invoice has not been posted yet.')
1348
                    :                  undef,
1323 1349
        ],
1324 1350
      ], # end of combobox "Workflow"
1325 1351

  
......
1337 1363
        ],
1338 1364
        action => [
1339 1365
          t8('Record templates'),
1340
          call => [ 'kivi.RecordTemplate.popup', 'ar_transaction' ],
1366
          call     => [ 'kivi.RecordTemplate.popup', 'ar_transaction' ],
1367
          disabled => !$may_edit_create ? t8('You must not change this AR transaction.') : undef,
1341 1368
        ],
1342 1369
        action => [
1343 1370
          t8('Drafts'),
1344 1371
          call     => [ 'kivi.Draft.popup', 'ar', 'invoice', $::form->{draft_id}, $::form->{draft_description} ],
1345
          disabled => $::form->{id} ? t8('This invoice has already been posted.')
1346
                    : $is_closed    ? t8('The billing period has already been locked.')
1347
                    :                 undef,
1372
          disabled => !$may_edit_create ? t8('You must not change this AR transaction.')
1373
                    : $::form->{id}     ? t8('This invoice has already been posted.')
1374
                    : $is_closed        ? t8('The billing period has already been locked.')
1375
                    :                     undef,
1348 1376
        ],
1349 1377
      ], # end of combobox "more"
1350 1378
    );
bin/mozilla/is.pl
58 58

  
59 59
# end of main
60 60

  
61
sub _may_view_or_edit_this_invoice {
62
  return 1 if  $::auth->assert('invoice_edit', 1); # may edit all invoices
63
  return 0 if !$::form->{id};                      # creating new invoices isn't allowed without invoice_edit
64
  return 0 if !$::form->{globalproject_id};        # existing records without a project ID are not allowed
65
  return SL::DB::Project->new(id => $::form->{globalproject_id})->load->may_employee_view_project_invoices(SL::DB::Manager::Employee->current);
66
}
67

  
68
sub _assert_access {
69
  my $cache = $::request->cache('is.pl::_assert_access');
70

  
71
  $cache->{_may_view_or_edit_this_invoice} = _may_view_or_edit_this_invoice()                              if !exists $cache->{_may_view_or_edit_this_invoice};
72
  $::form->show_generic_error($::locale->text("You do not have the permissions to access this function.")) if !       $cache->{_may_view_or_edit_this_invoice};
73
}
74

  
61 75
sub add {
62 76
  $main::lxdebug->enter_sub();
63 77

  
......
92 106
sub edit {
93 107
  $main::lxdebug->enter_sub();
94 108

  
109
  # Delay access check to after the invoice's been loaded in
110
  # "invoice_links" so that project-specific invoice rights can be
111
  # evaluated.
112

  
95 113
  my $form     = $main::form;
96 114
  my $locale   = $main::locale;
97 115

  
98
  $main::auth->assert('invoice_edit');
99

  
100 116
  $form->{show_details}                = $::myconfig{show_form_details};
101 117
  $form->{taxincluded_changed_by_user} = 1;
102 118

  
......
134 150
sub invoice_links {
135 151
  $main::lxdebug->enter_sub();
136 152

  
153
  # Delay access check to after the invoice's been loaded so that
154
  # project-specific invoice rights can be evaluated.
155

  
137 156
  my $form     = $main::form;
138 157
  my %myconfig = %main::myconfig;
139 158

  
140
  $main::auth->assert('invoice_edit');
141

  
142 159
  $form->{vc} = 'customer';
143 160

  
144 161
  # create links
145 162
  $form->create_links("AR", \%myconfig, "customer");
146 163

  
164
  _assert_access();
165

  
147 166
  my $editing = $form->{id};
148 167

  
149 168
  $form->backup_vars(qw(payment_id language_id taxzone_id salesman_id
......
206 225
sub prepare_invoice {
207 226
  $main::lxdebug->enter_sub();
208 227

  
228
  _assert_access();
229

  
209 230
  my $form     = $main::form;
210 231
  my %myconfig = %main::myconfig;
211 232

  
212
  $main::auth->assert('invoice_edit');
213

  
214 233
  if ($form->{type} eq "credit_note") {
215 234
    $form->{type}     = "credit_note";
216 235
    $form->{formname} = "credit_note";
......
258 277
  my $change_on_same_day_only = $::instance_conf->get_is_changeable == 2 && ($form->current_date(\%::myconfig) ne $form->{gldate});
259 278
  my $payments_balanced       = ($::form->{oldtotalpaid} == 0);
260 279
  my $has_storno              = ($::form->{storno} && !$::form->{storno_id});
280
  my $may_edit_create         = $::auth->assert('invoice_edit', 1);
261 281

  
262 282
  for my $bar ($::request->layout->get('actionbar')) {
263 283
    $bar->add(
264 284
      action => [
265 285
        t8('Update'),
266 286
        submit    => [ '#form', { action => "update" } ],
267
        disabled  => $form->{locked} ? t8('The billing period has already been locked.') : undef,
287
        disabled  => !$may_edit_create ? t8('You must not change this invoice.')
288
                   : $form->{locked}   ? t8('The billing period has already been locked.')
289
                   :                     undef,
268 290
        id        => 'update_button',
269 291
        checks    => [ 'kivi.validate_form' ],
270 292
        accesskey => 'enter',
......
275 297
          t8('Post'),
276 298
          submit   => [ '#form', { action => "post" } ],
277 299
          checks   => [ 'kivi.validate_form' ],
278
          disabled => $form->{locked}                           ? t8('The billing period has already been locked.')
300
          disabled => !$may_edit_create                         ? t8('You must not change this invoice.')
301
                    : $form->{locked}                           ? t8('The billing period has already been locked.')
279 302
                    : $form->{storno}                           ? t8('A canceled invoice cannot be posted.')
280 303
                    : ($form->{id} && $change_never)            ? t8('Changing invoices has been disabled in the configuration.')
281 304
                    : ($form->{id} && $change_on_same_day_only) ? t8('Invoices can only be changed on the day they are posted.')
......
285 308
          t8('Post Payment'),
286 309
          submit   => [ '#form', { action => "post_payment" } ],
287 310
          checks   => [ 'kivi.validate_form' ],
288
          disabled => !$form->{id} ? t8('This invoice has not been posted yet.') : undef,
311
          disabled => !$may_edit_create ? t8('You must not change this invoice.')
312
                    : !$form->{id}      ? t8('This invoice has not been posted yet.')
313
                    :                     undef,
289 314
        ],
290 315
        action => [ t8('Mark as paid'),
291 316
          submit   => [ '#form', { action => "mark_as_paid" } ],
292 317
          confirm  => t8('This will remove the invoice from showing as unpaid even if the unpaid amount does not match the amount. Proceed?'),
293
          disabled => !$form->{id} ? t8('This invoice has not been posted yet.') : undef,
318
          disabled => !$may_edit_create ? t8('You must not change this invoice.')
319
                    : !$form->{id}      ? t8('This invoice has not been posted yet.')
320
                    :                     undef,
294 321
          only_if  => $::instance_conf->get_is_show_mark_as_paid,
295 322
        ],
296 323
      ], # end of combobox "Post"
......
300 327
          submit   => [ '#form', { action => "storno" } ],
301 328
          confirm  => t8('Do you really want to cancel this invoice?'),
302 329
          checks   => [ 'kivi.validate_form' ],
303
          disabled => !$form->{id}        ? t8('This invoice has not been posted yet.')
330
          disabled => !$may_edit_create   ? t8('You must not change this invoice.')
331
                    : !$form->{id}        ? t8('This invoice has not been posted yet.')
304 332
                    : !$payments_balanced ? t8('Cancelling is disallowed. Either undo or balance the current payments until the open amount matches the invoice amount')
305 333
                    : undef,
306 334
        ],
......
308 336
          submit   => [ '#form', { action => "delete" } ],
309 337
          confirm  => t8('Do you really want to delete this object?'),
310 338
          checks   => [ 'kivi.validate_form' ],
311
          disabled => !$form->{id}             ? t8('This invoice has not been posted yet.')
339
          disabled => !$may_edit_create        ? t8('You must not change this invoice.')
340
                    : !$form->{id}             ? t8('This invoice has not been posted yet.')
312 341
                    : $form->{locked}          ? t8('The billing period has already been locked.')
313 342
                    : $change_never            ? t8('Changing invoices has been disabled in the configuration.')
314 343
                    : $change_on_same_day_only ? t8('Invoices can only be changed on the day they are posted.')
......
325 354
          t8('Use As New'),
326 355
          submit   => [ '#form', { action => "use_as_new" } ],
327 356
          checks   => [ 'kivi.validate_form' ],
328
          disabled => !$form->{id} ? t8('This invoice has not been posted yet.') : undef,
357
          disabled => !$may_edit_create ? t8('You must not change this invoice.')
358
                    : !$form->{id}      ? t8('This invoice has not been posted yet.')
359
                    :                     undef,
329 360
        ],
330 361
        action => [
331 362
          t8('Credit Note'),
332 363
          submit   => [ '#form', { action => "credit_note" } ],
333 364
          checks   => [ 'kivi.validate_form' ],
334
          disabled => $form->{type} eq "credit_note" ? t8('Credit notes cannot be converted into other credit notes.')
365
          disabled => !$may_edit_create              ? t8('You must not change this invoice.')
366
                    : $form->{type} eq "credit_note" ? t8('Credit notes cannot be converted into other credit notes.')
335 367
                    : !$form->{id}                   ? t8('This invoice has not been posted yet.')
336 368
                    :                                  undef,
337 369
        ],
......
349 381
          ($form->{id} ? t8('Print') : t8('Preview')),
350 382
          call     => [ 'kivi.SalesPurchase.show_print_dialog', $form->{id} ? 'print' : 'preview' ],
351 383
          checks   => [ 'kivi.validate_form' ],
352
          disabled => !$form->{id} && $form->{locked} ? t8('The billing period has already been locked.') : undef,
384
          disabled => !$may_edit_create               ? t8('You must not print this invoice.')
385
                    : !$form->{id} && $form->{locked} ? t8('The billing period has already been locked.')
386
                    :                                   undef,
353 387
        ],
354 388
        action => [ t8('Print and Post'),
355 389
          call     => [ 'kivi.SalesPurchase.show_print_dialog', $form->{id} ? 'print' : 'print_and_post' ],
356 390
          checks   => [ 'kivi.validate_form' ],
357
          disabled => $form->{id} ? t8('This invoice has already been posted.') : undef,,
391
          disabled => !$may_edit_create ? t8('You must not print this invoice.')
392
                    : $form->{id}       ? t8('This invoice has already been posted.')
393
                    :                     undef,,
358 394
        ],
359 395
        action => [ t8('E Mail'),
360 396
          call     => [ 'kivi.SalesPurchase.show_email_dialog' ],
361 397
          checks   => [ 'kivi.validate_form' ],
362
          disabled => !$form->{id} ? t8('This invoice has not been posted yet.') : undef,
398
          disabled => !$may_edit_create ? t8('You must not print this invoice.')
399
                    : !$form->{id}      ? t8('This invoice has not been posted yet.')
400
                    :                     undef,
363 401
        ],
364 402
      ], # end of combobox "Export"
365 403

  
......
378 416
        action => [
379 417
          t8('Drafts'),
380 418
          call     => [ 'kivi.Draft.popup', 'is', 'invoice', $form->{draft_id}, $form->{draft_description} ],
381
          disabled => $form->{id}     ? t8('This invoice has already been posted.')
382
                    : $form->{locked} ? t8('The billing period has already been locked.')
383
                    :                   undef,
419
          disabled => !$may_edit_create ? t8('You must not change this invoice.')
420
                    :  $form->{id}      ? t8('This invoice has already been posted.')
421
                    : $form->{locked}   ? t8('The billing period has already been locked.')
422
                    :                     undef,
384 423
        ],
385 424
      ], # end of combobox "more"
386 425
    );
......
391 430
sub form_header {
392 431
  $main::lxdebug->enter_sub();
393 432

  
433
  _assert_access();
434

  
394 435
  my $form     = $main::form;
395 436
  my %myconfig = %main::myconfig;
396 437
  my $locale   = $main::locale;
397 438
  my $cgi      = $::request->{cgi};
398 439

  
399
  $main::auth->assert('invoice_edit');
400

  
401 440
  my %TMPL_VAR = ();
402 441
  my @custom_hiddens;
403 442

  
......
526 565
sub form_footer {
527 566
  $main::lxdebug->enter_sub();
528 567

  
568
  _assert_access();
569

  
529 570
  my $form     = $main::form;
530 571
  my %myconfig = %main::myconfig;
531 572
  my $locale   = $main::locale;
532 573

  
533
  $main::auth->assert('invoice_edit');
534

  
535 574
  $form->{invtotal}    = $form->{invsubtotal};
536 575

  
537 576
  # note rows
......
658 697
sub update {
659 698
  $main::lxdebug->enter_sub();
660 699

  
700
  _assert_access();
701

  
661 702
  my $form     = $main::form;
662 703
  my %myconfig = %main::myconfig;
663 704

  
664
  $main::auth->assert('invoice_edit');
665

  
666 705
  my ($recursive_call) = @_;
667 706

  
668 707
  $form->{print_and_post} = 0         if $form->{second_run};
......
1180 1219
sub display_form {
1181 1220
  $::lxdebug->enter_sub;
1182 1221

  
1183
  $::auth->assert('invoice_edit');
1222
  _assert_access();
1184 1223

  
1185 1224
  relink_accounts();
1186 1225

  
locale/de/all
250 250
  'All as list'                 => 'Alle als Liste',
251 251
  'All changes in that file have been reverted.' => 'Alle Änderungen in dieser Datei wurden rückgängig gemacht.',
252 252
  'All clients'                 => 'Alle Mandanten',
253
  'All employees'               => 'Alle Angestellten',
253 254
  'All general ledger entries'  => 'Alle Hauptbucheinträge',
254 255
  'All groups'                  => 'Alle Gruppen',
255 256
  'All modules'                 => 'Alle Module',
......
1233 1234
  'Employee (database ID)'      => 'Bearbeiter (Datenbank-ID)',
1234 1235
  'Employee from the original invoice' => 'Mitarbeiter der Ursprungs-Rechnung',
1235 1236
  'Employees'                   => 'Benutzer',
1237
  'Employees with read access to the project\'s invoices' => 'Angestellte mit Leserechten auf die Projektrechnungen',
1236 1238
  'Empty selection for warehouse will not be added, even if the old bin is still visible (use back and forth to edit again).' => 'Leere Lager-Auswahl wird ignoriert, selbst wenn noch ein Lagerplatz ausgewählt ist. Alle Daten können durch zurück und vorwärts korrigiert werden.',
1237 1239
  'Empty transaction!'          => 'Buchung ist leer!',
1238 1240
  'Enabled Quick Searched'      => 'Aktivierte Schnellsuchen',
......
2267 2269
  'Periodic inventory'          => 'Aufwandsmethode',
2268 2270
  'Periodic invoices active'    => 'Wiederkehrende Rechnungen aktiv',
2269 2271
  'Periodic invoices inactive'  => 'Wiederkehrende Rechnungen inaktiv',
2272
  'Permissions for invoices'    => 'Ansehrechte für Rechnungen',
2270 2273
  'Perpetual inventory'         => 'Bestandsmethode',
2271 2274
  'Personal settings'           => 'Persönliche Einstellungen',
2272 2275
  'Phone'                       => 'Telefon',
......
2451 2454
  'Project type'                => 'Projekttyp',
2452 2455
  'Project types'               => 'Projekttypen',
2453 2456
  'Projects'                    => 'Projekte',
2457
  'Projects: edit the list of employees allowed to view invoices' => 'Projekte: Liste der Angestellten bearbeiten, die Projektrechnungen ansehen dürfen',
2454 2458
  'Projecttransactions'         => 'Projektbuchungen',
2455 2459
  'Proposal'                    => 'Vorschlag',
2456 2460
  'Proposals'                   => 'Vorschläge',
......
3922 3926
  'You have to specify an execution date for each antry.' => 'Sie müssen für jeden zu buchenden Eintrag ein Ausführungsdatum angeben.',
3923 3927
  'You must chose a user.'      => 'Sie müssen einen Benutzer auswählen.',
3924 3928
  'You must enter a name for your new print templates.' => 'Sie müssen einen Namen für die neuen Druckvorlagen angeben.',
3929
  'You must not change this AR transaction.' => 'Sie dürfen diese Debitorenbuchung nicht verändern.',
3930
  'You must not change this invoice.' => 'Sie dürfen diese Rechnung nicht verändern.',
3931
  'You must not print this invoice.' => 'Sie dürfen diese Rechnung nicht drucken.',
3925 3932
  'You must select existing print templates or create a new set.' => 'Sie müssen vorhandene Druckvorlagen auswählen oder einen neuen Satz anlegen.',
3926 3933
  'You should create a backup of the database before proceeding because the backup might not be reversible.' => 'Sie sollten eine Sicherungskopie der Datenbank erstellen, bevor Sie fortfahren, da die Aktualisierung unter Umständen nicht umkehrbar ist.',
3927 3934
  'You\'re not editing a file.' => 'Sie bearbeiten momentan keine Datei.',
menus/user/00-erp.yaml
308 308
  name: Invoices, Credit Notes & AR Transactions
309 309
  icon: invoices_report
310 310
  order: 500
311
  access: invoice_edit
312 311
  module: ar.pl
313 312
  params:
314 313
    action: search
sql/Pg-upgrade2-auth/rights_for_viewing_project_specific_invoices.sql
1
-- @tag: rights_for_viewing_project_specific_invoices
2
-- @description: Rechte zum Anzeigen von Rechnungen, die zu Projekten gehören
3
-- @depends: release_3_5_3
4
-- @locales: Projects: edit the list of employees allowed to view invoices
5
INSERT INTO auth.master_rights (position, name, description, category)
6
VALUES (
7
  (SELECT position + 2
8
   FROM auth.master_rights
9
   WHERE name = 'project_edit'),
10
  'project_edit_view_invoices_permission',
11
  'Projects: edit the list of employees allowed to view invoices',
12
  false
13
);
14

  
15
INSERT INTO auth.group_rights (group_id, "right", granted)
16
SELECT id, 'project_edit_view_invoices_permission', true
17
FROM auth.group
18
WHERE name = 'Vollzugriff';
sql/Pg-upgrade2/add_emloyee_project_assignment_for_viewing_invoices.sql
1
-- @tag: add_emloyee_project_assignment_for_viewing_invoices
2
-- @description: Mitarbeiter*innen Projekten zuweisen können, damit diese Projektrechnungen anschauen dürfen
3
-- @depends: release_3_5_3
4
CREATE TABLE employee_project_invoices (
5
  employee_id INTEGER NOT NULL,
6
  project_id  INTEGER NOT NULL,
7

  
8
  CONSTRAINT employee_project_invoices_pkey             PRIMARY KEY (employee_id, project_id),
9
  CONSTRAINT employee_project_invoices_employee_id_fkey FOREIGN KEY (employee_id) REFERENCES employee (id) ON DELETE CASCADE,
10
  CONSTRAINT employee_project_invoices_project_id_fkey  FOREIGN KEY (project_id)  REFERENCES project  (id) ON DELETE CASCADE
11
);
templates/webpages/project/_invoice_permissions.html
1
[%- USE LxERP -%][%- USE L -%]<div class="clearfix">
2
 [% L.select_tag("project.employee_invoice_permissions[]", SELF.employees, id="employee_invoice_permissions", title_key="safe_name", default=SELF.project.employee_invoice_permissions, default_value_key='id', multiple=1) %]
3
 [% L.multiselect2side("employee_invoice_permissions", labelsx => LxERP.t8("All employees"), labeldx => LxERP.t8("Employees with read access to the project's invoices")) %]
4
</div>
templates/webpages/project/form.html
17 17
    [%- IF CUSTOM_VARIABLES.size %]
18 18
    <li><a href="#custom_variables">[% 'Custom Variables' | $T8 %]</a></li>
19 19
    [%- END %]
20
    [%- IF SELF.may_edit_invoice_permissions %]
21
     <li><a href="#invoice_permissions">[% 'Permissions for invoices' | $T8 %]</a></li>
22
    [%- END %]
20 23
    [%- IF SELF.project.id and AUTH.assert('record_links', 1) %]
21 24
    <li><a href="#linked_records">[% 'Linked Records' | $T8 %]</a></li>
22 25
    [%- END %]
......
32 35
   </div>
33 36
   [%- END %]
34 37

  
38
   [%- IF SELF.may_edit_invoice_permissions %]
39
    <div id="invoice_permissions">
40
     [%- PROCESS 'project/_invoice_permissions.html' %]
41
    </div>
42
   [%- END %]
43

  
35 44
   [%- IF SELF.project.id and AUTH.assert('record_links', 1) %]
36 45
   <div id="linked_records">
37 46
   [%- PROCESS 'project/_linked_records.html' records=SELF.linked_records %]

Auch abrufbar als: Unified diff