Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision eb0c10b0

Von Moritz Bunkus vor mehr als 15 Jahren hinzugefügt

  • ID eb0c10b0a09da8ff4590c3043a9fa6dd10775ee4
  • Vorgänger 72d93b0b
  • Nachfolger e20f3f0d

Korrekturmodul für das Hauptbuch implementiert

Frührere Lx-Office-Versionen enthalten einige Bugs und Features,
die den Export von Buchungsdaten ins DATEV-Format verhindern und
allgemein zu ungültigen und/oder unlogischen Einträgen in acc_trans
führen. Mit Hilfe dieses Modules, das über den Menüpunkt "System ->
Korrekturen -> Korrekturen im Hauptbuch" erreichbar ist, können die
Auswirkungen dieser Bugs und Features teils automatisch, teils manuell
behoben werden.

Unterschiede anzeigen:

SL/AccTransCorrections.pm
1
package AccTransCorrections;
2

  
3
use strict;
4

  
5
use List::Util qw(first);
6

  
7
use SL::DBUtils;
8
use SL::Taxkeys;
9

  
10
sub new {
11
  my $type = shift;
12

  
13
  my $self = {};
14

  
15
  bless $self, $type;
16

  
17
  $self->{taxkeys} = Taxkeys->new();
18

  
19
  return $self;
20
}
21

  
22
sub _fetch_transactions {
23
  $main::lxdebug->enter_sub();
24

  
25
  my $self     = shift;
26
  my %params   = @_;
27

  
28
  my $myconfig = \%main::myconfig;
29
  my $form     = $main::form;
30

  
31
  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
32

  
33
  my (@where, @values) = ((), ());
34

  
35
  if ($params{transdate_from}) {
36
    push @where,  qq|at.transdate >= ?|;
37
    push @values, $params{transdate_from};
38
  }
39

  
40
  if ($params{transdate_to}) {
41
    push @where,  qq|at.transdate <= ?|;
42
    push @values, $params{transdate_to};
43
  }
44
#   $params{trans_id} = 3150;
45
  if ($params{trans_id}) {
46
    push @where,  qq|at.trans_id = ?|;
47
    push @values, $params{trans_id};
48
  }
49

  
50
  my $where = '';
51
  if (scalar @where) {
52
    $where = 'WHERE ' . join(' AND ', map { "($_)" } @where);
53
  }
54

  
55
  my $query = qq!
56
    SELECT at.oid, at.*,
57
      c.accno, c.description AS chartdescription, c.charttype, c.category AS chartcategory, c.link AS chartlink,
58
      COALESCE(gl.reference, COALESCE(ap.invnumber, ar.invnumber)) AS reference,
59
      COALESCE(ap.invoice, COALESCE(ar.invoice, FALSE)) AS invoice,
60
      CASE
61
        WHEN gl.id IS NOT NULL THEN gl.storno AND (gl.storno_id IS NOT NULL)
62
        WHEN ap.id IS NOT NULL THEN ap.storno AND (ap.storno_id IS NOT NULL)
63
        ELSE                        ar.storno AND (ar.storno_id IS NOT NULL)
64
      END AS is_storno,
65
      CASE
66
        WHEN gl.id IS NOT NULL THEN 'gl'
67
        WHEN ap.id IS NOT NULL THEN 'ap'
68
        ELSE                        'ar'
69
      END AS module
70

  
71
    FROM acc_trans at
72
    LEFT JOIN chart c ON (at.chart_id = c.id)
73
    LEFT JOIN gl      ON (at.trans_id = gl.id)
74
    LEFT JOIN ap      ON (at.trans_id = ap.id)
75
    LEFT JOIN ar      ON (at.trans_id = ar.id)
76
    $where
77
    ORDER BY at.trans_id, at.oid
78
!;
79

  
80
  my @transactions = ();
81
  my $last_trans   = undef;
82

  
83
  foreach my $entry (@{ selectall_hashref_query($form, $dbh, $query, @values) }) {
84
    if (!$last_trans || ($last_trans->[0]->{trans_id} != $entry->{trans_id})) {
85
      $last_trans = [];
86
      push @transactions, $last_trans;
87
    }
88

  
89
    push @{ $last_trans }, $entry;
90
  }
91

  
92
  $main::lxdebug->leave_sub();
93

  
94
  return @transactions;
95
}
96

  
97
sub _prepare_data {
98
  $main::lxdebug->enter_sub();
99

  
100
  my $self        = shift;
101
  my %params      = @_;
102

  
103
  my $transaction = $params{transaction};
104
  my $callback    = $params{callback};
105

  
106
  my $myconfig    = \%main::myconfig;
107
  my $form        = $main::form;
108

  
109
  my $data          = {
110
    'credit'        => {
111
      'num'         => 0,
112
      'sum'         => 0,
113
      'entries'     => [],
114
      'tax_sum'     => 0,
115
      'tax_entries' => [],
116
    },
117
    'debit'         => {
118
      'num'         => 0,
119
      'sum'         => 0,
120
      'entries'     => [],
121
      'tax_sum'     => 0,
122
      'tax_entries' => [],
123
    },
124
    'payments'      => [],
125
  };
126

  
127
  foreach my $entry (@{ $transaction }) {
128
    $entry->{chartlinks} = { map { $_ => 1 } split(m/:/, $entry->{chartlink}) };
129
    delete $entry->{chartlink};
130
  }
131

  
132
  # Verkn?pfungen zwischen Steuerschl?sseln und zum Zeitpunkt der Transaktion
133
  # g?ltigen Steuers?tze
134
  my %all_taxes = $self->{taxkeys}->get_full_tax_info('transdate' => $transaction->[0]->{transdate});
135

  
136
  my ($trans_type, $previous_non_tax_entry);
137
  my $sum             = 0;
138
  my $first_sub_trans = 1;
139

  
140
  my $storno_mult     = $transaction->[0]->{is_storno} ? -1 : 1;
141

  
142
  # Aufteilung der Buchungspositionen in Soll-, Habenseite sowie
143
  # getrennte Auflistung der Positionen, die auf Steuerkonten gebucht werden.
144
  foreach my $entry (@{ $transaction }) {
145
    if (!$first_sub_trans && ($entry->{chartlinks}->{AP_paid} || $entry->{chartlinks}->{AR_paid})) {
146
      push @{ $data->{payments} }, $entry;
147
      next;
148
    }
149

  
150
    my $tax_info = $all_taxes{taxkeys}->{ $entry->{taxkey} };
151
    if ($tax_info) {
152
      $entry->{taxdescription} = $tax_info->{taxdescription} . ' ' . $form->format_amount($myconfig, $tax_info->{taxrate} * 100) . ' %';
153
    }
154

  
155
    if ($entry->{chartlinks}->{AP}) {
156
      $trans_type = 'AP';
157
    } elsif ($entry->{chartlinks}->{AR}) {
158
      $trans_type = 'AR';
159
    }
160

  
161
    my $idx = 0 < ($entry->{amount} * $storno_mult) ? 'credit' : 'debit';
162

  
163
    if ($entry->{chartlinks}->{AP_tax} || $entry->{chartlinks}->{AR_tax}) {
164
      $data->{$idx}->{tax_sum} += $entry->{amount};
165
      push @{ $data->{$idx}->{tax_entries} }, $entry;
166

  
167
      if ($previous_non_tax_entry) {
168
        $previous_non_tax_entry->{tax_entry} = $entry;
169
        undef $previous_non_tax_entry;
170
      }
171

  
172
    } else {
173
      $data->{$idx}->{sum} += $entry->{amount};
174
      push @{ $data->{$idx}->{entries} }, $entry;
175

  
176
      $previous_non_tax_entry = $entry;
177
    }
178

  
179
    $sum += $entry->{amount};
180

  
181
    if (abs($sum) < 0.02) {
182
      $sum             = 0;
183
      $first_sub_trans = 0;
184
    }
185
  }
186

  
187
  # Alle Eintr?ge entfernen, die die Gegenkonten zu Zahlungsein- und
188
  # -ausg?ngen darstellen.
189
  foreach my $payment (@{ $data->{payments} }) {
190
    my $idx = 0 < $payment->{amount} ? 'debit' : 'credit';
191

  
192
    foreach my $i (0 .. scalar(@{ $data->{$idx}->{entries} }) - 1) {
193
      my $entry = $data->{$idx}->{entries}->[$i];
194

  
195
      next if ((($payment->{amount} * -1) != $entry->{amount}) || ($payment->{transdate} ne $entry->{transdate}));
196

  
197
      splice @{ $data->{$idx}->{entries} }, $i, 1;
198

  
199
      last;
200
    }
201
  }
202

  
203
  delete $data->{payments};
204

  
205
  map { $data->{$_}->{num} = scalar @{ $data->{$_}->{entries} } } qw(credit debit);
206

  
207
  my $info   = $transaction->[0];
208
  my $script = ($info->{module} eq 'ar') && $info->{invoice} ? 'is'
209
             : ($info->{module} eq 'ap') && $info->{invoice} ? 'ir'
210
             :                                                 $info->{module};
211

  
212
  my %common_args = (
213
    'data'          => $data,
214
    'trans_type'    => $trans_type,
215
    'all_taxes'     => { %all_taxes },
216
    'transaction'   => $transaction,
217
    'full_analysis' => $params{full_analysis},
218
    'problem'       => {
219
      'data'        => $info,
220
      'link'        => $script . ".pl?action=edit${callback}&id=" . $info->{trans_id},
221
    },
222
    );
223

  
224
  $main::lxdebug->leave_sub();
225

  
226
  return %common_args;
227
}
228

  
229
sub _group_sub_transactions {
230
  $main::lxdebug->enter_sub();
231

  
232
  my $self             = shift;
233
  my $transaction      = shift;
234

  
235
  my @sub_transactions = ();
236
  my $sum              = 0;
237

  
238
  foreach my $i (0 .. scalar(@{ $transaction }) - 1) {
239
    my $entry = $transaction->[$i];
240

  
241
    if (abs($sum) <= 0.01) {
242
      push @sub_transactions, [];
243
      $sum = 0;
244
    }
245
    $sum += $entry->{amount};
246

  
247
    push @{ $sub_transactions[-1] }, $entry;
248
  }
249

  
250
  $main::lxdebug->leave_sub();
251

  
252
  return @sub_transactions;
253
}
254

  
255
# Problemfall: Verkaufsrechnungen, bei denen Buchungen auf Warenbestandskonten
256
# mit Steuerschl?ssel != 0 durchgef?hrt wurden. Richtig w?re, dass alle
257
# Steuerschl?ssel f?r solche Warenbestandsbuchungen 0 sind.
258
sub _check_trans_invoices_inventory_with_taxkeys {
259
  $main::lxdebug->enter_sub();
260

  
261
  my $self   = shift;
262
  my %params = @_;
263

  
264
  if (!$params{transaction}->[0]->{invoice}) {
265
    $main::lxdebug->leave_sub();
266
    return 0;
267
  }
268

  
269
  my @sub_transactions = $self->_group_sub_transactions($params{transaction});
270

  
271
  foreach my $sub_transaction (@sub_transactions) {
272
    my $is_cogs = first { $_->{chartlinks}->{IC_cogs} } @{ $sub_transaction };
273
    next unless ($is_cogs);
274

  
275
    my $needs_fixing = first { $_->{taxkey} != 0 } @{ $sub_transaction };
276
    next unless ($needs_fixing);
277

  
278
    $params{problem}->{type} = 'invoice_inventory_with_taxkeys';
279
    push @{ $self->{invoice_inventory_taxkey_problems} }, $params{problem};
280

  
281
    $main::lxdebug->leave_sub();
282

  
283
    return 1;
284
  }
285

  
286
  $main::lxdebug->leave_sub();
287

  
288
  return 0;
289
}
290

  
291
# Problemfall: Kreditorenbuchungen, bei denen mit Umsatzsteuerschl?sseln
292
# gebucht wurde und Debitorenbuchungen, bei denen mit Vorsteuerschl?sseln
293
# gebucht wurde.
294
sub _check_trans_ap_ar_wrong_taxkeys {
295
  $main::lxdebug->enter_sub();
296

  
297
  my $self   = shift;
298
  my %params = @_;
299

  
300
  my $retval = 0;
301

  
302
  if (!$params{transaction}->[0]->{invoice}
303
      && ((   ($params{transaction}->[0]->{module} eq 'ap')
304
          && (first { my $taxkey = $_->{taxkey}; first { $taxkey == $_ } (2, 3, 12, 13) } @{ $params{transaction} }))
305
         ||
306
         (   ($params{transaction}->[0]->{module} eq 'ar')
307
          && (first { my $taxkey = $_->{taxkey}; first { $taxkey == $_ } (8, 9, 18, 19) } @{ $params{transaction} })))) {
308
    $params{problem}->{type} = 'ap_ar_wrong_taxkeys';
309
    push @{ $self->{ap_ar_taxkey_problems} }, $params{problem};
310

  
311
    $retval = 1;
312
  }
313

  
314
  $main::lxdebug->leave_sub();
315

  
316
  return $retval;
317
}
318

  
319
# Problemfall: Splitbuchungen, die mehrere Haben- und Sollkonten ansprechen.
320
# Aber nur f?r Debitoren- und Kreditorenbuchungen, weil das bei Einkaufs- und
321
# Verkaufsrechnungen hingegen v?llig normal ist.
322
sub _check_trans_split_multiple_credit_and_debit {
323
  $main::lxdebug->enter_sub();
324

  
325
  my $self   = shift;
326
  my %params = @_;
327

  
328
  my $retval = 0;
329

  
330
  if (   !$params{transaction}->[0]->{invoice}
331
      && (1 < $params{data}->{credit}->{num})
332
      && (1 < $params{data}->{debit}->{num})) {
333
    $params{problem}->{type} = 'split_multiple_credit_and_debit';
334
    push @{ $self->{problems} }, $params{problem};
335

  
336
    $retval = 1;
337
  }
338

  
339
  $main::lxdebug->leave_sub();
340

  
341
  return $retval;
342
}
343

  
344
# Problemfall: Buchungen, bei denen Steuersummen nicht mit den Summen
345
# ?bereinstimmen, die nach ausgew?hltem Steuerschl?ssel h?tten auftreten m?ssen.
346
sub _check_trans_wrong_taxkeys {
347
  $main::lxdebug->enter_sub();
348

  
349
  my $self        = shift;
350
  my %params      = @_;
351

  
352
  my $form        = $main::form;
353

  
354
  my %data        = %{ $params{data} };
355
  my $transaction = $params{transaction};
356

  
357
  if (   $transaction->[0]->{invoice}
358
      || $transaction->[0]->{ob_transaction}
359
      || $transaction->[0]->{cb_transaction}
360
      || (!scalar @{ $data{credit}->{entries} } && !scalar @{ $data{debit}->{entries} })
361
      || (   ($transaction->[0]->{module} eq 'gl')
362
          && (!scalar @{ $data{credit}->{entries} } || !scalar @{ $data{debit}->{entries} }))) {
363
    $main::lxdebug->leave_sub();
364
    return 0;
365
  }
366

  
367
  my $retval = 0;
368

  
369
  my ($side, $other_side);
370
  if (   (grep { $_->{taxkey} * 1 } @{ $data{credit}->{entries} })
371
      || (scalar @{ $data{credit}->{tax_entries} })) {
372
    $side       = 'credit';
373
    $other_side = 'debit';
374

  
375
  } elsif (   (grep { $_->{taxkey} * 1 } @{ $data{debit}->{entries} })
376
           || (scalar @{ $data{debit}->{tax_entries} })) {
377
    $side       = 'debit';
378
    $other_side = 'credit';
379
  }
380

  
381
  if (!$side) {
382
    $main::lxdebug->leave_sub();
383
    return 0;
384
  }
385

  
386
  my $expected_tax          = 0;
387
  my %num_entries_per_chart = ();
388
  my $num_taxed_entries     = 0;
389

  
390
  foreach my $entry (@{ $data{$side}->{entries} }) {
391
    my $taxinfo             = $params{all_taxes}->{taxkeys}->{$entry->{taxkey}} || { };
392
    $entry->{expected_tax}  = $entry->{amount} * $taxinfo->{taxrate};
393
    $expected_tax          += $entry->{expected_tax};
394

  
395
    $num_taxed_entries++ if ($taxinfo->{taxrate} * 1);
396

  
397
    my $chart_key = $entry->{chart_id} . "-" . $entry->{taxkey};
398
    $num_entries_per_chart{$chart_key} ||= 0;
399
    $num_entries_per_chart{$chart_key}++;
400
  }
401

  
402
#   $main::lxdebug->message(0, "side $side trans_id $transaction->[0]->{trans_id} expected tax $expected_tax actual tax $data{$side}->{tax_sum}");
403

  
404
  if (abs($expected_tax - $data{$side}->{tax_sum}) >= (0.01 * ($num_taxed_entries + 1))) {
405
    if ($params{full_analysis}) {
406
      my $storno_mult = $data{$side}->{entries}->[0]->{is_storno} ? -1 : 1;
407

  
408
      foreach my $entry (@{ $data{$other_side}->{entries} }) {
409
        $entry->{display_amount} = $form->round_amount(abs($entry->{amount}) * $storno_mult, 2);
410
      }
411

  
412
      foreach my $entry (@{ $data{$side}->{entries} }) {
413
        $entry->{actual_tax}     = $form->round_amount(abs($entry->{tax_entry} ? $entry->{tax_entry}->{amount} : 0), 2);
414
        $entry->{expected_tax}   = $form->round_amount(abs($entry->{expected_tax}), 2);
415
        $entry->{taxkey_error}   =    ( $entry->{taxkey} && !$entry->{tax_entry})
416
                                   || (!$entry->{taxkey} &&  $entry->{tax_entry})
417
                                   || (abs($entry->{expected_tax} - $entry->{actual_tax}) >= 0.02);
418
        $entry->{tax_entry_oid}  = $entry->{tax_entry}->{oid};
419
        delete $entry->{tax_entry};
420

  
421
        $entry->{display_amount}       = $form->round_amount(abs($entry->{amount}) * $storno_mult, 2);
422
        $entry->{display_actual_tax}   = $entry->{actual_tax}   * $storno_mult;
423
        $entry->{display_expected_tax} = $entry->{expected_tax} * $storno_mult;
424

  
425
        if ($entry->{taxkey_error}) {
426
          $self->{negative_taxkey_filter} ||= {
427
            'ar' => { map { $_ => 1 } (   8, 9, 18, 19) },
428
            'ap' => { map { $_ => 1 } (1, 2, 3, 12, 13) },
429
            'gl' => { },
430
          };
431

  
432
          $entry->{correct_taxkeys} = [];
433

  
434
          my %all_taxes = $self->{taxkeys}->get_full_tax_info('transdate' => $entry->{transdate});
435

  
436
          foreach my $taxkey (sort { $a <=> $b } keys %{ $all_taxes{taxkeys} }) {
437
            next if ($self->{negative_taxkey_filter}->{ $entry->{module} }->{$taxkey});
438

  
439
            my $tax_info = $all_taxes{taxkeys}->{$taxkey};
440

  
441
            next if ((!$tax_info || (0 == $tax_info->{taxrate} * 1)) && $entry->{tax_entry_oid});
442

  
443
            push @{ $entry->{correct_taxkeys} }, {
444
              'taxkey'      => $taxkey,
445
              'tax'         => $form->round_amount(abs($entry->{amount}) * $tax_info->{taxrate}, 2),
446
              'description' => sprintf("%s %d%%", $tax_info->{taxdescription}, int($tax_info->{taxrate} * 100)),
447
            };
448
          }
449
        }
450
      }
451
    }
452

  
453
    if (first { $_ > 1 } values %num_entries_per_chart) {
454
      $params{problem}->{type} = 'wrong_taxkeys';
455
    } else {
456
      $params{problem}->{type} = 'wrong_taxes';
457
    }
458

  
459
    $params{problem}->{acc_trans} = { %data };
460
    push @{ $self->{problems} }, $params{problem};
461

  
462
    $retval = 1;
463
  }
464

  
465
  $main::lxdebug->leave_sub();
466

  
467
  return $retval;
468
}
469

  
470
# Inaktiver Code f?r das Erraten m?glicher Verteilungen von
471
# Steuerschl?sseln. Deaktiviert, weil er exponentiell Zeit
472
# ben?tigt.
473

  
474
#       if (abs($expected_tax - $data{$side}->{tax_sum}) >= 0.02) {
475
#         my @potential_taxkeys = $trans_type eq 'AP' ? (0, 8, 9) : (0, 1, 2, 3);
476

  
477
#         $main::lxdebug->dump(0, "pota", \@potential_taxkeys);
478

  
479
#         # ?ber alle Kombinationen aus Buchungss?tzen und potenziellen Steuerschl?sseln
480
#         # iterieren und jeweils die Summe ermitteln.
481
#         my $num_entries    = scalar @{ $data{$side}->{entries} };
482
#         my @taxkey_indices = (0) x $num_entries;
483

  
484
#         my @solutions      = ();
485

  
486
#         my $start_time     = time();
487

  
488
#         $main::lxdebug->message(0, "num_entries $num_entries");
489

  
490
#         while ($num_entries == scalar @taxkey_indices) {
491
#           my @tax_cache = ();
492

  
493
#           # Berechnen der Steuersumme f?r die aktuell angenommenen Steuerschl?ssel.
494
#           my $tax_sum = 0;
495
#           foreach my $i (0 .. $num_entries - 1) {
496
#             my $taxkey      = $potential_taxkeys[$taxkey_indices[$i]];
497
#             my $entry       = $data{$side}->{entries}->[$i];
498
#             my $taxinfo     = $all_taxes{taxkeys}->{ $taxkey } || { };
499
#             $tax_cache[$i]  = $entry->{amount} * $taxinfo->{taxrate};
500
#             $tax_sum       += $tax_cache[$i];
501
#           }
502

  
503
#           # Entspricht die Steuersumme mit den aktuell angenommenen Steuerschl?sseln
504
#           # der verbuchten Steuersumme? Wenn ja, dann ist das eine potenzielle
505
#           # L?sung.
506
#           if (abs($tax_sum - $data{$side}->{tax_sum}) < 0.02) {
507
#             push @solutions, {
508
#               'taxkeys' => [ @potential_taxkeys[@taxkey_indices] ],
509
#               'taxes'   => [ @tax_cache ],
510
#             }
511
#           }
512

  
513
#           # Weiterz?hlen der Steuerschl?sselindices zum Interieren ?ber
514
#           # alle m?glichen Kombinationen.
515
#           my $i = 0;
516
#           while (1) {
517
#             $taxkey_indices[$i]++;
518
#             last if ($taxkey_indices[$i] < scalar @potential_taxkeys);
519

  
520
#             $taxkey_indices[$i] = 0;
521
#             $i++;
522
#           }
523

  
524
#           my $now = time();
525
#           if (($now - $start_time) >= 5) {
526
#             $main::lxdebug->message(0, "  " . join("", @taxkey_indices));
527
#             $start_time = $now;
528
#           }
529
#         }
530

  
531
#         foreach my $solution (@solutions) {
532
#           $solution->{rows}    = [];
533
#           $solution->{changes} = [];
534
#           my $error            = 0;
535

  
536
#           foreach my $i (0 .. $num_entries - 1) {
537
#             if ($solution->{taxes}->[$i]) {
538
#               my $tax_rounded          = $form->round_amount($solution->{taxes}->[$i] + $error, 2);
539
#               $error                   = $solution->{taxes}->[$i] + $error - $tax_rounded;
540
#               $solution->{taxes}->[$i] = $tax_rounded;
541
#             }
542

  
543
#             my $entry     = $data{$side}->{entries}->[$i];
544
#             my $tax_entry = $all_taxes{taxkeys}->{ $solution->{taxkeys}->[$i] };
545

  
546
#             push @{ $solution->{rows} }, {
547
#               %{ $entry },
548
#               %{ $tax_entry },
549
#               'taxamount' => $solution->{taxes}->[$i],
550
#             };
551

  
552
#             $solution->{rows}->[$i]->{taxdescription} .= ' ' . $form->format_amount(\%myconfig, $tax_entry->{taxrate} * 100) . ' %';
553

  
554
#             push @{ $solution->{changes} }, {
555
#               'oid'    => $entry->{oid},
556
#               'taxkey' => $solution->{taxkeys}->[$i],
557
#             };
558
#           }
559

  
560
#           push @{ $solution->{rows} }, @{ $data{$other_side}->{entries} };
561

  
562
#           delete @{ $solution }{ qw(taxes taxkeys) };
563
#         }
564

  
565
#         $problem->{type}      = 'wrong_taxkeys';
566
#         $problem->{solutions} = [ @solutions ];
567
#         $problem->{acc_trans} = { %data };
568
#         push @problems, $problem;
569

  
570
#         next;
571
#       }
572

  
573
sub analyze {
574
  $main::lxdebug->enter_sub();
575

  
576
  my $self         = shift;
577
  my %params       = @_;
578

  
579
  my $myconfig     = \%main::myconfig;
580
  my $form         = $main::form;
581

  
582
  my $dbh          = $params{dbh} || $form->get_standard_dbh($myconfig);
583

  
584
  my @transactions = $self->_fetch_transactions(%params, 'dbh' => $dbh);
585

  
586
  if (!scalar @transactions) {
587
    $main::lxdebug->leave_sub();
588
    return ();
589
  }
590

  
591
  my $callback = $params{callback} ? '&callback=' . $params{callback} : '';
592

  
593
  $self->{problems}                          = [];
594
  $self->{ap_ar_taxkey_problems}             = [];
595
  $self->{invoice_inventory_taxkey_problems} = [];
596

  
597
  foreach my $transaction (@transactions) {
598
    my %common_args = $self->_prepare_data('transaction' => $transaction, 'callback' => $callback, 'full_analysis' => $params{full_analysis});
599

  
600
    next if ($self->_check_trans_ap_ar_wrong_taxkeys(%common_args));
601
    next if ($self->_check_trans_invoices_inventory_with_taxkeys(%common_args));
602
    next if ($self->_check_trans_split_multiple_credit_and_debit(%common_args));
603
    next if ($self->_check_trans_wrong_taxkeys(%common_args));
604
  }
605

  
606
  my @problems = @{ $self->{problems} };
607

  
608
  if (0 != scalar @{ $self->{ap_ar_taxkey_problems} }) {
609
    my $problem = {
610
      'type'        => 'ap_ar_wrong_taxkeys',
611
      'ap_problems' => [ grep { $_->{data}->{module} eq 'ap' } @{ $self->{ap_ar_taxkey_problems} } ],
612
      'ar_problems' => [ grep { $_->{data}->{module} eq 'ar' } @{ $self->{ap_ar_taxkey_problems} } ],
613
    };
614
    unshift @problems, $problem;
615
  }
616

  
617
  if (0 != scalar @{ $self->{invoice_inventory_taxkey_problems} }) {
618
    my $problem = {
619
      'type'        => 'invoice_inventory_with_taxkeys',
620
      'ap_problems' => [ grep { $_->{data}->{module} eq 'ap' } @{ $self->{invoice_inventory_taxkey_problems} } ],
621
      'ar_problems' => [ grep { $_->{data}->{module} eq 'ar' } @{ $self->{invoice_inventory_taxkey_problems} } ],
622
    };
623
    unshift @problems, $problem;
624
  }
625

  
626
  $main::lxdebug->leave_sub();
627

  
628

  
629
  return @problems;
630
}
631

  
632
sub fix_ap_ar_wrong_taxkeys {
633
  $main::lxdebug->enter_sub();
634

  
635
  my $self     = shift;
636
  my %params   = @_;
637

  
638
  my $myconfig = \%main::myconfig;
639
  my $form     = $main::form;
640

  
641
  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
642

  
643
  my $query    = qq|SELECT 'ap' AS module,
644
                      at.oid, at.trans_id, at.chart_id, at.amount, at.taxkey, at.transdate,
645
                      c.link
646
                    FROM acc_trans at
647
                    LEFT JOIN chart c ON (at.chart_id = c.id)
648
                    WHERE (trans_id IN (SELECT id FROM ap WHERE NOT invoice))
649
                      AND (taxkey IN (2, 3, 12, 13))
650

  
651
                    UNION
652

  
653
                    SELECT 'ar' AS module,
654
                      at.oid, at.trans_id, at.chart_id, at.amount, at.taxkey, at.transdate,
655
                      c.link
656
                    FROM acc_trans at
657
                    LEFT JOIN chart c ON (at.chart_id = c.id)
658
                    WHERE (trans_id IN (SELECT id FROM ar WHERE NOT invoice))
659
                      AND (taxkey IN (8, 9, 18, 19))
660

  
661
                    ORDER BY trans_id, oid|;
662

  
663
  my $sth      = prepare_execute_query($form, $dbh, $query);
664
  my @transactions;
665

  
666
  while (my $ref = $sth->fetchrow_hashref()) {
667
    if ((!scalar @transactions) || ($ref->{trans_id} != $transactions[-1]->[0]->{trans_id})) {
668
      push @transactions, [];
669
    }
670

  
671
    push @{ $transactions[-1] }, $ref;
672
  }
673

  
674
  $sth->finish();
675

  
676
  @transactions = grep { (scalar(@transactions) % 2) == 0 } @transactions;
677

  
678
  my %taxkey_replacements = (
679
     2 =>  8,
680
     3 =>  9,
681
     8 =>  2,
682
     9 =>  3,
683
    12 => 18,
684
    13 => 19,
685
    18 => 12,
686
    19 => 13,
687
    );
688

  
689
  my %bad_taxkeys = (
690
    'ap' => { map { $_ => 1 } (2, 3, 12, 13) },
691
    'ar' => { map { $_ => 1 } (8, 9, 18, 19) },
692
    );
693

  
694
  my @corrections = ();
695

  
696
  foreach my $transaction (@transactions) {
697

  
698
    for (my $i = 0; $i < scalar @{ $transaction }; $i += 2) {
699
      my ($non_tax_idx, $tax_idx) = abs($transaction->[$i]->{amount}) > abs($transaction->[$i + 1]->{amount}) ? ($i, $i + 1) : ($i + 1, $i);
700
      my ($non_tax,     $tax)     = @{ $transaction }[$non_tax_idx, $tax_idx];
701

  
702
      last if ($non_tax->{link} =~ m/(:?AP|AR)_tax(:?$|:)/);
703
      last if ($tax->{link}     !~ m/(:?AP|AR)_tax(:?$|:)/);
704

  
705
      next if (!$bad_taxkeys{ $non_tax->{module} }->{ $non_tax->{taxkey} });
706

  
707
      my %all_taxes = $self->{taxkeys}->get_full_tax_info('transdate' => $non_tax->{transdate});
708

  
709
      push @corrections, ({ 'oid'      => $non_tax->{oid},
710
                            'taxkey'   => $taxkey_replacements{$non_tax->{taxkey}},
711
                          },
712
                          {
713
                            'oid'      => $tax->{oid},
714
                            'taxkey'   => $taxkey_replacements{$non_tax->{taxkey}},
715
                            'chart_id' => $all_taxes{taxkeys}->{ $taxkey_replacements{$non_tax->{taxkey}} }->{taxchart_id},
716
                          });
717
    }
718
  }
719

  
720
  if (scalar @corrections) {
721
    my $q_taxkey_only     = qq|UPDATE acc_trans SET taxkey = ? WHERE oid = ?|;
722
    my $h_taxkey_only     = prepare_query($form, $dbh, $q_taxkey_only);
723

  
724
    my $q_taxkey_chart_id = qq|UPDATE acc_trans SET taxkey = ?, chart_id = ? WHERE oid = ?|;
725
    my $h_taxkey_chart_id = prepare_query($form, $dbh, $q_taxkey_chart_id);
726

  
727
    foreach my $entry (@corrections) {
728
      if ($entry->{chart_id}) {
729
        do_statement($form, $h_taxkey_chart_id, $q_taxkey_chart_id, $entry->{taxkey}, $entry->{chart_id}, $entry->{oid});
730
      } else {
731
        do_statement($form, $h_taxkey_only, $q_taxkey_only, $entry->{taxkey}, $entry->{oid});
732
      }
733
    }
734

  
735
    $h_taxkey_only->finish();
736
    $h_taxkey_chart_id->finish();
737

  
738
    $dbh->commit() unless ($params{dbh});
739
  }
740

  
741
  $main::lxdebug->leave_sub();
742
}
743

  
744
sub fix_invoice_inventory_with_taxkeys {
745
  $main::lxdebug->enter_sub();
746

  
747
  my $self     = shift;
748
  my %params   = @_;
749

  
750
  my $myconfig = \%main::myconfig;
751
  my $form     = $main::form;
752

  
753
  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
754

  
755
  my $query    = qq|SELECT at.oid, at.*, c.link
756
                    FROM acc_trans at
757
                    LEFT JOIN ar      ON (at.trans_id = ar.id)
758
                    LEFT JOIN chart c ON (at.chart_id = c.id)
759
                    WHERE (ar.invoice)
760

  
761
                    UNION
762

  
763
                    SELECT at.oid, at.*, c.link
764
                    FROM acc_trans at
765
                    LEFT JOIN ap      ON (at.trans_id = ap.id)
766
                    LEFT JOIN chart c ON (at.chart_id = c.id)
767
                    WHERE (ap.invoice)
768

  
769
                    ORDER BY trans_id, oid|;
770

  
771
  my $sth      = prepare_execute_query($form, $dbh, $query);
772
  my @transactions;
773

  
774
  while (my $ref = $sth->fetchrow_hashref()) {
775
    if ((!scalar @transactions) || ($ref->{trans_id} != $transactions[-1]->[0]->{trans_id})) {
776
      push @transactions, [];
777
    }
778

  
779
    push @{ $transactions[-1] }, $ref;
780
  }
781

  
782
  $sth->finish();
783

  
784
  my @corrections = ();
785

  
786
  foreach my $transaction (@transactions) {
787
    my @sub_transactions = $self->_group_sub_transactions($transaction);
788

  
789
    foreach my $sub_transaction (@sub_transactions) {
790
      my $is_cogs = first { $_->{link} =~ m/IC_cogs/ } @{ $sub_transaction };
791
      next unless ($is_cogs);
792

  
793
      foreach my $entry (@{ $sub_transaction }) {
794
        next if ($entry->{taxkey} == 0);
795
        push @corrections, $entry->{oid};
796
      }
797
    }
798
  }
799

  
800
  if (@corrections) {
801
    $query = qq|UPDATE acc_trans SET taxkey = 0 WHERE oid = ?|;
802
    $sth   = prepare_query($form, $dbh, $query);
803

  
804
    foreach my $oid (@corrections) {
805
      do_statement($form, $sth, $query, $oid);
806
    }
807

  
808
    $sth->finish();
809

  
810
    $dbh->commit() unless ($params{dbh});
811
#     $dbh->rollback();
812
  }
813

  
814
  $main::lxdebug->leave_sub();
815
}
816

  
817
sub fix_wrong_taxkeys {
818
  $main::lxdebug->enter_sub();
819

  
820
  my $self     = shift;
821
  my %params   = @_;
822

  
823
  Common::check_params(\%params, qw(fixes));
824

  
825
  my $myconfig = \%main::myconfig;
826
  my $form     = $main::form;
827

  
828
  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
829

  
830
  my $q_taxkey_only  = qq|UPDATE acc_trans SET taxkey = ? WHERE oid = ?|;
831
  my $h_taxkey_only  = prepare_query($form, $dbh, $q_taxkey_only);
832

  
833
  my $q_taxkey_chart = qq|UPDATE acc_trans SET taxkey = ?, chart_id = ? WHERE oid = ?|;
834
  my $h_taxkey_chart = prepare_query($form, $dbh, $q_taxkey_chart);
835

  
836
  my $q_transdate    = qq|SELECT transdate FROM acc_trans WHERE oid = ?|;
837
  my $h_transdate    = prepare_query($form, $dbh, $q_transdate);
838

  
839
  foreach my $fix (@{ $params{fixes} }) {
840
    next unless ($fix->{oid});
841

  
842
    do_statement($form, $h_taxkey_only, $q_taxkey_only, conv_i($fix->{taxkey}), conv_i($fix->{oid}));
843

  
844
    next unless ($fix->{tax_entry_oid});
845

  
846
    do_statement($form, $h_transdate, $q_transdate, conv_i($fix->{tax_entry_oid}));
847
    my ($transdate) = $h_transdate->fetchrow_array();
848

  
849
    my %all_taxes = $self->{taxkeys}->get_full_tax_info('transdate' => $transdate);
850
    my $tax_info  = $all_taxes{taxkeys}->{ $fix->{taxkey} };
851

  
852
    next unless ($tax_info);
853

  
854
    do_statement($form, $h_taxkey_chart, $q_taxkey_chart, conv_i($fix->{taxkey}), conv_i($tax_info->{taxchart_id}), conv_i($fix->{tax_entry_oid}));
855
  }
856

  
857
  $h_taxkey_only->finish();
858
  $h_taxkey_chart->finish();
859
  $h_transdate->finish();
860

  
861
#   $dbh->rollback();
862
  $dbh->commit() unless ($params{dbh});
863

  
864
  $main::lxdebug->leave_sub();
865
}
866

  
867
sub delete_transaction {
868
  $main::lxdebug->enter_sub();
869

  
870
  my $self     = shift;
871
  my %params   = @_;
872

  
873
  Common::check_params(\%params, qw(trans_id));
874

  
875
  my $myconfig = \%main::myconfig;
876
  my $form     = $main::form;
877

  
878
  my $dbh      = $params{dbh} || $form->get_standard_dbh($myconfig);
879

  
880
  do_query($form, $dbh, qq|UPDATE ar SET storno_id = NULL WHERE storno_id = ?|, conv_i($params{trans_id}));
881
  do_query($form, $dbh, qq|UPDATE ap SET storno_id = NULL WHERE storno_id = ?|, conv_i($params{trans_id}));
882
  do_query($form, $dbh, qq|UPDATE gl SET storno_id = NULL WHERE storno_id = ?|, conv_i($params{trans_id}));
883

  
884
  do_query($form, $dbh, qq|DELETE FROM ar        WHERE id       = ?|, conv_i($params{trans_id}));
885
  do_query($form, $dbh, qq|DELETE FROM ap        WHERE id       = ?|, conv_i($params{trans_id}));
886
  do_query($form, $dbh, qq|DELETE FROM gl        WHERE id       = ?|, conv_i($params{trans_id}));
887
  do_query($form, $dbh, qq|DELETE FROM acc_trans WHERE trans_id = ?|, conv_i($params{trans_id}));
888

  
889
#   $dbh->rollback();
890
  $dbh->commit() unless ($params{dbh});
891

  
892
  $main::lxdebug->leave_sub();
893
}
894

  
895
1;
SL/Locale.pm
85 85
      $self->{charset} = Common::DEFAULT_CHARSET;
