#!/usr/bin/php
<?php
/**
 * phpaga
 *
 * Convert invoices and wuotations from the pre-line items age to the
 * new format.
 *
 * Creates a single line item from the description and start sum of
 * each invoice/quotation.
 *
 * WARNNING
 *
 * BACKUP YOUR DATA BEFORE RUNNING THIS SCRIPT
 *
 * MAKE SURE YOU RUN THIS ONLY BEFORE CREATING NEW INVOICES/QUOTATIONS
 * WITH PHPAGA 0.3. THIS SCRIPT WILL MESS UP ANY INVOICES/QUOTATIONS
 * CREATED WITH PHPAGA 0.3 OR GREATER.
 *
 * END WARNING
 *
 * @author Florian Lanthaler <florian@phpaga.net>
 * @version $Id: convert_invoices.php 524 2005-05-08 13:09:12Z worf $
 *
 * Copyright (c) 2005 Florian Lanthaler <florian@phpaga.net>
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *    * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in
 *      the documentation and/or other materials provided with the
 *      distribution.
 *
 *    * Neither the name of Florian Lanthaler nor the names of his
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* Database system; currently supported values are
 *	pgsql : PostgreSQL
 *	mysql : MySQL
 */
define('PHPAGA_DB_SYSTEM', 'pgsql');

/* Name or IP address of the host the database server is running on */
define('PHPAGA_DB_HOST', '');

/* Database name */
define('PHPAGA_DB_NAME', 'dbname');

/* Database username */
define('PHPAGA_DB_LOGIN', 'dbuser');

/* Database password */
define('PHPAGA_DB_PASSWD', 'dbpasswd');

/* Should the total duration of the linked tasks be used for the
 * qty/hours field on the generated line item?
 *   true:  use total duration
 *   false: leave emtpy
 */
define('PUT_SUM_HOURS_INTO_LIT_QTY', true);


/* -------------------------------------------------- */
/* No neeed to touch anything below
/* -------------------------------------------------- */

function _msg($text = null, $err = false)
{
    if ($err)
        $pref = "ERROR: ";
    else
        $pref = "";

    print(sprintf("-> %s%s\n", $pref, $text));
}


include("DB.php");

$db = DB::connect(sprintf("%s://%s:%s@%s/%s",
                          PHPAGA_DB_SYSTEM,
                          PHPAGA_DB_LOGIN,
                          PHPAGA_DB_PASSWD,
                          PHPAGA_DB_HOST,
                          PHPAGA_DB_NAME));

if (DB::isError($db))
{
    die(sprintf("Unable to connect to the database:\n%s\n", $db->getDebugInfo()));
}

 _msg("Connected");

$db->setFetchMode(DB_FETCHMODE_ASSOC);

/* First the invoices */

$result = $db->query("SELECT bill_id, bill_date, bill_number, bill_desc, bill_startsum FROM bills");

if (DB::isError($result))
{
    die(_msg(sprintf("Unable to fetch invoices:\n%s", $result->getDebugInfo()), true));

}

if (PHPAGA_DB_SYSTEM == "pgsql")
{
    $db->query("BEGIN TRANSACTION");
}

$status = true;

