#=====================================================================
# SQL-Ledger Accounting
# Copyright (C) 2002
#
#  Author: Dieter Simader
#   Email: dsimader@sql-ledger.org
#     Web: http://www.sql-ledger.org
#
#  Contributors:
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#======================================================================
#
# Account reconciliation routines
#
#======================================================================

package RC;


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

  # connect to database
  my $dbh = $form->dbconnect($myconfig);

  my $query = qq|SELECT accno, description
                 FROM chart
		 WHERE link LIKE '%_paid%'
		 AND (category = 'A' OR category = 'L')
		 ORDER BY accno|;
  my $sth = $dbh->prepare($query);
  $sth->execute || $form->dberror($query);

  while (my $ref = $sth->fetchrow_hashref(NAME_lc)) {
    push @{ $form->{PR} }, $ref;
  }
  $sth->finish;

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

  $dbh->disconnect;

}


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

  # connect to database, turn AutoCommit off
  my $dbh = $form->dbconnect_noauto($myconfig);

  my $query;
  my $sth;

  $query = qq|SELECT category FROM chart
              WHERE accno = '$form->{accno}'|;
  ($form->{category}) = $dbh->selectrow_array($query);
  
  my $cleared;

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

  my $transdate = qq| AND ac.transdate < date '$form->{fromdate}'|;

  if (! $form->{fromdate}) {
    $cleared = qq| AND ac.cleared = '1'|;
    $transdate = "";
  }
    
  # get beginning balance
  $query = qq|SELECT sum(ac.amount)
	      FROM acc_trans ac
	      JOIN chart c ON (c.id = ac.chart_id)
	      WHERE c.accno = '$form->{accno}'
	      $transdate
	      $cleared
	      |;
  ($form->{beginningbalance}) = $dbh->selectrow_array($query);

  # fx balance
  $query = qq|SELECT sum(ac.amount)
	      FROM acc_trans ac
	      JOIN chart c ON (c.id = ac.chart_id)
	      WHERE c.accno = '$form->{accno}'
	      AND ac.fx_transaction = '1'
	      $transdate
	      $cleared
	      |;
  ($form->{fx_balance}) = $dbh->selectrow_array($query);
  

  $transdate = "";
  if ($form->{todate}) {
    $transdate = qq| AND ac.transdate <= date '$form->{todate}'|;
  }
 
  # get statement balance
  $query = qq|SELECT sum(ac.amount)
	      FROM acc_trans ac
	      JOIN chart c ON (c.id = ac.chart_id)
	      WHERE c.accno = '$form->{accno}'
	      $transdate
	      |;
  ($form->{endingbalance}) = $dbh->selectrow_array($query);

  # fx balance
  $query = qq|SELECT sum(ac.amount)
	      FROM acc_trans ac
	      JOIN chart c ON (c.id = ac.chart_id)
	      WHERE c.accno = '$form->{accno}'
	      AND ac.fx_transaction = '1'
	      $transdate
	      |;
  ($form->{fx_endingbalance}) = $dbh->selectrow_array($query);


  $cleared = qq| AND ac.cleared = '0'| unless $form->{fromdate};
  
  if ($form->{report}) {
    $cleared = qq| AND NOT (ac.cleared = '0' OR ac.cleared = '1')|;
    if ($form->{cleared}) {
      $cleared = qq| AND ac.cleared = '1'|;
    }
    if ($form->{outstanding}) {
      $cleared = ($form->{cleared}) ? "" : qq| AND ac.cleared = '0'|;
    }
    if (! $form->{fromdate}) {
      $form->{beginningbalance} = 0;
      $form->{fx_balance} = 0;
    }
  }
  
  
  if ($form->{summary}) {
    $query = qq|SELECT ac.transdate, ac.source,
		sum(ac.amount) AS amount, ac.cleared
		FROM acc_trans ac
		JOIN chart ch ON (ac.chart_id = ch.id)
		WHERE ch.accno = '$form->{accno}'
		AND ac.amount >= 0
		AND ac.fx_transaction = '0'
		$cleared|;
    $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
    $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
    $query .= " GROUP BY ac.source, ac.transdate, ac.cleared";
    $query .= qq|
                UNION
		SELECT ac.transdate, ac.source,
		sum(ac.amount) AS amount, ac.cleared
		FROM acc_trans ac
		JOIN chart ch ON (ac.chart_id = ch.id)
		WHERE ch.accno = '$form->{accno}'
		AND ac.amount < 0
		AND ac.fx_transaction = '0'
		$cleared|;
    $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
    $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
    $query .= " GROUP BY ac.source, ac.transdate, ac.cleared";

    $query .= " ORDER BY 1,2";
    
  } else {
    
    $query = qq|SELECT ac.transdate, ac.source, ac.fx_transaction,
		ac.amount, ac.cleared, g.id, g.description
		FROM acc_trans ac
		JOIN chart ch ON (ac.chart_id = ch.id)
		JOIN gl g ON (g.id = ac.trans_id)
		WHERE ch.accno = '$form->{accno}'
		AND ac.fx_transaction = '0'
		$cleared|;
    $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
    $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
    
    $query .= qq|
                UNION
		SELECT ac.transdate, ac.source, ac.fx_transaction,
		ac.amount, ac.cleared, a.id, n.name
		FROM acc_trans ac
		JOIN chart ch ON (ac.chart_id = ch.id)
		JOIN ar a ON (a.id = ac.trans_id)
		JOIN customer n ON (n.id = a.customer_id)
		WHERE ch.accno = '$form->{accno}'
		AND ac.fx_transaction = '0'
		$cleared|;
    $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
    $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
    
    $query .= qq|
                UNION
		SELECT ac.transdate, ac.source, ac.fx_transaction,
		ac.amount, ac.cleared, a.id, n.name
		FROM acc_trans ac
		JOIN chart ch ON (ac.chart_id = ch.id)
		JOIN ap a ON (a.id = ac.trans_id)
		JOIN vendor n ON (n.id = a.vendor_id)
		WHERE ch.accno = '$form->{accno}'
		AND ac.fx_transaction = '0'
		$cleared|;
    $query .= " AND ac.transdate >= '$form->{fromdate}'" if $form->{fromdate};
    $query .= " AND ac.transdate <= '$form->{todate}'" if $form->{todate};
    
    $query .= " ORDER BY 1,2,3";
  }

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

  my $dr;
  my $cr;
  my $fxs;
  
  if ($form->{summary}) {
    $query = qq|SELECT ac.amount, ac.cleared
		FROM acc_trans ac
		JOIN ar a ON (a.id = ac.trans_id)
		JOIN customer n ON (n.id = a.customer_id)
		WHERE ac.fx_transaction = '1'
		AND n.name = ?
		AND ac.transdate = ?
		AND ac.trans_id IN (SELECT id FROM ar a
				    JOIN acc_trans ac ON (a.id = ac.trans_id)
				    WHERE ac.source = ?)
		AND ac.cleared = ?
		AND NOT
		   (ac.chart_id IN
		    (SELECT fxgain_accno_id FROM defaults
		     UNION
		     SELECT fxloss_accno_id FROM defaults))
		|;
		
    $query .= qq|
		UNION
		SELECT ac.amount, ac.cleared
		FROM acc_trans ac
		JOIN ap a ON (a.id = ac.trans_id)
		JOIN vendor n ON (n.id = a.vendor_id)
		WHERE ac.fx_transaction = '1'
		AND n.name = ?
		AND ac.transdate = ?
		AND ac.trans_id IN (SELECT id FROM ap a
				    JOIN acc_trans ac ON (a.id = ac.trans_id)
				    WHERE ac.source = ?)
		AND ac.cleared = ?
		AND NOT
		   (ac.chart_id IN
		    (SELECT fxgain_accno_id FROM defaults
		     UNION
		     SELECT fxloss_accno_id FROM defaults))
		|;

  } else {

    $query = qq|SELECT ac.amount, ac.cleared
		FROM acc_trans ac
		WHERE ac.trans_id = ?
		AND ac.fx_transaction = '1'
		$cleared
		AND NOT
		   (ac.chart_id IN
		    (SELECT fxgain_accno_id FROM defaults
		     UNION
		     SELECT fxloss_accno_id FROM defaults))
		|;
	
  }

  $fxs = $dbh->prepare($query);


  if ($form->{summary}) {
    $query = qq|SELECT c.name
		FROM customer c
		JOIN ar a ON (c.id = a.customer_id)
		JOIN acc_trans ac ON (a.id = ac.trans_id)
		WHERE ac.transdate = ?
		AND ac.source = ?
		AND ac.amount > 0
		$cleared
	UNION
		SELECT v.name
		FROM vendor v
		JOIN ap a ON (v.id = a.vendor_id)
		JOIN acc_trans ac ON (a.id = ac.trans_id)
		WHERE ac.transdate = ?
		AND ac.source = ?
		AND ac.amount > 0
		$cleared
	UNION
		SELECT g.description
		FROM gl g
		JOIN acc_trans ac ON (g.id = ac.trans_id)
		WHERE ac.transdate = ?
		AND ac.source = ?
		AND ac.amount > 0
		$cleared
		|;
    
    $query .= " ORDER BY 1";
    $dr = $dbh->prepare($query);


    $query = qq|SELECT c.name
		FROM customer c
		JOIN ar a ON (c.id = a.customer_id)
		JOIN acc_trans ac ON (a.id = ac.trans_id)
		WHERE ac.transdate = ?
		AND ac.source = ?
		AND ac.amount < 0
		$cleared
	UNION
		SELECT v.name
		FROM vendor v
		JOIN ap a ON (v.id = a.vendor_id)
		JOIN acc_trans ac ON (a.id = ac.trans_id)
		WHERE ac.transdate = ?
		AND ac.source = ?
		AND ac.amount < 0
		$cleared
	UNION
		SELECT g.description
		FROM gl g
		JOIN acc_trans ac ON (g.id = ac.trans_id)
		WHERE ac.transdate = ?
		AND ac.source = ?
		AND ac.amount < 0
		$cleared
		|;
		
    $query .= " ORDER BY 1";
    $cr = $dbh->prepare($query);
  }
 

  my $name;
  my $ref;
  my $xfref;

  while ($ref = $sth->fetchrow_hashref(NAME_lc)) {

    if ($form->{summary}) {

      if ($ref->{amount} > 0) {
	$dr->execute($ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source});
	$ref->{oldcleared} = $ref->{cleared};
	$ref->{name} = ();
	while (($name) = $dr->fetchrow_array) {
	  push @{ $ref->{name} }, $name;
	}
	$dr->finish;
      } else {
      
	$cr->execute($ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source}, $ref->{transdate}, $ref->{source});
	$ref->{oldcleared} = $ref->{cleared};
	$ref->{name} = ();
	while (($name) = $cr->fetchrow_array) {
	  push @{ $ref->{name} }, $name;
	}
	$cr->finish;
	
      }

    } else {
      push @{ $ref->{name} }, $ref->{description};
    }

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

    # include fx transactions
    $amount = 0;
    $addfx = 0;
    $ref->{oldcleared} = $ref->{cleared};
    if ($form->{summary}) {
      foreach $name (@{ $ref->{name} }) {
	$fxs->execute($name, $ref->{transdate}, $ref->{source}, $ref->{cleared}, $name, $ref->{transdate}, $ref->{source}, $ref->{cleared});
	while ($fxref = $fxs->fetchrow_hashref(NAME_lc)) {
	  $addfx = 1;
	  $amount += $fxref->{amount};
	}
	$fxs->finish;
      }
    } else {
      $fxs->execute($ref->{id});
      while ($fxref = $fxs->fetchrow_hashref(NAME_lc)) {
	$addfx = 1;
	$amount += $fxref->{amount};
      }
      $fxs->finish;
    }
    
    if ($addfx) {
      $fxref = ();
      map { $fxref->{$_} = $ref->{$_} } keys %$ref;
      $fxref->{fx_transaction} = 1;
      $fxref->{name} = ();
      $fxref->{source} = "";
      $fxref->{transdate} = "";
      $fxref->{amount} = $amount;
      push @{ $form->{PR} }, $fxref;
    }
 
  }
  $sth->finish;

  $dbh->disconnect;
  
}


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

  # connect to database
  my $dbh = $form->dbconnect($myconfig);

  my $query = qq|SELECT id FROM chart
                 WHERE accno = '$form->{accno}'|;
  my ($chart_id) = $dbh->selectrow_array($query);
  $chart_id *= 1;
  
  $query = qq|SELECT trans_id FROM acc_trans
              WHERE source = ?
	      AND transdate = ?
	      AND cleared = '0'|;
  my $sth = $dbh->prepare($query) || $form->dberror($query);
    
  my $i;
  my $trans_id;

  $query = qq|UPDATE acc_trans SET cleared = '1'
              WHERE cleared = '0'
	      AND trans_id = ? 
	      AND transdate = ?
	      AND chart_id = $chart_id|;
  my $tth = $dbh->prepare($query) || $form->dberror($query);
  
  # clear flags
  for $i (1 .. $form->{rowcount}) {
    if ($form->{"cleared_$i"} && ! $form->{"oldcleared_$i"}) {
      if ($form->{summary}) {
	$sth->execute($form->{"source_$i"}, $form->{"transdate_$i"}) || $form->dberror;
      
	while (($trans_id) = $sth->fetchrow_array) {
	  $tth->execute($trans_id, $form->{"transdate_$i"}) || $form->dberror;
	  $tth->finish;
	}
	$sth->finish;
	
      } else {

	$tth->execute($form->{"id_$i"}, $form->{"transdate_$i"}) || $form->dberror;
	$tth->finish;
      }
    }
  }

  $dbh->disconnect;

}

1;

