This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
khosb/modules/invoice/invoice.inc.php

4048 lines
134 KiB
PHP
Raw Normal View History

<?php
/**
* AgileBill - Open Billing Software
*
* This body of work is free software; you can redistribute it and/or
* modify it under the terms of the Open AgileBill License
* License as published at http://www.agileco.com/agilebill/license1-4.txt
2009-08-03 04:10:16 +00:00
*
* Originally authored by Tony Landis, AgileBill LLC
*
* Recent modifications by Deon George
*
* @author Deon George <deonATleenooksDOTnet>
* @copyright 2009 Deon George
* @link http://osb.leenooks.net
*
* @link http://www.agileco.com/
* @copyright 2004-2008 Agileco, LLC.
* @license http://www.agileco.com/agilebill/license1-4.txt
2009-08-03 04:10:16 +00:00
* @author Tony Landis <tony@agileco.com>
* @package AgileBill
2009-08-03 04:10:16 +00:00
* @subpackage Modules:Invoice
*/
2009-08-03 04:10:16 +00:00
/**
2009-08-03 04:10:16 +00:00
* The main AgileBill Invoice Class
*
* @package AgileBill
* @subpackage Modules:Invoice
*/
2009-08-03 04:10:16 +00:00
class invoice extends OSB_module {
# Array holding all our print information
public $print = array();
# Enable summary invoice view that rolls multiple instances of the same sku w/identical base&setup price & attributes into one line item
private $summarizeInvoice = true;
# Holds sku's of line items to exclude from invoice summarys (pdf view only)
# @todo not implemented
private $summarizeInvoiceExclude = array();
/** Invoice type, 0=new, 1=recurr */
var $type=0;
2009-08-03 04:10:16 +00:00
# Invoice Creation Timestamp
private $date_orig;
# Last modification Timestamp
private $date_last;
# Invoice Id
# @todo change to invoice_id?
public $record_id;
/** Invoice Item Id */
2009-08-03 04:10:16 +00:00
private $item_id=0;
# Parent Invoice Id for recurring
public $parent_id;
# Account Id for invoice
public $account_id;
# Affiliate Id of Invoice
public $affiliate_id;
# Account Billing Id
public $account_billing_id;
# Campaign Id
public $campaign_id;
# Reseller Id
public $reseller_id;
# Billed Currency Id
public $billed_currency_id;
# Actual Billed Currency selected by Client
public $actual_billed_currency_id;
# Checkout Plugin Id
public $checkout_plugin_id;
# array of checkout plugin data returned by checkout plugin
public $checkout_plugin_data;
/** Current Notice Count */
var $notice_count=0;
2009-08-03 04:10:16 +00:00
/** Last Notice Timestamp */
2009-08-03 04:10:16 +00:00
var $notice_date;
# Due Date Timestamp
private $due_date;
/** Net Term Id */
var $net_term_id=false;
2009-08-03 04:10:16 +00:00
/** Net Term Last Notice/Late fee Timestamp */
var $net_term_date_last;
2009-08-03 04:10:16 +00:00
/** Net Term Interval Count */
var $net_term_intervals=0;
2009-08-03 04:10:16 +00:00
# Process Status
private $process_status = 0;
# Billing Status
private $billing_status = 0;
/** Suspend Billing Status */
var $suspend_billing=0;
2009-08-03 04:10:16 +00:00
# Printed Invoice Status
private $print_status = 0;
/** Refunded Invoice Status */
var $refund_status=0;
2009-08-03 04:10:16 +00:00
/** Calcuate Taxes */
2009-08-03 04:10:16 +00:00
var $tax=true;
/** Calculate Discounts */
2009-08-03 04:10:16 +00:00
var $discount=true;
# Total Invoice Amount
public $total_amt = 0;
# Total Amount Billed
private $billed_amt = 0;
/** Actual total amount billed (converted to local) */
var $actual_billed_amt=0;
2009-08-03 04:10:16 +00:00
# Total Tax Amount
public $tax_amt = 0;
# Total Discount Amount
public $discount_amt = 0;
/** Recurring Amount */
2009-08-03 04:10:16 +00:00
public $recur_amt = 0;
/** Recurring array for Later Processing */
var $recur_arr;
2009-08-03 04:10:16 +00:00
# IP Address of User
private $ip = USER_IP;
/** array of the Invoice items */
var $invoice_item;
2009-08-03 04:10:16 +00:00
/** array of the discounts for the Invoice items */
var $item_discount;
2009-08-03 04:10:16 +00:00
/** array of the taxes for the Invoice Items */
var $item_tax;
2009-08-03 04:10:16 +00:00
/** Tracking to determine payment options */
var $any_new=false;
var $any_trial=false;
var $any_recurring=false;
2009-08-03 04:10:16 +00:00
/** Invoice Config Global Options */
var $invoice_delivery=1;
2009-08-03 04:10:16 +00:00
var $invoice_format=0;
var $notice_max=MAX_BILLING_NOTICE;
var $grace_period=GRACE_PERIOD;
/**
2009-08-03 04:10:16 +00:00
* Determine the number of days in advance an invoice should be generated.
* Invoices are generated when the greater of:
* + system default (setup:max_inv_gen_period), (to be deprecated)
* + system default (setup_invoice:invoice_advance_gen),
*/
2009-08-03 04:10:16 +00:00
public function invoice_days() {
$db = &DB();
# Get the max invoice days from the setup_invoice table
$days = 0;
# First from the setup table.
$setup = $db->Execute(sqlSelect($db,'setup','max_inv_gen_period',''));
if (isset($setup->fields['max_inv_gen_period']))
$days = $setup->fields['max_inv_gen_period'];
# Then from the setup_invoice table.
$setup = $db->Execute(sqlSelect($db,'setup_invoice','invoice_advance_gen,advance_notice',''));
if (isset($setup->fields['invoice_advance_gen']) && $setup->fields['invoice_advance_gen'] > $days)
$days = $setup->fields['invoice_advance_gen'];
if (isset($setup->fields['advance_notice']) && $setup->fields['advance_notice'] > $days)
$days = $setup->fields['advance_notice'];
return $days;
}
/**
* Return the SQL that determines which invoices need to be generated
*
* Invoices are generated when the greater of:
* + system default (setup:max_inv_gen_period), (to be deprecated)
* + system default (setup_invoice:invoice_advance_gen),
* + the account setting (account:invoice_advance_gen)
* + the net_terms setting (net_term:invoice_advance_gen) (linked from the account:net_term_id))
*
* This function can be called to display the SQL that is need to generate upcoming invoices.
*
* @param string The SQL to use in the SELECT portion of the query, to return the fields
* @param int Days in advance of the normal invoice generation date to obtain
* @param int|array Limit the query to just a(n) (set of) Account ID(s)
* @param string The SQL to use in the ORDER BY portion of the query.
*/
public function sql_invoice_soon($fields=null,$adddays=0,$account=null,$orderby=null) {
global $C_list;
$db = &DB();
# Get the max invoice days from the system configuration tables.
$days = $this->invoice_days();
# Pre-notification date for service
$max_date = date('Y-m-d',time()+(($adddays+$days)*86400));
if ($account) {
if (is_array($account))
$account_where = sprintf('AND account.id IN (%s)',implode(',',$account));
else
$account_where = sprintf('AND account.id=%s',$account);
} else
$account_where = '';
if (is_null($fields))
$fields = "DISTINCT service.id AS sid,account.id AS aid,invoice.id AS iid,FROM_UNIXTIME(service.date_next_invoice,'%Y-%m-%d') AS invoice_date,service.sku AS sku,service.price AS price,account.first_name AS first_name,account.last_name AS last_name,account.currency_id AS billed_currency_id";
if (is_null($orderby))
$orderby = 'ORDER BY aid,invoice_date,sid';
$p=AGILE_DB_PREFIX; $s=DEFAULT_SITE;
// @todo NET_TERM is not tested.
if ($C_list->is_installed('net_term')) {
$net_term = "LEFT JOIN {$p}net_term AS net_term ON (account.net_term_id=net_term.id AND net_term.site_id={$s})";
$net_term_where = "OR ((net_term.invoice_advance_gen!='' OR net_term.invoice_advance_gen IS NOT NULL) AND service.date_next_invoice<=((86400*(net_term.invoice_advance_gen+{$adddays}+{$days}))+(UNIX_TIMESTAMP(CURDATE()))))";
} else {
$net_term = '';
$net_term_where = '';
}
$sql = "
SELECT {$fields}
FROM {$p}service AS service
JOIN {$p}account AS account ON (service.account_id=account.id AND account.site_id={$s})
LEFT JOIN {$p}invoice AS invoice ON (service.invoice_id=invoice.id AND invoice.site_id={$s})
{$net_term}
WHERE service.site_id={$s}
AND service.active=1
AND price > 0
AND (service.suspend_billing IS NULL OR service.suspend_billing=0)
AND (service.date_next_invoice>0 AND service.date_next_invoice IS NOT NULL)
AND (
((account.invoice_advance_gen!='' OR account.invoice_advance_gen IS NOT NULL) AND service.date_next_invoice<=((86400*(account.invoice_advance_gen+{$adddays}+{$days}))+(UNIX_TIMESTAMP(CURDATE()))))
{$net_term_where}
OR service.date_next_invoice<=UNIX_TIMESTAMP('{$max_date}')
)
{$account_where} {$orderby}";
return $sql;
}
/**
* List all invoices that will be generated soon
*/
public function invoicesoon($VAR) {
global $smarty,$C_list;
$db = &DB();
# Then from the setup_invoice table.
$setup = $db->Execute(sqlSelect($db,'setup_invoice','advance_notice',''));
# Run the database query
$result = $db->Execute($this->sql_invoice_soon(null,$setup->fields['advance_notice']));
$invoice = array();
$i = 0;
$amount = 0;
while (! $result->EOF) {
$result->fields['_C'] = ++$i%2 ? 'row1' : 'row2';
array_push($invoice,$result->fields);
$amount += $result->fields['price'];
$result->MoveNext();
}
# Error reporting
if ($result === false) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
return false;
}
$results = $result->RecordCount();
# Create the definition for fast-forwarding to a single record:
if ($results == 1 && ! isset($this->fast_forward))
$smarty->assign('record_id',$record_id);
# Create the search record:
if($results > 0) {
# create the search record
include_once(PATH_CORE.'search.inc.php');
$search = new CORE_search;
$arr['module'] = $this->module;
$arr['sql'] = $this->sql_invoice_soon();
# $arr['limit'] = $limit;
# $arr['order_by']= $order_by;
$arr['results'] = $results;
$search->add($arr);
# define the search id and other parameters for Smarty
$smarty->assign('search_id', $search->id);
# page:
$smarty->assign('page', '1');
# limit:
# $smarty->assign('limit', $limit);
# order_by:
# $smarty->assign('order_by', $order_by);
}
# define the result count
$smarty->assign('results',$results);
$smarty->assign('invoice',$invoice);
$smarty->assign('total_amount',$C_list->format_currency($amount,DEFAULT_CURRENCY));
}
public function task_overdue() {
$db = &DB();
$rs = $db->Execute($q=sqlSelect($db,array('invoice','account'),'A.id,A.account_id,SUM(A.total_amt-A.billed_amt) as total,B.first_name,B.last_name,A.due_date',sprintf('A.status=1 AND A.total_amt-A.billed_amt>0 AND A.account_id=B.id AND A.due_date<%s',time()),false,false,false,'account_id,id'));
if ($rs && $rs->RecordCount()) {
$body = '';
$account_total = 0;
$account_id = '';
$i = 0;
$count = 0;
$grand_total = 0;
while (! $rs->EOF) {
if ($account_id != $rs->fields['account_id'] && $i) {
$body .= sprintf("Total: %3.2f\n\n",$account_total);
$account_total = 0;
$i = 0;
}
if (! $i)
$body .= sprintf("%s %s (%s)\n",$rs->fields['last_name'],$rs->fields['first_name'],$rs->fields['account_id']);
$body .= sprintf(" Invoice: %s, Due Date: %s, Amount: %3.2f\n",$rs->fields['id'],date('Y-m-d',$rs->fields['due_date']),$rs->fields['total']);
$account_total += $rs->fields['total'];
$grand_total += $rs->fields['total'];
$account_id = $rs->fields['account_id'];
$count++;
$i++;
$rs->MoveNext();
}
if ($account_total)
$body .= sprintf("Total: %3.2f\n",$account_total);
$body .= "\n";
if ($count || $ground_total)
$body .= sprintf("%3.2f outstanding in %s invoices\n",$grand_total,$count);
# Send the e-mail....
require_once(PATH_INCLUDES.'phpmailer/class.phpmailer.php');
$mail = new PHPMailer();
$mail->AddAddress('deon@leenooks.vpn','Deon George');
$mail->From = SITE_EMAIL;
$mail->FromName = SITE_NAME;
$mail->Subject = 'Overdue invoices';
$mail->Body = $body;
$mail->Send();
}
}
/**
* Get a list of unpaid invoices for an account
*/
public function unpaid($account_id) {
$db = &DB();
$invoices = array();
$rs = $db->Execute($q=sqlSelect($db,'invoice','id,SUM(total_amt-billed_amt) as total',array('account_id'=>$account_id,'billing_status'=>0,'refund_status'=>0),false,false,'','id'));
if ($rs && $rs->RecordCount()) {
while (! $rs->EOF) {
$invoices[$rs->fields['id']] = $rs->fields['total'];
$rs->MoveNext();
}
}
2009-08-03 04:10:16 +00:00
return $invoices;
}
2009-08-03 04:10:16 +00:00
/**
* Get the account level invoice options
*
* @param int $id Account Id
*/
2009-08-03 04:10:16 +00:00
private function setupAccount() {
if (! $this->account_id)
return;
$db = &DB();
$acctrs = $db->Execute(sqlSelect($db,'account','invoice_grace,invoice_advance_gen',sprintf('id=%s',$this->account_id)));
if ($acctrs && $acctrs->RecordCount()) {
$this->advance_gen = $acctrs->fields['invoice_advance_gen'];
if ($this->grace_period == GRACE_PERIOD && ! empty($acctrs->fields['invoice_grace']))
$this->grace_period = $acctrs->fields['invoice_grace'];
}
}
/**
* Return the invoice ID
*/
public function getInvoiceID() {
return sprintf('%02s-%06s-%06s',DEFAULT_SITE,$this->print['account']['id'],$this->getInvoiceNum());
}
public function getInvoiceNum() {
return $this->print['invoice']['id'];
}
public function getPreviousBalance() {
static $bal = 0;
if ($bal)
return $bal;
foreach ($this->print['previousinvoices'] as $item)
$bal += $item['total_amt']-$item['billed_amt'];
return $bal;
}
/**
* Initialize new invoice creation
*
* @param bool $type 0=new 1=recur
*/
2009-08-03 04:10:16 +00:00
public function initNew($type=0) {
$this->type = $type;
$this->date_orig = time();
$this->date_last = time();
global $C_list;
2009-08-03 04:10:16 +00:00
$this->net_term = $C_list->is_installed('net_term');
}
2009-08-03 04:10:16 +00:00
/** HERE **/
/**
* Commit the current invoice/items/discounts/taxes
*
* @param object $taxObj Object for Tax Calculation
2009-08-03 04:10:16 +00:00
* @param object $discountObj Object for Discount Calculation
* @param bool $email Send customer/admin e-mails
*/
function commitNew(&$taxObj, &$discountObj, $email=true) {
2009-08-03 04:10:16 +00:00
# init DB transaction
$db = &DB();
$db->BeginTrans();
2009-08-03 04:10:16 +00:00
# Get invoice id
if (empty($this->record_id))
$this->record_id = sqlGenID($db,'invoice');
# Serialized records:
if (is_array($this->checkout_plugin_data))
$this->checkout_plugin_data=serialize($this->checkout_plugin_data);
if (is_array($this->recur_arr))
$this->recur_arr=serialize($this->recur_arr);
# Dates & defaults
if (empty($this->due_date))
$this->due_date = time();
if (empty($this->date_orig))
$this->date_orig = time();
if (empty($this->date_last))
$this->date_last = time();
if (empty($this->notice_next_date))
$this->notice_next_date = $this->due_date+86400;
# net terms
if ($this->net_term && ! $this->billing_status && $this->total_amt>0) {
include_once(PATH_MODULES.'net_term/net_term.inc.php');
2009-08-03 04:10:16 +00:00
$net = new net_term;
$this->net_term_id = $net->termsAllowed($this->account_id, $this->checkout_plugin_id);
2009-08-03 04:10:16 +00:00
if (empty($this->net_term_date_last))
$this->net_term_date_last = time();
}
# Insert invoice
$fields=array(
'date_orig'=>$this->date_orig,
2009-08-03 04:10:16 +00:00
'date_last'=>$this->date_last,
'parent_id'=>$this->parent_id,
'type'=>$this->type,
'process_status'=>$this->process_status,
'billing_status'=>$this->billing_status,
'suspend_billing'=>$this->suspend_billing,
'refund_status'=>$this->refund_status,
'print_status'=>$this->print_status,
'account_id'=>$this->account_id,
'account_billing_id'=>$this->account_billing_id,
'affiliate_id'=>$this->affiliate_id,
'campaign_id'=>$this->campaign_id,
'reseller_id'=>$this->reseller_id,
'checkout_plugin_id'=>$this->checkout_plugin_id,
'checkout_plugin_data'=>$this->checkout_plugin_data,
2009-08-03 04:10:16 +00:00
'tax_amt'=>$this->tax_amt,
'discount_amt'=>$this->discount_amt,
'total_amt'=>$this->total_amt,
'billed_amt'=>$this->billed_amt,
'recur_amt'=>$this->recur_amt,
'recur_arr'=>$this->recur_arr,
'actual_billed_amt'=>$this->actual_billed_amt,
'billed_currency_id'=>$this->billed_currency_id,
'actual_billed_currency_id'=>$this->actual_billed_currency_id,
'notice_count'=>$this->notice_count,
'notice_max'=>$this->notice_max,
'notice_next_date'=>$this->notice_next_date,
2009-08-03 04:10:16 +00:00
'due_date'=>$this->due_date,
'grace_period'=>$this->grace_period,
'net_term_id'=>$this->net_term_id,
'net_term_date_last'=>$this->net_term_date_last,
'net_term_intervals'=>$this->net_term_intervals,
'ip'=>$this->ip
);
2009-08-03 04:10:16 +00:00
$db->Execute(sqlInsert($db,'invoice',$fields,$this->record_id));
# Loop through invoice items
if (is_array($this->invoice_item)) {
foreach ($this->invoice_item as $id=>$fields) {
# Get an invoice_item id
$invoice_item_id = sqlGenID($db,'invoice_item');
# Domain sku's
if ($fields['item_type'] == 2) {
2009-08-03 04:10:16 +00:00
$fields['sku'] = sprintf('DOMAIN-%s',strtoupper($fields['domain_type']));
$fields['price_type'] = '0';
}
2009-08-03 04:10:16 +00:00
# Build e-mail item details
if ($email) {
$email_instructions = '';
if ($fields['item_type']<2 && !empty($fields['product_id'])) {
// product, get email instructions and translated name
2009-08-03 04:10:16 +00:00
$translate_prod = $db->Execute(
sqlSelect($db,'product_translate','email_template,name',array('product_id'=>$fields['product_id'],'language_id'=>SESS_LANGUAGE)));
if ($translate_prod && $translate_prod->RecordCount()) {
$instructions=$translate_prod->fields['email_template'];
$name=$translate_prod->fields['name'];
2009-08-03 04:10:16 +00:00
} else {
2009-08-03 04:10:16 +00:00
$name = $fields['sku'];
}
2009-08-03 04:10:16 +00:00
} elseif ($fields['item_type'] == 2) {
$name=strtoupper($fields['domain_name'].".".$fields['domain_tld']);
2009-08-03 04:10:16 +00:00
} else {
2009-08-03 04:10:16 +00:00
if (! empty($fields['product_name']))
$name = $fields['product_name'];
else
$name = $fields['sku'];
}
2009-08-03 04:10:16 +00:00
// add to e-mail array
$email_arr[] = array('Qty' => '('.$fields["quantity"].')', 'Item' => 'SKU '.$fields["sku"], 'Price' => number_format($fields["total_amt"],2), 'Name' => $name, 'Instructions' => $instructions);
}
// insert the invoice item_id
$fields['invoice_id']=$this->record_id;
$fields['date_orig']=time();
$attr = serialize($fields['product_attr']);
$fields['product_attr']=$fields['product_attr_cart'];
2009-08-03 04:10:16 +00:00
$fields['product_attr_cart']=$attr;
$db->Execute(sqlInsert($db,'invoice_item',$fields,$invoice_item_id));
# Load tax object for tax calculation
include_once(PATH_MODULES.'tax/tax.inc.php');
$taxObj = new tax;
# Load discount object for discount calculation
include_once(PATH_MODULES.'discount/discount.inc.php');
$discountObj = new discount;
$discountObj->available_discounts($this->account_id);
// insert taxes
2009-08-03 04:10:16 +00:00
if ($this->tax && $this->tax_amt > 0 && ! empty($this->tax_arr[$id]))
$taxObj->invoice_item($this->record_id,$invoice_item_id,$this->account_id,$this->tax_arr[$id]);
// insert discounts
2009-08-03 04:10:16 +00:00
if($this->discount && $this->discount_amt>0 && !empty($this->discount_arr[$id]))
$discountObj->invoice_item($this->record_id, $invoice_item_id, $this->account_id, $this->discount_arr[$id]);
}
}
2009-08-03 04:10:16 +00:00
// complete DB transaction
$db->CompleteTrans();
2009-08-03 04:10:16 +00:00
// complete building e-mail notices and send
2009-08-03 04:10:16 +00:00
if ($email) {
include_once(PATH_MODULES.'email_template/email_template.inc.php');
2009-08-03 04:10:16 +00:00
// Create the products order list for the e-mail:
$e_itm_usr = '';
$e_itm_adm = '';
if(is_array($email_arr)) {
foreach($email_arr as $i=>$em) {
$e_itm_usr .= $em['Qty'].' '.$em['Item'].' ('.$em['Name'].') '.$em['Price'];
$e_itm_adm .= $em['Qty'].' '.$em['Item'].' ('.$em['Name'].') '.$em['Price']."\r\n";
2009-08-03 04:10:16 +00:00
if(!empty($email_arr[$i]['Instructions'])) $e_itm_usr .= "\r\n * " . $email_item_arr[$i]['Instructions'];
$e_itm_usr .= "\r\n";
}
$e_arr_user = array('%products%' => $e_itm_usr);
$e_arr_adm = array('%products%' => $e_itm_adm);
}
2009-08-03 04:10:16 +00:00
// e-mail invoice creation confirmation
$mail = new email_template;
2009-08-03 04:10:16 +00:00
$mail->send('invoice_confirm_user', $this->account_id, $this->record_id, $this->checkout_plugin_id, $e_arr_user);
$email = new email_template;
2009-08-03 04:10:16 +00:00
$email->send('admin->invoice_confirm_admin', $this->account_id, $this->record_id, $this->checkout_plugin_id, $e_arr_adm);
}
2009-08-03 04:10:16 +00:00
// net terms?
if($this->net_term_id) {
2009-08-03 04:10:16 +00:00
$this->approveInvoice(array('id'=>$this->record_id), $this);
return $this->record_id;
2009-08-03 04:10:16 +00:00
}
// Determine the approval status by checkout plugin type & settings:
2009-08-03 04:10:16 +00:00
if($email && $this->billing_status == 0 && $this->billed_amt > 0) {
global $C_list;
if($this->checkout_type == 'redirect') {
// User e-mail alert of due invoice
$email = new email_template;
$email->send('invoice_due_user', $this->account_id, $this->record_id, $user_currency, $C_list->date($this->due_date));
} elseif ($this->checkout_type == 'other') {
// Admin e-mail alert of manual payment processing
$email = new email_template;
$email->send('admin->invoice_due_admin', $this->account_id, $this->record_id, $admin_currency, $C_list->date($this->due_date));
}
2009-08-03 04:10:16 +00:00
} elseif($this->billed_amt>0) {
if($email) {
// User alert of payment processed
$email = new email_template;
$email->send('invoice_paid_user', $this->account_id, $this->record_id, $this->billed_currency_id, '');
// Admin alert of payment processed
$email = new email_template;
$email->send('admin->invoice_paid_admin', $this->account_id, $this->record_id, $this->billed_currency_id, '');
}
$this->autoApproveInvoice($this->record_id);
2009-08-03 04:10:16 +00:00
} elseif($this->billed_amt == 0 && $this->billing_status == 1) {
$this->autoApproveInvoice($this->record_id);
}
2009-08-03 04:10:16 +00:00
// return invoice id
return $this->record_id;
}
2009-08-03 04:10:16 +00:00
/**
* Add an invoice item
*
* @param int $id Reference ID for use in Cart or false
2009-08-03 04:10:16 +00:00
* @param object $cartrs RS from cart query
*/
2009-08-03 04:10:16 +00:00
public function addItem($id,$cartrs) {
# Setup Variables
$item_type = $cartrs->fields['cart_type'];
$product_id = $cartrs->fields['product_id'];
$recurring_schedule = $cartrs->fields['recurr_schedule'];
$domain_tld = $cartrs->fields['domain_tld'];
$domain_term = $cartrs->fields['domain_term'];
$domain_type = $cartrs->fields['domain_type'];
# Define correct qty
if ($cartrs->fields['quantity']<0)
$quantity = 1;
else
$quantity = $cartrs->fields['quantity'];
if (! empty($cartrs->fields['product_attr']) && ! is_array($cartrs->fields['product_attr']))
$product_attr = unserialize($result->fields['product_attr']);
else
$product_attr = array();
# Special processing for ADHOC items
if ($item_type == 3) {
$taxable = $cartrs->fields['cart_type'];
$product_name = $cartrs->fields['ad_hoc_name'];
$sku = $cartrs->fields['ad_hoc_sku'];
$price_base = $cartrs->fields['ad_hoc_amount'];
$price_setup = $cartrs->fields['ad_hoc_setup'];
$discount_manual = $cartrs->fields['ad_hoc_discount'];
} else {
2009-08-03 04:10:16 +00:00
$taxable = false;
$product_name = '';
$sku = '';
$price_base = false;
$price_setup = false;
$discount_manual = false;
}
2009-08-03 04:10:16 +00:00
$tax_amt = 0;
$total_amt = 0;
$discount_amt = 0;
$item = null;
# Load tax object for tax calculation
include_once(PATH_MODULES.'tax/tax.inc.php');
$taxObj = new tax;
# Load discount object for discount calculation
include_once(PATH_MODULES.'discount/discount.inc.php');
$discountObj = new discount;
$discountObj->available_discounts($this->account_id);
# Determine the reference id for this item
if ($id>0)
$this->item_id=$id;
else
$this->item_id++;
if ($product_id) {
include_once(PATH_MODULES.'product/product.inc.php');
$item_object = new product;
$item = $item_object->getID($product_id);
$this->product[$this->item_id] = $item;
}
2009-08-03 04:10:16 +00:00
switch ($item_type) {
# Get the tld details
case '2':
include_once(PATH_MODULES.'host_tld/host_tld.inc.php');
$item_object = new host_tld;
$item = $item_object->getName($domain_tld);
# Get the TLD pricing
if ($price_base===false && $price_setup===false && $domain_tld && $domain_term && $domain_type) {
$tldprice = $item_object->price_tld_arr($domain_tld,$domain_type,false,false,false,$this->account_id);
if ($domain_type == 'park') {
$price_base = $tldprice;
} else {
$price_base = $tldprice[$domain_term];
$this->tld_arr[$this->item_id] = $tldprice;
}
}
$price_recur = $price_base;
break;
default:
# Get the product pricing
$price_type = 0;
if ($price_base===false && $price_setup===false && $this->product[$this->item_id]) {
$price_type = $this->product[$this->item_id]['price_type'];
$sku = $this->product[$this->item_id]['sku'];
# Get pricing for this product:
$prod_price = $item_object->price_prod($this->product[$this->item_id],$recurring_schedule,$this->account_id);
$price_base = $prod_price['base'];
$price_setup = $prod_price['setup'];
$prod_price = $item_object->price_prod($this->product[$this->item_id],$recurring_schedule,$this->account_id,false);
$price_recur = $prod_price['base'];
# Calculate any product attributes fees
$attr_price = $item_object->price_attr($this->product[$this->item_id],$product_attr,$recurring_schedule,$this->account_id);
$price_base += $attr_price['base'];
$price_setup += $attr_price['setup'];
# @todo this cant be the right value for recurring addons?
$price_recur += $attr_price['base'];
# Determine price type for checkout
switch ($price_type) {
case 0: $this->any_new = true; break;
case 1: $this->any_recurring = true; break;
case 2: $this->any_trial = true; break;
}
} else {
$this->any_new = true;
$price_recur = $price_base;
}
break;
}
2009-08-03 04:10:16 +00:00
if ($item && isset($item['taxable']))
$taxable = $item['taxable'];
# Set total amount for this line item before attributes, taxes, or discounts
$price_base *= $quantity;
$price_setup *= $quantity;
2009-08-03 04:10:16 +00:00
$total_amt = ($price_setup+$price_base);
//echo '<PRE>';print_r(array('q'=>$quantity,'pb'=>$price_base,'pt'=>$price_type,'pr'=>$price_recur,'id'=>$id,'iid'=>$this->item_id,'p'=>$product->fields));
# Format product attributes for storage
$product_attr_cart = false;
if (($item_type==0 || $item_type>2) && is_array($product_attr))
$product_attr_cart = $this->get_product_attr_cart($product_attr);
# Recurring taxes and arrays
if (($price_recur || $price_base) && $price_type==1) {
$this->recur_amt += $price_recur;
# Determine taxes for the recurring amount
if ($this->tax && $taxable && $price_recur>0 && $this->account_id) {
$recur_tax_arr = $taxObj->calculate($price_recur,$this->country_id,$this->state);
if (is_array($recur_tax_arr))
foreach ($recur_tax_arr as $tx)
$this->recur_amt += $tx['rate'];
}
# Get the recurring arrays for price and invoice
if ($item_object) {
$this->price_arr[$this->item_id] = $item_object->price_recurr_arr($this->product[$this->item_id],$this->account_id);
$this->recur_arr[] = array(
'price' => $price_base*$quantity,
'recurr_schedule'=> $recurring_schedule,
2009-08-03 04:10:16 +00:00
'recurr_type' => $this->product[$this->item_id]['price_recurr_type'],
'recurr_weekday' => $this->product[$this->item_id]['price_recurr_weekday'],
'recurr_week' => $this->product[$this->item_id]['price_recurr_week']
);
}
}
2009-08-03 04:10:16 +00:00
# Calculate any ad-hoc line item level (admin) discounts
if ($this->discount && $discount_manual>0) {
$total_amt -= $discount_manual;
$discount_amt += $discount_manual;
2009-08-03 04:10:16 +00:00
$this->discount_amt += $discount_amt;
$discountObj->add_manual_discount($discount_manual,'MISC',$this->item_id);
}
2009-08-03 04:10:16 +00:00
# Account level discounts
if ($this->discount && $this->account_id) {
# Calculate any database level discounts for this item (both account specific and session specific)
$discount_amt = $discountObj->calc_all_discounts(0,$this->item_id,$product_id,$total_amt,$this->account_id,$this->total_amt+$total_amt);
$total_amt -= $discount_amt;
$this->discount_amt += $discount_amt;
}
2009-08-03 04:10:16 +00:00
# Add to total discount array
if (is_array($discountObj->discount_arr)) {
$this->discount_arr[$this->item_id] = $discountObj->discount_arr;
}
2009-08-03 04:10:16 +00:00
# Increment invoice total amount
$this->total_amt += $total_amt;
2009-08-03 04:10:16 +00:00
// calculate any taxes for current item
if ($this->tax && $taxable && $total_amt>0 && $this->account_id) {
$tax_arr = $taxObj->calculate($total_amt, $this->country_id, $this->state);
if(is_array($tax_arr)) {
2009-08-03 04:10:16 +00:00
foreach($tax_arr as $tx) $tax_amt += $tx['rate'];
$this->item_tax[$this->item_id] = $tax_arr;
$this->tax_arr[$this->item_id] = $tax_arr;
}
$this->tax_amt += $tax_amt;
2009-08-03 04:10:16 +00:00
$this->total_amt += $tax_amt;
}
2009-08-03 04:10:16 +00:00
// store the fields to an array
2009-08-03 04:10:16 +00:00
$this->invoice_item[$this->item_id] = array(
'item_type'=>$item_type,
'price_type'=>$price_type,
'taxable'=>$taxable,
2009-08-03 04:10:16 +00:00
'service_id'=>$cartrs->fields['service_id'],
'parent_id'=>$cartrs->fields['parent_id'],
'product_id'=>$product_id,
'product_attr'=>$product_attr,
'product_attr_cart'=>$product_attr_cart,
'product_name'=>$product_name,
'sku'=>$sku,
'quantity'=>$quantity,
'price_base'=>$price_base,
'price_setup'=>$price_setup,
'recurring_schedule'=>$recurring_schedule,
2009-08-03 04:10:16 +00:00
'date_start'=>'',
'date_stop'=>'',
'domain_name'=>$cartrs->fields['domain_name'],
'domain_tld'=>$domain_tld,
'domain_term'=>$domain_term,
2009-08-03 04:10:16 +00:00
'domain_type'=>$domain_type,
'total_amt'=>$total_amt,
'tax_amt'=>$tax_amt,
'discount_amt'=>$discount_amt
);
}
2009-08-03 04:10:16 +00:00
/**
* Group all taxes to lump sums
*/
2009-08-03 04:10:16 +00:00
public function group_taxes() {
if(is_array($this->tax_arr)) {
2009-08-03 04:10:16 +00:00
foreach($this->tax_arr as $taxarr) foreach($taxarr as $taxes) $arr[$taxes["name"]]+=$taxes["rate"];
if(is_array($arr)) {
2009-08-03 04:10:16 +00:00
foreach($arr as $a=>$b) $ret[] = array('name'=>$a, 'rate'=>$b);
return $ret;
}
}
}
2009-08-03 04:10:16 +00:00
/**
* Group all discounts to lump sums
*/
2009-08-03 04:10:16 +00:00
public function group_discounts() {
if(is_array($this->discount_arr)) {
foreach($this->discount_arr as $discarr) foreach($discarr as $discounts) $arr[$discounts["discount"]]+=$discounts["amount"];
if(is_array($arr)) {
2009-08-03 04:10:16 +00:00
foreach($arr as $a=>$b) $ret[] = array('name'=>$a, 'total'=>$b);
return $ret;
}
2009-08-03 04:10:16 +00:00
}
}
/**
* Build a formatted product attribute list
*
* @param array $attributes
* @return string Formatted product attribute list
*/
2009-08-03 04:10:16 +00:00
public function get_product_attr_cart($attributes) {
# Set the attribute array:
if(!empty($attributes) && is_array($attributes)) {
$db=&DB();
2009-08-03 04:10:16 +00:00
$product_attr = false;
foreach($attributes as $id=>$value) {
if (!empty($value)) {
2009-08-03 04:10:16 +00:00
if(is_numeric($id)) {
$attr = $db->Execute(sqlSelect($db,"product_attr","name","id=$id"));
if ($attr && $attr->RecordCount()) $product_attr .= "{$attr->fields['name']}==".ereg_replace("\r\n", "<br>", $value)."\r\n";
} else {
$product_attr .= "{$id}=={$value}\r\n";
}
}
}
}
return $product_attr;
}
2009-08-03 04:10:16 +00:00
/**
* Custom Tracking
* @todo: should this be here, or under the affilate module? what does it do?
*/
public function custom_tracking($VAR) {
# Get the invoice id
2009-08-03 04:10:16 +00:00
if (SESS_LOGGED == false)
return false;
# Check if we are in the iframe
2009-08-03 04:10:16 +00:00
if (empty($VAR['_escape']) || empty($VAR['confirm'])) {
printf('<iframe id="custom_ecom_track" style="border:0px; width:0px; height:0px;" scrolling="auto" frameborder="0" src="?_page=core:blank&_escape=1&confirm=1&do[]=invoice:custom_tracking&rand=%s"></iframe>',
md5(microtime()));
return;
}
# Get the un-tracked invoice details
$db = &DB();
2009-08-03 04:10:16 +00:00
$result = $db->Execute(sqlSelect($db,'invoice','*',sprintf('(custom_affiliate_status IS NULL OR custom_affiliate_status=0) AND billing_status=1 AND account_id=%s',SESS_ACCOUNT)));
if ($result === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,sprintf('%s (%s)',$db->ErrorMsg(),$sql));
return false;
}
2009-08-03 04:10:16 +00:00
if ($result->RecordCount() == 0)
return false;
# Get the totals
$invoice = '';
$total_amount = false;
2009-08-03 04:10:16 +00:00
while (! $result->EOF) {
if (! empty($invoice))
$invoice .= '-';
$invoice .= $result->fields['id'];
2009-08-03 04:10:16 +00:00
$amt = $result->fields['total_amt'];
$total_amount += $amt;
$result->MoveNext();
}
2009-08-03 04:10:16 +00:00
# Echo the custom tracking code to the screen:
if (! is_file(PATH_FILES.'tracking.txt'))
return false;
$tracking = file_get_contents(PATH_FILES.'tracking.txt');
2009-08-03 04:10:16 +00:00
$tracking = str_replace('%%amount%%',$total_amount,$tracking);
$tracking = str_replace('%%invoice%%',$invoice,$tracking);
$tracking = str_replace('%%affiliate%%',SESS_AFFILIATE,$tracking);
$tracking = str_replace('%%campaign%%',SESS_CAMPAIGN,$tracking);
$tracking = str_replace('%%account%%',SESS_ACCOUNT,$tracking);
echo $tracking;
2009-08-03 04:10:16 +00:00
# Update the record so it is not tracked again
2009-08-03 04:10:16 +00:00
$rs = $db->Execute(sqlUpdate($db,'invoice',array('custom_affiliate_status'=>1),sprintf('account_id=%s AND billing_status=1',SESS_ACCOUNT)));
if ($rs === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,sprintf('%s (%s)',$db->ErrorMsg(),$sql));
}
2009-08-03 04:10:16 +00:00
return true;
}
2009-08-03 04:10:16 +00:00
/** Performance: (for the admin dashboard)
*/
2009-08-03 04:10:16 +00:00
public function performance($VAR)
{
global $smarty, $C_list, $C_translate;
2009-08-03 04:10:16 +00:00
# Get the period type, default to month
if (empty($VAR['period']))
$p = 'm';
else
$p = $VAR['period'];
# Determine the correct period language:
2009-08-03 04:10:16 +00:00
if($p=='' or $p == 'm')
{
$pTrans = $C_translate->translate('thismonth','invoice','') . ' '.
$C_translate->translate('vs','invoice','') . ' ' .
$C_translate->translate('lastmonth','invoice','');
$pFore = $C_translate->translate('thismonth','invoice','');
2009-08-03 04:10:16 +00:00
}
elseif ($p == 'w')
{
$pTrans = $C_translate->translate('thisweek','invoice','') . ' '.
$C_translate->translate('vs','invoice','') . ' ' .
2009-08-03 04:10:16 +00:00
$C_translate->translate('lastweek','invoice','');
$pFore = $C_translate->translate('thisweek','invoice','');
}
2009-08-03 04:10:16 +00:00
elseif ($p == 'y')
{
$pTrans = $C_translate->translate('thisyear','invoice','') . ' '.
$C_translate->translate('vs','invoice','') . ' ' .
2009-08-03 04:10:16 +00:00
$C_translate->translate('lastyear','invoice','');
$pFore = $C_translate->translate('thisyear','invoice','');
}
2009-08-03 04:10:16 +00:00
$smarty->assign('period_compare', $pTrans);
2009-08-03 04:10:16 +00:00
$smarty->assign('period_forcast', $pFore);
# Get the period start & end
switch ($p) {
case 'w':
$dow = date('w');
$this_start = mktime(0,0,0,date('m'), date('d')-$dow, date('y'));
$this_end = mktime(23,59,59,date('m'), date('d'), date('y'));
$last_start = mktime(0,0,0,date('m'), date('d', $this_start)-7, date('y'));
$last_end = $this_start-1;
break;
case 'm':
$this_start = mktime(0,0,0,date('m'), 1, date('y'));
$this_end = mktime(23,59,59,date('m'), date('d'), date('y'));
$last_start = mktime(0,0,0, date('m', $this_start)-1, 1, date('y'));
$last_end = $this_start-1;
break;
case 'y':
$this_start = mktime(0,0,0,1,1, date('y', time()));
$this_end = mktime(23,59,59, date('m'), date('d'), date('y'));
$last_start = mktime(0,0,0,1,1, date('y', $this_start)-1);
$last_end = $this_start-1;
break;
}
##############################
# Get sales for this period
##############################
$db = &DB();
$this_amt = 0;
$sql = 'SELECT total_amt FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($this_start) . ' AND
date_orig <= ' . $db->qstr($this_end) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
2009-08-03 04:10:16 +00:00
while(!$rs->EOF) {
$this_amt += $rs->fields['total_amt'];
$rs->MoveNext();
}
$smarty->assign('sales_current', $this_amt);
###############################
# Get sales for last period
###############################
$last_amt = 0;
$sql = 'SELECT total_amt FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($last_start) . ' AND
date_orig <= ' . $db->qstr($last_end) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
2009-08-03 04:10:16 +00:00
while(!$rs->EOF) {
$last_amt += $rs->fields['total_amt'];
$rs->MoveNext();
}
$smarty->assign('sales_previous', $last_amt);
###############################
# Get sales change percentage
###############################
if($last_amt > 0)
$sales_change = $this_amt/$last_amt *100 -100;
else
$sales_change = 0;
if($sales_change == 0)
$sales_change = '';
elseif($sales_change < 0)
$sales_change = '<font color="#990000">' . number_format($sales_change, 1). '%</font>';
else
$sales_change = '+'.number_format($sales_change, 1). '%';
$smarty->assign('sales_change', $sales_change);
#################################
# Get forcast for current period
#################################
switch ($p) {
case 'w':
$dow = date('w')+1;
$forcast_daily = $this_amt/$dow ;
$forcast_l_daily = $last_amt / 7;
@$forcast_change = $forcast_daily / $forcast_1_daily *100 -100;
$forcast_current = $forcast_daily * 7;
break;
case 'm':
$forcast_daily = $this_amt / date('d');
$forcast_1_daily = $last_amt / date('t', mktime(0,0,0,date('m')-1, 1, date('y')));
@$forcast_change = $forcast_daily / $forcast_1_daily *100 -100;
$forcast_current = $forcast_daily * date('t');
break;
case 'y':
$forcast_daily = $this_amt / date('z');
$forcast_1_daily = $last_amt / 356;
@$forcast_change = $forcast_daily / $forcast_1_daily *100 -100;
$forcast_current = $forcast_daily * 365;
break;
}
$smarty->assign('forcast_current', $forcast_current);
###############################
# Get forcast change percentage
###############################
2009-08-03 04:10:16 +00:00
if($last_amt > 0)
@$forcast_change = $forcast_daily/$forcast_1_daily *100;
else
$forcast_change = 0;
if($forcast_change == 0)
$forcast_change = '-';
elseif($forcast_change < 0)
$forcast_change = '<font color="#990000">' . number_format($forcast_change, 1). '%</font>';
else
$forcast_change = '+'.number_format($forcast_change, 1). '%';
$smarty->assign('forcast_change', $forcast_change);
####################################################
# Get Quota for Today to meet Forcasted sales:
####################################################
$smarty->assign('quota_current', $forcast_daily);
##############################
# Get AR credits for this period
##############################
$this_billed_amt = 0;
$sql = 'SELECT billed_amt FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($this_start) . ' AND
date_orig <= ' . $db->qstr($this_end) . ' AND
billed_amt > ' . $db->qstr(0) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
2009-08-03 04:10:16 +00:00
while(!$rs->EOF) {
$this_billed_amt += $rs->fields['billed_amt'];
$rs->MoveNext();
}
$smarty->assign('ar_credits_current', $this_billed_amt);
###############################
# Get AR credits for last period
###############################
$last_billed_amt = 0;
$sql = 'SELECT billed_amt FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($last_start) . ' AND
date_orig <= ' . $db->qstr($last_end) . ' AND
billed_amt > ' . $db->qstr(0) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
2009-08-03 04:10:16 +00:00
while(!$rs->EOF) {
$last_billed_amt += $rs->fields['billed_amt'];
$rs->MoveNext();
}
$smarty->assign('ar_credits_previous', $last_billed_amt);
###############################
# Get AR Credits change percentage
###############################
if($last_billed_amt > 0)
$ar_change = $this_billed_amt/$last_billed_amt *100 -100;
else
$ar_change = 0;
if($ar_change == 0)
$ar_change = '-';
elseif($ar_change < 0)
$ar_change = '<font color="#990000">' . number_format($ar_change, 1). '%</font>';
else
$ar_change = '+'.number_format($ar_change, 1). '%';
$smarty->assign('ar_credit_change', $ar_change);
##########################################
# Get AR Balance
##########################################
$this_ar_balance = $this_billed_amt - $this_amt;
$last_ar_balance = $last_billed_amt - $last_amt;
$smarty->assign('ar_balance_current', $this_ar_balance);
$smarty->assign('ar_balance_last', $last_ar_balance);
#########################################
# Get Users (current)
#########################################
$sql = 'SELECT id FROM ' . AGILE_DB_PREFIX . 'account WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($this_start) . ' AND
date_orig <= ' . $db->qstr($this_end) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
$users_current = $rs->RecordCount();
$smarty->assign('users_current', $users_current);
#########################################
# Get Users (previous)
#########################################
$sql = 'SELECT id FROM ' . AGILE_DB_PREFIX . 'account WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($last_start) . ' AND
date_orig <= ' . $db->qstr($last_end) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
$users_previous = $rs->RecordCount();
$smarty->assign('users_previous', $users_previous);
###############################
# Get users change percentage
###############################
if($users_previous > 0)
@$users_change = $users_current/$users_current *100 -100;
else
$users_change = 0;
if($users_change == 0)
$users_change = '-';
elseif($users_change < 0)
$users_change = '<font color="#990000">' . number_format($users_change, 1). '%</font>';
else
$users_change = '+'.number_format($users_change, 1). '%';
$smarty->assign('users_change', $users_change);
# Get Affiliate stats
2009-08-03 04:10:16 +00:00
if($C_list->is_installed('affiliate'))
{
$smarty->assign('show_affiliates', true);
###########################################
# Get affiliate sales for this period
###########################################
$this_amt = 0;
$sql = 'SELECT total_amt FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($this_start) . ' AND
date_orig <= ' . $db->qstr($this_end) . ' AND
affiliate_id != ' . $db->qstr(0) . ' AND
affiliate_id != ' . $db->qstr('') . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
2009-08-03 04:10:16 +00:00
while(!$rs->EOF) {
$this_amt += $rs->fields['total_amt'];
$rs->MoveNext();
}
$smarty->assign('affiliate_sales_current', $this_amt);
##########################################
# Get affiliate sales for last period
##########################################
$last_amt = 0;
$sql = 'SELECT total_amt FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
date_orig >= ' . $db->qstr($last_start) . ' AND
date_orig <= ' . $db->qstr($last_end) . ' AND
affiliate_id != ' . $db->qstr(0) . ' AND
affiliate_id != ' . $db->qstr('') . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
2009-08-03 04:10:16 +00:00
while(!$rs->EOF) {
$last_amt += $rs->fields['total_amt'];
$rs->MoveNext();
}
$smarty->assign('affiliate_sales_previous', $last_amt);
###########################################
# Get affiliate sales change percentage
###########################################
if($last_amt > 0)
$sales_change = $this_amt/$last_amt *100 -100;
else
$sales_change = 0;
if($sales_change == 0)
$sales_change = '-';
elseif($sales_change < 0)
$sales_change = '<font color="#990000">' . number_format($sales_change, 1). '%</font>';
else
$sales_change = '+'.number_format($sales_change, 1). '%';
$smarty->assign('affiliate_sales_change', $sales_change);
}
2009-08-03 04:10:16 +00:00
/** Get VoIP Performance Data
2009-08-03 04:10:16 +00:00
*/
if( $C_list->is_installed('voip') )
2009-08-03 04:10:16 +00:00
{
# Avg. Call Duration for this period
$rs = $db->Execute(sqlSelect($db, "voip_cdr", "avg(ceiling(billsec/60))", "disposition='ANSWERED' AND date_orig >= $this_start AND date_orig <= $this_end"));
2009-08-03 04:10:16 +00:00
if(empty($rs->fields[0])) $acd=0; else $acd = $rs->fields[0];
$smarty->assign('acd',$acd);
# Avg. Call Duration for last period
$rs = $db->Execute(sqlSelect($db, "voip_cdr", "avg(ceiling(billsec/60))", "disposition='ANSWERED' AND date_orig >= $last_start AND date_orig <= $last_end"));
2009-08-03 04:10:16 +00:00
if(empty($rs->fields[0])) $acd_last=0; else $acd_last = $rs->fields[0];
$smarty->assign('acd_last',$acd_last);
2009-08-03 04:10:16 +00:00
# Get Avg. Call Duration change Percentage
if($acd > 0) $acd_change = $acd/$acd_last*100-100; else $acd_change = 0;
2009-08-03 04:10:16 +00:00
if($acd_change == 0)
$acd_change = '-';
elseif ($acd_change < 0)
$acd_change = '<font color="#990000">' . number_format($acd_change, 1). '%</font>';
2009-08-03 04:10:16 +00:00
else
$acd_change = '+'.number_format($acd_change, 1). '%';
$smarty->assign('acd_change', $acd_change);
2009-08-03 04:10:16 +00:00
# Avg. Successful Rate for this period
$rs = $db->Execute(sqlSelect($db, "voip_cdr", "count(*)", "disposition='ANSWERED' AND date_orig >= $this_start AND date_orig <= $this_end"));
$rs1 = $db->Execute(sqlSelect($db, "voip_cdr", "count(*)", "date_orig >= $this_start AND date_orig <= $this_end"));
if ($rs->fields[0])
$asr = number_format(($rs->fields[0] / $rs1->fields[0]) * 100,3)." %";
else
$asr = "-";
2009-08-03 04:10:16 +00:00
$smarty->assign('asr', $asr);
# Number of CDRs for this period
$cdrs = $rs1->fields[0];
2009-08-03 04:10:16 +00:00
$smarty->assign('cdrs', number_format($cdrs,0));
# Avg. Successful Rate for last period
$rs = $db->Execute(sqlSelect($db, "voip_cdr", "count(*)", "disposition='ANSWERED' AND date_orig >= $last_start AND date_orig <= $last_end"));
$rs1 = $db->Execute(sqlSelect($db, "voip_cdr", "count(*)", "date_orig >= $last_start AND date_orig <= $last_end"));
if ($rs->fields[0])
$asr_last = number_format(($rs->fields[0] / $rs1->fields[0]) * 100,3)." %";
else
$asr_last = "-";
2009-08-03 04:10:16 +00:00
$smarty->assign('asr_last', $asr_last);
# Number of CDRS for last period
$cdrs_last = $rs1->fields[0];
2009-08-03 04:10:16 +00:00
$smarty->assign('cdrs_last', number_format($cdrs_last,0));
# Get Avg. Successful Rate change Percentage
if($asr > 0) $asr_change = $asr/$asr_last*100-100; else $asr_change = 0;
2009-08-03 04:10:16 +00:00
if($asr_change == 0)
$asr_change = '-';
elseif ($asr_change < 0)
$asr_change = '<font color="#990000">' . number_format($asr_change, 1). '%</font>';
2009-08-03 04:10:16 +00:00
else
$asr_change = '+'.number_format($asr_change, 1). '%';
$smarty->assign('asr_change', $asr_change);
2009-08-03 04:10:16 +00:00
# Get Number of CDRs change Percentage
if($cdrs > 0) $cdrs_change = $cdrs/$cdrs_last*100-100; else $cdrs_change = 0;
2009-08-03 04:10:16 +00:00
if($cdrs_change == 0)
$cdrs_change = '-';
elseif ($cdrs_change < 0)
$cdrs_change = '<font color="#990000">' . number_format($cdrs_change, 1). '%</font>';
2009-08-03 04:10:16 +00:00
else
$cdrs_change = '+'.number_format($cdrs_change, 1). '%';
$smarty->assign('cdrs_change', $cdrs_change);
}
2009-08-03 04:10:16 +00:00
# Generate the Calendar Overview
include_once(PATH_MODULES.'core/calendar.inc.php');
2009-08-03 04:10:16 +00:00
$calendar = new calendar;
$start = $calendar->start;
2009-08-03 04:10:16 +00:00
$end = $calendar->end;
global $C_list;
$C_list->currency(DEFAULT_CURRENCY);
$currency_symbol=$C_list->format_currency[DEFAULT_CURRENCY]['symbol'];
2009-08-03 04:10:16 +00:00
# Get the paid/due invoice statistics
$rs = $db->Execute($sql=sqlSelect($db,"invoice","date_orig,total_amt,billing_status,refund_status,billed_amt,suspend_billing","date_orig >= $start and date_orig <= $end"));
2009-08-03 04:10:16 +00:00
if($rs && $rs->RecordCount()) {
while(!$rs->EOF) {
$day = date("j", $rs->fields['date_orig']);
2009-08-03 04:10:16 +00:00
if($rs->fields['billed_amt'] > 0 && ($rs->fields['billing_status'] == 1 || $rs->fields['refund_status'] != 1)) {
$paid[$day] += $rs->fields['billed_amt'];
}
2009-08-03 04:10:16 +00:00
if ($rs->fields['billing_status'] != 1 && $rs->fields['refund_status'] != 1) {
$amt = $rs->fields['total_amt'] - $rs->fields['billed_amt'];
$due[$day] += $amt;
2009-08-03 04:10:16 +00:00
}
$rs->MoveNext();
2009-08-03 04:10:16 +00:00
}
if(is_array($paid))
2009-08-03 04:10:16 +00:00
foreach($paid as $day=>$item)
$calendar->add("<b>Paid</b> - {$currency_symbol}". number_format($item,2), $day, 'green', 'green');
2009-08-03 04:10:16 +00:00
if(is_array($due))
2009-08-03 04:10:16 +00:00
foreach($due as $day=>$item)
$calendar->add("<b>Due</b> - {$currency_symbol}". number_format($item,2), $day,'red','red');
}
2009-08-03 04:10:16 +00:00
# Get the upcoming due services
$rs = $db->Execute($sql=sqlSelect($db,"service","date_next_invoice,price","price > 0 AND date_next_invoice >= $start AND date_next_invoice <= $end AND suspend_billing <> 1"));
2009-08-03 04:10:16 +00:00
if($rs && $rs->RecordCount()) {
while(!$rs->EOF) {
2009-08-03 04:10:16 +00:00
$day = date("j", $rs->fields['date_next_invoice']);
$sdue[$day] += $rs->fields['price'];
$rs->MoveNext();
2009-08-03 04:10:16 +00:00
}
foreach($sdue as $day=>$item) {
$calendar->add("<b>Recurring</b> - {$currency_symbol}". number_format($item,2), $day, 'grey', 'grey');
2009-08-03 04:10:16 +00:00
}
}
$calout= $calendar->generate();
$smarty->assign("calendar", $calout);
2009-08-03 04:10:16 +00:00
return;
}
/** AUTO APPROVE INVOICE
*/
function autoApproveInvoice($invoice_id)
{
$do = false;
# Get the invoice details:
$db = &DB();
$q = "SELECT * FROM ".AGILE_DB_PREFIX."invoice WHERE
id = ".$db->qstr($invoice_id)." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$invoice = $db->Execute($q);
if ($invoice === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'autoApproveInvoice', $db->ErrorMsg());
return false;
}
# Get the checkout details:
$q = "SELECT * FROM ".AGILE_DB_PREFIX."checkout WHERE
id = ".$db->qstr($invoice->fields['checkout_plugin_id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$checkout = $db->Execute($q);
if ($checkout === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'autoApproveInvoice', $db->ErrorMsg());
return false;
}
# Get the account details:
$q = "SELECT * FROM ".AGILE_DB_PREFIX."account WHERE
id = ".$db->qstr($invoice->fields['account_id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$account = $db->Execute($q);
if ($account === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'autoApproveInvoice', $db->ErrorMsg());
return false;
}
# is this a recurring invoices, and is manual approvale req?
2009-08-03 04:10:16 +00:00
if ($invoice->fields['type'] == 1 && $checkout->fields['manual_approval_recur'] != 1) {
$do = true;
}
# Manual approval required for all?
2009-08-03 04:10:16 +00:00
if($invoice->fields['type'] != 1 && $checkout->fields['manual_approval_all'] != 1) {
$do = true;
}
if(!$do) {
# manual approval req. for invoice amount?
if(!empty($checkout->fields['manual_approval_amount']) && $do == true)
if($checkout->fields['manual_approval_amount'] <= $invoice->fields['total_amt'])
$do = false;
# manual approval req. for user's country?
if(!empty($checkout->fields['manual_approval_country']) && $do == true) {
$arr = unserialize($checkout->fields['manual_approval_country']);
for($i=0; $i<count($arr); $i++) {
if($account->fields['country_id'] == $arr[$i])
$do = false;
}
}
# manual approval req. for user's currency?
if(!empty($checkout->fields['manual_approval_currency']) && $do == true) {
$arr = unserialize($checkout->fields['manual_approval_currency']);
for($i=0; $i<count($arr); $i++) {
if($invoice->fields['actual_billed_currency_id'] == $arr[$i])
$do = false;
}
}
# manual approval req. for user's group(s)?
if(!empty($checkout->fields['manual_approval_group']) && $do == true) {
# Get the group details:
$q = "SELECT group_id FROM ".AGILE_DB_PREFIX."account_group WHERE
account_id = ".$db->qstr($invoice->fields['account_id'])." AND
active = ".$db->qstr('1')." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$groups = $db->Execute($q);
if ($groups === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'autoApproveInvoice', $db->ErrorMsg());
}
$arr = unserialize($checkout->fields['manual_approval_group']);
while(!$groups->EOF) {
for($i=0; $i<count($arr); $i++) {
$idx = $groups->fields["group_id"];
if($idx == $arr[$i])
$do = false;
}
$groups->MoveNext();
}
}
}
if ($do)
{
# Approve the invoice
$arr['id'] = $invoice_id;
$this->approveInvoice($arr, $this);
}
else
{
# Admin manual approval notice
include_once(PATH_MODULES.'email_template/email_template.inc.php');
$mail = new email_template;
$mail->send('invoice_manual_auth_admin', $invoice->fields['account_id'], $invoice->fields['id'], $invoice->fields['checkout_plugin_id'], '');
}
}
/* APPROVE INVOICE
*/
function approveInvoice($VAR)
{
# Get the invoice details:
$db = &DB();
$q = "SELECT * FROM ".AGILE_DB_PREFIX."invoice WHERE
id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$invoice = $db->Execute($q);
if ($invoice === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'approveInvoice', $db->ErrorMsg());
return false;
}
# Validate invoice exists & needs approval:
if($invoice->fields['id'] != $VAR['id'] || $invoice->fields['process_status'] == '1') return false;
# Update the invoice approval status:
$q = "UPDATE ".AGILE_DB_PREFIX."invoice SET
date_last = ".$db->qstr(time()).",
process_status = ".$db->qstr('1')." WHERE
id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$result = $db->Execute($q);
if ($result === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'approveInvoice', $db->ErrorMsg());
return false;
}
# Send approval notice to user:
include_once(PATH_MODULES.'email_template/email_template.inc.php');
$mail = new email_template;
$mail->send('invoice_approved_user', $invoice->fields['account_id'], $VAR['id'], '', '');
# Include the service class
include_once(PATH_MODULES.'service/service.inc.php');
$srvc = new service;
# Determine if services have already been created for this invoice:
2009-08-03 04:10:16 +00:00
if($invoice->fields['type'] != 1)
{
$q = "SELECT id FROM ".AGILE_DB_PREFIX."service WHERE
invoice_id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$service = $db->Execute($q);
if ($service === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'approveInvoice', $db->ErrorMsg());
return false;
}
if ($service->RecordCount() > 0)
{
# Update services to approved status:
while(!$service->EOF)
{
$srvc->approveService($service->fields['id']);
$service->MoveNext();
}
return true;
}
# Get the parent items in this invoice :
$q = "SELECT * FROM ".AGILE_DB_PREFIX."invoice_item WHERE
2009-08-03 04:10:16 +00:00
(parent_id = 0 OR parent_id IS NULL OR parent_id = '') AND
invoice_id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$ii = $db->Execute($q);
if ($ii === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'approveInvoice', $db->ErrorMsg());
return false;
}
while(!$ii->EOF)
{
if(empty($ii->fields['service_id']))
{
# Add the service
$srvc->invoiceItemToService($ii->fields['id'], $invoice);
# Check for any children items in this invoice:
$q = "SELECT * FROM ".AGILE_DB_PREFIX."invoice_item WHERE
parent_id = ".$db->qstr($ii->fields['id'])." AND
invoice_id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$iii = $db->Execute($q);
if ($iii === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'approveInvoice', $db->ErrorMsg());
return false;
}
while(!$iii->EOF)
{
# Add the service
$srvc->invoiceItemToService($ii->fields['id'], $invoice);
$iii->MoveNext();
}
}
else
{
$srvc = new service;
2009-08-03 04:10:16 +00:00
if($ii->fields['item_type'] == 2 && $ii->fields['domain_type'] == 'renew') {
# this is a domain renewal
2009-08-03 04:10:16 +00:00
$srvc->renewDomain($ii, $invoice->fields['account_billing_id']);
} else {
# this is an upgrade for an existing service
2009-08-03 04:10:16 +00:00
$srvc->modifyService($ii, $invoice->fields['account_billing_id']);
}
}
$ii->MoveNext();
}
}
2009-08-03 04:10:16 +00:00
elseif ($invoice->fields['type'] == 1)
{
# recurring invoice, just update assoc services
# Loop through invoice items & approve assoc services
$q = "SELECT service_id FROM ".AGILE_DB_PREFIX."invoice_item WHERE
invoice_id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$service = $db->Execute($q);
if ($service === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'voidInvoice', $db->ErrorMsg());
return false;
}
if ($service->RecordCount() > 0)
{
# Include the service class
include_once(PATH_MODULES.'service/service.inc.php');
$srvc = new service;
# Update services to inactive status:
while(!$service->EOF) {
$srvc->approveService($service->fields['service_id']);
$service->MoveNext();
}
}
}
# get account id
if(defined("SESS_ACCOUNT"))
$account_id = SESS_ACCOUNT;
else
$account_id = 0;
# if approved, create a memo
$id = $db->GenID(AGILE_DB_PREFIX . 'invoice_memo_id');
$q = "INSERT INTO ".AGILE_DB_PREFIX."invoice_memo
SET
id = ".$db->qstr($id).",
site_id = ".$db->qstr(DEFAULT_SITE).",
date_orig = ".$db->qstr(time()).",
invoice_id = ".$db->qstr($VAR['id']).",
account_id = ".$db->qstr($account_id).",
type = ".$db->qstr('approval').",
memo = ".$db->qstr('NA');
$memo = $db->Execute($q);
if ($memo === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'approveInvoice', $db->ErrorMsg());
return false;
}
return true;
}
/** VOID INVOICE
*/
function voidInvoice($VAR)
{
# Update the invoice approval status:
$db = &DB();
$q = "UPDATE ".AGILE_DB_PREFIX."invoice SET
date_last = ".$db->qstr(time()).",
process_status = ".$db->qstr('0')." WHERE
id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$update = $db->Execute($q);
if ($update === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'voidInvoice', $db->ErrorMsg());
return false;
}
# Determine if services have already been created for this invoice and deactivate:
$q = "SELECT id FROM ".AGILE_DB_PREFIX."service WHERE
invoice_id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$service = $db->Execute($q);
if ($service === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'voidInvoice', $db->ErrorMsg());
return false;
}
if ($service->RecordCount() > 0)
{
# Include the service class
include_once(PATH_MODULES.'service/service.inc.php');
$srvc = new service;
# Update services to inactive status:
while(!$service->EOF) {
$srvc->voidService($service->fields['id']);
$service->MoveNext();
}
}
# Loop through invoice items & delete assoc services
$q = "SELECT service_id FROM ".AGILE_DB_PREFIX."invoice_item WHERE
invoice_id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$service = $db->Execute($q);
if ($service === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'voidInvoice', $db->ErrorMsg());
return false;
}
if ($service->RecordCount() > 0)
{
# Include the service class
include_once(PATH_MODULES.'service/service.inc.php');
$srvc = new service;
# Update services to inactive status:
while(!$service->EOF) {
$srvc->voidService($service->fields['service_id']);
$service->MoveNext();
}
2009-08-03 04:10:16 +00:00
}
# if voided, create a memo
$id = $db->GenID(AGILE_DB_PREFIX . 'invoice_memo_id');
$q = "INSERT INTO ".AGILE_DB_PREFIX."invoice_memo
SET
id = ".$db->qstr($id).",
site_id = ".$db->qstr(DEFAULT_SITE).",
date_orig = ".$db->qstr(time()).",
invoice_id = ".$db->qstr($VAR['id']).",
account_id = ".$db->qstr(SESS_ACCOUNT).",
type = ".$db->qstr('void').",
memo = ".$db->qstr('NA');
$insert = $db->Execute($q);
if ($insert === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'voidInvoice', $db->ErrorMsg());
return false;
}
return true;
}
/** RECONCILE INVOICE
*/
function reconcile($VAR)
{
global $C_translate, $C_debug;
# validate amt
2009-08-03 04:10:16 +00:00
if($VAR['amount'] <= 0) {
$C_debug->alert("Payment amount to low!");
return false;
}
# get the invoice details
$db = &DB();
$sql = 'SELECT * FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
id = ' . $db->qstr($VAR['id']) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
if ($rs === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'reconcileInvoice', $db->ErrorMsg());
return false;
}
if(@$rs->RecordCount() == 0) return false;
$amt = $VAR['amount'];
$total_amt = $rs->fields['total_amt'];
$billed_amt = $rs->fields['billed_amt'];
$billed_currency_id = $rs->fields['billed_currency_id'];
$actual_billed_amt = $rs->fields['actual_billed_amt'];
$actual_billed_currency_id = $rs->fields['actual_billed_currency_id'];
$due = $total_amt - $billed_amt;
$overpaid = false;
if($amt > $due)
{
$billed = 1;
$update = $total_amt;
$overpaid = $amt - $due;
$C_translate->value['invoice']['amt'] = number_format($overpaid, 2);
$alert = $C_translate->translate('rec_over','invoice','');
}
elseif ($amt == $due)
{
$billed = 1;
$update = $total_amt;
}
else
{
$billed = 0;
$update = $amt + $billed_amt;
}
# Update the invoice record
$sql = 'UPDATE ' . AGILE_DB_PREFIX . 'invoice
SET
2009-08-03 04:10:16 +00:00
billed_amt = ' . $db->qstr($update) . ',
billing_status = ' . $db->qstr($billed) . '
WHERE
2009-08-03 04:10:16 +00:00
id = ' . $db->qstr($VAR['id']) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$db->Execute($sql);
2009-08-03 04:10:16 +00:00
# Create a memo
$id = $db->GenID(AGILE_DB_PREFIX . 'invoice_memo_id');
$q = "INSERT INTO ".AGILE_DB_PREFIX."invoice_memo
SET
id = ".$db->qstr($id).",
site_id = ".$db->qstr(DEFAULT_SITE).",
date_orig = ".$db->qstr(time()).",
invoice_id = ".$db->qstr($VAR['id']).",
account_id = ".$db->qstr(SESS_ACCOUNT).",
type = ".$db->qstr('reconcile').",
memo = ".$db->qstr('+ '.number_format($VAR['amount'],2) . " \r\n" . @$VAR['memo']);
$db->Execute($q);
2009-08-03 04:10:16 +00:00
# Reciept printing
include_once PATH_MODULES.'invoice/receipt_print.php';
$receipt = new receipt_print;
$receipt->add($rs, number_format($VAR['amount'],2), number_format($update,2));
2009-08-03 04:10:16 +00:00
# Auto update if billed complete
if($billed)
{
$this->autoApproveInvoice($VAR['id']);
# Get the default currency ISO
$q = "SELECT ".AGILE_DB_PREFIX."invoice_memo
SET
id = ".$db->qstr($id).",
site_id = ".$db->qstr(DEFAULT_SITE).",
date_orig = ".$db->qstr(time()).",
invoice_id = ".$db->qstr($VAR['id']).",
account_id = ".$db->qstr(SESS_ACCOUNT).",
type = ".$db->qstr('reconcile').",
memo = ".$db->qstr('+ '.number_format($VAR['amount'],2) . " \r\n" . @$VAR['memo']);
$currency = $db->Execute($q);
# User invoice creation confirmation
include_once(PATH_MODULES.'email_template/email_template.inc.php');
$email = new email_template;
$email->send('invoice_paid_user', $rs->fields['account_id'], $VAR['id'], $rs->fields['billed_currency_id'], '');
# Admin alert of payment processed
$email = new email_template;
$email->send('admin->invoice_paid_admin', $rs->fields['account_id'], $VAR['id'], $rs->fields['billed_currency_id'], '');
}
# Redirect
if(!empty($VAR['redirect']))
{
echo '
<script language="JavaScript">
window.parent.location=\''.$VAR['redirect'].'\'; ';
if(!empty($alert))
echo 'alert(\''.$alert.'\');';
echo '</script>';
exit;
}
$msg = $C_translate->translate('ref_comp','invoice','');
2009-08-03 04:10:16 +00:00
$C_debug->alert($msg);
return;
}
2009-08-03 04:10:16 +00:00
/** REFUND INVOICE
*/
function refund($VAR)
{
global $C_translate, $C_debug;
# validate amt
2009-08-03 04:10:16 +00:00
if($VAR['amount'] <= 0) {
$C_debug->alert("Refund amount to low!");
return false;
}
# get the invoice details
$db = &DB();
$sql = 'SELECT * FROM ' . AGILE_DB_PREFIX . 'invoice WHERE
2009-08-03 04:10:16 +00:00
id = ' . $db->qstr($VAR['id']) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$rs = $db->Execute($sql);
if(@$rs->RecordCount() == 0) return false;
$amt = $VAR['amount'];
$total_amt = $rs->fields['total_amt'];
$billed_amt = $rs->fields['billed_amt'];
$billed_currency_id = $rs->fields['billed_currency_id'];
$actual_billed_amt = $rs->fields['actual_billed_amt'];
$actual_billed_currency_id = $rs->fields['actual_billed_currency_id'];
$update = $billed_amt - $amt;
if($update>0) $billing_status=1; else $billing_status=0;
2009-08-03 04:10:16 +00:00
# Update the invoice record
echo $sql = 'UPDATE ' . AGILE_DB_PREFIX . 'invoice
SET
2009-08-03 04:10:16 +00:00
billed_amt = '.$db->qstr($update).',
billing_status = '.$billing_status.',
suspend_billing = 1,
2009-08-03 04:10:16 +00:00
refund_status = 1
WHERE
2009-08-03 04:10:16 +00:00
id = ' . $db->qstr($VAR['id']) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$update2 = $db->Execute($sql);
if ($update2 === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'refundInvoice', $db->ErrorMsg());
return false;
}
# Create a memo
$id = $db->GenID(AGILE_DB_PREFIX . 'invoice_memo_id');
$q = "INSERT INTO ".AGILE_DB_PREFIX."invoice_memo
SET
id = ".$db->qstr($id).",
site_id = ".$db->qstr(DEFAULT_SITE).",
date_orig = ".$db->qstr(time()).",
invoice_id = ".$db->qstr($VAR['id']).",
account_id = ".$db->qstr(SESS_ACCOUNT).",
type = ".$db->qstr('refund').",
memo = ".$db->qstr('- '.number_format($VAR['amount'],2) . " \r\n" . @$VAR['memo']);
$insert = $db->Execute($q);
if ($insert === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'refundInvoice', $db->ErrorMsg());
return false;
}
# Void:
$this->voidInvoice($VAR, $this);
2009-08-03 04:10:16 +00:00
# Call into the checkout plugin and attempt realtime refund
$billing = $db->Execute($sql=sqlSelect($db, array('account_billing','checkout'), 'A.*,B.checkout_plugin',
"A.id = ::{$rs->fields['account_billing_id']}:: AND A.checkout_plugin_id=B.id"));
if($billing && $billing->RecordCount() && !empty($billing->fields['checkout_plugin'])) {
$plugin_file = PATH_PLUGINS.'checkout/'. $billing->fields['checkout_plugin'] .'.php';
if(is_file($plugin_file)) {
2009-08-03 04:10:16 +00:00
include_once ($plugin_file);
eval('$PLG = new plg_chout_' . $billing->fields['checkout_plugin'] . '("'.$billing->fields['checkout_plugin_id'].'");');
if(is_callable(array($PLG,"refund"))) $PLG->refund($rs->fields, $billing->fields, $amt);
}
}
# Redirect
if(!empty($VAR['redirect'])) {
echo ' <script language="JavaScript"> window.parent.location=\''.$VAR['redirect'].'\'; </script>';
return;
}
2009-08-03 04:10:16 +00:00
$msg = $C_translate->translate('ref_comp','invoice','');
2009-08-03 04:10:16 +00:00
$C_debug->alert($msg);
return;
}
# Get translated/hardcoded line item description for PDF invoice
2009-08-03 04:10:16 +00:00
# @uses CORE_list;
private function getLineItemDesc($sku,$id,$domain=false,$item_name) {
if (! empty($item_name))
return $item_name;
global $C_translate;
2009-08-03 04:10:16 +00:00
if (! empty($sku) && in_array($sku,array('DOMAIN-PARK','DOMAIN-TRANSFER','DOMAIN-REGISTER','DOMAIN-RENEW'))) {
switch ($sku) {
case 'DOMAIN-REGISTER': $name = $C_translate->translate('register','cart',''); break;
case 'DOMAIN-TRANSFER': $name = $C_translate->translate('transfer','cart',''); break;
case 'DOMAIN-PARK': $name = $C_translate->translate('park','cart',''); break;
case 'DOMAIN-RENEW': $name = $C_translate->translate('renew','cart',''); break;
}
if ($domain)
return sprinf("%s\r\n ( %s )",$domain,$name);
else
return $name;
} else {
include_once(PATH_CORE.'list.inc.php');
2009-08-03 04:10:16 +00:00
$C_list = new CORE_list;
if (empty($this->product_desc[$id])) {
$desc = $C_list->translate('product_translate','name','product_id',$id,'translate_product');
$this->product_desc[$id] = $desc['name'];
}
2009-08-03 04:10:16 +00:00
if (! empty($this->product_desc[$id]))
return $this->product_desc[$id];
else
return $sku ? $sku : 'Other Item';
}
}
// @todo: To be depreciated
function delivery_task() {
return $this->task_mail_invoices();
}
/**
* Task based function to e-mail or store printable PDF of all unprinted invoices
2009-08-03 04:10:16 +00:00
* @todo This seems to be hard limited to do 100 invoices in a run - why? (make it configurable, or remove the limit?)
*/
2009-08-03 04:10:16 +00:00
public function task_mail_invoices() {
# Get all unprinted invoices
$db = &DB();
$rs = $db->SelectLimit(sqlSelect($db,array('invoice','account'),
'A.id,B.email,B.first_name,B.last_name,B.invoice_delivery,B.invoice_show_itemized',
'(A.billing_status=0 OR A.billing_status IS NULL) AND (A.print_status=0 OR A.print_status=NULL) and A.account_id=B.id and (B.invoice_delivery IS NOT NULL AND B.invoice_delivery>0)'),100);
2009-08-03 04:10:16 +00:00
if ($rs && $rs->RecordCount()) {
# Send the e-mail....
require_once(PATH_INCLUDES.'phpmailer/class.phpmailer.php');
$mail = new PHPMailer();
2009-08-03 04:10:16 +00:00
$mail->From = SITE_EMAIL;
$mail->FromName = SITE_NAME;
/*
$mail->SMTPAuth = true;
$mail->Host = "smtp.domain.com";
$mail->Username = "user";
$mail->Password = "pass";
$mail->Mailer = "smtp";
$mail->Debug = true;
*/
2009-08-03 04:10:16 +00:00
while (! $rs->EOF) {
if (! $pdf = $this->initInvoicePDF(array('id'=>$rs->fields['id'])))
continue;
$this->pdfInvoiceSummary($rs->fields['id'],$pdf);
switch ($rs->fields['invoice_delivery']) {
# Email Invoice
case 1:
$file = $pdf->Output(null,'S');
$mail->AddAddress($rs->fields['email'], sprintf('%s %s',$rs->fields['first_name'],$rs->fields['last_name']));
$mail->Subject = sprintf('%s %s: %s',SITE_NAME,_('Invoice'),$rs->fields['id']);
$mail->Body = sprintf("Please find the printable version of invoice number %s attached.\r\n\r\nThank you,\r\n%s",$rs->fields['id'],SITE_NAME);
$mail->AddStringAttachment($file,sprintf('%s.pdf',$this->getInvoiceID()),'base64','application/pdf');
if ($mail->Send())
$db->Execute(sqlUpdate($db,'invoice',array('print_status'=>1),array('id'=>$rs->fields['id'])));
else
printf('Unable to email invoice # %s to %s<br/>',$rs->fields['id'],$rs->fields['email']);
$mail->ClearAddresses();
$mail->ClearAttachments();
break;
# Print Invoice
case 2:
$file = tempnam(PATH_FILES,sprintf('pdf_inv_%s.pdf',$this->getInvoiceID()));
$pdf->Output($file,'F');
if (copy($file,sprintf('%sinvoice_%s.pdf',AGILE_PDF_INVOICE_PATH,$this->getInvoiceID())))
$db->Execute(sqlUpdate($db,'invoice',array('print_status'=>1),array('id'=>$rs->fields['id'])));
unlink($file);
break;
default:
printf('Unknown invoice_delivery: %s for %s<br/>',$rs->fields['invoice_delivery'],$rs->fields['id']);
}
2009-08-03 04:10:16 +00:00
$rs->MoveNext();
}
}
}
2009-08-03 04:10:16 +00:00
/**
* Initialise an invoice
*
* This function is responsible for getting all the information required to render an invoice.
*/
private function initInvoicePrint($VAR) {
# Check invoice
2009-08-03 04:10:16 +00:00
if (! isset($VAR['id'])) {
echo 'No Invoice Specified.';
2009-08-03 04:10:16 +00:00
return false;
}
# Check admin authentication:
global $C_auth;
2009-08-03 04:10:16 +00:00
$db = &DB();
if ($C_auth->auth_method_by_name('invoice','view') == false) {
# Validate on account level
2009-08-03 04:10:16 +00:00
$rs = $db->Execute(sqlSelect($db,'invoice','account_id',array('id'=>$VAR['id'])));
# @todo redirect to login page if not logged
if ($rs->fields['account_id'] != SESS_ACCOUNT)
return false;
}
2009-08-03 04:10:16 +00:00
$invoice = array();
#@todo this should be in setup_invoice
$invoice['site']['TAXID'] = SITE_TAXID;
$invoice['site']['NAME'] = SITE_NAME;
$invoice['site']['ADDRESS'] = SITE_ADDRESS;
$invoice['site']['CITY'] = SITE_CITY;
$invoice['site']['STATE'] = SITE_STATE;
$invoice['site']['ZIP'] = SITE_ZIP;
$invoice['site']['FAX'] = SITE_FAX;
$invoice['site']['PHONE'] = SITE_PHONE;
$invoice['site']['EMAIL'] = SITE_EMAIL;
$invoice['site']['URL'] = URL;
# Invoice Configuration
$rs = $db->Execute(sqlSelect($db,'setup_invoice','*',''));
$invoice['invcfg'] = $rs->fields;
# Invoice details
$rs = $db->Execute($a=sqlSelect($db,array('invoice','currency'),'A.*,B.symbol',sprintf('A.id=%s AND B.id=A.billed_currency_id',$VAR['id'])));
$invoice['invoice'] = $rs->fields;
# Account detail:
$rs = $db->Execute($q = sqlSelect($db,'account','*',array('id'=>$invoice['invoice']['account_id'])));
$invoice['account'] = $rs->fields;
# Invoice Item details
$invoice['invoiceitems'] = array();
$rs = $db->Execute($b=sqlSelect($db,'invoice_item','*',array('invoice_id'=>$VAR['id'])));
while (! $rs->EOF) {
array_push($invoice['invoiceitems'],$rs->fields);
$rs->moveNext();
}
# Get previous invoices
$invoice['previousinvoices'] = array();
$rs = $db->Execute($q=sqlSelect($db,'invoice','*',sprintf('account_id=%s AND (billed_amt < total_amt OR billed_amt IS NULL) AND date_orig < %s',
$invoice['invoice']['account_id'],$invoice['invoice']['date_orig'])));
while (! $rs->EOF) {
array_push($invoice['previousinvoices'],$rs->fields);
$rs->moveNext();
}
# If we get here, all is OK.
return $invoice;
}
/**
* Initialise a PDF invoice
*
* This function is resonsible for setting up a PDF invoice
*/
private function initInvoicePDF($VAR) {
# Get our invoice details
if (! $this->print = $this->initInvoicePrint($VAR))
return false;
#@todo since the view template dynamic finds available plugins, this should also find the plugin (incase the prefix/dir is moved).
require_once(sprintf('%sinvoice/PDF/pdf_invoice_%s.inc.php',PATH_MODULES,$this->print['invcfg']['invoice_pdf_plugin']));
$pdf = new pdf_invoice_overview($this);
#@todo This should be deprecated
$null = false;
$pdf->load_setup($null);
if ($pdf->getTemplate()) {
$pagecount = $pdf->setSourceFile($pdf->getTemplate());
$tplidx = $pdf->ImportPage(1);
}
$pdf->addPage();
2009-08-03 04:10:16 +00:00
# If we are using FPDI
if (isset($tplidx))
$pdf->useTemplate($tplidx);
# If we get here, all is OK.
return $pdf;
}
/**
* Display a PDF invoice in the browser for download.
*/
public function pdf($VAR) {
if (! $pdf = $this->initInvoicePDF($VAR))
return false;
$this->pdfInvoiceSummary($VAR['id'],$pdf);
$pdf->Output(sprintf('%s.pdf',$this->getInvoiceID()),'I');
}
/** Export multiple invoices */
2009-08-03 04:10:16 +00:00
function pdfExport(&$rs)
{
$db =& DB();
$invcfg = $db->Execute(sqlSelect($db,"setup_invoice","*",""));
2009-08-03 04:10:16 +00:00
ob_start();
$pdf = new pdf_invoice_overview();
$pdf->companyName = SITE_NAME;
$pdf->companyAddress = SITE_ADDRESS;
$pdf->companyCity = SITE_CITY;
$pdf->companyState = SITE_STATE;
2009-08-03 04:10:16 +00:00
$pdf->companyZip = SITE_ZIP;
$pdf->load_setup($invcfg);
if ($pdf->getTemplate())
$pagecount = $pdf->setSourceFile($pdf->getTemplate());
2009-08-03 04:10:16 +00:00
$tplidx = $pdf->ImportPage(1);
while(!$rs->EOF) {
$pdf->addPage();
2009-08-03 04:10:16 +00:00
$pdf->useTemplate($tplidx);
$this->pdfInvoiceSummary($rs->fields['id'], $pdf);
$rs->MoveNext();
unset($pdf->itemsSummary);
2009-08-03 04:10:16 +00:00
}
$pdf->Output();
2009-08-03 04:10:16 +00:00
ob_end_flush();
}
2009-08-03 04:10:16 +00:00
/**
* Render an invoice with the summary page
* @todo Draw discounts
* @todo Draw tax details
*/
private function pdfInvoiceSummary($id,$pdf) {
# Invoice details:
2009-08-03 04:10:16 +00:00
$db = &DB();
# Draw Invoice Basics
$pdf->drawCompanyLogo();
$pdf->drawCompanyAddress($this);
$pdf->drawInvoiceHeader($this);
$pdf->drawNews($this->print['invcfg']['news']);
$pdf->drawRemittenceStub($this);
$pdf->drawPaymentMethods($this);
if ($this->print['invoice']['billing_status'] !=1 && $this->print['invoice']['suspend_billing'] != 1 && $this->print['invoice']['due_date'] <= time())
$pdf->drawInvoiceDueNotice();
elseif($this->print['invoice']['billing_status'] == 1)
$pdf->drawInvoicePaidNotice();
if ($this->getPreviousBalance())
$pdf->drawSummaryInvoicesDue($this->print['previousinvoices']);
$pdf->drawSummaryLineItems($this);
unset($pdf->itemsSummary);
2009-08-03 04:10:16 +00:00
# BEGIN loop for enumerating information in multiple ways on the invoice
$iteration = 0;
2009-08-03 04:10:16 +00:00
while ($pdf->drawLineItems_pre($iteration)) {
# Get the line items:
$items = $db->Execute(sqlSelect($db,'invoice_item','*',array('invoice_id'=>$this->getInvoiceNum())));
if ($items && $items->RecordCount()) {
while (! $items->EOF) {
# Get the date range if set
if (! empty($items->fields['date_start']) && ! empty($items->fields['date_stop'])) {
global $C_translate;
2009-08-03 04:10:16 +00:00
$C_translate->value('invoice','start',date(UNIX_DATE_FORMAT,$items->fields['date_start']));
$C_translate->value('invoice','stop',date(UNIX_DATE_FORMAT,$items->fields['date_stop']));
}
2009-08-03 04:10:16 +00:00
$cost = $items->fields['price_base'];
$total = $cost * $items->fields['quantity'];
2009-08-03 04:10:16 +00:00
$desc = $this->getLineItemDesc($items->fields['sku'],$items->fields['product_id'],strtolower($items->fields['domain_name'].'.'.$items->fields['domain_tld']),$items->fields['product_name']);
$line = array(
2009-08-03 04:10:16 +00:00
'name' => $desc,
'domain' => $items->fields['domain_name'],
'amount' => $cost,
'sku'=>$items->fields['sku'],
'qty'=>$items->fields['quantity'],
'cost'=>$cost,
'attr'=>$items->fields['product_attr'],
'price_type'=>$items->fields['price_type'],
'price_base'=>$items->fields['price_base'],
'item_type'=>$items->fields['item_type'],
2009-08-03 04:10:16 +00:00
'daterange'=>sprintf('%s - %s',date(UNIX_DATE_FORMAT,$items->fields['date_start']),date(UNIX_DATE_FORMAT,$items->fields['date_stop'])),
'total_amt'=>$items->fields['total_amt']
2009-08-03 04:10:16 +00:00
);
$pdf->drawLineItems($db,$line,$this->getInvoiceNum());
if ($items->fields['price_setup']) {
2009-08-03 04:10:16 +00:00
$desc .= ' Set-up Charge';
$total = $items->fields['price_setup'];
2009-08-03 04:10:16 +00:00
$line = array('name'=>$desc,'amount'=>$total,'qty'=>'1','sku'=>$items->fields['sku'],'cost'=>$total,'price_base'=>$total,'price_type'=>999);
$pdf->drawLineItems($db,$line,$this->getInvoiceNum());
}
2009-08-03 04:10:16 +00:00
$items->MoveNext();
}
2009-08-03 04:10:16 +00:00
}
if ($this->print['invoice']['discount_amt']) {
$desc = 'Discount';
2009-08-03 04:10:16 +00:00
$total = -($this->print['invoice']['discount_amt']);
$line = array('name'=>$desc,'amount'=>$total,'qty'=>'1','cost'=>$total,'price_base'=>$total,'price_type'=>999);
$pdf->drawLineItems($db,$line,$this->getInvoiceNum());
}
2009-08-03 04:10:16 +00:00
if ($this->print['invoice']['tax_amt']) {
$trs = $db->Execute(sqlSelect($db,array('invoice_item_tax','tax'),'A.amount,B.description',sprintf('A.tax_id=B.id AND A.invoice_id=%s',$this->getInvoiceNum())));
if ($trs && $trs->RecordCount()) {
$taxes = array();
while (! $trs->EOF) {
if (! isset($taxes[$trs->fields['description']]))
$taxes[$trs->fields['description']] = $trs->fields['amount'];
else
$taxes[$trs->fields['description']] += $trs->fields['amount'];
$trs->MoveNext();
}
2009-08-03 04:10:16 +00:00
foreach ($taxes as $txds=>$txamt) {
$line = array('name'=>$txds,'amount'=>$txamt,'total_amt'=>$txamt,'price_type'=>999);
$pdf->drawLineItems($db,$line,$this->getInvoiceNum());
}
}
}
2009-08-03 04:10:16 +00:00
# Increment the iteration
++$iteration;
}
2009-08-03 04:10:16 +00:00
# Custom functions:
2009-08-03 04:10:16 +00:00
$pdf->drawCustom();
unset($db);
}
2009-08-03 04:10:16 +00:00
/** RESEND DUE NOTICE
*/
function resend($VAR)
{
global $C_debug;
2009-08-03 04:10:16 +00:00
# User invoice creation confirmation
include_once(PATH_MODULES.'email_template/email_template.inc.php');
$mail = new email_template;
$mail->send('invoice_resend', $VAR['account_id'], $VAR['id'], '', '');
2009-08-03 04:10:16 +00:00
# Alert
$C_debug->alert('Sent payment due notice to user');
2009-08-03 04:10:16 +00:00
# Update invoice
$db = &DB();
$q = "SELECT notice_count FROM ".AGILE_DB_PREFIX."invoice WHERE
id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$rs = $db->Execute($q);
$count = $rs->fields['notice_count'] + 1;
$q = "UPDATE ".AGILE_DB_PREFIX."invoice SET
notice_count = ".$db->qstr($count)." WHERE
id = ".$db->qstr($VAR['id'])." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$rs = $db->Execute($q);
}
2009-08-03 04:10:16 +00:00
/**
2009-08-03 04:10:16 +00:00
* Generate all invoices for recurring services/charges/domains
*/
2009-08-03 04:10:16 +00:00
public function generate() {
# Check if charge module installed
global $C_list;
2009-08-03 04:10:16 +00:00
$isChargeInstalled = $C_list->is_installed('charge');
// get services to be billed grouped by account and date
2009-08-03 04:10:16 +00:00
if (! defined('MAX_INV_GEN_PERIOD') || MAX_INV_GEN_PERIOD <= 0)
$max_date = time()+86400;
else
$max_date = time()+(MAX_INV_GEN_PERIOD*86400);
#$p=AGILE_DB_PREFIX; $s=DEFAULT_SITE;
/*
$sql = "SELECT DISTINCT service.id as serviceId, account.id as accountId, invoice.id as invoiceId, from_unixtime(service.date_next_invoice,'%Y-%m-%d') as dayGroup
FROM {$p}service as service
JOIN {$p}account as account ON ( service.account_id=account.id and account.site_id={$s} )
LEFT JOIN {$p}invoice as invoice ON ( service.invoice_id=invoice.id and invoice.site_id={$s} )
2009-08-03 04:10:16 +00:00
WHERE service.site_id={$s}
AND service.active = 1
AND ( service.suspend_billing IS NULL OR service.suspend_billing = 0 )
AND ( service.date_next_invoice > 0 AND service.date_next_invoice IS NOT NULL )
2009-08-03 04:10:16 +00:00
AND
((
2009-08-03 04:10:16 +00:00
(account.invoice_advance_gen!='' OR account.invoice_advance_gen is not null) AND service.date_next_invoice <= (UNIX_TIMESTAMP(CURDATE())+(account.invoice_advance_gen*86400))
) OR (
(account.invoice_advance_gen='' OR account.invoice_advance_gen is null) AND service.date_next_invoice <= {$max_date}
))
2009-08-03 04:10:16 +00:00
ORDER BY accountId, dayGroup, serviceId";
*/
$db=&DB();
2009-08-03 04:10:16 +00:00
$rs = $db->Execute($sql = $this->sql_invoice_soon());
if (! $rs) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
} elseif($rs->RecordCount()) {
$ids = '';
$account = '';
$date = '';
$invoice = '';
while (! $rs->EOF) {
if ($ids && (($rs->fields['aid'] != $account) || ($rs->fields['invoice_date'] != $date))) {
$this->generateInvoices($ids,$account,$invoice,$isChargeInstalled);
$ids = '';
}
2009-08-03 04:10:16 +00:00
# Set the current account and date
$account = $rs->fields['aid'];
$invoice = $rs->fields['iid'];
$date = $rs->fields['invoice_date'];
# Add to id list
if ($ids)
$ids .= ','.$rs->fields['sid'];
else
$ids = $rs->fields['sid'];
$rs->MoveNext();
}
2009-08-03 04:10:16 +00:00
if ($ids)
$this->generateInvoices($ids,$account,$invoice,$isChargeInstalled);
}
2009-08-03 04:10:16 +00:00
// Generate invoices for any domains expiring in X days.
if ($C_list->is_installed('host_tld'))
$this->generateDomains();
return true;
}
2009-08-03 04:10:16 +00:00
public function generateinvoice_account($VAR) {
# Check if charge module installed
global $C_list;
$charge_installed = $C_list->is_installed('charge');
$db = &DB();
$rs = $db->Execute($q = $this->sql_invoice_soon(null,0,$VAR['account_id']));
if (! $rs) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
return;
}
# Set the invoice and date
$invoice = $rs->fields['iid'];
$date = $rs->fields['invoice_date'];
$ids = '';
while (! $rs->EOF) {
if ($ids && ($rs->fields['invoice_date'] != $date)) {
$this->generateInvoices($ids,$VAR['account_id'],$invoice,$charge_installed);
$ids = '';
}
# Add to id list
if ($ids)
$ids .= ',';
$ids .= $rs->fields['sid'];
$rs->MoveNext();
}
if ($ids)
$this->generateInvoices($ids,$VAR['account_id'],$invoice,$charge_installed);
if (isset($VAR['_page_next']))
define('REDIRECT_PAGE','?_page='.$VAR['_page_next']);
}
/**
* Generate an Invoice
*/
private function generateInvoices($ids,$account_id,$invoice_id,$charge_installed=false) {
if (empty($ids))
return false;
# Load required elements
include_once(PATH_MODULES.'service/service.inc.php');
$serviceObj = new service;
include_once(PATH_MODULES.'discount/discount.inc.php');
$discountObj = new discount;
include_once(PATH_MODULES.'tax/tax.inc.php');
$taxObj = new tax;
2009-08-03 04:10:16 +00:00
# Start a transaction
$db = &DB();
if (AGILE_DB_TYPE == 'mysqlt') {
$db->StartTrans();
2009-08-03 04:10:16 +00:00
if (! $db->hasTransactions) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$msg = "Transactions not supported in 'mysql' driver. Use 'mysqlt' or 'mysqli' driver";
$C_debug->alert($msg);
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,$msg);
return false;
}
}
2009-08-03 04:10:16 +00:00
# Generate an invoice id
$invoice = sqlGenID($db,'invoice');
# Check for any discounts for the parent invoice or account_id
# applied at checkout and should continue to be applied if recurring type discount
2009-08-03 04:10:16 +00:00
$discountObj->available_discounts($account_id,1,$invoice_id);
# Beginning totals
$sub_total = 0;
$total = 0;
$taxable_amount = 0;
$tax_amt = 0;
$discount_amt = 0;
# Get the full account and service and invoice details
$p=AGILE_DB_PREFIX; $s=DEFAULT_SITE;
2009-08-03 04:10:16 +00:00
$sql = "SELECT DISTINCT
service.id, service.parent_id, service.invoice_id, service.invoice_item_id, service.account_id, service.account_billing_id, service.product_id,
service.sku, service.active, service.bind, service.type, service.price, service.price_type, service.taxable, service.date_last_invoice, service.date_next_invoice,
service.recur_type, service.recur_schedule, service.recur_weekday, service.recur_week, service.domain_name,
service.domain_tld, service.domain_type, service.domain_term, service.prod_attr, service.prod_attr_cart,
account.currency_id, account.first_name, account.last_name, account.country_id, account.state, account.invoice_grace, account.invoice_advance_gen, account.affiliate_id as account_affiliate_id,
invoice.affiliate_id, invoice.campaign_id, invoice.reseller_id, invoice.checkout_plugin_id, invoice.checkout_plugin_data, invoice.billed_currency_id, invoice.actual_billed_currency_id
FROM {$p}service as service
JOIN {$p}account as account ON (service.account_id=account.id AND account.site_id={$s})
LEFT JOIN {$p}invoice as invoice ON (service.invoice_id=invoice.id AND invoice.site_id={$s})
WHERE service.id in ({$ids})";
$service = $db->Execute($sql);
if ($service === false) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
$db->FailTrans();
return false;
}
if ($service && $service->RecordCount()) {
while (! $service->EOF) {
if (empty($service->fields['billed_currency_id']))
$service->fields['billed_currency_id'] = DEFAULT_CURRENCY;
if (empty($service->fields['actual_billed_currency_id']))
$service->fields['actual_billed_currency_id'] = $service->fields['billed_currency_id'];
$this->account_id = $service->fields['account_id'];
$this->parent_id = $service->fields['invoice_id'];
$this->account_billing_id = $service->fields['account_billing_id'];
if (! empty($service->fields['account_affiliate_id']))
$this->affiliate_id = $service->fields['account_affiliate_id'];
else
$this->affiliate_id = $service->fields['affiliate_id'];
$this->campaign_id = $service->fields['campaign_id'];
$this->reseller_id = $service->fields['reseller_id'];
$this->checkout_plugin_id = $service->fields['checkout_plugin_id'];
$this->checkout_plugin_data = $service->fields['checkout_plugin_data'];
$this->billed_currency_id = $service->fields['billed_currency_id'];
$this->actual_billed_currency_id = $service->fields['actual_billed_currency_id'];
$this->invoice_grace = $service->fields['invoice_grace'];
$item_tax_amt = 0;
$item_total_amt = 0;
$item_discount_amt = 0;
# Gen item_id
$item = sqlGenID($db,'invoice_item');
# Calculate any recurring discounts for this item
$item_total_amt = $service->fields['price'];
$item_discount_amt = $discountObj->calc_all_discounts(1,$item,$service->fields['product_id'],$service->fields['price'],$service->fields['account_id'],$sub_total+$service->fields['price']);
$item_total_amt -= $item_discount_amt;
$sub_total += $item_total_amt;
$discount_amt += $item_discount_amt;
# Calculate any taxes for this item
if ($service->fields['taxable'] == 1) {
$item_tax_amt = 0;
$item_tax_arr = $taxObj->calculate($item_total_amt,$service->fields['country_id'],$service->fields['state']);
if (is_array($item_tax_arr))
foreach($item_tax_arr as $tx)
$item_tax_amt += $tx['rate'];
$tax_amt += $item_tax_amt;
}
2009-08-03 04:10:16 +00:00
# Calculate next invoice date
2009-08-03 04:10:16 +00:00
$next_invoice = $serviceObj->calcNextInvoiceDate($service->fields['date_next_invoice'],$service->fields['recur_schedule'],$service->fields['recur_type'],$service->fields['recur_weekday']);
$due_date = $service->fields['date_next_invoice'];
2009-08-03 04:10:16 +00:00
$recur_schedule = 0;
if (! empty($service->fields['recur_schedule']))
$recur_schedule = $service->fields['recur_schedule'];
# Create the invoice item
$itemrs = $db->Execute(sqlInsert($db,'invoice_item',array(
'date_orig'=>time(),
'invoice_id'=>$invoice,
'account_id'=>$service->fields['account_id'],
'service_id'=>$service->fields['id'],
'product_id'=>$service->fields['product_id'],
'product_attr'=>$service->fields['prod_attr'],
'product_attr_cart'=>$service->fields['prod_attr_cart'],
'sku'=>$service->fields['sku'],
'quantity'=>1,
'item_type'=>0,
'price_type'=>$service->fields['price_type'],
'price_base'=>$service->fields['price'],
'price_setup'=>0,
'recurring_schedule'=>$recur_schedule,
'date_start'=>$service->fields['date_next_invoice'],
'date_stop'=>$next_invoice,
'domain_name'=>$service->fields['domain_name'],
'domain_tld'=>$service->fields['domain_tld'],
'domain_type'=>$service->fields['domain_type'],
'tax_amt'=>$tax_amt,
'total_amt'=>$item_total_amt,
'discount_amt'=>$item_discount_amt
),$item));
if ($itemrs === false) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
$db->FailTrans();
return false;
}
# Insert tax records
$taxObj->invoice_item($invoice,$item,$service->fields['account_id'],@$item_tax_arr);
# Insert discount records
2009-08-03 04:10:16 +00:00
$discountObj->invoice_item($invoice,$item,$service->fields['account_id'],@$discountObj->discount_arr);
# Update the last & next invoice date for this service
$srvsrs = $db->Execute(sqlUpdate($db,'service',array('date_last_invoice'=>$service->fields['date_next_invoice'],'date_next_invoice'=>$next_invoice),array('id'=>$service->fields['id'])));
if ($srvsrs === false) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
$db->FailTrans();
return false;
}
# Get any charges for this service and create them as invoice items
if ($charge_installed) {
$sql = "SELECT * FROM ".AGILE_DB_PREFIX."charge WHERE (status=0 or status is null) and site_id=".DEFAULT_SITE." AND service_id = ".$service->fields['id']." AND date_orig < ". $service->fields['date_next_invoice'];
$charge = $db->Execute($sql);
2009-08-03 04:10:16 +00:00
if($charge && $charge->RecordCount()) {
while(!$charge->EOF) {
$item_tax_amt=0;
$item_total_amt=0;
$item_discount_amt=0;
2009-08-03 04:10:16 +00:00
// Calculate any recurring discounts for this charge item
2009-08-03 04:10:16 +00:00
$item_total_amt = ($charge->fields['quantity']*$charge->fields['amount']);
$item_discount_amt = $discountObj->calc_all_discounts(1, $item, $charge->fields['product_id'], $item_total_amt, $service->fields['account_id'], $sub_total+$item_total_amt);
$item_total_amt -= $item_discount_amt;
$sub_total += $item_total_amt;
2009-08-03 04:10:16 +00:00
$discount_amt += $item_discount_amt;
// calculate any taxes for this item
if($charge->fields['taxable'] == 1) {
2009-08-03 04:10:16 +00:00
$item_tax_amt=0;
$item_tax_arr = $taxObj->calculate($chargeamt, $service->fields['country_id'], $service->fields['state']);
if(is_array($item_tax_arr)) foreach($item_tax_arr as $tx) $item_tax_amt += $tx['rate'];
$tax_amt += $item_tax_amt;
}
// create the invoice item
$charge_item_id = sqlGenID($db, 'invoice_item');
2009-08-03 04:10:16 +00:00
$sql = "INSERT INTO {$p}invoice_item SET
id = $charge_item_id,
site_id = $s,
charge_id = {$charge->fields['id']},
date_orig = ".time().",
2009-08-03 04:10:16 +00:00
invoice_id = $invoice,
account_id = ".$this->account_id.",
service_id = ".$db->qstr($service->fields['id']).",
2009-08-03 04:10:16 +00:00
product_id = ".$db->qstr($charge->fields['product_id']).",
product_attr= ".$db->qstr($charge->fields['attributes']).",
sku = ".$db->qstr($service->fields['sku']).",
price_base = ".$db->qstr($charge->fields['amount']).",
quantity = ".$charge->fields['quantity'].",
item_type = 5,
price_type = 0,
2009-08-03 04:10:16 +00:00
price_setup = 0,
tax_amt = $item_tax_amt,
total_amt = $item_total_amt,
discount_amt= $item_discount_amt";
2009-08-03 04:10:16 +00:00
$itemrs=$db->Execute($sql);
if($itemrs === false) {global $C_debug; $C_debug->error('invoice.inc.php','generateInvoices()4', $sql . " \r\n\r\n " . @$db->ErrorMsg()); $db->FailTrans(); return false; }
2009-08-03 04:10:16 +00:00
# Insert tax records
2009-08-03 04:10:16 +00:00
$taxObj->invoice_item($invoice, $charge_item_id, $charge->fields['account_id'], @$item_tax_arr);
# Insert discount records
$discountObj->invoice_item($invoice, $charge_item_id, $charge->fields['account_id'], @$discountObj->discount_arr);
2009-08-03 04:10:16 +00:00
# update charge status
$chargers=$db->Execute("UPDATE ".AGILE_DB_PREFIX."charge set status=1 WHERE id={$charge->fields['id']} AND site_id=".DEFAULT_SITE);
if($chargers === false) {global $C_debug; $C_debug->error('invoice.inc.php','generateInvoices()2', $sql . " \r\n\r\n " . @$db->ErrorMsg()); $db->FailTrans(); return false; }
2009-08-03 04:10:16 +00:00
$charge->MoveNext();
2009-08-03 04:10:16 +00:00
}
}
}
$service->MoveNext();
}
# Add any taxes
$total = $sub_total+$tax_amt;
# Get invoice grace period from global/account
if (! empty($this->invoice_grace))
$grace_period = $this->invoice_grace;
else
$grace_period = GRACE_PERIOD;
$invoicers = $db->Execute($a=sqlInsert($db,'invoice',array(
'date_orig'=>time(),
'date_last'=>time(),
'notice_next_date'=>time(),
'type'=>1,
'process_status'=>0,
'billing_status'=>0,
'suspend_billing'=>0,
'print_status'=>0,
'refund_status'=>0,
'billed_amt'=>0,
'actual_billed_amt'=>0,
'notice_count'=>0,
'parent_id'=>$this->parent_id,
'account_id'=>$this->account_id,
'account_billing_id'=>$this->account_billing_id,
'affiliate_id'=>$this->affiliate_id,
'campaign_id'=>$this->campaign_id,
'reseller_id'=>$this->reseller_id,
'checkout_plugin_id'=>$this->checkout_plugin_id,
'checkout_plugin_data'=>$this->checkout_plugin_data,
'actual_billed_currency_id'=>$this->actual_billed_currency_id,
'billed_currency_id'=>$this->billed_currency_id,
'notice_max'=>MAX_BILLING_NOTICE,
'grace_period'=>$grace_period,
'tax_amt'=>$tax_amt,
'discount_amt'=>$discount_amt,
'total_amt'=>$total,
'due_date'=>$due_date
),$invoice));
if ($invoicers === false) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
$db->FailTrans();
return false;
}
2009-08-03 04:10:16 +00:00
}
if (AGILE_DB_TYPE == 'mysqlt')
$db->CompleteTrans();
}
2009-08-03 04:10:16 +00:00
/** Invoice expiring domains
*/
function generateDomains()
2009-08-03 04:10:16 +00:00
{
$db = &DB();
define('DEFAULT_DOMAIN_INVOICE', 30); //how far out to generate expiring domain invoices
$expire = time() + (DEFAULT_DOMAIN_INVOICE*86400);
2009-08-03 04:10:16 +00:00
### Get domains expiring soon:
$rs = $db->Execute( sqlSelect( $db, 'service', '*', " active=1 AND domain_date_expire <= $expire AND type = 'domain' AND queue = 'none' AND
( domain_type = 'register' OR domain_type = 'transfer' OR domain_type = 'renew' ) AND
( suspend_billing = 0 OR suspend_billing IS NULL) " ) );
2009-08-03 04:10:16 +00:00
if($rs && $rs->RecordCount() > 0 ) {
while(!$rs->EOF) {
# Check that this domain has not already been invoiced
2009-08-03 04:10:16 +00:00
$invoiced = $db->Execute(sqlSelect ($db, array('invoice_item','invoice'), array('A.*','B.*'),
" A.invoice_id = B.id AND A.service_id = {$rs->fields['id']} AND A.sku = 'DOMAIN-RENEW' AND domain_type = 'renew' AND
2009-08-03 04:10:16 +00:00
date_start = {$rs->fields['date_last_invoice']} AND date_stop = {$rs->fields['domain_date_expire']}" ) );
if($invoiced && $invoiced->RecordCount() == 0) {
# Not previously invoiced, generate now!
$this->generatedomaininvoice( $rs->fields, $this );
2009-08-03 04:10:16 +00:00
}
$rs->MoveNext();
}
}
}
2009-08-03 04:10:16 +00:00
/** Invoice expiring domains p2
*/
2009-08-03 04:10:16 +00:00
function generatedomaininvoice($VAR)
{
include_once(PATH_MODULES . 'tax/tax.inc.php');
$taxObj = new tax;
2009-08-03 04:10:16 +00:00
$db = &DB();
2009-08-03 04:10:16 +00:00
if( is_array( $VAR ) ) {
$expire = time();
2009-08-03 04:10:16 +00:00
$rs = $db->Execute(sqlSelect($db, 'service', '*', " id = ::{$VAR['id']}:: AND active=1
AND type = 'domain' AND queue = 'none' AND
2009-08-03 04:10:16 +00:00
(domain_type = 'register' OR domain_type = 'transfer' OR domain_type = 'renew') AND
(suspend_billing = 0 OR suspend_billing IS NULL) "));
$service = $rs->fields;
} else {
$service = $VAR;
2009-08-03 04:10:16 +00:00
}
if(empty($service['id'])) {
global $C_debug;
$C_debug->alert("Unable to generate domain renweal invoice due to domain status.");
return false;
}
2009-08-03 04:10:16 +00:00
# Get the parent invoice details:
if(!empty($service['invoice_id'])) {
2009-08-03 04:10:16 +00:00
$rs = $db->Execute(sqlSelect($db, 'invoice', '*', " id = {$service['invoice_id']} ", ""));
$invoice = $rs->fields;
} else {
$invoice = false;
}
2009-08-03 04:10:16 +00:00
# Get the account details:
2009-08-03 04:10:16 +00:00
$rs = $db->Execute(sqlSelect($db, 'account', '*', " id = {$service['account_id']} ", ""));
$account = $rs->fields;
2009-08-03 04:10:16 +00:00
# Get the account price
include_once(PATH_MODULES.'host_tld/host_tld.inc.php');
2009-08-03 04:10:16 +00:00
$tldObj=new host_tld;
$tld_arr = $tldObj->price_tld_arr($service['domain_tld'], 'renew', false, false, false, $service['account_id']);
foreach($tld_arr as $term => $price) break;
2009-08-03 04:10:16 +00:00
# Calculate taxes:
2009-08-03 04:10:16 +00:00
$rs = $db->Execute($sql=sqlSelect($db,"host_tld","taxable","name = ::{$service['domain_tld']}::"));
if( $service['taxable'] || @$rs->fields['taxable'] ) {
$tax_arr = $taxObj->calculate($price, $account["country_id"], $account["state"]);
} else {
$tax_arr = false;
}
2009-08-03 04:10:16 +00:00
$total = $price;
2009-08-03 04:10:16 +00:00
$tax_amt = 0;
if(is_array($tax_arr)) {
foreach($tax_arr as $tx) {
$tax_amt += $tx['rate'];
}
$total += $tax_amt;
}
2009-08-03 04:10:16 +00:00
# calculate the dates
$expire = $service['domain_date_expire'] + ($term*86400);
$due_date = $service['domain_date_expire'] - (86400*3);
2009-08-03 04:10:16 +00:00
# Create the invoice
2009-08-03 04:10:16 +00:00
$id = sqlGenID($db, "invoice");
$insert = $db->Execute($sql = sqlInsert($db, "invoice",
array(
'date_orig' => time(),
'date_last' => time(),
'type' => 2,
'process_status' => 0,
'billing_status' => 0,
'suspend_billing' => 0,
'print_status' => 0,
'parent_id' => $service['invoice_id'],
'account_id' => $service['account_id'],
'account_billing_id'=> $service['account_billing_id'],
'affiliate_id' => @$invoice['affiliate_id'],
'campaign_id' => @$invoice['campaign_id'],
'reseller_id' => @$invoice['reseller_id'],
'checkout_plugin_id'=> @$invoice['checkout_plugin_id'],
'tax_amt' => $tax_amt,
'discount_arr' => serialize(@$discount_arr),
'discount_amt' => @$discount_amt,
'total_amt' => $total,
'billed_amt' => 0,
'billed_currency_id'=> DEFAULT_CURRENCY,
'actual_billed_amt' => 0,
'actual_billed_currency_id' => @$invoice['actual_billed_currency_id'],
'notice_count' => 0,
'notice_next_date' => time(),
'notice_max' => MAX_BILLING_NOTICE,
'grace_period' => 0,
'due_date' => $due_date
2009-08-03 04:10:16 +00:00
), $id)) ;
# create the invoice item:
if($insert) {
2009-08-03 04:10:16 +00:00
$db->Execute ($idx = sqlInsert($db, "invoice_item",
array(
'date_orig' => time(),
'invoice_id' => $id,
'account_id' => $service['account_id'],
'service_id' => $service['id'],
'sku' => 'DOMAIN-RENEW',
'quantity' => 1,
'item_type' => 2,
'price_type' => 0,
'price_base' => $price,
'price_setup' => 0,
'domain_type' => 'renew',
'date_start' => $service['domain_date_expire'],
'date_stop' => $expire,
'domain_name' => $service['domain_name'],
'domain_tld' => $service['domain_tld'],
'domain_term' => $term,
'tax_amt' => $tax_amt,
'total_amt' => $price
2009-08-03 04:10:16 +00:00
)));
# Insert tax records
2009-08-03 04:10:16 +00:00
$taxObj->invoice_item($id, $idx, $service['account_id'], @$item_tax_arr);
# Update the service record
2009-08-03 04:10:16 +00:00
$fields=array('active' => 0);
$db->Execute(sqlUpdate($db,"service",$fields,"id = {$service['id']}"));
2009-08-03 04:10:16 +00:00
global $C_debug;
$C_debug->alert("Generated domain renewal invoice for {$service['domain_name']}.{$service['domain_tld']}");
return $id;
}
}
2009-08-03 04:10:16 +00:00
/** Run AutoBilling and Due Notices
*/
function autobill($VAR)
{
global $VAR, $C_debug, $C_list;
# User invoice creation confirmation
include_once(PATH_MODULES.'email_template/email_template.inc.php');
$mail = new email_template;
# get all due invoices
2009-08-03 04:10:16 +00:00
$db = &DB();
#$db->debug = true;
2009-08-03 04:10:16 +00:00
if(empty($VAR['invoice_id']))
{
$this->bill_one = false;
$sql = 'SELECT * FROM ' . AGILE_DB_PREFIX . 'invoice
2009-08-03 04:10:16 +00:00
WHERE notice_next_date <= ' . $db->qstr( time() ) . '
AND (
billing_status = 0 OR
billing_status IS NULL
2009-08-03 04:10:16 +00:00
) AND (
suspend_billing = 0 OR
suspend_billing IS NULL
2009-08-03 04:10:16 +00:00
)
AND site_id = ' . $db->qstr(DEFAULT_SITE);
$invoice = $db->Execute($sql);
if($invoice->RecordCount() == 0) {
$C_debug->alert('No Invoices to Autobill');
return false;
}
} else {
# get the specified invoice:
$this->bill_one = true;
$sql = 'SELECT * FROM ' . AGILE_DB_PREFIX . 'invoice
WHERE (
billing_status = 0 OR
billing_status IS NULL
2009-08-03 04:10:16 +00:00
)
AND id = ' . $db->qstr($VAR['invoice_id']) . '
AND site_id = ' . $db->qstr(DEFAULT_SITE);
$invoice = $db->Execute($sql);
}
# Check for results
if($invoice->RecordCount() == 0) {
$C_debug->alert('Invoice could not be billed!');
return false;
}
# Loop through results
while(!$invoice->EOF)
{
$db->StartTrans();
2009-08-03 04:10:16 +00:00
$due = true;
# get currency code
$cyid = $invoice->fields['actual_billed_currency_id'];
$billed_currency_id = $invoice->fields['billed_currency_id'];
if(empty($this->currency_iso[$cyid]))
{
$q = "SELECT three_digit,convert_array FROM ". AGILE_DB_PREFIX ."currency WHERE
id = ". $db->qstr($cyid)." AND
site_id = ". $db->qstr(DEFAULT_SITE);
$currb = $db->Execute($q);
2009-08-03 04:10:16 +00:00
$this->format_currency[$cyid] = array('convert' => unserialize($currb->fields["convert_array"]),
'iso' => $currb->fields["three_digit"]);
}
# get the currency codes (default)
if(empty($this->format_currency[$billed_currency_id]))
{
# Get the billed currency id currency info:
$q = "SELECT three_digit,convert_array FROM ".AGILE_DB_PREFIX."currency WHERE
id = ".$db->qstr($billed_currency_id)." AND
site_id = ".$db->qstr(DEFAULT_SITE);
$currb = $db->Execute($q);
2009-08-03 04:10:16 +00:00
$this->format_currency[$billed_currency_id] = array('convert' => unserialize($currb->fields["convert_array"]),
'iso' => $currb->fields["three_digit"]);
}
# attempt to autobill?
2009-08-03 04:10:16 +00:00
if(!empty($invoice->fields['account_billing_id']))
{
# get checkout plugin details:
$billing =& $db->Execute($sql=sqlSelect($db, array('account_billing','checkout'), 'A.*,B.checkout_plugin',
"A.id = ::{$invoice->fields['account_billing_id']}:: AND A.checkout_plugin_id=B.id"));
if($billing && $billing->RecordCount() == 1 && !empty($billing->fields['checkout_plugin'])) {
$plugin_file = PATH_PLUGINS.'checkout/'. $billing->fields['checkout_plugin'] .'.php';
if(!is_file($plugin_file)) {
$err = $plugin_file .' missing when autobilling invoice id ' . $invoice->fields['id'];
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,$err);
} else {
2009-08-03 04:10:16 +00:00
include_once ($plugin_file);
eval('$PLG = new plg_chout_' . $billing->fields['checkout_plugin'] . '("'.$billing->fields['checkout_plugin_id'].'");');
}
} else {
$err = 'account_billing.id '.$invoice->fields['account_billing_id'].' empty or not associated with a checkout plugin when autobilling invoice id ' . $invoice->fields['id'];
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,$err);
}
}
# get the actual billed amount
$amount = $invoice->fields['total_amt'] - $invoice->fields['billed_amt'];
$billed_amt = $invoice->fields['total_amt'];
$actual_billed_amt = $invoice->fields['total_amt'];
if($amount <= 0) $due = false;
if(!empty($PLG) && is_object($PLG) && $PLG->type == 'gateway' && $amount > 0)
2009-08-03 04:10:16 +00:00
{
# attempt autobilling if account billing exists and gateway plugin
2009-08-03 04:10:16 +00:00
if($invoice->fields['account_billing_id'] > 0)
{
/* get the account details */
$account = $db->Execute(sqlSelect($db,"account","id,email","id=::{$invoice->fields['account_id']}"));
2009-08-03 04:10:16 +00:00
/* Convert the invoice amount to the actual billed currency amount */
2009-08-03 04:10:16 +00:00
if($cyid != $invoice->fields['billed_currency_id']) {
$conversion = $this->format_currency[$billed_currency_id]["convert"][$cyid]["rate"];
$amount *= $conversion;
$actual_billed_amt = $invoice->fields['actual_billed_amt'] + $amount;
}
2009-08-03 04:10:16 +00:00
/* load the billing details from the database */
$PLG->setBillingFromDBObj($billing, true);
2009-08-03 04:10:16 +00:00
/* attempt to auto-bill */
if(!$checkout_plugin_data = $PLG->bill_checkout( number_format($amount,2), $invoice->fields['id'], $this->format_currency[$cyid]['iso'], $account->fields, 0,0) ) {
2009-08-03 04:10:16 +00:00
$due = true;
$email = new email_template;
$email->send('invoice_decline_user', $invoice->fields['account_id'], $invoice->fields['id'],$C_list->format_currency($invoice->fields['total_amt'],$cyid), $C_list->date($invoice->fields['due_date']));
$email = new email_template;
$email->send('admin->invoice_decline_admin', $invoice->fields['account_id'], $invoice->fields['id'], $C_list->format_currency($invoice->fields['total_amt'],''), $C_list->date($invoice->fields['due_date']));
} else {
$due = false;
}
}
}
# send proper alert & manage services
if ($due)
{
# determine if overdue
$due = $invoice->fields['due_date'];
$grace = $invoice->fields['grace_period'];
if(time() < $due+(86400*$grace))
{
if($invoice->fields['notice_count'] <= 0)
{
# send out first alert - new invoice created!
$email = new email_template;
$email->send('invoice_recur_user', $invoice->fields['account_id'], $invoice->fields['id'], $C_list->format_currency($invoice->fields['total_amt'],$cyid), $C_list->date($invoice->fields['due_date']));
$email = new email_template;
$email->send('admin->invoice_recur_admin', $invoice->fields['account_id'], $invoice->fields['id'], $C_list->format_currency($invoice->fields['total_amt'],''), $C_list->date($invoice->fields['due_date']));
}
else
{
# send out payment due notice
if(empty($PLG) || $PLG->type == 'gateway') {
$email = new email_template;
$email->send('invoice_due_user', $invoice->fields['account_id'], $invoice->fields['id'], $this->format_currency[$cyid]["iso"], $C_list->date($invoice->fields['due_date']));
$email = new email_template;
$email->send('admin->invoice_due_admin', $invoice->fields['account_id'], $invoice->fields['id'], $this->format_currency[$billed_currency_id]["iso"], $C_list->date($invoice->fields['due_date']));
}
elseif($PLG->type == 'redirect') {
$email = new email_template;
$email->send('invoice_due_user', $invoice->fields['account_id'], $invoice->fields['id'], $this->format_currency[$cyid]["iso"], $C_list->date($invoice->fields['due_date']));
} elseif ($PLG->type == 'other') {
$email = new email_template;
$email->send('admin->invoice_due_admin', $invoice->fields['account_id'], $invoice->fields['id'], $this->format_currency[$billed_currency_id]["iso"], $C_list->date($invoice->fields['due_date']));
}
}
# increment notice counter
$sql = 'UPDATE ' . AGILE_DB_PREFIX . 'invoice SET
notice_count = ' . $db->qstr($invoice->fields['notice_count']+1) . ',
notice_next_date = ' . $db->qstr(time()+86400*3) . '
WHERE
2009-08-03 04:10:16 +00:00
id = ' . $db->qstr($invoice->fields['id']) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$db->Execute($sql);
}
else
{
# send service cancelation notice
$email = new email_template;
$email->send('service_suspend_user', $invoice->fields['account_id'], $invoice->fields['id'], $C_list->format_currency($invoice->fields['total_amt'],$cyid), $C_list->date($invoice->fields['due_date']));
$email = new email_template;
$email->send('admin->service_suspend_admin', $invoice->fields['account_id'], $invoice->fields['id'], $C_list->format_currency($invoice->fields['total_amt'],''), $C_list->date($invoice->fields['due_date']));
# overdue - cancel services
$vara['id'] = $invoice->fields['id'];
$this->voidInvoice($vara, $this);
# suspend billing activity
$sql = 'UPDATE ' . AGILE_DB_PREFIX . 'invoice SET
notice_count = ' . $db->qstr($invoice->fields['notice_count']+1) . ',
suspend_billing = ' . $db->qstr('1') . '
WHERE
2009-08-03 04:10:16 +00:00
id = ' . $db->qstr($invoice->fields['id']) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
2009-08-03 04:10:16 +00:00
$db->Execute($sql);
}
}
else
{
# update billing stauts
$sql = 'UPDATE ' . AGILE_DB_PREFIX . 'invoice SET
notice_count = ' . $db->qstr($invoice->fields['notice_count']+1) . ',
billing_status = ' . $db->qstr('1') . ',
billed_amt = ' . $db->qstr($billed_amt) . ',
actual_billed_amt = ' . $db->qstr($actual_billed_amt) . '
WHERE
2009-08-03 04:10:16 +00:00
id = ' . $db->qstr($invoice->fields['id']) . ' AND
site_id = ' . $db->qstr(DEFAULT_SITE);
$db->Execute($sql);
# update invoice via autoapproveInvoice
$this->autoApproveInvoice($invoice->fields['id']);
# User alert of payment processed
$email = new email_template;
$email->send('invoice_paid_user', $invoice->fields['account_id'], $invoice->fields['id'], $this->format_currency[$cyid]['iso'], '');
# Admin alert of payment processed
$email = new email_template;
$email->send('admin->invoice_paid_admin', $invoice->fields['account_id'], $invoice->fields['id'], $this->format_currency[$billed_currency_id]['iso'], '');
}
$invoice->MoveNext();
unset($PLG);
2009-08-03 04:10:16 +00:00
/* finish transaction */
$db->CompleteTrans();
}
}
/**
* Find out if a user has unpaid invoices
*/
2009-08-03 04:10:16 +00:00
public function has_unpaid($VAR) {
global $smarty, $C_list;
if (! SESS_LOGGED)
return false;
$total = 0;
foreach ($this->unpaid(SESS_ACCOUNT) as $amount)
$total += $amount;
if ($total)
$smarty->assign('has_unpaid',$C_list->format_currency_num($total,SESS_CURRENCY));
}
/**
* Get the totals for multiple invoices or for a group of invoices stored in temp
2009-08-03 04:10:16 +00:00
*
* The retrieved invoice numbers are stored in $this->invoice;
*
* @param string If invoice is 'MULTI-*', get unpaid invoices from the temporary_data table, otherwise
* get the unpaid invoices listed, or all invoices if blank.
*/
2009-08-03 04:10:16 +00:00
private function multiple_invoice_total($invoice,$account_id=SESS_ACCOUNT) {
$this->invoice = array();
$db = &DB();
2009-08-03 04:10:16 +00:00
if (! preg_match('/^MULTI-/',$invoice)) {
$id_list='';
2009-08-03 04:10:16 +00:00
if ($invoice = preg_replace('/,$/','',$invoice))
$id_list = sprintf('id in (%s) AND',$invoice);
# Get invoice totals
$total = 0;
$rs = $db->Execute(sqlSelect($db,'invoice','id,total_amt,billed_amt',sprintf('%s account_id=%s AND billing_status=0 AND refund_status=0',$id_list,SESS_ACCOUNT)));
if ($rs && $rs->RecordCount()) {
while (! $rs->EOF) {
$this->invoice[$rs->fields['id']] = $rs->fields['total_amt']-$rs->fields['billed_amt'];
$total += $this->invoice[$rs->fields['id']];
$rs->MoveNext();
}
2009-08-03 04:10:16 +00:00
return $total;
}
2009-08-03 04:10:16 +00:00
} else {
2009-08-03 04:10:16 +00:00
# Get total from temp data
$rs = $db->Execute(sqlSelect($db,'temporary_data','data,field1',array('field2'=>$invoice)));
if ($rs && $rs->RecordCount() && $rs->fields['field1'] > 0) {
$this->invoice = unserialize($rs->fields['data']);
return $rs->fields['field1'];
}
}
2009-08-03 04:10:16 +00:00
return false;
}
/**
* Preview checkout of multiple invoices
*/
2009-08-03 04:10:16 +00:00
public function tpl_checkout_multiple_preview($VAR) {
global $smarty,$C_list;
2009-08-03 04:10:16 +00:00
if (! SESS_LOGGED)
return false;
# If the ID is blank, this will get all unpaid invoices.
if (! isset($VAR['id']))
$VAR['id'] = '';
$total = $this->multiple_invoice_total($VAR['id'],SESS_ACCOUNT);
$db = &DB();
if ($total > 0 && count($this->invoice) > 1) {
# Get country id for checkout options
$account = $db->Execute(sqlSelect($db,'account','country_id',array('id'=>SESS_ACCOUNT)));
# Get payment options
include_once(PATH_MODULES.'checkout/checkout.inc.php');
$checkout = new checkout;
2009-08-03 04:10:16 +00:00
$checkoutoptions = $checkout->get_checkout_options(SESS_ACCOUNT,$total,false,$account->fields['country_id'],true);
# Get a temporary id (48 hours)
$id = sqlGenID($db,'temporary_data');
$invoice['id'] = sprintf('MULTI-%s',$id);
$invoice['total'] = $total;
$fields = array('date_orig'=>time(),'date_expire'=>time()+86400*3,'field2'=>$invoice['id'],'field1'=>$total,'data'=>serialize($this->invoice));
$rs = $db->Execute($q=sqlInsert($db,'temporary_data',$fields,$id));
$smarty->assign('record',$invoice);
$smarty->assign('total',$C_list->format_currency_num($total,SESS_CURRENCY));
$smarty->assign('checkoutoptions',$checkoutoptions);
} elseif (count($this->invoice) == 1) {
printf("<script language=javascript>document.location.href='?_page=invoice:user_view&id=%s';</script>",key($this->invoice));
} else {
2009-08-03 04:10:16 +00:00
echo _('No due invoices selected for payment.');
}
}
2009-08-03 04:10:16 +00:00
/**
* Make a payment now
*/
public function checkoutnow($VAR) {
global $C_translate,$smarty,$C_list,$VAR;
# Validate user logged in:
2009-08-03 04:10:16 +00:00
if (SESS_LOGGED != '1') {
echo '<script type="text/javascript">alert("You must be logged in to complete this purchase! Please refresh this page in your browser to login now...");</script>';
return false;
}
2009-08-03 04:10:16 +00:00
# If the ID is blank, this will get all unpaid invoices.
if (! isset($VAR['invoice_id']))
return false;
# Some defaults
$recur_amt = 0;
$db = &DB();
if(preg_match('/^MULTI-/',@$VAR['invoice_id'])) {
# Get multi-invoice details
$total = $this->multiple_invoice_total($VAR['invoice_id'],SESS_ACCOUNT);
if (! $total)
return false;
$recur_arr = false;
$account_id = SESS_ACCOUNT;
$this->invoice_id = $VAR['invoice_id'];
$CURRENCY = DEFAULT_CURRENCY;
2009-08-03 04:10:16 +00:00
$multi = true;
} else {
# Validate the invoice selected, & get the totals:
2009-08-03 04:10:16 +00:00
$result = $db->Execute($q=sqlSelect($db,'invoice','*',array('id'=>$VAR['invoice_id'])));
if (! $result || $result->RecordCount() == 0)
return false;
# Determine the price & currency
2009-08-03 04:10:16 +00:00
if ($result->fields['billed_currency_id'] != $result->fields['actual_billed_currency_id']) {
global $C_list;
2009-08-03 04:10:16 +00:00
$CURRENCY = $result->fields['actual_billed_currency_id'];
if($result->fields['billed_amt'] <= 0)
2009-08-03 04:10:16 +00:00
$total = $C_list->format_currency_decimal($result->fields['total_amt'],$CURRENCY);
else
2009-08-03 04:10:16 +00:00
$total = $C_list->format_currency_decimal($result->fields['total_amt'],$CURRENCY)-$result->fields['actual_billed_amt'];
} else {
$CURRENCY = $result->fields['billed_currency_id'];
$total = $result->fields['total_amt']-$result->fields['billed_amt'];
}
2009-08-03 04:10:16 +00:00
if ($result->fields['recur_amt'] > 0)
$recur_amt = $C_list->format_currency_decimal($result->fields['recur_amt'],$CURRENCY);
@$recur_arr = unserialize($result->fields['recur_arr']);
$account_id = $result->fields['account_id'];
$this->invoice_id = $result->fields['id'];
$this->invoice[$result->fields['id']] = $total;
$multi = false;
}
$amount = round($total, 2);
# Get the account details:
$sql = 'SELECT * FROM ' . AGILE_DB_PREFIX . 'account WHERE site_id = ' . $db->qstr(DEFAULT_SITE) . ' AND id = ' . $db->qstr($account_id);
$account = $db->Execute($sql);
if (!$account || !$account->RecordCount()) return false;
2009-08-03 04:10:16 +00:00
# Validate checkout option selected is allowed for purchase:
$q = "SELECT * FROM ".AGILE_DB_PREFIX."checkout WHERE site_id = ".$db->qstr(DEFAULT_SITE)." AND id = ".$db->qstr(@$VAR['option'])." AND active = 1 AND ";
2009-08-03 04:10:16 +00:00
if($recur_amt>0 && @$billed_amt == 0) $q .= "allow_recurring = 1 "; else $q .= "allow_new = 1 ";
$chopt = $db->Execute($q);
if (!$chopt || !$chopt->RecordCount()) return false;
if($chopt && $chopt->RecordCount()) {
$show = true;
2009-08-03 04:10:16 +00:00
if ( @$chopt->fields["total_maximum"] != "" && $total > $chopt->fields["total_maximum"] ) $show = false;
if ( @$chopt->fields["total_miniumum"] != "" && $total < $chopt->fields["total_miniumum"] ) $show = false;
}
if(!$show) {
echo '<script language=Javascript> alert("Unable to checkout with the selected method, please select another."); </script> ';
return false;
2009-08-03 04:10:16 +00:00
}
# Load the checkout plugin:
$plugin_file = PATH_PLUGINS . 'checkout/'. $chopt->fields["checkout_plugin"] . '.php';
include_once ( $plugin_file );
2009-08-03 04:10:16 +00:00
eval ( '$PLG = new plg_chout_' . $chopt->fields["checkout_plugin"] . '("'.@$VAR["option"].'",$multi);');
if(!empty($VAR['account_billing_id']) && @$VAR['new_card']==2) {
/* validate credit card on file details */
2009-08-03 04:10:16 +00:00
$account_billing_id=$VAR['account_billing_id'];
if(!$PLG->setBillingFromDB($account_id, $account_billing_id, $VAR['option'])) {
global $C_debug;
$C_debug->alert("Sorry, we cannot use that billing record for this purchase.");
return false;
}
} else {
/* use passed in vars */
$PLG->setBillingFromParams($VAR);
}
2009-08-03 04:10:16 +00:00
# Set Invoice Vars:
$this->total_amt = $amount;
$this->currency_iso = $C_list->currency_iso($CURRENCY);
2009-08-03 04:10:16 +00:00
$this->currency_iso_admin = $C_list->currency_iso($CURRENCY);
$this->account_id = $account_id;
$this->actual_billed_currency_id = $CURRENCY;
$this->billed_currency_id = $CURRENCY;
$this->checkout_plugin_id = @$VAR["option"];
2009-08-03 04:10:16 +00:00
# Run the plugin bill_checkout() method:
2009-08-03 04:10:16 +00:00
$this->checkout_plugin_data = $PLG->bill_checkout($amount, $this->invoice_id, $this->currency_iso, $account->fields, $recur_amt, $recur_arr,$this->invoice);
# redirect
if(!empty($this->checkout_plugin_data['redirect'])) echo $this->checkout_plugin_data['redirect'];
2009-08-03 04:10:16 +00:00
# determine results
if( $this->checkout_plugin_data === false ) {
2009-08-03 04:10:16 +00:00
if(!empty($PLG->redirect)) echo $PLG->redirect;
return false;
} elseif ($PLG->type == "gateway" && empty($PLG->redirect)) {
if(empty($this->admin_checkout)) {
$VAR['_page'] = "invoice:thankyou";
} else {
$VAR['_page'] = "invoice:view";
2009-08-03 04:10:16 +00:00
}
} elseif ($PLG->type == "redirect") {
2009-08-03 04:10:16 +00:00
echo "<html><head></head><body><center>
Please wait while we redirect you to the secure payment site....
2009-08-03 04:10:16 +00:00
{$PLG->redirect}</center></body></html>";
}
# Call the Plugin method for storing the checkout data, if new data entered:
$this->account_billing_id = $PLG->store_billing($VAR, $PLG);
# Load the email template module
include_once(PATH_MODULES.'email_template/email_template.inc.php');
$mail = new email_template;
# Update billing details for this invoice, if realtime billing succeeded:
if($PLG->type == 'gateway' || $amount == 0) {
$q = "UPDATE ".AGILE_DB_PREFIX."invoice
SET
account_billing_id = " .$db->qstr($this->account_billing_id). ",
billing_status = " .$db->qstr(1). ",
billed_amt = " .$db->qstr($total). ",
actual_billed_amt = " .$db->qstr($amount). ",
date_last = " .$db->qstr(time()). ",
checkout_plugin_id = " .$db->qstr($this->checkout_plugin_id) .",
checkout_plugin_data = " .$db->qstr(serialize($this->checkout_plugin_data)). "
WHERE
site_id = ".$db->qstr(DEFAULT_SITE)." AND
2009-08-03 04:10:16 +00:00
id = ".$db->qstr($this->invoice_id);
$rst = $db->Execute($q);
if ($rst === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
return false;
}
// loop through each invoice paid
2009-08-03 04:10:16 +00:00
foreach($this->invoice as $this->invoice_id) {
# Send billed e-mail notice to user
$email = new email_template;
$email->send('invoice_paid_user', $this->account_id, $this->invoice_id, $this->currency_iso, '');
2009-08-03 04:10:16 +00:00
# Admin alert of payment processed
$email = new email_template;
$email->send('admin->invoice_paid_admin', $this->account_id, $this->invoice_id, $this->currency_iso_admin, '');
2009-08-03 04:10:16 +00:00
# Submit the invoice for approval
$arr['id'] = $this->invoice_id;
$this->approveInvoice($arr, $this);
}
} else {
# Just update the last_date and plugin data
$q = "UPDATE ".AGILE_DB_PREFIX."invoice
2009-08-03 04:10:16 +00:00
SET
account_billing_id = " .$db->qstr($this->account_billing_id). ",
date_last = " .$db->qstr(time()). ",
checkout_plugin_id = " .$db->qstr($this->checkout_plugin_id) .",
checkout_plugin_data = " .$db->qstr(serialize($this->checkout_plugin_data)). "
WHERE
site_id = ".$db->qstr(DEFAULT_SITE)." AND
2009-08-03 04:10:16 +00:00
id = ".$db->qstr($this->invoice_id);
$rst = $db->Execute($q);
if ($rst === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
return false;
}
# Admin e-mail alert of manual payment processing
2009-08-03 04:10:16 +00:00
if ( $PLG->name == 'MANUAL' ) {
$date_due = $C_list->date(time());
2009-08-03 04:10:16 +00:00
foreach($this->invoice as $this->invoice_id) {
$email = new email_template;
$email->send('admin->invoice_due_admin', $this->account_id, $this->invoice_id, '', $date_due);
}
2009-08-03 04:10:16 +00:00
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->alert($C_translate->translate('manual_alert','checkout'));
}
}
2009-08-03 04:10:16 +00:00
}
2009-08-03 04:10:16 +00:00
/**
* Create modified array for invoice summarization
*
* This function will summarise the invoice items based on the same
* SKU, BASE_PRICE, SETUP_PRICE & PRODUCT_ATTR
*/
public function summarizeLineItems($smart_items) {
//$ignore['SKU']=true;
2009-08-03 04:10:16 +00:00
$sum = array();
if (is_array($smart_items)) {
foreach ($smart_items as $it) {
# Unique line item
if (! isset($sum[$it['sku']])) {
if (! isset($ignore[$it['sku']]))
$sum[$it['sku']] = array($it);
$sum[$it['sku']][0]['summaryname'] = $this->getLineItemDesc($it['sku'],$it['product_id'],false,$it['sku'] ? false : $it['product_name']);
} else {
2009-08-03 04:10:16 +00:00
# Is unique price/attributes?
$unique = true;
foreach ($sum[$it['sku']] as $sid => $flds) {
if ($flds['price_base'] == $it['price_base'] &&
$flds['price_setup'] == $it['price_setup'] &&
$flds['product_attr'] == $it['product_attr']) {
$sum[$it['sku']][$sid]['quantity'] += 1;
$unique = false;
break;
}
}
2009-08-03 04:10:16 +00:00
# Unique line item
if ($unique) {
$a = count($sum[$it['sku']]);
array_push($sum[$it['sku']],$it);
$sum[$it['sku']][$a]['summaryname'] = $this->getLineItemDesc($it['sku'],$it['product_id'],false,$it['sku'] ? false : $it['product_name']);
}
}
}
}
2009-08-03 04:10:16 +00:00
if (count($sum)) {
$smart_items = array();
foreach ($sum as $sku => $item)
foreach ($item as $sitem)
array_push($smart_items,$sitem);
return $smart_items;
}
}
2009-08-03 04:10:16 +00:00
/**
* View an Invoice
* Shown both in the admin pages and after checkout
*
* @uses net_term
*/
public function view($VAR) {
global $C_translate,$C_list;
$db = &DB();
2009-08-03 04:10:16 +00:00
if ($smart = parent::view($VAR)) {
# Get the product checkout plugin name
if (! empty($smart['checkout_plugin_id'])) {
$cplg = $db->Execute(sqlSelect($db,'checkout','name',sprintf('id=%s',$smart['checkout_plugin_id'])));
2009-08-03 04:10:16 +00:00
if ($cplg && $cplg->RecordCount())
$smart['checkout_plugin'] = $cplg->fields['name'];
}
2009-08-03 04:10:16 +00:00
if ($smart['total_amt'] == 0)
$smart['balance'] = 0;
else
2009-08-03 04:10:16 +00:00
$smart['balance'] = $smart['total_amt']-$smart['billed_amt'];
2009-08-03 04:10:16 +00:00
# Get the tax details
if (! empty($smart['tax_amt'])) {
$trs = $db->Execute(sqlSelect($db,array('invoice_item_tax','tax'),'A.amount,B.description',sprintf('A.tax_id=B.id AND A.invoice_id=%s',$smart['id'])));
if ($trs && $trs->RecordCount()) {
$taxes = array();
while (!$trs->EOF) {
@$taxes[$trs->fields['description']] += $trs->fields['amount'];
$trs->MoveNext();
}
2009-08-03 04:10:16 +00:00
$smart['tax_arr'] = array();
foreach ($taxes as $txds => $txamt)
array_push($smart['tax_arr'],array('description'=>$txds,'amount'=>$txamt));
}
}
2009-08-03 04:10:16 +00:00
# Get the discount details
if (! empty($smart['discount_amt'])) {
$drs = $db->Execute(sqlSelect($db,'invoice_item_discount','amount,discount',sprintf('invoice_id=%s',$smart['id'])));
2009-08-03 04:10:16 +00:00
if ($drs && $drs->RecordCount()) {
$discounts = array();
while(!$drs->EOF) {
@$discounts[$drs->fields['discount']] += $drs->fields["amount"];
$drs->MoveNext();
}
2009-08-03 04:10:16 +00:00
$dhtml = '';
foreach ($discounts as $dsds=>$dsamt)
$dhtml .= sprintf('<a href=\'?_page=core:search&module=discount&discount_name=%s\'>%s</a> - <br/>',$dsds,$dsds,number_format($dsamt,2));
2009-08-03 04:10:16 +00:00
$smart['discount_popup'] = $dhtml;
$dhtml = '';
foreach ($discounts as $dsds=>$dsamt)
$dhtml .= sprintf('%s - %s<br/>',$dsds,number_format($dsamt,2));
2009-08-03 04:10:16 +00:00
$smart['discount_popup_user'] = $dhtml;
}
2009-08-03 04:10:16 +00:00
}
# Get the checkout plugin details
if (! empty($smart['checkout_plugin_data'])) {
$plugin_data = unserialize($smart['checkout_plugin_data']);
2009-08-03 04:10:16 +00:00
if (is_array($plugin_data))
$smart['checkout_plugin_data'] = $plugin_data;
else
2009-08-03 04:10:16 +00:00
$smart['checkout_plugin_data'] = array(0=>$smart['checkout_plugin_data']);
}
2009-08-03 04:10:16 +00:00
# Get the line items
$q = sqlSelect($db,'invoice_item','*',sprintf('invoice_id=%s',$smart['id']));
if ($C_list->is_installed('voip'))
$q .= ' AND item_type!=5';
2009-08-03 04:10:16 +00:00
$items = $db->Execute($q);
if ($items === false) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
2009-08-03 04:10:16 +00:00
return false;
}
2009-08-03 04:10:16 +00:00
# Get the term dates
include_once(PATH_MODULES.'net_term/net_term.inc.php');
$net_term = new net_term;
2009-08-03 04:10:16 +00:00
$smart['termdates'] = $net_term->getTermDates($smart['net_term_id'],$smart['date_orig'],$smart['due_date']);
2009-08-03 04:10:16 +00:00
$ii =0;
while (! $items->EOF) {
$smart_items[$ii] = $items->fields;
2009-08-03 04:10:16 +00:00
# Get the product attribs
if (! empty($items->fields['product_attr'])) {
@$attrib = explode("\r\n",$items->fields['product_attr']);
$js = '';
2009-08-03 04:10:16 +00:00
for ($attr_i=0; $attr_i<count($attrib); $attr_i++) {
$attributei = explode('==',$attrib[$attr_i]);
2009-08-03 04:10:16 +00:00
if (! empty($attributei[0]) && ! empty($attributei[1]))
$js .= sprintf('<div style="text-decoration: underline;">%s</div> : %s <br/>',$attributei[0],$attributei[1]);
}
2009-08-03 04:10:16 +00:00
$smart_items[$ii]['attribute_popup'] = $js;
}
2009-08-03 04:10:16 +00:00
# Get the date range if set
if (! empty($items->fields['date_start']) && ! empty($items->fields['date_stop'])) {
$C_translate->value('invoice','start',date(UNIX_DATE_FORMAT,$items->fields['date_start']));
$C_translate->value('invoice','stop',date(UNIX_DATE_FORMAT,$items->fields['date_stop']));
2009-08-03 04:10:16 +00:00
$smart_items[$ii]['range'] = $C_translate->translate('recur_date_range','invoice','');
}
2009-08-03 04:10:16 +00:00
# Set charge type for payment option list
$any_new = true;
if ($items->fields['price_type']=='1' && ! empty($smart['recurr_arr']) && is_array(unserialize($smart['recurr_arr'])))
$any_recurring = true;
2009-08-03 04:10:16 +00:00
$items->MoveNext();
$ii++;
}
2009-08-03 04:10:16 +00:00
# Create a summary (for duplicate skus w/identical price,and attributes, roll into a single value
if ($this->summarizeInvoice)
$smart_items = $this->summarizeLineItems($smart_items);
2009-08-03 04:10:16 +00:00
# Get the checkout (payment) options
if ($VAR['_page'] != 'invoice:view') {
# Get the converted amount due:
if ($smart['billed_currency_id'] != $smart['actual_billed_currency_id']) {
global $C_list;
2009-08-03 04:10:16 +00:00
$CURRENCY = $smart['actual_billed_currency_id'];
if ($smart['billed_amt'] <= 0)
$total = $C_list->format_currency_decimal($smart['total_amt'],$CURRENCY);
else
$total = $C_list->format_currency_decimal($smart['total_amt'],$CURRENCY)-$smart['actual_billed_amt'];
2009-08-03 04:10:16 +00:00
} else {
$CURRENCY = $smart['billed_currency_id'];
$total = $smart['total_amt']-$smart['billed_amt'];
}
2009-08-03 04:10:16 +00:00
$q = sqlSelect($db,'checkout','*','active=1');
2009-08-03 04:10:16 +00:00
if ($any_trial)
$q .= sprintf(' AND allow_trial = %s',$db->qstr('1'));
2009-08-03 04:10:16 +00:00
if ($any_recurring)
$q .= sprintf(' AND allow_recurring = %s',$db->qstr('1'));
2009-08-03 04:10:16 +00:00
if ($any_new)
$q .= sprintf(' AND allow_new = %s',$db->qstr('1'));
2009-08-03 04:10:16 +00:00
$chopt = $db->Execute($q);
2009-08-03 04:10:16 +00:00
if ($chopt === false) {
global $C_debug;
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
2009-08-03 04:10:16 +00:00
return false;
}
2009-08-03 04:10:16 +00:00
if ($chopt != false && $chopt->RecordCount() > 0) {
while (! $chopt->EOF) {
$show = true;
2009-08-03 04:10:16 +00:00
# Check that the cart total is not to high:
if ($chopt->fields['total_maximum'] != '' && $smart['total_amt'] >= $chopt->fields['total_maximum'])
$show = false;
2009-08-03 04:10:16 +00:00
# Check that the cart total is not to low:
if ($chopt->fields['total_miniumum'] != '' && $smart['total_amt'] <= $chopt->fields['total_miniumum'])
$show = false;
2009-08-03 04:10:16 +00:00
# Check that the group requirement is met:
if ($show && ! empty($chopt->fields['required_groups'])) {
global $C_auth;
2009-08-03 04:10:16 +00:00
$arr = unserialize($chopt->fields['required_groups']);
if (count($arr) > 0 && ! empty($arr[0]))
$show = false;
2009-08-03 04:10:16 +00:00
for ($i=0; $i<count($arr); $i++) {
if ($C_auth->auth_group_by_id($arr)) {
$show = true;
$i = count($arr);
}
}
}
2009-08-03 04:10:16 +00:00
# Check that the customer is not ordering a blocked SKU
if ($show && ! empty($chopt->fields['excluded_products'])) {
$arr = unserialize($chopt->fields['excluded_products']);
if (count($arr) > 0) {
for ($i=0; $i<count($smart_items); $i++) {
for ($isk=0; $isk<count($arr); $isk++) {
if ($smart_items['product_id'] == $arr[$isk] && !empty($arr[$isk]) && !empty($smart_items['product_id'])) {
$show = false;
$i = count($smart);
$isk = count($arr);
}
}
}
}
}
2009-08-03 04:10:16 +00:00
$list_ord = 100;
if ($show) {
# Check if this method should be the default method
# By Amount
if (! empty($chopt->fields['default_when_amount'])) {
$arr = unserialize($chopt->fields['default_when_amount']);
2009-08-03 04:10:16 +00:00
for ($idx=0; $idx<count($arr); $idx++) {
if ($total >= $arr[$idx])
$list_ord--;
2009-08-03 04:10:16 +00:00
$idx = count($arr);
}
}
2009-08-03 04:10:16 +00:00
# By Currency
if (! empty($chopt->fields['default_when_currency'])) {
$arr = unserialize($chopt->fields['default_when_currency']);
2009-08-03 04:10:16 +00:00
for ($idx=0; $idx<count($arr); $idx++) {
if ($CURRENCY == $arr[$idx])
$list_ord--;
2009-08-03 04:10:16 +00:00
$idx = count($arr);
}
}
2009-08-03 04:10:16 +00:00
# By Group
if (! empty($chopt->fields['default_when_group'])) {
$arr = unserialize($chopt->fields['default_when_group']);
global $C_auth;
2009-08-03 04:10:16 +00:00
for ($idx=0; $idx<count($arr); $idx++) {
if ($C_auth->auth_group_by_id($arr[$idx]))
$list_ord--;
2009-08-03 04:10:16 +00:00
$idx = count($arr);
}
}
2009-08-03 04:10:16 +00:00
# By Country
if (! empty($chopt->fields['default_when_country'])) {
$arr = unserialize($chopt->fields['default_when_country']);
2009-08-03 04:10:16 +00:00
for ($idx=0; $idx<count($arr); $idx++) {
if ($account->fields['country_id'] == $arr[$idx])
$list_ord--;
2009-08-03 04:10:16 +00:00
$idx = count($arr);
}
}
2009-08-03 04:10:16 +00:00
# Add to the array
$checkout_optionsx[] = array('sort'=>$list_ord,'fields'=>$chopt->fields);
}
2009-08-03 04:10:16 +00:00
$chopt->MoveNext();
}
2009-08-03 04:10:16 +00:00
# Sort the checkout_options array by the [fields] element
if (count($checkout_optionsx)>0) {
foreach ($checkout_optionsx as $key => $row)
$sort[$key] = $row['sort'];
2009-08-03 04:10:16 +00:00
array_multisort($sort,SORT_ASC,$checkout_optionsx);
}
}
}
2009-08-03 04:10:16 +00:00
# No results
if (count($smart) == 0) {
global $C_debug;
$C_debug->error(__FILE__, __METHOD__,'The selected record does not exist any longer, or your account is not authorized to view it');
2009-08-03 04:10:16 +00:00
return;
}
2009-08-03 04:10:16 +00:00
# Define the DB vars as a Smarty accessible block
global $smarty;
2009-08-03 04:10:16 +00:00
# Define the results
$smarty->assign('cart',$smart_items);
$smarty->assign('record',$smart);
$smarty->assign('checkoutoptions',$checkout_optionsx);
}
}
2009-08-03 04:10:16 +00:00
/**
* Delete an invoice
*/
public function delete($VAR) {
$db = &DB();
2009-08-03 04:10:16 +00:00
# Get the array
if (isset($VAR['delete_id']))
$ids = explode(',',preg_replace('/,$/','',$VAR['delete_id']));
elseif (isset($VAR['id']))
$ids = explode(',',preg_replace('/,$/','',$VAR['id']));
2009-08-03 04:10:16 +00:00
# Load the service module
include_once(PATH_MODULES.'service/service.inc.php');
$service = new service;
2009-08-03 04:10:16 +00:00
# Loop:
for ($i=0; $i<count($ids); $i++) {
# Loop through all services for this invoice and delete:
$rs = $db->Execute(sqlSelect($db,'service',array('invoice_id'=>$ids[$i])));
2009-08-03 04:10:16 +00:00
if ($rs === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,'delete', $db->ErrorMsg());
return false;
}
2009-08-03 04:10:16 +00:00
if ($rs->RecordCount() > 0) {
while (! $rs->EOF) {
$service->delete($rs->fields['id'],$service);
$rs->MoveNext();
}
}
2009-08-03 04:10:16 +00:00
# Delete the service record
$this->associated_DELETE = array();
array_push($this->associated_DELETE,array('table'=>'invoice_commission','field'=>'invoice_id'));
array_push($this->associated_DELETE,array('table'=>'invoice_item','field'=>'invoice_id'));
array_push($this->associated_DELETE,array('table'=>'invoice_memo','field'=>'invoice_id'));
// array_push($this->associated_DELETE,array('table'=>'service','field'=>'invoice_id'));
array_push($this->associated_DELETE,array('table'=>'invoice_item_tax','field'=>'invoice_id'));
array_push($this->associated_DELETE,array('table'=>'invoice_item_discount','field'=>'invoice_id'));
2009-08-03 04:10:16 +00:00
$result = parent::delete($VAR);
}
}
2009-08-03 04:10:16 +00:00
/**
* User view an invoice
*/
public function user_view($VAR) {
global $C_auth;
2009-08-03 04:10:16 +00:00
if (! SESS_LOGGED)
return false;
# Verify the account_id for this order is the SESS_ACCOUNT
if ($C_auth->auth_method_by_name('invoice','view') == false) {
$id = preg_replace('/,$/','',$VAR['id']);
$db = &DB();
2009-08-03 04:10:16 +00:00
$rs = $db->Execute($q=sqlSelect($db,'invoice','account_id',array('id'=>$id)));
if ($rs === false) {
global $C_debug;
2009-08-03 04:10:16 +00:00
$C_debug->error(__FILE__,__METHOD__,$db->ErrorMsg());
return false;
}
2009-08-03 04:10:16 +00:00
if ($rs->fields['account_id'] != SESS_ACCOUNT)
return false;
}
2009-08-03 04:10:16 +00:00
$this->view($VAR,$this);
}
2009-08-03 04:10:16 +00:00
}
?>