Cart work for payments and Paypal work to test
This commit is contained in:
parent
133ae4d5c6
commit
69645c4eea
@ -2,7 +2,7 @@
|
|||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
|
|
||||||
# Installation directory
|
# Installation directory
|
||||||
RewriteBase /osb/
|
RewriteBase /
|
||||||
|
|
||||||
# Protect hidden files from being viewed
|
# Protect hidden files from being viewed
|
||||||
<Files .*>
|
<Files .*>
|
||||||
|
@ -90,7 +90,7 @@ if (isset($_SERVER['KOHANA_ENV']))
|
|||||||
* - boolean expose set the X-Powered-By header FALSE
|
* - boolean expose set the X-Powered-By header FALSE
|
||||||
*/
|
*/
|
||||||
Kohana::init(array(
|
Kohana::init(array(
|
||||||
'base_url' => '/osb/',
|
'base_url' => '/',
|
||||||
'caching' => TRUE,
|
'caching' => TRUE,
|
||||||
'index_file' => '',
|
'index_file' => '',
|
||||||
));
|
));
|
||||||
|
@ -254,21 +254,13 @@ class Auth_OSB extends Auth_ORM {
|
|||||||
$this->complete_login($user);
|
$this->complete_login($user);
|
||||||
|
|
||||||
// Do we need to update databases with our new sesion ID
|
// Do we need to update databases with our new sesion ID
|
||||||
// @todo figure out where this is best to go
|
$sct = Kohana::$config->load('config')->session_change_trigger;
|
||||||
$session_change_trigger = array('Cart'=>'session_id');
|
if (session_id() != $oldsess AND count($sct))
|
||||||
|
foreach ($sct as $t => $c)
|
||||||
if (count($session_change_trigger) AND (session_id() != $oldsess)) {
|
if (Config::moduleexist($t))
|
||||||
foreach ($session_change_trigger as $t => $c) {
|
foreach (ORM::factory(ucwords($t))->where($c,'=',$oldsess)->find_all() as $o)
|
||||||
if (Config::moduleexist($c)) {
|
|
||||||
$orm = ORM::factory($t)
|
|
||||||
->where($c,'=',$oldsess);
|
|
||||||
|
|
||||||
foreach ($orm->find_all() as $o)
|
|
||||||
$o->set('session_id',session_id())
|
$o->set('session_id',session_id())
|
||||||
->update();
|
->update();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
<?php defined('SYSPATH') or die('No direct access allowed.');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class overrides Kohana's Cache
|
|
||||||
*
|
|
||||||
* @package OSB/Modifications
|
|
||||||
* @category Classes
|
|
||||||
* @category Helpers
|
|
||||||
* @author Deon George
|
|
||||||
* @copyright (c) 2010 Deon George
|
|
||||||
* @license http://dev.leenooks.net/license.html
|
|
||||||
*/
|
|
||||||
abstract class Cache extends Kohana_Cache {
|
|
||||||
public static $default = 'apc';
|
|
||||||
}
|
|
||||||
?>
|
|
@ -124,7 +124,7 @@ class Config extends Kohana_Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static function moduleexist($module) {
|
public static function moduleexist($module) {
|
||||||
return array_key_exists($module,static::modules()) ? TRUE : FALSE;
|
return array_key_exists(strtolower($module),static::modules()) ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function copywrite() {
|
public static function copywrite() {
|
||||||
|
@ -12,6 +12,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Controller_Login extends lnApp_Controller_Login {
|
class Controller_Login extends lnApp_Controller_Login {
|
||||||
|
/**
|
||||||
|
* Enable site registration
|
||||||
|
*
|
||||||
|
* @todo Needs to be written
|
||||||
|
*/
|
||||||
public function action_register() {
|
public function action_register() {
|
||||||
// If user already signed-in
|
// If user already signed-in
|
||||||
if (Auth::instance()->logged_in()!= 0) {
|
if (Auth::instance()->logged_in()!= 0) {
|
||||||
@ -19,53 +24,7 @@ class Controller_Login extends lnApp_Controller_Login {
|
|||||||
HTTP::redirect('welcome/index');
|
HTTP::redirect('welcome/index');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate a new user
|
HTTP::redirect('login');
|
||||||
$account = ORM::factory('Account');
|
|
||||||
|
|
||||||
// If there is a post and $_POST is not empty
|
|
||||||
if ($_POST) {
|
|
||||||
// Check Auth
|
|
||||||
$status = $account->values($_POST)->check();
|
|
||||||
|
|
||||||
if (! $status) {
|
|
||||||
foreach ($account->validation()->errors('form/register') as $f => $r) {
|
|
||||||
// $r[0] has our reason for validation failure
|
|
||||||
switch ($r[0]) {
|
|
||||||
// Generic validation reason
|
|
||||||
default:
|
|
||||||
SystemMessage::add(array(
|
|
||||||
'title'=>_('Validation failed'),
|
|
||||||
'type'=>'error',
|
|
||||||
'body'=>sprintf(_('The defaults on your submission were not valid for field %s (%s).'),$f,$r)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$ido = ORM::factory('Module')
|
|
||||||
->where('name','=','account')
|
|
||||||
->find();
|
|
||||||
|
|
||||||
$account->id = $ido->record_id->next_id($ido->id);
|
|
||||||
// Save the user details
|
|
||||||
if ($account->save()) {}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemMessage::add(array(
|
|
||||||
'title'=>_('Already have an account?'),
|
|
||||||
'type'=>'info',
|
|
||||||
'body'=>_('If you already have an account, please login..')
|
|
||||||
));
|
|
||||||
|
|
||||||
Block::add(array(
|
|
||||||
'title'=>_('Register'),
|
|
||||||
'body'=>View::factory('register')
|
|
||||||
->set('account',$account)
|
|
||||||
->set('errors',$account->validation()->errors('form/register')),
|
|
||||||
));
|
|
||||||
|
|
||||||
$this->template->left = HTML::anchor('login','Login').'...';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,17 +39,11 @@ class Controller_TemplateDefault extends lnApp_Controller_TemplateDefault {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function _right() {
|
protected function _right() {
|
||||||
if ($this->template->right)
|
return ($this->template->right) ? $this->template->right : $this->_cart();
|
||||||
return $this->template->right;
|
|
||||||
else
|
|
||||||
return $this->_cart();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _cart() {
|
private function _cart() {
|
||||||
if (! Config::moduleexist('cart') OR ! class_exists('cart') OR ! Cart::instance()->contents()->reset(FALSE)->count_all())
|
return (! Config::moduleexist('cart') OR ! class_exists('Cart') OR ! count(Cart::instance()->contents()) OR strtolower(Request::current()->controller()) == 'cart') ? '' : Cart::instance()->cart_block();
|
||||||
return '';
|
|
||||||
|
|
||||||
return Cart::instance()->cart_block();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -11,21 +11,16 @@
|
|||||||
* @license http://dev.leenooks.net/license.html
|
* @license http://dev.leenooks.net/license.html
|
||||||
*/
|
*/
|
||||||
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {
|
class HTTP_Exception_404 extends Kohana_HTTP_Exception_404 {
|
||||||
public function __construct($message = NULL, array $variables = NULL, Exception $previous = NULL)
|
public function get_response() {
|
||||||
{
|
$response = Response::factory();
|
||||||
set_exception_handler(array(get_class($this),'handler'));
|
$response->status($this->_code);
|
||||||
parent::__construct($message, $variables, $previous);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function handler(Exception $e)
|
$view = View::factory('errors/404');
|
||||||
{
|
$view->message = $this->getMessage();
|
||||||
SystemMessage::add(array(
|
|
||||||
'title'=>_('Page not found'),
|
|
||||||
'type'=>'error',
|
|
||||||
'body'=>sprintf(_('The page [%s] you requested was not found?'),Request::detect_uri()),
|
|
||||||
));
|
|
||||||
|
|
||||||
HTTP::redirect('welcome');
|
$response->body($view->render());
|
||||||
|
|
||||||
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -46,5 +46,12 @@ abstract class Kohana extends Kohana_Core {
|
|||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Work out our Class Name as per Kohana's standards
|
||||||
|
*/
|
||||||
|
public static function classname($name) {
|
||||||
|
return str_replace(' ','_',ucwords(strtolower(str_replace('_',' ',$name))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -36,6 +36,15 @@ class Model_Module extends ORM_OSB {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an instance of this Module's Model
|
||||||
|
*
|
||||||
|
* @param $id PK of Model
|
||||||
|
*/
|
||||||
|
public function instance($id=NULL) {
|
||||||
|
return ORM::factory(ucwords($this->name),$id);
|
||||||
|
}
|
||||||
|
|
||||||
public function list_external() {
|
public function list_external() {
|
||||||
return $this->_where_active()->where('external','=',TRUE)->find_all();
|
return $this->_where_active()->where('external','=',TRUE)->find_all();
|
||||||
}
|
}
|
||||||
|
@ -37,77 +37,8 @@ abstract class ORM_OSB extends ORM {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This function will enhance the [Validate::filter], since it always passes
|
|
||||||
* the value as the first argument and sometimes functions need that to not
|
|
||||||
* be the first argument.
|
|
||||||
*
|
|
||||||
* Currently this implements:
|
|
||||||
* [date()][date-ref]
|
|
||||||
*
|
|
||||||
* [date-ref]: http://www.php.net/date
|
|
||||||
*
|
|
||||||
* This function will throw an exception if called without a function
|
|
||||||
* defined.
|
|
||||||
*
|
|
||||||
* @param mixed $val Value to be processed
|
|
||||||
* @param string $func Name of function to call
|
|
||||||
* @param string $arg Other arguments for the function
|
|
||||||
* @todo This has probably changed in KH 3.1
|
|
||||||
*/
|
|
||||||
final public static function _filters($val,$func,$arg) {
|
|
||||||
switch ($func) {
|
|
||||||
case 'date':
|
|
||||||
return date($arg,$val);
|
|
||||||
default:
|
|
||||||
throw new Exception(sprintf(_('Unknown function: %s (%s,%s)'),$func,$arg,$val));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final public static function form($table,$blank=FALSE) {
|
|
||||||
return ORM::factory($table)->formselect($blank);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Next record id
|
|
||||||
*
|
|
||||||
* @param array Validate object
|
|
||||||
* @param string Primary Key
|
|
||||||
*/
|
|
||||||
public static function get_next_id($model,$field) {
|
|
||||||
if (! is_null($model->$field))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
$model->_changed[$field] = $field;
|
|
||||||
|
|
||||||
$ido = ORM::factory('Module')
|
|
||||||
->where('name','=',$model->_table_name)
|
|
||||||
->find();
|
|
||||||
|
|
||||||
if (! $ido->loaded())
|
|
||||||
throw new Kohana_Exception('Problem getting record_id for :table',array(':table'=>$model->_table_name));
|
|
||||||
|
|
||||||
$model->$field = $ido->record_id->next_id($ido->id);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the site ID attribute for each row update
|
|
||||||
*/
|
|
||||||
public static function set_site_id($model,$field) {
|
|
||||||
if (! is_null($model->$field))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
$model->_changed[$field] = $field;
|
|
||||||
$model->$field = Config::siteid();
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __get($column) {
|
public function __get($column) {
|
||||||
if (array_key_exists($column,$this->_table_columns)) {
|
if (array_key_exists($column,$this->_table_columns)) {
|
||||||
|
|
||||||
// If the column is a blob, we'll decode it automatically
|
// If the column is a blob, we'll decode it automatically
|
||||||
if (
|
if (
|
||||||
$this->_table_columns[$column]['data_type'] == 'blob'
|
$this->_table_columns[$column]['data_type'] == 'blob'
|
||||||
@ -155,7 +86,94 @@ abstract class ORM_OSB extends ORM {
|
|||||||
return parent::__get($column);
|
return parent::__get($column);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function formselect($blank) {
|
/**
|
||||||
|
* This function will enhance the [Validate::filter], since it always passes
|
||||||
|
* the value as the first argument and sometimes functions need that to not
|
||||||
|
* be the first argument.
|
||||||
|
*
|
||||||
|
* Currently this implements:
|
||||||
|
* [date()][date-ref]
|
||||||
|
*
|
||||||
|
* [date-ref]: http://www.php.net/date
|
||||||
|
*
|
||||||
|
* This function will throw an exception if called without a function
|
||||||
|
* defined.
|
||||||
|
*
|
||||||
|
* @param mixed $val Value to be processed
|
||||||
|
* @param string $func Name of function to call
|
||||||
|
* @param string $arg Other arguments for the function
|
||||||
|
* @todo This has probably changed in KH 3.1
|
||||||
|
*/
|
||||||
|
final public static function x_filters($val,$func,$arg) {
|
||||||
|
switch ($func) {
|
||||||
|
case 'date':
|
||||||
|
return date($arg,$val);
|
||||||
|
default:
|
||||||
|
throw new Exception(sprintf(_('Unknown function: %s (%s,%s)'),$func,$arg,$val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function xform($table,$blank=FALSE) {
|
||||||
|
return ORM::factory($table)->formselect($blank);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve and Store DB BLOB data.
|
||||||
|
*/
|
||||||
|
private function blob($data,$set=FALSE) {
|
||||||
|
try {
|
||||||
|
return $set ? gzcompress(serialize($data)) : unserialize(gzuncompress($data));
|
||||||
|
|
||||||
|
// Maybe the data isnt compressed?
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return $set ? serialize($data) : unserialize($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function config($key) {
|
||||||
|
$mc = Config::instance()->so->module_config($this->_object_name);
|
||||||
|
|
||||||
|
return empty($mc[$key]) ? '' : $mc[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Next record id
|
||||||
|
*
|
||||||
|
* @param array Validate object
|
||||||
|
* @param string Primary Key
|
||||||
|
*/
|
||||||
|
final public static function get_next_id($model,$field) {
|
||||||
|
if (! is_null($model->$field))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
$model->_changed[$field] = $field;
|
||||||
|
|
||||||
|
$ido = ORM::factory('Module')
|
||||||
|
->where('name','=',$model->_table_name)
|
||||||
|
->find();
|
||||||
|
|
||||||
|
if (! $ido->loaded())
|
||||||
|
throw new Kohana_Exception('Problem getting record_id for :table',array(':table'=>$model->_table_name));
|
||||||
|
|
||||||
|
$model->$field = $ido->record_id->next_id($ido->id);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the site ID attribute for each row update
|
||||||
|
*/
|
||||||
|
final public static function set_site_id($model,$field) {
|
||||||
|
if (! is_null($model->$field))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
$model->_changed[$field] = $field;
|
||||||
|
$model->$field = Config::siteid();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function xformselect($blank) {
|
||||||
$result = array();
|
$result = array();
|
||||||
|
|
||||||
if ($blank)
|
if ($blank)
|
||||||
@ -174,6 +192,10 @@ abstract class ORM_OSB extends ORM {
|
|||||||
return array_key_exists($key,$this->$column) ? $this->{$column}[$key] : NULL;
|
return array_key_exists($key,$this->$column) ? $this->{$column}[$key] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function mid() {
|
||||||
|
return ORM::factory('Module',array('name'=>$this->_table_name));
|
||||||
|
}
|
||||||
|
|
||||||
public function save(Validation $validation = NULL) {
|
public function save(Validation $validation = NULL) {
|
||||||
// Find any fields that have changed, and process them.
|
// Find any fields that have changed, and process them.
|
||||||
if ($this->_changed)
|
if ($this->_changed)
|
||||||
@ -194,19 +216,6 @@ abstract class ORM_OSB extends ORM {
|
|||||||
return parent::save($validation);
|
return parent::save($validation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve and Store DB BLOB data.
|
|
||||||
*/
|
|
||||||
private function blob($data,$set=FALSE) {
|
|
||||||
return $set ? gzcompress(serialize($data)) : unserialize(gzuncompress($data));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function config($key) {
|
|
||||||
$mc = Config::instance()->so->module_config($this->_object_name);
|
|
||||||
|
|
||||||
return empty($mc[$key]) ? '' : $mc[$key];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function list_active() {
|
public function list_active() {
|
||||||
return $this->_where_active()->find_all();
|
return $this->_where_active()->find_all();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
<?php
|
|
||||||
class Cache extends Kohana_Cache {
|
|
||||||
public static $default = 'apc';
|
|
||||||
}
|
|
||||||
?>
|
|
@ -19,7 +19,7 @@ return array(
|
|||||||
|
|
||||||
'file' => array(
|
'file' => array(
|
||||||
'driver' => 'file',
|
'driver' => 'file',
|
||||||
'cache_dir' => Kohana::$cache_dir ? Kohana::$cache_dir : '/dev/shm/lnapp',
|
'cache_dir' => Kohana::$cache_dir ? Kohana::$cache_dir : APPPATH.'cache/',
|
||||||
'default_expire' => 3600,
|
'default_expire' => 3600,
|
||||||
'ignore_on_delete' => array(
|
'ignore_on_delete' => array(
|
||||||
'.gitignore',
|
'.gitignore',
|
||||||
|
@ -16,7 +16,7 @@ return array(
|
|||||||
'cache_type' => 'file',
|
'cache_type' => 'file',
|
||||||
'email_from' => array('noreply@graytech.net.au'=>'Graytech Hosting'),
|
'email_from' => array('noreply@graytech.net.au'=>'Graytech Hosting'),
|
||||||
'email_admin_only'=> array(
|
'email_admin_only'=> array(
|
||||||
'adsl_traffic_notice'=>array('deon@c5t61p.leenooks.vpn'=>'Deon George'),
|
// 'adsl_traffic_notice'=>array('deon@leenooks.vpn'=>'Deon George'),
|
||||||
),
|
),
|
||||||
'method_directory'=> array( // Out method paths for the different functions
|
'method_directory'=> array( // Out method paths for the different functions
|
||||||
'admin',
|
'admin',
|
||||||
@ -26,6 +26,9 @@ return array(
|
|||||||
'user',
|
'user',
|
||||||
),
|
),
|
||||||
'method_security' => TRUE, // Enables Method Security. Setting to false means any method can be run without authentication
|
'method_security' => TRUE, // Enables Method Security. Setting to false means any method can be run without authentication
|
||||||
|
'session_change_trigger'=>array( // Updates to tables to make when our session ID is changed
|
||||||
|
'Cart'=>'session_id',
|
||||||
|
),
|
||||||
'site' => array(
|
'site' => array(
|
||||||
'172.31.9.4'=>1,
|
'172.31.9.4'=>1,
|
||||||
'www.graytech.net.au'=>1,
|
'www.graytech.net.au'=>1,
|
||||||
|
@ -15,6 +15,7 @@ return array
|
|||||||
(
|
(
|
||||||
'ajax'=>FALSE, // AJAX actions can only be run by ajax calls if set to FALSE
|
'ajax'=>FALSE, // AJAX actions can only be run by ajax calls if set to FALSE
|
||||||
'etag'=>FALSE, // Force generating ETAGS
|
'etag'=>FALSE, // Force generating ETAGS
|
||||||
|
'checkout_notify'=>FALSE, // Test mode to test a particular checkout_notify item
|
||||||
'invoice'=>0, // Number of invoices to generate in a pass
|
'invoice'=>0, // Number of invoices to generate in a pass
|
||||||
'show_inactive'=>FALSE, // Show Inactive Items
|
'show_inactive'=>FALSE, // Show Inactive Items
|
||||||
'task_sim'=>FALSE, // Simulate running tasks
|
'task_sim'=>FALSE, // Simulate running tasks
|
||||||
|
1
application/views/errors/404.php
Normal file
1
application/views/errors/404.php
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?php echo $message; ?>
|
@ -11,8 +11,14 @@
|
|||||||
* @license http://dev.leenooks.net/license.html
|
* @license http://dev.leenooks.net/license.html
|
||||||
*/
|
*/
|
||||||
class Cart {
|
class Cart {
|
||||||
public static function instance() {
|
private $id = NULL;
|
||||||
return new Cart;
|
|
||||||
|
public function __construct($id=NULL) {
|
||||||
|
$this->id = is_null($id) ? Session::instance()->id() : $id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function instance($id=NULL) {
|
||||||
|
return new Cart($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -20,7 +26,34 @@ class Cart {
|
|||||||
*/
|
*/
|
||||||
public function contents() {
|
public function contents() {
|
||||||
return ORM::factory('Cart')
|
return ORM::factory('Cart')
|
||||||
->where('session_id','=',Session::instance()->id());
|
->where('session_id','=',$this->id)
|
||||||
|
->find_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function delete() {
|
||||||
|
foreach (ORM::factory('Cart')->where('session_id','=',$this->id)->find_all() as $co)
|
||||||
|
$co->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($mid,$item) {
|
||||||
|
return ORM::factory('Cart')
|
||||||
|
->where('session_id','=',$this->id)
|
||||||
|
->and_where('module_id','=',$mid)
|
||||||
|
->and_where('module_item','=',$item)
|
||||||
|
->find_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function id() {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function total($format=FALSE) {
|
||||||
|
$total = 0;
|
||||||
|
|
||||||
|
foreach ($this->contents() as $cio)
|
||||||
|
$total += $cio->item()->t;
|
||||||
|
|
||||||
|
return $format ? Currency::display($total) : $total;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -29,8 +62,10 @@ class Cart {
|
|||||||
* @param bool $detail List a detailed cart or a summary cart
|
* @param bool $detail List a detailed cart or a summary cart
|
||||||
*/
|
*/
|
||||||
public function cart_block() {
|
public function cart_block() {
|
||||||
|
// @todo To implement.
|
||||||
|
return '';
|
||||||
// If the cart is empty, we'll return here.
|
// If the cart is empty, we'll return here.
|
||||||
if (! $this->contents()->count_all())
|
if (! count($this->contents()))
|
||||||
return 'The cart is empty.';
|
return 'The cart is empty.';
|
||||||
|
|
||||||
Style::add(array(
|
Style::add(array(
|
||||||
@ -39,7 +74,7 @@ class Cart {
|
|||||||
));
|
));
|
||||||
|
|
||||||
$output = '<table class="cart_blocklist" border="0">';
|
$output = '<table class="cart_blocklist" border="0">';
|
||||||
foreach ($this->contents()->find_all() as $item) {
|
foreach ($this->contents() as $item) {
|
||||||
$ppa = $item->product->get_price_array();
|
$ppa = $item->product->get_price_array();
|
||||||
$pdata = Period::details($item->recurr_schedule,$item->product->price_recurr_weekday,time(),TRUE);
|
$pdata = Period::details($item->recurr_schedule,$item->product->price_recurr_weekday,time(),TRUE);
|
||||||
|
|
||||||
@ -58,48 +93,5 @@ class Cart {
|
|||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test to see if the cart has some trial options
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function has_trial() {
|
|
||||||
foreach ($this->contents()->find_all() as $item)
|
|
||||||
if ($item->product->is_trial())
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function subtotal() {
|
|
||||||
$total = 0;
|
|
||||||
|
|
||||||
foreach ($this->contents()->find_all() as $item) {
|
|
||||||
$ppa = $item->product->get_price_array();
|
|
||||||
$period = Period::details($item->recurr_schedule,$item->product->price_recurr_weekday,time(),TRUE);
|
|
||||||
|
|
||||||
$total += $item->quantity*$ppa[$item->recurr_schedule]['price_base']*$period['prorata'];
|
|
||||||
$total += $item->quantity*$ppa[$item->recurr_schedule]['price_setup'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate Tax for the cart items
|
|
||||||
*
|
|
||||||
* @return unknown_type
|
|
||||||
* @uses Tax
|
|
||||||
*/
|
|
||||||
public function tax() {
|
|
||||||
// @todo Tax zone should come from somewhere else
|
|
||||||
return Tax::detail(61,NULL,$this->subtotal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function total() {
|
|
||||||
// @todo Tax zone should come from somewhere else
|
|
||||||
return $this->subtotal()+Tax::total(61,NULL,$this->subtotal());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
37
modules/cart/classes/Cart/Item.php
Normal file
37
modules/cart/classes/Cart/Item.php
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides a Cart Item
|
||||||
|
*
|
||||||
|
* @package OSB
|
||||||
|
* @subpackage Cart
|
||||||
|
* @category Helpers
|
||||||
|
* @author Deon George
|
||||||
|
* @copyright (c) 2010 Deon George
|
||||||
|
* @license http://dev.leenooks.net/license.html
|
||||||
|
*/
|
||||||
|
class Cart_Item {
|
||||||
|
// Quantity
|
||||||
|
private $q = 0;
|
||||||
|
// Item
|
||||||
|
private $i = 0;
|
||||||
|
// Total
|
||||||
|
private $t = 0;
|
||||||
|
|
||||||
|
public function __construct($q,$i,$t) {
|
||||||
|
$this->q = $q;
|
||||||
|
$this->i = $i;
|
||||||
|
$this->t = $t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($key) {
|
||||||
|
switch($key) {
|
||||||
|
case 'i':
|
||||||
|
case 'q': return $this->{$key};
|
||||||
|
case 't': return Currency::display($this->{$key});
|
||||||
|
|
||||||
|
default: throw new Kohana_Exception('Unknown Key :key',array(':key',$key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
19
modules/cart/classes/Cartable.php
Normal file
19
modules/cart/classes/Cartable.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface ensures that all cart processing objects have the right methods
|
||||||
|
*
|
||||||
|
* @package OSB
|
||||||
|
* @subpackage Cart
|
||||||
|
* @category Helpers
|
||||||
|
* @author Deon George
|
||||||
|
* @copyright (c) 2010 Deon George
|
||||||
|
* @license http://dev.leenooks.net/license.html
|
||||||
|
*/
|
||||||
|
interface Cartable {
|
||||||
|
// Render a cart line item.
|
||||||
|
public function cart_item();
|
||||||
|
// Return if this invoice is already in the cart
|
||||||
|
public function cart_exists();
|
||||||
|
}
|
||||||
|
?>
|
@ -12,71 +12,56 @@
|
|||||||
*/
|
*/
|
||||||
class Controller_Cart extends Controller_TemplateDefault {
|
class Controller_Cart extends Controller_TemplateDefault {
|
||||||
/**
|
/**
|
||||||
* Default action when called
|
* List the cart contents
|
||||||
*/
|
*/
|
||||||
public function action_index() {
|
public function action_index() {
|
||||||
return $this->action_list();
|
$output = '';
|
||||||
}
|
$co = Cart::instance();
|
||||||
|
|
||||||
/**
|
|
||||||
* List items in the cart
|
|
||||||
*/
|
|
||||||
public function action_list() {
|
|
||||||
// @todo - this should be a global config item
|
|
||||||
$mediapath = Route::get('default/media');
|
|
||||||
|
|
||||||
// If the cart is empty, we'll return here.
|
// If the cart is empty, we'll return here.
|
||||||
if (! Cart::instance()->contents()->count_all())
|
if (! count($co->contents()))
|
||||||
Block::add(array(
|
Block::add(array(
|
||||||
'title'=>_('Empty Cart'),
|
'title'=>_('Empty Cart'),
|
||||||
'body'=>_('The cart is empty')
|
'body'=>_('The cart is empty')
|
||||||
));
|
));
|
||||||
|
|
||||||
else {
|
else {
|
||||||
Style::add(array(
|
Block::add(array(
|
||||||
'type'=>'file',
|
'title'=>_('Cart Items'),
|
||||||
'data'=>'css/cart_contents.css',
|
'body'=>Table::display(
|
||||||
|
$co->contents(),
|
||||||
|
NULL,
|
||||||
|
array(
|
||||||
|
'item()->q'=>array('label'=>'Quantity'),
|
||||||
|
'item()->i'=>array('label'=>'Item'),
|
||||||
|
'item()->t'=>array('label'=>'Total','class'=>'right'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'type'=>'list',
|
||||||
|
)
|
||||||
|
),
|
||||||
));
|
));
|
||||||
|
|
||||||
$output = Form::open('checkout/noready');
|
$checkout = ORM::factory('Checkout')->where_active()->find_all()->as_array();
|
||||||
foreach (Cart::instance()->contents()->find_all() as $item) {
|
|
||||||
$ppa = $item->product->get_price_array();
|
|
||||||
$pdata = Period::details($item->recurr_schedule,$item->product->price_recurr_weekday,time(),TRUE);
|
|
||||||
|
|
||||||
$price_box = View::factory('cart/list_pricebox')
|
foreach ($co->contents() as $cio)
|
||||||
->set('price_recurring',Currency::display($item->quantity*$ppa[$item->recurr_schedule]['price_base']))
|
$checkout = array_intersect($checkout,$cio->checkout()->as_array());
|
||||||
->set('price_firstinvoice',Currency::display($item->quantity*$ppa[$item->recurr_schedule]['price_base']*$pdata['prorata']))
|
|
||||||
->set('price_setup',Currency::display($item->quantity*$ppa[$item->recurr_schedule]['price_setup']))
|
|
||||||
->set('item',$item)
|
|
||||||
->set('mediapath',$mediapath);
|
|
||||||
|
|
||||||
$output .= View::factory('cart/list_item')
|
$payopt = array();
|
||||||
->set('price_box',$price_box)
|
foreach ($checkout as $cko)
|
||||||
->set('service_start',$pdata['date'])
|
$payopt[$cko->id] = $cko->name;
|
||||||
->set('service_end',$pdata['end'])
|
|
||||||
->set('price_recurring',Currency::display($item->quantity*$ppa[$item->recurr_schedule]['price_base']))
|
|
||||||
->set('item',$item)
|
|
||||||
->set('mediapath',$mediapath);
|
|
||||||
|
|
||||||
// If we are a plugin product, we might need more information
|
$output .= _('Total amount due for payment').' '.$co->total(TRUE);
|
||||||
// @todo If an admin, show a system message if cart_info doesnt exist.
|
$output .= Form::open('checkout/before');
|
||||||
if ($item->product->prod_plugin AND method_exists($item->product->prod_plugin_file,'product_cart') AND Kohana::find_file('views',sprintf('%s/cart_info',strtolower($item->product->prod_plugin_file)))) {
|
$output .= Form::select('checkout_id',$payopt);
|
||||||
$output .= View::factory(sprintf('%s/cart_info',strtolower($item->product->prod_plugin_file)));
|
$output .= Form::submit('submit',_('Checkout'));
|
||||||
|
|
||||||
// @todo JS validation will need to verify data before submission
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$output .= '<div>'.Form::submit('submit',_('Checkout')).'</div>';
|
|
||||||
$output .= Form::close();
|
$output .= Form::close();
|
||||||
|
|
||||||
Block::add(array(
|
Block::add(array(
|
||||||
'title'=>_('Your Items'),
|
'title'=>_('Payment'),
|
||||||
'body'=>$output,
|
'body'=>$output,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Suppress our right hand tab
|
|
||||||
$this->template->right = ' ';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,13 +72,10 @@ class Controller_Cart extends Controller_TemplateDefault {
|
|||||||
|
|
||||||
$cart->session_id = Session::instance()->id();
|
$cart->session_id = Session::instance()->id();
|
||||||
|
|
||||||
if (Auth::instance()->logged_in())
|
if ($cart->values(Request::current()->post())->check())
|
||||||
$cart->account_id = Auth::instance()->get_user()->id;
|
|
||||||
|
|
||||||
if ($cart->values($_POST)->check())
|
|
||||||
$cart->save();
|
$cart->save();
|
||||||
else
|
else
|
||||||
echo Kohana::debug($cart->validate()->errors());
|
throw new Kohana_Exception('Unable to add to cart');
|
||||||
|
|
||||||
if ($cart->saved())
|
if ($cart->saved())
|
||||||
HTTP::redirect('cart/index');
|
HTTP::redirect('cart/index');
|
||||||
@ -102,10 +84,8 @@ class Controller_Cart extends Controller_TemplateDefault {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function action_empty() {
|
public function action_empty() {
|
||||||
$cart = ORM::factory('Cart')
|
foreach (ORM::factory('Cart')->where('session_id','=',Session::instance()->id())->find_all() as $co)
|
||||||
->where('session_id','=',session_id());
|
$co->delete();
|
||||||
|
|
||||||
$cart->delete_all();
|
|
||||||
|
|
||||||
$this->template->content = _('Cart Emptied');
|
$this->template->content = _('Cart Emptied');
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,10 @@ class Model_Cart extends ORM_OSB {
|
|||||||
// Cart doesnt use the update column
|
// Cart doesnt use the update column
|
||||||
protected $_updated_column = FALSE;
|
protected $_updated_column = FALSE;
|
||||||
|
|
||||||
|
protected $_serialize_column = array(
|
||||||
|
'module_data',
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filters used to format the display of values into friendlier values
|
* Filters used to format the display of values into friendlier values
|
||||||
*/
|
*/
|
||||||
@ -26,5 +30,47 @@ class Model_Cart extends ORM_OSB {
|
|||||||
array('StaticList_RecurSchedule::display',array(':value')),
|
array('StaticList_RecurSchedule::display',array(':value')),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private $mo;
|
||||||
|
|
||||||
|
public function __construct($id = NULL) {
|
||||||
|
// Load our Model
|
||||||
|
parent::__construct($id);
|
||||||
|
|
||||||
|
// Autoload our Sub Items
|
||||||
|
if ($this->loaded())
|
||||||
|
$this->_load_sub_items();
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _load_sub_items() {
|
||||||
|
$this->mo = ORM::factory('Module',$this->module_id)->instance($this->module_item);
|
||||||
|
|
||||||
|
if (! $this->mo->loaded())
|
||||||
|
throw new Kohana_Exception('Item :item not loaded?',array(':item'=>$this->module_item));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkout() {
|
||||||
|
if (! method_exists($this->mo,'checkout'))
|
||||||
|
throw new Kohana_Exception('Module :module doesnt implement checkout?',array(':module'=>get_class($this->mo)));
|
||||||
|
|
||||||
|
return $this->mo->checkout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item() {
|
||||||
|
if (! method_exists($this->mo,'cart_item'))
|
||||||
|
throw new Kohana_Exception('Module :module doesnt implement cart_item?',array(':module'=>get_class($this->mo)));
|
||||||
|
|
||||||
|
return $this->mo->cart_item();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mo() {
|
||||||
|
return $this->mo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function motype() {
|
||||||
|
return strtolower(preg_replace('/^Model_/','',get_class($this->mo)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
/** Cart Block Contents Style Sheet **/
|
|
||||||
|
|
||||||
table.cart_blocklist {
|
|
||||||
/* margin-left: auto; */
|
|
||||||
/* margin-right: auto; */
|
|
||||||
width: 100%;
|
|
||||||
background-color: #F9F9FA;
|
|
||||||
border: 0px solid #AAAACC;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_blocklist tr td.sku {
|
|
||||||
color: #000000;
|
|
||||||
font-size: 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_blocklist tr td.price {
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_blocklist tr td.schedule {
|
|
||||||
font-size: 60%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_blocklist tr.submit td {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
table.cart_blocklist tr.submit td button {
|
|
||||||
font-size: 60%;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/** Cart Contents Style Sheet **/
|
|
||||||
|
|
||||||
table.cart_contents {
|
|
||||||
/* margin-left: auto; */
|
|
||||||
/* margin-right: auto; */
|
|
||||||
width: 100%;
|
|
||||||
background-color: #F9F9FA;
|
|
||||||
border: 0px solid #AAAACC;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td.title {
|
|
||||||
color: #000000;
|
|
||||||
font-size: 125%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td.title a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #0000AA;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td.icon {
|
|
||||||
width: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td.price_box {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td.price_box table.cart_detail_pricebox {
|
|
||||||
width: 100%;
|
|
||||||
background-color: #FAFAFB;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td.price_box table.cart_detail_pricebox td.head {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.cart_contents tr td.price_box table.cart_detail_pricebox td.value {
|
|
||||||
font-weight: bold;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/** Checkout Cart Style Sheet **/
|
|
||||||
|
|
||||||
table.checkout_cartlist {
|
|
||||||
/* margin-left: auto; */
|
|
||||||
/* margin-right: auto; */
|
|
||||||
width: 100%;
|
|
||||||
background-color: #F9F9FA;
|
|
||||||
border: 0px solid #AAAACC;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.checkout_cartlist tr td.title {
|
|
||||||
color: #000000;
|
|
||||||
font-size: 125%;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.checkout_cartlist tr td.title a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #0000AA;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.checkout_cartlist tr td {
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.checkout_cartlist tr td.icon {
|
|
||||||
width: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.checkout_cartlist tr td.value {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 120%;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
<tr>
|
|
||||||
<td class="sku"><?php echo $item->product->sku; ?></td>
|
|
||||||
<td class="schedule"><?php echo $item->display('recurr_schedule');?></td>
|
|
||||||
<td class="price"><?php echo Currency::display($price_firstinvoice+$price_setup); ?></td>
|
|
||||||
</tr>
|
|
@ -1,11 +0,0 @@
|
|||||||
<!-- @todo Translation required -->
|
|
||||||
<tr>
|
|
||||||
<td colspan="3" class="title"><b><?php echo HTML::anchor(sprintf('product/view/%s',$item->product->id),$item->product->product_translate->find()->name); ?></b></td>
|
|
||||||
<td class="value"><?php echo Currency::display($price_firstinvoice+$price_setup); ?></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td> </td>
|
|
||||||
<td>Current Service Period:</td>
|
|
||||||
<td><b><?php printf('%s -> %s',$service_start,$service_end);?></b></td>
|
|
||||||
<td> </td>
|
|
||||||
</tr>
|
|
@ -1,25 +0,0 @@
|
|||||||
<table>
|
|
||||||
<!-- @todo This rounding should be a global configuration item -->
|
|
||||||
<tr>
|
|
||||||
<td><?php echo Country::icon($country); ?></td>
|
|
||||||
<td>Cart Sub-Total:</td>
|
|
||||||
<td><?php echo Currency::display($cart->subtotal()); ?></td>
|
|
||||||
</tr>
|
|
||||||
<?php if ($cart->tax()) { ?>
|
|
||||||
<?php foreach ($cart->tax() as $tax) { ?>
|
|
||||||
<!-- @todo This rounding should be a global configuration item -->
|
|
||||||
<!-- @todo Tax details should come from central configuration -->
|
|
||||||
<tr>
|
|
||||||
<td> </td>
|
|
||||||
<td>Tax (<?php echo $tax['description']; ?>):</td>
|
|
||||||
<td><?php echo Currency::display($tax['amount']); ?></td>
|
|
||||||
</tr>
|
|
||||||
<?php } ?>
|
|
||||||
<?php } ?>
|
|
||||||
<!-- @todo This rounding should be a global configuration item -->
|
|
||||||
<tr>
|
|
||||||
<td> </td>
|
|
||||||
<td>Cart Total:</td>
|
|
||||||
<td><?php echo Currency::display($cart->total()); ?></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
@ -1,17 +0,0 @@
|
|||||||
<!-- @todo Translation required -->
|
|
||||||
<table class="cart_contents" border="0">
|
|
||||||
<tr>
|
|
||||||
<td colspan="3" class="title"><b><?php echo HTML::anchor(sprintf('product/view/%s',$item->product->id),$item->product->product_translate->find()->name); ?></b></td>
|
|
||||||
<td class="icon"><?php echo HTML::image($mediapath->uri(array('file'=>'img/edit-delete.png')),array('alt'=>_('Remove'))); ?></td>
|
|
||||||
<td rowspan="4" class="price_box"><?php echo $price_box; ?></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td> </td><td>Pricing Structure:</td><td colspan="2"><b><?php echo $item->product->display('price_type'); ?></b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td> </td><td>Invoice Frequency:</td><td colspan="2"><b><?php echo $item->display('recurr_schedule'); ?> (<?php echo $price_recurring; ?>)</b></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td> </td><td>Current Service Period:</td><td><b><?php printf('%s -> %s',$service_start,$service_end); ?></b></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
@ -1,27 +0,0 @@
|
|||||||
<!-- @todo translation needed -->
|
|
||||||
<table class="cart_detail_pricebox" border="0">
|
|
||||||
<tr>
|
|
||||||
<td class="head">Re-Occuring Price</td>
|
|
||||||
<td class="value"><?php echo $price_recurring; ?></td>
|
|
||||||
<td> </td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td colspan="2"> </td></tr>
|
|
||||||
<tr>
|
|
||||||
<td class="head">First Invoice</td>
|
|
||||||
<td class="value"><?php echo $price_firstinvoice; ?></td>
|
|
||||||
<td> </td>
|
|
||||||
</tr>
|
|
||||||
<?php if ($price_setup) { ?>
|
|
||||||
<tr>
|
|
||||||
<td class="head">Setup</td>
|
|
||||||
<td class="value"><?php echo $price_setup; ?></td>
|
|
||||||
<td> </td>
|
|
||||||
</tr>
|
|
||||||
<?php } ?>
|
|
||||||
<tr>
|
|
||||||
<td class="head">Quantity</td><!-- // @todo Quantity cannot be changed -->
|
|
||||||
<td class="value"><?php echo Form::input('quantity',$item->quantity,array('size'=>2,'disabled'=>'disabled')); ?></td>
|
|
||||||
<td class="icon"><?php echo HTML::image($mediapath->uri(array('file'=>'img/accessories-calculator-small.png')),array('alt'=>_('Re-Calc'))); ?></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
35
modules/checkout/classes/Checkout/Plugin.php
Normal file
35
modules/checkout/classes/Checkout/Plugin.php
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides CHECKOUT Plugin Support
|
||||||
|
*
|
||||||
|
* @package OSB
|
||||||
|
* @subpackage Checkout Plugins
|
||||||
|
* @category Plugins
|
||||||
|
* @author Deon George
|
||||||
|
* @copyright (c) 2010 Deon George
|
||||||
|
* @license http://dev.leenooks.net/license.html
|
||||||
|
* @todo Does this need to be Serializable?
|
||||||
|
*/
|
||||||
|
abstract class Checkout_Plugin implements Serializable {
|
||||||
|
protected $co; // Our Checkout Object
|
||||||
|
protected $_object;
|
||||||
|
|
||||||
|
// Our required abstract classes
|
||||||
|
public function serialize() {
|
||||||
|
return (string)$this->_object;
|
||||||
|
}
|
||||||
|
public function unserialize($s) {
|
||||||
|
$this->_object = XML::factory(NULL,NULL,$s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required abstract classes
|
||||||
|
// Present pre-plugin processing information
|
||||||
|
abstract public function before(Cart $co);
|
||||||
|
abstract public function notify(Model_Checkout_Notify $cno);
|
||||||
|
|
||||||
|
public function __construct(Model_Checkout $co) {
|
||||||
|
$this->co = $co;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
206
modules/checkout/classes/Checkout/Plugin/Paypal.php
Normal file
206
modules/checkout/classes/Checkout/Plugin/Paypal.php
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides PAYPAL support
|
||||||
|
*
|
||||||
|
* @package OSB
|
||||||
|
* @subpackage Plugins/Paypal
|
||||||
|
* @category Plugins
|
||||||
|
* @author Deon George
|
||||||
|
* @copyright (c) 2010 Deon George
|
||||||
|
* @license http://dev.leenooks.net/license.html
|
||||||
|
*/
|
||||||
|
abstract class Checkout_Plugin_Paypal extends Checkout_Plugin {
|
||||||
|
protected $url_prod = 'www.paypal.com';
|
||||||
|
protected $url_test = 'www.sandbox.paypal.com';
|
||||||
|
private $ipn_test = '173.0.82.126';
|
||||||
|
|
||||||
|
protected $curlopts = array(
|
||||||
|
CURLOPT_CONNECTTIMEOUT => 60,
|
||||||
|
CURLOPT_FAILONERROR => TRUE,
|
||||||
|
CURLOPT_FOLLOWLOCATION => FALSE,
|
||||||
|
CURLOPT_HEADER => FALSE,
|
||||||
|
CURLOPT_HTTPPROXYTUNNEL => FALSE,
|
||||||
|
CURLOPT_RETURNTRANSFER => TRUE,
|
||||||
|
CURLOPT_TIMEOUT => 30,
|
||||||
|
CURLOPT_SSL_VERIFYHOST => FALSE,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => FALSE,
|
||||||
|
CURLOPT_VERBOSE => FALSE,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User return from Paypal after payment
|
||||||
|
*/
|
||||||
|
public function after(Cart $co) {
|
||||||
|
SystemMessage::add(array(
|
||||||
|
'title'=>_('Payment Processing'),
|
||||||
|
'type'=>'info',
|
||||||
|
'body'=>sprintf('Thank you for your payment with paypal. It will be processed and applied to your cart items automatically in due course.'),
|
||||||
|
));
|
||||||
|
|
||||||
|
HTTP::redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User cancelled from Paypal and returned
|
||||||
|
*/
|
||||||
|
public function cancel(Cart $co) {
|
||||||
|
SystemMessage::add(array(
|
||||||
|
'title'=>_('Payment Cancelled'),
|
||||||
|
'type'=>'info',
|
||||||
|
'body'=>sprintf('Payment with Paypal was cancelled at your request.'),
|
||||||
|
));
|
||||||
|
|
||||||
|
HTTP::redirect('cart');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paypal payment notification and verification
|
||||||
|
*/
|
||||||
|
public function notify(Model_Checkout_Notify $cno) {
|
||||||
|
$debug_mode = Kohana::$config->load('debug')->checkout_notify;
|
||||||
|
|
||||||
|
// If testing
|
||||||
|
if (! $cno->status OR $cno->processed OR ($debug_mode AND Request::$client_ip == $this->ipn_test))
|
||||||
|
return ('Thank you');
|
||||||
|
|
||||||
|
$co = Cart::instance(isset($cno->data['custom']) ? $cno->data['custom'] : '');
|
||||||
|
|
||||||
|
if (! $co->contents())
|
||||||
|
return _('Thank you!');
|
||||||
|
|
||||||
|
if (! $debug_mode) {
|
||||||
|
$request = Request::factory(sprintf('https://%s/cgi-bin/webscr',$cno->data['test_ipn'] ? $this->url_test : $this->url_prod))
|
||||||
|
->method('POST');
|
||||||
|
|
||||||
|
$request->client()->options(Arr::merge($this->curlopts,array(
|
||||||
|
CURLOPT_POSTFIELDS => Arr::merge(array('cmd'=>'_notify-validate'),$cno->data),
|
||||||
|
)));
|
||||||
|
|
||||||
|
$response = $request->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($debug_mode ? 'VERIFIED' : $response->body()) {
|
||||||
|
case 'VERIFIED':
|
||||||
|
// Verify that the IPN is for us.
|
||||||
|
// @todo This should be in the DB.
|
||||||
|
if ($cno->data['business'] == 'deon_1260578114_biz@graytech.net.au') {
|
||||||
|
|
||||||
|
switch ($cno->data['payment_status']) {
|
||||||
|
case 'Completed':
|
||||||
|
// Our cart items total.
|
||||||
|
$total = $co->total();
|
||||||
|
$po = ORM::factory('Payment');
|
||||||
|
|
||||||
|
// Does the payment cover the cart total?
|
||||||
|
if ($this->co->fee_passon AND $cno->data['mc_gross'] == $total+$this->co->fee($total)) {
|
||||||
|
// Store the amounts in an array, so we can pro-rata the fee to each item.
|
||||||
|
$amts = array();
|
||||||
|
|
||||||
|
// Add the fee to each item (pro-rated)
|
||||||
|
for ($c=1;$c<=$cno->data['num_cart_items'];$c++) {
|
||||||
|
// The payment fee - there should only be 1 of these, and it should be the last item.
|
||||||
|
// We assume fees are added to $po->items() which are invoices.
|
||||||
|
if (preg_match('/^0:/',$cno->data['item_number'.$c])) {
|
||||||
|
$i = $j = 0;
|
||||||
|
foreach ($po->items() as $pio) {
|
||||||
|
$io = ORM::factory('Invoice',$pio->invoice_id);
|
||||||
|
// @todo Need to do tax.
|
||||||
|
$iio = $io->add_item();
|
||||||
|
$iio->quantity = 1;
|
||||||
|
$iio->module_id = $cno->mid()->id;
|
||||||
|
$iio->item_type = 125; // Payment Fee
|
||||||
|
$iio->price_base = (++$j==count($amts)) ? $cno->data['mc_gross_'.$c]-$i : Currency::round($pio->alloc_amt/array_sum($amts)*$cno->data['mc_gross_'.$c]);
|
||||||
|
$iio->date_start = $iio->date_stop = time();
|
||||||
|
|
||||||
|
// @todo Validate Save
|
||||||
|
$io->save();
|
||||||
|
|
||||||
|
$pio->alloc_amt = ($pio->alloc_amt+$iio->price_base > $pio->invoice->total()) ? $pio->alloc_amt : $pio->alloc_amt+$iio->price_base;
|
||||||
|
$i += $iio->price_base;
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif (is_numeric($cno->data['item_number'.$c])) {
|
||||||
|
array_push($amts,$cno->data['mc_gross_'.$c]);
|
||||||
|
$cio = ORM::factory('cart',$cno->data['item_number'.$c]);
|
||||||
|
|
||||||
|
if ($cio->loaded())
|
||||||
|
switch ($cio->motype()) {
|
||||||
|
case 'invoice':
|
||||||
|
// Validate we are all the same account
|
||||||
|
// @todo Need to handle if the cart has more than 1 account.
|
||||||
|
if (! $po->account_id AND $cio->mo()->account_id) {
|
||||||
|
$po->account_id = $cio->mo()->account_id;
|
||||||
|
|
||||||
|
} elseif ($po->account_id != $cio->mo()->account_id) {
|
||||||
|
throw new Kohana_Exception('Unable to handle payments for multiple accounts');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$po->add_item($cio->module_item)->alloc_amt = $cno->data['mc_gross_'.$c];
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Kohana_Exception('Dont know how to handle :item',array(':item',$cio->motype()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dont know how to handle this item.
|
||||||
|
} else {
|
||||||
|
// @todo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo Validate Save
|
||||||
|
$po->account_id = $cio->mo()->account_id;
|
||||||
|
$po->fees_amt = $cno->data['mc_fee'];
|
||||||
|
$po->total_amt = $cno->data['mc_gross'];
|
||||||
|
$po->date_payment = strtotime($cno->data['payment_date']);
|
||||||
|
$po->checkout_plugin_id = $this->co->id;
|
||||||
|
$po->notes = $cno->data['txn_id'];
|
||||||
|
$po->save();
|
||||||
|
|
||||||
|
// Clear the cart
|
||||||
|
if (! $debug_mode)
|
||||||
|
$co->delete();
|
||||||
|
|
||||||
|
} elseif (! $this->co->fee_passon AND $cno->data['mc_gross']-$cno->data['mc_fee'] == $total) {
|
||||||
|
// Ignore the fee
|
||||||
|
|
||||||
|
} else {
|
||||||
|
echo Debug::vars('IPN doesnt match cart total');
|
||||||
|
// If there is more than 1 item in the cart, we'll leave it to an admin to process.
|
||||||
|
if ($cno->data['num_cart_items'] == 1) {
|
||||||
|
echo Debug::vars('Apply to cart item');
|
||||||
|
} else {
|
||||||
|
// @todo - add the payment, with no payment items
|
||||||
|
echo Debug::vars('Leave for admin');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Refunded':
|
||||||
|
default:
|
||||||
|
throw new Kohana_Exception('Unable to handle payments of type :type',array(':type'=>$cno->data['payment_status']));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$cno->status = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'INVALID':
|
||||||
|
default:
|
||||||
|
$cno->status = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cno->processed = TRUE;
|
||||||
|
if (! $debug_mode)
|
||||||
|
$cno->save();
|
||||||
|
|
||||||
|
return _('Processed, thank you!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
56
modules/checkout/classes/Checkout/Plugin/Paypal/Cart.php
Normal file
56
modules/checkout/classes/Checkout/Plugin/Paypal/Cart.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides PAYPAL CART support
|
||||||
|
*
|
||||||
|
* @package OSB
|
||||||
|
* @subpackage Plugins/Paypal
|
||||||
|
* @category Plugins
|
||||||
|
* @author Deon George
|
||||||
|
* @copyright (c) 2010 Deon George
|
||||||
|
* @license http://dev.leenooks.net/license.html
|
||||||
|
*/
|
||||||
|
class Checkout_Plugin_Paypal_Cart extends Checkout_Plugin_Paypal {
|
||||||
|
private $test_mode = TRUE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set payment via Paypal
|
||||||
|
*/
|
||||||
|
public function before(Cart $co) {
|
||||||
|
$output = '';
|
||||||
|
|
||||||
|
$output .= View::factory('checkout/plugin/paypal/before')
|
||||||
|
->set('checkout',$this->co)
|
||||||
|
->set('cart',$co);
|
||||||
|
|
||||||
|
$output .= Form::open(sprintf('https://%s/cgi-bin/webscr',$this->test_mode ? $this->url_test : $this->url_prod),array('method'=>'POST'));
|
||||||
|
$output .= Form::hidden('cmd','_cart');
|
||||||
|
$output .= Form::hidden('business',$this->test_mode ? 'deon_1260578114_biz@graytech.net.au' : 'deon@graytech.net.au');
|
||||||
|
$output .= Form::hidden('bn','Graytech_BuyNow_WPS_AU');
|
||||||
|
$output .= Form::hidden('cancel_return',URL::site('checkout/cancel/'.$this->co->id,TRUE));
|
||||||
|
$output .= Form::hidden('custom',$co->id());
|
||||||
|
// @todo This should be dynamic
|
||||||
|
$output .= Form::hidden('currency_code','AUD');
|
||||||
|
$output .= Form::hidden('notify_url',URL::site('checkout/notify/'.$this->co->id,TRUE));
|
||||||
|
$output .= Form::hidden('return',URL::site('checkout/after/'.$this->co->id,TRUE));
|
||||||
|
$output .= Form::hidden('upload','1');
|
||||||
|
|
||||||
|
$c = 1;
|
||||||
|
foreach ($co->contents() as $cio) {
|
||||||
|
$output .= Form::hidden('item_number_'.$c,$cio->id);
|
||||||
|
$output .= Form::hidden('item_name_'.$c,$cio->item()->i);
|
||||||
|
$output .= Form::hidden('amount_'.$c,$cio->item()->t);
|
||||||
|
$c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$output .= Form::hidden('item_number_'.$c,'0:PAYFEE');
|
||||||
|
$output .= Form::hidden('item_name_'.$c,'Paypal Fee');
|
||||||
|
$output .= Form::hidden('amount_'.$c,$this->co->fee($co->total()));
|
||||||
|
|
||||||
|
$output .= Form::submit('submit','Pay Now');
|
||||||
|
$output .= Form::close();
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -11,137 +11,85 @@
|
|||||||
* @license http://dev.osbill.net/license.html
|
* @license http://dev.osbill.net/license.html
|
||||||
*/
|
*/
|
||||||
class Controller_Checkout extends Controller_TemplateDefault {
|
class Controller_Checkout extends Controller_TemplateDefault {
|
||||||
protected $auth_required = TRUE;
|
protected $auth_required = FALSE;
|
||||||
protected $noauth_redirect = 'login/register';
|
protected $secure_actions = array(
|
||||||
|
'before'=>TRUE,
|
||||||
|
'after'=>TRUE,
|
||||||
|
'cancel'=>TRUE,
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the main call to export, providing a list of items to export and
|
|
||||||
* setting up the page to call the export plugin when submitted.
|
|
||||||
*/
|
|
||||||
public function action_index() {
|
public function action_index() {
|
||||||
if ($_POST)
|
HTTP::redirect('cart');
|
||||||
return $this->checkout();
|
|
||||||
|
|
||||||
// @todo - this should be a global config item
|
|
||||||
$mediapath = Route::get('default/media');
|
|
||||||
|
|
||||||
// @todo Items in the cart dont have account_id if they were put in the cart when the user was not logged in
|
|
||||||
|
|
||||||
// If the cart is empty, we'll return here.
|
|
||||||
if (! Cart::instance()->contents()->count_all())
|
|
||||||
Block::add(array(
|
|
||||||
'title'=>_('Empty Cart'),
|
|
||||||
'body'=>_('The cart is empty')
|
|
||||||
));
|
|
||||||
|
|
||||||
else {
|
|
||||||
Style::add(array(
|
|
||||||
'type'=>'file',
|
|
||||||
'data'=>'css/checkout_cartlist.css',
|
|
||||||
));
|
|
||||||
|
|
||||||
// Show a list of items in the cart
|
|
||||||
$output = '<table class="checkout_cartlist" border="0">';
|
|
||||||
foreach (Cart::instance()->contents()->find_all() as $item) {
|
|
||||||
$ppa = $item->product->get_price_array();
|
|
||||||
$pdata = Period::details($item->recurr_schedule,$item->product->price_recurr_weekday,time(),TRUE);
|
|
||||||
|
|
||||||
$output .= View::factory('cart/checkout_list')
|
|
||||||
->set('price_firstinvoice',$item->quantity*$ppa[$item->recurr_schedule]['price_base']*$pdata['prorata'])
|
|
||||||
->set('price_setup',$item->quantity*$ppa[$item->recurr_schedule]['price_setup'])
|
|
||||||
->set('service_start',$pdata['date'])
|
|
||||||
->set('service_end',$pdata['end'])
|
|
||||||
->set('price_recurring',$item->quantity*$ppa[$item->recurr_schedule]['price_base'])
|
|
||||||
->set('item',$item)
|
|
||||||
->set('mediapath',$mediapath);
|
|
||||||
}
|
|
||||||
$output .= '</table>';
|
|
||||||
|
|
||||||
Block::add(array(
|
|
||||||
'title'=>_('Your Items'),
|
|
||||||
'body'=>$output,
|
|
||||||
));
|
|
||||||
|
|
||||||
$po = ORM::factory('Checkout')
|
|
||||||
->payment_options_cart();
|
|
||||||
|
|
||||||
// @todo Country value should come from somewhere?
|
|
||||||
Block::add(array(
|
|
||||||
'title'=>_('Order Total'),
|
|
||||||
'body'=>View::factory('cart/checkout_total')
|
|
||||||
->set('cart',Cart::instance())
|
|
||||||
->set('country',61),
|
|
||||||
));
|
|
||||||
|
|
||||||
$output = Form::open();
|
|
||||||
$output .= '<table class="payment_options_box" border="0">';
|
|
||||||
|
|
||||||
foreach ($po as $payment) {
|
|
||||||
$output .= View::factory('checkout/payment_option')
|
|
||||||
->set('payment',$payment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo Add Javascript to stop submission if something not selected
|
public function action_before() {
|
||||||
$output .= '<tr><td> </td></tr>';
|
// If we are not here by a POST operation, we'll redirect to the cart.
|
||||||
$output .= '<tr>';
|
if (! $cid=Request::current()->post('checkout_id'))
|
||||||
$output .= sprintf('<td>%s</td>',Form::submit('submit',_('Submit Order')));
|
HTTP::redirect('cart');
|
||||||
$output .= '</tr>';
|
|
||||||
|
|
||||||
$output .= '</table>';
|
$co = ORM::factory('Checkout',$cid);
|
||||||
$output .= Form::close();
|
|
||||||
|
|
||||||
Block::add(array(
|
Block::add(array(
|
||||||
'title'=>_('Available Payment Methods'),
|
'title'=>'Checkout',
|
||||||
'body'=>$output,
|
'body'=>$co->plugin()->before(Cart::instance()),
|
||||||
));
|
));
|
||||||
}
|
|
||||||
|
|
||||||
// Suppress our right hand tab
|
// Suppress our right hand tab
|
||||||
$this->template->right = ' ';
|
$this->template->right = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function action_after() {
|
||||||
* Process checkout
|
$co = ORM::factory('Checkout',$this->request->param('id'));
|
||||||
*/
|
|
||||||
private function checkout() {
|
|
||||||
$invoice = ORM::factory('Invoice');
|
|
||||||
|
|
||||||
// Add our individual items to the invoice
|
if (! $co->loaded())
|
||||||
foreach (Cart::instance()->contents()->find_all() as $item) {
|
HTTP::redirect('/');
|
||||||
$invoice_item = $invoice->add_item();
|
|
||||||
|
|
||||||
$invoice_item->product_id = $item->product_id;
|
return method_exists($co->plugin(),'after') ? $co->plugin()->after(Cart::instance()) : HTTP::redirect('/');
|
||||||
$invoice_item->product_attr = $item->product_attr;
|
|
||||||
$invoice_item->product_attr_cart = $item->product_attr;
|
|
||||||
$invoice_item->quantity = $item->quantity;
|
|
||||||
$invoice_item->recurring_schedule = $item->recurr_schedule;
|
|
||||||
|
|
||||||
$ppa = $item->product->get_price_array();
|
|
||||||
$period = Period::details($item->recurr_schedule,$item->product->price_recurr_weekday,time(),TRUE);
|
|
||||||
// @todo rounding should be a global config
|
|
||||||
$invoice_item->price_base = round($item->quantity*$ppa[$item->recurr_schedule]['price_base']*$period['prorata'],2);
|
|
||||||
$invoice_item->price_setup = round($item->quantity*$ppa[$item->recurr_schedule]['price_setup'],2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->account_id = Auth::instance()->get_user()->id;
|
public function action_cancel() {
|
||||||
$invoice->type = 2; // INVOICED VIA CHECKOUT
|
$co = ORM::factory('Checkout',$this->request->param('id'));
|
||||||
$invoice->status = 1; // INVOICE IS NOT CANCELLED
|
|
||||||
$invoice->due_date = time(); // DATE INVOICE MUST BE PAID
|
|
||||||
$invoice->billed_currency_id = 6; // @todo This should come from the site config or the currency selected
|
|
||||||
/*
|
|
||||||
$invoice->process_status = NULL; // TO BE PROCESSED
|
|
||||||
$invoice->billing_status = NULL; // UNPAID
|
|
||||||
$invoice->refund_status = NULL; // NOT REFUNDED
|
|
||||||
$invoice->print_status = NULL; // NOT YET PRINTED
|
|
||||||
$invoice->discount_amt = NULL; // @todo CALCULATE DISCOUNTS
|
|
||||||
$invoice->checkout_plugin_id = NULL; // @todo Update the selected checkout plugin
|
|
||||||
$invoice->checkout_plugin_data = NULL; // @todo Data required for the checkout plugin
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ($invoice->check())
|
if (! $co->loaded())
|
||||||
$invoice->save();
|
HTTP::redirect('cart');
|
||||||
else
|
|
||||||
throw new Kohana_Exception('Problem saving invoice - Failed check()');
|
return method_exists($co->plugin(),'cancel') ? $co->plugin()->cancel(Cart::instance()) : HTTP::redirect('cart');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function action_notify() {
|
||||||
|
$test_id = FALSE;
|
||||||
|
$co = ORM::factory('Checkout',$this->request->param('id'));
|
||||||
|
|
||||||
|
if ((! $co->loaded() OR ! Request::current()->post()) AND ! $test_id=Kohana::$config->load('debug')->checkout_notify)
|
||||||
|
throw HTTP_Exception::factory(404,'Payment not found!');
|
||||||
|
|
||||||
|
$this->auto_render = FALSE;
|
||||||
|
|
||||||
|
$cno = ORM::factory('Checkout_Notify');
|
||||||
|
|
||||||
|
if (! $test_id) {
|
||||||
|
$cno->checkout_id = $co->id;
|
||||||
|
$cno->status = 1;
|
||||||
|
$cno->data = Request::current()->post();
|
||||||
|
$cno->save();
|
||||||
|
} else {
|
||||||
|
$cno->where('id','=',$test_id)->find();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $cno->loaded())
|
||||||
|
throw HTTP_Exception::factory(500,'Unable to save!');
|
||||||
|
|
||||||
|
// Process our Notify
|
||||||
|
try {
|
||||||
|
$this->response->body($cno->process());
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->response->body('Received, thank you!');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response->headers('Content-Type','text/plain');
|
||||||
|
$this->response->headers('Content-Length',(string)$this->response->content_length());
|
||||||
|
$this->response->headers('Last-Modified',time());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -11,58 +11,38 @@
|
|||||||
* @license http://dev.osbill.net/license.html
|
* @license http://dev.osbill.net/license.html
|
||||||
*/
|
*/
|
||||||
class Model_Checkout extends ORM_OSB {
|
class Model_Checkout extends ORM_OSB {
|
||||||
protected $_has_many = array(
|
|
||||||
'account'=>array('through'=>'account_billing','foreign_key'=>'checkout_plugin_id'),
|
|
||||||
'payment'=>array(),
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Give a cart, this will present the available checkout options
|
* Calcuale the fee for this checkout method
|
||||||
*
|
|
||||||
* Trial Products are NEW products
|
|
||||||
* Cart items are NEW products
|
|
||||||
* Invoice items are RE-OCCURING items (ie: carts are not re-occuring)
|
|
||||||
*
|
*
|
||||||
|
* @param $amt The amount the fee will be based on
|
||||||
*/
|
*/
|
||||||
public function payment_options_cart() {
|
public function fee($amt) {
|
||||||
$cart = Cart::instance();
|
if (! $this->fee_passon)
|
||||||
|
return 0;
|
||||||
|
|
||||||
$available_payments = array();
|
$net = $amt;
|
||||||
|
|
||||||
if ($cart->has_trial())
|
if (! is_null($this->fee_fixed))
|
||||||
$this->and_where('allow_trial','=',TRUE);
|
$net += $this->fee_fixed;
|
||||||
|
|
||||||
$this->and_where('allow_new','=',TRUE);
|
if (! is_null($this->fee_variable))
|
||||||
|
$net /= (1-$this->fee_variable);
|
||||||
|
|
||||||
foreach ($this->list_active() as $item) {
|
return Currency::round($net-$amt);
|
||||||
// Check that the cart total meets the minimum requirement
|
|
||||||
if ($item->total_minimum AND $cart->total() < $item->total_minimum)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check the cart total meets the maximum requirement
|
|
||||||
if (($item->total_maximum AND $cart->total() > $item->total_maximum) OR ($item->total_maximum == '0' AND $cart->total()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Check that the payment option is available to this client based on groups
|
|
||||||
// @todo Enable this test
|
|
||||||
|
|
||||||
// Check that the payment option is not prohibited by an SKU item
|
|
||||||
// @todo Enable this test
|
|
||||||
|
|
||||||
// Check if this payment method is a default payment method
|
|
||||||
// @todo Enable this test
|
|
||||||
// By Amount
|
|
||||||
// By Currency
|
|
||||||
// By Group
|
|
||||||
// By Country
|
|
||||||
|
|
||||||
// This payment option is valid
|
|
||||||
array_push($available_payments,$item);
|
|
||||||
// Sort the checkout options
|
|
||||||
// @todo Is this required?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $available_payments;
|
/**
|
||||||
|
* Return the object of the checkout plugin
|
||||||
|
*/
|
||||||
|
public function plugin($type='') {
|
||||||
|
$c = Kohana::classname('Checkout_Plugin_'.$this->plugin);
|
||||||
|
|
||||||
|
if (! $this->plugin OR ! class_exists($c))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
$o = new $c($this);
|
||||||
|
|
||||||
|
return $type ? $o->$type : $o;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
23
modules/checkout/classes/Model/Checkout/Notify.php
Normal file
23
modules/checkout/classes/Model/Checkout/Notify.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php defined('SYSPATH') or die('No direct access allowed.');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides checkout capabilities.
|
||||||
|
*
|
||||||
|
* @package OSB
|
||||||
|
* @subpackage Checkout
|
||||||
|
* @category Models
|
||||||
|
* @author Deon George
|
||||||
|
* @copyright (c) 2010 Open Source Billing
|
||||||
|
* @license http://dev.osbill.net/license.html
|
||||||
|
*/
|
||||||
|
class Model_Checkout_Notify extends ORM_OSB {
|
||||||
|
// Relationships
|
||||||
|
protected $_has_one = array(
|
||||||
|
'checkout'=>array('far_key'=>'checkout_id','foreign_key'=>'id'),
|
||||||
|
);
|
||||||
|
|
||||||
|
public function process() {
|
||||||
|
return $this->checkout->plugin()->notify($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
32
modules/checkout/views/checkout/plugin/paypal/before.php
Normal file
32
modules/checkout/views/checkout/plugin/paypal/before.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<p>Paypal will be used to pay for the following items:</p>
|
||||||
|
</br>
|
||||||
|
<?php
|
||||||
|
echo Table::display(
|
||||||
|
$cart->contents(),
|
||||||
|
NULL,
|
||||||
|
array(
|
||||||
|
'item()->q'=>array('label'=>'Quantity'),
|
||||||
|
'item()->i'=>array('label'=>'Item'),
|
||||||
|
'item()->t'=>array('label'=>'Total','class'=>'right'),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'type'=>'list',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</br>
|
||||||
|
<p>Please Note: Paypal charges a fee to receive payments, and that fee will be added to your payment.</p>
|
||||||
|
<table class="list-box-left">
|
||||||
|
<tr class="list-data">
|
||||||
|
<th>Cart Total</th>
|
||||||
|
<td class="right"><?php echo $t=$cart->total(TRUE); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="list-data">
|
||||||
|
<th>Payment Fee</th>
|
||||||
|
<td class="right"><?php echo Currency::display($f=$checkout->fee($t)); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr class="list-data">
|
||||||
|
<th>Total</th>
|
||||||
|
<td class="right"><?php echo Currency::display($t+$f); ?></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
@ -61,6 +61,12 @@ class Controller_User_Invoice extends Controller_TemplateDefault_User {
|
|||||||
->set('mediapath',Route::get('default/media'))
|
->set('mediapath',Route::get('default/media'))
|
||||||
->set('io',$io);
|
->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) {
|
if (! $io->status) {
|
||||||
// Add a gribber popup
|
// Add a gribber popup
|
||||||
// @todo Make a gribber popup a class on its own.
|
// @todo Make a gribber popup a class on its own.
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* @copyright (c) 2010 Open Source Billing
|
* @copyright (c) 2010 Open Source Billing
|
||||||
* @license http://dev.osbill.net/license.html
|
* @license http://dev.osbill.net/license.html
|
||||||
*/
|
*/
|
||||||
class Model_Invoice extends ORM_OSB {
|
class Model_Invoice extends ORM_OSB implements Cartable {
|
||||||
protected $_belongs_to = array(
|
protected $_belongs_to = array(
|
||||||
'account'=>array()
|
'account'=>array()
|
||||||
);
|
);
|
||||||
@ -47,74 +47,68 @@ class Model_Invoice extends ORM_OSB {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** INTERFACE REQUIREMENTS **/
|
||||||
|
public function cart_item() {
|
||||||
|
return new Cart_Item(1,sprintf('Invoice: %s',$this->refnum()),$this->due());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return if this invoice is already in the cart
|
||||||
|
*/
|
||||||
|
public function cart_exists() {
|
||||||
|
return count(Cart::instance()->get($this->mid(),$this->id));
|
||||||
|
}
|
||||||
|
|
||||||
// Items belonging to an invoice
|
// Items belonging to an invoice
|
||||||
private $invoice_items = array();
|
private $invoice_items = array();
|
||||||
private $subitems_load = FALSE;
|
|
||||||
|
|
||||||
public function __construct($id = NULL) {
|
public function __construct($id = NULL) {
|
||||||
// Load our model.
|
// Load our Model
|
||||||
parent::__construct($id);
|
parent::__construct($id);
|
||||||
|
|
||||||
return $this->load_sub_items();
|
// Autoload our Sub Items
|
||||||
}
|
if ($this->loaded())
|
||||||
|
$this->_load_sub_items();
|
||||||
private function load_sub_items() {
|
|
||||||
// Load our sub items
|
|
||||||
if (! $this->subitems_load AND $this->loaded()) {
|
|
||||||
$this->invoice_items = $this->invoice_item->find_all()->as_array();
|
|
||||||
$this->subitems_load = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a list of invoice items for this payment.
|
* Load our invoice items
|
||||||
|
* We need these so that we can calculate totals, etc
|
||||||
*/
|
*/
|
||||||
public function items() {
|
private function _load_sub_items() {
|
||||||
$this->load_sub_items();
|
// Load our sub items
|
||||||
|
$this->invoice_items = $this->invoice_item->find_all()->as_array();
|
||||||
return $this->invoice_items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the Invoice Number
|
* Add an item to an invoice
|
||||||
*/
|
*/
|
||||||
public function id() {
|
public function add_item() {
|
||||||
return sprintf('%06s',$this->id);
|
if ($this->loaded() and ! $this->invoice_items)
|
||||||
|
throw new Kohana_Exception('Need to load invoice_items?');
|
||||||
|
|
||||||
|
$c = count($this->invoice_items);
|
||||||
|
|
||||||
|
$this->invoice_items[$c] = ORM::factory('Invoice_Item');
|
||||||
|
|
||||||
|
return $this->invoice_items[$c];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the Invoice Reference Number
|
* Return a list of valid checkout options for this invoice
|
||||||
*/
|
*/
|
||||||
public function refnum() {
|
public function checkout() {
|
||||||
return sprintf('%s-%06s',$this->account->accnum(),$this->id);
|
$due = $this->due();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return ORM::factory('Checkout')
|
||||||
* Display the amount due
|
->where_active()
|
||||||
*/
|
->where('amount_min','<=',$due)
|
||||||
public function due($format=FALSE) {
|
->where_open()
|
||||||
// If the invoice is active calculate the due amount
|
->and_where('amount_max','>=',$due)
|
||||||
$result = $this->status ? $this->total()-$this->payments_total() : 0;
|
->or_where('amount_max','is',null)
|
||||||
|
->where_close()->find_all();
|
||||||
// @todo This should not be required.
|
|
||||||
if ((Currency::round($result) == .01) or Currency::round($result) == .02)
|
|
||||||
$result = 0;
|
|
||||||
|
|
||||||
return $format ? Currency::display($result) : Currency::round($result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the subtotal of all items
|
|
||||||
*/
|
|
||||||
public function subtotal($format=FALSE) {
|
|
||||||
$result = 0;
|
|
||||||
|
|
||||||
foreach ($this->items() as $ito)
|
|
||||||
$result += $ito->subtotal();
|
|
||||||
|
|
||||||
return $format ? Currency::display($result) : Currency::round($result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function credits() {
|
public function credits() {
|
||||||
@ -139,41 +133,32 @@ class Model_Invoice extends ORM_OSB {
|
|||||||
return $format ? Currency::display($result) : Currency::round($result);
|
return $format ? Currency::display($result) : Currency::round($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tax($format=FALSE) {
|
/**
|
||||||
$result = 0;
|
* Display the amount due
|
||||||
|
*/
|
||||||
|
public function due($format=FALSE) {
|
||||||
|
// If the invoice is active calculate the due amount
|
||||||
|
$result = $this->status ? $this->total()-$this->payments_total() : 0;
|
||||||
|
|
||||||
foreach ($this->items() as $ito)
|
// @todo This should not be required.
|
||||||
$result += $ito->tax();
|
if ((Currency::round($result) == .01) or Currency::round($result) == .02)
|
||||||
|
$result = 0;
|
||||||
|
|
||||||
return $format ? Currency::display($result) : Currency::round($result);
|
return $format ? Currency::display($result) : Currency::round($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the total of all items
|
* Display the Invoice Number
|
||||||
*/
|
*/
|
||||||
public function total($format=FALSE) {
|
public function id() {
|
||||||
$result = 0;
|
return sprintf('%06s',$this->id);
|
||||||
|
|
||||||
foreach ($this->items() as $ito)
|
|
||||||
$result += $ito->total();
|
|
||||||
|
|
||||||
// Reduce by any credits
|
|
||||||
$result -= $this->credit_amt;
|
|
||||||
|
|
||||||
return $format ? Currency::display($result) : Currency::round($result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function payments() {
|
/**
|
||||||
return $this->payment_item->find_all();
|
* Return a list of invoice items for this payment.
|
||||||
}
|
*/
|
||||||
|
public function items() {
|
||||||
public function payments_total($format=FALSE) {
|
return $this->invoice_items;
|
||||||
$result = 0;
|
|
||||||
|
|
||||||
foreach ($this->payments() as $po)
|
|
||||||
$result += $po->alloc_amt;
|
|
||||||
|
|
||||||
return $format ? Currency::display($result) : Currency::round($result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -345,79 +330,28 @@ class Model_Invoice extends ORM_OSB {
|
|||||||
return $total;
|
return $total;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of taxes used on this invoice
|
|
||||||
* @todo Move some of this to invoice_item_tax.
|
|
||||||
*/
|
|
||||||
public function tax_summary() {
|
|
||||||
$summary = array();
|
|
||||||
|
|
||||||
foreach ($this->items() as $ito) {
|
|
||||||
foreach ($ito->invoice_item_tax->find_all() as $item_tax) {
|
|
||||||
if (! isset($summary[$item_tax->tax_id]))
|
|
||||||
$summary[$item_tax->tax_id] = $item_tax->amount;
|
|
||||||
else
|
|
||||||
$summary[$item_tax->tax_id] += $item_tax->amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo This should be removed eventually
|
|
||||||
if (! $summary)
|
|
||||||
$summary[1] = $this->tax();
|
|
||||||
|
|
||||||
return $summary;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an item to an invoice
|
|
||||||
*/
|
|
||||||
public function add_item() {
|
|
||||||
if ($this->loaded() and ! $this->invoice_items)
|
|
||||||
throw new Kohana_Exception('Need to load invoice_items?');
|
|
||||||
|
|
||||||
$c = count($this->invoice_items);
|
|
||||||
|
|
||||||
$this->invoice_items[$c] = ORM::factory('Invoice_Item');
|
|
||||||
|
|
||||||
return $this->invoice_items[$c];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function min_due($date) {
|
public function min_due($date) {
|
||||||
return strtotime(date('Y-M-d',($date < time()) ? time()+ORM::factory('Invoice')->config('DUE_DAYS_MIN')*86400 : $date));
|
return strtotime(date('Y-M-d',($date < time()) ? time()+ORM::factory('Invoice')->config('DUE_DAYS_MIN')*86400 : $date));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function save(Validation $validation = NULL) {
|
/**
|
||||||
// Our items will be clobbered once we save the object, so we need to save it here.
|
* Display the Invoice Reference Number
|
||||||
$items = $this->items();
|
*/
|
||||||
|
public function refnum() {
|
||||||
// Save the invoice
|
return sprintf('%s-%06s',$this->account->accnum(),$this->id);
|
||||||
parent::save($validation);
|
|
||||||
|
|
||||||
// Need to save the associated items and their taxes
|
|
||||||
if ($this->saved()) {
|
|
||||||
foreach ($items as $iio) {
|
|
||||||
$iio->invoice_id = $this->id;
|
|
||||||
|
|
||||||
if (! $iio->check()) {
|
|
||||||
// @todo Mark invoice as cancelled and write a memo, then...
|
|
||||||
throw new Kohana_Exception('Problem saving invoice_item for invoice :invoice - Failed check()',array(':invoice'=>$invoice->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$iio->save();
|
public function payments() {
|
||||||
|
return $this->payment_item->find_all();
|
||||||
if (! $iio->saved()) {
|
|
||||||
// @todo Mark invoice as cancelled and write a memo, then...
|
|
||||||
throw new Kohana_Exception('Problem saving invoice_item for invoice :invoice - Failed save()',array(':invoice'=>$invoice->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @todo Need to save discount information
|
public function payments_total($format=FALSE) {
|
||||||
}
|
$result = 0;
|
||||||
|
|
||||||
|
foreach ($this->payments() as $po)
|
||||||
|
$result += $po->alloc_amt;
|
||||||
|
|
||||||
} else
|
return $format ? Currency::display($result) : Currency::round($result);
|
||||||
throw new Kohana_Exception('Couldnt save invoice for some reason?');
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,6 +375,44 @@ class Model_Invoice extends ORM_OSB {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function save(Validation $validation = NULL) {
|
||||||
|
// Our items will be clobbered once we save the object, so we need to save it here.
|
||||||
|
$items = $this->items();
|
||||||
|
|
||||||
|
// Save the invoice
|
||||||
|
if ($this->changed())
|
||||||
|
parent::save($validation);
|
||||||
|
|
||||||
|
// Need to save the associated items and their taxes
|
||||||
|
if ($this->loaded()) {
|
||||||
|
foreach ($items as $iio) {
|
||||||
|
$iio->invoice_id = $this->id;
|
||||||
|
|
||||||
|
if (! $iio->changed())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (! $iio->check()) {
|
||||||
|
// @todo Mark invoice as cancelled and write a memo, then...
|
||||||
|
throw new Kohana_Exception('Problem saving invoice_item for invoice :invoice - Failed check()',array(':invoice'=>$this->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
$iio->save();
|
||||||
|
|
||||||
|
if (! $iio->saved()) {
|
||||||
|
// @todo Mark invoice as cancelled and write a memo, then...
|
||||||
|
throw new Kohana_Exception('Problem saving invoice_item for invoice :invoice - Failed save()',array(':invoice'=>$this->id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo Need to save discount information
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} else
|
||||||
|
throw new Kohana_Exception('Couldnt save invoice for some reason?');
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
public function set_remind($key,$value,$add=FALSE) {
|
public function set_remind($key,$value,$add=FALSE) {
|
||||||
if (! $this->loaded())
|
if (! $this->loaded())
|
||||||
throw new Kohana_Exception('Cant call :method when a record not loaded.',array(':method',__METHOD__));
|
throw new Kohana_Exception('Cant call :method when a record not loaded.',array(':method',__METHOD__));
|
||||||
@ -484,6 +456,69 @@ class Model_Invoice extends ORM_OSB {
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the subtotal of all items
|
||||||
|
*/
|
||||||
|
public function subtotal($format=FALSE) {
|
||||||
|
$result = 0;
|
||||||
|
|
||||||
|
foreach ($this->items() as $ito)
|
||||||
|
$result += $ito->subtotal();
|
||||||
|
|
||||||
|
return $format ? Currency::display($result) : Currency::round($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tax($format=FALSE) {
|
||||||
|
$result = 0;
|
||||||
|
|
||||||
|
foreach ($this->items() as $ito)
|
||||||
|
$result += $ito->tax();
|
||||||
|
|
||||||
|
return $format ? Currency::display($result) : Currency::round($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a list of taxes used on this invoice
|
||||||
|
* @todo Move some of this to invoice_item_tax.
|
||||||
|
*/
|
||||||
|
public function tax_summary() {
|
||||||
|
$summary = array();
|
||||||
|
|
||||||
|
foreach ($this->items() as $ito) {
|
||||||
|
foreach ($ito->invoice_item_tax->find_all() as $item_tax) {
|
||||||
|
if (! isset($summary[$item_tax->tax_id]))
|
||||||
|
$summary[$item_tax->tax_id] = $item_tax->amount;
|
||||||
|
else
|
||||||
|
$summary[$item_tax->tax_id] += $item_tax->amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo This should be removed eventually
|
||||||
|
if (! $summary)
|
||||||
|
$summary[1] = $this->tax();
|
||||||
|
|
||||||
|
return $summary;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the total of all items
|
||||||
|
*/
|
||||||
|
public function total($format=FALSE) {
|
||||||
|
$result = 0;
|
||||||
|
|
||||||
|
// @todo - This should be required, but during checkout payment processing $pio->invoice->total() showed no invoice items?
|
||||||
|
if ($this->loaded() AND ! count($this->items()))
|
||||||
|
$this->_load_sub_items();
|
||||||
|
|
||||||
|
foreach ($this->items() as $ito)
|
||||||
|
$result += $ito->total();
|
||||||
|
|
||||||
|
// Reduce by any credits
|
||||||
|
$result -= $this->credit_amt;
|
||||||
|
|
||||||
|
return $format ? Currency::display($result) : Currency::round($result);
|
||||||
|
}
|
||||||
|
|
||||||
/** LIST FUNCTIONS **/
|
/** LIST FUNCTIONS **/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -142,6 +142,8 @@ class Model_Invoice_Item extends ORM_OSB {
|
|||||||
|
|
||||||
case 6: return _('Service Excess Fee');
|
case 6: return _('Service Excess Fee');
|
||||||
|
|
||||||
|
case 125: return _('Payment Fee');
|
||||||
|
|
||||||
case 126: return _('Rounding');
|
case 126: return _('Rounding');
|
||||||
|
|
||||||
case 127: return _('Late Payment Fee');
|
case 127: return _('Late Payment Fee');
|
||||||
@ -164,6 +166,9 @@ class Model_Invoice_Item extends ORM_OSB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function save(Validation $validation = NULL) {
|
public function save(Validation $validation = NULL) {
|
||||||
|
if (! $this->changed())
|
||||||
|
return;
|
||||||
|
|
||||||
// Save the invoice item
|
// Save the invoice item
|
||||||
parent::save($validation);
|
parent::save($validation);
|
||||||
|
|
||||||
|
7
modules/invoice/views/invoice/user/view/pay.php
Normal file
7
modules/invoice/views/invoice/user/view/pay.php
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
echo Form::open('cart/add');
|
||||||
|
echo Form::hidden('module_id',$mid);
|
||||||
|
echo Form::hidden('module_item',$o->id);
|
||||||
|
?>
|
||||||
|
Add to cart for payment: <?php echo StaticList_YesNo::form('cart_add',true); ?>
|
||||||
|
<?php echo Form::submit('submit','Add to Cart'); echo Form::close('cart/add'); ?>
|
@ -156,7 +156,8 @@ class Model_Payment extends ORM_OSB {
|
|||||||
// Our items will be clobbered once we save the object, so we need to save it here.
|
// Our items will be clobbered once we save the object, so we need to save it here.
|
||||||
$items = $this->items();
|
$items = $this->items();
|
||||||
|
|
||||||
$this->source_id = Auth::instance()->get_user()->id;
|
// @todo This should not be mandatory - or there should be a source for non-users (automatic postings)
|
||||||
|
$this->source_id = Auth::instance()->get_user() ? Auth::instance()->get_user()->id : 1;
|
||||||
$this->ip = Request::$client_ip;
|
$this->ip = Request::$client_ip;
|
||||||
|
|
||||||
// Make sure we dont over allocate
|
// Make sure we dont over allocate
|
||||||
|
@ -11,6 +11,13 @@
|
|||||||
* @license http://dev.osbill.net/license.html
|
* @license http://dev.osbill.net/license.html
|
||||||
*/
|
*/
|
||||||
class Model_Payment_Item extends ORM_OSB {
|
class Model_Payment_Item extends ORM_OSB {
|
||||||
protected $_belongs_to = array('payment'=>array(),'invoice'=>array());
|
// Relationships
|
||||||
|
protected $_has_one = array(
|
||||||
|
'invoice'=>array('far_key'=>'invoice_id','foreign_key'=>'id'),
|
||||||
|
);
|
||||||
|
|
||||||
|
protected $_belongs_to = array(
|
||||||
|
'payment'=>array(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
Reference in New Issue
Block a user