Page MenuHomeIn-Portal Phabricator

in-commerce
No OneTemporary

File Metadata

Created
Mon, Feb 24, 9:48 PM

in-commerce

Index: branches/5.2.x/units/product_option_combinations/product_option_combinations_event_handler.php
===================================================================
--- branches/5.2.x/units/product_option_combinations/product_option_combinations_event_handler.php (revision 15385)
+++ branches/5.2.x/units/product_option_combinations/product_option_combinations_event_handler.php (revision 15386)
@@ -1,443 +1,443 @@
<?php
/**
* @version $Id$
* @package In-Commerce
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license Commercial License
* This software is protected by copyright law and international treaties.
* Unauthorized reproduction or unlicensed usage of the code of this program,
* or any portion of it may result in severe civil and criminal penalties,
* and will be prosecuted to the maximum extent possible under the law
* See http://www.in-portal.org/commercial-license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class ProductOptionCombinationsEventHandler extends kDBEventHandler {
/**
* Apply custom processing to item
*
* @param kEvent $event
* @param string $type
* @return void
* @access protected
*/
protected function customProcessing(kEvent $event, $type)
{
if ( $type == 'after' ) {
return;
}
switch ($event->Name) {
case 'OnCreate':
case 'OnUpdate':
$object = $event->getObject();
/* @var $object kDBItem */
$options = unserialize($object->GetDBField('Combination'));
ksort($options);
$object->SetDBField('CombinationCRC', kUtil::crc32(serialize($options)));
break;
case 'OnMassDelete':
// delete only option combinations that has no associated inventory
$object = $event->getObject();
/* @var $object kDBItem */
$ids = $event->getEventParam('ids');
$sql = 'SELECT ' . $object->IDField . '
FROM ' . $object->TableName . '
WHERE (' . $object->IDField . ' IN (' . implode(',', $ids) . ')) AND
(QtyInStock = 0) AND (QtyReserved = 0) AND (QtyBackOrdered = 0) AND (QtyOnOrder = 0)';
$event->setEventParam('ids', $this->Conn->GetCol($sql));
break;
}
}
/**
* GetOptionValues
*
* @param kEvent $event
*/
function GetOptionValues($event, $option_id)
{
$object = $event->getObject();
if ($object->IsTempTable()) {
$table = $this->Application->GetTempName(TABLE_PREFIX.'ProductOptions', 'prefix:'.$event->Prefix);
}
else {
$table = TABLE_PREFIX.'ProductOptions';
}
$query = 'SELECT `Values` FROM '.$table.' WHERE ProductOptionId = '.$option_id;
return explode(',', $this->Conn->GetOne($query));
}
function CreateCombinations($event, $fields, $current_option=null)
{
$recursed = false;
$combination = $fields['Combination'];
foreach ($combination as $option_id => $option)
{
if ($option_id == $current_option || $recursed) continue;
if ($option == '_ANY_') {
$recursed = true;
$values = $this->GetOptionValues($event, $option_id);
foreach ($values as $a_value) {
$fields['Combination'][$option_id] = $a_value;
$this->CreateCombinations($event, $fields, $option_id);
}
}
}
if (!$recursed) {
$object = $event->getObject();
/* @var $object kDBItem */
$salt = $fields['Combination'];
ksort($salt);
$object->Load(kUtil::crc32(serialize($salt)), 'CombinationCRC');
$object->SetFieldsFromHash($fields);
$this->customProcessing($event,'before');
if ( $object->isLoaded() ) { // Update if such combination already exists
if( $object->Update() )
{
$this->customProcessing($event,'after');
$event->status=kEvent::erSUCCESS;
}
}
else {
if( $object->Create($event->getEventParam('ForceCreateId')) )
{
$this->customProcessing($event,'after');
$event->status=kEvent::erSUCCESS;
}
}
}
}
function UpdateCombinations($event, $fields, $current_option=null)
{
$recursed = false;
$combination = $fields['Combination'];
foreach ($combination as $option_id => $option)
{
if ($option_id == $current_option || $recursed) continue;
if ($option == '_ANY_') {
$recursed = true;
$values = $this->GetOptionValues($event, $option_id);
foreach ($values as $a_value) {
$fields['Combination'][$option_id] = $a_value;
$this->UpdateCombinations($event, $fields, $option_id);
}
}
}
if (!$recursed) {
$object = $event->getObject();
/* @var $object kDBItem */
$edit_id = $object->GetId();
$salt = $fields['Combination'];
ksort($salt);
// try to load combination by salt - if loaded, it will update the combination
$object->Load(kUtil::crc32(serialize($salt)), 'CombinationCRC');
if ( !$object->isLoaded() ) {
$object->Load($edit_id);
}
$object->SetFieldsFromHash($fields);
$this->customProcessing($event,'before');
if( $object->Update() )
{
$this->customProcessing($event,'after');
$event->status=kEvent::erSUCCESS;
}
}
}
/**
* Creates new kDBItem
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnCreate(kEvent $event)
{
$object = $event->getObject(Array ('skip_autoload' => true));
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ( !$items_info ) {
return;
}
list($id, $field_values) = each($items_info);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
if ( !$object->Validate() ) {
$event->status = kEvent::erFAIL;
$event->redirect = false;
$this->Application->SetVar($event->getPrefixSpecial() . '_SaveEvent', 'OnCreate');
$object->setID($id);
return;
}
$this->CreateCombinations($event, $field_values);
}
/**
* Updates kDBItem
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnUpdate(kEvent $event)
{
$object = $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
foreach($items_info as $id => $field_values)
{
$object->Load($id);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
if (!$object->Validate()) {
$event->status = kEvent::erFAIL;
$event->redirect = false;
return;
}
$this->UpdateCombinations($event, $field_values);
/*$this->customProcessing($event, 'before');
if( $object->Update($id) )
{
$this->customProcessing($event, 'after');
$event->status=kEvent::erSUCCESS;
}
else
{
$event->status=kEvent::erFAIL;
$event->redirect=false;
break;
}*/
}
}
$this->Application->SetVar($event->GetPrefixSpecial().'_id', '');
}
/**
* Builds item (loads if needed)
*
* Pattern: Prototype Manager
*
* @param kEvent $event
* @access protected
*/
protected function OnItemBuild(kEvent $event)
{
$object = $event->getObject();
/* @var $object kDBItem */
$this->dbBuild($object, $event);
$sql = $this->ItemPrepareQuery($event);
$sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
// 2. loads if allowed
$auto_load = $this->Application->getUnitOption($event->Prefix, 'AutoLoad');
$skip_autoload = $event->getEventParam('skip_autoload');
if ( $auto_load && !$skip_autoload ) {
$this->LoadItem($event);
}
$actions = $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_GoTab', '');
$actions->Set($event->getPrefixSpecial() . '_GoId', '');
}
/**
* Load item if id is available
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function LoadItem(kEvent $event)
{
$object = $event->getObject();
/* @var $object kDBItem */
$id = $this->getPassedID($event);
if ( !$id ) {
$event->CallSubEvent('OnNew');
return;
}
if ( $object->Load($id) ) {
$actions = $this->Application->recallObject('kActions');
/* @var $actions Params */
$actions->Set($event->getPrefixSpecial() . '_id', $object->GetId());
}
}
/**
* Returns special of main item for linking with sub-item
*
* @param kEvent $event
* @return string
* @access protected
*/
protected function getMainSpecial(kEvent $event)
{
$special = $event->getEventParam('main_special');
if ( $special === false || $special == '$main_special' ) {
$special = $event->Special;
}
if ( $special == 'grid' ) {
$special = '';
}
return $special;
}
/**
* Occurs before an item has been cloned
* Id of newly created item is passed as event' 'id' param
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeClone(kEvent $event)
{
parent::OnBeforeClone($event);
$event->Init($event->Prefix, '-item');
$object = $event->getObject();
/* @var $object kDBItem */
$options_mapping = $this->Application->GetVar('poc_mapping');
if ( !$options_mapping ) {
return;
}
foreach ($options_mapping as $original => $new) {
$n_combs = array ();
$comb_data = unserialize($object->GetDBField('Combination'));
foreach ($comb_data as $key => $val) {
$n_key = $key == $original ? $new : $key;
$n_combs[$n_key] = $val;
}
ksort($n_combs);
$n_combs = serialize($n_combs);
$n_crc = kUtil::crc32($n_combs);
$object->SetDBField('Combination', $n_combs);
$object->SetDBField('CombinationCRC', $n_crc);
}
}
/**
* Restore back values from live table to temp table before overwriting live with temp
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeDeleteFromLive(kEvent $event)
{
parent::OnBeforeDeleteFromLive($event);
// check if product inventory management is via options and then proceed
$id = $event->getEventParam('id');
$products_table = $this->Application->getUnitOption('p', 'TableName');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$sql = 'SELECT p.InventoryStatus
FROM ' . $products_table . ' p
LEFT JOIN ' . $table_name . ' poc ON poc.ProductId = p.ProductId
WHERE poc.' . $id_field . ' = ' . $id;
$inventory_status = $this->Conn->GetOne($sql);
if ( $inventory_status == ProductInventory::BY_OPTIONS ) {
$live_object = $this->Application->recallObject($event->Prefix . '.itemlive', null, Array ('skip_autoload' => true));
/* @var $live_object kDBItem */
$live_object->SwitchToLive();
$live_object->Load($id);
$temp_object = $this->Application->recallObject($event->Prefix . '.itemtemp', null, Array ('skip_autoload' => true));
/* @var $temp_object kDBItem */
$temp_object->SwitchToTemp();
$temp_object->Load($id);
- $temp_object->SetDBFieldsFromHash($live_object->GetFieldValues(), Array ('QtyInStock', 'QtyReserved', 'QtyBackOrdered', 'QtyOnOrder'));
+ $temp_object->SetDBFieldsFromHash($live_object->GetFieldValues(), null, Array ('QtyInStock', 'QtyReserved', 'QtyBackOrdered', 'QtyOnOrder'));
$temp_object->Update();
}
}
/**
* Create search filters based on search query
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSearch(kEvent $event)
{
parent::OnSearch($event);
$this->_saveProduct($event);
}
/**
* Clear search keywords
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSearchReset(kEvent $event)
{
parent::OnSearchReset($event);
$this->_saveProduct($event);
}
/**
* Makes event remember product id (if passed)
*
* @param kEvent $event
*/
function _saveProduct($event)
{
$product_id = $this->Application->GetVar('p_id');
if ($product_id) {
$event->SetRedirectParam('p_id', $product_id);
}
}
}
\ No newline at end of file
Index: branches/5.2.x/units/products/products_event_handler.php
===================================================================
--- branches/5.2.x/units/products/products_event_handler.php (revision 15385)
+++ branches/5.2.x/units/products/products_event_handler.php (revision 15386)
@@ -1,1593 +1,1593 @@
<?php
/**
* @version $Id$
* @package In-Commerce
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license Commercial License
* This software is protected by copyright law and international treaties.
* Unauthorized reproduction or unlicensed usage of the code of this program,
* or any portion of it may result in severe civil and criminal penalties,
* and will be prosecuted to the maximum extent possible under the law
* See http://www.in-portal.org/commercial-license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class ProductsEventHandler extends kCatDBEventHandler {
/**
* Allows to override standard permission mapping
*
* @return void
* @access protected
* @see kEventHandler::$permMapping
*/
protected function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
// front
'OnCancelAction' => Array('self' => true),
'OnRateProduct' => Array('self' => true),
'OnClearRecent' => Array('self' => true),
'OnRecommendProduct' => Array('self' => true),
'OnAddToCompare' => Array('self' => true),
'OnRemoveFromCompare' => Array('self' => true),
'OnCancelCompare' => Array('self' => true),
// admin
'OnQtyAdd' => Array('self' => 'add|edit'),
'OnQtyRemove' => Array('self' => 'add|edit'),
'OnQtyOrder' => Array('self' => 'add|edit'),
'OnQtyReceiveOrder' => Array('self' => 'add|edit'),
'OnQtyCancelOrder' => Array('self' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Define alternative event processing method names
*
* @return void
* @see kEventHandler::$eventMethods
* @access protected
*/
protected function mapEvents()
{
parent::mapEvents(); // ensure auto-adding of approve/decine and so on events
$product_events = Array (
'OnQtyAdd'=>'InventoryAction',
'OnQtyRemove'=>'InventoryAction',
'OnQtyOrder'=>'InventoryAction',
'OnQtyReceiveOrder'=>'InventoryAction',
'OnQtyCancelOrder'=>'InventoryAction',
);
$this->eventMethods = array_merge($this->eventMethods, $product_events);
}
/**
* Sets default processing data for subscriptions
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemCreate(kEvent $event)
{
parent::OnBeforeItemCreate($event);
$object = $event->getObject();
/* @var $object kDBItem */
$product_approve_events = Array (
2 => 'p:OnSubscriptionApprove',
4 => 'p:OnDownloadableApprove',
5 => 'p:OnPackageApprove'
);
$product_type = $object->GetDBField('Type');
$type_found = in_array($product_type, array_keys($product_approve_events));
if ( $type_found && !$object->GetDBField('ProcessingData') ) {
$processing_data = Array ('ApproveEvent' => $product_approve_events[$product_type]);
$object->SetDBField('ProcessingData', serialize($processing_data));
}
}
/**
* Process product count manipulations
*
* @param kEvent $event
* @access private
*/
function InventoryAction($event)
{
$object = $event->getObject();
/* @var $object kDBItem */
$field_values = $this->getSubmittedFields($event);
$object->SetFieldsFromHash($field_values, $this->getRequestProtectedFields($field_values));
if ($object->GetDBField('InventoryStatus') == 2) {
// inventory by options (use first selected combination in grid)
$combination_id = array_shift( array_keys( $this->Application->GetVar('poc_grid') ) );
}
else {
// inventory by product
$combination_id = 0;
}
// save id of selected option combination & preselect it in grid
$this->Application->SetVar('combination_id', $combination_id);
$this->ScheduleInventoryAction($event->Name, $object->GetId(), $object->GetDBField('Qty'), $combination_id);
$object->Validate();
if ( !$object->GetErrorPseudo('Qty') ){
// only update, when no error on that field
$this->modifyInventory($event->Name, $object, $object->GetDBField('Qty'), $combination_id);
}
$object->SetDBField('Qty', null);
$event->redirect = false;
}
/**
* Perform inventory action on supplied object
*
* @param string $action event name which is actually called by user
* @param ProductsItem $product
* @param int $qty
* @param int $combination_id
*/
function modifyInventory($action, &$product, $qty, $combination_id)
{
if ($product->GetDBField('InventoryStatus') == 2) {
// save inventory changes to option combination instead of product
$object = $this->Application->recallObject('poc.-item', null, Array('skip_autoload' => true));
$object->Load($combination_id);
}
elseif ($combination_id > 0) {
// combination id present, but not inventory by combinations => skip
return false;
}
elseif ($product->GetDBField('InventoryStatus') == 1) {
// save inventory changes to product
$object =& $product;
}
else {
// product has inventory actions, but don't use inventory => skip
return false;
}
if (!$object->isLoaded()) {
// product/combination in action doesn't exist in database by now
return false;
}
switch ($action) {
case 'OnQtyAdd':
$object->SetDBField('QtyInStock', $object->GetDBField('QtyInStock') + $qty);
break;
case 'OnQtyRemove':
if ($object->GetDBField('QtyInStock') < $qty) {
$qty = $object->GetDBField('QtyInStock');
}
$object->SetDBField('QtyInStock', $object->GetDBField('QtyInStock') - $qty);
break;
case 'OnQtyOrder':
$object->SetDBField('QtyOnOrder', $object->GetDBField('QtyOnOrder') + $qty);
break;
case 'OnQtyReceiveOrder':
$object->SetDBField('QtyOnOrder', $object->GetDBField('QtyOnOrder') - $qty);
$object->SetDBField('QtyInStock', $object->GetDBField('QtyInStock') + $qty);
break;
case 'OnQtyCancelOrder':
$object->SetDBField('QtyOnOrder', $object->GetDBField('QtyOnOrder') - $qty);
break;
}
return $object->Update();
}
function ScheduleInventoryAction($action, $prod_id, $qty, $combination_id = 0)
{
$inv_actions = $this->Application->RecallVar('inventory_actions');
if (!$inv_actions) {
$inv_actions = Array();
}
else {
$inv_actions = unserialize($inv_actions);
}
array_push($inv_actions, Array('action' => $action, 'product_id' => $prod_id, 'combination_id' => $combination_id, 'qty' => $qty));
$this->Application->StoreVar('inventory_actions', serialize($inv_actions));
}
function RealInventoryAction($action, $prod_id, $qty, $combination_id)
{
$product = $this->Application->recallObject('p.liveitem', null, Array('skip_autoload' => true));
$product->SwitchToLive();
$product->Load($prod_id);
$this->modifyInventory($action, $product, $qty, $combination_id);
}
function RunScheduledInventoryActions($event)
{
$inv_actions = $this->Application->GetVar('inventory_actions');
if (!$inv_actions) {
return;
}
$inv_actions = unserialize($inv_actions);
$products = array();
foreach($inv_actions as $an_action) {
$this->RealInventoryAction($an_action['action'], $an_action['product_id'], $an_action['qty'], $an_action['combination_id']);
array_push($products, $an_action['product_id'].'_'.$an_action['combination_id']);
}
$products = array_unique($products);
if ($products) {
$product_obj = $this->Application->recallObject('p.liveitem', null, Array('skip_autoload' => true));
$product_obj->SwitchToLive();
foreach ($products as $product_key) {
list($prod_id, $combination_id) = explode('_', $product_key);
$product_obj->Load($prod_id);
$this->FullfillBackOrders($product_obj, $combination_id);
}
}
}
/**
* In case if products arrived into inventory and they are required by old (non processed) orders, then use them (products) in that orders
*
* @param ProductsItem $product
* @param int $combination_id
*/
function FullfillBackOrders(&$product, $combination_id)
{
if ( !$this->Application->ConfigValue('Comm_Process_Backorders_Auto') ) return;
if ($combination_id && ($product->GetDBField('InventoryStatus') == 2)) {
// if combination id present and inventory by combinations
$poc_idfield = $this->Application->getUnitOption('poc', 'IDField');
$poc_tablename = $this->Application->getUnitOption('poc', 'TableName');
$sql = 'SELECT QtyInStock
FROM '.$poc_tablename.'
WHERE '.$poc_idfield.' = '.$combination_id;
$stock_qty = $this->Conn->GetOne($sql);
}
else {
// inventory by product
$stock_qty = $product->GetDBField('QtyInStock');
}
$qty = (int) $stock_qty - $product->GetDBField('QtyInStockMin');
$prod_id = $product->GetID();
if ($prod_id <= 0 || !$prod_id || $qty <= 0) return;
//selecting up to $qty backorders with $prod_id where full qty is not reserved
$query = 'SELECT '.TABLE_PREFIX.'Orders.OrderId
FROM '.TABLE_PREFIX.'OrderItems
LEFT JOIN '.TABLE_PREFIX.'Orders ON '.TABLE_PREFIX.'Orders.OrderId = '.TABLE_PREFIX.'OrderItems.OrderId
WHERE (ProductId = '.$prod_id.') AND (Quantity > QuantityReserved) AND (Status = '.ORDER_STATUS_BACKORDERS.')
GROUP BY '.TABLE_PREFIX.'Orders.OrderId
ORDER BY OrderDate ASC
LIMIT 0,'.$qty; //assuming 1 item per order - minimum possible
$orders = $this->Conn->GetCol($query);
if (!$orders) return;
$order = $this->Application->recallObject('ord.-inv', null, Array('skip_autoload' => true));
foreach ($orders as $ord_id) {
$order->Load($ord_id);
$this->Application->EmailEventAdmin('BACKORDER.FULLFILL');
//reserve what's possible in any case
$event = new kEvent('ord:OnReserveItems');
$this->Application->HandleEvent($event);
if ( $event->status == kEvent::erSUCCESS ) { //
//in case the order is ready to process - process it
$this->Application->HandleEvent($event, 'ord:OnOrderProcess');
}
}
}
/**
* Occurs before an item is deleted from live table when copying from temp
* (temp handler deleted all items from live and then copy over all items from temp)
* Id of item being deleted is passed as event' 'id' param
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeDeleteFromLive(kEvent $event)
{
parent::OnBeforeDeleteFromLive($event);
$product = $this->Application->recallObject($event->Prefix . '.itemlive', null, Array ('skip_autoload' => true));
/* @var $product kCatDBItem */
$product->SwitchToLive();
$id = $event->getEventParam('id');
if ( !$product->Load($id) ) {
// this will make sure New product will not be overwritten with empty data
return ;
}
$temp = $this->Application->recallObject($event->Prefix . '.itemtemp', null, Array ('skip_autoload' => true));
/* @var $temp kCatDBItem */
$temp->SwitchToTemp();
$temp->Load($id);
- $temp->SetDBFieldsFromHash($product->GetFieldValues(), Array ('QtyInStock', 'QtyReserved', 'QtyBackOrdered', 'QtyOnOrder'));
+ $temp->SetDBFieldsFromHash($product->GetFieldValues(), null, Array ('QtyInStock', 'QtyReserved', 'QtyBackOrdered', 'QtyOnOrder'));
$temp->Update();
}
/**
* Removes any information about current/selected ids
* from Application variables and Session
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function clearSelectedIDs(kEvent $event)
{
parent::clearSelectedIDs($event);
$this->Application->SetVar('inventory_actions', $this->Application->RecallVar('inventory_actions'));
$this->Application->RemoveVar('inventory_actions');
}
/**
* Saves content of temp table into live and
* redirects to event' default redirect (normally grid template)
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnSave(kEvent $event)
{
parent::OnSave($event);
if ( $event->status == kEvent::erSUCCESS ) {
$this->RunScheduledInventoryActions($event);
}
}
/**
* Prepare temp tables for creating new item
* but does not create it. Actual create is
* done in OnPreSaveCreated
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnPreCreate(kEvent $event)
{
parent::onPreCreate($event);
$object = $event->getObject();
/* @var $object kDBItem */
$object->SetDBField('Type', $this->Application->GetVar($event->getPrefixSpecial(true) . '_new_type'));
}
/**
* Saves edited item in temp table and loads
* item with passed id in current template
* Used in Prev/Next buttons
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnPreSaveAndGo(kEvent $event)
{
$event->CallSubEvent('OnPreSave');
$this->LoadItem($event);
$object = $event->getObject();
/* @var $object kDBItem */
$from_type = $object->GetDBField('Type');
if ( $event->status == kEvent::erSUCCESS ) {
$this->Application->SetVar($event->getPrefixSpecial() . '_id', $this->Application->GetVar($event->getPrefixSpecial(true) . '_GoId'));
$this->LoadItem($event);
$to_type = $object->GetDBField('Type');
if ( $from_type != $to_type ) {
$from_tabs = $this->GetTabs($from_type);
$from_tab_i = array_search($this->Application->GetVar('t'), $from_tabs);
$to_tabs = $this->GetTabs($to_type);
$to_tab = $this->Application->GetVar('t');
$found = false;
while (!isset($to_tabs[$from_tab_i]) && $from_tab_i < count($to_tabs)) {
$from_tab_i++;
}
if ( !isset($to_tabs[$from_tab_i]) ) {
$from_tab_i = 0;
}
$to_tab = $to_tabs[$from_tab_i];
$event->redirect = $to_tab;
}
}
}
function GetTabs($type)
{
switch($type)
{
case 1:
return Array(
0 => 'in-commerce/products/products_edit',
1 => 'in-commerce/products/products_inventory',
2 => 'in-commerce/products/products_pricing',
3 => 'in-commerce/products/products_categories',
4 => 'in-commerce/products/products_images',
5 => 'in-commerce/products/products_reviews',
6 => 'in-commerce/products/products_custom',
);
case 2:
return Array(
0 => 'in-commerce/products/products_edit',
1 => 'in-commerce/products/products_access',
/*2 => 'in-commerce/products/products_access_pricing',*/
3 => 'in-commerce/products/products_categories',
4 => 'in-commerce/products/products_images',
5 => 'in-commerce/products/products_reviews',
6 => 'in-commerce/products/products_custom',
);
case 3:
return Array(
0 => 'in-commerce/products/products_edit',
2 => 'in-commerce/products/products_access_pricing',
3 => 'in-commerce/products/products_categories',
4 => 'in-commerce/products/products_images',
5 => 'in-commerce/products/products_reviews',
6 => 'in-commerce/products/products_custom',
);
case 4:
return Array(
0 => 'in-commerce/products/products_edit',
2 => 'in-commerce/products/products_files',
3 => 'in-commerce/products/products_categories',
4 => 'in-commerce/products/products_images',
5 => 'in-commerce/products/products_reviews',
6 => 'in-commerce/products/products_custom',
);
}
}
/**
* Return type clauses for list bulding on front
*
* @param kEvent $event
* @return Array
*/
function getTypeClauses($event)
{
$types = $event->getEventParam('types');
$types = $types ? explode(',', $types) : Array ();
$except_types = $event->getEventParam('except');
$except_types = $except_types ? explode(',', $except_types) : Array ();
$object = $event->getObject();
/* @var $object kDBList */
$type_clauses = parent::getTypeClauses($event);
$type_clauses['featured']['include'] = '%1$s.Featured = 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
$type_clauses['featured']['except'] = '%1$s.Featured != 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
$type_clauses['featured']['having_filter'] = false;
$type_clauses['onsale']['include'] = '%1$s.OnSale = 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
$type_clauses['onsale']['except'] = '%1$s.OnSale != 1 AND ' . TABLE_PREFIX . 'CategoryItems.PrimaryCat = 1';
$type_clauses['onsale']['having_filter'] = false;
// products from selected manufacturer: begin
$manufacturer = $event->getEventParam('manufacturer');
if ( !$manufacturer ) {
$manufacturer = $this->Application->GetVar('manuf_id');
}
if ( $manufacturer ) {
$type_clauses['manufacturer']['include'] = '%1$s.ManufacturerId = ' . $manufacturer . ' AND PrimaryCat = 1';
$type_clauses['manufacturer']['except'] = '%1$s.ManufacturerId != ' . $manufacturer . ' AND PrimaryCat = 1';
$type_clauses['manufacturer']['having_filter'] = false;
}
// products from selected manufacturer: end
// recent products: begin
$recent = $this->Application->RecallVar('recent_products');
if ( $recent ) {
$recent = unserialize($recent);
$type_clauses['recent']['include'] = '%1$s.ProductId IN (' . implode(',', $recent) . ') AND PrimaryCat = 1';
$type_clauses['recent']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $recent) . ') AND PrimaryCat = 1';
}
else {
$type_clauses['recent']['include'] = '0';
$type_clauses['recent']['except'] = '1';
}
$type_clauses['recent']['having_filter'] = false;
// recent products: end
// compare products: begin
if ( in_array('compare', $types) || in_array('compare', $except_types) ) {
$compare_products = $this->getCompareProducts();
if ( $compare_products ) {
$compare_products = $this->Conn->qstrArray($compare_products);
$type_clauses['compare']['include'] = '%1$s.ProductId IN (' . implode(',', $compare_products) . ') AND PrimaryCat = 1';
$type_clauses['compare']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $compare_products) . ') AND PrimaryCat = 1';
}
else {
$type_clauses['compare']['include'] = '0';
$type_clauses['compare']['except'] = '1';
}
$type_clauses['compare']['having_filter'] = false;
if ( $event->getEventParam('per_page') === false ) {
$event->setEventParam('per_page', $this->Application->ConfigValue('MaxCompareProducts'));
}
}
// compare products: end
// products already in shopping cart: begin
if ( in_array('in_cart', $types) || in_array('in_cart', $except_types) ) {
$order_id = $this->Application->RecallVar('ord_id');
if ( $order_id ) {
$sql = 'SELECT ProductId
FROM ' . TABLE_PREFIX . 'OrderItems
WHERE OrderId = ' . $order_id;
$in_cart = $this->Conn->GetCol($sql);
if ( $in_cart ) {
$type_clauses['in_cart']['include'] = '%1$s.ProductId IN (' . implode(',', $in_cart) . ') AND PrimaryCat = 1';
$type_clauses['in_cart']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $in_cart) . ') AND PrimaryCat = 1';
}
else {
$type_clauses['in_cart']['include'] = '0';
$type_clauses['in_cart']['except'] = '1';
}
}
else {
$type_clauses['in_cart']['include'] = '0';
$type_clauses['in_cart']['except'] = '1';
}
$type_clauses['in_cart']['having_filter'] = false;
}
// products already in shopping cart: end
// my downloadable products: begin
if ( in_array('my_downloads', $types) || in_array('my_downloads', $except_types) ) {
$user_id = $this->Application->RecallVar('user_id');
$sql = 'SELECT ProductId
FROM ' . TABLE_PREFIX . 'UserFileAccess
WHERE PortalUserId = ' . $user_id;
$my_downloads = $user_id > 0 ? $this->Conn->GetCol($sql) : false;
if ( $my_downloads ) {
$type_clauses['my_downloads']['include'] = '%1$s.ProductId IN (' . implode(',', $my_downloads) . ') AND PrimaryCat = 1';
$type_clauses['my_downloads']['except'] = '%1$s.ProductId NOT IN (' . implode(',', $my_downloads) . ') AND PrimaryCat = 1';
}
else {
$type_clauses['my_downloads']['include'] = '0';
$type_clauses['my_downloads']['except'] = '1';
}
$type_clauses['my_downloads']['having_filter'] = false;
}
// my downloadable products: end
// my favorite products: begin
if ( in_array('wish_list', $types) || in_array('wish_list', $except_types) ) {
$sql = 'SELECT ResourceId
FROM ' . $this->Application->getUnitOption('fav', 'TableName') . '
WHERE PortalUserId = ' . (int)$this->Application->RecallVar('user_id');
$wishlist_ids = $this->Conn->GetCol($sql);
if ( $wishlist_ids ) {
$type_clauses['wish_list']['include'] = '%1$s.ResourceId IN (' . implode(',', $wishlist_ids) . ') AND PrimaryCat = 1';
$type_clauses['wish_list']['except'] = '%1$s.ResourceId NOT IN (' . implode(',', $wishlist_ids) . ') AND PrimaryCat = 1';
}
else {
$type_clauses['wish_list']['include'] = '0';
$type_clauses['wish_list']['except'] = '1';
}
$type_clauses['wish_list']['having_filter'] = false;
}
// my favorite products: end
// products from package: begin
if ( in_array('content', $types) || in_array('content', $except_types) ) {
$object->removeFilter('category_filter');
$object->AddGroupByField('%1$s.ProductId');
$object_product = $this->Application->recallObject($event->Prefix);
/* @var $object_product ProductsItem */
$content_ids_array = $object_product->GetPackageContentIds();
if ( sizeof($content_ids_array) == 0 ) {
$content_ids_array = array ('-1');
}
if ( sizeof($content_ids_array) > 0 ) {
$type_clauses['content']['include'] = '%1$s.ProductId IN (' . implode(',', $content_ids_array) . ')';
}
else {
$type_clauses['content']['include'] = '0';
}
$type_clauses['related']['having_filter'] = false;
}
// products from package: end
$object->addFilter('not_virtual', '%1$s.Virtual = 0');
if ( !$this->Application->isAdminUser ) {
$object->addFilter('expire_filter', '%1$s.Expire IS NULL OR %1$s.Expire > ' . adodb_mktime());
}
return $type_clauses;
}
function OnClearRecent($event)
{
$this->Application->RemoveVar('recent_products');
}
/**
* Occurs, when user rates a product
*
* @param kEvent $event
*/
function OnRateProduct($event)
{
$event->SetRedirectParam('pass', 'all,p');
$event->redirect = $this->Application->GetVar('success_template');
$object = $event->getObject();
/* @var $object kDBItem */
$user_id = $this->Application->RecallVar('user_id');
$sql = ' SELECT * FROM ' . TABLE_PREFIX . 'SpamControl
WHERE ItemResourceId=' . $object->GetDBField('ResourceId') . '
AND IPaddress="' . $_SERVER['REMOTE_ADDR'] . '"
AND PortalUserId=' . $user_id . '
AND DataType="Rating"';
$res = $this->Conn->GetRow($sql);
if ( $res && $res['Expire'] < adodb_mktime() ) {
$sql = ' DELETE FROM ' . TABLE_PREFIX . 'SpamControl
WHERE ItemResourceId=' . $object->GetDBField('ResourceId') . '
AND IPaddress="' . $_SERVER['REMOTE_ADDR'] . '"
AND PortalUserId=' . $user_id . '
AND DataType="Rating"';
$this->Conn->Query($sql);
unset($res);
}
$new_rating = $this->Application->GetVar('rating');
if ( $new_rating !== false && !$res ) {
$rating = $object->GetDBField('CachedRating');
$votes = $object->GetDBField('CachedVotesQty');
$new_votes = $votes + 1;
$rating = (($rating * $votes) + $new_rating) / $new_votes;
$object->SetDBField('CachedRating', $rating);
$object->SetDBField('CachedVotesQty', $new_votes);
$object->Update();
$expire = adodb_mktime() + $this->Application->ConfigValue('product_ReviewDelay_Value') * $this->Application->ConfigValue('product_ReviewDelay_Interval');
$sql = ' INSERT INTO ' . TABLE_PREFIX . 'SpamControl
(ItemResourceId, IPaddress, PortalUserId, DataType, Expire)
VALUES (' . $object->GetDBField('ResourceId') . ',
"' . $_SERVER['REMOTE_ADDR'] . '",
' . $user_id . ',
"Rating",
' . $expire . ')';
$this->Conn->Query($sql);
}
else {
$event->status == kEvent::erFAIL;
$event->redirect = false;
$object->SetError('CachedRating', 'too_frequent', 'lu_ferror_rate_duplicate');
}
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnCancelAction($event)
{
$event->SetRedirectParam('pass', 'all,p');
$event->redirect = $this->Application->GetVar('cancel_template');
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnRecommendProduct($event)
{
// used for error reporting only -> rewrite code + theme (by Alex)
$object = $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too
/* @var $object kDBItem */
$friend_email = $this->Application->GetVar('friend_email');
$friend_name = $this->Application->GetVar('friend_name');
$my_email = $this->Application->GetVar('your_email');
$my_name = $this->Application->GetVar('your_name');
$my_message = $this->Application->GetVar('your_message');
$send_params = array();
$send_params['to_email']=$friend_email;
$send_params['to_name']=$friend_name;
$send_params['from_email']=$my_email;
$send_params['from_name']=$my_name;
$send_params['message']=$my_message;
if ( preg_match('/' . REGEX_EMAIL_USER . '@' . REGEX_EMAIL_DOMAIN . '/', $friend_email) ) {
$user_id = $this->Application->RecallVar('user_id');
$email_sent = $this->Application->EmailEventUser('PRODUCT.SUGGEST', $user_id, $send_params);
$this->Application->EmailEventAdmin('PRODUCT.SUGGEST');
if ( $email_sent ) {
$event->setRedirectParams(Array ('opener' => 's', 'pass' => 'all'));
$event->redirect = $this->Application->GetVar('template_success');
}
else {
// $event->setRedirectParams(Array('opener' => 's', 'pass' => 'all'));
// $event->redirect = $this->Application->GetVar('template_fail');
$object->SetError('Email', 'send_error', 'lu_email_send_error');
$event->status = kEvent::erFAIL;
}
}
else {
$object->SetError('Email', 'invalid_email', 'lu_InvalidEmail');
$event->status = kEvent::erFAIL;
}
}
/**
* Creates/updates virtual product based on listing type data
*
* @param kEvent $event
*/
function OnSaveVirtualProduct($event)
{
$object = $event->getObject( Array('skip_autoload' => true) );
$listing_type = $this->Application->recallObject('lst', null, Array('skip_autoload' => true));
$listing_type->Load($event->MasterEvent->getEventParam('id'));
$product_id = $listing_type->GetDBField('VirtualProductId');
if ($product_id) {
$object->Load($product_id);
}
if (!$listing_type->GetDBField('EnableBuying')) {
if ($product_id) {
// delete virtual product here
$temp_handler = $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$temp_handler->DeleteItems($event->Prefix, $event->Special, Array($product_id));
$listing_type->SetDBField('VirtualProductId', 0);
$listing_type->Update();
}
return true;
}
$ml_formatter = $this->Application->recallObject('kMultiLanguage');
$object->SetDBField($ml_formatter->LangFieldName('Name'), $listing_type->GetDBField('ShopCartName') );
$object->SetDBField($ml_formatter->LangFieldName('Description'), $listing_type->GetDBField('Description'));
$object->SetDBField('SKU', 'ENHANCE_LINK_'.abs( crc32( $listing_type->GetDBField('Name') ) ) );
if ($product_id) {
$object->Update();
}
else {
$object->SetDBField('Type', 2);
$object->SetDBField('Status', 1);
$object->SetDBField('HotItem', 0);
$object->SetDBField('PopItem', 0);
$object->SetDBField('NewItem', 0);
$object->SetDBField('Virtual', 1);
// $processing_data = Array('ApproveEvent' => 'ls:EnhanceLinkAfterOrderApprove', 'ExpireEvent' => 'ls:ExpireLink');
$processing_data = Array( 'ApproveEvent' => 'ls:EnhanceLinkAfterOrderApprove',
'DenyEvent' => 'ls:EnhanceLinkAfterOrderDeny',
'CompleteOrderEvent' => 'ls:EnhancedLinkOnCompleteOrder',
'ExpireEvent' => 'ls:ExpireLink',
'HasNewProcessing' => 1);
$object->SetDBField('ProcessingData', serialize($processing_data));
$object->Create();
$listing_type->SetDBField('VirtualProductId', $object->GetID());
$listing_type->Update();
}
$additiona_fields = Array( 'AccessDuration' => $listing_type->GetDBField('Duration'),
'AccessUnit' => $listing_type->GetDBField('DurationType'),
);
$this->setPrimaryPrice($object->GetID(), (double)$listing_type->GetDBField('Price'), $additiona_fields);
}
/**
* [HOOK] Deletes virtual product when listing type is deleted
*
* @param kEvent $event
*/
function OnDeleteListingType($event)
{
$listing_type = $event->MasterEvent->getObject();
/* @var $listing_type kDBItem */
$product_id = $listing_type->GetDBField('VirtualProductId');
if ( $product_id ) {
$temp_handler = $this->Application->recallObject($event->getPrefixSpecial() . '_TempHandler', 'kTempTablesHandler');
$temp_handler->DeleteItems($event->Prefix, $event->Special, Array ($product_id));
}
}
/**
* Extends user membership in group when his order is approved
*
* @param kEvent $event
*/
function OnSubscriptionApprove($event)
{
$field_values = $event->getEventParam('field_values');
$item_data = unserialize($field_values['ItemData']);
if ( !getArrayValue($item_data,'PortalGroupId') ) {
// is subscription product, but no group defined in it's properties
trigger_error('Invalid product <b>'.$field_values['ProductName'].'</b> (id: '.$field_values['ProductId'].')', E_USER_WARNING);
return false;
}
$sql = 'SELECT PortalUserId
FROM ' . $this->Application->getUnitOption('ord', 'TableName') . '
WHERE ' . $this->Application->getUnitOption('ord', 'IDField') . ' = ' . $field_values['OrderId'];
$user_id = $this->Conn->GetOne($sql);
$group_id = $item_data['PortalGroupId'];
$duration = $item_data['Duration'];
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'UserGroupRelations
WHERE PortalUserId = ' . $user_id;
$user_groups = $this->Conn->Query($sql, 'GroupId');
if ( !isset($user_groups[$group_id]) ) {
$expire = adodb_mktime() + $duration;
}
else {
$expire = $user_groups[$group_id]['MembershipExpires'];
$expire = $expire < adodb_mktime() ? adodb_mktime() + $duration : $expire + $duration;
}
/*// Customization healtheconomics.org
if ($item_data['DurationType'] == 2) {
$expire = $item_data['AccessExpiration'];
}
// Customization healtheconomics.org --*/
$fields_hash = Array (
'PortalUserId' => $user_id,
'GroupId' => $group_id,
'MembershipExpires' => $expire,
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'UserGroupRelations', 'REPLACE');
$sub_order = $this->Application->recallObject('ord.-sub'.$event->getEventParam('next_sub_number'), 'ord');
$sub_order->SetDBField('IsRecurringBilling', getArrayValue($item_data, 'IsRecurringBilling') ? 1 : 0);
$sub_order->SetDBField('GroupId', $group_id);
$sub_order->SetDBField('NextCharge_date', $expire);
$sub_order->SetDBField('NextCharge_time', $expire);
}
function OnDownloadableApprove($event)
{
$field_values = $event->getEventParam('field_values');
$product_id = $field_values['ProductId'];
$sql = 'SELECT PortalUserId FROM '.$this->Application->getUnitOption('ord', 'TableName').'
WHERE OrderId = '.$field_values['OrderId'];
$user_id = $this->Conn->GetOne($sql);
$sql = 'INSERT INTO '.TABLE_PREFIX.'UserFileAccess VALUES("", '.$product_id.', '.$user_id.')';
$this->Conn->Query($sql);
}
function OnPackageApprove($event){
$field_values = $event->getEventParam('field_values');
$item_data = unserialize($field_values['ItemData']);
$package_content_ids = $item_data['PackageContent'];
$object_item = &$this->Application->recallObject('p.packageitem', null, array('skip_autoload'=>true));
foreach ($package_content_ids as $package_item_id) {
$object_field_values = array();
// query processing data from product and run approve event
$sql = 'SELECT ProcessingData FROM '.TABLE_PREFIX.'Products WHERE ProductId = '.$package_item_id;
$processing_data = $this->Conn->GetOne($sql);
if($processing_data)
{
$processing_data = unserialize($processing_data);
$approve_event = new kEvent($processing_data['ApproveEvent']);
//$order_item_fields = $this->Conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'OrderItems WHERE OrderItemId = '.$grouping_data[1]);
$object_item->Load($package_item_id);
$object_field_values['OrderId'] = $field_values['OrderId'];
$object_field_values['ProductId'] = $package_item_id;
$object_field_values['ItemData'] = serialize($item_data['PackageItemsItemData'][$package_item_id]);
$approve_event->setEventParam('field_values', $object_field_values);
$this->Application->HandleEvent($approve_event);
}
}
}
/**
* Saves edited item into temp table
* If there is no id, new item is created in temp table
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnPreSave(kEvent $event)
{
$this->CheckRequiredOptions($event);
parent::OnPreSave($event);
}
/**
* Set new price to ProductsPricing
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemCreate(kEvent $event)
{
parent::OnAfterItemCreate($event);
$this->_updateProductPrice($event);
}
/**
* Set new price to ProductsPricing
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemUpdate(kEvent $event)
{
parent::OnAfterItemUpdate($event);
$this->_updateProductPrice($event);
}
/**
* Updates product's primary price based on Price virtual field value
*
* @param kEvent $event
*/
function _updateProductPrice($event)
{
$object = $event->getObject();
/* @var $object kDBItem */
$price = $object->GetDBField('Price');
// always create primary pricing, to show on Pricing tab (in admin) for tangible products
$force_create = ($object->GetDBField('Type') == PRODUCT_TYPE_TANGIBLE) && is_null($price);
if ($force_create || ($price != $object->GetOriginalField('Price'))) {
// new product OR price was changed in virtual field
$this->setPrimaryPrice($object->GetID(), (float)$price);
}
}
function CheckRequiredOptions($event)
{
$object = $event->getObject();
if ($object->GetDBField('ProductId') == '') return ; // if product does not have ID - it's not yet created
$opt_object = $this->Application->recallObject('po', null, Array('skip_autoload' => true) );
$has_required = $this->Conn->GetOne('SELECT COUNT(*) FROM '.$opt_object->TableName.' WHERE Required = 1 AND ProductId = '.$object->GetDBField('ProductId'));
//we need to imitate data sumbit, as parent' PreSave sets object values from $items_info
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
$items_info[$object->GetDBField('ProductId')]['HasRequiredOptions'] = $has_required ? '1' : '0';
$this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
$object->SetDBField('HasRequiredOptions', $has_required ? 1 : 0);
}
/**
* Sets required price in primary price backed, if it's missing, then create it
*
* @param int $product_id
* @param double $price
* @param Array $additional_fields
* @return bool
*/
function setPrimaryPrice($product_id, $price, $additional_fields = Array())
{
$pr_object = $this->Application->recallObject('pr.-item', null, Array('skip_autoload' => true) );
/* @var $pr_object kDBItem */
$pr_object->Load( Array('ProductId' => $product_id, 'IsPrimary' => 1) );
$sql = 'SELECT COUNT(*) FROM '.$pr_object->TableName.' WHERE ProductId = '.$product_id;
$has_pricings = $this->Conn->GetOne($sql);
if ($additional_fields) {
$pr_object->SetDBFieldsFromHash($additional_fields);
}
if( ($price === false) && $has_pricings ) return false;
if( $pr_object->isLoaded() )
{
$pr_object->SetField('Price', $price);
return $pr_object->Update();
}
else
{
$group_id = $this->Application->ConfigValue('User_LoggedInGroup');
$field_values = Array('ProductId' => $product_id, 'IsPrimary' => 1, 'MinQty' => 1, 'MaxQty' => -1, 'GroupId'=>$group_id);
$pr_object->SetDBFieldsFromHash($field_values);
$pr_object->SetField('Price', $price);
return $pr_object->Create();
}
}
/**
* Occurs after deleting item, id of deleted item
* is stored as 'id' param of event
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemDelete(kEvent $event)
{
parent::OnAfterItemDelete($event);
$product_id = $event->getEventParam('id');
if ( !$product_id ) {
return;
}
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'UserFileAccess
WHERE ProductId = ' . $product_id;
$this->Conn->Query($sql);
}
/**
* Load price from temp table if product mode is temp table
*
* @param kEvent $event
*/
/**
* Load price from temp table if product mode is temp table
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterItemLoad(kEvent $event)
{
parent::OnAfterItemLoad($event);
$object = $event->getObject();
/* @var $object ProductsItem */
$a_pricing = $object->getPrimaryPricing();
if ( !$a_pricing ) {
// pricing doesn't exist for new products
$price = $cost = null;
}
else {
$price = (float)$a_pricing['Price'];
$cost = (float)$a_pricing['Cost'];
}
// set original fields to use them in OnAfterItemCreate/OnAfterItemUpdate later
$object->SetDBField('Price', $price);
$object->SetOriginalField('Price', $price);
$object->SetDBField('Cost', $cost);
$object->SetOriginalField('Cost', $cost);
}
/**
* Allows to add products to package besides all that parent method does
*
* @param kEvent $event
*/
function OnProcessSelected($event)
{
$dst_field = $this->Application->RecallVar('dst_field');
if ($dst_field == 'PackageContent') {
$this->OnAddToPackage($event);
}
elseif ($dst_field == 'AssignedCoupon') {
$coupon_id = $this->Application->GetVar('selected_ids');
$object = $event->getObject();
$object->SetDBField('AssignedCoupon', $coupon_id);
$this->RemoveRequiredFields($object);
$object->Update();
}
else {
parent::OnProcessSelected($event);
}
$this->finalizePopup($event);
}
/**
* Called when some products are selected in products selector for this prefix
*
* @param kEvent $event
*/
function OnAddToPackage($event)
{
$selected_ids = $this->Application->GetVar('selected_ids');
// update current package content with selected products
$object = $event->getObject();
/* @var $object ProductsItem */
$product_ids = $selected_ids['p'] ? explode(',', $selected_ids['p']) : Array();
if ($product_ids) {
$current_ids = $object->GetPackageContentIds();
$current_ids = array_unique(array_merge($current_ids, $product_ids));
// remove package product from selected list
$this_product = array_search($object->GetID(), $current_ids);
if ($this_product !== false) {
unset($current_ids[$this_product]);
}
$dst_field = $this->Application->RecallVar('dst_field');
$object->SetDBField($dst_field, '|'.implode('|', $current_ids).'|');
$object->Update();
$this->ProcessPackageItems($event);
}
$this->finalizePopup($event);
}
function ProcessPackageItems($event)
{
//$this->Application->SetVar('p_mode', 't');
$object = $event->getObject();
/* @var $object ProductsItem */
$content_ids = $object->GetPackageContentIds();
if (sizeof($content_ids) > 0) {
$total_weight = $this->Conn->GetOne('SELECT SUM(Weight) FROM '.TABLE_PREFIX.'Products WHERE ProductId IN ('.implode(', ', $content_ids).') AND Type=1');
if (!$total_weight) $total_weight = 0;
$this->Conn->Query('UPDATE '.$object->TableName.' SET Weight='.$total_weight.' WHERE ProductId='.$object->GetID());
}
/*
$this->Application->SetVar('p_mode', false);
$list = &$this->Application->recallObject('p.content', 'p_List', array('types'=>'content'));
$this->Application->SetVar('p_mode', 't');
$list->Query();
$total_weight_a = 0;
$total_weight_b = 0;
$list->GoFirst();
while (!$list->EOL())
{
if ($list->GetDBField('Type')==1){
$total_weight_a += $list->GetField('Weight_a');
$total_weight_b += $list->GetField('Weight_b');
}
$list->GoNext();
}
$object->SetField('Weight_a', $total_weight_a);
$object->SetField('Weight_b', $total_weight_b);
*/
//$object->Update();
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnSaveItems($event)
{
//$event->CallSubEvent('OnUpdate');
$event->redirect = false;
//$event->setRedirectParams(Array ('opener' => 's', 'pass' => 'all,p'));
}
/**
* Removes product from package
*
* @param kEvent $event
*/
function OnRemovePackageItem($event) {
$this->Application->SetVar('p_mode', 't');
$object = $event->getObject();
$items_info = $this->Application->GetVar('p_content');
if($items_info)
{
$product_ids = array_keys($items_info);
$current_ids = $object->GetPackageContentIds();
$current_ids_flip = array_flip($current_ids);
foreach($product_ids as $key=>$val){
unset($current_ids_flip[$val]);
}
$current_ids = array_keys($current_ids_flip);
$current_ids_str = '|'.implode('|', array_unique($current_ids)).'|';
$object->SetDBField('PackageContent', $current_ids_str);
}
$object->Update();
$this->ProcessPackageItems($event);
}
/**
* Occurs before deleting item, id of item being
* deleted is stored as 'id' event param
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnBeforeItemDelete(kEvent $event)
{
parent::OnBeforeItemDelete($event);
$object = $event->getObject();
/* @var $object kDBItem */
$sql = 'SELECT COUNT(*)
FROM ' . TABLE_PREFIX . 'Products
WHERE PackageContent LIKE "%|' . $object->GetID() . '%"';
$product_includes_in = $this->Conn->GetOne($sql);
if ( $product_includes_in > 0 ) {
$event->status = kEvent::erFAIL;
}
}
/**
* Returns specific to each item type columns only
*
* @param kEvent $event
* @return Array
* @access protected
*/
public function getCustomExportColumns(kEvent $event)
{
$columns = parent::getCustomExportColumns($event);
$new_columns = Array (
'__VIRTUAL__Price' => 'Price',
'__VIRTUAL__Cost' => 'Cost',
);
return array_merge($columns, $new_columns);
}
/**
* Sets non standart virtual fields (e.g. to other tables)
*
* @param kEvent $event
*/
function setCustomExportColumns($event)
{
parent::setCustomExportColumns($event);
$object = $event->getObject();
/* @var $object kDBItem */
$this->setPrimaryPrice($object->GetID(), (double)$object->GetDBField('Price'), Array ('Cost' => (double)$object->GetDBField('Cost')));
}
function OnPreSaveAndOpenPopup($event)
{
$object = $event->getObject();
/* @var $object kDBItem */
$this->RemoveRequiredFields($object);
$event->CallSubEvent('OnPreSave');
$event->redirect = $this->Application->GetVar('t');
// pass ID too, in case if product is created by OnPreSave call to ensure proper editing
$event->SetRedirectParam('pass', 'all');
$event->SetRedirectParam($event->getPrefixSpecial(true) . '_id', $object->GetID());
}
/**
* Returns ID of current item to be edited
* by checking ID passed in get/post as prefix_id
* or by looking at first from selected ids, stored.
* Returned id is also stored in Session in case
* it was explicitly passed as get/post
*
* @param kEvent $event
* @return int
* @access public
*/
public function getPassedID(kEvent $event)
{
if ( $this->Application->isAdminUser ) {
$event->setEventParam('raise_warnings', 0);
}
$passed = parent::getPassedID($event);
if ( $passed ) {
return $passed;
}
if ( $this->Application->isAdminUser ) {
// we may get product id out of OrderItem, if it exists
$ord_item = $this->Application->recallObject('orditems', null, Array ('raise_warnings' => 0));
/* @var $ord_item OrdersItem */
if ( $ord_item->GetDBField('ProductId') ) {
$passed = $ord_item->GetDBField('ProductId');
}
}
return $passed;
}
/**
* Occurs, when config was parsed, allows to change config data dynamically
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAfterConfigRead(kEvent $event)
{
parent::OnAfterConfigRead($event);
if (!$this->Application->LoggedIn()) {
return ;
}
$user_id = $this->Application->RecallVar('user_id');
$sql = 'SELECT PrimaryGroupId
FROM ' . TABLE_PREFIX . 'Users
WHERE PortalUserId = ' . $user_id;
$primary_group_id = $this->Conn->GetOne($sql);
if (!$primary_group_id) {
return;
}
$sub_select = ' SELECT pp.Price
FROM ' . TABLE_PREFIX . 'ProductsPricing AS pp
WHERE pp.ProductId = %1$s.ProductId AND GroupId = ' . $primary_group_id . '
ORDER BY MinQty
LIMIT 0,1';
$calculated_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields');
$calculated_fields['']['Price'] = 'IFNULL((' . $sub_select . '), ' . $calculated_fields['']['Price'] . ')';
$this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calculated_fields);
}
/**
* Starts product editing, remove any pending inventory actions
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnEdit(kEvent $event)
{
$this->Application->RemoveVar('inventory_actions');
parent::OnEdit($event);
}
/**
* Adds "Shop Cart" tab on paid listing type editing tab
*
* @param kEvent $event
*/
function OnModifyPaidListingConfig($event)
{
$edit_tab_presets = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'EditTabPresets');
$edit_tab_presets['Default']['shopping_cart'] = Array ('title' => 'la_tab_ShopCartEntry', 't' => 'in-commerce/paid_listings/paid_listing_type_shopcart', 'priority' => 2);
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'EditTabPresets', $edit_tab_presets);
}
/**
* [HOOK] Allows to add cloned subitem to given prefix
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnCloneSubItem(kEvent $event)
{
parent::OnCloneSubItem($event);
if ( $event->MasterEvent->Prefix == 'rev' ) {
$clones = $this->Application->getUnitOption($event->MasterEvent->Prefix, 'Clones');
$subitem_prefix = $event->Prefix . '-' . $event->MasterEvent->Prefix;
$clones[$subitem_prefix]['ConfigMapping'] = Array (
'PerPage' => 'Comm_Perpage_Reviews',
'ReviewDelayInterval' => 'product_ReviewDelay_Value',
'ReviewDelayValue' => 'product_ReviewDelay_Interval',
);
$this->Application->setUnitOption($event->MasterEvent->Prefix, 'Clones', $clones);
}
}
/**
* Adds product to comparison list
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnAddToCompare(kEvent $event)
{
$products = $this->getCompareProducts();
$product_id = (int)$this->Application->GetVar($event->Prefix . '_id');
if ( $product_id ) {
$max_products = $this->Application->ConfigValue('MaxCompareProducts');
if ( count($products) < $max_products ) {
$products[] = $product_id;
$this->Application->Session->SetCookie('compare_products', implode('|', array_unique($products)));
$event->SetRedirectParam('result', 'added');
}
else {
$event->SetRedirectParam('result', 'error');
}
}
$event->SetRedirectParam('pass', 'm,p');
}
/**
* Adds product to comparison list
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnRemoveFromCompare(kEvent $event)
{
$products = $this->getCompareProducts();
$product_id = (int)$this->Application->GetVar($event->Prefix . '_id');
if ( $product_id && in_array($product_id, $products) ) {
$products = array_diff($products, Array ($product_id));
$this->Application->Session->SetCookie('compare_products', implode('|', array_unique($products)));
$event->SetRedirectParam('result', 'removed');
}
$event->SetRedirectParam('pass', 'm,p');
}
/**
* Cancels product compare
*
* @param kEvent $event
* @return void
* @access protected
*/
protected function OnCancelCompare(kEvent $event)
{
$this->Application->Session->SetCookie('compare_products', '', -1);
$event->SetRedirectParam('result', 'all_removed');
}
/**
* Returns products, that needs to be compared with each other
*
* @return Array
* @access protected
*/
protected function getCompareProducts()
{
$products = $this->Application->GetVarDirect('compare_products', 'Cookie');
$products = $products ? explode('|', $products) : Array ();
return $products;
}
}
\ No newline at end of file

Event Timeline