Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 95f601bd

Von Martin Helmling mh@waldpark.octosoft.eu vor etwa 8 Jahren hinzugefügt

  • ID 95f601bd5af1c5a76ed4950d4f68984bbf9649ad
  • Vorgänger ce52db90
  • Nachfolger c1c6288a

Erstellen von Jahresabschluss-Buchungen

Das Erstellen von Schluss- und Eröffnungsbuchungen (mit Saldovortrag auf 9000-Konten)
wird erleichtern bzw. automatisieren.

- Neuer Menüpunkt "Finanzbuchhaltung > SB/EB buchen"
Buchungsdatum:
SB: dem 31.12. des Vorjahres
EB: dem 01.01. des aktuellen Jahre
- Referenz und Beschreibung
- Auswahl eines 9000 Kontos
- Danach Liste der unausgeglichenen Konten, per Checkbox auswählbar.
- Iteratives Erzeugen der SB / EB Buchungen
- Start der Saldoberechnung abhängig von Mandantenkonfig Einstellungen "get_balance_startdate_method" und "closedto"

- Erweiterung der zweiten Seite (SB/EB buchen)

1. Zusätzliche Spalte "Summe SB-Buchungen" welche die Summe aller SB-Buchungen im betroffenen Zeitraum anzeigt.
2. Zusätzliche Spalte "Summe EB-Buchungen" welche die Summe aller EB-Buchungen im Zeitraum des nächsten Jahres anzeigt.
3. Die Anzeige "Salden von $datum bis $datum" als gemeinsame Spaltenüberschrift "Zeitraum: $datum - $datum" für die Spalten "Soll", "Haben", "Summe SB-Buchungen"
4. Eine ähnliche zweite Überschrift "Zeitraum: $datum2 - $datum2" für die Spalte "Summe EB-Buchungen", wobei $datum2 hier das "folgejahr" darstellt.

- Nun auch S und H bei Summenspalten
- Test eingebaut

Unterschiede anzeigen:

