OSB enhancements to date

This commit is contained in:
Deon George
2010-11-30 09:41:08 +11:00
parent 8715a2059b
commit ec6a542bc3
478 changed files with 23423 additions and 9309 deletions

View File

@@ -29,16 +29,6 @@
* @subpackage Module:Cart
*/
class cart extends OSB_module {
var $account_id;
var $session_id;
/**
* How many associated product levels to check for products to grant?
*
* @var int
*/
var $module='cart';
/**
* Admin View Cart Contents
*/
@@ -188,148 +178,49 @@ class cart extends OSB_module {
/**
* Get cart contents and return adodb rs
*/
public function get_contents() {
$db = &DB();
$sql = sprintf('SELECT DISTINCT c.* FROM %scart as c',AGILE_DB_PREFIX);
if (! empty($this->account_id)) {
$sql .= sprintf(' LEFT JOIN %ssession AS s ON (s.site_id=%s AND s.account_id=%s) WHERE (c.account_id=%s OR c.session_id=s.id) ',
AGILE_DB_PREFIX,DEFAULT_SITE,$this->account_id,$this->account_id);
} else {
$sql .= sprintf(' WHERE c.session_id=%s',$db->qstr(SESS));
$this->account_id = SESS_ACCOUNT;
}
$sql .= sprintf(' AND c.site_id=%s AND (c.cart_parent_id=0 OR c.cart_parent_id IS NULL) ORDER BY c.cart_type,c.date_orig',DEFAULT_SITE);
$result = $db->Execute($sql);
return $result;
}
/**
* Convert cart contents into invoice object & get smarty data
*/
public function put_contents_invoice(&$result,&$invoice) {
$db = &DB();
# get parent cart items
$i = 0;
$smart = array();
while (! $result->EOF) {
$id = $result->fields['id'];
$this->addInvoiceItem($id,$result,$invoice,$smart,$i);
switch ($result->fields['cart_type']) {
# AD HOC
case 3:
$smart[$i]['price'] = $invoice->invoice_item[$id]['total_amt'];
break;
# Domain
case 2:
$smart[$i]['price'] = $invoice->invoice_item[$id]['total_amt'];
$smart[$i]['tld_arr'] = $invoice->tld_arr[$id];
$smart[$i]['sku'] = sprintf('DOMAIN-%s',strtoupper($result->fields['host_type']));
break;
# Product
default:
@$smart[$i]['price'] = $invoice->price_arr[$id];
}
# Get the product attributes
$smart[$i]['attr'] = '';
if (! empty($invoice->invoice_item[$id]['product_attr_cart'])) {
@$attrib = explode("\r\n",$invoice->invoice_item[$id]['product_attr_cart']);
foreach($attrib as $attr) {
$attributei = explode('==',$attr);
if (! empty($attributei[0]) && !empty($attributei[1]))
$smart[$i]['attr'] .= sprintf('<span style="text-decoration: underline;">%s</span> : %s<br/>',$attributei[0],$attributei[1]);
}
}
# Get all children of this item
$ii = 0;
$resultassoc = $db->Execute(sqlSelect($db,'cart','*',sprintf('cart_parent_id=%s AND id !=%s',$result->fields['id'],$result->fields['id'])));
if ($resultassoc && $resultassoc->RecordCount()) {
while (!$resultassoc->EOF) {
$id = $resultassoc->fields['id'];
$this->addInvoiceItem($id,$resultassoc,$invoice,$smart,$i,$ii,true);
# Domain
if ($resultassoc->fields['cart_type'] == 2 ) {
$smart[$i]['assoc'][$ii]['price'] = $invoice->invoice_item[$id]['total_amt'];
$smart[$i]['assoc'][$ii]['tld_arr'] = $invoice->tld_arr[$id];
$smart[$i]['assoc'][$ii]['sku'] = sprintf('DOMAIN-%s',strtoupper($result->fields['host_type']));
}
$resultassoc->MoveNext();
}
}
$result->MoveNext();
$i++;
}
return $smart;
public function sGetContents() {
return $this->sql_GetRecords(array('where'=>array('session_id'=>SESS)));
}
/**
* View Cart Contents
*
* @uses invoice
*/
public function user_view($VAR) {
global $smarty;
# Get cart contents RS
$result = $this->get_contents();
if (! $result || $result->RecordCount() == 0) {
# Get cart contents
if (! count($results = $this->sGetContents())) {
$smarty->assign('result','0');
return false;
}
// init invoice object
include_once(PATH_MODULES.'invoice/invoice.inc.php');
$invoice = new invoice;
$invoice->initNew(0);
$invoice->taxable=false;
$invoice->discount=false;
$invoice->setRecordAttr('account_id',SESS_ACCOUNT);
$smart = $this->put_contents_invoice($result,$invoice);
$smarty->assign('results',count($invoice->invoice_item));
$smarty->assign('cart',$smart);
}
/**
* Run a cart item through the invoice class to retrieve totals, discounts, taxes, attributes, etc.
*
* @param int $id
* @param array $result
* @param object $invoice
* @param array $smart
* @param int $i
* @param int $assoc
*/
private function addInvoiceItem($id,&$result,&$invoice,&$smart,$i,$ii=false,$assoc=false) {
$invoice->addItem(
$id,
$result
);
if (! $assoc) {
@$smart[$i] = $result->fields;
@$smart[$i]['product'] = $invoice->product[$id];
@$smart[$i]['price_base'] = $invoice->invoice_item[$id]['price_base'];
@$smart[$i]['price_setup'] = $invoice->invoice_item[$id]['price_setup'];
} else {
@$smart[$i]['assoc'][$ii] = $result->fields;
@$smart[$i]['assoc'][$ii]['product'] = $invoice->product[$id];
@$smart[$i]['assoc'][$ii]['price_base'] = $invoice->invoice_item[$id]['price_base'];
@$smart[$i]['assoc'][$ii]['price_setup'] = $invoice->invoice_item[$id]['price_setup'];
foreach ($results as $result) {
$invoice->aaddItem(array(
'cart_id'=>$result['id'],
'domain_name'=>$result['domain_name'],
'domain_term'=>$result['domain_term'],
'domain_tld'=>$result['domain_tld'],
'domain_type'=>$result['domain_type'],
'item_type'=>0,
'product_id'=>$result['product_id'],
'quantity'=>$result['quantity'],
'recurr_schedule'=>$result['recurr_schedule'],
'product_attr'=>$result['product_attr'],
'product_attr_cart'=>$result['product_attr'],
'host_type'=>$result['host_type'],
'type'=>in_array($result['host_type'],array('register')) ? 'domain' : null
));
}
$smarty->assign('results',$invoice->sCountItems());
$smarty->assign('cart',$invoice->getItems());
}
/**
@@ -761,7 +652,6 @@ class cart extends OSB_module {
# Make sure this service is not in the cart
$sql = 'DELETE FROM ' . AGILE_DB_PREFIX . 'cart WHERE site_id='.$db->qstr(DEFAULT_SITE).' AND service_id='.$db->qstr($VAR['service_id']) ;
echo '<PRE>';print_r(array($sql=>$sql,'q'=>sqlDelete($db,'cart',array('service_id'=>$VAR['service_id']))));die();
$rs = $db->Execute($sql);
# Make sure this service has no outstanding invoices:

View File

@@ -17,7 +17,7 @@
<!-- SUB Modules to install with this one -->
<sub_modules></sub_modules>
<!-- MODULE Type (core|base), core modules cannot be deleted, unrecognised types are ignored. -->
<type>base</type>
<type></type>
</module_properties>
<!-- Tree Menu & Module Methods to load, they will be assigned the group permissions on install time, as selected by the user. -->

View File

@@ -0,0 +1,105 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides a order cart
*
* @package OSB
* @subpackage Cart
* @category Helpers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Cart {
public static function instance() {
return new Cart;
}
/**
* Return a list of items in the cart
*/
public function contents() {
return ORM::factory('cart')
->where('session_id','=',Session::instance()->id());
}
/**
* Print an HTML cart list
*
* @param bool $detail List a detailed cart or a summary cart
*/
public function cart_block() {
// If the cart is empty, we'll return here.
if (! $this->contents()->count_all())
return 'The cart is empty.';
Style::add(array(
'type'=>'file',
'data'=>'css/cart_blocklist.css',
));
$output = '<table class="cart_blocklist" border="0">';
foreach ($this->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/block_list')
->set('item',$item)
->set('price_setup',$item->quantity*$ppa[$item->recurr_schedule]['price_setup'])
->set('price_firstinvoice',$item->quantity*$ppa[$item->recurr_schedule]['price_base']*$pdata['prorata']);
}
$output .= '<tr class="submit">';
$output .= sprintf('<td colspan="3">%s&nbsp;%s</td>',
Form::button('checkout','Checkout',array('type' => 'submit')),
Form::button('empty','Empty',array('type' => 'submit')));
$output .= '</tr>';
$output .= '</table>';
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());
}
}
?>

View File

@@ -0,0 +1,116 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class provides a order cart
*
* @package OSB
* @subpackage Cart
* @category Controllers
* @author Deon George
* @copyright (c) 2010 Deon George
* @license http://dev.leenooks.net/license.html
*/
class Controller_Cart extends Controller_TemplateDefault {
/**
* Default action when called
*/
public function action_index() {
return $this->action_list();
}
/**
* List items in the cart
*/
public function action_list() {
// @todo - this should be a global config item
$mediapath = Route::get('default/media');
$block = new block;
// 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/cart_contents.css',
));
$output = Form::open('checkout/noready');
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')
->set('price_recurring',Currency::display($item->quantity*$ppa[$item->recurr_schedule]['price_base']))
->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')
->set('price_box',$price_box)
->set('service_start',$pdata['date'])
->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
if ($item->product->prod_plugin AND method_exists($item->product->prod_plugin_file,'product_cart')) {
$output .= View::factory(sprintf('%s/cart_info',strtolower($item->product->prod_plugin_file)));
// @todo JS validation will need to verify data before submission
}
}
$output .= '<div>'.Form::submit('submit',_('Checkout')).'</div>';
$output .= Form::close();
$block->add(array(
'title'=>_('Your Items'),
'body'=>$output,
));
}
$this->template->content = $block;
// Suppress our right hand tab
$this->template->right = ' ';
}
/**
* Add an item to the cart
*/
public function action_add() {
$cart = ORM::factory('cart');
$cart->session_id = Session::instance()->id();
if (Auth::instance()->logged_in())
$cart->account_id = Auth::instance()->get_user()->id;
if ($cart->values($_POST)->check())
$cart->save();
else
echo Kohana::debug($cart->validate()->errors());
if ($cart->saved())
Request::instance()->redirect('cart/index');
else
throw new Kohana_Exception(_('There was a problem adding the item to the cart.'));
}
public function action_empty() {
$cart = ORM::factory('cart')
->where('session_id','=',session_id());
$cart->delete_all();
$this->template->content = _('Cart Emptied');
}
}
?>

