#=====================================================================
# LedgerSMB
# Small Medium Business Accounting software
# http://www.ledgersmb.org/
# Copyright (C) 2006
# This work contains copyrighted information from a number of sources all used
# with permission.
#
# This file contains source code included with or based on SQL-Ledger which
# is Copyright Dieter Simader and DWS Systems Inc. 2000-2005 and licensed
# under the GNU General Public License version 2 or, at your option, any later
# version.  For a full list including contact information of contributors,
# maintainers, and copyright holders, see the CONTRIBUTORS file.
#
# Original Copyright Notice from SQL-Ledger 2.6.17 (before the fork):
# Copyright (C) 2006
#
#  Author: DWS Systems Inc.
#     Web: http://www.sql-ledger.org
#
#  Contributors:
#
#
# See COPYRIGHT file for copyright information
#======================================================================
#
# This file has undergone whitespace cleanup.
#
#======================================================================
#
# AR/AP backend routines
# common routines
#
#======================================================================

package AA;
use LedgerSMB::Sysconfig;

sub post_transaction {

    my ( $self, $myconfig, $form ) = @_;

    # connect to database
    my $dbh = $form->{dbh};

    my $query;
    my $sth;

    my $null;
    ( $null, $form->{department_id} ) = split( /--/, $form->{department} );
    $form->{department_id} *= 1;

    my $ml        = 1;
    my $table     = 'ar';
    my $buysell   = 'buy';
    my $ARAP      = 'AR';
    my $invnumber = "sinumber";
    my $keepcleared;

    if ( $form->{vc} eq 'vendor' ) {
        $table     = 'ap';
        $buysell   = 'sell';
        $ARAP      = 'AP';
        $ml        = -1;
        $invnumber = "vinumber";
    }
    $form->{invnumber} = $form->update_defaults( $myconfig, $invnumber)
      unless $form->{invnumber};

    if ( $form->{currency} eq $form->{defaultcurrency} ) {
        $form->{exchangerate} = 1;
    }
    else {
        $exchangerate =
          $form->check_exchangerate( $myconfig, $form->{currency},
            $form->{transdate}, $buysell );

        $form->{exchangerate} =
          ($exchangerate)
          ? $exchangerate
          : $form->parse_amount( $myconfig, $form->{exchangerate} );
    }

    my @taxaccounts = split / /, $form->{taxaccounts};
    my $tax         = 0;
    my $fxtax       = 0;
    my $amount;
    my $diff;

    my %tax = ();
    my $accno;

    # add taxes
    foreach $accno (@taxaccounts) {
        $fxtax += $tax{fxamount}{$accno} =
          $form->parse_amount( $myconfig, $form->{"tax_$accno"} );
        $tax += $tax{fxamount}{$accno};

        push @{ $form->{acc_trans}{taxes} },
          {
            accno          => $accno,
            amount         => $tax{fxamount}{$accno},
            project_id     => undef,
            fx_transaction => 0
          };

        $amount = $tax{fxamount}{$accno} * $form->{exchangerate};
        $tax{amount}{$accno} = $form->round_amount( $amount - $diff, 2 );
        $diff = $tax{amount}{$accno} - ( $amount - $diff );
        $amount = $tax{amount}{$accno} - $tax{fxamount}{$accno};
        $tax += $amount;

        if ( $form->{currency} ne $form->{defaultcurrency} ) {
            push @{ $form->{acc_trans}{taxes} },
              {
                accno          => $accno,
                amount         => $amount,
                project_id     => undef,
                fx_transaction => 1
              };
        }

    }

    my %amount      = ();
    my $fxinvamount = 0;
    for ( 1 .. $form->{rowcount} ) {
        $fxinvamount += $amount{fxamount}{$_} =
          $form->parse_amount( $myconfig, $form->{"amount_$_"} );
    }

    $form->{taxincluded} *= 1;

    my $i;
    my $project_id;
    my $cleared = 0;

    $diff = 0;

    # deduct tax from amounts if tax included
    for $i ( 1 .. $form->{rowcount} ) {

        if ( $amount{fxamount}{$i} ) {

            if ( $form->{taxincluded} ) {
                $amount =
                  ($fxinvamount)
                  ? $fxtax * $amount{fxamount}{$i} / $fxinvamount
                  : 0;
                $amount{fxamount}{$i} -= $amount;
            }

            # multiply by exchangerate
            $amount = $amount{fxamount}{$i} * $form->{exchangerate};
            $amount{amount}{$i} = $form->round_amount( $amount - $diff, 2 );
            $diff = $amount{amount}{$i} - ( $amount - $diff );

            ( $null, $project_id ) = split /--/, $form->{"projectnumber_$i"};
            $project_id ||= undef;
            ($accno) = split /--/, $form->{"${ARAP}_amount_$i"};

            if ($keepcleared) {
                $cleared = ( $form->{"cleared_$i"} ) ? 1 : 0;
            }

            push @{ $form->{acc_trans}{lineitems} },
              {
                accno          => $accno,
                amount         => $amount{fxamount}{$i},
                project_id     => $project_id,
                description    => $form->{"description_$i"},
                cleared        => $cleared,
                fx_transaction => 0
              };

            if ( $form->{currency} ne $form->{defaultcurrency} ) {
                $amount = $amount{amount}{$i} - $amount{fxamount}{$i};
                push @{ $form->{acc_trans}{lineitems} },
                  {
                    accno          => $accno,
                    amount         => $amount,
                    project_id     => $project_id,
                    description    => $form->{"description_$i"},
                    cleared        => $cleared,
                    fx_transaction => 1
                  };
            }
        }
    }

    my $invnetamount = 0;
    for ( @{ $form->{acc_trans}{lineitems} } ) { $invnetamount += $_->{amount} }
    my $invamount = $invnetamount + $tax;

    # adjust paidaccounts if there is no date in the last row
    $form->{paidaccounts}--
      unless ( $form->{"datepaid_$form->{paidaccounts}"} );

    if ( $form->{vc} ne "customer" ) {
        $form->{vc} = "vendor";
    }

    my $paid = 0;
    my $fxamount;

    $diff = 0;

    # add payments
    for $i ( 1 .. $form->{paidaccounts} ) {
        $fxamount = $form->parse_amount( $myconfig, $form->{"paid_$i"} );

        if ($fxamount) {
            $paid += $fxamount;

            $paidamount = $fxamount * $form->{exchangerate};

            $amount = $form->round_amount( $paidamount - $diff, 2 );
            $diff = $amount - ( $paidamount - $diff );

            $form->{datepaid} = $form->{"datepaid_$i"};

            $paid{fxamount}{$i} = $fxamount;
            $paid{amount}{$i}   = $amount;
        }
    }

    $fxinvamount += $fxtax unless $form->{taxincluded};
    $fxinvamount = $form->round_amount( $fxinvamount, 2 );
    $invamount   = $form->round_amount( $invamount,   2 );
    $paid        = $form->round_amount( $paid,        2 );

    $paid =
      ( $fxinvamount == $paid )
      ? $invamount
      : $form->round_amount( $paid * $form->{exchangerate}, 2 );

    $query = q|
		SELECT (SELECT value FROM defaults 
		         WHERE setting_key = 'fxgain_accno_id'), 
		       (SELECT value FROM defaults
		         WHERE setting_key = 'fxloss_accno_id')|;

    my ( $fxgain_accno_id, $fxloss_accno_id ) = $dbh->selectrow_array($query);

    ( $null, $form->{employee_id} ) = split /--/, $form->{employee};
    unless ( $form->{employee_id} ) {
        ( $form->{employee}, $form->{employee_id} ) = $form->get_employee($dbh);
    }

    # check if id really exists
    if ( $form->{id} ) {
        my $id = $dbh->quote( $form->{id} );
        $keepcleared = 1;
        $query       = qq|
			SELECT id
			  FROM $table
			 WHERE id = $id|;

        if ( $dbh->selectrow_array($query) ) {

            # delete detail records
            $query = qq|
				DELETE FROM acc_trans
				 WHERE trans_id = $id|;

            $dbh->do($query) || $form->dberror($query);
        }
    }
    else {

        my $uid = localtime;
        $uid .= "$$";

        $query = qq|
			INSERT INTO $table (invnumber)
			     VALUES ('$uid')|;

        $dbh->do($query) || $form->dberror($query);

        $query = qq|
			SELECT id FROM $table
			 WHERE invnumber = '$uid'|;

        ( $form->{id} ) = $dbh->selectrow_array($query);
    }

    # record last payment date in ar/ap table
    $form->{datepaid} = $form->{transdate} unless $form->{datepaid};
    my $datepaid = ($paid) ? qq|'$form->{datepaid}'| : undef;


    $query = qq|
		UPDATE $table 
		SET invnumber = ?,
			ordnumber = ?,
			transdate = ?,
			$form->{vc}_id = ?,
			taxincluded = ?,
			amount = ?,
			duedate = ?,
			paid = ?,
			datepaid = ?,
			netamount = ?,
			curr = ?,
			notes = ?,
			department_id = ?,
			employee_id = ?,
			ponumber = ?
		WHERE id = ?
	|;

    my @queryargs = (
        $form->{invnumber},     $form->{ordnumber},
        $form->{transdate},     $form->{"$form->{vc}_id"},
        $form->{taxincluded},   $invamount,
        $form->{duedate},       $paid,
        $datepaid,              $invnetamount,
        $form->{currency},      $form->{notes},
        $form->{department_id}, $form->{employee_id},
        $form->{ponumber},      $form->{id}
    );

    $dbh->prepare($query)->execute(@queryargs) || $form->dberror($query);

    @queries = $form->run_custom_queries( $table, 'INSERT' );

    # update exchangerate
    my $buy  = $form->{exchangerate};
    my $sell = 0;
    if ( $form->{vc} eq 'vendor' ) {
        $buy  = 0;
        $sell = $form->{exchangerate};
    }

    if ( ( $form->{currency} ne $form->{defaultcurrency} ) && !$exchangerate ) {
        $form->update_exchangerate( $dbh, $form->{currency}, $form->{transdate},
            $buy, $sell );
    }

    my $ref;

    # add individual transactions
    foreach $ref ( @{ $form->{acc_trans}{lineitems} } ) {

        # insert detail records in acc_trans
        if ( $ref->{amount} ) {
            $query = qq|
				INSERT INTO acc_trans 
				            (trans_id, chart_id, amount, 
				            transdate, project_id, memo, 
				            fx_transaction, cleared)
				    VALUES  (?, (SELECT id FROM chart
				                  WHERE accno = ?), 
				            ?, ?, ?, ?, ?, ?)|;

            @queryargs = (
                $form->{id},            $ref->{accno},
                $ref->{amount} * $ml,   $form->{transdate},
                $ref->{project_id},     $ref->{description},
                $ref->{fx_transaction}, $ref->{cleared}
            );
            $dbh->prepare($query)->execute(@queryargs)
              || $form->dberror($query);
        }
    }

    # save taxes
    foreach $ref ( @{ $form->{acc_trans}{taxes} } ) {
        if ( $ref->{amount} ) {
            $query = qq|
				INSERT INTO acc_trans 
				            (trans_id, chart_id, amount,
				            transdate, fx_transaction)
				     VALUES (?, (SELECT id FROM chart
					          WHERE accno = ?),
				            ?, ?, ?)|;

            @queryargs = (
                $form->{id}, $ref->{accno}, $ref->{amount} * $ml,
                $form->{transdate}, $ref->{fx_transaction}
            );
            $dbh->prepare($query)->execute(@queryargs)
              || $form->dberror($query);
        }
    }

    my $arap;

    # record ar/ap
    if ( ( $arap = $invamount ) ) {
        ($accno) = split /--/, $form->{$ARAP};

        $query = qq|
			INSERT INTO acc_trans 
			            (trans_id, chart_id, amount, transdate)
			     VALUES (?, (SELECT id FROM chart
			                  WHERE accno = ?), 
			                  ?, ?)|;
        @queryargs =
          ( $form->{id}, $accno, $invamount * -1 * $ml, $form->{transdate} );

        $dbh->prepare($query)->execute(@queryargs)
          || $form->dberror($query);
    }

    # if there is no amount force ar/ap
    if ( $fxinvamount == 0 ) {
        $arap = 1;
    }

    my $exchangerate;

    # add paid transactions
    for $i ( 1 .. $form->{paidaccounts} ) {

        if ( $paid{fxamount}{$i} ) {

            ($accno) = split( /--/, $form->{"${ARAP}_paid_$i"} );
            $form->{"datepaid_$i"} = $form->{transdate}
              unless ( $form->{"datepaid_$i"} );

            $exchangerate = 0;

            if ( $form->{currency} eq $form->{defaultcurrency} ) {
                $form->{"exchangerate_$i"} = 1;
            }
            else {
                $exchangerate =
                  $form->check_exchangerate( $myconfig, $form->{currency},
                    $form->{"datepaid_$i"}, $buysell );

                $form->{"exchangerate_$i"} =
                  ($exchangerate)
                  ? $exchangerate
                  : $form->parse_amount( $myconfig,
                    $form->{"exchangerate_$i"} );
            }

            # if there is no amount
            if ( $fxinvamount == 0 ) {
                $form->{exchangerate} = $form->{"exchangerate_$i"};
            }

            # ar/ap amount
            if ($arap) {
                ($accno) = split /--/, $form->{$ARAP};

                # add ar/ap
                $query = qq|
					INSERT INTO acc_trans 
					            (trans_id, chart_id, 
					            amount,transdate)
					     VALUES (?, (SELECT id FROM chart
					                  WHERE accno = ?),
					            ?, ?)|;

                @queryargs = (
                    $form->{id}, $accno,
                    $paid{amount}{$i} * $ml,
                    $form->{"datepaid_$i"}
                );
                $dbh->prepare($query)->execute(@queryargs)
                  || $form->dberror($query);
            }

            $arap = $paid{amount}{$i};

            # add payment
            if ( $paid{fxamount}{$i} ) {

                ($accno) = split /--/, $form->{"${ARAP}_paid_$i"};

                my $cleared = ( $form->{"cleared_$i"} ) ? 1 : 0;

                $amount = $paid{fxamount}{$i};
                $query  = qq|
					INSERT INTO acc_trans 
					            (trans_id, chart_id, amount,
					            transdate, source, memo, 
					            cleared)
					     VALUES (?, (SELECT id FROM chart
						          WHERE accno = ?),
					            ?, ?, ?, ?, ?)|;

                @queryargs = (
                    $form->{id},          $accno,
                    $amount * -1 * $ml,   $form->{"datepaid_$i"},
                    $form->{"source_$i"}, $form->{"memo_$i"},
                    $cleared
                );
                $dbh->prepare($query)->execute(@queryargs)
                  || $form->dberror($query);

                if ( $form->{currency} ne $form->{defaultcurrency} ) {

                    # exchangerate gain/loss
                    $amount = (
                        $form->round_amount(
                            $paid{fxamount}{$i} * $form->{exchangerate}, 2 ) -
                          $form->round_amount(
                            $paid{fxamount}{$i} * $form->{"exchangerate_$i"}, 2
                          )
                    ) * -1;

                    if ($amount) {

                        my $accno_id =
                          ( ( $amount * $ml ) > 0 )
                          ? $fxgain_accno_id
                          : $fxloss_accno_id;

                        $query = qq|
							INSERT INTO acc_trans 
							            (trans_id, 
							            chart_id, 
							            amount,
							            transdate, 
							            fx_transaction, 
							            cleared)
							     VALUES (?, ?, 
							            ?, 
							            ?, '1', ?)|;

                        @queryargs = (
                            $form->{id}, $accno_id,
                            $amount * $ml,
                            $form->{"datepaid_$i"}, $cleared
                        );
                        $sth = $dbh->prepare($query);
                        $sth->execute(@queryargs)
                          || $form->dberror($query);
                    }

                    # exchangerate difference
                    $amount = $paid{amount}{$i} - $paid{fxamount}{$i} + $amount;

                    $query = qq|
						INSERT INTO acc_trans 
						            (trans_id, chart_id,
						            amount,
						            transdate, 
						            fx_transaction, 
						            cleared, source)
						     VALUES (?, (SELECT id 
						                   FROM chart
						                  WHERE accno 
						                        = ?),
						            ?, ?, 
						            '1', ?, ?)|;

                    @queryargs = (
                        $form->{id}, $accno,
                        $amount * -1 * $ml,
                        $form->{"datepaid_$i"},
                        $cleared, $form->{"source_$i"}
                    );
                    $sth = $dbh->prepare($query);
                    $sth->execute(@queryargs)
                      || $form->dberror($query);

                }

                # update exchangerate record
                $buy  = $form->{"exchangerate_$i"};
                $sell = 0;

                if ( $form->{vc} eq 'vendor' ) {
                    $buy  = 0;
                    $sell = $form->{"exchangerate_$i"};
                }

                if ( ( $form->{currency} ne $form->{defaultcurrency} )
                    && !$exchangerate )
                {

                    $form->update_exchangerate( $dbh, $form->{currency},
                        $form->{"datepaid_$i"},
                        $buy, $sell );
                }
            }
        }
    }
    if ($invamount->is_nan) {
        $dbh->rollback;
	return;
    }
    # save printed and queued
    $form->save_status($dbh);

    my %audittrail = (
        tablename => $table,
        reference => $form->{invnumber},
        formname  => 'transaction',
        action    => 'posted',
        id        => $form->{id}
    );

    $form->audittrail( $dbh, "", \%audittrail );

    $form->save_recurring( $dbh, $myconfig );

    my $rc = $dbh->commit;

    $rc;

}