SL/Controller/YearlyTransactions.pm
1
package SL::Controller::YearlyTransactions;
2

  
3
use strict;
4

  
5
use parent qw(SL::Controller::Base);
6

  
7
use DateTime;
8
use SL::Locale::String qw(t8);
9
use SL::ReportGenerator;
10
use SL::Helper::Flash;
11
use SL::DBUtils;
12

  
13
use SL::DB::Chart;
14
use SL::DB::GLTransaction;
15
use SL::DB::AccTransaction;
16
use SL::DB::Helper::AccountingPeriod qw(get_balance_starting_date);
17

  
18
use Rose::Object::MakeMethods::Generic (
19
  'scalar --get_set_init' => [ qw(charts charts9000 cbob_chart cb_date cb_startdate ob_date cb_reference ob_reference cb_description ob_description) ],
20
);
21

  
22
__PACKAGE__->run_before('check_auth');
23

  
24
sub action_filter {
25
  my ($self) = @_;
26

  
27
  $self->ob_date(DateTime->today->truncate(to => 'year'))                  if !$self->ob_date;
28
  $self->cb_date(DateTime->today->truncate(to => 'year')->add(days => -1)) if !$self->cb_date;
29
  $self->ob_reference(t8('OB Transaction')) if !$self->ob_reference;
30
  $self->cb_reference(t8('CB Transaction')) if !$self->cb_reference;
31
  $self->ob_description(t8('OB Transaction')) if !$self->ob_description;
32
  $self->cb_description(t8('CB Transaction')) if !$self->cb_description;
33
  $self->render('gl/yearly_filter', 
34
                title => t8('CB/OB Transactions'),
35
                make_title_of_chart => sub { $_[0]->accno.' '.$_[0]->description }
36
               );
37

  
38
}
39

  
40
sub action_list {
41
  my ($self) = @_;
42
  $main::lxdebug->enter_sub();
43

  
44
  my $report     = SL::ReportGenerator->new(\%::myconfig, $::form);
45

  
46
  $self->prepare_report($report);
47

  
48
  $report->set_options(
49
    output_format    => 'HTML',
50
    raw_top_info_text    => $::form->parse_html_template('gl/yearly_top', { SELF => $self }),
51
    raw_bottom_info_text => $::form->parse_html_template('gl/yearly_bottom', { SELF => $self }),
52
    allow_pdf_export => 0,
53
    allow_csv_export => 0,
54
    title            => $::locale->text('CB/OB Transactions'),
55
    );
56
  $report->generate_with_headers();
57
  $main::lxdebug->leave_sub();
58
}
59

  
60
sub action_generate {
61
  my ($self) = @_;
62

  
63
  my $cnt = $self->make_booking();
64

  
65
  flash('info', $::locale->text('#1 CB transactions and #1 OB transactions generated.',$cnt)) if $cnt > 0;
66

  
67
  $self->action_list;
68
}
69

  
70
sub check_auth {
71
  $::auth->assert('general_ledger');
72
}
73

  
74
#
75
# helpers
76
#
77

  
78
sub make_booking {
79
  my ($self) = @_;
80
  $main::lxdebug->enter_sub();
81
  my @ids = map { $::form->{"trans_id_$_"} } grep { $::form->{"multi_id_$_"} } (1..$::form->{rowcount});
82
  my $cnt = 0;
83
  $main::lxdebug->message(LXDebug->DEBUG2(),"generate for ".$::form->{cbob_chart}." # ".scalar(@ids)." charts");
84
  if (scalar(@ids) && $::form->{cbob_chart}) {
85
    my $carryoverchart = SL::DB::Manager::Chart->get_first(  query => [ id => $::form->{cbob_chart} ] );
86
    my $charts = SL::DB::Manager::Chart->get_all(  query => [ id => \@ids ] );
87
    foreach my $chart (@{ $charts }) {
88
      $main::lxdebug->message(LXDebug->DEBUG2(),"chart_id=".$chart->id." accno=".$chart->accno);
89
      my $balance = $self->get_balance($chart);
90
      if ( $balance != 0 ) {
91
        # SB
92
        $self->gl_booking($balance,$self->cb_date,$::form->{cb_reference},$::form->{cb_description},$chart,$carryoverchart,0,1);
93
        # EB
94
        $self->gl_booking($balance,$self->ob_date,$::form->{ob_reference},$::form->{ob_description},$carryoverchart,$chart,1,0);
95
        $cnt++;
96
      }
97
    }
98
  }
99
  $main::lxdebug->leave_sub();
100
  return $cnt;
101
}
102

  
103

  
104
sub prepare_report {
105
  my ($self,$report) = @_;
106
  $main::lxdebug->enter_sub();
107
  my $idx = 1;
108
  my $cgi = $::request->{cgi};
109

  
110
  my %column_defs = (
111
    'ids'                     => { 'text' => '<input type="checkbox" id="multi_all" value="1">', 'align' => 'center' },
112
    'chart'                   => { 'text' => $::locale->text('Account'), },
113
    'description'             => { 'text' => $::locale->text('Description'), },
114
    'saldo'                   => { 'text' => $::locale->text('Saldo'),  'align' => 'right'},
115
    'sum_cb'                  => { 'text' => $::locale->text('Sum CB Transactions'), 'align' => 'right'},  ##close == Schluss
116
    'sum_ob'                  => { 'text' => $::locale->text('Sum OB Transactions'), 'align' => 'right'},  ##open  == Eingang
117
  );
118
  my @columns    = qw(ids chart description saldo sum_cb sum_ob);
119
  map { $column_defs{$_}->{visible} = 1 } @columns;
120
  my $ob_next_date = $::locale->parse_date_to_object($self->ob_date)->add(years => 1)->add(days => -1)->to_kivitendo;
121

  
122
  $self->cb_startdate($self->get_balance_starting_date($self->cb_date));
123

  
124
  my @custom_headers = ();
125
  # Zeile 1:
126
  push @custom_headers, [
127
      { 'text' => '   ', 'colspan' => 3 },
128
      { 'text' => $::locale->text("Timerange")."<br />".$self->cb_startdate." - ".$self->cb_date, 'colspan' => 2, 'align' => 'center'},
129
      { 'text' => $::locale->text("Timerange")."<br />".$self->ob_date." - ".$ob_next_date, 'align' => 'center'},
130
    ];
131

  
132
  # Zeile 2:
133
  my @line_2 = ();
134
  map { push @line_2 , $column_defs{$_} } grep { $column_defs{$_}->{visible} } @columns;
135
  push @custom_headers, [ @line_2 ];
136

  
137
  $report->set_custom_headers(@custom_headers);
138
  $report->set_columns(%column_defs);
139
  $report->set_column_order(@columns);
140

  
141
  my $chart9actual = SL::DB::Manager::Chart->get_first( query => [ id => $self->cbob_chart ] );
142
  $self->{cbob_chartaccno} = $chart9actual->accno.' '.$chart9actual->description;
143

  
144
  foreach my $chart (@{ $self->charts }) {
145
    my $balance = $self->get_balance($chart);
146
    if ( $balance != 0 ) {
147
      my $chart_id = $chart->id;
148
      my $row = { map { $_ => { 'data' => '' } } @columns };
149
      $row->{ids}  = {
150
        'raw_data' =>   $cgi->hidden('-name' => "trans_id_${idx}", '-value' => $chart_id)
151
                    . $cgi->checkbox('-name' => "multi_id_${idx}",' id' => "multi_id_id_".$chart_id, '-value' => 1, '-label' => ''),
152
            'valign'   => 'center',
153
            'align'    => 'center',
154
      };
155
      $row->{chart}->{data}        = $chart->accno;
156
      $row->{description}->{data}  = $chart->description;
157
      if ( $balance > 0 ) {
158
        $row->{saldo}->{data} = $::form->format_amount(\%::myconfig, $balance, 2)." H";
159
      } elsif ( $balance < 0 )  {
160
        $row->{saldo}->{data} = $::form->format_amount(\%::myconfig,-$balance, 2)." S";
161
      } else {
162
        $row->{saldo}->{data} = $::form->format_amount(\%::myconfig,0, 2)."  ";
163
      }
164
      my $sum_cb = 0;
165
      foreach my $acc ( @{ SL::DB::Manager::AccTransaction->get_all(where => [ chart_id => $chart->id, cb_transaction => 't',
166
                                                                               transdate => { ge => $self->cb_startdate},
167
                                                                               transdate => { le => $self->cb_date }]) }) {
168
        $sum_cb += $acc->amount;
169
      }
170
      my $sum_ob = 0;
171
      foreach my $acc ( @{ SL::DB::Manager::AccTransaction->get_all(where => [ chart_id => $chart->id, ob_transaction => 't',
172
                                                                               transdate => { ge => $self->ob_date},
173
                                                                               transdate => { le => $ob_next_date }]) }) {
174
        $sum_ob += $acc->amount;
175
      }
176
      if ( $sum_cb > 0 ) {
177
        $row->{sum_cb}->{data} = $::form->format_amount(\%::myconfig, $sum_cb, 2)." H";
178
      } elsif ( $sum_cb < 0 )  {
179
        $row->{sum_cb}->{data} = $::form->format_amount(\%::myconfig,-$sum_cb, 2)." S";
180
      } else {
181
        $row->{sum_cb}->{data} = $::form->format_amount(\%::myconfig,0, 2)."  ";
182
      }
183
      if ( $sum_ob > 0 ) {
184
        $row->{sum_ob}->{data} = $::form->format_amount(\%::myconfig, $sum_ob, 2)." H";
185
      } elsif ( $sum_ob < 0 )  {
186
        $row->{sum_ob}->{data} = $::form->format_amount(\%::myconfig,-$sum_ob, 2)." S";
187
      } else {
188
        $row->{sum_ob}->{data} = $::form->format_amount(\%::myconfig,0, 2)."  ";
189
      }
190
      $report->add_data($row);
191
    }
192
    $idx++;
193
  }
194

  
195
  $self->{row_count} = $idx;
196
  $main::lxdebug->leave_sub();
197
}
198

  
199
sub get_balance {
200
  $main::lxdebug->enter_sub();
201
  my ($self,$chart) = @_;
202

  
203
## eigene Abfrage da SL:DB:Chart->get_balance keine cb_transactions mitzählt
204
## Alternative in Chart cb_transaction abfrage per neuem Parameter 'with_cb' disablen:
205
#  my %balance_params = ( fromdate   => $self->startdate,
206
#                         todate     => $self->cb_date,
207
#                         accounting_method => 'accrual',
208
#                         with_cb    => 1, ## in Chart cb_transaction abfrage disablen
209
#                       );
210
#  return $chart->get_balance(%balance_params);
211

  
212
  $main::lxdebug->message(LXDebug->DEBUG2(),"get_balance from=".$self->cb_startdate." to=".$self->cb_date);
213
  my $query = qq|SELECT SUM(amount) AS sum FROM acc_trans WHERE chart_id = ? | .
214
              qq| AND transdate >= ? AND transdate <= ? |;
215
  my @query_args = ( $chart->id, $self->cb_startdate, $self->cb_date);
216
  my ($balance)  = selectfirst_array_query($::form, $chart->db->dbh, $query, @query_args);
217

  
218
  $main::lxdebug->leave_sub();
219
  return 0 unless $balance != 0;
220
  return $balance;
221
}
222

  
223
sub gl_booking {
224
  my ($self, $amount, $transdate, $reference, $description, $konto, $gegenkonto, $ob, $cb) = @_;
225
  $::form->get_employee();
226
  my $employee_id = $::form->{employee_id};
227
  $main::lxdebug->message(LXDebug->DEBUG2(),"employee_id=".$employee_id." ob=".$ob." cb=".$cb);
228
  my $gl_entry = SL::DB::GLTransaction->new();
229
  $gl_entry->assign_attributes(
230
    employee_id => $employee_id,
231
    transdate   => $transdate,
232
    reference   => $reference,
233
    description => $description,
234
    ob_transaction => $ob,
235
    cb_transaction => $cb,
236
  );
237
  $gl_entry->save;
238
  my $kto_trans1 = SL::DB::AccTransaction->new();
239
  $kto_trans1->assign_attributes(
240
    trans_id    => $gl_entry->id,
241
    transdate   => $transdate,
242
    ob_transaction => $ob,
243
    cb_transaction => $cb,
244
    chart_id       => $gegenkonto->id,
245
    chart_link     => $konto->link,
246
    tax_id         => 0,
247
    taxkey         => 0,
248
    amount         => $amount,
249
  );
250
  $kto_trans1->save;
251
  my $kto_trans2 = SL::DB::AccTransaction->new();
252
  $kto_trans2->assign_attributes(
253
    trans_id    => $gl_entry->id,
254
    transdate   => $transdate,
255
    ob_transaction => $ob,
256
    cb_transaction => $cb,
257
    chart_id       => $konto->id,
258
    chart_link     => $konto->link,
259
    tax_id         => 0,
260
    taxkey         => 0,
261
    amount         => -$amount,
262
  );
263
  $kto_trans2->save;
264
}
265

  
266
sub init_cbob_chart { $::form->{cbob_chart} }
267
sub init_ob_date { $::form->{ob_date} }
268
sub init_ob_reference { $::form->{ob_reference} }
269
sub init_ob_description { $::form->{ob_description} }
270
sub init_cb_startdate { $::form->{cb_startdate} }
271
sub init_cb_date { $::form->{cb_date} }
272
sub init_cb_reference { $::form->{cb_reference} }
273
sub init_cb_description { $::form->{cb_description} }
274

  
275
sub init_charts9000 { 
276
  # wie geht prüfen von länge auf 4 in rose ?
277
  SL::DB::Manager::Chart->get_all(  query => [ \ "accno like '9%' and length(accno) = 4"] );
278
  #SL::DB::Manager::Chart->get_all(  query => [ accno => { like => '9%'}] );
279
}
280

  
281
sub init_charts { 
282
  # wie geht 'not like' in rose ?
283
  SL::DB::Manager::Chart->get_all(  query => [ \ "accno not like '9%'"], sort_by => 'accno ASC' );
284
}
285

  
286
1;
locale/de/all
15 15
  ' Part Number missing!'       => ' Artikelnummer fehlt!',
