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/classes/controller/task/invoice.php
2012-01-12 19:55:07 +11:00

344 lines
10 KiB
PHP

<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides OSB invoice task capabilities.
*
* @package OSB
* @subpackage Invoice
* @category Controllers/Task
* @author Deon George
* @copyright (c) 2010 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();
// @todo This should go in a config somewhere
$days = 5;
$key = 'remind_due';
foreach (ORM::factory('invoice')->list_due(time()+86400*$days) as $io) {
// 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'))
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('user/invoice/view/'.$io->id,'http'),
'SITE_NAME'=>Config::sitename(),
);
// @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:
// @todo This should go in a config somewhere
$days = 2;
break;
case 2:
// @todo This should go in a config somewhere
$days = 7;
break;
case 3:
// @todo This should go in a config somewhere
$days = 13;
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) {
// If we have already sent a reminder, we'll skip to the next one.
if ($io->remind($key) AND (is_null($x) OR $x != 'again'))
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'=>'accounts@graytech.net.au', // @todo This should come from a config.
'FIRST_NAME'=>$io->account->first_name,
'INV_NUM'=>$io->refnum(),
'INV_URL'=>URL::site('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'=>Config::sitename(),
);
// @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)
*/
public function action_services() {
// Used to only process X invoices in a row.
// @todo This should be a configuration item.
$max = 10;
$action = array();
$snd = array(); // Our service next billing dates that need to be updated if this is successful.
$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();
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_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;
}
$ppa = $so->product->get_price_array();
// @todo Need to check our recurr_weekday configuration for items that need to be pro-rated and items that are billed on absolute dates.
$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;
$iio->discount_amt = null; // @todo
$iio->price_type = $so->product->price_type; // @todo Do we need this?
// @todo Might be a better way to do this
$iio->price_base = $so->price ? $so->price : (isset($ppa[$so->recur_schedule]['price_base']) ? $ppa[$so->recur_schedule]['price_base'] : 0);
$iio->recurring_schedule = $so->recur_schedule;
$iio->date_start = $pdata['start_time']; // @todo
$iio->date_stop = $pdata['end_time']; // @todo
// 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
$co->status=2;
$co->save();
}
array_push($action,(string)$so->id);
}
// Save our invoice.
if (! $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.
foreach ($snd as $sid=>$date) {
$so = ORM::factory('service',$sid);
$so->date_next_invoice = $date;
$so->save();
}
$this->response->body(_('Services Invoiced: ').join('|',$action));
}
public function action_send() {
// Used to only process X invoices in a row.
// @todo This should be a configuration item.
$max = 2;
$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, we'll skip to the next one.
if ($io->remind($key) AND (is_null($x) OR $x != 'again'))
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'=>'accounts@graytech.net.au', // @todo This should come from a config.
'FIRST_NAME'=>$io->account->first_name,
'HTML_INVOICE'=>$io->html(),
'INV_NUM'=>$io->refnum(),
'INV_URL'=>URL::site('user/invoice/view/'.$io->id,'http'),
'INV_URL_DOWNLOAD'=>URL::site(sprintf('user/invoice/download/%s?token=%s',$io->id,$token),'http'),
'SITE_NAME'=>Config::sitename(),
);
// @todo Record email log id if possible.
if ($et->send()) {
$io->print_status = 1;
$io->set_remind($key,time());
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);
}
}
?>