86 86
    }
87 87

  
88
    my $db_charset         = $main::dbcharset || Common::DEFAULT_CHARSET;
88
    my $db_charset            = $main::dbcharset || Common::DEFAULT_CHARSET;
89 89

  
90
    $self->{iconv}         = Text::Iconv->new($self->{charset}, $db_charset);
91
    $self->{iconv_reverse} = Text::Iconv->new($db_charset,      $self->{charset});
92
    $self->{iconv_english} = Text::Iconv->new('ASCII',          $db_charset);
93
    $self->{iconv_iso8859} = Text::Iconv->new('ISO-8859-15',    $db_charset);
90
    $self->{iconv}            = Text::Iconv->new($self->{charset}, $db_charset);
91
    $self->{iconv_reverse}    = Text::Iconv->new($db_charset,      $self->{charset});
92
    $self->{iconv_english}    = Text::Iconv->new('ASCII',          $db_charset);
93
    $self->{iconv_iso8859}    = Text::Iconv->new('ISO-8859-15',    $db_charset);
94
    $self->{iconv_to_iso8859} = Text::Iconv->new($db_charset,      'ISO-8859-15');
94 95

  
95 96
    $self->_read_special_chars_file($country);
96 97
  }
SL/Taxkeys.pm
1
package Taxkeys;
2

  
3
use strict;
4

  
5
use Memoize;
6

  
7
use SL::DBUtils;
8

  
9
sub new {
10
  my $type = shift;
11

  
12
  my $self = {};
13

  
14
  bless $self, $type;
15

  
16
  return $self->_init();
17
}
18

  
19
sub DESTROY {
20
  my $self = shift;
21

  
22
  $self->_finish_statements();
23
}
24

  
25
sub _init {
26
  my $self = shift;
27

  
28
  $self->{handles} = { };
29
  $self->{queries} = { };
30

  
31
  memoize 'get_tax_info';
32
  memoize 'get_full_tax_info';
33

  
34
  return $self;
35
}
36

  
37
sub _finish_statements {
38
  $main::lxdebug->enter_sub();
39

  
40
  my $self = shift;
41

  
42
  foreach my $idx (keys %{ $self->{handles} }) {
43
    $self->{handles}->{$idx}->finish();
44
    delete $self->{handles}->{$idx};
45
  }
46

  
47
  $main::lxdebug->leave_sub();
48
}
49

  
50
sub get_tax_info {
51
  $main::lxdebug->enter_sub();
52

  
53
  my $self     = shift;
54
  my %params   = @_;
55

  
56
  Common::check_params(\%params, qw(transdate taxkey));
57

  
58
  my $myconfig = \%main::myconfig;
59
  my $form     = $main::form;
60

  
61
  if (!$self->{handles}->{get_tax_info}) {
62
    $self->{queries}->{get_tax_info} = qq|
63
      SELECT t.rate AS taxrate, t.taxnumber, t.taxdescription, t.chart_id AS taxchart_id,
64
        c.accno AS taxaccno, c.description AS taxaccount
65
      FROM taxkeys tk
66
      LEFT JOIN tax t   ON (tk.tax_id  = t.id)
67
      LEFT JOIN chart c ON (t.chart_id = c.id)
68
      WHERE tk.id =
69
        (SELECT id
70
         FROM taxkeys
71
         WHERE (taxkey_id = ?)
72
           AND (startdate <= ?)
73
         ORDER BY startdate DESC
74
         LIMIT 1)
75
|;
76

  
77
    $self->{handles}->{get_tax_info} = prepare_query($form, $params{dbh} || $form->get_standard_dbh($myconfig), $self->{queries}->{get_tax_info});
78
  }
79

  
80
  my $sth = $self->{handles}->{get_tax_info};
81
  do_statement($form, $sth, $self->{queries}->{get_tax_info}, $params{taxkey}, $params{transdate});
82

  
83
  my $ref = $sth->fetchrow_hashref() || { };
84

  
85
  $main::lxdebug->leave_sub();
86

  
87
  return $ref;
88
}
89

  
90
sub get_full_tax_info {
91
  $main::lxdebug->enter_sub();
92

  
93
  my $self     = shift;
94
  my %params   = @_;
95

  
96
  Common::check_params(\%params, qw(transdate));
97

  
98
  my $myconfig = \%main::myconfig;
99
  my $form     = $main::form;
100

  
101
  my %tax_info     = (
102
    'taxkeys'      => { },
103
    'taxchart_ids' => { },
104
    );
105

  
106
  my @all_taxkeys = map { $_->{taxkey} } (selectall_hashref_query($form, $form->get_standard_dbh(), qq|SELECT DISTINCT taxkey FROM tax WHERE taxkey IS NOT NULL|));
107

  
108
  foreach my $taxkey (@all_taxkeys) {
109
    my $ref = $self->get_tax_info('transdate' => $params{transdate}, 'taxkey' => $taxkey);
110

  
111
    $tax_info{taxkeys}->{$taxkey}            = $ref;
112
    $tax_info{accnos}->{$ref->{taxchart_id}} = $ref if ($ref->{taxchart_id});
113
  }
114

  
115
  $main::lxdebug->leave_sub();
116

  
117
  return %tax_info;
118
}
119

  
120
1;
SL/Template/Plugin/LxERP.pm
90 90
  }
