1 #=====================================================================
4 # Based on SQL-Ledger Version 2.1.9
5 # Web http://www.lx-office.org
7 #=====================================================================
8 # SQL-Ledger Accounting
11 # Author: Dieter Simader
12 # Email: dsimader@sql-ledger.org
13 # Web: http://www.sql-ledger.org
17 # This program is free software; you can redistribute it and/or modify
18 # it under the terms of the GNU General Public License as published by
19 # the Free Software Foundation; either version 2 of the License, or
20 # (at your option) any later version.
22 # This program is distributed in the hope that it will be useful,
23 # but WITHOUT ANY WARRANTY; without even the implied warranty of
24 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 # GNU General Public License for more details.
26 # You should have received a copy of the GNU General Public License
27 # along with this program; if not, write to the Free Software
28 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
30 #======================================================================
32 # General ledger backend code
35 # DS. 2000-07-04 Created
36 # DS. 2001-06-12 Changed relations from accno to chart_id
38 #======================================================================
42 use List::Util qw(first);
45 use SL::DATEV qw(:CONSTANTS);
49 use SL::Util qw(trim);
54 sub delete_transaction {
55 my ($self, $myconfig, $form) = @_;
56 $main::lxdebug->enter_sub();
58 SL::DB->client->with_transaction(sub {
59 do_query($form, SL::DB->client->dbh, qq|DELETE FROM gl WHERE id = ?|, conv_i($form->{id}));
61 }) or do { die SL::DB->client->error };
63 $main::lxdebug->leave_sub();
66 sub post_transaction {
67 my ($self, $myconfig, $form) = @_;
68 $main::lxdebug->enter_sub();
70 my $rc = SL::DB->client->with_transaction(\&_post_transaction, $self, $myconfig, $form);
72 $::lxdebug->leave_sub;
76 sub _post_transaction {
77 my ($self, $myconfig, $form) = @_;
78 $main::lxdebug->enter_sub();
80 my ($debit, $credit) = (0, 0);
85 my $dbh = SL::DB->client->dbh;
87 # post the transaction
88 # make up a unique handle and store in reference field
89 # then retrieve the record based on the unique handle to get the id
90 # replace the reference field with the actual variable
91 # add records to acc_trans
93 # if there is a $form->{id} replace the old transaction
94 # delete all acc_trans entries and add the new ones
96 if (!$form->{taxincluded}) {
97 $form->{taxincluded} = 0;
100 my ($query, $sth, @values, $taxkey, $rate, $posted);
104 # delete individual transactions
105 $query = qq|DELETE FROM acc_trans WHERE trans_id = ?|;
106 @values = (conv_i($form->{id}));
107 do_query($form, $dbh, $query, @values);
110 $query = qq|SELECT nextval('glid')|;
111 ($form->{id}) = selectrow_query($form, $dbh, $query);
114 qq|INSERT INTO gl (id, employee_id) | .
115 qq|VALUES (?, (SELECT id FROM employee WHERE login = ?))|;
116 @values = ($form->{id}, $::myconfig{login});
117 do_query($form, $dbh, $query, @values);
120 $form->{ob_transaction} *= 1;
121 $form->{cb_transaction} *= 1;
125 reference = ?, description = ?, notes = ?,
126 transdate = ?, deliverydate = ?, department_id = ?, taxincluded = ?,
127 storno = ?, storno_id = ?, ob_transaction = ?, cb_transaction = ?
130 @values = ($form->{reference}, $form->{description}, $form->{notes},
131 conv_date($form->{transdate}), conv_date($form->{deliverydate}), conv_i($form->{department_id}), $form->{taxincluded} ? 't' : 'f',
132 $form->{storno} ? 't' : 'f', conv_i($form->{storno_id}), $form->{ob_transaction} ? 't' : 'f', $form->{cb_transaction} ? 't' : 'f',
133 conv_i($form->{id}));
134 do_query($form, $dbh, $query, @values);
136 # insert acc_trans transactions
137 for $i (1 .. $form->{rowcount}) {
138 ($form->{"tax_id_$i"}) = split(/--/, $form->{"taxchart_$i"});
139 if ($form->{"tax_id_$i"} ne "") {
140 $query = qq|SELECT taxkey, rate FROM tax WHERE id = ?|;
141 ($taxkey, $rate) = selectrow_query($form, $dbh, $query, conv_i($form->{"tax_id_$i"}));
145 my $debit = $form->{"debit_$i"};
146 my $credit = $form->{"credit_$i"};
147 my $tax = $form->{"tax_$i"};
154 $amount = $debit * -1;
159 $project_id = conv_i($form->{"project_id_$i"});
161 # if there is an amount, add the record
164 qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
165 source, memo, project_id, taxkey, ob_transaction, cb_transaction, tax_id, chart_link)
166 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, (SELECT link FROM chart WHERE id = ?))|;
167 @values = (conv_i($form->{id}), $form->{"accno_id_$i"}, $amount, conv_date($form->{transdate}),
168 $form->{"source_$i"}, $form->{"memo_$i"}, $project_id, $taxkey, $form->{ob_transaction} ? 't' : 'f', $form->{cb_transaction} ? 't' : 'f', conv_i($form->{"tax_id_$i"}), $form->{"accno_id_$i"});
169 do_query($form, $dbh, $query, @values);
175 qq|INSERT INTO acc_trans (trans_id, chart_id, amount, transdate,
176 source, memo, project_id, taxkey, tax_id, chart_link)
177 VALUES (?, (SELECT chart_id FROM tax WHERE id = ?),
178 ?, ?, ?, ?, ?, ?, ?, (SELECT link
180 WHERE id = (SELECT chart_id
183 @values = (conv_i($form->{id}), conv_i($form->{"tax_id_$i"}),
184 $tax, conv_date($form->{transdate}), $form->{"source_$i"},
185 $form->{"memo_$i"}, $project_id, $taxkey, conv_i($form->{"tax_id_$i"}), conv_i($form->{"tax_id_$i"}));
186 do_query($form, $dbh, $query, @values);
190 if ($form->{storno} && $form->{storno_id}) {
191 do_query($form, $dbh, qq|UPDATE gl SET storno = 't' WHERE id = ?|, conv_i($form->{storno_id}));
194 if ($form->{draft_id}) {
195 SL::DB::Manager::Draft->delete_all(where => [ id => delete($form->{draft_id}) ]);
198 # safety check datev export
199 if ($::instance_conf->get_datev_check_on_gl_transaction) {
201 # create datev object
202 my $datev = SL::DATEV->new(
204 trans_id => $form->{id},
207 $datev->generate_datev_data;
209 if ($datev->errors) {
210 die join "\n", $::locale->text('DATEV check returned errors:'), $datev->errors;
217 sub all_transactions {
218 my ($self, $myconfig, $form) = @_;
219 $main::lxdebug->enter_sub();
221 my $dbh = SL::DB->client->dbh;
222 my ($query, $sth, $source, $null, $space);
224 my ($glwhere, $arwhere, $apwhere) = ("1 = 1", "1 = 1", "1 = 1");
225 my (@glvalues, @arvalues, @apvalues);
227 if ($form->{reference}) {
228 $glwhere .= qq| AND g.reference ILIKE ?|;
229 $arwhere .= qq| AND a.invnumber ILIKE ?|;
230 $apwhere .= qq| AND a.invnumber ILIKE ?|;
231 push(@glvalues, like($form->{reference}));
232 push(@arvalues, like($form->{reference}));
233 push(@apvalues, like($form->{reference}));
236 if ($form->{department_id}) {
237 $glwhere .= qq| AND g.department_id = ?|;
238 $arwhere .= qq| AND a.department_id = ?|;
239 $apwhere .= qq| AND a.department_id = ?|;
240 push(@glvalues, $form->{department_id});
241 push(@arvalues, $form->{department_id});
242 push(@apvalues, $form->{department_id});
245 if ($form->{source}) {
246 $glwhere .= " AND ac.trans_id IN (SELECT trans_id from acc_trans WHERE source ILIKE ?)";
247 $arwhere .= " AND ac.trans_id IN (SELECT trans_id from acc_trans WHERE source ILIKE ?)";
248 $apwhere .= " AND ac.trans_id IN (SELECT trans_id from acc_trans WHERE source ILIKE ?)";
249 push(@glvalues, like($form->{source}));
250 push(@arvalues, like($form->{source}));
251 push(@apvalues, like($form->{source}));
254 # default Datumseinschränkung falls nicht oder falsch übergeben (sollte nie passieren)
255 $form->{datesort} = 'transdate' unless $form->{datesort} =~ /^(transdate|gldate)$/;
257 if (trim($form->{datefrom})) {
258 $glwhere .= " AND ac.$form->{datesort} >= ?";
259 $arwhere .= " AND ac.$form->{datesort} >= ?";
260 $apwhere .= " AND ac.$form->{datesort} >= ?";
261 push(@glvalues, trim($form->{datefrom}));
262 push(@arvalues, trim($form->{datefrom}));
263 push(@apvalues, trim($form->{datefrom}));
266 if (trim($form->{dateto})) {
267 $glwhere .= " AND ac.$form->{datesort} <= ?";
268 $arwhere .= " AND ac.$form->{datesort} <= ?";
269 $apwhere .= " AND ac.$form->{datesort} <= ?";
270 push(@glvalues, trim($form->{dateto}));
271 push(@arvalues, trim($form->{dateto}));
272 push(@apvalues, trim($form->{dateto}));
275 if (trim($form->{description})) {
276 $glwhere .= " AND g.description ILIKE ?";
277 $arwhere .= " AND ct.name ILIKE ?";
278 $apwhere .= " AND ct.name ILIKE ?";
279 push(@glvalues, like($form->{description}));
280 push(@arvalues, like($form->{description}));
281 push(@apvalues, like($form->{description}));
284 if ($form->{employee_id}) {
285 $glwhere .= " AND g.employee_id = ? ";
286 $arwhere .= " AND a.employee_id = ? ";
287 $apwhere .= " AND a.employee_id = ? ";
288 push(@glvalues, conv_i($form->{employee_id}));
289 push(@arvalues, conv_i($form->{employee_id}));
290 push(@apvalues, conv_i($form->{employee_id}));
293 if (trim($form->{notes})) {
294 $glwhere .= " AND g.notes ILIKE ?";
295 $arwhere .= " AND a.notes ILIKE ?";
296 $apwhere .= " AND a.notes ILIKE ?";
297 push(@glvalues, like($form->{notes}));
298 push(@arvalues, like($form->{notes}));
299 push(@apvalues, like($form->{notes}));
302 if ($form->{accno}) {
303 $glwhere .= " AND c.accno = '$form->{accno}'";
304 $arwhere .= " AND c.accno = '$form->{accno}'";
305 $apwhere .= " AND c.accno = '$form->{accno}'";
308 if ($form->{category} ne 'X') {
309 $glwhere .= qq| AND g.id in (SELECT trans_id FROM acc_trans ac2 WHERE ac2.chart_id IN (SELECT id FROM chart c2 WHERE c2.category = ?))|;
310 $arwhere .= qq| AND a.id in (SELECT trans_id FROM acc_trans ac2 WHERE ac2.chart_id IN (SELECT id FROM chart c2 WHERE c2.category = ?))|;
311 $apwhere .= qq| AND a.id in (SELECT trans_id FROM acc_trans ac2 WHERE ac2.chart_id IN (SELECT id FROM chart c2 WHERE c2.category = ?))|;
312 push(@glvalues, $form->{category});
313 push(@arvalues, $form->{category});
314 push(@apvalues, $form->{category});
317 if ($form->{project_id}) {
318 $glwhere .= qq| AND g.id IN (SELECT DISTINCT trans_id FROM acc_trans WHERE project_id = ?)|;
320 qq| AND ((a.globalproject_id = ?) OR
321 (a.id IN (SELECT DISTINCT trans_id FROM acc_trans WHERE project_id = ?)))|;
323 qq| AND ((a.globalproject_id = ?) OR
324 (a.id IN (SELECT DISTINCT trans_id FROM acc_trans WHERE project_id = ?)))|;
325 my $project_id = conv_i($form->{project_id});
326 push(@glvalues, $project_id);
327 push(@arvalues, $project_id, $project_id);
328 push(@apvalues, $project_id, $project_id);
331 my ($project_columns, $project_join);
332 if ($form->{"l_projectnumbers"}) {
333 $project_columns = qq|, ac.project_id, pr.projectnumber|;
334 $project_join = qq|LEFT JOIN project pr ON (ac.project_id = pr.id)|;
337 if ($form->{accno}) {
338 # get category for account
339 $query = qq|SELECT category FROM chart WHERE accno = ?|;
340 ($form->{ml}) = selectrow_query($form, $dbh, $query, $form->{accno});
342 if ($form->{datefrom}) {
344 qq|SELECT SUM(ac.amount)
346 LEFT JOIN chart c ON (ac.chart_id = c.id)
347 WHERE (c.accno = ?) AND (ac.$form->{datesort} < ?)|;
348 ($form->{balance}) = selectrow_query($form, $dbh, $query, $form->{accno}, conv_date($form->{datefrom}));
354 'transdate' => [ qw(transdate id) ],
355 'gldate' => [ qw(gldate id) ],
356 'reference' => [ qw(lower_reference id) ],
357 'description' => [ qw(lower_description id) ],
358 'accno' => [ qw(accno transdate id) ],
360 my %lowered_columns = (
361 'reference' => { 'gl' => 'g.reference', 'arap' => 'a.invnumber', },
362 'source' => { 'gl' => 'ac.source', 'arap' => 'ac.source', },
363 'description' => { 'gl' => 'g.description', 'arap' => 'ct.name', },
366 # sortdir = sort direction (ascending or descending)
367 my $sortdir = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
368 my $sortkey = $sort_columns{$form->{sort}} ? $form->{sort} : $form->{datesort}; # default used to be transdate
369 my $sortorder = join ', ', map { "$_ $sortdir" } @{ $sort_columns{$sortkey} };
371 my %columns_for_sorting = ( 'gl' => '', 'arap' => '', );
372 foreach my $spec (@{ $sort_columns{$sortkey} }) {
373 next if ($spec !~ m/^lower_(.*)$/);
376 map { $columns_for_sorting{$_} .= sprintf(', lower(%s) AS lower_%s', $lowered_columns{$column}->{$_}, $column) } qw(gl arap);
381 ac.acc_trans_id, g.id, 'gl' AS type, FALSE AS invoice, g.reference, ac.taxkey, c.link,
382 g.description, ac.transdate, ac.gldate, ac.source, ac.trans_id,
383 ac.amount, c.accno, g.notes, t.chart_id,
384 CASE WHEN (COALESCE(e.name, '') = '') THEN e.login ELSE e.name END AS employee
386 $columns_for_sorting{gl}
388 LEFT JOIN employee e ON (g.employee_id = e.id),
389 acc_trans ac $project_join, chart c
390 LEFT JOIN tax t ON (t.chart_id = c.id)
392 AND (ac.chart_id = c.id)
393 AND (g.id = ac.trans_id)
397 SELECT ac.acc_trans_id, a.id, 'ar' AS type, a.invoice, a.invnumber, ac.taxkey, c.link,
398 ct.name, ac.transdate, ac.gldate, ac.source, ac.trans_id,
399 ac.amount, c.accno, a.notes, t.chart_id,
400 CASE WHEN (COALESCE(e.name, '') = '') THEN e.login ELSE e.name END AS employee
402 $columns_for_sorting{arap}
404 LEFT JOIN employee e ON (a.employee_id = e.id),
405 acc_trans ac $project_join, customer ct, chart c
406 LEFT JOIN tax t ON (t.chart_id=c.id)
408 AND (ac.chart_id = c.id)
409 AND (a.customer_id = ct.id)
410 AND (a.id = ac.trans_id)
414 SELECT ac.acc_trans_id, a.id, 'ap' AS type, a.invoice, a.invnumber, ac.taxkey, c.link,
415 ct.name, ac.transdate, ac.gldate, ac.source, ac.trans_id,
416 ac.amount, c.accno, a.notes, t.chart_id,
417 CASE WHEN (COALESCE(e.name, '') = '') THEN e.login ELSE e.name END AS employee
419 $columns_for_sorting{arap}
421 LEFT JOIN employee e ON (a.employee_id = e.id),
422 acc_trans ac $project_join, vendor ct, chart c
423 LEFT JOIN tax t ON (t.chart_id=c.id)
425 AND (ac.chart_id = c.id)
426 AND (a.vendor_id = ct.id)
427 AND (a.id = ac.trans_id)
429 ORDER BY $sortorder, acc_trans_id $sortdir|;
430 # ORDER BY gldate DESC, id DESC, acc_trans_id DESC
432 my @values = (@glvalues, @arvalues, @apvalues);
434 # Show all $query in Debuglevel LXDebug::QUERY
435 my $callingdetails = (caller (0))[3];
436 dump_query(LXDebug->QUERY(), "$callingdetails", $query, @values);
438 $sth = prepare_execute_query($form, $dbh, $query, @values);
443 my ($i, $j, $k, $l, $ref, $ref2);
446 while (my $ref0 = $sth->fetchrow_hashref("NAME_lc")) {
448 $trans_id = $ref0->{id};
450 my $source = $ref0->{source};
451 undef($ref0->{source});
453 if ($trans_id != $trans_id2) { # first line of a booking
456 push(@{ $form->{GL} }, $ref);
461 $trans_id2 = $ref->{id};
464 if ($ref->{type} eq "gl") {
465 $ref->{module} = "gl";
469 if ($ref->{type} eq "ap") {
470 if ($ref->{invoice}) {
471 $ref->{module} = "ir";
473 $ref->{module} = "ap";
478 if ($ref->{type} eq "ar") {
479 if ($ref->{invoice}) {
480 $ref->{module} = "is";
482 $ref->{module} = "ar";
486 $ref->{"projectnumbers"} = {};
487 $ref->{"projectnumbers"}->{$ref->{"projectnumber"}} = 1 if ($ref->{"projectnumber"});
489 $balance = $ref->{amount};
491 # Linenumbers of General Ledger
492 $k = 0; # Debit # AP # Soll
493 $l = 0; # Credit # AR # Haben
494 $i = 0; # Debit Tax # AP_tax # VSt
495 $j = 0; # Credit Tax # AR_tax # USt
497 if ($ref->{chart_id} > 0) { # all tax accounts first line, no line increasing
498 if ($ref->{amount} < 0) {
499 if ($ref->{link} =~ /AR_tax/) {
500 $ref->{credit_tax}{$j} = $ref->{amount};
501 $ref->{credit_tax_accno}{$j} = $ref->{accno};
503 if ($ref->{link} =~ /AP_tax/) {
504 $ref->{debit_tax}{$i} = $ref->{amount} * -1;
505 $ref->{debit_tax_accno}{$i} = $ref->{accno};
508 if ($ref->{link} =~ /AR_tax/) {
509 $ref->{credit_tax}{$j} = $ref->{amount};
510 $ref->{credit_tax_accno}{$j} = $ref->{accno};
512 if ($ref->{link} =~ /AP_tax/) {
513 $ref->{debit_tax}{$i} = $ref->{amount} * -1;
514 $ref->{debit_tax_accno}{$i} = $ref->{accno};
517 } else { #all other accounts first line
519 if ($ref->{amount} < 0) {
520 $ref->{debit}{$k} = $ref->{amount} * -1;
521 $ref->{debit_accno}{$k} = $ref->{accno};
522 $ref->{debit_taxkey}{$k} = $ref->{taxkey};
523 $ref->{ac_transdate}{$k} = $ref->{transdate};
524 $ref->{source}{$k} = $source;
526 $ref->{credit}{$l} = $ref->{amount} * 1;
527 $ref->{credit_accno}{$l} = $ref->{accno};
528 $ref->{credit_taxkey}{$l} = $ref->{taxkey};
529 $ref->{ac_transdate}{$l} = $ref->{transdate};
530 $ref->{source}{$l} = $source;
534 } else { # following lines of a booking, line increasing
537 # $trans_old = $trans_id2; # doesn't seem to be used anymore
538 $trans_id2 = $ref2->{id};
541 (int($balance * 100000) + int(100000 * $ref2->{amount})) / 100000;
543 $ref->{"projectnumbers"}->{$ref2->{"projectnumber"}} = 1 if ($ref2->{"projectnumber"});
545 if ($ref2->{chart_id} > 0) { # all tax accounts, following lines
546 if ($ref2->{amount} < 0) {
547 if ($ref2->{link} =~ /AR_tax/) {
548 if ($ref->{credit_tax_accno}{$j} ne "") {
551 $ref->{credit_tax}{$j} = $ref2->{amount};
552 $ref->{credit_tax_accno}{$j} = $ref2->{accno};
554 if ($ref2->{link} =~ /AP_tax/) {
555 if ($ref->{debit_tax_accno}{$i} ne "") {
558 $ref->{debit_tax}{$i} = $ref2->{amount} * -1;
559 $ref->{debit_tax_accno}{$i} = $ref2->{accno};
562 if ($ref2->{link} =~ /AR_tax/) {
563 if ($ref->{credit_tax_accno}{$j} ne "") {
566 $ref->{credit_tax}{$j} = $ref2->{amount};
567 $ref->{credit_tax_accno}{$j} = $ref2->{accno};
569 if ($ref2->{link} =~ /AP_tax/) {
570 if ($ref->{debit_tax_accno}{$i} ne "") {
573 $ref->{debit_tax}{$i} = $ref2->{amount} * -1;
574 $ref->{debit_tax_accno}{$i} = $ref2->{accno};
577 } else { # all other accounts, following lines
578 if ($ref2->{amount} < 0) {
579 if ($ref->{debit_accno}{$k} ne "") {
582 if ($ref->{source}{$k} ne "") {
587 $ref->{debit}{$k} = $ref2->{amount} * - 1;
588 $ref->{debit_accno}{$k} = $ref2->{accno};
589 $ref->{debit_taxkey}{$k} = $ref2->{taxkey};
590 $ref->{ac_transdate}{$k} = $ref2->{transdate};
591 $ref->{source}{$k} = $source . $space . $ref->{source}{$k};
593 if ($ref->{credit_accno}{$l} ne "") {
596 if ($ref->{source}{$l} ne "") {
601 $ref->{credit}{$l} = $ref2->{amount};
602 $ref->{credit_accno}{$l} = $ref2->{accno};
603 $ref->{credit_taxkey}{$l} = $ref2->{taxkey};
604 $ref->{ac_transdate}{$l} = $ref2->{transdate};
605 $ref->{source}{$l} = $ref->{source}{$l} . $space . $source;
611 push @{ $form->{GL} }, $ref;
614 if ($form->{accno}) {
615 $query = qq|SELECT c.description FROM chart c WHERE c.accno = ?|;
616 ($form->{account_description}) = selectrow_query($form, $dbh, $query, $form->{accno});
619 $main::lxdebug->leave_sub();
623 my ($self, $myconfig, $form) = @_;
624 $main::lxdebug->enter_sub();
626 my ($query, $sth, $ref, @values);
628 my $dbh = SL::DB->client->dbh;
630 $query = qq|SELECT closedto, revtrans FROM defaults|;
631 ($form->{closedto}, $form->{revtrans}) = selectrow_query($form, $dbh, $query);
633 $query = qq|SELECT id, gldate
635 WHERE id = (SELECT max(id) FROM gl)|;
636 ($form->{previous_id}, $form->{previous_gldate}) = selectrow_query($form, $dbh, $query);
640 qq|SELECT g.reference, g.description, g.notes, g.transdate, g.deliverydate,
641 g.storno, g.storno_id,
642 g.department_id, d.description AS department,
643 e.name AS employee, g.taxincluded, g.gldate,
644 g.ob_transaction, g.cb_transaction
646 LEFT JOIN department d ON (d.id = g.department_id)
647 LEFT JOIN employee e ON (e.id = g.employee_id)
649 $ref = selectfirst_hashref_query($form, $dbh, $query, conv_i($form->{id}));
650 map { $form->{$_} = $ref->{$_} } keys %$ref;
652 # retrieve individual rows
654 qq|SELECT c.accno, t.taxkey AS accnotaxkey, a.amount, a.memo, a.source,
655 a.transdate, a.cleared, a.project_id, p.projectnumber,
656 a.taxkey, t.rate AS taxrate, t.id, a.chart_id,
658 FROM chart c1, tax t1
659 WHERE (t1.id = t.id) AND (c1.id = t.chart_id)) AS taxaccno,
662 WHERE (tk.chart_id = a.chart_id) AND (tk.startdate <= a.transdate)
663 ORDER BY tk.startdate desc LIMIT 1) AS tax_id
665 JOIN chart c ON (c.id = a.chart_id)
666 LEFT JOIN project p ON (p.id = a.project_id)
667 LEFT JOIN tax t ON (t.id = a.tax_id)
668 WHERE (a.trans_id = ?)
669 AND (a.fx_transaction = '0')
670 ORDER BY a.acc_trans_id, a.transdate|;
671 $form->{GL} = selectall_hashref_query($form, $dbh, $query, conv_i($form->{id}));
678 WHERE id = (SELECT MAX(id) FROM gl)
681 ($form->{transdate}) = selectrow_query($form, $dbh, $query);
684 # get tax description
685 $query = qq|SELECT * FROM tax ORDER BY taxkey|;
686 $form->{TAX} = selectall_hashref_query($form, $dbh, $query);
688 # get chart of accounts
690 qq|SELECT c.accno, c.description, c.link, tk.taxkey_id, tk.tax_id
692 LEFT JOIN taxkeys tk ON (tk.id =
695 WHERE (taxkeys.chart_id = c.id)
697 ORDER BY startdate DESC
700 $form->{chart} = selectall_hashref_query($form, $dbh, $query, conv_date($form->{transdate}));
702 $main::lxdebug->leave_sub();
706 my ($self, $form, $myconfig, $id) = @_;
707 $main::lxdebug->enter_sub();
709 my $rc = SL::DB->client->with_transaction(\&_storno, $self, $form, $myconfig, $id);
711 $::lxdebug->leave_sub;
716 my ($self, $form, $myconfig, $id) = @_;
718 my ($query, $new_id, $storno_row, $acc_trans_rows);
719 my $dbh = SL::DB->client->dbh;
721 $query = qq|SELECT nextval('glid')|;
722 ($new_id) = selectrow_query($form, $dbh, $query);
724 $query = qq|SELECT * FROM gl WHERE id = ?|;
725 $storno_row = selectfirst_hashref_query($form, $dbh, $query, $id);
727 $storno_row->{id} = $new_id;
728 $storno_row->{storno_id} = $id;
729 $storno_row->{storno} = 't';
730 $storno_row->{reference} = 'Storno-' . $storno_row->{reference};
732 $query = qq|SELECT id FROM employee WHERE login = ?|;
733 my ($employee_id) = selectrow_query($form, $dbh, $query, $::myconfig{login});
734 $storno_row->{employee_id} = $employee_id;
736 delete @$storno_row{qw(itime mtime gldate)};
738 $query = sprintf 'INSERT INTO gl (%s) VALUES (%s)', join(', ', keys %$storno_row), join(', ', map '?', values %$storno_row);
739 do_query($form, $dbh, $query, (values %$storno_row));
741 $query = qq|UPDATE gl SET storno = 't' WHERE id = ?|;
742 do_query($form, $dbh, $query, $id);
744 # now copy acc_trans entries
745 $query = qq|SELECT * FROM acc_trans WHERE trans_id = ?|;
746 my $rowref = selectall_hashref_query($form, $dbh, $query, $id);
748 for my $row (@$rowref) {
749 delete @$row{qw(itime mtime acc_trans_id gldate)};
750 $query = sprintf 'INSERT INTO acc_trans (%s) VALUES (%s)', join(', ', keys %$row), join(', ', map '?', values %$row);
751 $row->{trans_id} = $new_id;
752 $row->{amount} *= -1;
753 do_query($form, $dbh, $query, (values %$row));
759 sub get_chart_balances {
760 my ($self, @chart_ids) = @_;
762 return () unless @chart_ids;
764 my $placeholders = join ', ', ('?') x scalar(@chart_ids);
765 my $query = qq|SELECT chart_id, SUM(amount) AS sum
767 WHERE chart_id IN (${placeholders})
770 my %balances = selectall_as_map($::form, $::form->get_standard_dbh(\%::myconfig), $query, 'chart_id', 'sum', @chart_ids);
775 sub get_active_taxes_for_chart {
776 my ($self, $chart_id, $transdate, $tax_id) = @_;
778 my $chart = SL::DB::Chart->new(id => $chart_id)->load;
779 my $active_taxkey = $chart->get_active_taxkey($transdate);
781 my $where = [ chart_categories => { like => '%' . $chart->category . '%' } ];
783 if ( defined $tax_id && $tax_id >= 0 ) {
784 $where = [ or => [ chart_categories => { like => '%' . $chart->category . '%' },
790 my $taxes = SL::DB::Manager::Tax->get_all(
792 sort_by => 'taxkey, rate',
795 my $default_tax = first { $active_taxkey->tax_id == $_->id } @{ $taxes };
796 $default_tax->{is_default} = 1 if $default_tax;
811 SL::GL - some useful GL functions
817 =item C<get_active_taxes_for_chart> $transdate $tax_id
819 Returns a list of valid taxes for a certain chart.
821 If the optional param transdate exists one entry in the returning list
822 may get the attribute C<is_default> for this specific tax-dependent date.
823 The possible entries are filtered by the charttype of the tax, i.e. only taxes
824 whose chart_categories match the category of the chart will be shown.
826 In the case of existing records, e.g. when opening an old ar record, due to
827 changes in the configurations the desired tax might not be available in the
828 dropdown anymore. If we are loading an old record and know its tax_id (from
829 acc_trans), we can pass $tax_id as the third parameter and be sure that the
830 original tax always appears in the dropdown.
832 The functions returns an array which may be used for building dropdowns in ar/ap/gl code.
844 G. Richardson E<lt>grichardson@kivitec.de<gt>