<?php
/*
 * osBilling - Open Billing Software
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 *
 * Originally authored by Deon George
 *
 * @author Deon George <deonATleenooksDOTnet>
 * @copyright 2009 Deon George
 * @link http://osb.leenooks.net
 * @license http://www.gnu.org/licenses/
 * @package AgileBill
 * @subpackage Import
 */

DEFINE('WHMCS_DIR','/var/www/whmcs/');
include_once WHMCS_DIR.'includes/functions.php';

/**
 * WHMCS import module
 *
 * @package AgileBill
 * @subpackage Import
 */
class import_plugin extends import {
	private $encryption_key;

	public function __construct() {
		# Configure the database name, host, and login:
		$this->host	= 'localhost';
		$this->db	= '';
		$this->user = '';
		$this->pass = '';
		$this->type	= 'mysql';

		# If importing CC details, enter the gateway plugin to use for recurring charges:
		$this->gateway = 'AUTHORIZE_NET';

		# Do not change anything past this line:
		$this->name = 'WHMCS';
		$this->plugin = 'WHMCS';
		$this->select_limit	= 50;

		$this->instructions = '
<b>Preliminary Instructions:</b><br/><br/>
<ol>
<li>Open '. __FILE__ .' and edit the database settings, and the location to your WHMCS_DIR...</li>
<li>If you will be importing credit card details, paste the Checkout Plugin name from the checkout plugin list page to the "$this->gateway" value
that will be used to process all recurring charges...  this should be a gateway such as AUTHORIZE_NET or LINKPOINT.</li>
<li>Make sure you have your TLD configurations set, before importing domains.</li>
<li>HINT: Before importing products, ensure that you have configured your map file, this will set the SKU, and will save you changing this data if you need to undo and re-import.</li>
</ol>';

		array_push($this->actions,array(
			'name' => 'test',
			'desc' => '<b>Step 1:</b> Test the database connection',
			'depn' => false
		));

		array_push($this->actions,array(
			'name' => 'product_cat',
			'desc' => '<b>Step 2:</b> Import the Product Categories',
			'depn' => array('test')
		));

		array_push($this->actions,array(
			'name' => 'products',
			'desc' => '<b>Step 3:</b> Import the Products',
			'depn' => array('test','product_cat')
		));

		array_push($this->actions,array(
			'name' => 'accounts',
			'desc' => '<b>Step 4:</b> Import the Accounts',
			'depn' => array('test')
		));

		array_push($this->actions,array(
			'name' => 'pre_services',
			'desc' => '<b>Step 5:</b> Edit the Products (update the SKU details if necessary) then click Ready',
			'depn' => array('products')
		));

		array_push($this->actions,array(
			'name' => 'services',
			'desc' => '<b>Step 6:</b> Import the Services',
			'depn' => array('pre_services','accounts')
		));

		array_push($this->actions,array(
			'name' => 'pre_tld',
			'desc' => '<b>Step 7:</b> Set up your TLD then click Ready',
			'depn' => array('test')
		));

		array_push($this->actions,array(
			'name' => 'domains',
			'desc' => '<b>Step 8:</b> Import the Domains',
			'depn' => array('pre_tld','accounts')
		));

		array_push($this->actions,array(
			'name' => 'invoices',
			'desc' => '<b>Step 9:</b> Import the Invoices',
			'depn' => array('services','accounts')
		));

		array_push($this->actions,array(
			'name' => 'invoice_items',
			'desc' => '<b>Step 10:</b> Import the Invoices Items',
			'depn' => array('invoices')
		));

		array_push($this->actions,array(
			'name' => 'payments',
			'desc' => '<b>Step 11:</b> Import the Payments',
			'depn' => array('invoices')
		));
	}

	protected function pre_services() {
		$this->pre_test();
	}

	protected function pre_tld() {
		$this->pre_test();
	}