while (($r = $result->fetchRow()) && $status)
{
    _msg(sprintf("Converting invoice: %s / %s", $r["bill_number"], $r["bill_date"]));

    $qty = null;

    if (PUT_SUM_HOURS_INTO_LIT_QTY)
    {
        $qh = $db->query("SELECT SUM(op_duration) AS duration ".
                         "FROM operations ".
                         "WHERE bill_id = ".$db->quoteSmart($r["bill_id"]));

        if (DB::isError($qh))
        {
            $status = false;
            _msg(sprintf("Unable to fetch hours for invoice %s / %s:\n%s",
                         $r["bill_number"],
                         $r["bill_date"],
                         $qh->getDebugInfo()), true);

            break;
        }

        if ($drec = $qh->fetchRow()) {
            $qty = $drec["duration"];
            if (is_numeric($qty))
                $qty = (floor($qty / 60).":".sprintf("%02d", ($qty % 60)));
        }
    }


    /* delete existing line items - you don't want to double your line
     * items if you accidentally run this script twice */

    $qd = $db->query("DELETE FROM lineitems WHERE bill_id = ".$db->quoteSmart($r["bill_id"]));

    if (DB::isError($qd))
    {
        $status = false;
        _msg(sprintf("Unable to delete line items:\n%s", $qd->getDebugInfo()), true);
        break;
    }

    $fields = array("lit_id" => $db->nextId("lineitems_lit_id"),
                    "bill_id" => $r["bill_id"],
                    "lit_desc" => $r["bill_desc"],
                    "lit_qty" => $qty,
                    "lit_netprice" => $r["bill_startsum"]);

    $qi = $db->autoExecute("lineitems", $fields, DB_AUTOQUERY_INSERT);

    if (DB::isError($qi))
    {
        $status = false;
        _msg(sprintf("Unable to insert line item for invoice %s / %s:\n%s",
                     $r["bill_number"],
                     $r["bill_date"],
                     $qi->getDebugInfo()), true);
        break;
    }

}

if (!$status) {
    _msg("Conversion aborted", true);
}

if (PHPAGA_DB_SYSTEM == "pgsql") {
    if ($status)
        $db->query("COMMIT TRANSACTION");
    else
    {
        $roll = $db->query("ROLLBACK");

        if (DB::isError($roll)) {
            _msg("Ugh - unable to ROLLBACK the transaction, this looks ugly. I go hide.", true);
        }
        else {
            _msg("ROLLBACK successful");
        }
    }
}

/* Now the quotations */

$result = $db->query("SELECT quot_id, quot_date, quot_number, quot_desc, quot_startsum FROM quotations");

if (DB::isError($result))
{
    die(_msg(sprintf("Unable to fetch quotations:\n%s", $result->getDebugInfo()), true));

}

if (PHPAGA_DB_SYSTEM == "pgsql")
{
    $db->query("BEGIN TRANSACTION");
}

$status = true;

while (($r = $result->fetchRow()) && $status)
{
    _msg(sprintf("Converting quotation: %s / %s", $r["quot_number"], $r["quot_date"]));

    /* delete existing line items - you don't want to double your line
     * items if you accidentally run this script twice */

    $qd = $db->query("DELETE FROM lineitems WHERE quot_id = ".$db->quoteSmart($r["quot_id"]));

    if (DB::isError($qd))
    {
        $status = false;
        _msg(sprintf("Unable to delete line items:\n%s", $qd->getDebugInfo()), true);
        break;
    }

    $fields = array("lit_id" => $db->nextId("lineitems_lit_id"),
                    "quot_id" => $r["quot_id"],
                    "lit_desc" => $r["quot_desc"],
                    "lit_qty" => null,
                    "lit_netprice" => $r["quot_startsum"]);

    $qi = $db->autoExecute("lineitems", $fields, DB_AUTOQUERY_INSERT);

    if (DB::isError($qi))
    {
        $status = false;
        _msg(sprintf("Unable to insert line item for quotation %s / %s:\n%s",
                     $r["quot_number"],
                     $r["quot_date"],
                     $qi->getDebugInfo()), true);
        break;
    }

}

if (!$status) {
    _msg("Conversion aborted", true);
}

if (PHPAGA_DB_SYSTEM == "pgsql") {
    if ($status)
        $db->query("COMMIT TRANSACTION");
    else
    {
        $roll = $db->query("ROLLBACK");

        if (DB::isError($roll)) {
            _msg("Ugh - unable to ROLLBACK the transaction, this looks ugly. I go hide.", true);
        }
        else {
            _msg("ROLLBACK successful");
        }
    }
}

if ($status) {
    _msg("Done");
}

?>