16 16
  ' missing!'                   => ' fehlt!',
17 17
  '#1 (custom variable)'        => '#1 (benutzerdefinierte Variable)',
18
  '#1 CB transactions and #1 OB transactions generated.' => '#1 Schluss- und #1 Eröffnungsbuchungen wurden erstellt.',
18 19
  '#1 MD'                       => '#1 PT',
19 20
  '#1 additional part(s)'       => '#1 zusätzliche(r) Artikel',
20 21
  '#1 dunnings have been deleted' => '#1 Mahnung(en) wurden gelöscht',
......
274 275
  'Apr'                         => 'Apr',
275 276
  'April'                       => 'April',
276 277
  'Ar aging on %s'              => 'Offene Forderungen zum %s',
278
  'Are you sure to generate cb/ob transactions?' => 'Sollen die EB/SB Buchungen wirklich erzeugt werden?',
277 279
  'Are you sure you want to delete Invoice Number' => 'Soll die Rechnung mit folgender Nummer wirklich gelöscht werden:',
278 280
  'Are you sure you want to delete Transaction' => 'Buchung wirklich löschen?',
279 281
  'Are you sure you want to delete this background job?' => 'Sind Sie sicher, dass Sie diesen Hintergrund-Job löschen möchten?',
......
317 319
  'Attachment name'             => 'Name des Anhangs',
318 320
  'Attachments'                 => 'Dateianhänge',
319 321
  'Attempt to call an undefined sub named \'%s\'' => 'Es wurde versucht, eine nicht definierte Unterfunktion namens \'%s\' aufzurufen.',
