Open Source Billing
This commit is contained in:
72
modules/invoice/classes/Controller/Admin/Invoice.php
Normal file
72
modules/invoice/classes/Controller/Admin/Invoice.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides invoice capabilities.
|
||||
*
|
||||
* @package Invoice
|
||||
* @category Controllers/Admin
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*
|
||||
* Column Definitions:
|
||||
* + price_type: 0=One Time, 1=Recurring, 2=Trial, 3=Extra Item
|
||||
* + item_type: 0=MAIN Service Item,2=?,3=?,4=Connection/Setup,5=Excess Service Item,6=Change Service,126=Payment Fee,127=Late Fee
|
||||
*/
|
||||
class Controller_Admin_Invoice extends Controller_TemplateDefault_Admin {
|
||||
protected $secure_actions = array(
|
||||
'list'=>TRUE,
|
||||
'setup'=>TRUE,
|
||||
);
|
||||
|
||||
public function action_setup() {
|
||||
$this->setup(array(
|
||||
'EMAIL_INV_MAX'=>_('Email this many invoices in a run (0=no limit)'),
|
||||
'GEN_DAYS'=>_('Generate Invoices this many days in advance of the due date'),
|
||||
'GEN_INV_MAX'=>_('Generate this many invoices in a run (0=no limit)'),
|
||||
'GEN_SOON_DAYS'=>_('Days before GEN_DAYS to list invoices that will be generated'),
|
||||
'DUE_DAYS_MIN'=>_('When invoices are generated, the minimum days in advance the due date should be set to'),
|
||||
'REMIND_DUE'=>_('Days before an invoice due to sent out a reminder'),
|
||||
'REMIND_OVERDUE_1'=>_('Days after an invoice is due to send first reminder'),
|
||||
'REMIND_OVERDUE_2'=>_('Days after an invoice is due to send second reminder'),
|
||||
'REMIND_OVERDUE_3'=>_('Days after an invoice is due to send third and final reminder'),
|
||||
'TAX_ID'=>_('TAX ID shown on invoices'),
|
||||
'TAX_ID_NAME'=>_('TAX ID name shown on invoices'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a list of invoices
|
||||
*/
|
||||
public function action_list() {
|
||||
$id = $this->request->param('id');
|
||||
|
||||
$invs = ORM::factory('Invoice');
|
||||
|
||||
if ($id)
|
||||
$invs->where('account_id','=',$id);
|
||||
|
||||
Block::add(array(
|
||||
'title'=>_('System Customer Invoices'),
|
||||
'body'=>Table::display(
|
||||
$invs->find_all(),
|
||||
25,
|
||||
array(
|
||||
'id'=>array('label'=>'ID','url'=>URL::link('user','invoice/view/')),
|
||||
'date_orig'=>array('label'=>'Date'),
|
||||
'total(TRUE)'=>array('label'=>'Total','class'=>'right'),
|
||||
'total_credits(TRUE)'=>array('label'=>'Credits','class'=>'right'),
|
||||
'payments_total(TRUE)'=>array('label'=>'Payments','class'=>'right'),
|
||||
'due(TRUE)'=>array('label'=>'Still Due','class'=>'right'),
|
||||
'account->accnum()'=>array('label'=>'Cust ID'),
|
||||
'account->name()'=>array('label'=>'Customer'),
|
||||
),
|
||||
array(
|
||||
'page'=>TRUE,
|
||||
'type'=>'select',
|
||||
'form'=>URL::link('user','invoice/view'),
|
||||
)),
|
||||
));
|
||||
}
|
||||
}
|
||||
?>
|
138
modules/invoice/classes/Controller/Invoice.php
Normal file
138
modules/invoice/classes/Controller/Invoice.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides invoice capabilities.
|
||||
*
|
||||
* @package Invoice
|
||||
* @category Controllers
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Controller_Invoice extends Controller_TemplateDefault {
|
||||
protected $secure_actions = array(
|
||||
'download'=>TRUE,
|
||||
'list'=>TRUE,
|
||||
'view'=>TRUE,
|
||||
);
|
||||
|
||||
/**
|
||||
* Show a list of invoices
|
||||
*/
|
||||
public function action_list() {
|
||||
Block::add(array(
|
||||
'title'=>sprintf('%s: %s - %s',_('Invoices For'),$this->ao->accnum(),$this->ao->name(TRUE)),
|
||||
'body'=>Table::display(
|
||||
$this->ao->invoice->find_all(),
|
||||
25,
|
||||
array(
|
||||
'id'=>array('label'=>'ID','url'=>URL::link('user','invoice/view/')),
|
||||
'date_orig'=>array('label'=>'Date Issued'),
|
||||
'due_date'=>array('label'=>'Date Due'),
|
||||
'total(TRUE)'=>array('label'=>'Total','class'=>'right'),
|
||||
'total_credits(TRUE)'=>array('label'=>'Credits','class'=>'right'),
|
||||
'payments_total(TRUE)'=>array('label'=>'Payments','class'=>'right'),
|
||||
'due(TRUE)'=>array('label'=>'Still Due','class'=>'right'),
|
||||
),
|
||||
array(
|
||||
'page'=>TRUE,
|
||||
'type'=>'select',
|
||||
'form'=>URL::link('user','invoice/view'),
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* View an Invoice
|
||||
*/
|
||||
public function action_view() {
|
||||
list($id,$output) = Table::page(__METHOD__);
|
||||
|
||||
$io = ORM::factory('Invoice',$id);
|
||||
|
||||
if (! $io->loaded() OR ! Auth::instance()->authorised($io->account)) {
|
||||
$this->template->content = 'Unauthorised or doesnt exist?';
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$output .= View::factory($this->viewpath())
|
||||
->set('mediapath',Route::get('default/media'))
|
||||
->set('io',$io);
|
||||
|
||||
if ($io->due() AND ! $io->cart_exists()) {
|
||||
$output .= View::factory($this->viewpath().'/pay')
|
||||
->set('mid',$io->mid())
|
||||
->set('o',$io);
|
||||
}
|
||||
|
||||
if (! $io->status) {
|
||||
// Add a gribber popup
|
||||
// @todo Make a gribber popup a class on its own.
|
||||
Style::add(array(
|
||||
'type'=>'file',
|
||||
'data'=>'css/jquery.gritter.css',
|
||||
'media'=>'screen',
|
||||
));
|
||||
Script::add(array(
|
||||
'type'=>'file',
|
||||
'data'=>'js/jquery.gritter-1.5.js',
|
||||
));
|
||||
Script::add(array(
|
||||
'type'=>'stdin',
|
||||
'data'=>sprintf(
|
||||
'$(document).ready(function() {
|
||||
$.extend($.gritter.options, {
|
||||
fade_in_speed: "medium",
|
||||
fade_out_speed: 2000,
|
||||
time: "3000",
|
||||
sticky: false,
|
||||
});
|
||||
$.gritter.add({
|
||||
title: "%s",
|
||||
text: "%s",
|
||||
image: "%s",
|
||||
});});',
|
||||
'Cancelled','Invoice CANCELLED',URL::site().SystemMessage::image('info',true)
|
||||
)
|
||||
));
|
||||
|
||||
Style::add(array(
|
||||
'type'=>'stdin',
|
||||
'data'=>'
|
||||
#watermark {
|
||||
color: #800000;
|
||||
font-size: 4em;
|
||||
-webkit-transform: rotate(-45deg);
|
||||
-moz-transform: rotate(-45deg);
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
z-index: 1;
|
||||
left:250px;
|
||||
top:-20px;
|
||||
}
|
||||
'));
|
||||
|
||||
$output .= '<div id="watermark"><p>Invoice CANCELLED.</p></div>';
|
||||
}
|
||||
|
||||
Block::add(array(
|
||||
'title'=>sprintf('%s: %s - %s',_('Invoice'),$io->refnum(),$io->account->name()),
|
||||
'body'=>$output,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Download an invoice
|
||||
*/
|
||||
public function action_download() {
|
||||
$io = ORM::factory('Invoice',$this->request->param('id'));
|
||||
|
||||
$this->response->body(Invoice::instance($io)->pdf()->Output(sprintf('%s.pdf',$io->refnum()),'D'));
|
||||
$this->response->headers(array('Content-Type' => 'application/pdf'));
|
||||
$this->auto_render = FALSE;
|
||||
}
|
||||
}
|
||||
?>
|
33
modules/invoice/classes/Controller/Reseller/Invoice.php
Normal file
33
modules/invoice/classes/Controller/Reseller/Invoice.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides Reseller Invoice viewing functions
|
||||
*
|
||||
* @package Invoice
|
||||
* @category Controllers/Reseller
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Controller_Reseller_Invoice extends Controller_Invoice {
|
||||
public function action_list() {
|
||||
list($id,$output) = Table::page(__METHOD__);
|
||||
|
||||
$ao = ORM::factory('Account',$id);
|
||||
|
||||
if (! $ao->loaded() OR ! Auth::instance()->authorised($ao)) {
|
||||
$this->template->content = 'Unauthorised or doesnt exist?';
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Block::add(array(
|
||||
'body'=>$output,
|
||||
));
|
||||
|
||||
$this->ao = $ao;
|
||||
|
||||
// @todo Our pagination is broken if we select multiple accounts, and those accounts have multiple invoices.
|
||||
return parent::action_list();
|
||||
}
|
||||
}
|
||||
?>
|
340
modules/invoice/classes/Controller/Task/Invoice.php
Normal file
340
modules/invoice/classes/Controller/Task/Invoice.php
Normal file
@@ -0,0 +1,340 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides OSB invoice task capabilities.
|
||||
*
|
||||
* @package Invoice
|
||||
* @category Controllers
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Controller_Task_Invoice extends Controller_Task {
|
||||
/**
|
||||
* Email a list of invoice balances
|
||||
*
|
||||
* This function is typically used to list the overdue invoices to the admins
|
||||
* @param string mode The callback method to use as the data list eg: overdue
|
||||
*/
|
||||
public function action_list() {
|
||||
$mode = $this->request->param('id');
|
||||
|
||||
$i = ORM::factory('Invoice');
|
||||
$tm = 'list_'.$mode;
|
||||
|
||||
if (! method_exists($i,$tm))
|
||||
throw new Kohana_Exception('Unknown Task List command :command',array(':command'=>$mode));
|
||||
|
||||
$total = $numinv = 0;
|
||||
$duelist = View::factory('invoice/task/'.$tm.'_head');
|
||||
foreach ($i->$tm() as $t) {
|
||||
$duelist .= View::factory('invoice/task/'.$tm.'_body')
|
||||
->set('io',$t);
|
||||
|
||||
$numinv++;
|
||||
$total += $t->due();
|
||||
}
|
||||
$duelist .= View::factory('invoice/task/'.$tm.'_foot');
|
||||
|
||||
// Send our email
|
||||
$et = Email_Template::instance('task_invoice_list_overdue');
|
||||
|
||||
// @todo Update this to be dynamic
|
||||
$et->to = array('account'=>array(1,68));
|
||||
$et->variables = array(
|
||||
'TABLE'=>$duelist,
|
||||
'NUM_INV'=>$numinv,
|
||||
'TOTAL'=>$total,
|
||||
);
|
||||
$et->send();
|
||||
|
||||
$output = sprintf('List (%s) sent to: %s',$mode,implode(',',array_keys($et->to)));
|
||||
$this->response->body($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Email a customers a reminder of their upcoming invoices that are due.
|
||||
*/
|
||||
public function action_remind_due() {
|
||||
$action = array();
|
||||
$key = 'remind_due';
|
||||
$days = ORM::factory('Invoice')->config('REMIND_DUE');
|
||||
|
||||
foreach (ORM::factory('Invoice')->list_due(time()+86400*$days) as $io) {
|
||||
// @todo Use another option to supress reminders
|
||||
// If we have already sent a reminder, we'll skip to the next one.
|
||||
if (($io->remind($key) AND (is_null($x=$this->request->param('id')) OR $x != 'again')) OR ($io->account->invoice_delivery != 1))
|
||||
continue;
|
||||
|
||||
// Send our email
|
||||
$et = Email_Template::instance('task_invoice_'.$key);
|
||||
|
||||
$et->to = array('account'=>array($io->account_id));
|
||||
$et->variables = array(
|
||||
'DUE'=>$io->due(TRUE),
|
||||
'DUE_DATE'=>$io->display('due_date'),
|
||||
'FIRST_NAME'=>$io->account->first_name,
|
||||
'INV_NUM'=>$io->refnum(),
|
||||
'INV_URL'=>URL::site(URL::link('user','invoice/view/'.$io->id),'http'),
|
||||
'SITE_NAME'=>Company::instance()->name(),
|
||||
);
|
||||
|
||||
// @todo Record email log id if possible.
|
||||
if ($et->send()) {
|
||||
$io->set_remind($key,time());
|
||||
array_push($action,(string)$io);
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->body(_('Due Reminders Sent: ').join('|',$action));
|
||||
}
|
||||
|
||||
/**
|
||||
* Email a customers when their invoices are now overdue.
|
||||
*/
|
||||
public function action_remind_overdue() {
|
||||
$action = array();
|
||||
$notice = $this->request->param('id');
|
||||
$x = NULL;
|
||||
|
||||
if (preg_match('/:/',$notice))
|
||||
list($notice,$x) = explode(':',$notice);
|
||||
|
||||
switch ($notice) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
$days = ORM::factory('Invoice')->config('REMIND_OVERDUE_'.$notice);
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->response->body(_('Unknown Remind Period: ').$notice);
|
||||
return;
|
||||
}
|
||||
|
||||
$key = 'remind_overdue_'.$notice;
|
||||
|
||||
foreach (ORM::factory('Invoice')->list_overdue_billing(time()-86400*$days,FALSE) as $io) {
|
||||
// @todo Use another option to supress reminders
|
||||
// If we have already sent a reminder, we'll skip to the next one.
|
||||
if (($io->remind($key) AND (is_null($x=$this->request->param('id')) OR $x != 'again')) OR ($io->account->invoice_delivery != 1))
|
||||
continue;
|
||||
|
||||
// Send our email
|
||||
$et = Email_Template::instance('task_invoice_'.$key);
|
||||
|
||||
$et->to = array('account'=>array($io->account_id));
|
||||
$et->variables = array(
|
||||
'DUE'=>$io->due(TRUE),
|
||||
'DUE_DATE'=>$io->display('due_date'),
|
||||
'EMAIL'=>Company::instance()->email(),
|
||||
'FIRST_NAME'=>$io->account->first_name,
|
||||
'INV_NUM'=>$io->refnum(),
|
||||
'INV_URL'=>URL::site(URL::link('user','invoice/view/'.$io->id),'http'),
|
||||
'LATE_FEE'=>'5.50', // @todo This should come from a config file.
|
||||
'PAYMENTS_TABLE'=>$io->account->payment->list_recent_table(),
|
||||
'SITE_NAME'=>Company::instance()->name(),
|
||||
);
|
||||
|
||||
// @todo Record email log id if possible.
|
||||
if ($et->send()) {
|
||||
$io->set_remind($key,time());
|
||||
array_push($action,(string)$io);
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->body(_('Overdue Reminders Sent: ').join('|',$action));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate our services invoices, based on the service next invoice date
|
||||
*
|
||||
* @param int ID Service ID to generate invoice for (optional) - multiple services colon separated
|
||||
*/
|
||||
public function action_services() {
|
||||
// Used to only process X invoices in a row.
|
||||
$max = ($x=Kohana::$config->load('debug')->invoice) ? $x : ORM::factory('Invoice')->config('GEN_INV_MAX');
|
||||
// Our service next billing dates that need to be updated if this is successful.
|
||||
$snd = array();
|
||||
// Our charges that need to be updated if this is successful.
|
||||
$chgs = array();
|
||||
// If we are invoicing a specific service
|
||||
$sid = is_null($this->request->param('id')) ? NULL : explode(':',$this->request->param('id'));
|
||||
// Sort our service by account_id, then we can generate 1 invoice.
|
||||
$svs = ORM::factory('Service')->list_invoicesoon()->as_array();
|
||||
Sort::MAsort($svs,'account_id,date_next_invoice');
|
||||
|
||||
$aid = $due = $io = NULL;
|
||||
$max_count = 0;
|
||||
foreach ($svs as $so) {
|
||||
// If we are generating an invoice for a service, skip to that service.
|
||||
if (! is_null($sid) AND ! in_array($so->id,$sid))
|
||||
continue;
|
||||
|
||||
// Close off invoice, and start a new one.
|
||||
if (is_null($io) OR (! is_null($aid) AND $aid != $so->account_id) OR (! is_null($due) AND $due != $io->min_due($so->date_next_invoice))) {
|
||||
// Close this invoice.
|
||||
if (is_object($io)) {
|
||||
// Save our invoice.
|
||||
if (! $io->save())
|
||||
throw new Kohana_Exception('Failed to save invoice :invoice for service :service',array(':invoice'=>$io->id,':service'=>$so->id));
|
||||
}
|
||||
|
||||
// If we have issued the max number of invoices this round, finish.
|
||||
if ($max AND (++$max_count > $max))
|
||||
break;
|
||||
|
||||
// Start a new invoice.
|
||||
$io = ORM::factory('Invoice');
|
||||
$io->due_date = $due = $io->min_due($so->date_next_invoice);
|
||||
$io->account_id = $aid = $so->account_id;
|
||||
$io->status = TRUE;
|
||||
}
|
||||
|
||||
$pdata = Period::details($so->recur_schedule,$so->product->price_recurr_weekday,$so->date_next_invoice,TRUE);
|
||||
|
||||
$iio = $io->add_item();
|
||||
$iio->service_id = $so->id;
|
||||
$iio->product_id = $so->product_id;
|
||||
$iio->quantity = $pdata['prorata'];
|
||||
$iio->item_type = 0; // Service Billing
|
||||
$iio->discount_amt = NULL; // @todo
|
||||
$iio->price_type = $so->product->price_type;
|
||||
$iio->price_base = $so->price();
|
||||
$iio->recurring_schedule = $so->recur_schedule;
|
||||
$iio->date_start = $pdata['start_time'];
|
||||
$iio->date_stop = $pdata['end_time'];
|
||||
|
||||
// Our service next billing date, if this invoice generation is successful.
|
||||
$snd[$so->id] = $pdata['end_time']+86400;
|
||||
|
||||
// Check if there are any charges
|
||||
$c = ORM::factory('Charge')
|
||||
->where('service_id','=',$so->id)
|
||||
->where('status','=',0)
|
||||
->where('sweep_type','=',6); // @todo This needs to be dynamic, not "6"
|
||||
|
||||
foreach ($c->find_all() as $co) {
|
||||
$iio = $io->add_item();
|
||||
$iio->service_id = $co->service_id;
|
||||
$iio->product_id = $co->product_id;
|
||||
$iio->charge_id = $co->id;
|
||||
$iio->quantity = $co->quantity;
|
||||
$iio->item_type = 5; // @todo This probably should not be hard coded as "5".
|
||||
$iio->discount_amt = NULL; // @todo
|
||||
$iio->price_base = $co->amount;
|
||||
$iio->date_start = $co->date_orig;
|
||||
$iio->date_stop = $co->date_orig; // @todo
|
||||
|
||||
// @todo Temp
|
||||
// We'll mark any charges as temporarily processed, although they should be set to status=1 later.
|
||||
$co->status=2;
|
||||
$co->save();
|
||||
array_push($chgs,$co->id);
|
||||
}
|
||||
}
|
||||
|
||||
// Save our invoice.
|
||||
if ($io AND ! $io->saved() AND ! $io->save()) {
|
||||
print_r($io->items());
|
||||
throw new Kohana_Exception('Failed to save invoice :invoice for service :service',array(':invoice'=>$io->id,':service'=>$so->id));
|
||||
}
|
||||
|
||||
// Update our service next billing dates.
|
||||
// @todo Catch any update errors
|
||||
foreach ($snd as $sid=>$date) {
|
||||
$so = ORM::factory('Service',$sid);
|
||||
$so->date_next_invoice = $date;
|
||||
$so->save();
|
||||
}
|
||||
|
||||
// Update any processed charges as such
|
||||
// @todo Catch any update errors
|
||||
foreach ($chgs as $cid) {
|
||||
$co = ORM::factory('Charge',$cid);
|
||||
$co->status=1;
|
||||
$co->save();
|
||||
}
|
||||
|
||||
$this->response->body(_('Services Invoiced: ').join('|',array_keys($snd)));
|
||||
}
|
||||
|
||||
public function action_send() {
|
||||
// Used to only process X invoices in a row.
|
||||
$max = ORM::factory('Invoice')->config('EMAIL_INV_MAX');
|
||||
|
||||
$action = array();
|
||||
$iid = $this->request->param('id');
|
||||
$x = NULL;
|
||||
|
||||
if (preg_match('/:/',$iid))
|
||||
list($iid,$x) = explode(':',$iid);
|
||||
|
||||
// Get our list of invoices to send
|
||||
$i = $iid ? ORM::factory('Invoice')->where('id','=',$iid) : ORM::factory('Invoice')->list_tosend();
|
||||
|
||||
$key = 'send';
|
||||
|
||||
$max_count = 0;
|
||||
foreach ($i->find_all() as $io) {
|
||||
// If we have already sent a reminder or we dont email invoices we'll skip to the next one.
|
||||
if (($io->remind($key) AND (is_null($x) OR $x != 'again')) OR ($io->account->invoice_delivery != 1))
|
||||
continue;
|
||||
|
||||
// If we have issued the max number of invoices this round, finish.
|
||||
if (++$max_count > $max)
|
||||
break;
|
||||
|
||||
// Send our email
|
||||
$et = Email_Template::instance('task_invoice_'.$key);
|
||||
$token = ORM::factory('Module_Method_Token')
|
||||
->method(array('invoice','user_download'))
|
||||
->account($io->account)
|
||||
->expire(time()+86400*21)
|
||||
->uses(3)
|
||||
->generate();
|
||||
|
||||
$et->to = array('account'=>array($io->account_id));
|
||||
$et->variables = array(
|
||||
'DUE'=>$io->due(TRUE),
|
||||
'DUE_DATE'=>$io->display('due_date'),
|
||||
'EMAIL'=>Company::instance()->email(),
|
||||
'FIRST_NAME'=>$io->account->first_name,
|
||||
'HTML_INVOICE'=>$io->html(),
|
||||
'INV_NUM'=>$io->refnum(),
|
||||
'INV_URL'=>URL::site(URL::link('user','invoice/view/'.$io->id),'http'),
|
||||
'INV_URL_DOWNLOAD'=>URL::site(URL::link('user',sprintf('invoice/download/%s?token=%s',$io->id,$token)),'http'),
|
||||
'SITE_NAME'=>Company::instance()->name(),
|
||||
);
|
||||
|
||||
// @todo Record email log id if possible.
|
||||
if ($et->send()) {
|
||||
$io->print_status = 1;
|
||||
$io->set_remind($key,time(),($x=='again' ? TRUE : FALSE));
|
||||
array_push($action,(string)$io);
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->body(_('Invoices Sent: ').join('|',$action));
|
||||
}
|
||||
|
||||
/** END **/
|
||||
|
||||
public function action_audit_invoice_items() {
|
||||
$output = '';
|
||||
|
||||
foreach (ORM::factory('Invoice_Item')->find_all() as $iio) {
|
||||
if ($iio->product_name AND $iio->product_id) {
|
||||
if (md5(strtoupper($iio->product_name)) == md5(strtoupper($iio->product->name()))) {
|
||||
$iio->product_name = NULL;
|
||||
$iio->save();
|
||||
} else {
|
||||
print_r(array("DIFF",'id'=>$iio->id,'pn'=>serialize($iio->product_name),'ppn'=>serialize($iio->product->name()),'pid'=>$iio->product_id,'test'=>strcasecmp($iio->product_name,$iio->product->name())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->body($output);
|
||||
}
|
||||
}
|
||||
?>
|
14
modules/invoice/classes/Controller/User/Invoice.php
Normal file
14
modules/invoice/classes/Controller/User/Invoice.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||
|
||||
/**
|
||||
* This class provides User Invoice functions
|
||||
*
|
||||
* @package Invoice
|
||||
* @category Controllers/User
|
||||
* @author Deon George
|
||||
* @copyright (c) 2009-2013 Open Source Billing
|
||||
* @license http://dev.osbill.net/license.html
|
||||
*/
|
||||
class Controller_User_Invoice extends Controller_Invoice {
|
||||
}
|
||||
?>
|
Reference in New Issue
Block a user