91 91
}
92 92

  
93
sub abs {
94
  my $self = shift;
95
  my $var  = shift;
96

  
97
  return $var < 0 ? $var * -1 : $var;
98
}
99

  
93 100
1;
acctranscorrections.pl
1
link am.pl
bin/mozilla/acctranscorrections.pl
1
use SL::AccTransCorrections;
2
use SL::Form;
3
use SL::User;
4
use Data::Dumper;
5
use YAML;
6

  
7
require "bin/mozilla/common.pl";
8

  
9
sub analyze_filter {
10
  $lxdebug->enter_sub();
11

  
12
  $form->{jsscript} = 1;
13
  $form->{title}    = $locale->text('General ledger corrections');
14
  $form->header();
15
  print $form->parse_html_template('acctranscorrections/analyze_filter');
16

  
17
  $lxdebug->leave_sub();
18
}
19

  
20
sub analyze {
21
  $lxdebug->enter_sub();
22

  
23
  $form->{title} = $locale->text('General ledger corrections');
24

  
25
  delete @{ $form }{qw(transdate_from transdate_to)} if ($form->{scope} eq 'full');
26

  
27
  my $callback = 'acctranscorrections.pl?action=analyze';
28
  map { $callback .= "&${_}=" . $form->escape($form->{$_}) } grep { $form->{$_} } qw(transdate_from transdate_to);
29
  $callback = $form->escape($callback);
30

  
31
  my $analyzer = AccTransCorrections->new();
32

  
33
  my %params   = map { $_ => $form->{$_} } qw(transdate_from transdate_to);
34
  my @problems = $analyzer->analyze(%params, 'callback' => $callback);
35

  
36
  if (!scalar @problems) {
37
    $form->show_generic_information($locale->text('No problems were recognized.'));
38

  
39
    $lxdebug->leave_sub();
40
    return;
41
  }
42

  
43
  $form->header();
44
  print $form->parse_html_template('acctranscorrections/analyze_overview',
45
                                   { 'PROBLEMS' => \@problems,
46
                                     'callback' => $callback,
47
                                   });
48

  
49
  $lxdebug->leave_sub();
50
}
51

  
52
sub assistant {
53
  $lxdebug->enter_sub();
54

  
55
  $form->{title} = $locale->text('Assistant for general ledger corrections');
56

  
57
  $form->isblank('trans_id', $locale->text('Transaction ID missing.'));
58

  
59
  my $analyzer  = AccTransCorrections->new();
60
  my ($problem) = $analyzer->analyze('trans_id' => $form->{trans_id}, 'full_analysis' => 1);
61

  
62
  if (!$problem) {
63
    my $module =
64
        $form->{trans_module} eq 'ar' ? $locale->text('AR Transaction')
65
      : $form->{trans_module} eq 'ap' ? $locale->text('AP Transaction')
66
      :                                 $locale->text('General Ledger Transaction');
67

  
68
    $form->show_generic_information($locale->text('The assistant could not find anything wrong with #1. Maybe the problem has been solved in the meantime.',
69
                                                  "$module $form->{trans_reference}"));
70

  
71
    $lxdebug->leave_sub();
72
    return;
73
  }
74

  
75
  if ($problem->{type} eq 'wrong_taxkeys') {
76
    assistant_for_wrong_taxkeys($problem);
77

  
78
  } elsif ($problem->{type} eq 'wrong_taxes') {
79
    assistant_for_wrong_taxkeys($problem);
80
#     assistant_for_wrong_taxes($problem);
81

  
82
  } else {
83
    $form->show_generic_error($locale->text('Unknown problem type.'));
84
  }
85

  
86
  $lxdebug->leave_sub();
87
}
88

  
89
sub assistant_for_ap_ar_wrong_taxkeys {
90
  $lxdebug->enter_sub();
91

  
92
  $form->{title} = $locale->text('Assistant for general ledger corrections');
93

  
94
  $form->header();
95
  print $form->parse_html_template('acctranscorrections/assistant_for_ap_ar_wrong_taxkeys');
96

  
97
  $lxdebug->leave_sub();
98
}
99

  
100
sub fix_ap_ar_wrong_taxkeys {
101
  $lxdebug->enter_sub();
102

  
103
  my $analyzer = AccTransCorrections->new();
104
  $analyzer->fix_ap_ar_wrong_taxkeys();
105

  
106
  $form->{title} = $locale->text('Assistant for general ledger corrections');
107
  $form->header();
108
  print $form->parse_html_template('acctranscorrections/fix_ap_ar_wrong_taxkeys');
109

  
110
  $lxdebug->leave_sub();
111
}
112

  
113
sub assistant_for_invoice_inventory_with_taxkeys {
114
  $lxdebug->enter_sub();
115

  
116
  $form->{title} = $locale->text('Assistant for general ledger corrections');
117

  
118
  $form->header();
119
  print $form->parse_html_template('acctranscorrections/assistant_for_invoice_inventory_with_taxkeys');
120

  
121
  $lxdebug->leave_sub();
122
}
123

  
124
sub fix_invoice_inventory_with_taxkeys {
125
  $lxdebug->enter_sub();
126

  
127
  my $analyzer  = AccTransCorrections->new();
128
  $analyzer->fix_invoice_inventory_with_taxkeys();
129

  
130
  $form->{title} = $locale->text('Assistant for general ledger corrections');
131
  $form->header();
132
  print $form->parse_html_template('acctranscorrections/fix_invoice_inventory_with_taxkeys');
133

  
134
  $lxdebug->leave_sub();
135
}
136

  
137
sub assistant_for_wrong_taxes {
138
  $lxdebug->enter_sub();
139

  
140
  my $problem = shift;
141

  
142
  $form->{title} = $locale->text('Assistant for general ledger corrections');
143

  
144
  $form->header();
145
  print $form->parse_html_template('acctranscorrections/assistant_for_wrong_taxes', { 'problem' => $problem, });
146

  
147
  $lxdebug->leave_sub();
148
}
149

  
150
sub assistant_for_wrong_taxkeys {
151
  $lxdebug->enter_sub();
152

  
153
  my $problem = shift;
154

  
155
  $form->{title} = $locale->text('Assistant for general ledger corrections');
156

  
157
  $form->header();
158
  print $form->parse_html_template('acctranscorrections/assistant_for_wrong_taxkeys', { 'problem' => $problem, });
159

  
160
  $lxdebug->leave_sub();
161
}
162

  
163
sub fix_wrong_taxkeys {
164
  $lxdebug->enter_sub();
165

  
166
  my $fixes = ref $form->{fixes} eq 'ARRAY' ? $form->{fixes} : [];
167

  
168
  my $analyzer  = AccTransCorrections->new();
169
  $analyzer->fix_wrong_taxkeys('fixes' => $fixes);
170

  
171
  $form->{title} = $locale->text('Assistant for general ledger corrections');
172
  $form->header();
173
  print $form->parse_html_template('acctranscorrections/fix_wrong_taxkeys');
174

  
175
  $lxdebug->leave_sub();
176
}
177

  
178
sub delete_transaction {
179
  $lxdebug->enter_sub();
180

  
181
  $form->{title} = $locale->text('Delete transaction');
182
  $form->header();
183

  
184
  if (!$form->{confirmation}) {
185
    print $form->parse_html_template('acctranscorrections/delete_transaction_confirmation');
186
  } else {
187
    my $analyzer  = AccTransCorrections->new();
188
    $analyzer->delete_transaction('trans_id' => $form->{trans_id});
189

  
190
    print $form->parse_html_template('acctranscorrections/delete_transaction');
191
  }
192

  
193
  $lxdebug->leave_sub();
194
}
195

  
196
sub redirect {
197
  $lxdebug->enter_sub();
198

  
199
  $form->redirect('Missing callbcak');
200

  
201
  $lxdebug->leave_sub();
202
}
203

  
204
sub dispatcher {
205
  foreach my $action (qw(fix_wrong_taxkeys delete_transaction)) {
206
    if ($form->{"action_${action}"}) {
207
      call_sub($action);
208
      return;
209
    }
210
  }
211

  
212
  $form->error($locale->text('No action defined.'));
213
}
214

  
215
1;
locale/de/acctranscorrections
1
#!/usr/bin/perl
2

  
3
$self->{texts} = {
4
  'ADDED'                       => 'Hinzugef?gt',
5
  'AP'                          => 'Einkauf',
6
  'AP Transaction'              => 'Kreditorenbuchung',
7
  'AR'                          => 'Verkauf',
8
  'AR Transaction'              => 'Debitorenbuchung',
9
  'Address'                     => 'Adresse',
10
  'Advance turnover tax return' => 'Umsatzsteuervoranmeldung',
11
  'All reports'                 => 'Alle Berichte (Konten&uuml;bersicht, Summen- u. Saldenliste, GuV, BWA, Bilanz, Projektbuchungen)',
12
  'Assistant for general ledger corrections' => 'Assistent f?r die Korrektur von Hauptbucheintr?gen',
13
  'Attempt to call an undefined sub named \'%s\'' => 'Es wurde versucht, eine nicht definierte Unterfunktion namens \'%s\' aufzurufen.',
14
  'Bcc'                         => 'Bcc',
15
  'Bin List'                    => 'Lagerliste',
16
  'Binding to the LDAP server as "#1" failed. Please check config/authentication.pl.' => 'Die Anmeldung am LDAP-Server als "#1" schlug fehl. Bitte &uuml;berpr&uuml;fen Sie die Angaben in config/authentication.pl.',
17
  'CANCELED'                    => 'Storniert',
18
  'Cc'                          => 'Cc',
19
  'Change Lx-Office installation settings (all menu entries beneath \'System\')' => 'Ver&auml;ndern der Lx-Office-Installationseinstellungen (Men&uuml;punkte unterhalb von \'System\')',
20
  'Confirmation'                => 'Auftragsbest?tigung',
21
  'Contact'                     => 'Kontakt',
22
  'Create and edit RFQs'        => 'Lieferantenanfragen erfassen und bearbeiten',
23
  'Create and edit customers and vendors' => 'Kunden und Lieferanten erfassen und bearbeiten',
24
  'Create and edit dunnings'    => 'Mahnungen erfassen und bearbeiten',
25
  'Create and edit invoices and credit notes' => 'Rechnungen und Gutschriften erfassen und bearbeiten',
26
  'Create and edit parts, services, assemblies' => 'Artikel, Dienstleistungen, Erzeugnisse erfassen und bearbeiten',
27
  'Create and edit projects'    => 'Projekte erfassen und bearbeiten',
28
  'Create and edit purchase delivery orders' => 'Lieferscheine von Lieferanten erfassen und bearbeiten',
29
  'Create and edit purchase orders' => 'Lieferantenauftr&auml;ge erfassen und bearbeiten',
30
  'Create and edit sales delivery orders' => 'Lieferscheine f&uuml;r Kunden erfassen und bearbeiten',
31
  'Create and edit sales orders' => 'Auftragsbest&auml;tigungen erfassen und bearbeiten',
32
  'Create and edit sales quotations' => 'Angebote erfassen und bearbeiten',
33
  'Create and edit vendor invoices' => 'Eingangsrechnungen erfassen und bearbeiten',
34
  'Credit Note'                 => 'Gutschrift',
35
  'Customer Number'             => 'Kundennummer',
36
  'Customer details'            => 'Kundendetails',
37
  'DATEV Export'                => 'DATEV-Export',
38
  'DELETED'                     => 'Gel?scht',
39
  'DUNNING STARTED'             => 'Mahnprozess gestartet',
40
  'Dataset upgrade'             => 'Datenbankaktualisierung',
41
  'Date'                        => 'Datum',
42
  'Delete transaction'          => 'Buchung l?schen',
43
  'Delivery Order'              => 'Lieferschein',
44
  'Dependency loop detected:'   => 'Schleife in den Abh&auml;ngigkeiten entdeckt:',
45
  'Directory'                   => 'Verzeichnis',
46
  'ELSE'                        => 'Zusatz',
47
  'Enter longdescription'       => 'Langtext eingeben',
48
  'Error in database control file \'%s\': %s' => 'Fehler in Datenbankupgradekontrolldatei \'%s\': %s',
49
  'File'                        => 'Datei',
50
  'General Ledger Transaction'  => 'Dialogbuchung',
51
  'General ledger and cash'     => 'Finanzbuchhaltung und Zahlungsverkehr',
52
  'General ledger corrections'  => 'Korrekturen im Hauptbuch',
53
  'History'                     => 'Historie',
54
  'Invoice'                     => 'Rechnung',
55
  'MAILED'                      => 'Gesendet',
56
  'Manage license keys'         => 'Lizenzschl&uuml;ssel verwalten',
57
  'Mark as paid?'               => 'Als bezahlt markieren?',
58
  'Marked as paid'              => 'Als bezahlt markiert',
59
  'Master Data'                 => 'Stammdaten',
60
  'May set the BCC field when sending emails' => 'Beim Verschicken von Emails das Feld \'BCC\' setzen',
61
  'Message'                     => 'Nachricht',
62
  'Missing \'description\' field.' => 'Fehlendes Feld \'description\'.',
63
  'Missing \'tag\' field.'      => 'Fehlendes Feld \'tag\'.',
64
  'Missing parameter #1 in call to sub #2.' => 'Fehlernder Parameter \'#1\' in Funktionsaufruf \'#2\'.',
65
  'Missing parameter (at least one of #1) in call to sub #2.' => 'Fehlernder Parameter (mindestens einer aus \'#1\') in Funktionsaufruf \'#2\'.',
66
  'More than one control file with the tag \'%s\' exist.' => 'Es gibt mehr als eine Kontrolldatei mit dem Tag \'%s\'.',
67
  'Name'                        => 'Name',
68
  'No %s was found matching the search parameters.' => 'Es wurde kein %s gefunden, auf den die Suchparameter zutreffen.',
69
  'No Customer was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein Endkunde gefunden',
70
  'No Vendor was found matching the search parameters.' => 'Zu dem Suchbegriff wurde kein H?ndler gefunden',
71
  'No action defined.'          => 'Keine Aktion definiert.',
72
  'No customer has been selected yet.' => 'Es wurde noch kein Kunde ausgew?hlt.',
73
  'No or an unknown authenticantion module specified in "config/authentication.pl".' => 'Es wurde kein oder ein unbekanntes Authentifizierungsmodul in "config/authentication.pl" angegeben.',
74
  'No part was found matching the search parameters.' => 'Es wurde kein Artikel gefunden, auf den die Suchparameter zutreffen.',
75
  'No problems were recognized.' => 'Es wurden keine Probleme gefunden.',
76
  'No vendor has been selected yet.' => 'Es wurde noch kein Lieferant ausgew?hlt.',
77
  'Others'                      => 'Andere',
78
  'PAYMENT POSTED'              => 'Rechung gebucht',
79
  'POSTED'                      => 'Gebucht',
80
  'POSTED AS NEW'               => 'Als neu gebucht',
81
  'PRINTED'                     => 'Gedruckt',
82
  'Packing List'                => 'Lieferschein',
83
  'Part Number'                 => 'Artikelnummer',
84
  'Part description'            => 'Artikelbeschreibung',
85
  'Pick List'                   => 'Packliste',
86
  'Please enter values'         => 'Bitte Werte eingeben',
87
  'Preview'                     => 'Druckvorschau',
88
  'Proforma Invoice'            => 'Proformarechnung',
89
  'Purchase Order'              => 'Lieferantenauftrag',
90
  'Quotation'                   => 'Angebot',
91
  'RFQ'                         => 'Anfrage',
92
  'Receipt, payment, reconciliation' => 'Zahlungseingang, Zahlungsausgang, Kontenabgleich',
93
  'Reports'                     => 'Berichte',
94
  'SAVED'                       => 'Gespeichert',
95
  'SAVED FOR DUNNING'           => 'Gespeichert',
96
  'SCREENED'                    => 'Angezeigt',
97
  'Select a Customer'           => 'Endkunde ausw?hlen',
98
  'Select a customer'           => 'Einen Kunden ausw&auml;hlen',
99
  'Select a part'               => 'Artikel ausw&auml;hlen',
100
  'Select a vendor'             => 'Einen Lieferanten ausw&auml;hlen',
101
  'Storno Invoice'              => 'Stornorechnung',
102
  'Storno Packing List'         => 'Stornolieferschein',
103
  'Subject'                     => 'Betreff',
104
  'The \'tag\' field must only consist of alphanumeric characters or the carachters - _ ( )' => 'Das Feld \'tag\' darf nur aus alphanumerischen Zeichen und den Zeichen - _ ( ) bestehen.',
105
  'The LDAP server "#1:#2" is unreachable. Please check config/authentication.pl.' => 'Der LDAP-Server "#1:#2" ist nicht erreichbar. Bitte &uuml;berpr&uuml;fen Sie die Angaben in config/authentication.pl.',
106
  'The assistant could not find anything wrong with #1. Maybe the problem has been solved in the meantime.' => 'Der Korrekturassistent konnte kein Problem bei #1 feststellen. Eventuell wurde das Problem in der Zwischenzeit bereits behoben.',
107
  'The config file "config/authentication.pl" contained invalid Perl code:' => 'Die Konfigurationsdatei "config/authentication.pl" enthielt ung&uuml;tigen Perl-Code:',
108
  'The config file "config/authentication.pl" was not found.' => 'Die Konfigurationsdatei "config/authentication.pl" wurde nicht gefunden.',
109
  'The connection to the LDAP server cannot be encrypted (SSL/TLS startup failure). Please check config/authentication.pl.' => 'Die Verbindung zum LDAP-Server kann nicht verschl&uuml;sselt werden (Fehler bei SSL/TLS-Initialisierung). Bitte &uuml;berpr&uuml;fen Sie die Angaben in config/authentication.pl.',
110
  'The connection to the authentication database failed:' => 'Die Verbindung zur Authentifizierungsdatenbank schlug fehl:',
111
  'The connection to the template database failed:' => 'Die Verbindung zur Vorlagendatenbank schlug fehl:',
112
  'The creation of the authentication database failed:' => 'Das Anlegen der Authentifizierungsdatenbank schlug fehl:',
113
  'To (email)'                  => 'An',
114
  'Transaction ID missing.'     => 'Die Buchungs-ID fehlt.',
115
  'Transactions, AR transactions, AP transactions' => 'Dialogbuchen, Debitorenrechnungen, Kreditorenrechnungen',
116
  'Trying to call a sub without a name' => 'Es wurde versucht, eine Unterfunktion ohne Namen aufzurufen.',
117
  'Unit'                        => 'Einheit',
118
  'Unknown dependency \'%s\'.'  => 'Unbekannte Abh&auml;ngigkeit \'%s\'.',
119
  'Unknown problem type.'       => 'Unbekannter Problem-Typ',
120
  'Value'                       => 'Wert',
121
  'Variable'                    => 'Variable',
122
  'Vendor details'              => 'Lieferantendetails',
123
  'View warehouse content'      => 'Lagerbestand ansehen',
124
  'Warehouse management'        => 'Lagerverwaltung/Bestandsver?nderung',
125
  'You do not have the permissions to access this function.' => 'Sie verf&uuml;gen nicht &uuml;ber die notwendigen Rechte, um auf diese Funktion zuzugreifen.',
126
  '[email]'                     => '[email]',
127
  'bin_list'                    => 'Lagerliste',
128
  'config/authentication.pl: Key "DB_config" is missing.' => 'config/authentication.pl: Das Schl&uuml;sselwort "DB_config" fehlt.',
129
  'config/authentication.pl: Key "LDAP_config" is missing.' => 'config/authentication.pl: Der Schl&uuml;ssel "LDAP_config" fehlt.',
130
  'config/authentication.pl: Missing parameters in "DB_config". Required parameters are "host", "db" and "user".' => 'config/authentication.pl: Fehlende Parameter in "DB_config". Ben&ouml;tigte Parameter sind "host", "db" und "user".',
131
  'config/authentication.pl: Missing parameters in "LDAP_config". Required parameters are "host", "attribute" and "base_dn".' => 'config/authentication.pl: Fehlende Parameter in "LDAP_config". Ben&ouml;tigt werden "host", "attribute" und "base_dn".',
132
  'customer'                    => 'Kunde',
133
  'invoice'                     => 'Rechnung',
134
  'no'                          => 'nein',
135
  'packing_list'                => 'Versandliste',
136
  'pick_list'                   => 'Entnahmeliste',
137
  'proforma'                    => 'Proforma',
138
  'purchase_order'              => 'Auftrag',
139
  'request_quotation'           => 'Angebotsanforderung',
140
  'sales_order'                 => 'Kundenauftrag',
141
  'sales_quotation'             => 'Verkaufsangebot',
142
  'vendor'                      => 'Lieferant',
143
  'yes'                         => 'ja',
144
};
145

  
146
$self->{subs} = {
147
  'E'                           => 'E',
148
  'H'                           => 'H',
149
  'J'                           => 'J',
150
  'NTI'                         => 'NTI',
151
  'Q'                           => 'Q',
152
  'analyze'                     => 'analyze',
153
  'analyze_filter'              => 'analyze_filter',
154
  'assistant'                   => 'assistant',
155
  'assistant_for_ap_ar_wrong_taxkeys' => 'assistant_for_ap_ar_wrong_taxkeys',
156
  'assistant_for_invoice_inventory_with_taxkeys' => 'assistant_for_invoice_inventory_with_taxkeys',
157
  'assistant_for_wrong_taxes'   => 'assistant_for_wrong_taxes',
158
  'assistant_for_wrong_taxkeys' => 'assistant_for_wrong_taxkeys',
159
  'build_std_url'               => 'build_std_url',
160
  'calculate_qty'               => 'calculate_qty',
161
  'call_sub'                    => 'call_sub',
162
  'cov_selection_internal'      => 'cov_selection_internal',
163
  'delete_transaction'          => 'delete_transaction',
164
  'delivery_customer_selection' => 'delivery_customer_selection',
165
  'dispatcher'                  => 'dispatcher',
166
  'fix_ap_ar_wrong_taxkeys'     => 'fix_ap_ar_wrong_taxkeys',
167
  'fix_invoice_inventory_with_taxkeys' => 'fix_invoice_inventory_with_taxkeys',
168
  'fix_wrong_taxkeys'           => 'fix_wrong_taxkeys',
169
  'format_dates'                => 'format_dates',
170
  'mark_as_paid_common'         => 'mark_as_paid_common',
171
  'part_selection_internal'     => 'part_selection_internal',
172
  'redirect'                    => 'redirect',
173
  'reformat_numbers'            => 'reformat_numbers',
174
  'retrieve_partunits'          => 'retrieve_partunits',
175
  'select_part'                 => 'select_part',
176
  'select_part_internal'        => 'select_part_internal',
177
  'set_longdescription'         => 'set_longdescription',
178
  'show_history'                => 'show_history',
... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.

Auch abrufbar als: Unified diff