2013-10-10 02:44:53 +00:00
|
|
|
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This class supports OSB listing products
|
|
|
|
*
|
|
|
|
* @package Product
|
|
|
|
* @category Models
|
|
|
|
* @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
|
|
|
|
*/
|
|
|
|
class Model_Product extends ORM_OSB {
|
|
|
|
protected $_has_many = array(
|
|
|
|
'invoice'=>array('through'=>'invoice_item'),
|
2013-11-22 04:36:50 +00:00
|
|
|
'service'=>array('far_key'=>'id'),
|
|
|
|
'translate'=>array('model'=>'Product_Translate','far_key'=>'id'),
|
2013-10-10 02:44:53 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
protected $_sorting = array(
|
|
|
|
'position'=>'asc',
|
|
|
|
);
|
|
|
|
|
|
|
|
protected $_display_filters = array(
|
|
|
|
'price_type'=>array(
|
2013-04-26 01:42:09 +00:00
|
|
|
array('StaticList_PriceType::get',array(':value')),
|
2013-10-10 02:44:53 +00:00
|
|
|
),
|
|
|
|
'status'=>array(
|
2013-11-14 11:50:35 +00:00
|
|
|
array('StaticList_YesNo::get',array(':value',TRUE)),
|
2013-10-10 02:44:53 +00:00
|
|
|
),
|
|
|
|
'taxable'=>array(
|
2013-11-14 11:50:35 +00:00
|
|
|
array('StaticList_YesNo::get',array(':value',TRUE)),
|
2013-10-10 02:44:53 +00:00
|
|
|
),
|
|
|
|
);
|
|
|
|
|
2013-04-26 01:42:09 +00:00
|
|
|
protected $_nullifempty = array(
|
|
|
|
'price_group',
|
|
|
|
);
|
|
|
|
|
2013-10-10 02:44:53 +00:00
|
|
|
// Our attributes that are arrays, we'll convert/unconvert them
|
|
|
|
protected $_serialize_column = array(
|
|
|
|
'price_group',
|
|
|
|
);
|
|
|
|
|
2013-11-22 04:36:50 +00:00
|
|
|
protected $_save_message = TRUE;
|
|
|
|
|
2013-06-17 08:01:47 +00:00
|
|
|
/**
|
|
|
|
* Which categories is this product available in
|
|
|
|
*/
|
|
|
|
public function categories() {
|
|
|
|
return $this->avail_category;
|
|
|
|
}
|
|
|
|
|
2013-10-28 23:36:57 +00:00
|
|
|
public function cost($annual=FALSE) {
|
|
|
|
return $this->plugin() ? $this->plugin()->cost($annual) : 0;
|
|
|
|
}
|
|
|
|
|
2013-10-10 02:44:53 +00:00
|
|
|
/**
|
2013-04-26 01:42:09 +00:00
|
|
|
* Return the translated description for a category.
|
2013-10-10 02:44:53 +00:00
|
|
|
*/
|
2013-04-26 01:42:09 +00:00
|
|
|
public function description($full=FALSE) {
|
|
|
|
$x = $this->translate();
|
|
|
|
|
|
|
|
return $x->loaded() ? $x->display($full ? 'description_full' : 'description_short') : 'No Description';
|
2013-10-10 02:44:53 +00:00
|
|
|
}
|
|
|
|
|
2013-06-01 13:43:31 +00:00
|
|
|
/**
|
|
|
|
* This will render the product feature summary information
|
|
|
|
*/
|
|
|
|
public function feature_summary() {
|
|
|
|
return (is_null($plugin = $this->plugin())) ? HTML::nbsp('') : $plugin->feature_summary();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Is price shown for a specific period
|
|
|
|
*
|
|
|
|
* @param $p int recurring schedule period
|
|
|
|
*/
|
|
|
|
public function is_price_shown($p) {
|
|
|
|
$x = $this->keyget('price_group',$p);
|
|
|
|
|
|
|
|
return (isset($x['show']) AND $x['show']) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Test if the product is a TRIAL product
|
|
|
|
* (price_type == 2)
|
|
|
|
*
|
|
|
|
* @return boolean
|
|
|
|
*/
|
|
|
|
public function is_trial() {
|
|
|
|
return ($this->price_type == 2) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
2013-10-10 02:44:53 +00:00
|
|
|
/**
|
2013-04-26 01:42:09 +00:00
|
|
|
* Return the object of the product plugin
|
2013-10-10 02:44:53 +00:00
|
|
|
*/
|
2013-04-26 01:42:09 +00:00
|
|
|
public function plugin() {
|
|
|
|
if (! $this->prod_plugin_file)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (! is_numeric($this->prod_plugin_data))
|
|
|
|
throw new Kohana_Exception('Missing plugin_id for :product (:type)',array(':product'=>$this->id,':type'=>$this->prod_plugin_file));
|
|
|
|
|
|
|
|
return ORM::factory(Kohana::classname(sprintf('Product_Plugin_%s',$this->prod_plugin_file)),$this->prod_plugin_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function save(Validation $validation=NULL) {
|
2013-11-22 04:36:50 +00:00
|
|
|
parent::save($validation);
|
2013-04-26 01:42:09 +00:00
|
|
|
|
|
|
|
// Save our Translated Message
|
2013-11-22 04:36:50 +00:00
|
|
|
if ($x = array_diff_key($_POST,$this->_object) AND ! empty($_POST['language_id']) AND ! empty($_POST['translate']) AND is_array($_POST['translate'])) {
|
|
|
|
$to = $this->translate->where('language_id','=',$_POST['language_id'])->find();
|
2013-04-26 01:42:09 +00:00
|
|
|
|
2013-07-05 06:11:37 +00:00
|
|
|
// For a new entry, we need to set the product_id
|
2013-11-22 04:36:50 +00:00
|
|
|
if (! $to->loaded()) {
|
|
|
|
$to->product_id = $this->id;
|
|
|
|
$to->language_id = $_POST['language_id'];
|
2013-04-26 01:42:09 +00:00
|
|
|
}
|
|
|
|
|
2013-11-22 04:36:50 +00:00
|
|
|
$to->values($x['translate'])->save();
|
2013-04-26 01:42:09 +00:00
|
|
|
}
|
2013-11-22 04:36:50 +00:00
|
|
|
|
|
|
|
return $this;
|
2013-10-10 02:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-04-26 01:42:09 +00:00
|
|
|
* List the services that are linked to this product
|
2013-10-10 02:44:53 +00:00
|
|
|
*/
|
2013-04-26 01:42:09 +00:00
|
|
|
public function services($active=FALSE) {
|
|
|
|
return $active ? $this->service->where_active() : $this->service;
|
|
|
|
}
|
|
|
|
|
2013-10-28 23:36:57 +00:00
|
|
|
public function supplier() {
|
|
|
|
return $this->plugin() ? $this->plugin()->supplier() : 'other';
|
|
|
|
}
|
|
|
|
|
2013-04-26 01:42:09 +00:00
|
|
|
private function translate() {
|
2013-11-22 04:36:50 +00:00
|
|
|
return $this->translate->where('language_id','=',Config::language())->find();
|
2013-10-10 02:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2013-04-26 01:42:09 +00:00
|
|
|
* Return the translated title for a category
|
2013-10-10 02:44:53 +00:00
|
|
|
*/
|
2013-04-26 01:42:09 +00:00
|
|
|
public function title() {
|
|
|
|
$x = $this->translate();
|
|
|
|
|
|
|
|
return $x->loaded() ? $x->display('name') : 'No Title';
|
2013-10-10 02:44:53 +00:00
|
|
|
}
|
|
|
|
|
2013-06-01 13:43:31 +00:00
|
|
|
public function list_type($type) {
|
|
|
|
return $this->where('prod_plugin_file','=',$type)->find_all();
|
2013-10-10 02:44:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the best price to the uesr based on the users group's memberships
|
|
|
|
* @todo This needs to be tested with more than one price group enabled
|
|
|
|
*/
|
|
|
|
public function get_price_array() {
|
|
|
|
// Figure out our eligable groups
|
|
|
|
// @todo Need to work out our default groups elsewhere, not in product
|
|
|
|
// All users are members of the all user group "0"
|
|
|
|
$groups = array(0);
|
|
|
|
if (Auth::instance()->logged_in())
|
|
|
|
foreach (Auth::instance()->get_user()->group->find_all() as $go)
|
|
|
|
array_push($groups,$go->id);
|
|
|
|
|
|
|
|
// Work out the best price for the user
|
|
|
|
$price = array();
|
|
|
|
if (is_array($this->price_group))
|
|
|
|
foreach ($this->price_group as $bill_freq => $pg) {
|
|
|
|
if (isset($pg['show']) AND $pg['show'])
|
|
|
|
foreach ($groups as $gid) {
|
|
|
|
if (! empty($pg[$gid])) {
|
|
|
|
if (empty($price[$bill_freq]['price_base'])
|
|
|
|
OR ($pg[$gid]['price_base'] AND $price[$bill_freq]['price_base'] > $pg[$gid]['price_base'])) {
|
|
|
|
$price[$bill_freq]['price_setup'] = $pg[$gid]['price_setup'];
|
|
|
|
$price[$bill_freq]['price_base'] = $pg[$gid]['price_base'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// @todo Ugly hack
|
|
|
|
return $price ? $price : array('0'=>array('price_base'=>0,'price_setup'=>0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enable the plugin to store data
|
|
|
|
*/
|
|
|
|
public function admin_update() {
|
|
|
|
if (is_null($plugin = $this->plugin()))
|
|
|
|
return NULL;
|
|
|
|
else
|
|
|
|
return $plugin->admin_update();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the configured price groups for this product
|
|
|
|
*/
|
|
|
|
public function availPriceGroups() {
|
|
|
|
// @todo This needs to be worked out dynamically
|
|
|
|
return array(0,1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the available pricing options
|
|
|
|
*/
|
|
|
|
public function availPriceOptions() {
|
|
|
|
// @todo This needs to be worked out dynamically
|
|
|
|
return array('price_base','price_setup');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List the number of services using this product
|
|
|
|
*/
|
|
|
|
public function count_services() {
|
|
|
|
return $this->service->list_count(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* List the number of invoices using this product
|
|
|
|
*/
|
|
|
|
public function count_invoices() {
|
|
|
|
return $this->invoice->list_count(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the price for the particle group and price option for the period
|
|
|
|
*/
|
|
|
|
public function price($grp,$period,$option,$taxed=FALSE) {
|
|
|
|
$x = $this->keyget('price_group',$period);
|
|
|
|
|
|
|
|
if (isset($x[$grp][$option]))
|
|
|
|
return $taxed ? Tax::add($x[$grp][$option]) : $x[$grp][$option];
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
?>
|