322
  'Attention: Here will be generated a lot of CB/OB transactions.' => 'Hiermit werden Buchungen für den Schlussbestand (SB-Buchung) und den Eröffnungsbestand (EB-Buchung) für mehrere Konten gleichzeitig gebucht.<br>In diesem Schritt wird das Datum der Buchungen sowie das Saldovortragskonto festgelegt.<br>Das Datum der SB-Buchung wird außerdem verwendet um das Saldo der Konten zu ermitteln, welche im nächsten Schritt (nach "Weiter") angezeigt werden.',
320 323
  'Audit Control'               => 'Bücherkontrolle',
321 324
  'Aug'                         => 'Aug',
322 325
  'August'                      => 'August',
......
453 456
  'CANCELED'                    => 'Storniert',
454 457
  'CB Transaction'              => 'SB-Buchung',
455 458
  'CB Transactions'             => 'SB-Buchungen',
459
  'CB/OB Transactions'          => 'SB/EB buchen',
456 460
  'CR'                          => 'H',
457 461
  'CSS style for pictures'      => 'CSS Style für Bilder',
458 462
  'CSV'                         => 'CSV',
......
1828 1832
  'No requirement spec templates have been created yet.' => 'Es wurden noch keine Pflichtenheftvorlagen angelegt.',
1829 1833
  'No requirement spec type has been created yet.' => 'Es wurden noch keine Pflichtenhefttypen angelegt.',
1830 1834
  'No results.'                 => 'Keine Artikel',
1835
  'No revert available.'        => 'Dieser Vorgang kann nicht rückgängig gemacht werden, ggf. falsch erstellte Buchungen müssen einzeln manuell korrigiert werden.',
1831 1836
  'No risks level has been created yet.' => 'Es wurden noch keine Risikograde angelegt.',
1832 1837
  'No sections created yet'     => 'Keine Abschnitte erstellt',
1833 1838
  'No sections have been created so far.' => 'Bisher wurden noch keine Abschnitte angelegt.',
......
1888 1893
  'Number pages'                => 'Seiten nummerieren',
1889 1894
  'Number variables: \'PRECISION=n\' forces numbers to be shown with exactly n decimal places.' => 'Zahlenvariablen: Mit \'PRECISION=n\' erzwingt man, dass Zahlen mit n Nachkommastellen formatiert werden.',
1890 1895
  'OB Transaction'              => 'EB-Buchung',
1896
  'OB Transactions'             => 'EB-Buchungen',
1891 1897
  'Objects have been imported.' => 'Objekte wurden importiert.',
1892 1898
  'Obsolete'                    => 'Ungültig',
1893 1899
  'Oct'                         => 'Okt',
......
1899 1905
  'On'                          => 'An',
1900 1906
  'On Hand'                     => 'Auf Lager',
1901 1907
  'On Order'                    => 'Ist bestellt',
1908
  'One OB-transaction'          => 'Eine EB-Buchung',
1909
  'One SB-transaction'          => 'Eine SB-Buchung',
1902 1910
  'One of the columns "qty" or "target_qty" must be given. If "target_qty" is given, the quantity to transfer for each transfer will be calculate, so that the quantity for this part, warehouse and bin will result in the given "target_qty" after each transfer.' => 'Eine der Spalten "qty" oder "target_qty" muss angegeben werden. Wird "target_qty" angegeben, so wird die zu bewegende Menge für jede Lagerbewegung so berechnet, dass die Lagermenge für diesen Artikel, Lager und Lagerplatz nach jeder Lagerbewegung der angegebenen Zielmenge entspricht.',
1903 1911
  'One or more Perl modules missing' => 'Ein oder mehr Perl-Module fehlen',
1904 1912
  'Onhand only sets the quantity in master data, not in inventory. This is only a legacy info field and will be overwritten as soon as a inventory transfer happens.' => 'Das Import-Feld Auf Lager setzt nur die Menge in den Stammdaten, nicht im Lagerbereich. Dies ist historisch gewachsen nur ein Informationsfeld was mit dem tatsächlichen Wert überschrieben wird, sobald eine wirkliche Lagerbewegung stattfindet (DB-Trigger).',
......
2371 2379
  'SEPA message ID'             => 'SEPA-Nachrichten-ID',
2372 2380
  'SEPA message IDs'            => 'SEPA-Nachrichten-IDs',
2373 2381
  'SEPA strings'                => 'SEPA-Überweisungen',
2382
  'Saldo'                       => 'Saldo',
2374 2383
  'Saldo Credit'                => 'Saldo Haben',
2375 2384
  'Saldo Debit'                 => 'Saldo Soll',
2376 2385
  'Saldo neu'                   => 'Saldo neu',
......
2463 2472
  'Select a period'             => 'Bitte Zeitraum auswählen',
2464 2473
  'Select a vendor'             => 'Einen Lieferanten ausw&auml;hlen',
2465 2474
  'Select all'                  => 'Alle auswählen',
2475
  'Select charts for which the CB/OB transactions want to be posted.' => 'Wählen Sie Konten aus, zu welchen SB/EB-Buchungen erstellt werden sollen.',
2466 2476
  'Select federal state...'     => 'Bundesland auswählen...',
2467 2477
  'Select file to upload'       => 'Datei zum Hochladen auswählen',
2468 2478
  'Select from one of the items below' => 'Wählen Sie einen der untenstehenden Einträge',
......
2649 2659
  'Subtotals per quarter'       => 'Zwischensummen pro Quartal',
2650 2660
  'Such entries cannot be exported into the DATEV format and have to be fixed as well.' => 'Solche Einträge sind aber nicht DATEV-exportiertbar und müssen ebenfalls korrigiert werden.',
2651 2661
  'Suggested invoice'           => 'Rechnungsvorschlag',
2662
  'Sum CB Transactions'         => 'Summe SB',
2652 2663
  'Sum Credit'                  => 'Summe Haben',
2653 2664
  'Sum Debit'                   => 'Summe Soll',
