diff --git a/application/classes/controller/admin/welcome.php b/application/classes/controller/admin/welcome.php index 9226983f..31e6fb38 100644 --- a/application/classes/controller/admin/welcome.php +++ b/application/classes/controller/admin/welcome.php @@ -25,22 +25,34 @@ class Controller_Admin_Welcome extends Controller_TemplateDefault { Block_Sub::add(array( 'title'=>'Invoices Overdue', - 'body'=>Table::limit( + 'body'=>Table::display( $o->list_overdue($t), - 30, - array('Due Date'=>'display("due_date")','Account'=>'account->name()','Active'=>'account->display("status")','ID'=>'id()','Amount Due'=>'due(TRUE)'), - 'due()'), + 25, + array( + 'due_date'=>array('label'=>'Due Date'), + 'account->name()'=>array('label'=>'Account'), + 'account->display("status")'=>array('label'=>'Active'), + 'id()'=>array('label'=>'ID'), + 'due(TRUE)'=>array('label'=>'Amount Due','class'=>'right'), + ), + array('page'=>TRUE)), 'position'=>1, 'order'=>1, )); Block_Sub::add(array( 'title'=>'Invoices Due', - 'body'=>Table::limit( + 'body'=>Table::display( $o->list_due($t), - 30, - array('Due Date'=>'display("due_date")','Account'=>'account->name()','Active'=>'account->display("status")','ID'=>'id()','Amount Due'=>'due(TRUE)'), - 'due()'), + 25, + array( + 'due_date'=>array('label'=>'Due Date'), + 'account->name()'=>array('label'), + 'account->display("status")'=>array('label'=>'Active'), + 'id()'=>array('label'=>'ID'), + 'due(TRUE)'=>array('label'=>'Amount Due','class'=>'right'), + ), + array('show_other'=>'due()')), 'position'=>2, 'order'=>1, )); @@ -50,11 +62,17 @@ class Controller_Admin_Welcome extends Controller_TemplateDefault { Block_Sub::add(array( 'title'=>'Unapplied Payments', - 'body'=>Table::limit( + 'body'=>Table::display( $o->list_unapplied(), - 30, - array('ID'=>'id','Account'=>'account->name()','Total'=>'display("total_amt")','Balance'=>'balance(TRUE)'), - 'balance(TRUE)'), + 25, + array( + 'id'=>array('label'=>'ID'), + 'account->name()'=>array('label'=>'Account'), + 'account->display("status")'=>array('label'=>'Active'), + 'total_amt'=>array('label'=>'Total','class'=>'right'), + 'balance(TRUE)'=>array('label'=>'Balance','class'=>'right'), + ), + array('show_other'=>'balance()')), 'position'=>3, 'order'=>1, )); diff --git a/application/classes/controller/lnapp/login.php b/application/classes/controller/lnapp/login.php index e6fe1297..bfd43c8c 100644 --- a/application/classes/controller/lnapp/login.php +++ b/application/classes/controller/lnapp/login.php @@ -107,7 +107,7 @@ class Controller_lnApp_Login extends Controller_TemplateDefault { Block::add(array( 'title'=>_('Register'), - 'body'=>View::factory('bregister') + 'body'=>View::factory('register') ->set('account',$account) ->set('errors',$account->validation()->errors('form/register')), )); diff --git a/application/classes/controller/lnapp/templatedefault.php b/application/classes/controller/lnapp/templatedefault.php index f5970ac0..c31d0d2f 100644 --- a/application/classes/controller/lnapp/templatedefault.php +++ b/application/classes/controller/lnapp/templatedefault.php @@ -185,10 +185,13 @@ abstract class Controller_lnApp_TemplateDefault extends Controller_Template { if ($s = $this->_sysmsg() AND (string)$s) $this->response->body(sprintf('
%s
',$s)); - # In case there any style sheets or scrpits for this render. + // In case there any style sheets for this render. $this->response->bodyadd(Style::factory()); - # Get the response body + // In case there any javascript for this render. + $this->response->bodyadd(Script::factory()); + + // Get the response body $this->response->bodyadd(sprintf('
%s
',$this->template->content)); } diff --git a/application/classes/controller/lnapp/tree.php b/application/classes/controller/lnapp/tree.php index bc04e004..02c8629f 100644 --- a/application/classes/controller/lnapp/tree.php +++ b/application/classes/controller/lnapp/tree.php @@ -17,10 +17,10 @@ class Controller_lnApp_Tree extends Controller_Default { protected static $jsmediaroute = 'default/media'; public function after() { - parent::after(); - $this->response->headers('Content-Type','application/json'); $this->response->body(sprintf('[%s]',json_encode($this->output))); + + parent::after(); } public static function js() { diff --git a/application/classes/lnapp/block/sub.php b/application/classes/lnapp/block/sub.php index 0f0f781e..4b02a6b8 100644 --- a/application/classes/lnapp/block/sub.php +++ b/application/classes/lnapp/block/sub.php @@ -86,7 +86,7 @@ class lnApp_Block_Sub extends HTMLRender { // Render our output. $output .= ''; foreach ($o as $k => $v) - $output .= sprintf('',round(100/$y,0),implode('',$x=round(100/$y,0),implode(sprintf('
%s
',$v)); + $output .= sprintf('
%s
',$x),$v)); $output .= '
'; return $output; diff --git a/application/classes/lnapp/table.php b/application/classes/lnapp/table.php index e8acb547..03aa3404 100644 --- a/application/classes/lnapp/table.php +++ b/application/classes/lnapp/table.php @@ -12,52 +12,242 @@ * @uses Style */ class lnApp_Table { - public static function limit($data,$rows,array $cols,$other) { + public static function resolve($d,$key) { + if (is_array($d) AND isset($d[$key])) + $x = $d[$key]; + // If the key is a method, we need to eval it + elseif (preg_match('/\(/',$key)) + eval("\$x = \$d->$key;"); + elseif (preg_match('/^__VALUE__$/',$key)) + $x = $d; + else + $x = $d->display($key); + + return $x; + } + + public static function display($data,$rows,array $cols,array $option) { if (! (array)$data) return ''; - $output = ''; + $pag = NULL; + $view = $output = ''; - $other = $i = 0; - $output = ''; - $output .= ''; - foreach ($data as $do) { - if ($i++ < $rows) { - $output .= ''; + if (isset($option['type']) AND $option['type']) + switch ($option['type']) { + case 'select': + $view = 'table/select'; - foreach (array_values($cols) as $col) { - if (is_array($do) AND isset($do[$col])) - $x = $do[$col]; - // If the col is a method, we need to eval it - elseif (preg_match('/\(/',$col)) - eval("\$x = \$do->$col;"); - else - $x = $do->{$col}; - - $output .= sprintf('',$x); + Script::add(array( + 'type'=>'stdin', + 'data'=>' +(function($) { + // Enable Range Selection + $.fn.enableCheckboxRangeSelection = function() { + var lastCheckbox = null; + var followOn = 0; + var $spec = this; + $spec.bind("click", function(e) { + if (lastCheckbox != null && e.shiftKey) { + x = y = 0; + if (followOn != 0) { + if ($spec.index(lastCheckbox) < $spec.index(e.target)) { + x = 1 - ((followOn == 1) ? 1 : 0); + } else { + y = 1 - ((followOn == -1) ? 1 : 0); + } } - $output .= ''; + $spec.slice( + Math.min($spec.index(lastCheckbox) - x, $spec.index(e.target)) + 1, + Math.max($spec.index(lastCheckbox), $spec.index(e.target)) + y + ).attr("checked",function() { return ! this.checked; }) + .parent().parent().toggleClass("selected"); + followOn = ($spec.index(lastCheckbox) < $spec.index(e.target)) ? 1 : -1; } else { - if (is_array($do) AND isset($do[$col])) - $x = $do[$col]; - // If the col is a method, we need to eval it - elseif (preg_match('/\(/',$col)) - eval("\$x = \$do->$col;"); - else - $x = $do->{$col}; + followOn = 0; + } + lastCheckbox = e.target; + }); - $other += $x; + return $spec; + }; + + // Enable Toggle, (De)Select All + $.fn.check = function(mode) { + // if mode is undefined, use "on" as default + var mode = mode || "on"; + + switch(mode) { + case "on": + $("#select-table tr:not(.head)") + .filter(":has(:checkbox:not(checked))") + .toggleClass("selected") + break; + case "off": + $("#select-table tr:not(.head)") + .filter(":has(:checkbox:checked)") + .toggleClass("selected") + break; + case "toggle": + $("#select-table tr:not(.head)") + .toggleClass("selected"); + break; + } + + return this.each(function(e) { + switch(mode) { + case "on": + this.checked = true; + break; + case "off": + this.checked = false; + break; + case "toggle": + this.checked = !this.checked; + break; + } + }); + }; +})(jQuery); + +// Bind our actions +$(document).ready(function() { + $("#select-table :checkbox").enableCheckboxRangeSelection(); + $("#select-menu > #toggle").bind("click",function() { + $("#select-table :checkbox").check("toggle"); + }); + $("#select-menu > #all_on").bind("click",function() { + $("#select-table :checkbox").check("on"); + }); + $("#select-menu > #all_off").bind("click",function() { + $("#select-table :checkbox").check("off"); + }); + + // Our mouse over row highlight + $("#select-table tr:not(.head)").hover(function() { + $(this).children().toggleClass("highlight"); + }, + function() { + $(this).children().toggleClass("highlight"); + }); + + // Click to select Row + $("#select-table tr:not(.head)") + .filter(":has(:checkbox:checked)") + .addClass("selected") + .end() + .click(function(e) { + $(this).toggleClass("selected"); + if (e.target.type !== "checkbox") { + $(":checkbox", this).attr("checked", function() { + return !this.checked; + }); + } + }); +}); + ')); + + $output .= Form::open((isset($option['form']) ? $option['form'] : '')); + break; + + case 'list': + default: + Script::add(array( + 'type'=>'stdin', + 'data'=>' +// Bind our actions +$(document).ready(function() { + // Our mouse over row highlight + $("#list-table tr:not(.head)").hover(function() { + $(this).children().toggleClass("highlight"); + }, + function() { + $(this).children().toggleClass("highlight"); + }); +}); + ')); + } + + If (! $view) + $view = 'table/list'; + + if (isset($option['page']) AND $option['page']) { + $pag = new Pagination(array( + 'total_items'=>count($data), + 'items_per_page'=>$rows, + )); + + $output .= (string)$pag; + } + + $other = $i = 0; + $td = $th = array(); + foreach ($cols as $col => $details) { + $th[$col] = isset($details['label']) ? $details['label'] : ''; + $td[$col]['class'] = isset($details['class']) ? $details['class'] : ''; + $td[$col]['url'] = isset($details['url']) ? $details['url'] : ''; + } + + $output .= View::factory($view.'_head') + ->set('th',array_values($th)); + + foreach ($data as $do) { + if ($pag) { + if (++$i < $pag->current_first_item()) + continue; + elseif ($i > $pag->current_last_item()) + break; + } + + if ($pag OR ($i++ < $rows)) { + foreach (array_keys($cols) as $col) + $td[$col]['value'] = Table::resolve($do,$col); + + $output .= View::factory($view.'_body') + ->set('td',$td) + ->set('trc',$i%2 ? 'odd' : 'even'); + + } elseif (isset($option['show_other']) AND ($col=$option['show_other'])) { + $other += Table::resolve($do,$col); } } if ($other) - $output .= sprintf('',count($cols)-1,$i-$rows,$other); + $output .= View::factory($view.'_xtra') + ->set('td',array_values($cols)) + ->set('count',$i-$rows) + ->set('other',$other); - $output .= '
'.implode('',array_keys($cols)).'
%s
Other(%s) %s
'; + $output .= View::factory($view.'_foot'); + + if (isset($option['type']) AND $option['type']) + switch ($option['type']) { + case 'select': + $output .= Form::close(); + } return $output; } + + public static function post($key,$i='id') { + if (isset($_POST[$i])) + Session::instance()->set('page_table_view'.$key,$_POST[$i]); + } + + public static function page($key) { + if ($ids = Session::instance()->get('page_table_view'.$key)) { + $pag = new Pagination(array( + 'total_items'=>count($ids), + 'items_per_page'=>1, + )); + + return array($ids[$pag->current_first_item()-1],(string)$pag); + + // If we get here, then there is no previous data to retrieve. + } else + return array(NULL,''); + } } ?> diff --git a/application/classes/model/module.php b/application/classes/model/module.php index a7bb8f68..2fc039cf 100644 --- a/application/classes/model/module.php +++ b/application/classes/model/module.php @@ -27,8 +27,13 @@ class Model_Module extends ORMOSB { 'name'=>'ASC', ); - protected $_formats = array( - 'status'=>array('StaticList_YesNo::display'=>array()), + protected $_display_filters = array( + 'name'=>array( + array('strtoupper',array(':value')), + ), + 'status'=>array( + array('StaticList_YesNo::display',array(':value')), + ), ); } ?> diff --git a/application/config/pagination.php b/application/config/pagination.php new file mode 100644 index 00000000..889da06d --- /dev/null +++ b/application/config/pagination.php @@ -0,0 +1,15 @@ + array( + 'current_page' => array('source' => 'query_string', 'key' => 'page'), // source: "query_string" or "route" + 'total_items' => 0, + 'items_per_page' => 20, + 'view' => 'pagination/floating', + 'auto_hide' => TRUE, + 'first_page_in_url' => FALSE, + ), + +); diff --git a/application/media/css/default.css b/application/media/css/default.css index 277f02b8..56bdf1ba 100644 --- a/application/media/css/default.css +++ b/application/media/css/default.css @@ -1,5 +1,19 @@ /* Default Template CSS */ +.form_button { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 12px; + color: #000000; + background-color: #E1E1E3; + border-color: #AAAACC; + border-width: 1px; + padding: 1px; +} + +.highlight { + background-color: #AABBCC; +} + table.box-left { border: 1px solid #AAAACC; margin-right: auto; } table.box-center { border: 1px solid #AAAACC; margin-left: auto; margin-right: auto; } table.box-full { border: 1px solid #AAAACC; margin-right: auto; width: 100%; } @@ -14,6 +28,8 @@ td.data-right { font-weight: bold; text-align: right; } td.right { text-align: right; } tr.odd { background-color: #FCFCFE; } tr.even { background-color: #F6F6F8; } +tr.odd.selected { background-color: #ECECEE; } +tr.even.selected { background-color: #E6E6E8; } /* Global Page */ table.page { @@ -208,8 +224,6 @@ table.page tr.pagemain td.pagebody table.content table.subblockhead { table.page tr.pagemain td.pagebody table.content table.subblock { width: 100%; border: 1px solid #AAAACC; - margin-right: auto; - width: 100%; } table.page tr.pagemain td.pagebody table.content tr.title { diff --git a/application/views/table/list_body.php b/application/views/table/list_body.php new file mode 100644 index 00000000..0deec12a --- /dev/null +++ b/application/views/table/list_body.php @@ -0,0 +1,7 @@ + + $details) { ?> + + + + + diff --git a/modules/invoice/views/invoice/task/list_overdue_footer.php b/application/views/table/list_foot.php similarity index 100% rename from modules/invoice/views/invoice/task/list_overdue_footer.php rename to application/views/table/list_foot.php diff --git a/application/views/table/list_head.php b/application/views/table/list_head.php new file mode 100644 index 00000000..ab06c3c8 --- /dev/null +++ b/application/views/table/list_head.php @@ -0,0 +1,2 @@ + + diff --git a/application/views/table/list_xtra.php b/application/views/table/list_xtra.php new file mode 100644 index 00000000..a8c1fa78 --- /dev/null +++ b/application/views/table/list_xtra.php @@ -0,0 +1 @@ + diff --git a/application/views/table/select_body.php b/application/views/table/select_body.php new file mode 100644 index 00000000..8110a45b --- /dev/null +++ b/application/views/table/select_body.php @@ -0,0 +1,8 @@ + + + $details) { ?> + + + diff --git a/application/views/table/select_foot.php b/application/views/table/select_foot.php new file mode 100644 index 00000000..45034e94 --- /dev/null +++ b/application/views/table/select_foot.php @@ -0,0 +1,8 @@ +
',$th); ?>
Other
+ +
+
+
+ + + + +
diff --git a/application/views/table/select_head.php b/application/views/table/select_head.php new file mode 100644 index 00000000..a64ac769 --- /dev/null +++ b/application/views/table/select_head.php @@ -0,0 +1,2 @@ + + diff --git a/application/views/table/select_xtra.php b/application/views/table/select_xtra.php new file mode 100644 index 00000000..a8c1fa78 --- /dev/null +++ b/application/views/table/select_xtra.php @@ -0,0 +1 @@ + diff --git a/modules/account/classes/controller/user/account.php b/modules/account/classes/controller/user/account.php index f729aaa3..3ebc0875 100644 --- a/modules/account/classes/controller/user/account.php +++ b/modules/account/classes/controller/user/account.php @@ -93,7 +93,7 @@ class Controller_User_Account extends Controller_TemplateDefault_User { Block::add(array( 'title'=>sprintf('%s: %s - %s',_('Account Edit'),$this->ao->accnum(),$this->ao->name(TRUE)), - 'body'=>View::factory('account/edit') + 'body'=>View::factory('account/user/edit') ->set('record',$this->ao), )); } diff --git a/modules/account/classes/model/account.php b/modules/account/classes/model/account.php index ca068cdf..37a08da5 100644 --- a/modules/account/classes/model/account.php +++ b/modules/account/classes/model/account.php @@ -12,6 +12,7 @@ class Model_Account extends Model_Auth_UserDefault { // Relationships protected $_has_many = array( 'user_tokens' => array('model' => 'user_token'), + 'email_log' => array('far_key'=>'id'), 'group' => array('through' => 'account_group'), 'invoice' => array('far_key'=>'id'), 'payment'=>array('far_key'=>'id'), diff --git a/modules/account/views/account/edit.php b/modules/account/views/account/user/edit.php similarity index 100% rename from modules/account/views/account/edit.php rename to modules/account/views/account/user/edit.php diff --git a/modules/account/views/bregister.php b/modules/account/views/register.php similarity index 100% rename from modules/account/views/bregister.php rename to modules/account/views/register.php diff --git a/modules/email/classes/controller/admin/email.php b/modules/email/classes/controller/admin/email.php index c3909f12..3d225087 100644 --- a/modules/email/classes/controller/admin/email.php +++ b/modules/email/classes/controller/admin/email.php @@ -12,11 +12,38 @@ */ class Controller_Admin_Email extends Controller_TemplateDefault_Admin { protected $secure_actions = array( + 'list'=>TRUE, 'templateadd'=>TRUE, 'templateedit'=>TRUE, 'templatelist'=>TRUE, ); + /** + * Show a list of emails + */ + public function action_list() { + $elo = ORM::factory('email_log'); + + Block::add(array( + 'title'=>_('System Emails Sent'), + 'body'=>Table::display( + $elo->find_all(), + 25, + array( + 'id'=>array('label'=>'ID','url'=>'user/email/view/'), + 'date_orig'=>array('label'=>'Date'), + 'translate_resolve("subject")'=>array('label'=>'Subject'), + 'account->accnum()'=>array('label'=>'Cust ID'), + 'account->name()'=>array('label'=>'Customer'), + ), + array( + 'page'=>TRUE, + 'type'=>'select', + 'form'=>'user/email/view', + )), + )); + } + /** * List our defined email templates */ diff --git a/modules/email/classes/controller/user/email.php b/modules/email/classes/controller/user/email.php new file mode 100644 index 00000000..a03a937e --- /dev/null +++ b/modules/email/classes/controller/user/email.php @@ -0,0 +1,70 @@ +TRUE, + 'view'=>TRUE, + ); + + /** + * Show a list of emails + */ + public function action_list() { + Block::add(array( + 'title'=>sprintf('%s: %s - %s',_('Email For'),$this->ao->accnum(),$this->ao->name(TRUE)), + 'body'=>Table::display( + $this->ao->email_log->find_all(), + 25, + array( + 'id'=>array('label'=>'ID','url'=>'user/email/view/'), + 'date_orig'=>array('label'=>'Date'), + 'translate_resolve("subject")'=>array('label'=>'Subject'), + ), + array( + 'page'=>TRUE, + 'type'=>'select', + 'form'=>'user/email/view', + )), + )); + } + + public function action_view() { + $output = ''; + + if (! $id = $this->request->param('id')) { + if (isset($_POST['id']) AND is_array($_POST['id'])) + Table::post('email_view','id'); + + list($id,$output) = Table::page('email_view'); + + } else { + $id = $this->request->param('id'); + } + + $elo = ORM::factory('email_log',$id); + + if (! $elo->loaded() OR ! Auth::instance()->authorised($elo->account_id)) { + $this->template->content = 'Unauthorised or doesnt exist?'; + return FALSE; + } + + $output .= View::factory('email/user/view') + ->set('elo',$elo); + + Block::add(array( + 'title'=>sprintf('%s: %s',_('Email'),$elo->translate_resolve('subject')), + 'body'=>$output, + )); + } +} +?> diff --git a/modules/email/classes/email/template.php b/modules/email/classes/email/template.php index e576b65b..24b1d045 100644 --- a/modules/email/classes/email/template.php +++ b/modules/email/classes/email/template.php @@ -13,7 +13,7 @@ class Email_Template { // We'll store the template here private $template; - private $template_mail; + private $etto; private $email_data = array(); private $default_lang = 'en'; private $components = array('subject','message_text','message_html'); @@ -27,9 +27,9 @@ class Email_Template { if (is_null($language_id)) $language_id=$this->default_lang; - $this->template_mail = $this->template->email_template_translate->where('language_id','=',$language_id)->find(); - if (! $this->template_mail->loaded() AND - ($this->template_mail = $this->template->email_template_translate->where('language_id','=',$this->default_lang)->find()) AND ! $this->template_mail->loaded()) + $this->etto = $this->template->email_template_translate->where('language_id','=',$language_id)->find(); + if (! $this->etto->loaded() AND + ($this->etto = $this->template->email_template_translate->where('language_id','=',$this->default_lang)->find()) AND ! $this->etto->loaded()) // @todo Change this to log/email the admin throw new Kohana_Exception('No template (:template) found for user language (:language_id) or default language (:default_lang)', @@ -97,23 +97,20 @@ class Email_Template { $return = array(); foreach ($this->components as $v) - foreach ($this->template_mail->variables($v) as $x=>$y) + foreach ($this->etto->variables($v) as $x => $y) if (! in_array($y,$return)) array_push($return,$y); return $return; } - public function send($admin=FALSE) { + public function send(array $admin=array()) { $e = Email::connect(); $sm = Swift_Message::newInstance() ->setFrom(Kohana::config('config.email_from')); foreach ($this->components as $component) { - $s = $this->template_mail->$component; - - foreach ($this->template_mail->variables($component) as $k => $v) - $s = str_replace('%'.$v.'%',$this->email_data['variables'][$v],$s); + $s = $this->etto->resolve($this->email_data['variables'],$component); switch ($component) { case 'message_html': @@ -131,7 +128,6 @@ class Email_Template { } } - // @todo This should go to the admin defined in email_setup if ($admin OR ($admin = Config::testmail($this->template->name))) { $sm->setTo($admin); $sa = array(1); @@ -153,7 +149,7 @@ class Email_Template { $elo->clear(); $elo->account_id = $id; - $elo->email_template_id = $this->template_mail->id; + $elo->email_template_translate_id = $this->etto->id; $elo->data = $data; $elo->save(); } diff --git a/modules/email/classes/model/email/log.php b/modules/email/classes/model/email/log.php index a7bd4027..c39de74e 100644 --- a/modules/email/classes/model/email/log.php +++ b/modules/email/classes/model/email/log.php @@ -11,10 +11,26 @@ * @license http://dev.osbill.net/license.html */ class Model_Email_Log extends ORMOSB { + protected $_belongs_to = array( + 'account'=>array('far_key'=>'id'), + 'email_template_translate'=>array('far_key'=>'id'), + ); + + protected $_sorting = array( + 'id'=>'DESC', + ); + protected $_display_filters = array( 'date_orig'=>array( array('Config::datetime',array(':value')), ), ); + + public function translate_resolve($column) { + if (! $this->data OR ! ($r = $this->email_template_translate->variables($column))) + return $this->email_template_translate->display($column); + else + return $this->email_template_translate->resolve(unserialize(gzuncompress($this->data)),$column); + } } ?> diff --git a/modules/email/classes/model/email/template/translate.php b/modules/email/classes/model/email/template/translate.php index b1dabe32..6616cc81 100644 --- a/modules/email/classes/model/email/template/translate.php +++ b/modules/email/classes/model/email/template/translate.php @@ -28,5 +28,14 @@ class Model_Email_Template_Translate extends ORMOSB { return $results; } + + public function resolve($data,$column) { + $output = $this->display($column); + + foreach ($this->variables($column) as $k => $v) + $output = str_replace('%'.$v.'%',$data[$v],$output); + + return $output; + } } ?> diff --git a/modules/email/views/email/user/view.php b/modules/email/views/email/user/view.php new file mode 100644 index 00000000..a17da466 --- /dev/null +++ b/modules/email/views/email/user/view.php @@ -0,0 +1,20 @@ +
 ',$th); ?>
Other
+ + + + + + + + + + + + +
To:account->name(),$elo->account->display('email')); ?>
Date:display('date_orig'); ?>
Subject:translate_resolve('subject'); ?>
+ + + + +
translate_resolve('message_html'); ?>
+
diff --git a/modules/export/views/invoices.php b/modules/export/views/invoices.php deleted file mode 100644 index 4fb8c98a..00000000 --- a/modules/export/views/invoices.php +++ /dev/null @@ -1,28 +0,0 @@ -'.__FILE__.'
'; -echo Form::open(); -echo Form::select('plugin',$plugins); - -echo ''; -echo ''; -printf('','Date'); -printf('','Invoice'); -printf('','Customer'); -printf('','Method'); -printf('','Export'); -echo ''; - -$c = 0; -foreach ($invoices as $invoice) { - printf('',(++$c%2==0?'even':'odd')); - printf('', - $invoice->date_orig,$invoice->id, - $invoice->account->first_name,$invoice->account->last_name,$invoice->account->company,'paymentmethod',$invoice->total_amt,$invoice->due_date, - $invoice->id); - echo ''; -} - -echo '
%s%s%s%s%s
%s%s%s %s (%s)%s [%s/%s]
'; -echo Form::close(); -echo '
';print_r($invoice);
-?>
diff --git a/modules/invoice/classes/controller/admin/invoice.php b/modules/invoice/classes/controller/admin/invoice.php
index 83b8d4eb..2100cc72 100644
--- a/modules/invoice/classes/controller/admin/invoice.php
+++ b/modules/invoice/classes/controller/admin/invoice.php
@@ -11,6 +11,39 @@
  * @license    http://dev.osbill.net/license.html
  */
 class Controller_Admin_Invoice extends Controller_TemplateDefault_Admin {
+	protected $secure_actions = array(
+		'list'=>TRUE,
+	);
+
+	/**
+	 * Show a list of invoices
+	 */
+	public function action_list() {
+		$io = ORM::factory('invoice');
+
+		Block::add(array(
+			'title'=>_('System Customer Invoices'),
+			'body'=>Table::display(
+				$io->find_all(),
+				25,
+				array(
+					'id'=>array('label'=>'ID','url'=>'user/invoice/view/'),
+					'date_orig'=>array('label'=>'Date'),
+					'total_amt'=>array('label'=>'Total','class'=>'right'),
+					'credit_amt'=>array('label'=>'Credits','class'=>'right'),
+					'billed_amt'=>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'=>'user/invoice/view',
+				)),
+			));
+	}
+
 	public function action_convert() {
 		if (Config::sitemode() != KOHANA::DEVELOPMENT)
 			throw new Kohana_Exception(__METHOD__.' can only be run in development');
diff --git a/modules/invoice/classes/controller/invoice.php b/modules/invoice/classes/controller/invoice.php
index 0a4a76fe..e75a7c45 100644
--- a/modules/invoice/classes/controller/invoice.php
+++ b/modules/invoice/classes/controller/invoice.php
@@ -11,11 +11,5 @@
  * @license    http://dev.osbill.net/license.html
  */
 class Controller_Invoice extends Controller_TemplateDefault {
-	public function action_display() {
-		// @todo - this should be a global config item
-		$mediapath = Route::get('default/media');
-
-		$this->template->content = Kohana::debug(func_get_args());
-	}
 }
 ?>
diff --git a/modules/invoice/classes/controller/task/invoice.php b/modules/invoice/classes/controller/task/invoice.php
index 06490553..55779391 100644
--- a/modules/invoice/classes/controller/task/invoice.php
+++ b/modules/invoice/classes/controller/task/invoice.php
@@ -19,7 +19,7 @@ class Controller_Task_Invoice extends Controller_Task {
 			throw new Kohana_Exception('Unknown Task List command :command',array(':command'=>$mode));
 
 		$total = $numinv = 0;
-		$duelist = View::factory('invoice/task/'.$tm.'_header');
+		$duelist = View::factory('invoice/task/'.$tm.'_head');
 		foreach ($io->$tm() as $t) {
 			$duelist .= View::factory('invoice/task/'.$tm.'_body')
 				->set('io',$t);
@@ -27,7 +27,7 @@ class Controller_Task_Invoice extends Controller_Task {
 			$numinv++;
 			$total += $t->due();
 		}
-		$duelist .= View::factory('invoice/task/'.$tm.'_footer');
+		$duelist .= View::factory('invoice/task/'.$tm.'_foot');
 
 		// Send our email
 		$et = Email_Template::instance('task_invoice_overdue');
diff --git a/modules/invoice/classes/controller/user/invoice.php b/modules/invoice/classes/controller/user/invoice.php
index 336e9cbb..47e59538 100644
--- a/modules/invoice/classes/controller/user/invoice.php
+++ b/modules/invoice/classes/controller/user/invoice.php
@@ -18,20 +18,46 @@ class Controller_User_Invoice extends Controller_TemplateDefault_User {
 	);
 
 	/**
-	 * Show a product
+	 * 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'=>View::factory('invoice/user/list')
-				->set('invoices',$this->ao->invoice->find_all()),
+			'body'=>Table::display(
+				$this->ao->invoice->find_all(),
+				25,
+				array(
+					'id'=>array('label'=>'ID','url'=>'user/invoice/view/'),
+					'date_orig'=>array('label'=>'Date'),
+					'total_amt'=>array('label'=>'Total','class'=>'right'),
+					'credit_amt'=>array('label'=>'Credits','class'=>'right'),
+					'billed_amt'=>array('label'=>'Payments','class'=>'right'),
+					'due(TRUE)'=>array('label'=>'Still Due','class'=>'right'),
+				),
+				array(
+					'page'=>TRUE,
+					'type'=>'select',
+					'form'=>'user/invoice/view',
+				)),
 			));
 	}
 
 	/**
 	 * View an Invoice
 	 */
-	public function action_view($id) {
+	public function action_view() {
+		$output = '';
+
+		if (! $id = $this->request->param('id')) {
+			if (isset($_POST['id']) AND is_array($_POST['id']))
+				Table::post('invoice_view','id');
+
+			list($id,$output) = Table::page('invoice_view');
+
+		} else {
+			$id = $this->request->param('id');
+		}
+
 		$io = ORM::factory('invoice',$id);
 
 		if (! $io->loaded() OR ! Auth::instance()->authorised($io->account_id)) {
@@ -39,10 +65,14 @@ class Controller_User_Invoice extends Controller_TemplateDefault_User {
 			return FALSE;
 		}
 
-		// @todo media path probably should be a config item
-		$this->template->content = View::factory('invoice/user/html')
+		$output .= View::factory('invoice/user/view')
 			->set('mediapath',Route::get('default/media'))
-			->set('invoice',$io);
+			->set('io',$io);
+
+		Block::add(array(
+			'title'=>sprintf('%s: %s',_('Invoice'),$io->refnum()),
+			'body'=>$output,
+			));
 	}
 
 	/**
diff --git a/modules/module/views/module/admin/list_footer.php b/modules/invoice/views/invoice/task/list_overdue_foot.php
similarity index 100%
rename from modules/module/views/module/admin/list_footer.php
rename to modules/invoice/views/invoice/task/list_overdue_foot.php
diff --git a/modules/invoice/views/invoice/task/list_overdue_header.php b/modules/invoice/views/invoice/task/list_overdue_head.php
similarity index 100%
rename from modules/invoice/views/invoice/task/list_overdue_header.php
rename to modules/invoice/views/invoice/task/list_overdue_head.php
diff --git a/modules/invoice/views/invoice/user/list.php b/modules/invoice/views/invoice/user/list.php
deleted file mode 100644
index 343811b4..00000000
--- a/modules/invoice/views/invoice/user/list.php
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-	
-		
-		
-		
-		
-		
-		
-		
-	
-	
-		
-			
-			
-			
-			
-			
-			
-			
-		
-	
-
IDDateTotalCreditsPaymentsDueActive
id,$invoice->id()); ?>display('date_orig'); ?>display('total_amt'); ?>display('credit_amt'); ?>display('billed_amt'); ?>due()); ?>display('status'); ?>
diff --git a/modules/invoice/views/invoice/user/html.php b/modules/invoice/views/invoice/user/view.php similarity index 81% rename from modules/invoice/views/invoice/user/html.php rename to modules/invoice/views/invoice/user/view.php index 45e0fd73..2b4b0914 100644 --- a/modules/invoice/views/invoice/user/html.php +++ b/modules/invoice/views/invoice/user/view.php @@ -14,27 +14,27 @@ - + - + - + - + - + - +
TAX INVOICEid(); ?>id(); ?>
Issue Datedisplay('date_orig'); ?>display('date_orig'); ?>
Due Datedisplay('due_date'); ?>display('due_date'); ?>
Current Charges Duedisplay('total_amt'); ?>display('total_amt'); ?>
Payments Received to Datedisplay('billed_amt'); ?>display('billed_amt'); ?>
Total Charges Duedue(TRUE); ?>due(TRUE); ?>
@@ -46,7 +46,7 @@ Charges Detail: - sorted_service_items('recur_schedule') as $cat => $catitems) { ?> + sorted_service_items('recur_schedule') as $cat => $catitems) { ?>
uri(array('file'=>'img/toggle-closed.png')),array('alt'=>'+')); ?>
@@ -71,7 +71,7 @@ service->id,$item->service->id()); ?> product->product_translate->find()->name; ?> (product_id; ?>) - items_service_total($item->service_id));?> + items_service_total($item->service_id));?> @@ -86,7 +86,7 @@ items_sub($item->service_id) as $subitem) { + foreach ($io->items_sub($item->service_id) as $subitem) { if (! is_null($subitem->module_id)) { $m = StaticList_Module::record('module','name','id',$subitem->module_id); // @todo Need to remove the explicit test for 'charge' and be more dynamic @@ -109,14 +109,14 @@   - items_service_tax($item->service_id));?> + items_service_tax($item->service_id));?> items_sub(NULL) as $subitem) { + foreach ($io->items_sub(NULL) as $subitem) { if (! is_null($subitem->module_id)) { $m = StaticList_Module::record('module','name','id',$subitem->module_id); // @todo Need to remove the explicit test for 'charge' and be more dynamic @@ -142,13 +142,13 @@ Sub Total: - subtotal(TRUE); ?> + subtotal(TRUE); ?> Taxes Included: tax_summary() as $tid => $amount) { + foreach ($io->tax_summary() as $tid => $amount) { $m = ORM::factory('tax',$tid); ?> @@ -160,12 +160,12 @@ Total: - total(TRUE); ?> + total(TRUE); ?> - id,'Download detailed invoice'); ?> + id,'Download detailed invoice'); ?> diff --git a/modules/module/classes/controller/admin/module.php b/modules/module/classes/controller/admin/module.php index 638fa4cd..6ddc6a0c 100644 --- a/modules/module/classes/controller/admin/module.php +++ b/modules/module/classes/controller/admin/module.php @@ -12,6 +12,7 @@ */ class Controller_Admin_Module extends Controller_TemplateDefault_Admin { protected $secure_actions = array( + 'add'=>TRUE, 'edit'=>TRUE, 'list'=>TRUE, ); @@ -47,30 +48,32 @@ class Controller_Admin_Module extends Controller_TemplateDefault_Admin { * List our installed modules */ public function action_list() { - $modules = ORM::factory('module'); - - $output = ''; - - $output .= View::factory('module/admin/list_header'); - foreach ($modules->find_all() as $mo) { - $output .= View::factory('module/admin/list_body') - ->set('module',$mo); - } - $output .= View::factory('module/admin/list_footer'); + $mo = ORM::factory('module'); Block::add(array( - 'title'=>_('Currently installed modules'), - 'body'=>$output, - )); + 'title'=>sprintf('%s: %s - %s',_('Email For'),$this->ao->accnum(),$this->ao->name(TRUE)), + 'body'=>Table::display( + $mo->find_all(), + 25, + array( + 'id'=>array('label'=>'ID','url'=>'admin/module/edit/'), + 'name'=>array('label'=>'Name'), + 'status'=>array('label'=>'Active'), + ), + array( + 'page'=>TRUE, + 'type'=>'list', + )), + )); } /** * Edit a Module Configuration * - * @param int $mid Module ID * @todo Highlight those methods that have security, but the class does not have auth_required set to YES or the method isnt defined in secure_actions */ - public function action_edit($mid) { + public function action_edit() { + $mid = $this->request->param('id'); $mo = ORM::factory('module',$mid); if (! $mo->loaded()) { @@ -87,35 +90,42 @@ class Controller_Admin_Module extends Controller_TemplateDefault_Admin { $methods = $this->_methods($mo->name); // Show methods defined in the DB already. - $output .= View::factory('module/admin/method_list_header'); - foreach ($mo->module_method->find_all() as $meo) { + Block::add(array( + 'title'=>sprintf('%s: %s ',_('Defined Module Methods For'),$mo->display('name')), + 'body'=>Table::display( + $mo->module_method->find_all(), + 25, + array( + 'id'=>array('label'=>'ID','url'=>'admin/module_method/edit/'), + 'name'=>array('label'=>'Name'), + 'notes'=>array('label'=>'Notes'), + 'menu_display'=>array('label'=>'Menu'), + ), + array( + 'page'=>TRUE, + 'type'=>'list', + )), + )); + + // Show new methods NOT defined in the DB already. + foreach ($mo->module_method->find_all() as $meo) if (($method = array_search($meo->name,$methods)) !== false) unset($methods[$method]); - $output .= View::factory('module/admin/method_list_body') - ->set('method',$meo) - ->set('module',$mo) - ->set('defined',$method !== false); - } - - $output .= View::factory('module/admin/method_list_spacer'); - - // Show new methods NOT defined in the DB already. - foreach ($methods as $method) { - $meo = ORM::factory('module_method') - ->values(array('name'=>$method,'notes'=>_('Not defined in DB'))); - - $output .= View::factory('module/admin/method_list_body') - ->set('method',$meo) - ->set('module',$mo) - ->set('defined',$method === false); - } - $output .= View::factory('module/admin/method_list_footer'); - - Block::add(array( - 'title'=>sprintf(_('%s Methods'),strtoupper($mo->name)), - 'body'=>$output, - )); + if (count($methods)) + Block::add(array( + 'title'=>sprintf('%s: %s ',_('Undefined Module Methods For'),$mo->display('name')), + 'body'=>Table::display( + $methods, + 25, + array( + '__VALUE__'=>array('label'=>'Name','url'=>sprintf('admin/module_method/add/%s/',$mo->id)), + ), + array( + 'page'=>TRUE, + 'type'=>'list', + )), + )); } } ?> diff --git a/modules/module/classes/controller/admin/module/method.php b/modules/module/classes/controller/admin/module/method.php index 369f263e..b97f615a 100644 --- a/modules/module/classes/controller/admin/module/method.php +++ b/modules/module/classes/controller/admin/module/method.php @@ -10,7 +10,7 @@ * @copyright (c) 2010 Deon George * @license http://dev.leenooks.net/license.html */ -class Controller_Admin_Module_Method extends Controller_Module { +class Controller_Admin_Module_Method extends Controller_Admin_Module { /** * Add a method to the database */ @@ -63,7 +63,8 @@ class Controller_Admin_Module_Method extends Controller_Module { * * @param int $mid Module ID */ - public function action_edit($mid) { + public function action_edit() { + $mid = $this->request->param('id'); $mmo = ORM::factory('module_method',$mid); if (! $mmo->loaded()) { @@ -114,13 +115,13 @@ class Controller_Admin_Module_Method extends Controller_Module { $output .= Form::open(); - $output .= View::factory('module/admin/method_detail_header'); + $output .= View::factory('module/admin/method_detail_head'); foreach ($groups->find_all() as $go) { $output .= View::factory('module/admin/method_detail_body') ->set('group',$go) ->set('defined',$mmo->has('group',$go)); } - $output .= View::factory('module/admin/method_detail_footer'); + $output .= View::factory('module/admin/method_detail_foot'); $output .= '
'.Form::submit('submit',_('Update')).'
'; $output .= Form::close(); diff --git a/modules/module/views/module/admin/list_body.php b/modules/module/views/module/admin/list_body.php deleted file mode 100644 index 029b6ef3..00000000 --- a/modules/module/views/module/admin/list_body.php +++ /dev/null @@ -1,4 +0,0 @@ - - name; ?> - display('status'); ?> - diff --git a/modules/module/views/module/admin/list_header.php b/modules/module/views/module/admin/list_header.php deleted file mode 100644 index fb7b110b..00000000 --- a/modules/module/views/module/admin/list_header.php +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/modules/module/views/module/admin/method_detail_footer.php b/modules/module/views/module/admin/method_detail_foot.php similarity index 100% rename from modules/module/views/module/admin/method_detail_footer.php rename to modules/module/views/module/admin/method_detail_foot.php diff --git a/modules/module/views/module/admin/method_detail_header.php b/modules/module/views/module/admin/method_detail_head.php similarity index 100% rename from modules/module/views/module/admin/method_detail_header.php rename to modules/module/views/module/admin/method_detail_head.php diff --git a/modules/module/views/module/admin/method_list_body.php b/modules/module/views/module/admin/method_list_body.php deleted file mode 100644 index 9faa0db2..00000000 --- a/modules/module/views/module/admin/method_list_body.php +++ /dev/null @@ -1,11 +0,0 @@ - - - - - diff --git a/modules/module/views/module/admin/method_list_footer.php b/modules/module/views/module/admin/method_list_footer.php deleted file mode 100644 index 000ca4b0..00000000 --- a/modules/module/views/module/admin/method_list_footer.php +++ /dev/null @@ -1 +0,0 @@ -
ModuleActive
- - name; ?> - - name; ?> - - display('notes'); ?>display('menu_display'); ?>
diff --git a/modules/module/views/module/admin/method_list_header.php b/modules/module/views/module/admin/method_list_header.php deleted file mode 100644 index a70da832..00000000 --- a/modules/module/views/module/admin/method_list_header.php +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/modules/module/views/module/admin/method_list_spacer.php b/modules/module/views/module/admin/method_list_spacer.php deleted file mode 100644 index 673ad726..00000000 --- a/modules/module/views/module/admin/method_list_spacer.php +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/modules/payment/classes/controller/user/payment.php b/modules/payment/classes/controller/user/payment.php index 507c1682..8be87b10 100644 --- a/modules/payment/classes/controller/user/payment.php +++ b/modules/payment/classes/controller/user/payment.php @@ -20,9 +20,22 @@ class Controller_User_Payment extends Controller_TemplateDefault_User { */ public function action_list() { Block::add(array( - 'title'=>sprintf('%s: %s - %s',_('Payments For'),$this->ao->accnum(),$this->ao->name(TRUE)), - 'body'=>View::factory('payment/user/list') - ->set('payments',$this->ao->payment->find_all()), + 'title'=>sprintf('%s: %s - %s',_('Payments Received For'),$this->ao->accnum(),$this->ao->name(TRUE)), + 'body'=>Table::display( + $this->ao->payment->find_all(), + 25, + array( + 'id'=>array('label'=>'ID'), + 'date_payment'=>array('label'=>'Date'), + 'checkout->display("name")'=>array('label'=>'Method'), + 'total_amt'=>array('label'=>'Total','class'=>'right'), + 'balance(TRUE)'=>array('label'=>'Balance','class'=>'right'), + 'invoicelist()'=>array('label'=>'Invoices'), + ), + array( + 'page'=>TRUE, + 'type'=>'list', + )), )); } } diff --git a/modules/payment/views/payment/user/list.php b/modules/payment/views/payment/user/list.php deleted file mode 100644 index 6c9d4d39..00000000 --- a/modules/payment/views/payment/user/list.php +++ /dev/null @@ -1,21 +0,0 @@ - -
MethodNotesMenu
 
- - - - - - - - - - - - - - - - - - -
IDDateMethodTotalUnallocatedInvoices
id; ?>display('date_payment'); ?>checkout->display('name'); ?>display('total_amt'); ?>balance() ? ''.$po->balance(TRUE).'' : $po->balance(TRUE); ?>invoicelist(); ?>
diff --git a/modules/service/classes/controller/admin/service.php b/modules/service/classes/controller/admin/service.php index 11ee1201..4a040888 100644 --- a/modules/service/classes/controller/admin/service.php +++ b/modules/service/classes/controller/admin/service.php @@ -14,12 +14,43 @@ class Controller_Admin_Service extends Controller_TemplateDefault_Admin { protected $control = array('Services'=>'services'); protected $secure_actions = array( + 'list'=>TRUE, 'listbycheckout'=>TRUE, + 'listadslbilling'=>TRUE, 'listadslservices'=>TRUE, 'listhspaservices'=>TRUE, 'update'=>TRUE, ); + /** + * Show a list of services + */ + public function action_list() { + $so = ORM::factory('service'); + + Block::add(array( + 'title'=>_('System Customer Services'), + 'body'=>Table::display( + $so->find_all(), + 25, + array( + 'id'=>array('label'=>'ID','url'=>'user/service/view/'), + 'type'=>array('label'=>'Type'), + 'name()'=>array('label'=>'Details'), + 'recur_schedule'=>array('label'=>'Billing'), + 'price'=>array('label'=>'Price','class'=>'right'), + 'active'=>array('label'=>'Active'), + 'account->accnum()'=>array('label'=>'Cust ID'), + 'account->name()'=>array('label'=>'Customer'), + ), + array( + 'page'=>TRUE, + 'type'=>'select', + 'form'=>'user/email/view', + )), + )); + } + /** * List all services by their default checkout method */ diff --git a/modules/service/classes/controller/user/service.php b/modules/service/classes/controller/user/service.php index 34d90548..b6026f53 100644 --- a/modules/service/classes/controller/user/service.php +++ b/modules/service/classes/controller/user/service.php @@ -17,17 +17,43 @@ class Controller_User_Service extends Controller_TemplateDefault_User { ); /** - * Show a product + * Show a list of services */ public function action_list() { Block::add(array( 'title'=>sprintf('%s: %s - %s',_('Services For'),$this->ao->accnum(),$this->ao->name(TRUE)), - 'body'=>View::factory('service/user/list') - ->set('services',$this->ao->service->find_all()), + 'body'=>Table::display( + $this->ao->service->find_all(), + 25, + array( + 'id'=>array('label'=>'ID','url'=>'user/service/view/'), + 'type'=>array('label'=>'Type'), + 'name()'=>array('label'=>'Details'), + 'recur_schedule'=>array('label'=>'Billing'), + 'price'=>array('label'=>'Price','class'=>'right'), + 'active'=>array('label'=>'Active'), + ), + array( + 'page'=>TRUE, + 'type'=>'select', + 'form'=>'user/service/view', + )), )); } - public function action_view($id) { + public function action_view() { + $output = ''; + + if (! $id = $this->request->param('id')) { + if (isset($_POST['id']) AND is_array($_POST['id'])) + Table::post('service_view','id'); + + list($id,$output) = Table::page('service_view'); + + } else { + $id = $this->request->param('id'); + } + $so = ORM::factory('service',$id); if (! $so->loaded() OR ! Auth::instance()->authorised($so->account_id)) { @@ -35,10 +61,12 @@ class Controller_User_Service extends Controller_TemplateDefault_User { return FALSE; } + $output .= View::factory('service/user/view') + ->set('so',$so); + Block::add(array( 'title'=>sprintf('%s: %s',$so->id(),$so->product->name()), - 'body'=>View::factory('service/user/view') - ->set('so',$so), + 'body'=>$output, )); } } diff --git a/modules/service/views/service/user/list.php b/modules/service/views/service/user/list.php deleted file mode 100644 index 17b1e283..00000000 --- a/modules/service/views/service/user/list.php +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -
IDTypeDetailsBillingPriceActive
id,$service->id); ?>display('type'); ?>name(); ?>display('recur_schedule');?>display('price'); ?>display('active'); ?>