sub delete_transaction {
    my ( $self, $myconfig, $form ) = @_;

    # connect to database, turn AutoCommit off
    my $dbh = $form->{dbh};

    my $table = ( $form->{vc} eq 'customer' ) ? 'ar' : 'ap';

    my %audittrail = (
        tablename => $table,
        reference => $form->{invnumber},
        formname  => 'transaction',
        action    => 'deleted',
        id        => $form->{id}
    );

    $form->audittrail( $dbh, "", \%audittrail );

    my $query = qq|DELETE FROM $table WHERE id = $form->{id}|;
    $dbh->do($query) || $form->dberror($query);

    $query = qq|DELETE FROM acc_trans WHERE trans_id = ?|;
    $dbh->prepare($query)->execute( $form->{id} ) || $form->dberror($query);

    # get spool files
    $query = qq|SELECT spoolfile 
				  FROM status
				 WHERE trans_id = ?
				   AND spoolfile IS NOT NULL|;

    my $sth = $dbh->prepare($query);
    $sth->execute( $form->{id} ) || $form->dberror($query);

    my $spoolfile;
    my @spoolfiles = ();

    while ( ($spoolfile) = $sth->fetchrow_array ) {
        push @spoolfiles, $spoolfile;
    }

    $sth->finish;

    $query = qq|DELETE FROM status WHERE trans_id = ?|;
    $dbh->prepare($query)->execute( $form->{id} ) || $form->dberror($query);

    # commit
    my $rc = $dbh->commit;

    if ($rc) {
        foreach $spoolfile (@spoolfiles) {
            unlink "${LedgerSMB::Sysconfig::spool}/$spoolfile" if $spoolfile;
        }
    }

    $rc;
}