2665
  'Sum OB Transactions'         => 'Summe EB',
2654 2666
  'Sum for'                     => 'Summe für',
2655 2667
  'Sum for #1'                  => 'Summe für #1',
2656 2668
  'Sum for section'             => 'Summe für Abschnitt',
......
3079 3091
  'There was an error saving the draft' => 'Beim Speichern des Entwurfs ist ein Fehler aufgetretetn',
3080 3092
  'There was an error saving the letter' => 'Ein Fehler ist aufgetreten. Der Brief konnte nicht gespeichert werden.',
3081 3093
  'There was an error saving the letter draft' => 'Ein Fehler ist aufgetreten. Der Briefentwurf konnte nicht gespeichert werden.',
3094
  'There will be two transactions done:' => 'Zu jedem ausgewählten Konto werden jeweils zwei Buchungen erstellt:',
3082 3095
  'There you can let kivitendo create the basic tables for you, even in an already existing database.' => 'Dort können Sie kivitendo diese grundlegenden Tabellen erstellen lassen, selbst in einer bereits existierenden Datenbank.',
3083 3096
  'Therefore several settings that had to be made for each user in the past have been consolidated into the client configuration.' => 'Dazu wurden gewisse Einstellungen, die vorher bei jedem Benutzer vorgenommen werden mussten, in die Konfiguration eines Mandanten verschoben.',
3084 3097
  'Therefore the definition of "kg" with the base unit "g" and a factor of 1000 is valid while defining "g" with a base unit of "kg" and a factor of "0.001" is not.' => 'So ist die Definition von "kg" mit der Basiseinheit "g" und dem Faktor 1000 zulässig, die Definition von "g" mit der Basiseinheit "kg" und dem Faktor "0,001" hingegen nicht.',
......
3140 3153
  'Time estimate'               => 'Zeitschätzung',
3141 3154
  'Time period for the analysis:' => 'Analysezeitraum:',
3142 3155
  'Time/cost estimate actions'  => 'Aktionen für Kosten-/Zeitabschätzung',
3156
  'Timerange'                   => 'Zeitraum',
3143 3157
  'Timestamp'                   => 'Uhrzeit',
3144 3158
  'Title'                       => 'Titel',
3145 3159
  'To'                          => 'An',
......
3473 3487
  'cleared'                     => 'Abgeglichen',
3474 3488
  'click here to edit cvars'    => 'Klicken Sie hier, um nach benutzerdefinierten Variablen zu suchen',
3475 3489
  'close'                       => 'schließen',
3490
  'close chart'                 => 'Saldovortragskonto',
3476 3491
  'closed'                      => 'geschlossen',
3477 3492
  'companylogo_subtitle'        => 'Lizenziert f&uuml;r',
3478 3493
  'config/kivitendo.conf: Key "DB_config" is missing.' => 'config/kivitendo.conf: Das Schl&uuml;sselwort "DB_config" fehlt.',
......
3519 3534
  'found'                       => 'Gefunden',
3520 3535
  'from (time)'                 => 'von',
3521 3536
  'general_ledger_list'         => 'buchungsjournal',
3537
  'generate cb/ob transactions for selected charts' => 'Buchungen erstellen',
3522 3538
  'h'                           => 'h',
3523 3539
  'history'                     => 'Historie',
3524 3540
  'history search engine'       => 'Historien Suchmaschine',
menus/user/11-yearly-transactions.yaml
1
# This is the main menu config file for user space menu entries.
2
#
3
# opendynamic features
4
#
5
---
6
#
7
# SB/EB-Buchungen
8
#
9
- parent: general_ledger
10
  id: general_ledger_cbob_transactions
11
  name: CB/OB Transactions
12
  icon: cbob
13
  order: 470
14
  access: general_ledger
15
  params:
16
    action: YearlyTransactions/filter