View File

@@ -0,0 +1,25 @@
<?php defined('SYSPATH') or die('No direct access allowed.');
/**
* This class supports a product cart
*
* @package OSB
* @subpackage Cart
* @category Models
* @author Deon George
* @copyright (c) 2010 Open Source Billing
* @license http://dev.osbill.net/license.html
*/
class Model_Cart extends ORMOSB {
protected $_belongs_to = array(
'product'=>array(),
);
protected $_formats = array(
'recurr_schedule'=>array('StaticList_RecurSchedule::display'=>array()),
);
// Cart doesnt use the update column
protected $_updated_column = FALSE;
}
?>

View File

@@ -0,0 +1,32 @@
/** 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;
}

View File

@@ -0,0 +1,46 @@
/** 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;
}

View File

@@ -0,0 +1,34 @@
/** 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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1020 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,5 @@
<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>

View File

@@ -0,0 +1,11 @@
<!-- @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>&nbsp;</td>
<td>Current Service Period:</td>
<td><b><?php printf('%s -> %s',$service_start,$service_end);?></b></td>
<td>&nbsp;</td>
</tr>

View File

@@ -0,0 +1,25 @@
<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>&nbsp;</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>&nbsp;</td>
<td>Cart Total:</td>
<td><?php echo Currency::display($cart->total()); ?></td>
</tr>
</table>

View File

@@ -0,0 +1,17 @@
<!-- @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>&nbsp;</td><td>Pricing Structure:</td><td colspan="2"><b><?php echo $item->product->display('price_type'); ?></b></td>
</tr>
<tr>
<td>&nbsp;</td><td>Invoice Frequency:</td><td colspan="2"><b><?php echo $item->display('recurr_schedule'); ?> (<?php echo $price_recurring; ?>)</b></td>
</tr>
<tr>
<td>&nbsp;</td><td>Current Service Period:</td><td><b><?php printf('%s -> %s',$service_start,$service_end); ?></b></td>
</tr>
</table>

View File

@@ -0,0 +1,27 @@
<!-- @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>&nbsp;</td>
</tr>
<tr>
<td colspan="2">&nbsp;</td></tr>
<tr>
<td class="head">First Invoice</td>
<td class="value"><?php echo $price_firstinvoice; ?></td>
<td>&nbsp;</td>
</tr>
<?php if ($price_setup) { ?>
<tr>
<td class="head">Setup</td>
<td class="value"><?php echo $price_setup; ?></td>
<td>&nbsp;</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>