sub transactions {
    my ( $self, $myconfig, $form ) = @_;

    # connect to database
    my $dbh = $form->{dbh};
    my $null;
    my $var;
    my $paid    = "a.paid";
    my $ml      = 1;
    my $ARAP    = 'AR';
    my $table   = 'ar';
    my $buysell = 'buy';
    my $acc_trans_join;
    my $acc_trans_flds;

    if ( $form->{vc} eq 'vendor' ) {
        $ml      = -1;
        $ARAP    = 'AP';
        $table   = 'ap';
        $buysell = 'sell';
    }

    ( $form->{transdatefrom}, $form->{transdateto} ) =
      $form->from_to( $form->{year}, $form->{month}, $form->{interval} )
      if $form->{year} && $form->{month};

    my @paidargs = ();
    if ( $form->{outstanding} ) {
        $paid = qq|
			SELECT SUM(ac.amount) * -1 * $ml
			  FROM acc_trans ac
			  JOIN chart c ON (c.id = ac.chart_id)
			 WHERE ac.trans_id = a.id
			       AND (c.link LIKE '%${ARAP}_paid%' 
			       OR c.link = '')|;
        if ( $form->{transdateto} ) {
            $paid .= qq|
			       AND ac.transdate <= ?|;
            push @paidargs, $form->{transdateto};
        }
        $form->{summary} = 1;
    }

    if ( !$form->{summary} ) {
        $acc_trans_flds = qq|
			, c.accno, ac.source,
			pr.projectnumber, ac.memo AS description,
			ac.amount AS linetotal,
			i.description AS linedescription|;

        $acc_trans_join = qq| 
			     JOIN acc_trans ac ON (a.id = ac.trans_id)
			     JOIN chart c ON (c.id = ac.chart_id)
			LEFT JOIN project pr ON (pr.id = ac.project_id)
			LEFT JOIN invoice i ON (i.id = ac.invoice_id)|;
    }

    my $query = qq|
		   SELECT a.id, a.invnumber, a.ordnumber, a.transdate,
		          a.duedate, a.netamount, a.amount, ($paid) AS paid,
		          a.invoice, a.datepaid, a.terms, a.notes,
		          a.shipvia, a.shippingpoint, e.name AS employee, 
		          vc.name,
		          a.$form->{vc}_id, a.till, m.name AS manager, a.curr,
		          ex.$buysell AS exchangerate, 
		          d.description AS department, 
		          a.ponumber $acc_trans_flds
		     FROM $table a
		     JOIN $form->{vc} vc ON (a.$form->{vc}_id = vc.id)
		LEFT JOIN employee e ON (a.employee_id = e.id)
		LEFT JOIN employee m ON (e.managerid = m.id)
		LEFT JOIN exchangerate ex ON (ex.curr = a.curr
		          AND ex.transdate = a.transdate)
		LEFT JOIN department d ON (a.department_id = d.id) 
		$acc_trans_join|;

    my %ordinal = (
        id            => 1,
        invnumber     => 2,
        ordnumber     => 3,
        transdate     => 4,
        duedate       => 5,
        datepaid      => 10,
        shipvia       => 13,
        shippingpoint => 14,
        employee      => 15,
        name          => 16,
        manager       => 19,
        curr          => 20,
        department    => 22,
        ponumber      => 23,
        accno         => 24,
        source        => 25,
        project       => 26,
        description   => 27
    );

    my @a = ( transdate, invnumber, name );
    push @a, "employee" if $form->{l_employee};
    push @a, "manager"  if $form->{l_manager};
    my $sortorder = $form->sort_order( \@a, \%ordinal );

    my $where = "1 = 1";
    if ( $form->{"$form->{vc}_id"} ) {
        $where .= qq| AND a.$form->{vc}_id = $form->{"$form->{vc}_id"}|;
    }
    else {
        if ( $form->{ $form->{vc} } ) {
            $var = $dbh->quote( $form->like( lc $form->{ $form->{vc} } ) );
            $where .= " AND lower(vc.name) LIKE $var";
        }
    }

    for (qw(department employee)) {
        if ( $form->{$_} ) {
            ( $null, $var ) = split /--/, $form->{$_};
            $var = $dbh->quote($var);
            $where .= " AND a.${_}_id = $var";
        }
    }

    for (qw(invnumber ordnumber)) {
        if ( $form->{$_} ) {
            $var = $dbh->quote( $form->like( lc $form->{$_} ) );
            $where .= " AND lower(a.$_) LIKE $var";
            $form->{open} = $form->{closed} = 0;
        }
    }
    if ( $form->{partsid} ) {
        my $partsid = $dbh->quote( $form->{partsid} );
        $where .= " AND a.id IN (select trans_id FROM invoice
			WHERE parts_id = $partsid)";
    }

    for (qw(ponumber shipvia notes)) {
        if ( $form->{$_} ) {
            $var = $dbh->quote( $form->like( lc $form->{$_} ) );
            $where .= " AND lower(a.$_) LIKE $var";
        }
    }

    if ( $form->{description} ) {
        if ($acc_trans_flds) {
            $var = $dbh->quote( $form->like( lc $form->{description} ) );
            $where .= " AND lower(ac.memo) LIKE $var
			OR lower(i.description) LIKE $var";
        }
        else {
            $where .= " AND a.id = 0";
        }
    }

    if ( $form->{source} ) {
        if ($acc_trans_flds) {
            $var = $dbh->quote( $form->like( lc $form->{source} ) );
            $where .= " AND lower(ac.source) LIKE $var";
        }
        else {
            $where .= " AND a.id = 0";
        }
    }

    my $transdatefrom = $dbh->quote( $form->{transdatefrom} );
    $where .= " AND a.transdate >= $transdatefrom"
      if $form->{transdatefrom};

    my $transdateto = $dbh->quote( $form->{transdateto} );
    $where .= " AND a.transdate <= $transdateto" if $form->{transdateto};

    if ( $form->{open} || $form->{closed} ) {
        unless ( $form->{open} && $form->{closed} ) {
            $where .= " AND a.amount != a.paid" if ( $form->{open} );
            $where .= " AND a.amount = a.paid"  if ( $form->{closed} );
        }
    }

    if ( $form->{till} ne "" ) {
	$form->{till} = $dbh->quote($form->{till});
        $where .= " AND a.invoice = '1'
					AND a.till = $form->{till}";

        if ( $myconfig->{role} eq 'user' ) {
            my $login = $dbh->quote( $form->{login} );
            $where .= " AND e.login = $login";
        }
    }

    if ( $form->{$ARAP} ) {
        my ($accno) = split /--/, $form->{$ARAP};
        $accno = $dbh->quote($accno);
        $where .= qq|
			AND a.id IN (SELECT ac.trans_id
			               FROM acc_trans ac
			               JOIN chart c ON (c.id = ac.chart_id)
			              WHERE a.id = ac.trans_id
			                    AND c.accno = $accno)|;
    }

    if ( $form->{description} ) {
        $var = $dbh->quote( $form->like( lc $form->{description} ) );
        $where .= qq|
			AND (a.id IN (SELECT DISTINCT trans_id
			                FROM acc_trans
			               WHERE lower(memo) LIKE $var)
			                     OR a.id IN 
			                     (SELECT DISTINCT trans_id
			                                 FROM invoice
			                                WHERE lower(description)
			                                      LIKE $var))|;
    }

    $query .= "WHERE $where
			ORDER BY $sortorder";
    my $sth = $dbh->prepare($query);
    $sth->execute(@paidargs) || $form->dberror($query);

    while ( my $ref = $sth->fetchrow_hashref(NAME_lc) ) {
	$form->db_parse_numeric(sth => $sth, hashref => $ref);
        $ref->{exchangerate} = 1 unless $ref->{exchangerate};

        if ( $ref->{linetotal} <= 0 ) {
            $ref->{debit}  = $ref->{linetotal} * -1;
            $ref->{credit} = 0;
        }
        else {
            $ref->{debit}  = 0;
            $ref->{credit} = $ref->{linetotal};
        }

        if ( $ref->{invoice} ) {
            $ref->{description} ||= $ref->{linedescription};
        }

        if ( $form->{outstanding} ) {
            next
              if $form->round_amount( $ref->{amount}, 2 ) ==
              $form->round_amount( $ref->{paid}, 2 );
        }

        push @{ $form->{transactions} }, $ref;
    }

    $sth->finish;
    $dbh->commit;
}