t/bank/cb_ob_transactions.t
1
use Test::More;
2

  
3
use strict;
4

  
5
use lib 't';
6
use utf8;
7

  
8
use Carp;
9
use Support::TestSetup;
10
use Test::Exception;
11
use List::Util qw(sum);
12

  
13
use SL::DB::Buchungsgruppe;
14
use SL::DB::Currency;
15
use SL::DB::Exchangerate;
16
use SL::DB::Customer;
17
use SL::DB::Vendor;
18
use SL::DB::Employee;
19
use SL::DB::Invoice;
20
use SL::DB::Part;
21
use SL::DB::Unit;
22
use SL::DB::TaxZone;
23
use SL::DB::BankAccount;
24
use SL::DB::PaymentTerm;
25
use SL::DB::PurchaseInvoice;
26
use SL::DB::BankTransaction;
27
use SL::DB::AccTransaction;
28
use SL::Controller::YearlyTransactions;
29
use Data::Dumper;
30

  
31
my ($customer, $vendor, $currency_id, @parts, $unit, $employee, $tax, $tax7, $tax_9, $taxzone, $payment_terms, $bank_account);
32
my ($transdate1, $transdate2, $currency);
33
my ($ar_chart,$bank,$ar_amount_chart, $ap_chart, $ap_amount_chart, $saldo_chart);
34
my ($ar_transaction, $ap_transaction);
35

  
36
sub clear_up {
37

  
38
  SL::DB::Manager::BankTransaction->delete_all(all => 1);
39
  SL::DB::Manager::InvoiceItem->delete_all(all => 1);
40
  SL::DB::Manager::InvoiceItem->delete_all(all => 1);
41
  SL::DB::Manager::Invoice->delete_all(all => 1);
42
  SL::DB::Manager::PurchaseInvoice->delete_all(all => 1);
43
  SL::DB::Manager::Part->delete_all(all => 1);
44
  SL::DB::Manager::Customer->delete_all(all => 1);
45
  SL::DB::Manager::Vendor->delete_all(all => 1);
46
  SL::DB::Manager::BankAccount->delete_all(all => 1);
47
  SL::DB::Manager::AccTransaction->delete_all(all => 1);
48
  SL::DB::Manager::PaymentTerm->delete_all(all => 1);
49
  SL::DB::Manager::Currency->delete_all(where => [ name => 'CUR' ]);
50
};
51

  
52

  
53
# starting test:
54
Support::TestSetup::login();
55

  
56
reset_state(); # initialise customers/vendors/bank/currency/...
57

  
58
test1();
59

  
60
# remove all created data at end of test
61
clear_up();
62

  
63
done_testing();
64

  
65
###### functions for setting up data
66

  
67
sub reset_state {
68
  my %params = @_;
69

  
70
  $params{$_} ||= {} for qw(unit customer part tax vendor);
71

  
72
  clear_up();
73

  
74
  $transdate1 = DateTime->today;
75
  $transdate2 = DateTime->today->add(days => 5);
76

  
77
  $employee        = SL::DB::Manager::Employee->current                                          || croak "No employee";
78
  $tax             = SL::DB::Manager::Tax->find_by(taxkey => 3, rate => 0.19, %{ $params{tax} }) || croak "No tax";
79
  $tax7            = SL::DB::Manager::Tax->find_by(taxkey => 2, rate => 0.07)                    || croak "No tax for 7\%";
80
  $taxzone         = SL::DB::Manager::TaxZone->find_by( description => 'Inland')                 || croak "No taxzone";
81
  $tax_9           = SL::DB::Manager::Tax->find_by(taxkey => 9, rate => 0.19, %{ $params{tax} }) || croak "No tax";
82

  
83
  $currency_id     = $::instance_conf->get_currency_id;
84

  
85
  $bank_account     =  SL::DB::BankAccount->new(
86
    account_number  => '123',
87
    bank_code       => '123',
88
    iban            => '123',
89
    bic             => '123',
90
    bank            => '123',
91
    chart_id        => SL::DB::Manager::Chart->find_by(description => 'Bank')->id,
92
    name            => SL::DB::Manager::Chart->find_by(description => 'Bank')->description,
93
  )->save;
94

  
95
  $customer     = SL::DB::Customer->new(
96
    name                      => 'Test Customer',
97
    currency_id               => $currency_id,
98
    taxzone_id                => $taxzone->id,
99
    iban                      => 'DE12500105170648489890',
100
    bic                       => 'TESTBIC',
101
    account_number            => '648489890',
102
    mandate_date_of_signature => $transdate1,
103
    mandator_id               => 'foobar',
104
    bank                      => 'Geizkasse',
105
    depositor                 => 'Test Customer',
106
    %{ $params{customer} }
107
  )->save;
108

  
109
  $payment_terms     =  SL::DB::PaymentTerm->new(
110
    description      => 'payment',
111
    description_long => 'payment',
112
    terms_netto      => '30',
113
    terms_skonto     => '5',
114
    percent_skonto   => '0.05',
115
    auto_calculation => 1,
116
  )->save;
117

  
118
  $vendor       = SL::DB::Vendor->new(
119
    name        => 'Test Vendor',
120
    currency_id => $currency_id,
121
    taxzone_id  => $taxzone->id,
122
    payment_id  => $payment_terms->id,
123
    iban                      => 'DE12500105170648489890',
124
    bic                       => 'TESTBIC',
125
    account_number            => '648489890',
126
    bank                      => 'Geizkasse',
127
    depositor                 => 'Test Vendor',
128
    %{ $params{vendor} }
129
  )->save;
130

  
131
  $ar_chart        = SL::DB::Manager::Chart->find_by( accno => '1400' ); # Forderungen
132
  $ap_chart        = SL::DB::Manager::Chart->find_by( accno => '1600' ); # Verbindlichkeiten
133
  $bank            = SL::DB::Manager::Chart->find_by( accno => '1200' ); # Bank
134
  $ar_amount_chart = SL::DB::Manager::Chart->find_by( accno => '8400' ); # Erlöse
135
  $ap_amount_chart = SL::DB::Manager::Chart->find_by( accno => '3400' ); # Wareneingang 19%
136
  $saldo_chart     = SL::DB::Manager::Chart->find_by( accno => '9000' ); # Saldenvorträge
137

  
138
}
139

  
140
sub test_ar_transaction {
141
  my (%params) = @_;
142
  my $netamount = 100;
143
  my $amount    = $params{amount} || $::form->round_amount(100 * 1.19,2);
144
  my $invoice   = SL::DB::Invoice->new(
145
      invoice      => 0,
146
      invnumber    => $params{invnumber} || undef, # let it use its own invnumber
147
      amount       => $amount,
148
      netamount    => $netamount,
149
      transdate    => $transdate1,
150
      taxincluded  => 0,
151
      customer_id  => $customer->id,
152
      taxzone_id   => $customer->taxzone_id,
153
      currency_id  => $currency_id,
154
      transactions => [],
155
      payment_id   => $params{payment_id} || undef,
156
      notes        => 'test_ar_transaction',
157
  );
158
  $invoice->add_ar_amount_row(
159
    amount => $invoice->netamount,
160
    chart  => $ar_amount_chart,
161
    tax_id => $tax->id,
162
  );
163

  
164
  $invoice->create_ar_row(chart => $ar_chart);
165
  $invoice->save;
166

  
167
  is($invoice->currency_id , $currency_id , 'currency_id has been saved');
168
  is($invoice->netamount   , 100          , 'ar amount has been converted');
169
  is($invoice->amount      , 119          , 'ar amount has been converted');
170
  is($invoice->taxincluded , 0            , 'ar transaction doesn\'t have taxincluded');
171

  
172
  is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_amount_chart->id , trans_id => $invoice->id)->amount , '100.00000'  , $ar_amount_chart->accno . ': has been converted for currency');
173
  is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ar_chart->id        , trans_id => $invoice->id)->amount , '-119.00000' , $ar_chart->accno . ': has been converted for currency');
174

  
175
  return $invoice;