	/**
	 * Product Categories
	 */
	protected function product_cat() {
		global $VAR,$C_debug;

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tblproductgroups';
		$ab_table = 'product_cat';

		# Select
		$sql = sprintf('SELECT * FROM %s',$remote_table);
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		$map = array();
		$map['name'] = 'name';
		$map['position'] = 'order';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['name']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			$update['parent_id'] = 0;
			$update['group_avail'] = serialize(array('0'=>'0'));
			$update['template'] = 'Paged Listing';
			$update['notes'] = 'Imported from WHMCS';
			$update['thumbnail'] = '';
			$update['image'] = '';
			$update['max'] = '10';

			if ($rs->fields['hidden'] == 'on')
				$update['status'] = 0;
			else
				$update['status'] = 1;

			# Import the item
			$db->Execute(sqlInsert($db,$ab_table,$update));
			$id = $db->Execute(sqlSelect($db,$ab_table,'id',$update,'','0,1'));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id->fields['id'],$remote_table,$rs->fields['id'],$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}

	/**
	 * Products
	 */
	protected function products() {
		global $VAR,$C_debug;

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tblproducts';
		$ab_table = 'product';

		# Select
		$sql = sprintf('SELECT * FROM %s',$remote_table);
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		# Load Categories Imported
		$db = &DB();
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s::',$this->plugin,'product_cat')));
		while (! $imprs->EOF) {
			$cat[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		# If there is a map file, open it
		$pmap = $this->read_map();

		# Table mapping
		$map = array();
		$map['price_setup'] = 'msetupfee';
		$map['price_base'] = 'monthly';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['name']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			$update['date_last'] = time();
			$update['sku'] = sprintf('IMPORT-%s',$rs->fields['id']);
			$update['taxable'] = 1;
			$update['group_avail'] = serialize(array('0'=>'0'));
			$update['avail_category_id'] = serialize(array('0'=>$cat[$rs->fields['gid']]));
			$update['price_type'] = 1;
			$update['price_recurr_default'] = 1;
			$update['price_recurr_weekday'] = 1;
			$update['price_recurr_week'] = 1;
			$update['price_recurr_schedule'] = 0;
			$update['price_recurr_type'] = 1;

			if ($rs->fields['hidden'] == 'on')
				$update['active'] = 0;
			else
				$update['active'] = 1;

			# Pricing
			$pricing = array();
			# * Weekly
			$pricing[0]['show'] = '0';
			$pricing[0][0]['price_base'] = '0';
			$pricing[0][0]['price_setup'] = '0';
			# * Monthly
			$pricing[1]['show'] = $rs->fields['monthly'] > 0 ? '1' : '0';
			$pricing[1][0]['price_base'] = $rs->fields['monthly'];
			$pricing[1][0]['price_setup'] = $rs->fields['msetupfee'];
			# * Quarterly
			$pricing[2]['show'] = $rs->fields['quarterly'] > 0 ? '1' : '0';
			$pricing[2][0]['price_base'] = $rs->fields['quarterly'];
			$pricing[2][0]['price_setup'] = $rs->fields['qsetupfee'];
			# * 6 Months
			$pricing[3]['show'] = $rs->fields['semiannual'] > 0 ? '1' : '0';
			$pricing[3][0]['price_base'] = $rs->fields['semiannual'];
			$pricing[3][0]['price_setup'] = $rs->fields['ssetupfee'];
			# * 12 Months
			$pricing[4]['show'] = $rs->fields['annual'] > 0 ? '1' : '0';
			$pricing[4][0]['price_base'] = $rs->fields['annual'];
			$pricing[4][0]['price_setup'] = $rs->fields['asetupfee'];
			# * 24 Months
			$pricing[5]['show'] = $rs->fields['biennial'] > 0 ? '1' : '0';
			$pricing[5][0]['price_base'] = $rs->fields['biennial'];
			$pricing[5][0]['price_setup'] = $rs->fields['bsetupfee'];
			# * 36 Months
			$pricing[6]['show'] = '0';
			$pricing[6][0]['price_base'] = '0';
			$pricing[6][0]['price_setup'] = '0';

			$update['price_group'] = serialize($pricing);

			# Get the fixed items in the map table.
			if (isset($pmap[$ab_table][$rs->fields['id']*1]))
				foreach ($pmap[$ab_table][$rs->fields['id']*1] as $field => $value)
					$update[$field] = $value;

			# Import the item
			$db->Execute(sqlInsert($db,$ab_table,$update));
			$id = $db->Execute(sqlSelect($db,$ab_table,'id',$update,'','0,1'));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id->fields['id'],$remote_table,$rs->fields['id'],$db);

			# Add translations
			$submap = array();
			$submap['name'] = 'name';
			$submap['description_short'] = 'name';
			$submap['description_full'] = 'description';

			$update = array();
			foreach ($submap as $a => $b)
				$update[$a] = $rs->fields[$b];

			$update['language_id'] = DEFAULT_LANGUAGE;
			$update['product_id'] = $id->fields['id'];

			# @todo For some reason sqlInsert() generates an error, so we need to produce the SQL and run it normally
			$update['site_id'] = DEFAULT_SITE;
			# @todo It seems translations are referenced by 'id', rather than 'product_id'
			$update['id'] = $id->fields['id'];
			$sql = sprintf("INSERT INTO %s (%s) VALUES ('%s')",AGILE_DB_PREFIX.'product_translate',implode(',',array_keys($update)),implode("','",$update));
			$pdrs = $db->Execute($sql);
			if (! $pdrs && $db->_errorMsg) {
				printf("<pre>* %s\n%s</pre>",$db->_errorMsg,$sql);
			}

			$this->import_transaction($this->plugin,$VAR['action'],'product_translate',$update['id'],'',$rs->fields['id'],$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}

	/**
	 * Accounts
	 */
	protected function accounts() {
		global $VAR,$C_debug;

		# Files to your WHMCS installation (required to decrypt encrypted fields)
		include_once WHMCS_DIR.'dbconnect.php';

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tblclients';
		$ab_table = 'account';

		# Select
		$sql = sprintf('SELECT * FROM %s',$remote_table);
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		$map = array();
		$map['username'] = 'email';
		#$map['email'] = 'email';
		$map['first_name'] = 'firstname';
		$map['last_name'] = 'lastname';
		$map['company'] = 'companyname';
		$map['address1'] = 'address1';
		$map['address2'] = 'address2';
		$map['city'] = 'city';
		$map['state'] = 'state';
		$map['zip'] = 'postcode';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['email']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			$update['date_orig'] = time();
			$update['date_last'] = time();
			$update['language_id'] = DEFAULT_LANGUAGE;
			# @todo Work out currency based on country address
			$update['country_id'] = '36';
			$update['currency_id'] = '6';
			$update['theme_id'] = DEFAULT_THEME;
			$update['email_type'] = '1';
			$update['invoice_delivery'] = '1';
			$update['invoice_show_itemized'] = '1';
			$update['invoice_grace'] = '0';
			$update['invoice_advance_gen'] = '0';

			if ($rs->fields['status'] == 'Active')
				$update['status'] = 1;
			else
				$update['status'] = 0;

			$update['password'] = md5(decrypt($rs->fields['password'],$encryption_key));

			# Import the item
			$db->Execute(sqlInsert($db,$ab_table,$update));
			$id = $db->Execute(sqlSelect($db,$ab_table,'id',$update,'','0,1'));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id->fields['id'],$remote_table,$rs->fields['id'],$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}

	/**
	 * Services
	 */
	protected function services() {
		global $VAR,$C_debug;

		# Files to your WHMCS installation (required to decrypt encrypted fields)
		include_once WHMCS_DIR.'dbconnect.php';

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tblhosting';
		$ab_table = 'service';

		# Select
		$sql = '
SELECT tblhosting.id as id, userid, packageid, domainstatus, domain, amount, regdate, lastupdate, billingcycle, username, password, nextinvoicedate, tblproducts.name as product
FROM tblhosting,tblproducts where tblhosting.packageid=tblproducts.id';
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		$db = &DB();

		# Load Products Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'products','tblproducts')));
		while (! $imprs->EOF) {
			$prod[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		# Load Accounts Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'accounts','tblclients')));
		while (! $imprs->EOF) {
			$account[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		$map = array();
		# @todo This amount includes tax, and needs to exclude it.
		$map['price'] = 'amount';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['id']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			# @todo This amount includes tax, and needs to work out tax.
			$update['price'] = sprintf('%3.2f',$update['price']/11*10);

			if (preg_match('/^ADSL/',$rs->fields['product'])) {
				$update['prod_plugin_name'] = 'ADSL';
				$update['type'] = 'product';

				$sql = sprintf("SELECT fieldname,value FROM tblcustomfieldsvalues,tblcustomfields WHERE tblcustomfieldsvalues.fieldid=tblcustomfields.id AND tblcustomfieldsvalues.relid=%s AND tblcustomfields.relid=%s AND type='product'",$rs->fields['id'],$rs->fields['packageid']);

				$plugin = array();
				$update['prod_attr'] = '';

				# Connect to the remote DB
				$dbr = NewADOConnection($this->type);
				$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

				$adsl = $dbr->Execute($sql);

				if ($adsl && $adsl->RecordCount()) {
					while (! $adsl->EOF) {
						if (trim($adsl->fields['value'])) {
							$plugin[$adsl->fields['fieldname']] = $adsl->fields['value'];
							$update['prod_attr'] .= sprintf("%s==%s\r\n",$adsl->fields['fieldname'],$adsl->fields['value']);
							$update['host_username'] = $rs->fields['username'];
							$update['host_password'] = decrypt($rs->fields['password'],$encryption_key);
						}

						$adsl->MoveNext();
					}

					$update['prod_plugin_data'] = serialize($plugin);
				}

			} elseif ($rs->fields['domain']) {
				$update['type'] = 'host';
				$update['domain_name'] = $rs->fields['domain'];
				$update['host_username'] = $rs->fields['username'];
				$update['host_password'] = decrypt($rs->fields['password'],$encryption_key);
			}

			# Strip the leading zeros
			$rs->fields['packageid'] *= 1;
			$rs->fields['userid'] *= 1;
			$update['product_id'] = $prod[$rs->fields['packageid']];
			$update['account_id'] = $account[$rs->fields['userid']];

			$db = &DB();
			$sku = $db->Execute(sqlSelect($db,'product','sku',sprintf('id=%s',$update['product_id']),'','0,1'));
			$update['sku'] = $sku->fields['sku'];

			if ($rs->fields['domainstatus'] == 'Active')
				$update['active'] = 1;
			else
				$update['active'] = 0;

			$update['taxable'] = 1;
			$update['recur_schedule_change'] = 0;
			$update['suspend_billing'] = 0;
			$update['recur_cancel'] = 0;
			$update['recur_modify'] = 0;

			switch ($rs->fields['billingcycle']) {
				case 'Annually':
					$update['recur_schedule'] = 4; //monthly
					$update['recur_type'] = 0;

					break;

				case 'Monthly':
					$update['recur_schedule'] = 1; //monthly
					$update['recur_type'] = 1;
					$update['recur_type'] = 1;
					$update['recur_weekday'] = 1;

					break;

				case 'Quarterly':
					$update['recur_schedule'] = 2; //quarterly
					$update['recur_type'] = 1;
					$update['recur_weekday'] = 1;

					break;

				case 'Biennially':
					$update['recur_schedule'] = 5; //two-years
					$update['recur_type'] = 0;

					break;

				default:
					$update['recur_schedule'] = 0; //free?
					$update['recur_type'] = 0;
			};

			$update['date_next_invoice'] = strtotime($rs->fields['nextinvoicedate']);
			$update['date_orig'] = strtotime($rs->fields['regdate']);
			$update['date_last'] = strtotime($rs->fields['lastupdate']);

			# Import the item
			$db->Execute(sqlInsert($db,$ab_table,$update));
			$id = $db->Execute(sqlSelect($db,$ab_table,'id',$update,'','0,1'));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id->fields['id'],$remote_table,$rs->fields['id'],$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}

	/**
	 * Domains
	 */
	protected function domains() {
		global $VAR,$C_debug;

		# Files to your WHMCS installation (required to decrypt encrypted fields)
		include_once WHMCS_DIR.'dbconnect.php';

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tbldomains';
		$ab_table = 'service';

		# Select
		$sql = sprintf('SELECT * FROM %s',$remote_table);
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		$db = &DB();

		# Load Accounts Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'accounts','tblclients')));
		while (! $imprs->EOF) {
			$account[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		$map = array();
		$map['domain_term'] = 'registrationperiod';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['domain']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			# @todo Determine price from register details
			$update['price'] = 45*$update['domain_term'];

			$update['type'] = 'domain';
			$update['sku'] = 'DOMAIN-RENEW';

			# Strip the leading zeros
			$rs->fields['userid'] *= 1;
			$update['account_id'] = $account[$rs->fields['userid']];

			if ($rs->fields['status'] == 'Active')
				$update['active'] = 1;
			else
				$update['active'] = 0;

			$update['price_type'] = 0;
			$update['taxable'] = 1;
			$update['domain_date_expire'] = strtotime($rs->fields['expirydate']);

			switch ($rs->fields['type']) {
				case 'Register':
				default:
					$update['domain_type'] = 'register';
					break;
			}

			$update['date_next_invoice'] = strtotime($rs->fields['nextinvoicedate']);
			$update['date_orig'] = strtotime($rs->fields['registrationdate']);
			$update['date_last'] = time();

			# Work out TLD and REGISTER PLUGIN
			$arr = explode('.',strtolower($rs->fields['domain']));
			$update['domain_tld'] = '';
			$update['domain_name'] = $arr[0];

			for ($i=1; $i<count($arr); $i++)
				$update['domain_tld'] .= sprintf('.%s',$arr[$i]);

			# Chop off the initial .
			$update['domain_tld'] = preg_replace('/^\./','',$update['domain_tld']);

			# Determine the tld_id
			$tldrs = $db->Execute(sqlSelect($db,'host_tld','id,registrar_plugin_id',sprintf('name=::%s::',$update['domain_tld'])));
			$update['domain_host_tld_id'] = $tldrs->fields['id'];
			$update['domain_host_registrar_id'] = $tldrs->fields['registrar_plugin_id'];

			# Import the item
			$db->Execute(sqlInsert($db,$ab_table,$update));
			$id = $db->Execute(sqlSelect($db,$ab_table,'id',$update,'','0,1'));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id->fields['id'],$remote_table,$rs->fields['id'],$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}

	/**
	 * Invoices
	 */
	protected function invoices() {
		global $VAR,$C_debug;

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tblinvoices';
		$ab_table = 'invoice';

		# Select
		$sql = sprintf('SELECT * FROM %s',$remote_table);
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		$db = &DB();

		# Load Accounts Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'accounts','tblclients')));
		while (! $imprs->EOF) {
			$account[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		$map = array();
		# Our invoice ID should be preserved
		$map['tax_amt'] = 'tax';
		$map['total_amt'] = 'total';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['id']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			# Strip the leading zeros
			$rs->fields['userid'] *= 1;
			$update['account_id'] = $account[$rs->fields['userid']];

			# @todo Might be nice to automatically work out the currency
			$update['billed_currency_id'] = 6;
			$update['actual_billed_currency_id'] = 6;
			$update['type'] = 1;

			$update['date_orig'] = strtotime($rs->fields['date']);
			$update['due_date'] = strtotime($rs->fields['duedate']);
			$update['refund_status'] = 0;

			$update['total_amt'] += $rs->fields['credit'];
			switch ($rs->fields['status']) {
				case 'Unpaid':
					$update['billed_amt'] = 0;
					$update['process_status'] = 1;
					$update['billing_status'] = 0;
					$update['status'] = 1;

					break;

				case 'Paid':
					$update['billed_amt'] = $rs->fields['total']+$rs->fields['credit'];
					$update['process_status'] = 1;
					$update['billing_status'] = 1;
					$update['status'] = 1;

					break;

				case 'Cancelled':
					$update['billed_amt'] = 0;
					$update['process_status'] = 0;
					$update['billing_status'] = 0;
					$update['status'] = 0;

					break;
			}

			# Import the item
			$db->Execute(sqlInsert($db,$ab_table,$update,$rs->fields['id']));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$rs->fields['id'],$remote_table,$rs->fields['id'],$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}

	/**
	 * Invoice Items
	 */
	protected function invoice_items() {
		global $VAR,$C_debug;

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tblinvoiceitems';
		$ab_table = 'invoice_item';

		# Select
		$sql = sprintf('SELECT * FROM %s',$remote_table);
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		$db = &DB();

		# Load Products Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'services','tblhosting')));
		while (! $imprs->EOF) {
			$service[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		# Load Accounts Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'accounts','tblclients')));
		while (! $imprs->EOF) {
			$account[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		# Load Domains Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'domains','tbldomains')));
		while (! $imprs->EOF) {
			$domain[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		# Load Products Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'products','tblproducts')));
		while (! $imprs->EOF) {
			$prod[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		$map = array();
		# Our invoice ID should be preserved
		$map['invoice_id'] = 'invoiceid';
		$map['product_name'] = 'description';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['id']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			# Strip the leading zeros
			$rs->fields['relid'] *= 1;
			$rs->fields['userid'] *= 1;

			$update['account_id'] = $account[$rs->fields['userid']];
			$update['item_type'] = 3;
			$update['price_type'] = 0;

			$product = '';
			switch ($rs->fields['type']) {
				case 'Addon':
					break;

				case 'Domain':
					if (isset($domain[$rs->fields['relid']]))
						$update['service_id'] = $domain[$rs->fields['relid']];

					$update['sku'] = 'DOMAIN-REGISTER';
					break;


				default:
					if (isset($service[$rs->fields['relid']]))
						$update['service_id'] = $service[$rs->fields['relid']];

					# Get the Product
					$dbr = &NewADOConnection($this->type);
					$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

					$tldrs = $dbr->Execute(sprintf('SELECT packageid FROM tblhosting WHERE id=%s',$rs->fields['relid']));
					if (isset($tldrs->fields['packageid'])) {
						$tldrs->fields['packageid'] *= 1;
						$update['product_id'] = $prod[$tldrs->fields['packageid']];

						$db = &DB();
						$sku = $db->Execute(sqlSelect($db,'product','sku',sprintf('id=%s',$update['product_id']),'','0,1'));
						$update['sku'] = $sku->fields['sku'];

						$prod_name = $dbr->Execute(sprintf('SELECT name,paytype from tblproducts WHERE id=%s',$tldrs->fields['packageid']));
						$product = $prod_name->fields['name'];

						if ($prod_name->fields['paytype'] == 'recurring') {
							$update['price_type'] = 1;
							$update['item_type'] = 0;
						}
					}
			}

			# Detect the dates and domain from the product_name
			if ($update['product_name']) {
				# Chop of the dates.
				$reg = '/\s+\(([0-9]+\/[0-9]+\/[0-9]+)\s+-\s+([0-9]+\/[0-9]+\/[0-9]+)\)$/';

				$matches = array();
				if (preg_match($reg,$update['product_name'],$matches)) {
					$update['date_start'] = strtotime(str_replace('/','-',$matches[1]));
					$update['date_stop'] = strtotime(str_replace('/','-',$matches[2]));
					$update['product_name'] = str_replace($matches[0],'',$update['product_name']);

					# Find the domain portion
					if (isset($product) && $product) {
						$product_reg = str_replace('/','\/',$product);
						if (preg_match("/^{$product_reg}\s+/",$update['product_name'])) {
							$aaa = preg_replace("/^{$product_reg}\s+-\s+/",'',$update['product_name']);

							if ($update['product_name'] != $product) {
								$update['domain_name'] = $aaa;
								$update['product_name'] = preg_replace("/\s+-\s+{$aaa}/",'',$update['product_name']);
							}
						}
					}
				}
			}

			$update['quantity'] = 1;
			$update['tax_amt'] = sprintf('%3.2f',$rs->fields['amount']/11);
			$update['total_amt'] = $rs->fields['amount']-$update['tax_amt'];
			$update['price_base'] = $rs->fields['amount']-$update['tax_amt'];

			# Import the item
			$db = &DB();
			$id = sqlGenID($db,$ab_table);
			$result = $db->Execute(sqlInsert($db,$ab_table,$update,$id));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id,$remote_table,$rs->fields['id'],$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}

	/**
	 * Payments
	 */
	protected function payments() {
		global $VAR,$C_debug;

		# Connect to the remote DB
		$dbr = &NewADOConnection($this->type);
		$dbr->Connect($this->host,$this->user,$this->pass,$this->db);

		# Determine the offset for the account
		if (empty($VAR['offset']))
			$VAR['offset'] = 0;

		$offset = sprintf('%s,%s',$VAR['offset'],$this->select_limit);
		$remote_table = 'tblaccounts';
		$ab_table = 'payment';

		# Select
		$sql = sprintf('SELECT * FROM %s',$remote_table);
		$rs = $dbr->SelectLimit($sql,$this->select_limit,$offset);

		if ($rs === false) {
			$C_debug->alert(sprintf('Query to the table "%s" failed!',$remote_table));

			return false;
		}

		if ($rs->RecordCount() == 0) {
			$C_debug->alert('No more records to process!');
			printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=import:import&plugin=%s\'',1500);</script>",$VAR['plugin']);

			return;
		}

		# Load Checkout Plugins
		$db = &DB();
		$imprs = $db->Execute(sqlSelect($db,'checkout','id,checkout_plugin',''));
		while (! $imprs->EOF) {
			$co[$imprs->fields['checkout_plugin']] = $imprs->fields['id'];
			$imprs->MoveNext();
		}

		# Load Accounts Imported
		$imprs = $db->Execute(sqlSelect($db,'import','ab_id,remote_id',sprintf('plugin=::%s:: AND action=::%s:: AND remote_table=::%s::',$this->plugin,'accounts','tblclients')));
		while (! $imprs->EOF) {
			$account[$imprs->fields['remote_id']] = $imprs->fields['ab_id'];
			$imprs->MoveNext();
		}

		$msg = sprintf('Processing %s Records...<br/>',$rs->RecordCount());

		# If there is a map file, open it
		$pmap = $this->read_map();

		# Table mapping
		$map = array();
		$map['notes'] = 'description';
		$map['total_amt'] = 'amountin';
		$map['fees_amt'] = 'fees';

		# Loop through each remote item
		while (! $rs->EOF) {
			$msg .= sprintf('<br/>Processing : %s...',$rs->fields['invoiceid']);

			# Start a new transaction for the insert:
			$db = &DB();
			$db->StartTrans();

			$update = array();
			foreach ($map as $a => $b)
				$update[$a] = $rs->fields[$b];

			$update['account_id'] = $account[$rs->fields['userid']*1];
			$update['checkout_plugin_id'] = $account[$rs->fields['userid']*1];
			$update['date_payment'] = strtotime($rs->fields['date']);
			$update['date_orig'] = strtotime($rs->fields['date']);
			if ($rs->fields['transid'])
				$update['checkout_plugin_data'] = serialize(array('transid'=>$rs->fields['transid']));
			# Get the fixed items in the map table.
			if (isset($pmap[$ab_table][$rs->fields['gateway']])) {
				foreach ($pmap[$ab_table][$rs->fields['gateway']] as $field => $value) {
					if (isset($co[$value]))
						$update[$field] = $co[$value];
					else {
						$update[$field] = sprintf('NOMAP-%s',$rs->fields['gateway']);
					}
				}
			}

			# Import the item
			$db->Execute($r=sqlInsert($db,$ab_table,$update));
			$id = $db->Execute($q=sqlSelect($db,$ab_table,'id',$update,'','0,1'));

			# Insert the import record
			$this->import_transaction($this->plugin,$VAR['action'],$ab_table,$id->fields['id'],$remote_table,$rs->fields['id'],$db);

			$update = array();
			$update['date_orig'] = strtotime($rs->fields['date']);
			$update['payment_id'] = $id->fields['id'];
			$update['invoice_id'] = $rs->fields['invoiceid'];
			$update['alloc_amt'] = $rs->fields['amountin'];

			$db->Execute($r=sqlInsert($db,'payment_item',$update));
			$pi = $db->Execute($q=sqlSelect($db,'payment_item','id',$update,'','0,1'));

			$this->import_transaction($this->plugin,$VAR['action'],'payment_item',$pi->fields['id'],'',null,$db);

			# Complete the transaction
			$db->CompleteTrans();
			$rs->MoveNext();
		}

		$C_debug->alert($msg);

		printf("<script type='text/javascript' language=javascript>setTimeout('document.location=\'?_page=core:blank&offset=%s&action=%s&plugin=%s&do[]=import:do_action\'', 1200);</script>",
			$VAR['offset']+$this->select_limit,$VAR['action'],$VAR['plugin']);
	}
}
?>