# this is used in IS, IR to retrieve the name
sub get_name {

    my ( $self, $myconfig, $form ) = @_;

    # sanitize $form->{vc}
    if ( $form->{vc} ne 'customer' ) {
        $form->{vc} = 'vendor';
    }
    else {
        $form->{vc} = 'customer';
    }

    # connect to database
    my $dbh = $form->{dbh};

    my $dateformat = $myconfig->{dateformat};

    if ( $myconfig->{dateformat} !~ /^y/ ) {
        my @a = split /\W/, $form->{transdate};
        $dateformat .= "yy" if ( length $a[2] > 2 );
    }

    if ( $form->{transdate} !~ /\W/ ) {
        $dateformat = 'yyyymmdd';
    }

    my $duedate;

    $dateformat = $dbh->quote($dateformat);
    my $tdate = $dbh->quote( $form->{transdate} );
    $duedate = ( $form->{transdate} )
      ? "to_date($tdate, $dateformat) 
			+ c.terms"
      : "current_date + c.terms";

    $form->{"$form->{vc}_id"} *= 1;

    # get customer/vendor
    my $query = qq|
		   SELECT c.name AS $form->{vc}, c.discount, c.creditlimit, 
		          c.terms, c.email, c.cc, c.bcc, c.taxincluded,
		          c.address1, c.address2, c.city, c.state,
		          c.zipcode, c.country, c.curr AS currency, 
		          c.language_code, $duedate AS duedate, 
		          c.notes AS intnotes,
			  b.discount AS tradediscount, 
		          b.description AS business,
		          e.name AS employee, e.id AS employee_id
		     FROM $form->{vc} c
		LEFT JOIN business b ON (b.id = c.business_id)
		LEFT JOIN employee e ON (e.id = c.employee_id)
		    WHERE c.id = ?|;

    @queryargs = ( $form->{"$form->{vc}_id"} );
    my $sth = $dbh->prepare($query);

    $sth->execute(@queryargs) || $form->dberror($query);

    $ref = $sth->fetchrow_hashref(NAME_lc);
    $form->db_parse_numeric(sth => $sth, hashref => $ref);
    if ( $form->{id} ) {
        for (qw(currency employee employee_id intnotes)) {
            delete $ref->{$_};
        }
    }

    for ( keys %$ref ) { $form->{$_} = $ref->{$_} }
    $sth->finish;

    my $buysell = ( $form->{vc} eq 'customer' ) ? "buy" : "sell";

    # if no currency use defaultcurrency
    $form->{currency} =
      ( $form->{currency} )
      ? $form->{currency}
      : $form->{defaultcurrency};
    $form->{exchangerate} = 0
      if $form->{currency} eq $form->{defaultcurrency};

    if ( $form->{transdate}
        && ( $form->{currency} ne $form->{defaultcurrency} ) )
    {
        $form->{exchangerate} =
          $form->get_exchangerate( $dbh, $form->{currency}, $form->{transdate},
            $buysell );
    }

    $form->{forex} = $form->{exchangerate};

    # if no employee, default to login
    ( $form->{employee}, $form->{employee_id} ) = $form->get_employee($dbh)
      unless $form->{employee_id};

    my $arap = ( $form->{vc} eq 'customer' ) ? 'ar' : 'ap';
    my $ARAP = uc $arap;

    $form->{creditremaining} = $form->{creditlimit};
    $query = qq|
		SELECT SUM(amount - paid)
		  FROM $arap
		 WHERE $form->{vc}_id = ?|;

    $sth = $dbh->prepare($query);
    $sth->execute( $form->{"$form->{vc}_id"} )
      || $form->dberror($query);

    ( $form->{creditremaining} ) -= $sth->fetchrow_array;

    $sth->finish;
    if ( $form->{vc} ne "customer" ) {
        $form->{vc} = 'vendor';
    }

    $query = qq|
		SELECT o.amount, (SELECT e.$buysell FROM exchangerate e
		                   WHERE e.curr = o.curr
		                         AND e.transdate = o.transdate)
		  FROM oe o
		 WHERE o.$form->{vc}_id = ?
		       AND o.quotation = '0' AND o.closed = '0'|;

    $sth = $dbh->prepare($query);
    $sth->execute( $form->{"$form->{vc}_id"} ) || $form->dberror($query);

    while ( my @ref = $sth->fetchrow_array ) {
        $form->db_parse_numeric(sth => $sth, arrayref => \@ref);
        my ($amount, $exch) = @ref;
        $exch = 1 unless $exch;
        $form->{creditremaining} -= $amount * $exch;
    }

    $sth->finish;

    # get shipto if we did not converted an order or invoice
    if ( !$form->{shipto} ) {

        for (
            qw(shiptoname shiptoaddress1 shiptoaddress2
            shiptocity shiptostate shiptozipcode
            shiptocountry shiptocontact shiptophone
            shiptofax shiptoemail)
          )
        {
            delete $form->{$_};
        }

        ## needs fixing (SELECT *)
        $query = qq|
			SELECT * 
			  FROM shipto
			 WHERE trans_id = $form->{"$form->{vc}_id"}|;

        $sth = $dbh->prepare($query);
        $sth->execute || $form->dberror($query);

        $ref = $sth->fetchrow_hashref(NAME_lc);
        for ( keys %$ref ) { $form->{$_} = $ref->{$_} }
        $sth->finish;
    }

    # get taxes
    $query = qq|
		SELECT c.accno
		  FROM chart c
		  JOIN $form->{vc}tax ct ON (ct.chart_id = c.id)
		 WHERE ct.$form->{vc}_id = ?|;

    $sth = $dbh->prepare($query);
    $sth->execute( $form->{"$form->{vc}_id"} ) || $form->dberror($query);

    my %tax;

    while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
        $tax{ $ref->{accno} } = 1;
    }

    $sth->finish;
    $transdate = $dbh->quote( $form->{transdate} );
    my $where = qq|AND (t.validto >= $transdate OR t.validto IS NULL)|
      if $form->{transdate};

    # get tax rates and description
    $query = qq|
		   SELECT c.accno, c.description, t.rate, t.taxnumber
		     FROM chart c
		     JOIN tax t ON (c.id = t.chart_id)
		    WHERE c.link LIKE '%${ARAP}_tax%'
		          $where
		 ORDER BY accno, validto|;

    $sth = $dbh->prepare($query);
    $sth->execute || $form->dberror($query);

    $form->{taxaccounts} = "";
    my %a = ();

    while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
        $form->db_parse_numeric(sth => $sth, hashref => $hashref);

        if ( $tax{ $ref->{accno} } ) {
            if ( not exists $a{ $ref->{accno} } ) {
                for (qw(rate description taxnumber)) {
                    $form->{"$ref->{accno}_$_"} = $ref->{$_};
                }
                $form->{taxaccounts} .= "$ref->{accno} ";
                $a{ $ref->{accno} } = 1;
            }
        }
    }

    $sth->finish;
    chop $form->{taxaccounts};

    # setup last accounts used for this customer/vendor
    if ( !$form->{id} && $form->{type} !~ /_(order|quotation)/ ) {

        $query = qq|
			   SELECT c.accno, c.description, c.link, 
                                  c.category,
			          ac.project_id,
			          a.department_id
			     FROM chart c
			     JOIN acc_trans ac ON (ac.chart_id = c.id)
			     JOIN $arap a ON (a.id = ac.trans_id)
			    WHERE a.$form->{vc}_id = ?
			          AND a.id = (SELECT max(id) 
			                         FROM $arap
			                        WHERE $form->{vc}_id = 
			                              ?)
			|;

        $sth = $dbh->prepare($query);
        $sth->execute( $form->{"$form->{vc}_id"}, $form->{"$form->{vc}_id"} )
          || $form->dberror($query);

        my $i = 0;

        while ( $ref = $sth->fetchrow_hashref(NAME_lc) ) {
            $form->{department_id} = $ref->{department_id};
            if ( $ref->{link} =~ /_amount/ ) {
                $i++;
                $form->{"$form->{ARAP}_amount_$i"} =
                  "$ref->{accno}--$ref->{description}"
                  if $ref->{accno};
                $form->{"projectnumber_$i"} =
                  "$ref->{projectnumber}--" . "$ref->{project_id}"
                  if $ref->{project_id};
            }

            if ( $ref->{link} eq $form->{ARAP} ) {
                $form->{ $form->{ARAP} } = $form->{"$form->{ARAP}_1"} =
                  "$ref->{accno}--" . "$ref->{description}"
                  if $ref->{accno};
            }
        }

        $sth->finish;
        $query = "select description from department where id = ?";
        $sth = $dbh->prepare($query);
        $sth->execute($form->{department_id});
        ($form->{department}) = $sth->fetchrow_array;
        $form->{rowcount} = $i if ( $i && !$form->{type} );
    }

    $dbh->commit;
}

1;