176
};
177

  
178
sub test_ap_transaction {
179
  my (%params) = @_;
180
  my $netamount = 100;
181
  my $amount    = $::form->round_amount($netamount * 1.19,2);
182
  my $invoice   = SL::DB::PurchaseInvoice->new(
183
      invoice      => 0,
184
      invnumber    => $params{invnumber} || 'test_ap_transaction',
185
      amount       => $amount,
186
      netamount    => $netamount,
187
      transdate    => $transdate1,
188
      taxincluded  => 0,
189
      vendor_id    => $vendor->id,
190
      taxzone_id   => $vendor->taxzone_id,
191
      currency_id  => $currency_id,
192
      transactions => [],
193
      notes        => 'test_ap_transaction',
194
  );
195
  $invoice->add_ap_amount_row(
196
    amount     => $invoice->netamount,
197
    chart      => $ap_amount_chart,
198
    tax_id     => $tax_9->id,
199
  );
200

  
201
  $invoice->create_ap_row(chart => $ap_chart);
202
  $invoice->save;
203

  
204
  is($invoice->currency_id , $currency_id , 'currency_id has been saved');
205
  is($invoice->netamount   , 100          , 'ap amount has been converted');
206
  is($invoice->amount      , 119          , 'ap amount has been converted');
207
  is($invoice->taxincluded , 0            , 'ap transaction doesn\'t have taxincluded');
208

  
209
  is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_amount_chart->id , trans_id => $invoice->id)->amount , '-100.00000' , $ap_amount_chart->accno . ': has been converted for currency');
210
  is(SL::DB::Manager::AccTransaction->find_by(chart_id => $ap_chart->id        , trans_id => $invoice->id)->amount , '119.00000'  , $ap_chart->accno . ': has been converted for currency');
211

  
212
  return $invoice;
213
};
214

  
215
###### test cases
216

  
217
sub test1 {
218

  
219
  my $testname = 'test1';
220

  
221
  $ar_transaction = test_ar_transaction(invnumber => 'salesinv1');
222
  $ap_transaction = test_ap_transaction(invnumber => 'purchaseinv1');
223
  my $ar_transaction_2 = test_ar_transaction(invnumber => 'salesinv_2');
224

  
225
  my $yt_controller = SL::Controller::YearlyTransactions->new;
226
  my $report     = SL::ReportGenerator->new(\%::myconfig, $::form);
227

  
228
  $::form->{"ob_date"} = DateTime->today->truncate(to => 'year')->add(years => 1)->to_kivitendo;
229
  $::form->{"cb_date"} = DateTime->today->truncate(to => 'year')->add(years => 1)->add(days => -1)->to_kivitendo;
230
  #print "ob_date=".$::form->{"ob_date"}." cb_date=".$::form->{"cb_date"}."\n";
231
  $::form->{"cb_reference"} = 'SB-Buchung';
232
  $::form->{"ob_reference"} = 'EB-Buchung';
233
  $::form->{"cb_description"} = 'SB-Buchung Beschreibung';
234
  $::form->{"ob_description"} = 'EB-Buchung Beschreibung';
235
  $::form->{"cbob_chart"} = $saldo_chart->id;
236

  
237
  $yt_controller->prepare_report($report);
238

  
239
  ## check balance of charts
240

  
241
  my $idx = 1;
242
  foreach my $chart (@{ $yt_controller->charts }) {
243
    my $balance = $yt_controller->get_balance($chart);
244
    if ( $balance != 0 ) {
245
      #print "chart_id=".$chart->id."balance=".$balance."\n";
246
      is($balance , '-238.00000' , $chart->accno.' has right balance') if $chart->accno eq '1400';
247
      is($balance ,  '-19.00000' , $chart->accno.' has right balance') if $chart->accno eq '1576';
248
      is($balance ,  '119.00000' , $chart->accno.' has right balance') if $chart->accno eq '1600';
249
      is($balance ,   '38.00000' , $chart->accno.' has right balance') if $chart->accno eq '1776';
250
      is($balance , '-100.00000' , $chart->accno.' has right balance') if $chart->accno eq '3400';
251
      is($balance ,  '200.00000' , $chart->accno.' has right balance') if $chart->accno eq '8400';
252
      $::form->{"trans_id_${idx}"} = $chart->id;
253
      $::form->{"multi_id_${idx}"} = 1;
254
      $idx++ ;
255
    }
256
  }
257
  $::form->{"rowcount"} = $idx-1;
258
  #print "rowcount=". $::form->{"rowcount"}."\n";
259
  $::form->{"login"}="unittests";
260

  
261
  $yt_controller->make_booking;
262

  
263
  ## no check cb ob booking :
264

  
265
  my $sum_cb_p = 0;
266
  my $sum_cb_m = 0;
267
  foreach my $acc ( @{ SL::DB::Manager::AccTransaction->get_all(where => [ chart_id => $saldo_chart->id, cb_transaction => 't' ]) }) {
268
    #print "cb amount=".$acc->amount."\n";
269
    $sum_cb_p +=  $acc->amount if $acc->amount > 0;
270
    $sum_cb_m += -$acc->amount if $acc->amount < 0;
271
  }
272
  #print "chart_id=".$saldo_chart->id." sum_cb_p=".$sum_cb_p." sum_cb_m=".$sum_cb_m."\n";
273
  is($sum_cb_p ,  '357' , 'chart '.$saldo_chart->accno.' has right positive close saldo');
274
  is($sum_cb_m ,  '357' , 'chart '.$saldo_chart->accno.' has right negative close saldo');
275
  my $sum_ob_p = 0;
276
  my $sum_ob_m = 0;
277
  foreach my $acc ( @{ SL::DB::Manager::AccTransaction->get_all(where => [ chart_id => $saldo_chart->id, ob_transaction => 't' ]) }) {
278
    #print "ob amount=".$acc->amount."\n";
279
    $sum_ob_p +=  $acc->amount if $acc->amount > 0;
280
    $sum_ob_m += -$acc->amount if $acc->amount < 0;
281
  }
282
  #print "chart_id=".$saldo_chart->id." sum_ob_p=".$sum_ob_p." sum_ob_m=".$sum_ob_m."\n";
283
  is($sum_ob_p ,  '357' , 'chart '.$saldo_chart->accno.' has right positive open saldo');
284
  is($sum_ob_m ,  '357' , 'chart '.$saldo_chart->accno.' has right negative open saldo');
285
}
286

  
287

  
288

  
289
1;
templates/webpages/gl/yearly_bottom.html
1
[%- USE L %]
2
[%- USE LxERP %]
3
<table  width="100%">
4
  <tr><td>
5
    [%- L.hidden_tag("action","YearlyTransactions/dispatch") %]
6
    [%- L.hidden_tag("cb_date",SELF.cb_date) %]
7
    [%- L.hidden_tag("cb_startdate",SELF.cb_startdate) %]
8
    [%- L.hidden_tag("cb_reference",SELF.cb_reference) %]
9
    [%- L.hidden_tag("cb_description",SELF.cb_description) %]
10
    [%- L.hidden_tag("ob_date",SELF.ob_date) %]
11
    [%- L.hidden_tag("ob_reference",SELF.ob_reference) %]
12
    [%- L.hidden_tag("ob_description",SELF.ob_description) %]
13
    [%- L.hidden_tag("cbob_chart",SELF.cbob_chart) %]
14
    [%- L.hidden_tag("rowcount",SELF.row_count) %]
15
    [%- L.submit_tag("action_generate", LxERP.t8('generate cb/ob transactions for selected charts'),
16
                    confirm=LxERP.t8('Are you sure to generate cb/ob transactions?')) %]
17
    [%- L.submit_tag("action_filter", LxERP.t8('back')) %]
18
    </td>
19
  </tr>
20
</table></form>
21
<script type='text/javascript'>
22
$(function(){
23
  $('#multi_all').checkall("input[name^='multi_id']");
24
});
25
</script>  
templates/webpages/gl/yearly_filter.html
1
[%- USE HTML %]
2
[%- USE T8 %]
3
[%- USE L %]
4
[%- USE LxERP %]
5

  
6
<h1>[% title | html %]</h1>
7

  
8
[%- PROCESS 'common/flash.html' %]
9

  
10
<form id='filter_form'>
11

  
12
<table>
13
  <tr>
14
    <td width="20px"></td>
15
    <td align="left" colspan="5">[% 'Attention: Here will be generated a lot of CB/OB transactions.' | $T8 %]</td>
16
  </tr>
17
  <tr>
18
    <td><p></p></td>
19
  </tr>
20
  <tr>
21
    <th></th>
22
    <th width="400px" colspan="2" align="center">[% 'CB Transactions' | $T8 %]</th>
23
    <th width="400px"colspan="2" align="center">[% 'OB Transactions' | $T8 %]</th>
24
    <th>&nbsp;</th>
25
  </tr>
26
  <tr>
27
    <td></td>
28
    <td align="right">[% 'Date' | $T8 %]</td>
29
    <td>[% L.date_tag('cb_date', SELF.cb_date) %]</td>
30
    <td align="right">[% 'Date' | $T8 %]</td>
31
    <td>[% L.date_tag('ob_date', SELF.ob_date) %]</td>
32
    <td></td>
33
  </tr>
34
  <tr>
35
    <td></td>
36
    <td align="right">[% 'Reference' | $T8 %]</td>
37
    <td>[% L.input_tag('cb_reference', SELF.cb_reference) %]</td>
38
    <td align="right">[% 'Reference' | $T8 %]</td>
39
    <td>[% L.input_tag('ob_reference', SELF.ob_reference) %]</td>
40
    <td></td>
41
  </tr>
42
  <tr>
43
    <td></td>
44
    <td align="right">[% 'Description' | $T8 %]</td>
45
    <td>[% L.input_tag('cb_description', SELF.cb_description) %]</td>
46
    <td align="right">[% 'Description' | $T8 %]</td>
47
    <td>[% L.input_tag('ob_description', SELF.ob_description) %]</td>
48
    <td></td>
49
  </tr>
50
  <tr>
51
    <td><p></p></td>
52
  </tr>
53
  <tr>
54
    <th colspan="2"></th>
55
    <th align=right>[% 'close chart' | $T8 %]</th>
56
    <td colspan="3">[% L.select_tag('cbob_chart', SELF.charts9000, title_sub=\make_title_of_chart, default=SELF.cbob_chart, style="width: 400px") %]</td>
57
  </tr>
58
</table>
59

  
60
[% L.hidden_tag('action', 'YearlyTransactions/dispatch') %]
61
<hr size=3 noshade><br>
62
[% L.submit_tag('action_list', LxERP.t8('Continue')) %]
63

  
64
</form>
templates/webpages/gl/yearly_top.html
1
[%- USE LxERP %]
2
[%- INCLUDE 'common/flash.html' %]
3
<form method="post" action="controller.pl">
4
<table>
5
  <tr>
6
    <td width="20px"></td>
7
    <td colspan="6" align="left">
8
      [%- LxERP.t8('Select charts for which the CB/OB transactions want to be posted.') %]<br>
9
      [%- LxERP.t8('There will be two transactions done:') %]<br>
10
     - [%- LxERP.t8('One SB-transaction') %] ( [% SELF.cb_date %], [% SELF.cb_reference %], [% SELF.cb_description %], [% SELF.cbob_chartaccno %] )<br>
11
     - [%- LxERP.t8('One OB-transaction') %] ( [% SELF.ob_date %], [% SELF.ob_reference %], [% SELF.ob_description %], [% SELF.cbob_chartaccno %] )<br>
12
      [%- LxERP.t8('No revert available.') %]
13
    </td>
14
  </tr>
15
  <tr>
16
    <td><p></p></td>
17
  </tr>
18
  <tr>
19
    <th></th>
20
    <th align="right">[% LxERP.t8('close chart') %]</th>
21
    <td>[% SELF.cbob_chartaccno %]</td>
22
  </tr>
23
</table>

Auch abrufbar als: Unified diff