Răsfoiți Sursa

Merge branch 'master' of github.com:boonex/dolphin

Alex Trofimov 10 ani în urmă
părinte
comite
d807916780
100 a modificat fișierele cu 6623 adăugiri și 39 ștergeri
  1. 24 0
      cart.php
  2. 1 28
      inc/classes/BxDolAcl.php
  3. 177 0
      inc/classes/BxDolPayments.php
  4. 32 0
      inc/classes/BxDolPaymentsQuery.php
  5. 5 1
      inc/js/classes/BxDolGrid.js
  6. 0 1
      install/sql/system.sql
  7. 3 3
      modules/base/general/classes/BxBaseModGeneralConfig.php
  8. 1 1
      modules/base/notifications/classes/BxBaseModNotificationsConfig.php
  9. 98 0
      modules/base/payment/classes/BxBaseModPaymentCart.php
  10. 161 0
      modules/base/payment/classes/BxBaseModPaymentConfig.php
  11. 46 0
      modules/base/payment/classes/BxBaseModPaymentDb.php
  12. 119 0
      modules/base/payment/classes/BxBaseModPaymentGridOrders.php
  13. 25 0
      modules/base/payment/classes/BxBaseModPaymentJoin.php
  14. 185 0
      modules/base/payment/classes/BxBaseModPaymentModule.php
  15. 33 0
      modules/base/payment/classes/BxBaseModPaymentOrders.php
  16. 73 0
      modules/base/payment/classes/BxBaseModPaymentProvider.php
  17. 112 0
      modules/base/payment/classes/BxBaseModPaymentTemplate.php
  18. 1 1
      modules/boonex/accounts/classes/BxAccntConfig.php
  19. 21 0
      modules/boonex/air/data/template/system/scripts/BxTemplPaymentsServices.php
  20. 1 1
      modules/boonex/albums/classes/BxAlbumsConfig.php
  21. 7 0
      modules/boonex/english/data/langs/system/en.xml
  22. 1 1
      modules/boonex/invites/classes/BxInvConfig.php
  23. 21 0
      modules/boonex/lagoon/data/template/system/scripts/BxTemplPaymentsServices.php
  24. 21 0
      modules/boonex/market/classes/BxMarketAlertsResponse.php
  25. 24 0
      modules/boonex/market/classes/BxMarketCmtsSearchResult.php
  26. 133 0
      modules/boonex/market/classes/BxMarketConfig.php
  27. 23 0
      modules/boonex/market/classes/BxMarketDb.php
  28. 24 0
      modules/boonex/market/classes/BxMarketFormEntry.php
  29. 23 0
      modules/boonex/market/classes/BxMarketFormsEntryHelper.php
  30. 21 0
      modules/boonex/market/classes/BxMarketGridAdministration.php
  31. 21 0
      modules/boonex/market/classes/BxMarketGridCommon.php
  32. 24 0
      modules/boonex/market/classes/BxMarketMenu.php
  33. 25 0
      modules/boonex/market/classes/BxMarketMenuManageTools.php
  34. 24 0
      modules/boonex/market/classes/BxMarketMenuView.php
  35. 24 0
      modules/boonex/market/classes/BxMarketMenuViewActions.php
  36. 23 0
      modules/boonex/market/classes/BxMarketModule.php
  37. 24 0
      modules/boonex/market/classes/BxMarketPageAuthor.php
  38. 24 0
      modules/boonex/market/classes/BxMarketPageBrowse.php
  39. 24 0
      modules/boonex/market/classes/BxMarketPageEntry.php
  40. 126 0
      modules/boonex/market/classes/BxMarketSearchResult.php
  41. 44 0
      modules/boonex/market/classes/BxMarketTemplate.php
  42. 116 0
      modules/boonex/market/install/config.php
  43. 20 0
      modules/boonex/market/install/installer.php
  44. 217 0
      modules/boonex/market/install/langs/en.xml
  45. 42 0
      modules/boonex/market/install/sql/disable.sql
  46. 346 0
      modules/boonex/market/install/sql/enable.sql
  47. 299 0
      modules/boonex/market/install/sql/install.sql
  48. 39 0
      modules/boonex/market/install/sql/uninstall.sql
  49. 51 0
      modules/boonex/market/js/manage_tools.js
  50. 18 0
      modules/boonex/market/request.php
  51. 3 0
      modules/boonex/market/template/attachments.html
  52. 3 0
      modules/boonex/market/template/author.html
  53. 1 0
      modules/boonex/market/template/author_link.html
  54. 3 0
      modules/boonex/market/template/css/forms.css
  55. 3 0
      modules/boonex/market/template/css/main.css
  56. 1 0
      modules/boonex/market/template/css/manage_tools.css
  57. 3 0
      modules/boonex/market/template/entry-all-actions.html
  58. 3 0
      modules/boonex/market/template/entry-location.html
  59. 3 0
      modules/boonex/market/template/entry-share.html
  60. 3 0
      modules/boonex/market/template/entry-text.html
  61. 3 0
      modules/boonex/market/template/form_field_location.html
  62. 3 0
      modules/boonex/market/template/form_ghost_template.html
  63. BIN
      modules/boonex/market/template/images/icons/std-mi.png
  64. BIN
      modules/boonex/market/template/images/icons/std-pi.png
  65. BIN
      modules/boonex/market/template/images/icons/std-si.png
  66. BIN
      modules/boonex/market/template/images/icons/std-wi.png
  67. 1 0
      modules/boonex/market/template/title_link.html
  68. 3 0
      modules/boonex/market/template/unit.html
  69. 1 0
      modules/boonex/market/template/unit_full.html
  70. 1 0
      modules/boonex/market/template/unit_gallery.html
  71. 3 0
      modules/boonex/market/template/unit_live_search.html
  72. 3 0
      modules/boonex/market/template/unit_private.html
  73. 1 1
      modules/boonex/notifications/classes/BxNtfsConfig.php
  74. 21 0
      modules/boonex/ocean/data/template/system/scripts/BxTemplPaymentsServices.php
  75. 1 1
      modules/boonex/organizations/classes/BxOrgsConfig.php
  76. 221 0
      modules/boonex/payment/classes/BxPaymentCart.php
  77. 150 0
      modules/boonex/payment/classes/BxPaymentConfig.php
  78. 304 0
      modules/boonex/payment/classes/BxPaymentDb.php
  79. 192 0
      modules/boonex/payment/classes/BxPaymentDetails.php
  80. 20 0
      modules/boonex/payment/classes/BxPaymentFormView.php
  81. 35 0
      modules/boonex/payment/classes/BxPaymentGridHistory.php
  82. 90 0
      modules/boonex/payment/classes/BxPaymentGridPending.php
  83. 124 0
      modules/boonex/payment/classes/BxPaymentGridProcessed.php
  84. 118 0
      modules/boonex/payment/classes/BxPaymentJoin.php
  85. 364 0
      modules/boonex/payment/classes/BxPaymentModule.php
  86. 101 0
      modules/boonex/payment/classes/BxPaymentOrders.php
  87. 20 0
      modules/boonex/payment/classes/BxPaymentPageCart.php
  88. 20 0
      modules/boonex/payment/classes/BxPaymentPageDetails.php
  89. 20 0
      modules/boonex/payment/classes/BxPaymentPageHistory.php
  90. 20 0
      modules/boonex/payment/classes/BxPaymentPageJoin.php
  91. 20 0
      modules/boonex/payment/classes/BxPaymentPageOrders.php
  92. 143 0
      modules/boonex/payment/classes/BxPaymentProvider2Checkout.php
  93. 585 0
      modules/boonex/payment/classes/BxPaymentProviderBitPay.php
  94. 269 0
      modules/boonex/payment/classes/BxPaymentProviderPayPal.php
  95. 48 0
      modules/boonex/payment/classes/BxPaymentResponse.php
  96. 317 0
      modules/boonex/payment/classes/BxPaymentTemplate.php
  97. 70 0
      modules/boonex/payment/install/config.php
  98. 30 0
      modules/boonex/payment/install/installer.php
  99. 289 0
      modules/boonex/payment/install/langs/en.xml
  100. 39 0
      modules/boonex/payment/install/sql/disable.sql

+ 24 - 0
cart.php

@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    TridentCore Trident Core
+ * @{
+ */
+
+require_once('./inc/header.inc.php');
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+bx_import('BxDolLanguages');
+
+check_logged();
+
+$sLink = BxDolPayments::getInstance()->getCartLink();
+if(empty($sLink))
+	BxDolTemplate::getInstance()->displayPageNotFound();
+
+header('Location: ' . $sLink);
+exit;
+
+/** @} */

+ 1 - 28
inc/classes/BxDolAcl.php

@@ -541,33 +541,6 @@ class BxDolAcl extends BxDol implements iBxDolSingleton
         return true;
     }
 
-    /**
-     * Define action, defining all names are translated the following way:
-     *  my action => BX_MY_ACTION
-     *
-     * @param $aActions array of actions from sys_acl_actions table, with default array keys (starting from 0) and text values
-     */
-    function defineMembershipActions($mixedActions, $sPrefix = 'BX_')
-    {
-        if (is_array($mixedActions))
-            $aActions = $mixedActions;
-        else
-            $aActions = array($mixedActions);
-
-        $aNames = array();
-        foreach ($aActions as $sName)
-            if(!defined($sPrefix . strtoupper(str_replace(' ', '_', $sName))))
-                $aNames[] = $sName;
-
-        if(!$aNames)
-            return;
-
-        $aActions = array();
-        $this->oDb->getActions(array('type' => 'by_names', 'value' => $aNames), $aActions, false);
-        foreach($aActions as $aAction)
-            define($sPrefix . strtoupper(str_replace(' ', '_', $aAction['name'])), $aAction['id']);
-    }
-
     /**
      * get action id by module and name
      * @param $sAction action name
@@ -699,7 +672,7 @@ function checkActionModule($iProfileId, $sActionName, $sModuleName, $bPerformAct
 
     $iActionId = $oACL->getMembershipActionId($sActionName, $sModuleName);
 
-    return BxDolAcl::getInstance()->checkAction($iProfileId, $iActionId, $bPerformAction);
+    return $oACL->checkAction($iProfileId, $iActionId, $bPerformAction);
 }
 
 /** @} */

+ 177 - 0
inc/classes/BxDolPayments.php

@@ -0,0 +1,177 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    TridentCore Trident Core
+ * @{
+ */
+
+class BxDolPayments extends BxDol implements iBxDolSingleton
+{
+	protected $_oDb;
+
+	protected $_aObjects;
+	protected $_sActive;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+        $this->_oDb = new BxDolPaymentsQuery();
+
+        $this->_aObjects = $this->_oDb->getObjects();
+        $this->_sActive = getParam('sys_default_payment');
+    }
+
+	static public function getInstance()
+    {
+        if(!isset($GLOBALS['bxDolClasses']['BxDolPayments']))
+        	$GLOBALS['bxDolClasses']['BxDolPayments'] = new BxDolPayments();
+
+		return $GLOBALS['bxDolClasses']['BxDolPayments'];
+    }
+
+	public function setActive($sActive)
+    {
+		$this->_sActive = $sActive;
+    }
+
+    public function getActive()
+    {
+    	return $this->_sActive;
+    }
+
+    public function isActive()
+    {
+    	if(empty($this->_sActive))
+    		return false;
+
+    	if(!BxDolModuleQuery::getInstance()->isModuleByName($this->_sActive))
+    		return false;
+
+    	return true;
+    }
+
+	public function getPayments()
+    {
+        $aPayments = array(
+			'' => _t('_Select_one')
+        );
+		foreach($this->_aObjects as $aObject) {
+			if(empty($aObject) || !is_array($aObject))
+				continue;
+
+			$aPayments[$aObject['object']] = _t($aObject['title']);
+		}
+
+        return $aPayments;
+    }
+
+    public function getProviders($iVendorId, $sProvider = '')
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_providers'))
+    		return array();
+
+    	$aSrvParams = array($iVendorId, $sProvider);
+        return BxDolService::call($this->_sActive, 'get_providers', $aSrvParams);
+    }
+
+	public function getOption($sOption)
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_option'))
+    		return '';
+
+    	return BxDolService::call($this->_sActive, 'get_option', array($sOption));
+    }
+
+    public function getOrdersLink()
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_orders_link', 'Orders'))
+    		return '';
+
+    	return BxDolService::call($this->_sActive, 'get_orders_link', array(), 'Orders');
+    }
+
+    public function getOrdersCount($sType)
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_orders_count_new', 'Orders'))
+    		return array();
+
+		$aSrvParams = array($sType);
+		return BxDolService::call($this->_sActive, 'get_orders_count_new', $aSrvParams, 'Orders');
+    }
+
+    public function getCartLink()
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_cart_link', 'Cart'))
+    		return '';
+
+    	return BxDolService::call($this->_sActive, 'get_cart_link', array(), 'Cart');
+    }
+
+    public function getCartItemsCount()
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_cart_items_count', 'Cart'))
+    		return array();
+
+		$aSrvParams = array();
+		return BxDolService::call($this->_sActive, 'get_cart_items_count', $aSrvParams, 'Cart');
+    }
+
+    public function getCartItemDescriptor($iVendorId, $iModuleId, $iItemId, $iItemCount)
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_cart_item_descriptor', 'Cart'))
+    		return '';
+
+    	$aSrvParams = array($iVendorId, $iModuleId, $iItemId, $iItemCount);
+		return BxDolService::call($this->_sActive, 'get_cart_item_descriptor', $aSrvParams, 'Cart');
+    }
+    
+    public function getCartJs($bWrapped = true)
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_cart_js', 'Cart'))
+			return '';
+
+		$aSrvParams = array($bWrapped);
+		return BxDolService::call($this->_sActive, 'get_cart_js', $aSrvParams, 'Cart');
+    }
+
+    public function getAddToCartJs($iVendorId, $mixedModuleId, $iItemId, $iItemCount, $bNeedRedirect = false, $bWrapped = true)
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_add_to_cart_js', 'Cart'))
+			return array();
+
+		$aSrvParams = array($iVendorId, $mixedModuleId, $iItemId, $iItemCount, $bNeedRedirect, $bWrapped);
+		return BxDolService::call($this->_sActive, 'get_add_to_cart_js', $aSrvParams, 'Cart');
+    }
+
+    public function getAddToCartLink($iVendorId, $mixedModuleId, $iItemId, $iItemCount, $bNeedRedirect = false)
+    {
+		if(!BxDolRequest::serviceExists($this->_sActive, 'get_add_to_cart_link', 'Cart'))
+			return '';
+
+		$aSrvParams = array($iVendorId, $mixedModuleId, $iItemId, $iItemCount, $bNeedRedirect);
+		return BxDolService::call($this->_sActive, 'get_add_to_cart_link', $aSrvParams, 'Cart');
+    }
+
+    public function initializeCheckout($iVendorId, $sProvider, $aItems = array())
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'initialize_checkout'))
+			return '';
+
+		$aSrvParams = array($iVendorId, $sProvider, $aItems);
+		return BxDolService::call($this->_sActive, 'initialize_checkout', $aSrvParams);
+    }
+
+	public function prolongSubscription($sOrderId)
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'prolong_subscription'))
+			return '';
+
+		$aSrvParams = array($sOrderId);
+		return BxDolService::call($this->_sActive, 'prolong_subscription', $aSrvParams);
+    }
+}
+
+/** @} */

+ 32 - 0
inc/classes/BxDolPaymentsQuery.php

@@ -0,0 +1,32 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    TridentCore Trident Core
+ * @{
+ */
+
+/**
+ * @see BxDolPayments
+ */
+class BxDolPaymentsQuery extends BxDolDb
+{
+	public function __construct()
+    {
+    	parent::__construct();
+    }
+
+    public function getObjects()
+    {
+    	$sQuery = $this->prepare("SELECT * FROM `sys_objects_payments` WHERE 1");
+    	
+        $aObjects = $this->getAll($sQuery);
+        if(empty($aObjects) || !is_array($aObjects))
+            return array();
+
+        return $aObjects;
+    }
+}
+
+/** @} */

+ 5 - 1
inc/js/classes/BxDolGrid.js

@@ -16,7 +16,11 @@ function BxDolGrid (sObject, oOptions) {
     this._sOrderField = undefined == oOptions.order_field ? '' : oOptions.order_field;
     this._sOrderDir = undefined == oOptions.order_dir ? 'ASC' : oOptions.order_dir;
     this._sSearchInputText = undefined == oOptions.text_search_input ? '' : oOptions.text_search_input;
-    this._oPopupOptions = oOptions.popup_options || {};
+    this._oPopupOptions = $.extend({
+    	onBeforeShow: function(oElement) {
+    		jQuery(oElement).bxTime();
+    	}
+    }, oOptions.popup_options);
     this._oQueryAppend = oOptions.query_append;
     this._oConfirmMessages = oOptions.confirm_messages;
 

Fișier diff suprimat deoarece este prea mare
+ 0 - 1
install/sql/system.sql


+ 3 - 3
modules/base/general/classes/BxBaseModGeneralConfig.php

@@ -15,7 +15,7 @@ class BxBaseModGeneralConfig extends BxDolModuleConfig
 
     protected $_aObjects;
     protected $_aPrefixes;
-    protected $_aJsClass;
+    protected $_aJsClasses;
     protected $_aJsObjects;
     protected $_aGridObjects;
 
@@ -25,7 +25,7 @@ class BxBaseModGeneralConfig extends BxDolModuleConfig
 
         $this->_aObjects = array();
         $this->_aPrefixes = array();
-        $this->_aJsClass = array();
+        $this->_aJsClasses = array();
         $this->_aJsObjects = array();
         $this->_aGridObjects = array();
     }
@@ -48,7 +48,7 @@ class BxBaseModGeneralConfig extends BxDolModuleConfig
 
 	public function getJsClass($sType)
     {
-        return isset($this->_aJsClass[$sType]) ? $this->_aJsClass[$sType] : '';
+        return isset($this->_aJsClasses[$sType]) ? $this->_aJsClasses[$sType] : '';
     }
 
     public function getJsObject($sType)

+ 1 - 1
modules/base/notifications/classes/BxBaseModNotificationsConfig.php

@@ -46,7 +46,7 @@ class BxBaseModNotificationsConfig extends BxBaseModGeneralConfig
         $this->_aHandlersHidden = array();
         $this->_aHandlers = array();
 
-		$this->_aJsClass = array();
+		$this->_aJsClasses = array();
 		$this->_aJsObjects = array();
 
 		$this->_aPerPage = array();

+ 98 - 0
modules/base/payment/classes/BxBaseModPaymentCart.php

@@ -0,0 +1,98 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentCart extends BxDol
+{
+	protected $MODULE;
+	protected $_oModule;
+
+	function __construct()
+    {
+        parent::__construct();
+
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+    }
+
+	public function serviceGetCartLink()
+    {
+    	if(!$this->_oModule->isLogged())
+            return '';
+
+    	return $this->_oModule->_oConfig->getUrl('cart');
+    }
+
+    public function serviceGetCartJs($bWrapped = true)
+    {
+        return $this->_oModule->_oTemplate->displayCartJs($bWrapped);
+    }
+
+	public function serviceGetAddToCartLink($iVendorId, $mixedModuleId, $iItemId, $iItemCount, $bNeedRedirect = false)
+    {
+        $iModuleId = $this->_oModule->_oConfig->getModuleId($mixedModuleId);
+        if(empty($iModuleId))
+            return '';
+
+		return $this->_oModule->_oTemplate->displayAddToCartLink($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect);
+    }
+
+    public function serviceGetAddToCartJs($iVendorId, $mixedModuleId, $iItemId, $iItemCount, $bNeedRedirect = false, $bWrapped = true)
+    {
+		$iModuleId = $this->_oModule->_oConfig->getModuleId($mixedModuleId);
+        if(empty($iModuleId))
+            return '';
+
+        return $this->_oModule->_oTemplate->displayAddToCartJs($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect, $bWrapped);
+    }
+
+	public function serviceGetCartItemDescriptor($iVendorId, $iModuleId, $iItemId, $iItemCount)
+	{
+		return $this->_oModule->_oConfig->descriptorA2S(array($iVendorId, $iModuleId, $iItemId, $iItemCount));
+	}
+
+    public function serviceGetCartItemsCount($iUserId = 0)
+    {
+    	$iUserId = !empty($iUserId) ? $iUserId : $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return 0;
+
+        $aInfo = $this->getInfo($iUserId);
+
+        $iCount = 0;
+        foreach($aInfo as $iVendorId => $aVendorCart)
+            $iCount += $aVendorCart['items_count'];
+
+        return $iCount;
+    }
+
+	protected function _parseByVendor($iUserId)
+    {
+        $sItems = $this->_oModule->_oDb->getCartItems($iUserId);
+        return $this->_reparseBy($this->_oModule->_oConfig->descriptorsM2A($sItems), 'vendor_id');
+    }
+
+    protected function _parseByModule($iUserId)
+    {
+        $sItems = $this->_oModule->_oDb->getCartItems($iUserId);
+        return $this->_reparseBy($this->_oModule->_oConfig->descriptorsM2A($sItems), 'module_id');
+    }
+
+	protected function _reparseBy($aItems, $sKey)
+    {
+        $aResult = array();
+        foreach($aItems as $aItem)
+            if(isset($aItem[$sKey]))
+                $aResult[$aItem[$sKey]][] = $aItem;
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 161 - 0
modules/base/payment/classes/BxBaseModPaymentConfig.php

@@ -0,0 +1,161 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
+{
+	protected $_oDb;
+
+	protected $_iSiteId;
+	protected $_sCurrencySign;
+    protected $_sCurrencyCode;
+
+    protected $_aKeys;
+    protected $_aUrls;
+    protected $_aDividers;
+
+    protected $_aPerPage;
+    protected $_aHtmlIds;
+
+    protected $_sAnimationEffect;
+    protected $_iAnimationSpeed;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_aKeys = array(
+        	'session_key_pending' => $this->_sName . '_pending_id',
+        	'request_key_pending' => $this->_sName . '_pending_id'
+        );
+
+        $this->_aUrls = array();
+
+        $this->_aDividers = array(
+        	'descriptor' => '_',
+        	'descriptors' => ':'
+        );
+
+		$this->_aPrefixes = array(
+			'general' => $this->_sName . '_',
+			'langs' => '_' . $this->_sName . '_',
+        	'options' => $this->_sName . '_'
+		);
+
+		$this->_aObjects = array_merge($this->_aObjects, array(
+			'form_pendings' => $this->_sName . '_form_pendings',
+			'form_processed' => $this->_sName . '_form_processed',
+			'display_pendings_process' => $this->_sName . '_form_pendings_process',
+			'display_processed_add' => $this->_sName . '_form_processed_add',
+
+			'menu_cart_submenu' => $this->_sName . '_menu_cart_submenu',
+        	'menu_orders_submenu' => $this->_sName . '_menu_orders_submenu',
+
+			'grid_history' => $this->_sName . '_grid_orders_history',
+			'grid_processed' => $this->_sName . '_grid_orders_processed',
+			'grid_pending' => $this->_sName . '_grid_orders_pending'
+		));
+
+		$this->_aPerPage = array();
+		$this->_aHtmlIds = array();
+
+		$this->_sAnimationEffect = 'fade';
+        $this->_iAnimationSpeed = 'slow';
+    }
+
+    public function init(&$oDb)
+    {
+    	$this->_oDb = $oDb;
+    	
+    	$sPrefix = $this->getPrefix('options');
+        $this->_iSiteId = (int)$this->_oDb->getParam($sPrefix . 'site_admin');
+        $this->_sCurrencySign = $this->_oDb->getParam($sPrefix . 'default_currency_sign');
+        $this->_sCurrencyCode = $this->_oDb->getParam($sPrefix . 'default_currency_code');
+    }
+
+    public function getSiteId()
+    {
+        if(empty($this->_iSiteId))
+            return $this->_oDb->getFirstAdminId();
+
+        return $this->_iSiteId;
+    }
+
+    public function getCurrencySign()
+    {
+        return $this->_sCurrencySign;
+    }
+
+    public function getCurrencyCode()
+    {
+        return $this->_sCurrencyCode;
+    }
+
+	public function getKey($sType)
+    {
+    	if(empty($sType))
+            return $this->_aKeys;
+
+        return isset($this->_aKeys[$sType]) ? $this->_aKeys[$sType] : '';
+    }
+
+    public function getUrl($sType, $aParams = array(), $bSsl = false)
+    {
+    	if(empty($sType))
+            return $this->_aUrls;
+
+		$sResult = '';
+		if(!isset($this->_aUrls[$sType]))
+			return $sResult;
+
+		if(strncmp($this->_aUrls[$sType], BX_DOL_URL_ROOT, strlen(BX_DOL_URL_ROOT)) == 0)
+			$sResult = bx_append_url_params($this->_aUrls[$sType], $aParams);
+		else
+			$sResult = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink($this->_aUrls[$sType], $aParams);
+
+    	return $bSsl ? $this->http2https($sResult) : $sResult;
+    }
+
+	public function getDivider($sType)
+    {
+    	if(empty($sType))
+            return $this->_aDividers;
+
+        return isset($this->_aDividers[$sType]) ? $this->_aDividers[$sType] : '';
+    }
+
+	public function getPerPage($sType = 'default')
+    {
+    	if(empty($sType))
+            return $this->_aPerPage;
+
+        return isset($this->_aPerPage[$sType]) ? $this->_aPerPage[$sType] : '';
+    }
+
+	public function getHtmlIds($sType, $sKey = '')
+    {
+        if(empty($sKey))
+            return isset($this->_aHtmlIds[$sType]) ? $this->_aHtmlIds[$sType] : array();
+
+        return isset($this->_aHtmlIds[$sType][$sKey]) ? $this->_aHtmlIds[$sType][$sKey] : '';
+    }
+
+    public function getAnimationEffect()
+    {
+        return $this->_sAnimationEffect;
+    }
+
+	public function getAnimationSpeed()
+    {
+        return $this->_iAnimationSpeed;
+    }
+}
+
+/** @} */

+ 46 - 0
modules/base/payment/classes/BxBaseModPaymentDb.php

@@ -0,0 +1,46 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentDb extends BxBaseModGeneralDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+	public function insertModule($aData)
+    {
+    	$sQuery = $this->prepare("INSERT IGNORE INTO `" . $this->_sPrefix . "modules`(`name`) VALUES(?)", $aData['name']);
+		$this->query($sQuery);
+    }
+
+    public function deleteModule($aData)
+    {
+    	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "modules` WHERE `name`=? LIMIT 1", $aData['name']);
+    	$this->query($sQuery);
+    }
+
+    public function getModules()
+    {
+        $sQuery = $this->prepare("SELECT
+				`tsm`.`id` AS `id`,
+				`tm`.`name` AS `name`,
+				`tsm`.`title` AS `title`,
+				`tsm`.`uri` AS `uri`
+            FROM `" . $this->_sPrefix . "modules` AS `tm`
+            LEFT JOIN `sys_modules` AS `tsm` ON `tm`.`name`=`tsm`.`name`
+            ORDER BY `tsm`.`date`");
+
+        return $this->getAll($sQuery);
+    }
+}
+
+/** @} */

+ 119 - 0
modules/base/payment/classes/BxBaseModPaymentGridOrders.php

@@ -0,0 +1,119 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ * 
+ * @{
+ */
+
+class BxBaseModPaymentGridOrders extends BxTemplGrid
+{
+	protected $MODULE;
+	protected $_oModule;
+
+	protected $_sOrdersType;
+
+	protected $_sLangsPrefix;
+	protected $_sCurrencySign;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+        $this->_sCurrencySign = $this->_oModule->_oConfig->getCurrencySign();
+
+        $this->_sDefaultSortingOrder = 'DESC';
+
+	    $iSellerId = bx_get('seller_id');
+        if($iSellerId !== false)
+            $this->_aQueryAppend['seller_id'] = (int)$iSellerId;
+
+	    $iClientId = bx_get('client_id');
+        if($iClientId !== false)
+            $this->_aQueryAppend['client_id'] = (int)$iClientId;
+    }
+
+    public function addQueryParam($sKey, $sValue)
+    {
+    	if(empty($sKey) || !isset($sValue))
+    		return;
+
+		$this->_aQueryAppend[$sKey] = $sValue;
+    }
+
+    public function performActionViewOrder()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) 
+        	return echoJson(array());
+
+        $iId = (int)$aIds[0];
+
+        $sKey = 'order_' . $this->_sOrdersType . '_view';
+    	$sId = $this->_oModule->_oConfig->getHtmlIds($sKey);
+    	$sTitle = _t($this->_sLangsPrefix . 'grid_orders_popup_' . $sKey);
+    	$sContent = $this->_oModule->getObjectOrders()->getOrder($this->_sOrdersType, $iId);
+
+    	return echoJson(array('popup' => BxTemplFunctions::getInstance()->popupBox($sId, $sTitle, $sContent)));
+    }
+
+    public function performActionCancel()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) 
+        	return echoJson(array());
+
+		$oOrders = $this->_oModule->getObjectOrders();
+
+		$iAffected = 0;
+		$aAffected = array();
+		foreach($aIds as $iId)
+			if($oOrders->cancel($this->_sOrdersType, $iId)) {
+				$aAffected[] = $iId;
+            	$iAffected++;
+			}
+
+        echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aAffected) : array('msg' => _t($this->_sLangsPrefix . 'err_cannot_perform')));
+    }
+
+	protected function _getCellClientId($mixedValue, $sKey, $aField, $aRow)
+    {
+    	return parent::_getCellDefault($this->_toProfile($mixedValue), $sKey, $aField, $aRow);
+    }
+
+	protected function _getCellSellerId($mixedValue, $sKey, $aField, $aRow)
+    {
+    	return parent::_getCellDefault($this->_toProfile($mixedValue), $sKey, $aField, $aRow);
+    }
+
+	protected function _getCellAmount($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_sCurrencySign . $mixedValue, $sKey, $aField, $aRow);
+    }
+
+	protected function _getCellDate($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(bx_time_js($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _toProfile($mixedValue)
+    {
+    	$aProfile = $this->_oModule->getProfileInfo((int)$mixedValue);
+
+    	return $this->_oModule->_oTemplate->parseHtmlByName('profile_link.html', array(
+            'href' => $aProfile['link'],
+            'title' => bx_html_attribute($aProfile['name']),
+            'content' => $aProfile['name']
+        ));
+    }
+    
+    
+}
+
+/** @} */

+ 25 - 0
modules/base/payment/classes/BxBaseModPaymentJoin.php

@@ -0,0 +1,25 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentJoin extends BxDol
+{
+	protected $MODULE;
+	protected $_oModule;
+
+	function __construct()
+    {
+        parent::__construct();
+
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+    }
+}
+
+/** @} */

+ 185 - 0
modules/base/payment/classes/BxBaseModPaymentModule.php

@@ -0,0 +1,185 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentModule extends BxDolModule
+{
+	protected $_sLangsPrefix;
+
+	function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_oConfig->init($this->_oDb);
+
+        $this->_sLangsPrefix = $this->_oConfig->getPrefix('langs');
+    }
+
+	public function serviceUpdateDependentModules($sModule = 'all', $bInstall = true)
+    {
+    	$aModules = $sModule == 'all' ? $this->_oDb->getModulesBy(array('type' => 'modules')) : array($this->_oDb->getModuleByName($sModule));
+
+        foreach($aModules as $aModule) {
+        	$mixedData = $this->callGetPaymentData($aModule['name']);
+        	if($mixedData === false)
+        		continue;
+
+			$sMethodName = $bInstall ? 'insertModule' : 'deleteModule';
+			$this->_oDb->$sMethodName($mixedData);
+        }
+    }
+
+    public function serviceGetCurrencyInfo()
+    {
+        return array(
+            'sign' => $this->_oConfig->getCurrencySign(),
+            'code' => $this->_oConfig->getCurrencyCode()
+        );
+    }
+
+	public function serviceGetOption($sOption)
+    {
+    	return $this->_oDb->getParam($this->_oConfig->getPrefix('options') . $sOption);
+    }
+
+	public function serviceGetProviders($iVendorId, $sProvider = '')
+	{
+		$aVendorProviders = $this->_oDb->getVendorInfoProviders($iVendorId, $sProvider);
+
+		$aResult = array();
+		foreach($aVendorProviders as $aProvider) {
+			$aProvider['caption_cart'] = _t($this->_sLangsPrefix . 'txt_cart_' . $aProvider['name']);
+
+			$aResult[] = $aProvider;
+		}
+
+		return $aResult;
+	}
+
+	public function getVendorInfo($iUserId)
+    {
+        return array_merge($this->getProfileInfo($iUserId), array(
+        	'currency_code' => $this->_oConfig->getCurrencyCode(),
+			'currency_sign' => $this->_oConfig->getCurrencySign()
+        ));
+    }
+
+    public function getProfileId()
+    {
+    	return bx_get_logged_profile_id();
+    }
+
+	public function getProfileInfo($iUserId = 0)
+    {
+        $oProfile = $this->getObjectUser($iUserId);
+
+        return array(
+        	'id' => $iUserId,
+            'name' => $oProfile->getDisplayName(),
+            'link' => $oProfile->getUrl(),
+            'icon' => $oProfile->getIcon(),
+            'unit' => $oProfile->getUnit(),
+        	'active' => $oProfile->isActive(),
+        );
+    }
+    
+    public function getObjectUser($iUserId = 0)
+    {
+    	bx_import('BxDolProfile');
+        $oProfile = BxDolProfile::getInstance($iUserId);
+        if (!$oProfile) {
+            bx_import('BxDolProfileUndefined');
+            $oProfile = BxDolProfileUndefined::getInstance();
+        }
+
+        return $oProfile;
+    }
+
+	public function getObjectJoin()
+    {
+        $sClassName = $this->_oConfig->getClassPrefix() . 'Join';
+        if(!isset($GLOBALS['bxDolClasses'][$sClassName])) {
+        	bx_import('Join', $this->_aModule);
+            $GLOBALS['bxDolClasses'][$sClassName] = new $sClassName();
+        }
+
+        return $GLOBALS['bxDolClasses'][$sClassName];
+    }
+
+	public function getObjectCart()
+    {
+        $sClassName = $this->_oConfig->getClassPrefix() . 'Cart';
+        if(!isset($GLOBALS['bxDolClasses'][$sClassName])) {
+        	bx_import('Cart', $this->_aModule);
+            $GLOBALS['bxDolClasses'][$sClassName] = new $sClassName();
+        }
+
+        return $GLOBALS['bxDolClasses'][$sClassName];
+    }
+
+    public function getObjectOrders()
+    {
+    	$sClassName = $this->_oConfig->getClassPrefix() . 'Orders';
+        if(!isset($GLOBALS['bxDolClasses'][$sClassName])) {
+        	bx_import('Orders', $this->_aModule);
+            $GLOBALS['bxDolClasses'][$sClassName] = new $sClassName();
+        }
+
+        return $GLOBALS['bxDolClasses'][$sClassName];
+    }
+
+	public function getObjectDetails()
+    {
+    	$sClassName = $this->_oConfig->getClassPrefix() . 'Details';
+        if(!isset($GLOBALS['bxDolClasses'][$sClassName])) {
+        	bx_import('Details', $this->_aModule);
+            $GLOBALS['bxDolClasses'][$sClassName] = new $sClassName();
+        }
+
+        return $GLOBALS['bxDolClasses'][$sClassName];
+    }
+
+	public function getObjectProvider($sProvider, $mixedVendorId = BX_PAYMENT_EMPTY_ID)
+	{
+		$aProvider = is_numeric($mixedVendorId) && (int)$mixedVendorId != BX_PAYMENT_EMPTY_ID ? $this->_oDb->getVendorInfoProviders((int)$mixedVendorId, $sProvider) : $this->_oDb->getProviders($sProvider);
+        $sClassPath = !empty($aProvider['class_file']) ? BX_DIRECTORY_PATH_ROOT . $aProvider['class_file'] : $this->_oConfig->getClassPath() . $aProvider['class_name'] . '.php';
+        if(empty($aProvider) || !file_exists($sClassPath))
+        	return false;
+
+        require_once($sClassPath);
+        return new $aProvider['class_name']($aProvider);
+	}
+
+    public function callGetPaymentData($mixedModule)
+    {
+    	$sMethod = 'get_payment_data';
+		if(!BxDolRequest::serviceExists($mixedModule, $sMethod)) 
+			return false;
+
+		return BxDolService::call($mixedModule, $sMethod);
+    }
+
+    public function callGetCartItem($mixedModule, $aParams)
+    {
+    	return BxDolService::call($mixedModule, 'get_cart_item', $aParams);
+    }
+
+    public function callGetCartItems($mixedModule, $aParams)
+    {
+    	return BxDolService::call($mixedModule, 'get_cart_items', $aParams);
+    }
+
+    public function callRegisterCartItem($mixedModule, $aParams)
+    {
+    	return BxDolService::call($mixedModule, 'register_cart_item', $aParams);
+    }
+}
+
+/** @} */

+ 33 - 0
modules/base/payment/classes/BxBaseModPaymentOrders.php

@@ -0,0 +1,33 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentOrders extends BxDol
+{
+	protected $MODULE;
+	protected $_oModule;
+
+	function __construct()
+    {
+        parent::__construct();
+
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+    }
+
+	public function serviceGetOrdersLink()
+    {
+    	if(!$this->_oModule->isLogged())
+            return '';
+
+    	return $this->_oModule->_oConfig->getUrl('orders');
+    }
+}
+
+/** @} */

+ 73 - 0
modules/base/payment/classes/BxBaseModPaymentProvider.php

@@ -0,0 +1,73 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+interface iBxBaseModPaymentProvider
+{
+	public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0);
+    public function finalizeCheckout(&$aData);
+    public function checkoutFinished();
+}
+
+class BxBaseModPaymentProvider extends BxDol
+{
+	protected $MODULE;
+	protected $_oModule;
+
+	protected $_sLangsPrefix;
+
+    protected $_iId;
+    protected $_sName;
+    protected $_sCaption;
+    protected $_sPrefix;
+    protected $_aOptions;
+    protected $_bRedirectOnResult;
+
+    function __construct($aConfig)
+    {
+        parent::__construct();
+
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+
+        $this->_iId = (int)$aConfig['id'];
+        $this->_sName = $aConfig['name'];
+        $this->_sCaption = _t($aConfig['caption']);
+        $this->_sPrefix = $aConfig['option_prefix'];
+        $this->_aOptions = !empty($aConfig['options']) ? $aConfig['options'] : array();
+        $this->_bRedirectOnResult = false;
+    }
+
+    /**
+     * TODO: Check whether the method is needed or not. 
+     * Is used on success only.
+     */
+	public function needRedirect()
+    {
+        return $this->_bRedirectOnResult;
+    }
+
+    protected function getOptionsByPending($iPendingId)
+    {
+        $aPending = $this->_oModule->_oDb->getPending(array(
+            'type' => 'id',
+            'id' => (int)$iPendingId
+        ));
+        return $this->_oModule->_oDb->getOptions((int)$aPending['seller_id'], $this->_iId);
+    }
+
+    protected function getOption($sName)
+    {
+        return isset($this->_aOptions[$this->_sPrefix . $sName]) ? $this->_aOptions[$this->_sPrefix . $sName]['value'] : "";
+    }
+}
+
+/** @} */

+ 112 - 0
modules/base/payment/classes/BxBaseModPaymentTemplate.php

@@ -0,0 +1,112 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentTemplate extends BxBaseModGeneralTemplate
+{
+    function __construct($oConfig, $oDb)
+    {
+        parent::__construct($oConfig, $oDb);
+    }
+
+	public function displayJsCode($sType, $aParams = array(), $aRequestParams = array())
+    {
+    	$sJsClass = $this->_oConfig->getJsClass($sType);
+    	$sJsObject = $this->_oConfig->getJsObject($sType);
+
+    	$aParams = array_merge(array(
+    		'sActionUrl' => BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri(), 
+    		'sObjName' => $sJsObject,
+    		'sAnimationEffect' => $this->_oConfig->getAnimationEffect(),
+    		'iAnimationSpeed' => $this->_oConfig->getAnimationSpeed(),
+    		'aHtmlIds' => $this->_oConfig->getHtmlIds($sType),
+    		'oRequestParams' => $aRequestParams
+    	), $aParams);
+
+        return $this->_wrapInTagJsCode("var " . $sJsObject . " = new " . $sJsClass . "(" . json_encode($aParams) . ");");
+    }
+
+	public function displayPageCode(&$aParams)
+    {
+		check_logged();
+		$oTemplate = BxDolTemplate::getInstance();
+
+        $iIndex = isset($aParams['index']) ? (int)$aParams['index'] : BX_PAGE_DEFAULT;
+        $oTemplate->setPageNameIndex($iIndex);
+
+        if(isset($aParams['js']))
+			$oTemplate->addJs($aParams['js']);
+		if(isset($aParams['css']))
+			$oTemplate->addCss($aParams['css']);
+
+		if(isset($aParams['title']['page']))
+            $oTemplate->setPageHeader($aParams['title']['page']);
+        if(isset($aParams['title']['block']))
+         	$oTemplate->setPageParams(array('header_text' => $aParams['title']['block']));
+
+        if(isset($aParams['content']))
+            foreach($aParams['content'] as $sKey => $sValue)
+            	$oTemplate->setPageContent($sKey, $sValue);
+
+		$oTemplate->getPageCode();
+    }
+
+	public function displayPageCodeResponse($sMessage, $bWrap = true)
+    {
+		$aParams = array(
+            'title' => array(
+                'page' => _t($this->_sLangsPrefix . 'page_title_response')
+            ),
+            'content' => array(
+                'page_main_code' => $bWrap ? MsgBox(_t($sMessage)) : $sMessage
+            )
+        );
+        $this->displayPageCode($aParams);
+    }
+
+    public function displayPageCodeError($sMessage, $bWrap = true)
+    {
+		$aParams = array(
+            'title' => array(
+                'page' => _t($this->_sLangsPrefix . 'page_title_error')
+            ),
+            'content' => array(
+                'page_main_code' => $bWrap ? MsgBox(_t($sMessage)) : $sMessage
+            )
+        );
+        $this->displayPageCode($aParams);
+    }
+
+    public function displayPageCodeRedirect($sUrl, $aData = array(), $sMethod = 'post', $sMessage = '', $bWrap = true)
+    {
+    	if(empty($sMessage))
+    		$sMessage = $this->_sLangsPrefix . 'msg_redirecting';
+
+    	$aTmplVarsData = array();
+    	if(!empty($aData) && is_array($aData))
+    		foreach($aData as $sKey => $mixedValue)
+    			$aTmplVarsData[] = array('name' => bx_html_attribute($sKey), 'value' => bx_html_attribute($mixedValue));
+
+    	$aParams = array(
+    		'index' => BX_PAGE_CLEAR,
+    		'content' => array(
+                'page_main_code' => $this->parseHtmlByName('redirect.html', array(
+    				'content' => $bWrap ? MsgBox(_t($sMessage)) : $sMessage,
+    				'action' => $sUrl,
+    				'method' => $sMethod,
+    				'bx_repeat:items' => $aTmplVarsData
+    			))
+    		)
+    	);
+    	$this->displayPageCode($aParams);
+    }
+}
+
+/** @} */

+ 1 - 1
modules/boonex/accounts/classes/BxAccntConfig.php

@@ -45,7 +45,7 @@ class BxAccntConfig extends BxBaseModGeneralConfig
         	'alert' => $this->_sName,
         );
 
-        $this->_aJsClass = array(
+        $this->_aJsClasses = array(
         	'manage_tools' => 'BxAccntManageTools'
         );
 

+ 21 - 0
modules/boonex/air/data/template/system/scripts/BxTemplPaymentsServices.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    TridentCore Trident Core
+ * @{
+ */
+
+/**
+ * @see BxBasePaymentsServices
+ */
+class BxTemplPaymentsServices extends BxBasePaymentsServices
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+}
+
+/** @} */

+ 1 - 1
modules/boonex/albums/classes/BxAlbumsConfig.php

@@ -128,7 +128,7 @@ class BxAlbumsConfig extends BxBaseModTextConfig
             ),
         );
 
-        $this->_aJsClass = array(
+        $this->_aJsClasses = array(
         	'manage_tools' => 'BxAlbumsManageTools'
         );
 

+ 7 - 0
modules/boonex/english/data/langs/system/en.xml

@@ -79,6 +79,7 @@
 	<string name="_Reset"><![CDATA[Reset]]></string>
 	<string name="_Search"><![CDATA[Search]]></string>
 	<string name="_Section"><![CDATA[Section]]></string>
+	<string name="_Select_one"><![CDATA[Select one...]]></string>
 	<string name="_Select_all"><![CDATA[Select all]]></string>
 	<string name="_Show"><![CDATA[Show]]></string>
 	<string name="_Sorry, your IP been banned"><![CDATA[Sorry, your IP has been banned]]></string>
@@ -1148,6 +1149,8 @@
 	<string name="_adm_stg_cpt_option_sys_cache_memcache_port"><![CDATA[Memcached server port]]></string>
 	<string name="_adm_stg_cpt_option_sys_db_cache_enable"><![CDATA[Enable DB cache]]></string>
 	<string name="_adm_stg_cpt_option_sys_db_cache_engine"><![CDATA[DB cache engine (other than File option may require custom server setup)]]></string>
+	<string name="_adm_stg_cpt_option_sys_default_payment"><![CDATA[Payment module]]></string>
+	<string name="_adm_stg_err_option_sys_default_payment"><![CDATA[You need to install at least one payment processing module and activate it here by selecting from the list.]]></string>
 	<string name="_adm_stg_cpt_option_sys_format_date"><![CDATA[Date Format]]></string>
 	<string name="_adm_stg_cpt_option_sys_format_datetime"><![CDATA[Datetime Format]]></string>
 	<string name="_adm_stg_cpt_option_sys_format_time"><![CDATA[Time Format]]></string>
@@ -1816,6 +1819,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_menu_item_title_account_settings_info"><![CDATA[Account]]></string>
 	<string name="_sys_menu_item_title_account_settings_pwd"><![CDATA[Password]]></string>
 	<string name="_sys_menu_item_title_add_content"><![CDATA[Add...]]></string>
+	<string name="_sys_menu_item_title_cart"><![CDATA[Cart]]></string>
 	<string name="_sys_menu_item_title_cmts_item_delete"><![CDATA[Delete]]></string>
 	<string name="_sys_menu_item_title_cmts_item_edit"><![CDATA[Edit]]></string>
 	<string name="_sys_menu_item_title_cmts_item_reply"><![CDATA[Reply]]></string>
@@ -1824,6 +1828,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_menu_item_title_home"><![CDATA[Home]]></string>
 	<string name="_sys_menu_item_title_logout"><![CDATA[Sign out]]></string>
 	<string name="_sys_menu_item_title_more"><![CDATA[More]]></string>
+	<string name="_sys_menu_item_title_orders"><![CDATA[Orders]]></string>
 	<string name="_sys_menu_item_title_profile"><![CDATA[Profile]]></string>
 	<string name="_sys_menu_item_title_set_acl_level"><![CDATA[Set membership]]></string>
 	<string name="_sys_menu_item_title_studio"><![CDATA[Studio]]></string>
@@ -1839,6 +1844,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_menu_item_title_system_account_settings_info"><![CDATA[Account]]></string>
 	<string name="_sys_menu_item_title_system_account_settings_pwd"><![CDATA[Password]]></string>
 	<string name="_sys_menu_item_title_system_add_content"><![CDATA[Add Content]]></string>
+	<string name="_sys_menu_item_title_system_cart"><![CDATA[Cart]]></string>
 	<string name="_sys_menu_item_title_system_cmts_item_delete"><![CDATA[Delete]]></string>
 	<string name="_sys_menu_item_title_system_cmts_item_edit"><![CDATA[Edit]]></string>
 	<string name="_sys_menu_item_title_system_cmts_item_reply"><![CDATA[Reply]]></string>
@@ -1849,6 +1855,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_menu_item_title_system_logout"><![CDATA[Sign out]]></string>
 	<string name="_sys_menu_item_title_system_main_menu"><![CDATA[Main Menu]]></string>
 	<string name="_sys_menu_item_title_system_more"><![CDATA[More]]></string>
+	<string name="_sys_menu_item_title_system_orders"><![CDATA[Orders]]></string>
 	<string name="_sys_menu_item_title_system_profile"><![CDATA[Profile]]></string>
 	<string name="_sys_menu_item_title_system_search"><![CDATA[Search]]></string>
 	<string name="_sys_menu_item_title_system_set_acl_level"><![CDATA[Set membership]]></string>

+ 1 - 1
modules/boonex/invites/classes/BxInvConfig.php

@@ -53,7 +53,7 @@ class BxInvConfig extends BxBaseModGeneralConfig
         $this->_sRequestsEmail = '';
         $this->_bRegistrationByInvitation = true;
 
-        $this->_aJsClass = array(
+        $this->_aJsClasses = array(
         	'main' => 'BxInvMain',
         );
         $this->_aJsObjects = array(

+ 21 - 0
modules/boonex/lagoon/data/template/system/scripts/BxTemplPaymentsServices.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    TridentCore Trident Core
+ * @{
+ */
+
+/**
+ * @see BxBasePaymentsServices
+ */
+class BxTemplPaymentsServices extends BxBasePaymentsServices
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/market/classes/BxMarketAlertsResponse.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxMarketAlertsResponse extends BxBaseModTextAlertsResponse
+{
+    public function __construct()
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct();
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketCmtsSearchResult.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxMarketCmtsSearchResult extends BxBaseModGeneralCmtsSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+    	$this->sModule = 'bx_market';
+
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent['title'] = _t('_bx_market_page_block_title_browse_cmts');
+    }
+}
+
+/** @} */

+ 133 - 0
modules/boonex/market/classes/BxMarketConfig.php

@@ -0,0 +1,133 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxMarketConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'edit-product' => 'checkAllowedEdit',
+            'delete-product' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'file-text col-red3',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'products',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_TITLE' => 'title',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'product-text',
+        	'FIELD_PRICE' => 'price',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-product',
+            'URI_AUTHOR_ENTRIES' => 'products-author',
+            'URI_ADD_ENTRY' => 'create-product',
+        	'URI_EDIT_ENTRY' => 'edit-product',
+        	'URI_MANAGE_COMMON' => 'products-manage',
+
+            'URL_HOME' => 'page.php?i=products-home',
+            'URL_POPULAR' => 'page.php?i=products-popular',
+            'URL_UPDATED' => 'page.php?i=products-updated',
+        	'URL_MANAGE_COMMON' => 'page.php?i=products-manage',
+        	'URL_MANAGE_ADMINISTRATION' => 'page.php?i=products-administration',
+
+            // some params
+            'PARAM_CHARS_SUMMARY' => 'bx_market_summary_chars',
+            'PARAM_CHARS_SUMMARY_PLAIN' => 'bx_market_plain_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_market_rss_num',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_market_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_market_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_market_gallery',
+            'OBJECT_VIDEOS_TRANSCODERS' => array(),
+        	'OBJECT_REPORTS' => 'bx_market',
+            'OBJECT_VIEWS' => 'bx_market',
+            'OBJECT_VOTES' => 'bx_market',
+            'OBJECT_METATAGS' => 'bx_market',
+            'OBJECT_COMMENTS' => 'bx_market',
+            'OBJECT_PRIVACY_VIEW' => 'bx_market_allow_view_to',
+            'OBJECT_FORM_ENTRY' => 'bx_market',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_market_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_market_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_market_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_market_entry_delete',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_market_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_POPUP' => 'bx_market_view_popup', // actions menu popup on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_market_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_market_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_market_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'products-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_market_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_market_administration',
+        	'OBJECT_GRID_COMMON' => 'bx_market_common',
+            'OBJECT_UPLOADERS' => array('sys_simple', 'sys_html5'),
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_market_my' => array (
+                    'create-product' => 'checkAllowedAdd',
+                ),
+                'bx_market_view' => $aMenuItems2Methods,
+                'bx_market_view_popup' => $aMenuItems2Methods,
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_market_txt_sample_single',
+            	'txt_sample_comment_single' => '_bx_market_txt_sample_comment_single',
+            	'txt_sample_vote_single' => '_bx_market_txt_sample_vote_single',
+            	'grid_action_err_delete' => '_bx_market_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_market_grid_txt_account_manager',
+				'filter_item_active' => '_bx_market_grid_filter_item_title_adm_active',
+            	'filter_item_hidden' => '_bx_market_grid_filter_item_title_adm_hidden',
+            	'filter_item_select_one_filter1' => '_bx_market_grid_filter_item_title_adm_select_one_filter1',
+            	'menu_item_manage_my' => '_bx_market_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_market_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_market_txt_all_entries_by',
+            ),
+        );
+
+        $this->_aJsClass = array(
+        	'manage_tools' => 'BxMarketManageTools'
+        );
+
+        $this->_aJsObjects = array(
+        	'manage_tools' => 'oBxMarketManageTools'
+        );
+
+        $this->_aGridObjects = array(
+        	'common' => $this->CNF['OBJECT_GRID_COMMON'],
+        	'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        	
+        );
+    }
+}
+
+/** @} */

+ 23 - 0
modules/boonex/market/classes/BxMarketDb.php

@@ -0,0 +1,23 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/*
+ * Module database queries
+ */
+class BxMarketDb extends BxBaseModTextDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketFormEntry.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit entry form
+ */
+class BxMarketFormEntry extends BxBaseModTextFormEntry
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($aInfo, $oTemplate);
+    }
+}
+
+/** @} */

+ 23 - 0
modules/boonex/market/classes/BxMarketFormsEntryHelper.php

@@ -0,0 +1,23 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Entry forms helper functions
+ */
+class BxMarketFormsEntryHelper extends BxBaseModTextFormsEntryHelper
+{
+    public function __construct($oModule)
+    {
+        parent::__construct($oModule);
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/market/classes/BxMarketGridAdministration.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ * 
+ * @{
+ */
+
+class BxMarketGridAdministration extends BxBaseModTextGridAdministration
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_market';
+        parent::__construct ($aOptions, $oTemplate);
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/market/classes/BxMarketGridCommon.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ * 
+ * @{
+ */
+
+class BxMarketGridCommon extends BxBaseModTextGridCommon
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_market';
+        parent::__construct ($aOptions, $oTemplate);
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketMenu.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * General class for module menu.
+ */
+class BxMarketMenu extends BxBaseModTextMenu
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 25 - 0
modules/boonex/market/classes/BxMarketMenuManageTools.php

@@ -0,0 +1,25 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * 'Market manage tools' menu.
+ */
+class BxMarketMenuManageTools extends BxBaseModTextMenuManageTools
+{
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketMenuView.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * View entry menu
+ */
+class BxMarketMenuView extends BxBaseModTextMenuView
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketMenuViewActions.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Actions popup menu.
+ */
+class BxMarketMenuViewActions extends BxBaseModTextMenuViewActions
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 23 - 0
modules/boonex/market/classes/BxMarketModule.php

@@ -0,0 +1,23 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Market module
+ */
+class BxMarketModule extends BxBaseModTextModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketPageAuthor.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Profile's entries page.
+ */
+class BxMarketPageAuthor extends BxBaseModTextPageAuthor
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketPageBrowse.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Browse entries pages.
+ */
+class BxMarketPageBrowse extends BxBaseModTextPageBrowse
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/market/classes/BxMarketPageEntry.php

@@ -0,0 +1,24 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/**
+ * Entry create/edit pages
+ */
+class BxMarketPageEntry extends BxBaseModTextPageEntry
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 126 - 0
modules/boonex/market/classes/BxMarketSearchResult.php

@@ -0,0 +1,126 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxMarketSearchResult extends BxBaseModTextSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_market',
+            'module_name' => 'bx_market',
+            'object_metatags' => 'bx_market',
+            'title' => _t('_bx_market_page_title_browse'),
+            'table' => 'bx_market_products',
+            'ownFields' => array('id', 'title', 'text', 'thumb', 'author', 'added'),
+            'searchFields' => array('title', 'text'),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+        		'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_market_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'title',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'text',
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_market_filter';
+        $this->oModule = $this->getMain();
+
+        $oProfileAuthor = null;
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        switch ($sMode) {
+
+            case 'author':
+                $oProfileAuthor = BxDolProfile::getInstance((int)$aParams['author']);
+                if (!$oProfileAuthor) {
+                    $this->isError = true;
+                    break;
+                }
+
+                $this->aCurrent['restriction']['author']['value'] = $oProfileAuthor->id();
+
+                $this->sBrowseUrl = 'page.php?i=' . $CNF['URI_AUTHOR_ENTRIES'] . '&profile_id={profile_id}';
+                $this->aCurrent['title'] = _t('_bx_market_page_title_browse_by_author');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode . '/' . $oProfileAuthor->id();
+                break;
+
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_market_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_market_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_market_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_market');
+                $this->aCurrent['paginate']['perPage'] = 3;
+                unset($this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+    }
+
+    function getAlterOrder()
+    {
+        $aSql = array();
+        switch ($this->aCurrent['sorting']) {
+            case 'last':
+                $aSql['order'] = ' ORDER BY `bx_market_products`.`added` DESC';
+                break;
+            case 'updated':
+                $aSql['order'] = ' ORDER BY `bx_market_products`.`changed` DESC';
+                break;
+            case 'popular':
+                $aSql['order'] = ' ORDER BY `bx_market_products`.`views` DESC';
+                break;
+        }
+        return $aSql;
+    }
+}
+
+/** @} */

+ 44 - 0
modules/boonex/market/classes/BxMarketTemplate.php

@@ -0,0 +1,44 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxMarketTemplate extends BxBaseModTextTemplate
+{
+    /**
+     * Constructor
+     */
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_market';
+        parent::__construct($oConfig, $oDb);
+    }
+
+    function getAuthorAddon ($aData, $oProfile)
+    {
+        $s = parent::getAuthorAddon ($aData, $oProfile);
+        if (!$aData['cat'])
+            return $s;
+
+        if (!($oCat = BxTemplCategory::getObjectInstance('bx_market_cats')))
+            return $s;
+
+        if (!($aCats = BxDolForm::getDataItems('bx_market_cats')) || !isset($aCats[$aData['cat']]))
+            return $s;
+
+        $s = _t('_bx_market_txt_category_link', $oCat->getCategoryUrl($aData['cat']), $aCats[$aData['cat']]) . '<br />' . $s;
+
+        return $s;
+    }
+}
+
+/** @} */

+ 116 - 0
modules/boonex/market/install/config.php

@@ -0,0 +1,116 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_market',
+    'title' => 'Market',
+    'note' => 'Market module.',
+    'version' => '8.0.0.DEV',
+    'vendor' => 'BoonEx',
+	'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '8.0.x'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/market/',
+    'home_uri' => 'market',
+
+    'db_prefix' => 'bx_market_',
+    'class_prefix' => 'BxMarket',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Market',
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu'
+    ),
+
+    /**
+     * Storages.
+     */
+    'storages' => array(
+    	'bx_market_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_market_preview',
+        'bx_market_gallery',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_storages' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable_success' => array(
+    	'process_menu_triggers' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+    	'unregister_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'register_transcoders' => 1,
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Connections Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 20 - 0
modules/boonex/market/install/installer.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Market Market
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxMarketInstaller extends BxBaseModTextInstaller
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}
+
+/** @} */

+ 217 - 0
modules/boonex/market/install/langs/en.xml

@@ -0,0 +1,217 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+	<string name="_bx_market"><![CDATA[Market]]></string>
+	<string name="_bx_market_cmts"><![CDATA[Market's Comments]]></string>
+
+	<string name="_bx_market_option_summary_chars"><![CDATA[Number of characters in auto-cropped product summary]]></string>
+	<string name="_bx_market_option_plain_summary_chars"><![CDATA[Number of characters in plain product description when product hasn't thumb]]></string>
+	<string name="_bx_market_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+	<string name="_bx_market_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+
+	<string name="_bx_market_form_entry"><![CDATA[Market]]></string>
+	<string name="_bx_market_form_entry_display_add"><![CDATA[Add Product]]></string>
+	<string name="_bx_market_form_entry_display_edit"><![CDATA[Edit Product]]></string>
+	<string name="_bx_market_form_entry_display_delete"><![CDATA[Delete Product]]></string>
+	<string name="_bx_market_form_entry_display_view"><![CDATA[View Product]]></string>
+	<string name="_bx_market_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_market_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_market_form_entry_input_sys_do_publish"><![CDATA[Publish]]></string>
+	<string name="_bx_market_form_entry_input_do_publish"><![CDATA[Publish]]></string>
+	<string name="_bx_market_form_entry_input_sys_title"><![CDATA[Title]]></string>
+	<string name="_bx_market_form_entry_input_title"><![CDATA[Title]]></string>
+	<string name="_bx_market_form_entry_input_title_err"><![CDATA[Title is essential. Please, fill in this field]]></string>
+	<string name="_bx_market_form_entry_input_sys_cat"><![CDATA[Category]]></string>
+	<string name="_bx_market_form_entry_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_market_form_entry_input_cat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_market_form_entry_input_sys_price"><![CDATA[Monthly price]]></string>
+	<string name="_bx_market_form_entry_input_price"><![CDATA[Monthly price]]></string>
+    <string name="_bx_market_form_entry_input_price_err"><![CDATA[Please select price]]></string>
+	<string name="_bx_market_form_entry_input_sys_text"><![CDATA[Text]]></string>
+	<string name="_bx_market_form_entry_input_text"><![CDATA[Text]]></string>
+	<string name="_bx_market_form_entry_input_text_err"><![CDATA[Text field can't be empty]]></string>
+	<string name="_bx_market_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+	<string name="_bx_market_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this product]]></string>
+	<string name="_bx_market_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+	<string name="_bx_market_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the product]]></string>
+	<string name="_bx_market_form_entry_input_sys_pictures"><![CDATA[Pictures]]></string>
+	<string name="_bx_market_form_entry_input_pictures"><![CDATA[Pictures]]></string>
+    <string name="_bx_market_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_market_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+
+	<string name="_bx_market_acl_action_create_entry"><![CDATA[Create Product]]></string>
+	<string name="_bx_market_acl_action_delete_entry"><![CDATA[Delete Product]]></string>
+	<string name="_bx_market_acl_action_view_entry"><![CDATA[View Product]]></string>
+	<string name="_bx_market_acl_action_set_thumb"><![CDATA[Set Product Thumbnail]]></string>
+	<string name="_bx_market_acl_action_edit_any_entry"><![CDATA[Edit Any Product]]></string>
+
+	<string name="_bx_market_page_title_sys_create_entry"><![CDATA[New Product]]></string>
+	<string name="_bx_market_page_title_create_entry"><![CDATA[New Product]]></string>
+	<string name="_bx_market_page_block_title_create_entry"><![CDATA[New Product]]></string>
+	<string name="_bx_market_page_title_sys_edit_entry"><![CDATA[Edit Product]]></string>
+	<string name="_bx_market_page_title_edit_entry"><![CDATA[Edit Product]]></string>
+	<string name="_bx_market_page_block_title_edit_entry"><![CDATA[Edit Product]]></string>
+    <string name="_bx_market_page_title_sys_delete_entry"><![CDATA[Delete Product]]></string>
+    <string name="_bx_market_page_title_delete_entry"><![CDATA[Delete Product]]></string>
+    <string name="_bx_market_page_block_title_delete_entry"><![CDATA[Delete Product]]></string>
+	<string name="_bx_market_page_title_sys_view_entry"><![CDATA[View Product]]></string>
+	<string name="_bx_market_page_title_view_entry"><![CDATA[{title}]]></string>
+	<string name="_bx_market_page_block_title_entry_text"><![CDATA[Product Text]]></string>
+	<string name="_bx_market_page_title_browse"><![CDATA[Market]]></string>
+	<string name="_bx_market_page_title_search_results"><![CDATA[Products matching "{0}"]]></string>
+	<string name="_bx_market_page_title_browse_by_author"><![CDATA[Products of {display_name}]]></string>
+    <string name="_bx_market_page_title_browse_recent"><![CDATA[Recent Products]]></string>
+    <string name="_bx_market_page_title_browse_popular"><![CDATA[Popular Products]]></string>
+    <string name="_bx_market_page_title_browse_updated"><![CDATA[Updated Products]]></string>
+    <string name="_bx_market_page_title_sys_home"><![CDATA[Market Home]]></string>
+    <string name="_bx_market_page_title_home"><![CDATA[Market]]></string>
+    <string name="_bx_market_page_block_title_recent_entries"><![CDATA[Recent Products (Gallery View)]]></string>
+    <string name="_bx_market_page_block_title_recent_entries_view_extended"><![CDATA[Recent Products]]></string>
+    <string name="_bx_market_page_block_title_recent_entries_view_full"><![CDATA[Recent Products (Full View)]]></string>
+    <string name="_bx_market_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_market_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_market_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_market_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_market_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_market_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_market_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_market_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_market_page_title_sys_entries_popular"><![CDATA[Popular Products]]></string>
+    <string name="_bx_market_page_title_entries_popular"><![CDATA[Popular Products]]></string>
+    <string name="_bx_market_page_title_sys_entries_updated"><![CDATA[Updated Products]]></string>
+    <string name="_bx_market_page_title_entries_updated"><![CDATA[Updated Products]]></string>
+    <string name="_bx_market_page_block_title_popular_entries"><![CDATA[Popular Products]]></string>
+    <string name="_bx_market_page_block_title_popular_entries_view_extended"><![CDATA[Popular Products (Extended View)]]></string>
+    <string name="_bx_market_page_block_title_popular_entries_view_full"><![CDATA[Popular Products (Full View)]]></string>
+    <string name="_bx_market_page_block_title_updated_entries"><![CDATA[Updated Products]]></string>
+    <string name="_bx_market_page_title_sys_view_entry_comments"><![CDATA[Product Comments]]></string>
+    <string name="_bx_market_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_market_page_title_sys_entries_of_author"><![CDATA[Products of author]]></string>
+    <string name="_bx_market_page_title_entries_of_author"><![CDATA[Products by {display_name}]]></string>
+    <string name="_bx_market_page_block_title_entries_of_author"><![CDATA[Products by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_market_page_block_title_sys_entries_of_author"><![CDATA[Products of author]]></string>   
+    <string name="_bx_market_page_block_title_entries_actions"><![CDATA[Products actions]]></string>
+    <string name="_bx_market_page_block_title_browse_cmts"><![CDATA[Products' Comments]]></string>
+	<string name="_bx_market_page_title_sys_manage"><![CDATA[Manage Own Products]]></string>
+	<string name="_bx_market_page_title_sys_manage_administration"><![CDATA[Manage All Products]]></string>
+	<string name="_bx_market_page_title_manage"><![CDATA[Manage Products]]></string>
+	<string name="_bx_market_page_block_title_system_manage"><![CDATA[Manage Own Products]]></string>
+	<string name="_bx_market_page_block_title_system_manage_administration"><![CDATA[Manage All Products]]></string>
+	<string name="_bx_market_page_block_title_manage"><![CDATA[Manage Products]]></string>    
+	<string name="_bx_market_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+	<string name="_bx_market_page_block_title_cats"><![CDATA[Products Categories]]></string>
+	<string name="_bx_market_page_title_sys_entries_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_market_page_title_entries_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_market_page_block_title_categories_entries"><![CDATA[Products]]></string>
+    
+
+    <string name="_bx_market_menu_set_title_view_entry"><![CDATA[Product Actions]]></string>
+    <string name="_bx_market_menu_title_view_entry"><![CDATA[Product Actions]]></string>
+    <string name="_bx_market_menu_title_view_entry_popup"><![CDATA[Product Popup Actions]]></string>
+    <string name="_bx_market_menu_title_submenu"><![CDATA[Market Submenu]]></string>
+    <string name="_bx_market_menu_set_title_submenu"><![CDATA[Market Submenu]]></string>
+    <string name="_bx_market_menu_item_title_system_create_entry"><![CDATA[New Product]]></string>
+    <string name="_bx_market_menu_item_title_create_entry"><![CDATA[New Product]]></string>
+    <string name="_bx_market_menu_item_title_system_edit_entry"><![CDATA[Edit Product]]></string>
+    <string name="_bx_market_menu_item_title_edit_entry"><![CDATA[Edit Product]]></string>
+    <string name="_bx_market_menu_item_title_system_delete_entry"><![CDATA[Delete Product]]></string>
+    <string name="_bx_market_menu_item_title_delete_entry"><![CDATA[Delete Product]]></string>
+    <string name="_bx_market_menu_item_title_system_view_entry"><![CDATA[View Product]]></string>
+    <string name="_bx_market_menu_item_title_system_entries_home"><![CDATA[Market]]></string>
+    <string name="_bx_market_menu_item_title_entries_home"><![CDATA[Market]]></string>
+    <string name="_bx_market_menu_item_title_system_entries_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_market_menu_item_title_entries_categories"><![CDATA[Categories]]></string>
+    <string name="_bx_market_menu_item_title_system_entries_public"><![CDATA[Storefront]]></string>
+    <string name="_bx_market_menu_item_title_entries_public"><![CDATA[Storefront]]></string>
+    <string name="_bx_market_menu_item_title_system_entries_manage"><![CDATA[Manage Products]]></string>
+    <string name="_bx_market_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_market_menu_item_title_system_entries_popular"><![CDATA[Popular Products]]></string>
+    <string name="_bx_market_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_market_menu_title_view_entry_submenu"><![CDATA[View Product Submenu]]></string>
+    <string name="_bx_market_menu_set_title_view_entry_submenu"><![CDATA[View Product Submenu]]></string>
+    <string name="_bx_market_menu_item_title_view_entry_submenu_entry"><![CDATA[Product]]></string>
+    <string name="_bx_market_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_market_menu_item_title_system_view_entry_comments"><![CDATA[Product Comments]]></string>
+    <string name="_bx_market_menu_item_title_system_view_entries_author"><![CDATA[Products]]></string>
+    <string name="_bx_market_menu_item_title_view_entries_author"><![CDATA[Products]]></string>
+    <string name="_bx_market_menu_title_entries_my"><![CDATA[My Products Action Menu]]></string>
+    <string name="_bx_market_menu_set_title_entries_my"><![CDATA[My Products Menu]]></string>
+	<string name="_bx_market_menu_item_title_system_manage_my_products"><![CDATA[My products]]></string>
+    <string name="_bx_market_menu_item_title_manage_my_products"><![CDATA[{addon} products]]></string>
+    <string name="_bx_market_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_market_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_market_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_market_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+	<string name="_bx_market_menu_item_title_system_admt_products"><![CDATA[Products]]></string>
+	<string name="_bx_market_menu_item_title_admt_products"><![CDATA[Products - {addon} hidden]]></string>
+	<string name="_bx_market_menu_item_title_manage_my"><![CDATA[My Products]]></string>
+	<string name="_bx_market_menu_item_title_manage_all"><![CDATA[All Products]]></string>
+
+	<string name="_bx_market_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+	<string name="_bx_market_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+	<string name="_bx_market_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+	<string name="_bx_market_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_market_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_market_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_market_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_market_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_market_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_market_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_market_grid_action_err_delete"><![CDATA[Cannot delete the selected product(s).]]></string>
+    <string name="_bx_market_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_market_pre_lists_cats"><![CDATA[Product categories]]></string>
+    <string name="_bx_market_cat_administration"><![CDATA[Administration]]></string>
+    <string name="_bx_market_cat_adult"><![CDATA[Adult]]></string>
+    <string name="_bx_market_cat_advertisement"><![CDATA[Advertisement]]></string>
+    <string name="_bx_market_cat_affiliates"><![CDATA[Affiliates]]></string>
+    <string name="_bx_market_cat_authentication"><![CDATA[Authentication]]></string>
+    <string name="_bx_market_cat_calendars"><![CDATA[Calendars]]></string>
+    <string name="_bx_market_cat_communication"><![CDATA[Communication]]></string>
+    <string name="_bx_market_cat_content"><![CDATA[Content]]></string>
+    <string name="_bx_market_cat_conversion"><![CDATA[Conversion]]></string>
+    <string name="_bx_market_cat_core_changes"><![CDATA[Core Changes]]></string>
+    <string name="_bx_market_cat_dating"><![CDATA[Dating]]></string>
+    <string name="_bx_market_cat_documentation"><![CDATA[Documentation]]></string>
+    <string name="_bx_market_cat_ecommerce"><![CDATA[eCommerce]]></string>
+    <string name="_bx_market_cat_events"><![CDATA[Events]]></string>
+    <string name="_bx_market_cat_feedback"><![CDATA[Feedback]]></string>
+    <string name="_bx_market_cat_flash"><![CDATA[Flash]]></string>
+    <string name="_bx_market_cat_games"><![CDATA[Games]]></string>
+    <string name="_bx_market_cat_graphics"><![CDATA[Graphics]]></string>
+    <string name="_bx_market_cat_hosting"><![CDATA[Hosting]]></string>
+    <string name="_bx_market_cat_integrations"><![CDATA[Integrations]]></string>
+    <string name="_bx_market_cat_location"><![CDATA[Location]]></string>
+    <string name="_bx_market_cat_management"><![CDATA[Management]]></string>
+    <string name="_bx_market_cat_mobile"><![CDATA[Mobile]]></string>
+    <string name="_bx_market_cat_multimedia"><![CDATA[Multimedia]]></string>
+    <string name="_bx_market_cat_music"><![CDATA[Music]]></string>
+    <string name="_bx_market_cat_navigation"><![CDATA[Navigation]]></string>
+    <string name="_bx_market_cat_other"><![CDATA[Other]]></string>
+    <string name="_bx_market_cat_performance"><![CDATA[Performance]]></string>
+    <string name="_bx_market_cat_photos"><![CDATA[Photos]]></string>
+    <string name="_bx_market_cat_search"><![CDATA[Search]]></string>
+    <string name="_bx_market_cat_security"><![CDATA[Security]]></string>
+    <string name="_bx_market_cat_services"><![CDATA[Services]]></string>
+    <string name="_bx_market_cat_social"><![CDATA[Social]]></string>
+    <string name="_bx_market_cat_spam_prevention"><![CDATA[Spam Prevention]]></string>
+    <string name="_bx_market_cat_statistics"><![CDATA[Statistics]]></string>
+    <string name="_bx_market_cat_templates"><![CDATA[Templates]]></string>
+    <string name="_bx_market_cat_tools"><![CDATA[Tools]]></string>
+    <string name="_bx_market_cat_translations"><![CDATA[Translations]]></string>
+    <string name="_bx_market_cat_video"><![CDATA[Video]]></string>
+
+    <string name="_bx_market_pre_lists_prices"><![CDATA[Product prices]]></string>
+    <string name="_bx_market_cat_price_1"><![CDATA[1]]></string>
+    <string name="_bx_market_cat_price_2"><![CDATA[2]]></string>
+    <string name="_bx_market_cat_price_3"><![CDATA[3]]></string>
+    <string name="_bx_market_cat_price_4"><![CDATA[4]]></string>
+    <string name="_bx_market_cat_price_5"><![CDATA[5]]></string>
+
+
+    <string name="_bx_market_txt_all_entries_by"><![CDATA[<a href="{0}">All Products by {1} ({2})</a>]]></string>
+    <string name="_bx_market_txt_category_link"><![CDATA[<a href="{0}">{1}</a> category]]></string>
+    <string name="_bx_market_txt_sample_single"><![CDATA[product]]></string>
+    <string name="_bx_market_txt_sample_comment_single"><![CDATA[product's comment]]></string>
+    <string name="_bx_market_txt_sample_vote_single"><![CDATA[product's vote]]></string>
+</resources>

+ 42 - 0
modules/boonex/market/install/sql/disable.sql

@@ -0,0 +1,42 @@
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_market' LIMIT 1);
+SET @iCategId = (SELECT `ID` FROM `sys_options_categories` WHERE `type_id` = @iTypeId LIMIT 1);
+DELETE FROM `sys_options` WHERE `category_id` = @iCategId;
+DELETE FROM `sys_options_categories` WHERE `type_id` = @iTypeId;
+DELETE FROM `sys_options_types` WHERE `id` = @iTypeId;
+
+-- PAGES
+DELETE FROM `sys_objects_page` WHERE `module` = 'bx_market';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_market' OR `object` IN('bx_market_create_entry', 'bx_market_edit_entry', 'bx_market_delete_entry', 'bx_market_view_entry', 'bx_market_view_entry_comments', 'bx_market_home', 'bx_market_categories', 'bx_market_popular', 'bx_market_updated', 'bx_market_author');
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_market';
+DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_market';
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_market' OR `set_name` IN('bx_market_view', 'bx_market_submenu', 'bx_market_view_submenu', 'bx_market_my');
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object` = 'bx_market_allow_view_to';
+
+-- ACL
+DELETE `sys_acl_actions`, `sys_acl_matrix` FROM `sys_acl_actions`, `sys_acl_matrix` WHERE `sys_acl_matrix`.`IDAction` = `sys_acl_actions`.`ID` AND `sys_acl_actions`.`Module` = 'bx_market';
+DELETE FROM `sys_acl_actions` WHERE `Module` = 'bx_market';
+
+-- SEARCH
+DELETE FROM `sys_objects_search` WHERE `ObjectName` IN ('bx_market', 'bx_market_cmts');
+
+-- METATAGS
+DELETE FROM `sys_objects_metatags` WHERE `object` = 'bx_market';
+
+-- CATEGORY
+DELETE FROM `sys_objects_category` WHERE `object` = 'bx_market_cats';
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_market_administration', 'bx_market_common');
+DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_market_administration', 'bx_market_common');
+DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_market_administration', 'bx_market_common');
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_market' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;

+ 346 - 0
modules/boonex/market/install/sql/enable.sql

@@ -0,0 +1,346 @@
+
+-- SETTINGS
+SET @iTypeOrder = (SELECT MAX(`order`) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', 'bx_market', '_bx_market', 'bx_market@modules/boonex/market/|std-mi.png', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_market', '_bx_market', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_market_summary_chars', '700', @iCategId, '_bx_market_option_summary_chars', 'digit', '', '', '', 1),
+('bx_market_plain_summary_chars', '240', @iCategId, '_bx_market_option_plain_summary_chars', 'digit', '', '', '', 2),
+('bx_market_per_page_browse', '12', @iCategId, '_bx_market_option_per_page_browse', 'digit', '', '', '', 10),
+('bx_market_rss_num', '10', @iCategId, '_bx_market_option_rss_num', 'digit', '', '', '', 20);
+
+-- PAGE: create entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_create_entry', '_bx_market_page_title_sys_create_entry', '_bx_market_page_title_create_entry', 'bx_market', 5, 2147483647, 1, 'create-product', 'page.php?i=create-product', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_market_create_entry', 1, 'bx_market', '_bx_market_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_market";s:6:"method";s:13:"entity_create";}', 0, 1, 1);
+
+
+-- PAGE: edit entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_edit_entry', '_bx_market_page_title_sys_edit_entry', '_bx_market_page_title_edit_entry', 'bx_market', 5, 2147483647, 1, 'edit-product', '', '', '', '', 0, 1, 0, 'BxMarketPageEntry', 'modules/boonex/market/classes/BxMarketPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_market_edit_entry', 1, 'bx_market', '_bx_market_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_market";s:6:"method";s:11:"entity_edit";}', 0, 0, 0);
+
+
+-- PAGE: delete entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_delete_entry', '_bx_market_page_title_sys_delete_entry', '_bx_market_page_title_delete_entry', 'bx_market', 5, 2147483647, 1, 'delete-product', '', '', '', '', 0, 1, 0, 'BxMarketPageEntry', 'modules/boonex/market/classes/BxMarketPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_market_delete_entry', 1, 'bx_market', '_bx_market_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_market";s:6:"method";s:13:"entity_delete";}', 0, 0, 0);
+
+
+-- PAGE: view entry
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_view_entry', '_bx_market_page_title_sys_view_entry', '_bx_market_page_title_view_entry', 'bx_market', 10, 2147483647, 1, 'view-product', '', '', '', '', 0, 1, 0, 'BxMarketPageEntry', 'modules/boonex/market/classes/BxMarketPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_market_view_entry', 1, 'bx_market', '', '_bx_market_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 0),
+('bx_market_view_entry', 2, 'bx_market', '', '_bx_market_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:13:\"entity_author\";}', 0, 0, 1, 0),
+('bx_market_view_entry', 4, 'bx_market', '', '_bx_market_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:18:\"entity_all_actions\";}', 0, 0, 1, 0),
+('bx_market_view_entry', 3, 'bx_market', '', '_bx_market_page_block_title_entry_location', 3, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:13:\"locations_map\";s:6:\"params\";a:2:{i:0;s:9:\"bx_market\";i:1;s:4:\"{id}\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 0, 1, 0),
+('bx_market_view_entry', 3, 'bx_market', '', '_bx_market_page_block_title_entry_location', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:15:\"entity_location\";}', 0, 0, 0, 1),
+('bx_market_view_entry', 4, 'bx_market', '', '_bx_market_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:14:\"entity_actions\";}', 0, 0, 0, 1),
+('bx_market_view_entry', 4, 'bx_market', '', '_bx_market_page_block_title_entry_social_sharing', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:21:\"entity_social_sharing\";}', 0, 0, 0, 2),
+('bx_market_view_entry', 4, 'bx_market', '', '_bx_market_page_block_title_entry_attachments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:18:\"entity_attachments\";}', 0, 0, 0, 3),
+('bx_market_view_entry', 4, 'bx_market', '', '_bx_market_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 1, 4);
+
+
+-- PAGE: view entry comments
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_view_entry_comments', '_bx_market_page_title_sys_view_entry_comments', '_bx_market_page_title_view_entry_comments', 'bx_market', 5, 2147483647, 1, 'view-product-comments', '', '', '', '', 0, 1, 0, 'BxMarketPageEntry', 'modules/boonex/market/classes/BxMarketPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_market_view_entry_comments', 1, 'bx_market', '_bx_market_page_block_title_entry_comments', '_bx_market_page_block_title_entry_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 1);
+
+
+-- PAGE: categories
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_categories', '_bx_market_page_title_sys_entries_categories', '_bx_market_page_title_entries_categories', 'bx_market', 1, 2147483647, 1, 'products-categories', 'page.php?i=products-categories', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_market_categories', 1, 'bx_market', '_bx_market_page_block_title_cats', 11, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:15:\"categories_list\";s:6:\"params\";a:2:{i:0;s:14:\"bx_market_cats\";i:1;b:0;}s:5:\"class\";s:20:\"TemplServiceCategory\";}', 0, 1, 1),
+('bx_market_categories', 2, 'bx_market', '_bx_market_page_block_title_categories_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:15:"browse_category";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1);
+
+
+-- PAGE: popular entries
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_popular', '_bx_market_page_title_sys_entries_popular', '_bx_market_page_title_entries_popular', 'bx_market', 5, 2147483647, 1, 'products-popular', 'page.php?i=products-popular', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_market_popular', 1, 'bx_market', '_bx_market_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:14:"browse_popular";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+
+-- PAGE: recently updated entries
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_updated', '_bx_market_page_title_sys_entries_updated', '_bx_market_page_title_entries_updated', 'bx_market', 5, 2147483647, 1, 'products-updated', 'page.php?i=products-updated', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_market_updated', 1, 'bx_market', '_bx_market_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:14:"browse_updated";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+
+-- PAGE: entries of author
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_author', 'products-author', '_bx_market_page_title_sys_entries_of_author', '_bx_market_page_title_entries_of_author', 'bx_market', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxMarketPageAuthor', 'modules/boonex/market/classes/BxMarketPageAuthor.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_market_author', 1, 'bx_market', '', '_bx_market_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:18:\"my_entries_actions\";}', 0, 0, 1, 0),
+('bx_market_author', 1, 'bx_market', '_bx_market_page_block_title_sys_entries_of_author', '_bx_market_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:13:\"browse_author\";}', 0, 0, 1, 1);
+
+-- PAGE: module home
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_home', 'products-home', '_bx_market_page_title_sys_home', '_bx_market_page_title_home', 'bx_market', 1, 2147483647, 1, 'page.php?i=products-home', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_market_home', 1, 'bx_market', '', '_bx_market_page_block_title_popular_keywords', 11, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:14:\"keywords_cloud\";s:6:\"params\";a:2:{i:0;s:9:\"bx_market\";i:1;s:9:\"bx_market\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 1, 1, 0),
+('bx_market_home', 1, 'bx_market', '', '_bx_market_page_block_title_cats', 11, 2147483647, 'service', 'a:4:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:15:\"categories_list\";s:6:\"params\";a:2:{i:0;s:14:\"bx_market_cats\";i:1;b:0;}s:5:\"class\";s:20:\"TemplServiceCategory\";}', 0, 1, 1, 1),
+('bx_market_home', 2, 'bx_market', '', '_bx_market_page_block_title_recent_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 1, 0),
+('bx_market_home', 2, 'bx_market', '', '_bx_market_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 1, 1);
+
+-- PAGE: module manage own
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_manage', '_bx_market_page_title_sys_manage', '_bx_market_page_title_manage', 'bx_market', 5, 2147483647, 1, 'products-manage', 'page.php?i=products-manage', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_market_manage', 1, 'bx_market', '_bx_market_page_block_title_system_manage', '_bx_market_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:12:\"manage_tools\";}}', 0, 1, 0);
+
+-- PAGE: module manage all
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_administration', '_bx_market_page_title_sys_manage_administration', '_bx_market_page_title_manage', 'bx_market', 5, 192, 1, 'products-administration', 'page.php?i=products-administration', '', '', '', 0, 1, 0, 'BxMarketPageBrowse', 'modules/boonex/market/classes/BxMarketPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_market_administration', 1, 'bx_market', '_bx_market_page_block_title_system_manage_administration', '_bx_market_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
+
+-- PAGE: add block to homepage
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = 'sys_home' AND `cell_id` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('sys_home', 1, 'bx_market', '_bx_market_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:13:\"browse_public\";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1);
+
+-- PAGE: service blocks
+SET @iBlockOrder = (SELECT `order` FROM `sys_pages_blocks` WHERE `object` = '' AND `cell_id` = 0 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('', 0, 'bx_market', '_bx_market_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_market\";s:6:\"method\";s:13:\"browse_public\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:7:\"gallery\";s:13:\"empty_message\";b:1;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 1),
+
+('', 0, 'bx_market', '_bx_market_page_block_title_recent_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, 'bx_market', '_bx_market_page_block_title_popular_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, 'bx_market', '_bx_market_page_block_title_popular_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_market";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 4);
+
+-- MENU: add to site menu
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_site', 'bx_market', 'products-home', '_bx_market_menu_item_title_system_entries_home', '_bx_market_menu_item_title_entries_home', 'page.php?i=products-home', '', '', 'shopping-cart col-green3', 'bx_market_submenu', 2147483647, 1, 1, IFNULL(@iSiteMenuOrder, 0) + 1);
+
+-- MENU: add to homepage menu
+SET @iHomepageMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_homepage' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_homepage', 'bx_market', 'products-home', '_bx_market_menu_item_title_system_entries_home', '_bx_market_menu_item_title_entries_home', 'page.php?i=products-home', '', '', 'shopping-cart col-green3', 'bx_market_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- MENU: add to "add content" menu
+SET @iAddMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_add_content_links' AND `active` = 1 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_add_content_links', 'bx_market', 'create-product', '_bx_market_menu_item_title_system_create_entry', '_bx_market_menu_item_title_create_entry', 'page.php?i=create-product', '', '', 'shopping-cart col-green3', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+
+-- MENU: actions menu for view entry 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_view', '_bx_market_menu_title_view_entry', 'bx_market_view', 'bx_market', 9, 0, 1, 'BxMarketMenuView', 'modules/boonex/market/classes/BxMarketMenuView.php'),
+('bx_market_view_popup', '_bx_market_menu_title_view_entry_popup', '', 'bx_market', 16, 0, 1, 'BxMarketMenuViewActions', 'modules/boonex/market/classes/BxMarketMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_market_view', 'bx_market', '_bx_market_menu_set_title_view_entry', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_market_view', 'bx_market', 'edit-product', '_bx_market_menu_item_title_system_edit_entry', '_bx_market_menu_item_title_edit_entry', 'page.php?i=edit-product&id={content_id}', '', '', 'pencil', '', 2147483647, 1, 0, 1),
+('bx_market_view', 'bx_market', 'delete-product', '_bx_market_menu_item_title_system_delete_entry', '_bx_market_menu_item_title_delete_entry', 'page.php?i=delete-product&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 2);
+
+
+-- MENU: actions menu for my entries
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_my', '_bx_market_menu_title_entries_my', 'bx_market_my', 'bx_market', 9, 0, 1, 'BxMarketMenu', 'modules/boonex/market/classes/BxMarketMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_market_my', 'bx_market', '_bx_market_menu_set_title_entries_my', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_market_my', 'bx_market', 'create-product', '_bx_market_menu_item_title_system_create_entry', '_bx_market_menu_item_title_create_entry', 'page.php?i=create-product', '', '', 'plus', '', 2147483647, 1, 0, 0);
+
+
+-- MENU: module sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_submenu', '_bx_market_menu_title_submenu', 'bx_market_submenu', 'bx_market', 6, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_market_submenu', 'bx_market', '_bx_market_menu_set_title_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_market_submenu', 'bx_market', 'products-home', '_bx_market_menu_item_title_system_entries_public', '_bx_market_menu_item_title_entries_public', 'page.php?i=products-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_market_submenu', 'bx_market', 'products-categories', '_bx_market_menu_item_title_system_entries_categories', '_bx_market_menu_item_title_entries_categories', 'page.php?i=products-categories', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_market_submenu', 'bx_market', 'products-popular', '_bx_market_menu_item_title_system_entries_popular', '_bx_market_menu_item_title_entries_popular', 'page.php?i=products-popular', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_market_submenu', 'bx_market', 'products-manage', '_bx_market_menu_item_title_system_entries_manage', '_bx_market_menu_item_title_entries_manage', 'page.php?i=products-manage', '', '', '', '', 2147483646, 1, 1, 4);
+
+-- MENU: sub-menu for view entry
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_view_submenu', '_bx_market_menu_title_view_entry_submenu', 'bx_market_view_submenu', 'bx_market', 6, 0, 1, 'BxMarketMenuView', 'modules/boonex/market/classes/BxMarketMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_market_view_submenu', 'bx_market', '_bx_market_menu_set_title_view_entry_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_market_view_submenu', 'bx_market', 'view-product', '_bx_market_menu_item_title_system_view_entry', '_bx_market_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-product&id={content_id}', '', '', '', '', 2147483647, 1, 0, 1),
+('bx_market_view_submenu', 'bx_market', 'view-product-comments', '_bx_market_menu_item_title_system_view_entry_comments', '_bx_market_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-product-comments&id={content_id}', '', '', '', '', 2147483647, 1, 0, 2);
+
+-- MENU: profile stats
+SET @iNotifMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_profile_stats' AND `active` = 1 LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_market', 'profile-stats-manage-products', '_bx_market_menu_item_title_system_manage_my_products', '_bx_market_menu_item_title_manage_my_products', 'page.php?i=products-manage', '', '_self', 'shopping-cart col-green3', 'a:2:{s:6:"module";s:9:"bx_market";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, 1, 0, @iNotifMenuOrder + 1);
+
+-- MENU: manage tools submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market_menu_manage_tools', '_bx_market_menu_title_manage_tools', 'bx_market_menu_manage_tools', 'bx_market', 6, 0, 1, 'BxMarketMenuManageTools', 'modules/boonex/market/classes/BxMarketMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_market_menu_manage_tools', 'bx_market', '_bx_market_menu_set_title_manage_tools', 0);
+
+--INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+--('bx_market_menu_manage_tools', 'bx_market', 'delete-with-content', '_bx_market_menu_item_title_system_delete_with_content', '_bx_market_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'trash-o', '', 128, 1, 0, 0);
+
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_market', 'products-administration', '_bx_market_menu_item_title_system_admt_products', '_bx_market_menu_item_title_admt_products', 'page.php?i=products-administration', '', '_self', '', 'a:2:{s:6:"module";s:9:"bx_market";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+-- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('trigger_profile_view_submenu', 'bx_market', 'products-author', '_bx_market_menu_item_title_system_view_entries_author', '_bx_market_menu_item_title_view_entries_author', 'page.php?i=products-author&profile_id={profile_id}', '', '', 'shopping-cart col-green3', '', 2147483647, 1, 0, 0);
+
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_market_allow_view_to', 'bx_market', 'view', '_bx_market_form_entry_input_allow_view_to', '3', 'bx_market_products', 'id', 'author', '', '');
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_market', 'create entry', NULL, '_bx_market_acl_action_create_entry', '', 1, 3);
+SET @iIdActionEntryCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_market', 'delete entry', NULL, '_bx_market_acl_action_delete_entry', '', 1, 3);
+SET @iIdActionEntryDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_market', 'view entry', NULL, '_bx_market_acl_action_view_entry', '', 1, 0);
+SET @iIdActionEntryView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_market', 'set thumb', NULL, '_bx_market_acl_action_set_thumb', '', 1, 3);
+SET @iIdActionSetThumb = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_market', 'edit any entry', NULL, '_bx_market_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- entry create
+(@iStandard, @iIdActionEntryCreate),
+(@iModerator, @iIdActionEntryCreate),
+(@iAdministrator, @iIdActionEntryCreate),
+(@iPremium, @iIdActionEntryCreate),
+
+-- entry delete
+(@iStandard, @iIdActionEntryDelete),
+(@iModerator, @iIdActionEntryDelete),
+(@iAdministrator, @iIdActionEntryDelete),
+(@iPremium, @iIdActionEntryDelete),
+
+-- entry view
+(@iUnauthenticated, @iIdActionEntryView),
+(@iAccount, @iIdActionEntryView),
+(@iStandard, @iIdActionEntryView),
+(@iUnconfirmed, @iIdActionEntryView),
+(@iPending, @iIdActionEntryView),
+(@iModerator, @iIdActionEntryView),
+(@iAdministrator, @iIdActionEntryView),
+(@iPremium, @iIdActionEntryView),
+
+-- set entry thumb
+(@iStandard, @iIdActionSetThumb),
+(@iModerator, @iIdActionSetThumb),
+(@iAdministrator, @iIdActionSetThumb),
+(@iPremium, @iIdActionSetThumb),
+
+-- edit any entry
+(@iModerator, @iIdActionEntryEditAny),
+(@iAdministrator, @iIdActionEntryEditAny);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_market', '_bx_market', @iSearchOrder + 1, 'BxMarketSearchResult', 'modules/boonex/market/classes/BxMarketSearchResult.php'),
+('bx_market_cmts', '_bx_market_cmts', @iSearchOrder + 2, 'BxMarketCmtsSearchResult', 'modules/boonex/market/classes/BxMarketCmtsSearchResult.php');
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_market', 'bx_market_meta_keywords', 'bx_market_meta_locations', '', '', '');
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_market_cats', 'bx_market', 'bx_market', 'bx_market_cats', 'bx_market_products', 'cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`id` = `bx_market_products`.`author`)', 'AND `sys_profiles`.`status` = ''active''', '', '');
+
+-- GRIDS: moderation tools
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `override_class_name`, `override_class_file`) VALUES
+('bx_market_administration', 'Sql', 'SELECT * FROM `bx_market_products` WHERE 1 ', 'bx_market_products', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 'BxMarketGridAdministration', 'modules/boonex/market/classes/BxMarketGridAdministration.php'),
+('bx_market_common', 'Sql', 'SELECT * FROM `bx_market_products` WHERE 1 ', 'bx_market_products', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 'BxMarketGridCommon', 'modules/boonex/market/classes/BxMarketGridCommon.php');
+
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_market_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_market_administration', 'switcher', '_bx_market_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_market_administration', 'title', '_bx_market_grid_column_title_adm_title', '25%', 0, '', '', 3),
+('bx_market_administration', 'added', '_bx_market_grid_column_title_adm_added', '20%', 1, '25', '', 4),
+('bx_market_administration', 'author', '_bx_market_grid_column_title_adm_author', '25%', 0, '25', '', 5),
+('bx_market_administration', 'actions', '', '20%', 0, '', '', 6),
+('bx_market_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_market_common', 'switcher', '_bx_market_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_market_common', 'title', '_bx_market_grid_column_title_adm_title', '40%', 0, '', '', 3),
+('bx_market_common', 'added', '_bx_market_grid_column_title_adm_added', '30%', 1, '25', '', 4),
+('bx_market_common', 'actions', '', '20%', 0, '', '', 5);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_market_administration', 'bulk', 'delete', '_bx_market_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_market_administration', 'single', 'edit', '_bx_market_grid_action_title_adm_edit', 'pencil', 1, 0, 1),
+('bx_market_administration', 'single', 'delete', '_bx_market_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_market_administration', 'single', 'settings', '_bx_market_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_market_common', 'bulk', 'delete', '_bx_market_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_market_common', 'single', 'edit', '_bx_market_grid_action_title_adm_edit', 'pencil', 1, 0, 1),
+('bx_market_common', 'single', 'delete', '_bx_market_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_market_common', 'single', 'settings', '_bx_market_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_market', 'BxMarketAlertsResponse', 'modules/boonex/market/classes/BxMarketAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('profile', 'delete', @iHandler);

+ 299 - 0
modules/boonex/market/install/sql/install.sql

@@ -0,0 +1,299 @@
+
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_market_products` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(10) unsigned NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `thumb` int(11) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `text` text NOT NULL,
+  `cat` int(11) NOT NULL,
+  `price` int(11) NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `allow_view_to` int(11) NOT NULL DEFAULT '3',
+  `status` enum('active','hidden') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_market_files` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(255) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_market_photos_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(255) NOT NULL,
+  `path` varchar(255) NOT NULL,
+  `file_name` varchar(255) NOT NULL,
+  `mime_type` varchar(128) NOT NULL,
+  `ext` varchar(32) NOT NULL,
+  `size` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+-- TABLE: comments
+CREATE TABLE IF NOT EXISTS `bx_market_cmts` (
+  `cmt_id` int(11) NOT NULL AUTO_INCREMENT,
+  `cmt_parent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_vparent_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_object_id` int(11) NOT NULL DEFAULT '0',
+  `cmt_author_id` int(10) unsigned NOT NULL DEFAULT '0',
+  `cmt_level` int(11) NOT NULL DEFAULT '0',
+  `cmt_text` text NOT NULL,
+  `cmt_mood` tinyint(4) NOT NULL DEFAULT '0',
+  `cmt_rate` int(11) NOT NULL DEFAULT '0',
+  `cmt_rate_count` int(11) NOT NULL DEFAULT '0',
+  `cmt_time` int(11) unsigned NOT NULL DEFAULT '0',
+  `cmt_replies` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`)
+);
+
+-- TABLE: votes
+CREATE TABLE IF NOT EXISTS `bx_market_votes` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_market_votes_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: views
+CREATE TABLE `bx_market_views_track` (
+  `object_id` int(11) NOT NULL default '0',
+  `viewer_id` int(11) NOT NULL default '0',
+  `viewer_nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: metas
+CREATE TABLE `bx_market_meta_keywords` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE `bx_market_meta_locations` (
+  `object_id` int(10) unsigned NOT NULL,
+  `lat` double NOT NULL,
+  `lng` double NOT NULL,
+  `country` varchar(2) NOT NULL,
+  `state` varchar(255) NOT NULL,
+  `city` varchar(255) NOT NULL,
+  `zip` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_market_reports` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `bx_market_reports_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `author_nip` int(11) unsigned NOT NULL default '0',
+  `type` varchar(32) NOT NULL default '',
+  `text` text NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+) ENGINE=MYISAM DEFAULT CHARSET=utf8;
+
+
+-- STORAGES & TRANSCODERS
+INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
+('bx_market_files', 'Local', '', 360, 2592000, 3, 'bx_market_files', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
+('bx_market_photos_resized', 'Local', '', 360, 2592000, 3, 'bx_market_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`) VALUES 
+('bx_market_preview', 'bx_market_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_market_files";}', 'no', '1', '2592000', '0'),
+('bx_market_gallery', 'bx_market_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_market_files";}', 'no', '1', '2592000', '0');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_market_preview', 'Resize', 'a:3:{s:1:"w";s:3:"128";s:1:"h";s:3:"128";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_market_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0');
+
+-- FORMS
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_market', 'bx_market', '_bx_market_form_entry', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_market_products', 'id', '', '', 'do_submit', '', 0, 1, 'BxMarketFormEntry', 'modules/boonex/market/classes/BxMarketFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_market', 'bx_market_entry_add', 'bx_market', 0, '_bx_market_form_entry_display_add'),
+('bx_market', 'bx_market_entry_delete', 'bx_market', 0, '_bx_market_form_entry_display_delete'),
+('bx_market', 'bx_market_entry_edit', 'bx_market', 0, '_bx_market_form_entry_display_edit'),
+('bx_market', 'bx_market_entry_view', 'bx_market', 1, '_bx_market_form_entry_display_view');
+
+INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
+('bx_market', 'bx_market', 'allow_view_to', '', '', 0, 'custom', '_bx_market_form_entry_input_sys_allow_view_to', '_bx_market_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_market', 'bx_market', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_market_form_entry_input_sys_delete_confirm', '_bx_market_form_entry_input_delete_confirm', '_bx_market_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_market_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_market', 'bx_market', 'do_publish', '_bx_market_form_entry_input_do_publish', '', 0, 'submit', '_bx_market_form_entry_input_sys_do_publish', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_market', 'bx_market', 'do_submit', '_bx_market_form_entry_input_do_submit', '', 0, 'submit', '_bx_market_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_market', 'bx_market', 'location', '', '', 0, 'custom', '_sys_form_input_sys_location', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_market', 'bx_market', 'pictures', '', '', 0, 'files', '_bx_market_form_entry_input_sys_pictures', '_bx_market_form_entry_input_pictures', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_market', 'bx_market', 'text', '', '', 0, 'textarea', '_bx_market_form_entry_input_sys_text', '_bx_market_form_entry_input_text', '', 1, 0, 2, '', '', '', 'Avail', '', '_bx_market_form_entry_input_text_err', 'XssHtml', '', 1, 0),
+('bx_market', 'bx_market', 'title', '', '', 0, 'text', '_bx_market_form_entry_input_sys_title', '_bx_market_form_entry_input_title', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_market_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_market', 'bx_market', 'cat', '', '#!bx_market_cats', 0, 'select', '_bx_market_form_entry_input_sys_cat', '_bx_market_form_entry_input_cat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_market_form_entry_input_cat_err', 'Xss', '', 1, 0),
+('bx_market', 'bx_market', 'price', '', '#!bx_market_prices', 0, 'radio_set', '_bx_market_form_entry_input_sys_price', '_bx_market_form_entry_input_price', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_market_form_entry_input_price_err', 'Xss', '', 1, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_market_entry_add', 'delete_confirm', 2147483647, 0, 1),
+('bx_market_entry_add', 'title', 2147483647, 1, 2),
+('bx_market_entry_add', 'cat', 2147483647, 1, 3),
+('bx_market_entry_add', 'text', 2147483647, 1, 4),
+('bx_market_entry_add', 'pictures', 2147483647, 1, 5),
+('bx_market_entry_add', 'price', 2147483647, 1, 6),
+('bx_market_entry_add', 'allow_view_to', 2147483647, 1, 7),
+('bx_market_entry_add', 'location', 2147483647, 1, 8),
+('bx_market_entry_add', 'do_submit', 2147483647, 0, 9),
+('bx_market_entry_add', 'do_publish', 2147483647, 1, 10),
+('bx_market_entry_delete', 'location', 2147483647, 0, 0),
+('bx_market_entry_delete', 'cat', 2147483647, 0, 0),
+('bx_market_entry_delete', 'price', 2147483647, 0, 0),
+('bx_market_entry_delete', 'pictures', 2147483647, 0, 0),
+('bx_market_entry_delete', 'text', 2147483647, 0, 0),
+('bx_market_entry_delete', 'do_publish', 2147483647, 0, 0),
+('bx_market_entry_delete', 'title', 2147483647, 0, 0),
+('bx_market_entry_delete', 'allow_view_to', 2147483647, 0, 0),
+('bx_market_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_market_entry_delete', 'do_submit', 2147483647, 1, 2),
+('bx_market_entry_edit', 'do_publish', 2147483647, 0, 1),
+('bx_market_entry_edit', 'delete_confirm', 2147483647, 0, 2),
+('bx_market_entry_edit', 'title', 2147483647, 1, 3),
+('bx_market_entry_edit', 'cat', 2147483647, 1, 4),
+('bx_market_entry_edit', 'text', 2147483647, 1, 5),
+('bx_market_entry_edit', 'pictures', 2147483647, 1, 6),
+('bx_market_entry_edit', 'price', 2147483647, 1, 7),
+('bx_market_entry_edit', 'allow_view_to', 2147483647, 1, 8),
+('bx_market_entry_edit', 'location', 2147483647, 1, 9),
+('bx_market_entry_edit', 'do_submit', 2147483647, 1, 10),
+('bx_market_entry_view', 'location', 2147483647, 0, 0),
+('bx_market_entry_view', 'cat', 2147483647, 0, 0),
+('bx_market_entry_view', 'price', 2147483647, 0, 0),
+('bx_market_entry_view', 'pictures', 2147483647, 0, 0),
+('bx_market_entry_view', 'delete_confirm', 2147483647, 0, 0),
+('bx_market_entry_view', 'text', 2147483647, 1, 0),
+('bx_market_entry_view', 'do_publish', 2147483647, 0, 0),
+('bx_market_entry_view', 'title', 2147483647, 0, 0),
+('bx_market_entry_view', 'do_submit', 2147483647, 0, 0),
+('bx_market_entry_view', 'allow_view_to', 2147483647, 0, 0);
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_market_cats', '_bx_market_pre_lists_cats', 'bx_market', '0'),
+('bx_market_prices', '_bx_market_pre_lists_prices', 'bx_market', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_market_cats', '', 0, '_sys_please_select', ''),
+('bx_market_cats', '1', 1, '_bx_market_cat_administration', ''),
+('bx_market_cats', '2', 2, '_bx_market_cat_adult', ''),
+('bx_market_cats', '3', 3, '_bx_market_cat_advertisement', ''),
+('bx_market_cats', '4', 4, '_bx_market_cat_affiliates', ''),
+('bx_market_cats', '5', 5, '_bx_market_cat_authentication', ''),
+('bx_market_cats', '6', 6, '_bx_market_cat_calendars', ''),
+('bx_market_cats', '7', 7, '_bx_market_cat_communication', ''),
+('bx_market_cats', '8', 8, '_bx_market_cat_content', ''),
+('bx_market_cats', '9', 9, '_bx_market_cat_conversion', ''),
+('bx_market_cats', '10', 10, '_bx_market_cat_core_changes', ''),
+('bx_market_cats', '11', 11, '_bx_market_cat_dating', ''),
+('bx_market_cats', '12', 12, '_bx_market_cat_documentation', ''),
+('bx_market_cats', '13', 13, '_bx_market_cat_ecommerce', ''),
+('bx_market_cats', '14', 14, '_bx_market_cat_events', ''),
+('bx_market_cats', '15', 15, '_bx_market_cat_feedback', ''),
+('bx_market_cats', '16', 16, '_bx_market_cat_flash', ''),
+('bx_market_cats', '17', 17, '_bx_market_cat_games', ''),
+('bx_market_cats', '18', 18, '_bx_market_cat_graphics', ''),
+('bx_market_cats', '19', 19, '_bx_market_cat_hosting', ''),
+('bx_market_cats', '20', 20, '_bx_market_cat_integrations', ''),
+('bx_market_cats', '21', 21, '_bx_market_cat_location', ''),
+('bx_market_cats', '22', 22, '_bx_market_cat_management', ''),
+('bx_market_cats', '23', 23, '_bx_market_cat_mobile', ''),
+('bx_market_cats', '24', 24, '_bx_market_cat_multimedia', ''),
+('bx_market_cats', '25', 25, '_bx_market_cat_music', ''),
+('bx_market_cats', '26', 26, '_bx_market_cat_navigation', ''),
+('bx_market_cats', '27', 27, '_bx_market_cat_other', ''),
+('bx_market_cats', '28', 28, '_bx_market_cat_performance', ''),
+('bx_market_cats', '29', 29, '_bx_market_cat_photos', ''),
+('bx_market_cats', '30', 30, '_bx_market_cat_search', ''),
+('bx_market_cats', '31', 31, '_bx_market_cat_security', ''),
+('bx_market_cats', '32', 32, '_bx_market_cat_services', ''),
+('bx_market_cats', '33', 33, '_bx_market_cat_social', ''),
+('bx_market_cats', '34', 34, '_bx_market_cat_spam_prevention', ''),
+('bx_market_cats', '35', 35, '_bx_market_cat_statistics', ''),
+('bx_market_cats', '36', 36, '_bx_market_cat_templates', ''),
+('bx_market_cats', '37', 37, '_bx_market_cat_tools', ''),
+('bx_market_cats', '38', 38, '_bx_market_cat_translations', ''),
+('bx_market_cats', '39', 39, '_bx_market_cat_video', ''),
+
+('bx_market_prices', '1', 1, '_bx_market_cat_price_1', ''),
+('bx_market_prices', '2', 2, '_bx_market_cat_price_2', ''),
+('bx_market_prices', '3', 3, '_bx_market_cat_price_3', ''),
+('bx_market_prices', '4', 4, '_bx_market_cat_price_4', ''),
+('bx_market_prices', '5', 5, '_bx_market_cat_price_5', '');
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Nl2br`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_market', 'bx_market_cmts', 1, 5000, 1000, 1, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-product&id={object_id}', '', 'bx_market_products', 'id', 'author', 'title', 'comments', '', '');
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_market', 'bx_market_votes', 'bx_market_votes_track', '604800', '1', '1', '0', '1', 'bx_market_products', 'id', 'author', 'rate', 'votes', '', '');
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `table_main`, `table_track`, `is_on`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_market', 'bx_market_reports', 'bx_market_reports_track', '1', 'page.php?i=view-product&id={object_id}', 'bx_market_products', 'id', 'author', 'reports', '', '');
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_market', 'bx_market_views_track', '86400', '1', 'bx_market_products', 'id', 'views', '', '');
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_market', '_bx_market', '_bx_market', 'bx_market@modules/boonex/market/|std-pi.png');
+SET @iPageId = LAST_INSERT_ID();
+
+SET @iParentPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name` = 'home');
+SET @iParentPageOrder = (SELECT MAX(`order`) FROM `sys_std_pages_widgets` WHERE `page_id` = @iParentPageId);
+INSERT INTO `sys_std_widgets` (`page_id`, `module`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_market', '{url_studio}module.php?name=bx_market', '', 'bx_market@modules/boonex/market/|std-wi.png', '_bx_market', '', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_actions";s:6:"params";a:0:{}s:5:"class";s:18:"TemplStudioModules";}');
+INSERT INTO `sys_std_pages_widgets` (`page_id`, `widget_id`, `order`) VALUES
+(@iParentPageId, LAST_INSERT_ID(), IF(ISNULL(@iParentPageOrder), 1, @iParentPageOrder + 1));

+ 39 - 0
modules/boonex/market/install/sql/uninstall.sql

@@ -0,0 +1,39 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_market_products`, `bx_market_files`, `bx_market_photos_resized`, `bx_market_cmts`, `bx_market_votes`, `bx_market_votes_track`, `bx_market_views_track`, `bx_market_meta_keywords`, `bx_market_meta_locations`, `bx_market_reports`, `bx_market_reports_track`;
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_storage` WHERE `object` = 'bx_market_files' OR `object` = 'bx_market_photos_resized';
+DELETE FROM `sys_storage_tokens` WHERE `object` = 'bx_market_files' OR `object` = 'bx_market_photos_resized';
+
+DELETE FROM `sys_objects_transcoder` WHERE `object` IN('bx_market_preview', 'bx_market_gallery');
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` IN('bx_market_preview', 'bx_market_gallery');
+DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` IN('bx_market_preview', 'bx_market_gallery');
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_market';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_market';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_market';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN ('bx_market_entry_add', 'bx_market_entry_edit', 'bx_market_entry_view', 'bx_market_entry_delete');
+
+-- PRE-VALUES
+DELETE FROM `sys_form_pre_lists` WHERE `module` = 'bx_market';
+
+DELETE FROM `sys_form_pre_values` WHERE `Key` IN('bx_market_cats');
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` = 'bx_market';
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` = 'bx_market';
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `Name` = 'bx_market';
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `Name` = 'bx_market';
+
+-- STUDIO: page & widget
+DELETE FROM `tp`, `tw`, `tpw`
+USING `sys_std_pages` AS `tp`, `sys_std_widgets` AS `tw`, `sys_std_pages_widgets` AS `tpw`
+WHERE `tp`.`id` = `tw`.`page_id` AND `tw`.`id` = `tpw`.`widget_id` AND `tp`.`name` = 'bx_market';

+ 51 - 0
modules/boonex/market/js/manage_tools.js

@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+function BxPostsManageTools(oOptions) {
+	this._sActionsUrl = oOptions.sActionUrl;
+	this._sObjNameGrid = oOptions.sObjNameGrid;
+    this._sObjName = oOptions.sObjName == undefined ? 'oBxPostsManageTools' : oOptions.sObjName;
+
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._sParamsDivider = oOptions.sParamsDivider == undefined ? '#-#' : oOptions.sParamsDivider;
+
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+}
+
+BxPostsManageTools.prototype.onChangeFilter = function(oFilter) {
+	var oFilter1 = $('#bx-grid-filter1-' + this._sObjNameGrid);
+	var sValueFilter1 = oFilter1.length > 0 ? oFilter1.val() : '';
+
+	var oSearch = $('#bx-grid-search-' + this._sObjNameGrid);
+	var sValueSearch = oSearch.length > 0 ? oSearch.val() : '';
+	if(sValueSearch == _t('_sys_grid_search'))
+		sValueSearch = '';
+
+	glGrids[this._sObjNameGrid].setFilter(sValueFilter1 + this._sParamsDivider + sValueSearch, true);
+};
+
+BxPostsManageTools.prototype.onClickSettings = function(sMenuObject, oButton) {
+	if($(oButton).hasClass('bx-btn-disabled'))
+		return false;
+
+	bx_menu_popup(sMenuObject, oButton, {}, {
+		content_id: $(oButton).attr('bx_grid_action_data')
+	});
+};
+
+BxPostsManageTools.prototype.onClickDelete = function(iContentId) {
+	$('.bx-popup-applied:visible').dolPopupHide();
+
+	glGrids[this._sObjNameGrid].actionWithId(iContentId, 'delete', {}, '', false, 1);
+};
+
+/** @} */

+ 18 - 0
modules/boonex/market/request.php

@@ -0,0 +1,18 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+check_logged();
+
+BxBaseModTextRequest::processAsAction($GLOBALS['aModule'], $GLOBALS['aRequest']);
+
+/** @} */

+ 3 - 0
modules/boonex/market/template/attachments.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/attachments.html />
+

+ 3 - 0
modules/boonex/market/template/author.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/author.html />
+

+ 1 - 0
modules/boonex/market/template/author_link.html

@@ -0,0 +1 @@
+<bx_include_base:../modules/base/text/template/author_link.html />

+ 3 - 0
modules/boonex/market/template/css/forms.css

@@ -0,0 +1,3 @@
+
+@import url(../../../../base/text/template/css/forms.css);
+

+ 3 - 0
modules/boonex/market/template/css/main.css

@@ -0,0 +1,3 @@
+
+@import url(../../../../base/text/template/css/main.css);
+

+ 1 - 0
modules/boonex/market/template/css/manage_tools.css

@@ -0,0 +1 @@
+@import url(../../../../base/general/template/css/manage_tools.css);

+ 3 - 0
modules/boonex/market/template/entry-all-actions.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/entry-all-actions.html />
+

+ 3 - 0
modules/boonex/market/template/entry-location.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/general/template/entry-location.html />
+

+ 3 - 0
modules/boonex/market/template/entry-share.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/entry-share.html />
+

+ 3 - 0
modules/boonex/market/template/entry-text.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/entry-text.html />
+

+ 3 - 0
modules/boonex/market/template/form_field_location.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/general/template/form_field_location.html />
+

+ 3 - 0
modules/boonex/market/template/form_ghost_template.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/form_ghost_template.html />
+

BIN
modules/boonex/market/template/images/icons/std-mi.png


BIN
modules/boonex/market/template/images/icons/std-pi.png


BIN
modules/boonex/market/template/images/icons/std-si.png


BIN
modules/boonex/market/template/images/icons/std-wi.png


+ 1 - 0
modules/boonex/market/template/title_link.html

@@ -0,0 +1 @@
+<bx_include_base:../modules/base/text/template/title_link.html />

+ 3 - 0
modules/boonex/market/template/unit.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/unit.html />
+

+ 1 - 0
modules/boonex/market/template/unit_full.html

@@ -0,0 +1 @@
+<bx_include_base:../modules/base/text/template/unit_full.html />

+ 1 - 0
modules/boonex/market/template/unit_gallery.html

@@ -0,0 +1 @@
+<bx_include_base:../modules/base/text/template/unit_gallery.html />

+ 3 - 0
modules/boonex/market/template/unit_live_search.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/unit_live_search.html />
+

+ 3 - 0
modules/boonex/market/template/unit_private.html

@@ -0,0 +1,3 @@
+
+<bx_include_base:../modules/base/text/template/unit_private.html />
+

+ 1 - 1
modules/boonex/notifications/classes/BxNtfsConfig.php

@@ -35,7 +35,7 @@ class BxNtfsConfig extends BxBaseModNotificationsConfig
         $this->_aHandlerDescriptor = array('module_name' => '', 'module_method' => '', 'module_class' => '');
         $this->_sHandlersMethod = 'get_notifications_data';
 
-        $this->_aJsClass = array(
+        $this->_aJsClasses = array(
             'main' => 'BxNtfsMain',
         	'view' => 'BxNtfsView',
         );

+ 21 - 0
modules/boonex/ocean/data/template/system/scripts/BxTemplPaymentsServices.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    TridentCore Trident Core
+ * @{
+ */
+
+/**
+ * @see BxBasePaymentsServices
+ */
+class BxTemplPaymentsServices extends BxBasePaymentsServices
+{
+    public function __construct()
+    {
+        parent::__construct();
+    }
+}
+
+/** @} */

+ 1 - 1
modules/boonex/organizations/classes/BxOrgsConfig.php

@@ -134,7 +134,7 @@ class BxOrgsConfig extends BxBaseModProfileConfig
 
         );
 
-        $this->_aJsClass = array(
+        $this->_aJsClasses = array(
         	'manage_tools' => 'BxOrgsManageTools'
         );
 

+ 221 - 0
modules/boonex/payment/classes/BxPaymentCart.php

@@ -0,0 +1,221 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentCart extends BxBaseModPaymentCart
+{
+    protected $_sLangsPrefix;
+
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+    }
+
+    /*
+     * Service methods
+     */
+	public function serviceGetBlockCart($iVendor = BX_PAYMENT_EMPTY_ID)
+    {
+    	$iVendor = (int)$iVendor;
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return MsgBox(_t($this->_sLangsPrefix . 'err_required_login'));
+
+        $aCartInfo = $this->getInfo($iUserId, $iVendor);
+        return array(
+        	'content' => $this->_oModule->_oTemplate->displayBlockCart($aCartInfo, $iVendor),
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_cart_submenu')
+        );
+    }
+
+    public function serviceGetBlockCartHistory()
+    {
+		$iVendorId = bx_get('vendor') !== false ? (int)bx_get('vendor') : 0;
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return MsgBox(_t($this->_sLangsPrefix . 'err_required_login'));
+
+        return array(
+        	'content' => $this->_oModule->_oTemplate->displayBlockHistory($iUserId, $iVendorId),
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_cart_submenu')
+		);
+    }
+
+    public function serviceAddToCart($iVendorId, $iModuleId, $iItemId, $iItemCount)
+    {
+    	if($iVendorId == BX_PAYMENT_EMPTY_ID || empty($iModuleId) || empty($iItemId) || empty($iItemCount))
+            return array('code' => 1, 'message' => _t($this->_sLangsPrefix . 'err_wrong_data'));
+
+		$iClientId = $this->_oModule->getProfileId();
+        if(empty($iClientId))
+            return array('code' => 2, 'message' => _t($this->_sLangsPrefix . 'err_required_login'));
+
+        if($iClientId == $iVendorId)
+            return array('code' => 3, 'message' => _t($this->_sLangsPrefix . 'err_purchase_from_yourself'));
+
+        $aVendor = $this->_oModule->getVendorInfo($iVendorId);
+        if(!$aVendor['active'])
+            return array('code' => 4, 'message' => _t($this->_sLangsPrefix . 'err_inactive_vendor'));
+
+        $aVendorProviders = $this->_oModule->_oDb->getVendorInfoProviders($iVendorId);
+        if(empty($aVendorProviders))
+            return array('code' => 5, 'message' => _t($this->_sLangsPrefix . 'err_not_accept_payments'));
+
+        $sCartItem = $this->_oModule->_oConfig->descriptorA2S(array($iVendorId, $iModuleId, $iItemId, $iItemCount));
+        $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+
+        if(strpos($sCartItems, $this->_oModule->_oConfig->descriptorA2S(array($iVendorId, $iModuleId, $iItemId))) !== false)
+            $sCartItems = preg_replace_callback(
+            	"/" . $this->_oModule->_oConfig->descriptorA2S(array($iVendorId, $iModuleId, $iItemId, '([0-9])+')) . "/", 
+            	create_function('$aMatches', 'return ' . $this->_oModule->_oConfig->descriptorA2S(array("'" . $iVendorId, $iModuleId, $iItemId, "' . (\$aMatches[1] + " . $iItemCount . ")")) . ';'),
+            	$sCartItems
+			);
+        else
+            $sCartItems = empty($sCartItems) ? $sCartItem : $sCartItems . $this->_oModule->_oConfig->getDivider('descriptors') . $sCartItem;
+
+        $this->_oModule->_oDb->setCartItems($iClientId, $sCartItems);
+
+        $aInfo = $this->getInfo($iClientId);
+        $iTotalQuantity = 0;
+        foreach($aInfo as $aCart)
+           $iTotalQuantity += $aCart['items_count'];
+
+        return array(
+        	'code' => 0, 
+        	'message' => _t($this->_sLangsPrefix . 'msg_successfully_added'), 
+        	'total_quantity' => $iTotalQuantity,
+	        //TODO: Update account submenu if it's needed.  
+        	'content' => '' //$this->_oModule->_oTemplate->displayToolbarSubmenu($aInfo)
+        );
+    }
+
+    public function serviceDeleteFromCart($iVendorId, $iModuleId = 0, $iItemId = 0)
+    {
+        if($iVendorId == BX_PAYMENT_EMPTY_ID)
+            return array('code' => 1, 'message' => _t($this->_sLangsPrefix . 'err_wrong_data'));
+
+		$iClientId = $this->_oModule->getProfileId();
+        if(empty($iClientId))
+            return array('code' => 2, 'message' => _t($this->_sLangsPrefix . 'err_required_login'));
+
+        if(!empty($iModuleId) && !empty($iItemId))
+            $sPattern = "'" . $iVendorId . "_" . $iModuleId . "_" . $iItemId . "_[0-9]+:?'";
+        else
+            $sPattern = "'" . $iVendorId . "_[0-9]+_[0-9]+_[0-9]+:?'";
+
+        $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+        $sCartItems = trim(preg_replace($sPattern, "", $sCartItems), ":");
+        $this->_oModule->_oDb->setCartItems($iClientId, $sCartItems);
+
+        return array('code' => 0, 'message' => _t($this->_sLangsPrefix . 'inf_successfully_deleted'));
+    }
+
+    public function getInfo($iUserId, $iVendorId = BX_PAYMENT_EMPTY_ID, $aItems = array())
+    {
+        if($iVendorId != BX_PAYMENT_EMPTY_ID && !empty($aItems))
+            return $this->_getInfo($iUserId, $iVendorId, $this->_oModule->_oConfig->descriptorsM2A($aItems));
+
+        $aContent = $this->_parseByVendor($iUserId);
+
+        if($iVendorId != BX_PAYMENT_EMPTY_ID)
+            return isset($aContent[$iVendorId]) ? $this->_getInfo($iUserId, $iVendorId, $aContent[$iVendorId]) : array();
+
+        $aResult = array();
+        foreach($aContent as $iVendorId => $aVendorItems)
+            $aResult[$iVendorId] = $this->_getInfo($iUserId, $iVendorId, $aVendorItems);
+
+        return $aResult;
+    }
+
+    public function updateInfo($mixedPending)
+    {
+    	$aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+    	if(empty($aPending) || !is_array($aPending))
+    		return false;
+
+		if((int)$aPending['processed'] == 1)
+			return true;
+
+		$iClientId = (int)$aPending['client_id'];
+		$sOrderId = $this->_oModule->_oConfig->getLicense();
+
+        $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+        $aItems = $this->_oModule->_oConfig->descriptorsM2A($aPending['items']);
+
+        foreach($aItems as $aItem) {
+            $aItemInfo = $this->_oModule->callRegisterCartItem((int)$aItem['module_id'], array($aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $sOrderId));
+            if(!is_array($aItemInfo) || empty($aItemInfo))
+                continue;
+
+            $this->_oModule->_oDb->insertOrderProcessed(array(
+                'pending_id' => $aPending['id'],
+                'order_id' => $sOrderId,
+                'client_id' => $aPending['client_id'],
+                'seller_id' => $aPending['seller_id'],
+                'module_id' => $aItem['module_id'],
+                'item_id' => $aItem['item_id'],
+                'item_count' => $aItem['item_count'],
+                'amount' => $aItemInfo['price'] * $aItem['item_count'],
+            ));
+
+            $sCartItems = trim(preg_replace("'" . $this->_oModule->_oConfig->descriptorA2S($aItem) . ":?'", "", $sCartItems), ":");
+        }
+
+		$this->_oModule->_oDb->setCartItems($iClientId, $sCartItems);
+        return $this->_oModule->_oDb->updateOrderPending($aPending['id'], array('processed' => 1));
+    }
+
+    /**
+     * Enter description here...
+     *
+     * @param  integer $iClientId client's ID
+     * @param  integer $iVendorId vendor's ID
+     * @param  array   $aItems    item descriptors(quaternions) from shopping cart.
+     * @return array   with full info about vendor and items.
+     */
+    protected function _getInfo($iClientId, $iVendorId, $aItems)
+    {
+        $iItemsCount = 0;
+        $fItemsPrice = 0;
+        $aItemsInfo = array();
+        foreach($aItems as $aItem) {
+            $aItemInfo = $this->_oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id']));
+            $aItemInfo['module_id'] = (int)$aItem['module_id'];
+            $aItemInfo['quantity'] = (int)$aItem['item_count'];
+
+            $iItemsCount += $aItem['item_count'];
+            $fItemsPrice += $aItem['item_count'] * $aItemInfo['price'];
+            $aItemsInfo[] = $aItemInfo;
+        }
+
+        $aVendor = $this->_oModule->getVendorInfo((int)$iVendorId);
+        return array(
+        	'client_id' => $iClientId,
+            'vendor_id' => $aVendor['id'],
+            'vendor_name' => $aVendor['name'],
+        	'vendor_link' => $aVendor['link'],
+            'vendor_icon' => $aVendor['icon'],
+        	'vendor_unit' => $aVendor['unit'],
+            'vendor_currency_code' => $aVendor['currency_code'],
+            'vendor_currency_sign' => $aVendor['currency_sign'],
+            'items_count' => $iItemsCount,
+            'items_price' => $fItemsPrice,
+            'items' => $aItemsInfo
+        );
+    }
+}
+
+/** @} */

+ 150 - 0
modules/boonex/payment/classes/BxPaymentConfig.php

@@ -0,0 +1,150 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentConfig extends BxBaseModPaymentConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_aUrls = array(
+        	'join' => 'page.php?i=payment-join',
+        	'cart' => 'page.php?i=payment-cart',
+        	'history' => 'page.php?i=payment-history',
+        	'orders' => 'page.php?i=payment-orders',
+        	'details' => 'page.php?i=payment-details',
+
+        	'return' => 'page.php?i=payment-cart',
+        	'return_data' => BX_DOL_URL_ROOT . $this->getBaseUri() . 'finalize_checkout/'
+        );
+
+        $this->_aHtmlIds = array(
+        	'history' => array(
+        		'order_history_view' => $this->_sName . '-order-view-history',
+        	),
+        	'pending' => array(
+        		'order_pending_view' => $this->_sName . '-order-view-pending',
+        		'order_pending_process' => $this->_sName . '-order-process',
+        	),
+        	'processed' => array(
+        		'order_processed_view' => $this->_sName . '-order-view-processed',
+        		'order_processed_add' => $this->_sName . '-order-add',
+        		'order_processed_client_id' => $this->_sName . '-oa-client-id',
+        		'order_processed_client' => $this->_sName . '-oa-client',
+        		'order_processed_items' => $this->_sName . '-oa-items',	
+        	),
+        );
+
+        $this->_aPerPage = array(
+        	'orders' => 10,
+        	'history' => 10
+        );
+        $this->_aHandlers = array();
+
+        $this->_aJsClasses = array(
+        	'cart' => 'BxPaymentCart',
+        	'history' => 'BxPaymentOrders',
+        	'pending' => 'BxPaymentOrders',
+        	'processed' => 'BxPaymentOrders',
+        );
+
+        $this->_aJsObjects = array(
+        	'cart' => 'oPaymentCart',
+        	'history' => 'oPaymentOrders',
+        	'pending' => 'oPaymentOrders',
+        	'processed' => 'oPaymentOrders',
+        );
+    }
+
+	public function getLicense()
+    {
+        list($fMilliSec, $iSec) = explode(' ', microtime());
+        $fSeed = (float)$iSec + ((float)$fMilliSec * 100000);
+        srand($fSeed);
+
+        $sResult = '';
+        for($i=0; $i < 16; ++$i) {
+            switch(rand(1,2)) {
+                case 1:
+                    $c = chr(rand(ord('A'),ord('Z')));
+                    break;
+                case 2:
+                    $c = chr(rand(ord('0'),ord('9')));
+                    break;
+            }
+            $sResult .= $c;
+        }
+
+        return $sResult;
+    }
+
+    public function getModuleId($mixedId)
+    {
+    	if(is_int($mixedId))
+    		return (int)$mixedId;
+
+		if(is_string($mixedId)) {
+            $aInfo = $this->_oDb->getModuleByName($mixedId);
+            if(!is_array($aInfo) || empty($aInfo['id']))
+            	$aInfo = $this->_oDb->getModuleByUri($mixedId);
+
+            if(is_array($aInfo) && !empty($aInfo['id']))
+            	return (int)$aInfo['id'];
+        } 
+
+        return 0;
+    }
+
+    public function descriptorA2S($a) 
+    {
+    	return implode($this->getDivider('descriptor'), $a);
+    }
+
+	public function descriptorS2A($s) 
+    {
+    	return explode($this->getDivider('descriptor'), $s);
+    }
+
+	/**
+     * Conver items to array with necessary structure.
+     *
+     * @param  string/array $mixed - string with cart items divided with (:) or an array of cart items.
+     * @return array        with items.
+     */
+    public function descriptorsM2A($mixed)
+    {
+        $aResult = array();
+
+        if(is_string($mixed))
+           $aItems = explode($this->getDivider('descriptors'), $mixed);
+        else if(is_array($mixed))
+           $aItems = $mixed;
+        else
+            $aItems = array();
+
+        foreach($aItems as $sItem) {
+            $aItem = $this->descriptorS2A($sItem);
+            $aResult[] = array('vendor_id' => $aItem[0], 'module_id' => $aItem[1], 'item_id' => $aItem[2], 'item_count' => $aItem[3]);
+        }
+
+        return $aResult;
+    }
+
+	public function http2https($s)
+    {
+    	if(strncmp($s, 'https://', 8) == 0)
+    		return $s;
+
+        return 'https://' . bx_ltrim_str($s, 'http://');
+    }
+}
+
+/** @} */

+ 304 - 0
modules/boonex/payment/classes/BxPaymentDb.php

@@ -0,0 +1,304 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentDb extends BxBaseModPaymentDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    /**
+     * Payment details methods
+     */
+    public function getForm()
+    {
+        $sQuery = "SELECT
+                `tp`.`id` AS `provider_id`,
+                `tp`.`name` AS `provider_name`,
+                `tp`.`caption` AS `provider_caption`,
+                `tp`.`description` AS `provider_description`,
+                `tp`.`option_prefix` AS `provider_option_prefix`,
+                `tpo`.`id` AS `id`,
+                `tpo`.`name` AS `name`,
+                `tpo`.`type` AS `type`,
+                `tpo`.`caption` AS `caption`,
+                `tpo`.`description` AS `description`,
+                `tpo`.`extra` AS `extra`,
+                `tpo`.`check_type` AS `check_type`,
+                `tpo`.`check_params` AS `check_params`,
+                `tpo`.`check_error` AS `check_error`
+            FROM `" . $this->_sPrefix . "providers` AS `tp`
+            LEFT JOIN `" . $this->_sPrefix . "providers_options` AS `tpo` ON `tp`.`id`=`tpo`.`provider_id`
+            ORDER BY `tp`.`id` ASC, `tpo`.`order` ASC";
+
+        return $this->getAll($sQuery);
+    }
+
+    public function getFormData($iUserId)
+    {
+        $sQuery = $this->prepare("SELECT
+                `tuv`.`option_id` AS `option_id`,
+                `tuv`.`value` AS `value`
+            FROM `" . $this->_sPrefix . "user_values` AS `tuv`
+            WHERE `tuv`.`user_id`=?", $iUserId);
+
+        return $this->getAllWithKey($sQuery, 'option_id');
+    }
+
+	public function getProviders($sName = '')
+    {
+        $sWhereClause = "1";
+        if(!empty($sName))
+            $sWhereClause = $this->prepare("`tp`.`name`=?", $sName);
+
+        $sQuery = "SELECT
+                `tp`.`id` AS `id`,
+                `tp`.`name` AS `name`,
+                `tp`.`caption` AS `caption`,
+                `tp`.`description` AS `description`,
+                `tp`.`option_prefix` AS `option_prefix`,
+                `tp`.`for_visitor` AS `for_visitor`,
+                `tp`.`class_name` AS `class_name`,
+                `tp`.`class_file` AS `class_file`
+            FROM `" . $this->_sPrefix . "providers` AS `tp`
+            WHERE " . $sWhereClause;
+
+        return !empty($sName) ? $this->getRow($sQuery) : $this->getAll($sQuery);
+    }
+
+    public function getOptions($iUserId = BX_PAYMENT_EMPTY_ID, $iProviderId = 0)
+    {
+        if($iUserId == BX_PAYMENT_EMPTY_ID && empty($iProviderId))
+           return $this->getAll("SELECT `id`, `name`, `type` FROM `" . $this->_sPrefix . "providers_options`");
+
+        $sWhereAddon = "";
+        if(!empty($iProviderId))
+            $sWhereAddon = $this->prepare(" AND `tpo`.`provider_id`=?", $iProviderId);
+
+        $sQuery = $this->prepare("SELECT
+               `tpo`.`name` AS `name`,
+               `tuv`.`value` AS `value`
+            FROM `" . $this->_sPrefix . "providers_options` AS `tpo`
+            LEFT JOIN `" . $this->_sPrefix . "user_values` AS `tuv` ON `tpo`.`id`=`tuv`.`option_id`
+            WHERE 1" . $sWhereAddon . " AND `tuv`.`user_id`=?", $iUserId);
+
+        return $this->getAllWithKey($sQuery, 'name');
+    }
+
+    public function updateOption($iUserId, $iOptionId, $sValue)
+    {
+        $sQuery = $this->prepare("REPLACE INTO `" . $this->_sPrefix . "user_values` SET `user_id`=?, `option_id`=?, `value`=?", $iUserId, $iOptionId, $sValue);
+        return $this->query($sQuery);
+    }
+
+
+    /**
+     * Shopping cart methods.
+     */
+    public function getCartItems($iId)
+    {
+    	$sQuery = $this->prepare("SELECT `items` FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=? LIMIT 1", $iId);
+        return $this->getOne($sQuery);
+    }
+    public function setCartItems($iId, $sItems)
+    {
+        $sItems = trim($sItems, ":");
+        if(empty($sItems))
+            $sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=? LIMIT 1", $iId);
+        else
+            $sQuery = $this->prepare("REPLACE INTO `" . $this->_sPrefix . "cart` SET `client_id`=?, `items`=?", $iId, $sItems);
+
+        return $this->query($sQuery);
+    }
+    public function getVendorInfoProviders($iId, $sProvider = '')
+    {
+        $aResult = array();
+
+        //--- Get specified payment provider if it's available ---//
+        if(!empty($sProvider)) {
+            $aProvider = $this->getProviders($sProvider);
+            $aOptions = $this->getOptions($iId, $aProvider['id']);
+
+            if(isset($aOptions[$aProvider['option_prefix'] . 'active']) && $aOptions[$aProvider['option_prefix'] . 'active']['value'] == 'on') {
+                $aProvider['options'] = $aOptions;
+                $aResult = $aProvider;
+            }
+        }
+        //--- Get all available payment providers ---//
+        else{
+            $aProviders = $this->getProviders();
+            $aOptions = $this->getOptions($iId);
+
+            foreach($aProviders as $aProvider)
+               if(isset($aOptions[$aProvider['option_prefix'] . 'active']) && $aOptions[$aProvider['option_prefix'] . 'active']['value'] == 'on') {
+                   foreach($aOptions as $sName => $aOption)
+                       if(strpos($sName, $aProvider['option_prefix']) !== false)
+                           $aProvider['options'][$sName] = $aOption;
+                   $aResult[] = $aProvider;
+               }
+        }
+
+        return $aResult;
+    }
+    public function getFirstAdminId()
+    {
+    	$sQuery = $this->prepare("SELECT `profile_id` FROM `sys_accounts` WHERE `role`&" . BX_DOL_ROLE_ADMIN . " ORDER BY `profile_id` ASC LIMIT 1");
+        return (int)$this->getOne($sQuery);
+    }
+    public function getAdminsIds()
+    {
+    	$sQuery = $this->prepare("SELECT `profile_id` FROM `sys_accounts` WHERE `role`&" . BX_DOL_ROLE_ADMIN . " ORDER BY `profile_id` ASC");
+        return $this->getColumn($sQuery);
+    }
+
+
+	/*
+     * Pending Orders methods
+     */
+    public function getOrderPending($aParams)
+    {
+    	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
+
+    	$sWhereClause = $sLimitClause = '';
+        switch($aParams['type']) {
+            case 'id':
+                $sWhereClause = $this->prepare(" AND `id`=?", $aParams['id']);
+                $sLimitClause = " LIMIT 1";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT * FROM `" . $this->_sPrefix . "transactions_pending` WHERE 1 " . $sWhereClause . $sLimitClause;
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertOrderPending($iClientId, $sProviderName, $aCartInfo)
+    {
+        $sItems = "";
+        foreach($aCartInfo['items'] as $aItem)
+            $sItems .= $aCartInfo['vendor_id'] . '_' . $aItem['module_id'] . '_' . $aItem['id'] . '_' . $aItem['quantity'] . ':';
+
+        $sQuery = $this->prepare("INSERT INTO `" . $this->_sPrefix . "transactions_pending` SET
+                    `client_id`=?,
+                    `seller_id`=?,
+                    `items`=?,
+                    `amount`=?,
+                    `provider`=?,
+                    `date`=UNIX_TIMESTAMP()", $iClientId, $aCartInfo['vendor_id'], trim($sItems, ':'), $aCartInfo['items_price'], $sProviderName);
+
+        return (int)$this->query($sQuery) > 0 ? $this->lastId() : 0;
+    }
+
+    public function updateOrderPending($iId, $aValues)
+    {
+        $sQuery = $this->prepare("UPDATE `" . $this->_sPrefix . "transactions_pending` SET " . $this->arrayToSQL($aValues) . " WHERE `id`=?", $iId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function cancelOrderPending($mixedId)
+    {
+    	if(!is_array($mixedId))
+    		$mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "transactions_pending` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+    
+    /*
+     * Processed Orders
+     */
+    public function getOrderProcessed($aParams)
+    {
+    	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
+
+        $sWhereClause = "";
+        switch($aParams['type']) {
+            case 'id':
+                $sWhereClause = $this->prepare(" AND `tt`.`id`=?", $aParams['id']);
+                break;
+
+			case 'pending_id':
+                $aMethod['name'] = 'getAll';
+                if(!empty($aParams['with_key'])) {
+					$aMethod['name'] = 'getAllWithKey';
+					$aMethod['params'][1] = $aParams['with_key'];
+                }
+                $sWhereClause = $this->prepare(" AND `tt`.`pending_id`=?", $aParams['pending_id']);
+                break;
+
+            case 'order_id':
+                $aMethod['name'] = 'getAll';
+                $sWhereClause = $this->prepare(" AND `tt`.`order_id`=?", $aParams['order_id']);
+                break;
+
+            case 'mixed':
+                $aMethod['name'] = 'getAll';
+                foreach($aParams['conditions'] as $sKey => $sValue)
+                    $sWhereClause .= $this->prepare(" AND `tt`.`" . $sKey . "`=?", $sValue);
+                break;
+
+        }
+
+        $aMethod['params'][0] = "SELECT
+        		`tt`.`id`,
+                `tt`.`order_id`,
+                `tt`.`client_id`,
+                `tt`.`seller_id`,
+                `tt`.`module_id`,
+                `tt`.`item_id`,
+                `tt`.`item_count`,
+                `tt`.`amount`,
+                `tt`.`date`,
+                `ttp`.`order`,
+                `ttp`.`error_msg`,
+                `ttp`.`provider`
+            FROM `" . $this->_sPrefix . "transactions` AS `tt`
+            LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertOrderProcessed($aValues)
+    {
+        return $this->query("INSERT INTO `" . $this->_sPrefix . "transactions` SET " . $this->arrayToSQL($aValues) . ", `date`=UNIX_TIMESTAMP()");
+    }
+
+	public function updateOrderProcessed($iId, $aValues)
+    {
+        $sQuery = $this->prepare("UPDATE `" . $this->_sPrefix . "transactions` SET " . $this->arrayToSQL($aValues) . " WHERE `id`=?", $iId);
+        return (int)$this->query($sQuery) > 0;
+    }
+
+    public function cancelOrderProcessed($mixedId)
+    {
+    	if(!is_array($mixedId))
+    		$mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "transactions` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    public function getOrderHistory($aParams)
+    {
+        return $this->getOrderProcessed($aParams);
+    }
+
+    //--- Order Administration ---//
+    public function onProfileDelete($iId)
+    {
+    	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=?", $iId);
+    	$this->query($sQuery);
+
+    	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "user_values` WHERE `user_id`=?", $iId);
+    	$this->query($sQuery);
+    }
+}
+
+/** @} */

+ 192 - 0
modules/boonex/payment/classes/BxPaymentDetails.php

@@ -0,0 +1,192 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+bx_import('BxDolForm');
+
+class BxPaymentDetailsFormCheckerHelper extends BxDolFormCheckerHelper
+{
+	function checkHttps ($s)
+    {
+        return empty($s) || substr(BX_DOL_URL_ROOT, 0, 5) == 'https';
+    }
+}
+
+class BxPaymentDetails extends BxDol
+{
+    protected $MODULE;
+	protected $_oModule;
+
+	protected $_sLangsPrefix;
+    protected $_bCollapseFirst;
+
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+
+    	$this->_oModule = BxDolModule::getInstance($this->MODULE);
+
+    	$this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+        $this->_bCollapseFirst = true;
+    }
+
+    public function serviceGetBlockDetails($iUserId = BX_PAYMENT_EMPTY_ID)
+    {
+        if(!$this->_oModule->isLogged())
+			return MsgBox(_t($this->_sLangsPrefix . 'err_required_login'));
+
+        $iUserId = $iUserId != BX_PAYMENT_EMPTY_ID ? $iUserId : $this->_oModule->getProfileId();
+
+		$sContent = $this->getForm($iUserId);
+		if(empty($sContent))
+			$sContent = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        return array(
+        	'content' => $sContent,
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_orders_submenu')
+        );
+    }
+
+    public function getForm($iUserId)
+    {
+        $aInputs = $this->_oModule->_oDb->getForm();
+        if(empty($aInputs))
+            return '';
+
+		$aForm = array(
+            'form_attrs' => array(
+                'id' => 'pmt_details',
+                'name' => 'pmt_details',
+                'action' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=payment-details'),
+                'method' => 'post',
+                'enctype' => 'multipart/form-data'
+            ),
+            'params' => array(
+                'db' => array(
+                    'table' => '',
+                    'key' => 'id',
+                    'uri' => '',
+                    'uri_title' => '',
+                    'submit_name' => 'submit'
+                ),
+                'checker_helper' => 'BxPaymentDetailsFormCheckerHelper'
+            ),
+            'inputs' => array (
+            )
+        );
+
+        $bCollapsed = $this->_bCollapseFirst;
+        $iProviderId = 0;
+        $sProviderName = "";
+        $aUserValues = $this->_oModule->_oDb->getFormData($iUserId);
+        foreach($aInputs as $aInput) {
+            $sReturnDataUrl = $this->_oModule->_oConfig->getUrl('return_data') . $sProviderName . '/' . $iUserId;
+
+            if($iProviderId != $aInput['provider_id']) {
+                if(!empty($iProviderId))
+                    $aForm['inputs']['provider_' . $iProviderId . '_end'] = array(
+                        'type' => 'block_end'
+                    );
+
+                $aForm['inputs']['provider_' . $aInput['provider_id'] . '_begin'] = array(
+                    'type' => 'block_header',
+                    'caption' => _t($aInput['provider_caption']),
+                    'collapsable' => true,
+                    'collapsed' => $bCollapsed
+                );
+
+                $iProviderId = $aInput['provider_id'];
+                $sProviderName = $aInput['provider_name'];
+                $bCollapsed = true;
+            }
+
+            $aForm['inputs'][$aInput['name']] = array(
+				'type' => $aInput['type'],
+                'name' => $aInput['name'],
+                'caption' => _t($aInput['caption']),
+                'value' => isset($aUserValues[$aInput['id']]['value']) ? $aUserValues[$aInput['id']]['value'] : '',
+                'info' => _t($aInput['description']),
+            	'attrs' => array(
+            		'bx-data-provider' => $iProviderId
+            	),
+                'checker' => array (
+                    'func' => $aInput['check_type'],
+                    'params' => $aInput['check_params'],
+                    'error' => _t($aInput['check_error']),
+                )
+            );
+
+            //--- Make some field dependent actions ---//
+            switch($aInput['type']) {
+                case 'select':
+                    if(empty($aInput['extra']))
+                       break;
+
+                    $aAddon = array('values' => array());
+
+                    $aPairs = explode(',', $aInput['extra']);
+                    foreach($aPairs as $sPair) {
+                        $aPair = explode('|', $sPair);
+                        $aAddon['values'][] = array('key' => $aPair[0], 'value' => _t($aPair[1]));
+                    }
+                    break;
+
+                case 'checkbox':
+                    $aForm['inputs'][$aInput['name']]['value'] = 'on';
+                    $aAddon = array('checked' => isset($aUserValues[$aInput['id']]['value']) && $aUserValues[$aInput['id']]['value'] == 'on' ? true : false);
+                    break;
+
+				 case 'value':
+				 	if(str_replace($aInput['provider_option_prefix'], '', $aInput['name']) == 'return_url')
+				 		$aForm['inputs'][$aInput['name']]['value'] = $sReturnDataUrl;
+				 	break;
+            }
+
+            if(!empty($aAddon) && is_array($aAddon))
+                $aForm['inputs'][$aInput['name']] = array_merge($aForm['inputs'][$aInput['name']], $aAddon);
+        }
+
+        $aForm['inputs']['provider_' . $iProviderId . '_end'] = array(
+            'type' => 'block_end'
+        );
+        $aForm['inputs']['submit'] = array(
+            'type' => 'submit',
+            'name' => 'submit',
+            'value' => _t($this->_sLangsPrefix . 'form_details_input_do_submit'),
+        );
+
+        bx_import('BxTemplFormView');
+        $oForm = new BxTemplFormView($aForm);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            $aOptions = $this->_oModule->_oDb->getOptions();
+            foreach($aOptions as $aOption) {
+            	$sValue = bx_get($aOption['name']) !== false ? bx_get($aOption['name']) : '';
+                $this->_oModule->_oDb->updateOption($iUserId, $aOption['id'], bx_process_input($sValue, BX_TAGS_STRIP));
+            }
+
+            header('Location: ' . $oForm->aFormAttrs['action']);
+        }
+        else {
+        	foreach($oForm->aInputs as $aInput)
+        		if(!empty($aInput['error'])) {
+        			$iProviderId = (int)$aInput['attrs']['bx-data-provider'];
+        			$oForm->aInputs['provider_' . $iProviderId . '_begin']['collapsed'] = false;
+        		}
+
+			return $oForm->getCode();
+        }
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/payment/classes/BxPaymentFormView.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Developer Developer
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentFormView extends BxTemplStudioFormView
+{
+    function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+    }
+}
+
+/** @} */

+ 35 - 0
modules/boonex/payment/classes/BxPaymentGridHistory.php

@@ -0,0 +1,35 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ * 
+ * @{
+ */
+
+
+class BxPaymentGridHistory extends BxBaseModPaymentGridOrders
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sOrdersType = 'history';
+    }
+
+	protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+		if(empty($this->_aQueryAppend['client_id']))
+			return array();
+
+		$this->_aOptions['source'] .= $this->_oModule->_oDb->prepare(" AND `tt`.`client_id`=?", $this->_aQueryAppend['client_id']);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 90 - 0
modules/boonex/payment/classes/BxPaymentGridPending.php

@@ -0,0 +1,90 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ * 
+ * @{
+ */
+
+
+class BxPaymentGridPending extends BxBaseModPaymentGridOrders
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sOrdersType = 'pending';
+    }
+
+	public function performActionProcess()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId)
+                return echoJson(array());
+
+            $aIds = array($iId);
+        }
+
+        $iId = (int)$aIds[0];
+
+    	$sAction = 'process';
+        $sFormObject = $this->_oModule->_oConfig->getObject('form_pendings');
+        $sFormDisplay = $this->_oModule->_oConfig->getObject('display_pendings_process');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+
+        $oForm->aInputs['id']['value'] = $iId;
+        $oForm->aInputs['seller_id']['value'] = $this->_aQueryAppend['seller_id'];
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+        	$iId = $oForm->getCleanValue('id');
+
+			$this->_oModule->_oDb->updateOrderPending($iId, array(
+				'order' => $oForm->getCleanValue('order'),
+				'error_code' => 0,
+				'error_msg' => 'Manually processed'
+			));
+
+            if($this->_oModule->getObjectCart()->updateInfo($iId))
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t($this->_sLangsPrefix . 'err_cannot_perform'));
+
+            return echoJson($aRes);
+        }
+
+        $sKey = 'order_' . $this->_sOrdersType . '_process';
+        $sId = $this->_oModule->_oConfig->getHtmlIds($sKey);
+    	$sTitle = _t($this->_sLangsPrefix . 'grid_orders_popup_' . $sKey);
+
+		$sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('order_pending_process.html', array(
+			'form_id' => $oForm->aFormAttrs['id'],
+			'form' => $oForm->getCode(true),
+			'object' => $this->_sObject,
+			'action' => $sAction
+		)));
+
+		echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+	protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+    	if(empty($this->_aQueryAppend['seller_id']))
+    		return array();
+
+		$this->_aOptions['source'] .= $this->_oModule->_oDb->prepare(" AND `tt`.`seller_id`=?", $this->_aQueryAppend['seller_id']);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 124 - 0
modules/boonex/payment/classes/BxPaymentGridProcessed.php

@@ -0,0 +1,124 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ * 
+ * @{
+ */
+
+
+class BxPaymentGridProcessed extends BxBaseModPaymentGridOrders
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sOrdersType = 'processed';
+    }
+
+    public function performActionAdd()
+    {
+    	$sAction = 'add';
+    	$sJsObject = $this->_oModule->_oConfig->getJsObject('processed');
+
+        $sFormObject = $this->_oModule->_oConfig->getObject('form_processed');
+        $sFormDisplay = $this->_oModule->_oConfig->getObject('display_processed_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+
+        $oForm->aInputs['seller_id']['value'] = $this->_aQueryAppend['seller_id'];
+
+        $oForm->aInputs['client_id']['attrs'] = array(
+        	'id' => $this->_oModule->_oConfig->getHtmlIds('processed', 'order_processed_client_id'),
+        );
+        $oForm->aInputs['client']['attrs'] = array(
+        	'id' => $this->_oModule->_oConfig->getHtmlIds('processed', 'order_processed_client'),
+        );
+
+        $oForm->aInputs['module_id']['attrs'] = array(
+			'onchange' => 'javascript:' . $sJsObject . '.paOnSelectModule(this);'
+		);
+        $oForm->aInputs['module_id']['values'] = array(
+            array('key' => '0', 'value' => _t('_Select_one'))
+        );
+
+        $aModules = $this->_oModule->_oDb->getModules();
+        foreach($aModules as $aModule)
+           $oForm->aInputs['module_id']['values'][] = array('key' => $aModule['id'], 'value' => $aModule['title']);
+
+		$oForm->aInputs['items']['content'] = $this->_oModule->_oTemplate->displayItems();
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+        	$sFormMethod = $oForm->aFormAttrs['method'];
+
+        	$aItemIds = $oForm->getSubmittedValue('items', $sFormMethod);
+        	if(empty($aItemIds) || !is_array($aItemIds))
+            	return echoJson(array('msg' => $this->_sLangsPrefix . 'err_empty_items'));
+
+			$aItems = array();
+			foreach($aItemIds as $iItemId) {
+	            $iItemId = (int)$iItemId;
+	            $fItemPrice = (float)$oForm->getSubmittedValue('item-price-' . $iItemId, $sFormMethod);
+	            $iItemQuantity = (int)$oForm->getSubmittedValue('item-quantity-' . $iItemId, $sFormMethod);
+
+	            if($iItemQuantity <= 0)
+	                return echoJson(array('msg' => $this->_sLangsPrefix . 'err_wrong_quantity'));
+
+				$aItems[] = array('id' => $iItemId, 'price' => $fItemPrice, 'quantity' => $iItemQuantity);
+			}
+
+        	$mixedResult = $this->_oModule->getObjectOrders()->addOrder(array(
+        		'provider' => 'manual',
+        		'error_code' => 0,
+        		'error_msg' => 'Manually processed',
+        		'seller_id' => $oForm->getCleanValue('seller_id'),
+        		'client_id' => $oForm->getCleanValue('client_id'),
+        		'order' => $oForm->getCleanValue('order'),
+        		'module_id' => $oForm->getCleanValue('module_id'),
+        		'items' => $aItems
+        	));
+        	if(is_array($mixedResult))
+        		return echoJson($mixedResult);
+
+			$iPendingId = (int)$mixedResult;
+        	if(!$this->_oModule->getObjectCart()->updateInfo($iPendingId))
+        		return echoJson(array('msg' => _t($this->_sLangsPrefix . 'err_cannot_perform')));
+
+			$aOrders = $this->_oModule->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => $iPendingId, 'with_key' => 'id'));
+            return echoJson(array('grid' => $this->getCode(false), 'blink' => array_keys($aOrders)));
+        }
+
+        $sKey = 'order_' . $this->_sOrdersType . '_add';
+        $sId = $this->_oModule->_oConfig->getHtmlIds($sKey);
+    	$sTitle = _t($this->_sLangsPrefix . 'grid_orders_popup_' . $sKey);
+
+		$sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('order_processed_add.html', array(
+			'js_object' => $sJsObject,
+			'form_id' => $oForm->aFormAttrs['id'],
+			'form' => $oForm->getCode(true),
+			'object' => $this->_sObject,
+			'action' => $sAction
+		)));
+
+		echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+	protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+    	if(empty($this->_aQueryAppend['seller_id']))
+    		return array();
+
+		$this->_aOptions['source'] .= $this->_oModule->_oDb->prepare(" AND `tt`.`seller_id`=?", $this->_aQueryAppend['seller_id']);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 118 - 0
modules/boonex/payment/classes/BxPaymentJoin.php

@@ -0,0 +1,118 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentJoin extends BxBaseModPaymentJoin
+{
+    protected $_sLangsPrefix;
+
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+    }
+
+    /*
+     * Service methods
+     * 
+     * TODO: Should be tested when paid memberships with "Paid Before Join" or some similar feature will appear.
+     */
+	public function serviceGetBlockJoin()
+    {
+    	$sSessionKeyPending = $this->_oModule->_oConfig->getKey('session_key_pending');
+    	$sRequestKeyPending = $this->_oModule->_oConfig->getKey('request_key_pending');
+
+    	$oSession = BxDolSession::getInstance();
+    	$iPendingId = (int)$oSession->getValue($sSessionKeyPending);
+
+    	if(empty($iPendingId) && bx_get($sRequestKeyPending) !== false) {
+    		$iPendingId = (int)bx_get($sRequestKeyPending);
+
+    		$oSession->setValue($sSessionKeyPending, $iPendingId);
+    	}
+
+		if(empty($iPendingId))
+			return MsgBox(_t($this->_sLangsPrefix . 'err_not_allowed'));
+
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+	    if(empty($aPending['order']) || (int)$aPending['error_code'] != 1)
+			return MsgBox(_t($this->_sLangsPrefix . 'err_not_processed'));
+
+		if((int)$aPending['processed'] == 1)
+			return MsgBox(_t($this->_sLangsPrefix . 'err_already_processed'));
+
+		//--- 'System' -> 'Join after Payment' for Alerts Engine ---//
+		$bOverride = false;
+		$sOverrideError = '';
+
+		bx_import('BxDolAlerts');
+        $oAlert = new BxDolAlerts('system', 'join_after_payment', 0, 0, array('override' => &$bOverride, 'override_error' => &$sOverrideError));
+        $oAlert->alert();
+
+        if($bOverride)
+        	return;
+		//--- 'System' -> 'Join after Payment' for Alerts Engine ---//
+
+    	$sContent = BxDolService::call('system', 'create_account_form', array(array('action' => $this->_oModule->_oConfig->getUrl('join'))), 'TemplServiceAccount');
+    	if(!empty($sOverrideError))
+    		$sContent = MsgBox(_t($sOverrideError)) . $sContent;
+
+		return array(
+        	'content' => $sContent
+		);
+    }
+
+	public function performJoin($iPendingId, $aPayment = array())
+    {
+		BxDolSession::getInstance()->setValue($this->_oModule->_oConfig->getKey('session_key_pending'), (int)$iPendingId);
+
+		if(!empty($aPayment['payer_name']) && !empty($aPayment['payer_email'])) {
+			bx_import('BxDolEmailTemplates');
+			$oEmailTemplates = new BxDolEmailTemplates();
+
+			$aTemplate = $oEmailTemplates->parseTemplate($this->_oModule->_oConfig->getPrefix('general') . 'paid_need_join', array(
+				'RealName' => $aPayment['payer_name'],
+				'JoinLink' => $this->_oModule->_oConfig->getUrl('join', array($this->_oModule->_oConfig->getKey('request_key_pending') => (int)$iPendingId))
+			));
+
+			sendMail($aPayment['payer_email'], $aTemplate['Subject'], $aTemplate['Body'], 0, array(), 'html', false, true);
+		}
+
+		header('Location: ' . $this->_oModule->_oConfig->getUrl('join'));
+		exit;
+	}
+
+	public function onProfileJoin($iProfileId)
+    {
+    	$sSessionKeyPending = $this->_oModule->_oConfig->getKey('session_key_pending');
+
+    	$oSession = BxDolSession::getInstance();
+		$iPendingId = (int)$oSession->getValue($sSessionKeyPending);
+
+        if(empty($iProfileId) || empty($iPendingId))
+        	return;
+ 
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+		if(empty($aPending) || (isset($aPending['client_id']) && (int)$aPending['client_id'] != 0))
+			return;
+
+		if(!$this->_oModule->_oDb->updateOrderPending($iPendingId, array('client_id' => $iProfileId)))
+			return;
+
+		$this->_oModule->getObjectCart()->updateInfo($iPendingId);
+
+		$oSession->unsetValue($sSessionKeyPending);
+    }
+}
+
+/** @} */

+ 364 - 0
modules/boonex/payment/classes/BxPaymentModule.php

@@ -0,0 +1,364 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+define('BX_PAYMENT_ORDERS_TYPE_PENDING', 'pending');
+define('BX_PAYMENT_ORDERS_TYPE_PROCESSED', 'processed');
+define('BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION', 'subscription');
+define('BX_PAYMENT_ORDERS_TYPE_HISTORY', 'history');
+
+define('BX_PAYMENT_EMPTY_ID', 0);
+
+define('BX_PAYMENT_RESULT_SUCCESS', 0);
+
+/**
+ * Payment module by BoonEx
+ *
+ * This module is needed to work with payment providers and organize the process
+ * of some item purchasing. Shopping Cart and Orders Manager are included.
+ *
+ * Integration notes:
+ * To integrate your module with this one, you need:
+ * 1. Get 'Add To Cart' button using serviceGetAddToCartLink service.
+ * 2. Add info about your module in the 'bx_pmt_modules' table.
+ * 3. Realize the following service methods in your Module class.
+ *   a. serviceGetItems($iVendorId) - Is used in Orders Administration to get all products of the requested seller(vendor).
+ *   b. serviceGetCartItem($iClientId, $iItemId) - Is used in Shopping Cart to get one product by specified id.
+ *   c. serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrderId) - Register purchased product.
+ *   d. serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrderId) - Unregister the product purchased earlier.
+ * @see You may see an example of integration in Membership module.
+ *
+ *
+ * Profile's Wall:
+ * no spy events
+ *
+ *
+ *
+ * Spy:
+ * no spy events
+ *
+ *
+ *
+ * Memberships/ACL:
+ * Doesn't depend on user's membership.
+ *
+ *
+ *
+ * Service methods:
+ *
+ * Is used to get "Add to cart" link for some item(s) in your module.
+ * @see BxPmtModule::serviceGetAddToCartLink
+ * BxDolService::call('payment', 'get_add_to_cart_link', array($iVendorId, $mixedModuleId, $iItemId, $iItemCount));
+ *
+ * Check transaction(s) in database which satisty all conditions.
+ * @see BxPmtModule::serviceGetTransactionsInfo
+ * BxDolService::call('payment', 'get_transactions_info', array($aConditions));
+ *
+ * Get total count of items in Shopping Cart.
+ * @see BxPmtModule::serviceGetCartItemsCount
+ * BxDolService::call('payment', 'get_cart_items_count', array($iUserId, $iOldCount));
+ * @note is needed for internal usage(integration with member tool bar).
+ *
+ * Get Shopping cart content.
+ * @see BxPmtModule::serviceGetCartItems
+ * BxDolService::call('payment', 'get_cart_items');
+ * @note is needed for internal usage(integration with member tool bar).
+ *
+ *
+ * Alerts:
+ * no alerts available
+ *
+ */
+class BxPaymentModule extends BxBaseModPaymentModule
+{
+    protected $_iUserId;
+
+    protected $_aOrderTypes;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_iUserId = $this->getProfileId();
+
+        $this->_aOrderTypes = array(
+        	BX_PAYMENT_ORDERS_TYPE_PENDING, 
+        	BX_PAYMENT_ORDERS_TYPE_PROCESSED, 
+        	BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION, 
+        	BX_PAYMENT_ORDERS_TYPE_HISTORY
+        );
+    }
+
+    /**
+     * Manage Orders Methods
+     */
+	public function actionGetClients()
+    {
+        $sTerm = bx_get('term');
+
+        $aResult = BxDolService::call('system', 'profiles_search', array($sTerm), 'TemplServiceProfiles');
+
+        echoJson($aResult);
+    }
+
+    public function actionGetItems($iModuleId)
+    {
+    	$iSellerId = $this->getProfileId();
+        $aItems = $this->callGetCartItems((int)$iModuleId, array($iSellerId));
+
+        $aResult = array('code' => 0);
+        if(is_array($aItems) && !empty($aItems))
+            $aResult['data'] = $this->_oTemplate->displayItems($aItems);
+
+		echoJson($aResult);
+    }
+
+
+    /**
+     * Payment Details Methods
+     */
+    public function serviceGetOptionsSiteAdmin()
+    {
+        $aResult = array(
+            array('key' => '', 'value' => _t('_Select_one'))
+        );
+
+        $aIds = $this->_oDb->getAdminsIds();
+        foreach($aIds as $iId) {
+        	$aUser = $this->getProfileInfo($iId);
+
+            $aResult[] = array(
+                'key' => $iId,
+                'value' => $aUser['name']
+            );
+        }
+
+        return $aResult;
+    }
+
+    /**
+     * Check transaction(s) in database which satisty all conditions.
+     *
+     * @param array $aConditions an array of pears('key' => 'value'). Available keys are the following:
+     * a. order_id - internal order ID (string)
+     * b. client_id - client's ID (integer)
+     * c. seller_id - seller's ID (integer)
+     * d. module_id - modules's where the purchased product is located. (integer)
+     * e. item_id - item id in the database. (integer)
+     * f. date - the date when the payment was processed(UNIXTIME STAMP)
+     *
+     * @return array of transactions. Each transaction has full info(client ID, seller ID, external transaction ID, date and so on)
+     */
+    public function serviceGetTransactionsInfo($aConditions)
+    {
+        return $this->_oDb->getOrderProcessed(array('type' => 'mixed', 'conditions' => $aConditions));
+    }
+
+
+    /**
+     * Cart Processing Methods
+     */
+    public function actionCartSubmit()
+    {
+    	if(!$this->isLogged())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+        if(bx_get('bx-payment-delete') !== false && bx_get('items') !== false){
+        	$aItems = bx_get('items');
+            foreach($aItems as $sItem) {
+                list($iVendorId, $iModuleId, $iItemId, $iItemCount) = $this->_oConfig->descriptorS2A($sItem);
+                $this->getObjectCart()->serviceDeleteFromCart($iVendorId, $iModuleId, $iItemId);
+            }
+        }
+		else if(bx_get('bx-payment-checkout') !== false && bx_get('items') !== false) {
+			$iVendorId = (int)bx_get('vendor_id');
+			$sProvider = bx_process_input(bx_get('provider'));
+			$aItems = bx_get('items');
+
+			$sError = $this->serviceInitializeCheckout($iVendorId, $sProvider, $aItems);
+			if(!empty($sError))
+	    		return $this->_oTemplate->displayPageCodeError($sError, false);
+		}
+
+        header('Location: ' . $this->_oConfig->getUrl('cart'));
+        exit;
+    }
+
+    public function actionAddToCart($iVendorId, $iModuleId, $iItemId, $iItemCount)
+    {
+        $aResult = $this->getObjectCart()->serviceAddToCart($iVendorId, $iModuleId, $iItemId, $iItemCount);
+		echoJson($aResult);
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionDeleteFromCart($iVendorId, $iModuleId, $iItemId)
+    {
+        $aResult = $this->getObjectCart()->serviceDeleteFromCart($iVendorId, $iModuleId, $iItemId);
+        echoJson($aResult);
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionEmptyCart($iVendorId)
+    {
+        $aResult = $this->getObjectCart()->serviceDeleteFromCart($this->_iUserId, $iVendorId);
+		echoJson($aResult);
+    }
+
+
+    /**
+     * Payment Processing Methods
+     */
+	public function serviceInitializeCheckout($iVendorId, $sProvider, $aItems = array())
+	{
+		if(!is_array($aItems))
+			$aItems = array($aItems);
+
+		$iVendorId = (int)$iVendorId;
+        if($iVendorId == BX_PAYMENT_EMPTY_ID)
+            return MsgBox(_t($this->_sLangsPrefix . 'err_unknown_vendor'));
+
+		$oProvider = $this->getObjectProvider($sProvider, $iVendorId);
+        if($oProvider === false)
+        	return MsgBox(_t($this->_sLangsPrefix . 'err_incorrect_provider'));
+
+        $aInfo = $this->getObjectCart()->getInfo($this->_iUserId, $iVendorId, $aItems);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return MsgBox(_t($this->_sLangsPrefix . 'err_empty_order'));
+
+		/*
+		 * Process FREE (price = 0) items for LOGGED IN members
+		 * WITHOUT processing via payment provider.
+		 */
+		$bProcessedFree = false;
+		foreach($aInfo['items'] as $iIndex => $aItem)
+			if((int)$aInfo['client_id'] != 0 && (float)$aItem['price'] == 0) {
+				$aItemInfo = $this->callRegisterCartItem((int)$aItem['module_id'], array($aInfo['client_id'], $aInfo['vendor_id'], $aItem['id'], $aItem['quantity'], $this->_oConfig->getLicense()));
+	            if(is_array($aItemInfo) && !empty($aItemInfo))
+	            	$bProcessedFree = true;
+
+	            $aInfo['items_count'] -= 1;
+	            unset($aInfo['items'][$iIndex]);
+
+	            $sCartItems = $this->_oDb->getCartItems($aInfo['client_id']);
+	            $sCartItems = trim(preg_replace("'" . $this->_oConfig->descriptorA2S(array($aInfo['vendor_id'], $aItem['module_id'], $aItem['id'], $aItem['quantity'])) . ":?'", "", $sCartItems), ":");
+	            $this->_oDb->setCartItems($aInfo['client_id'], $sCartItems);
+			}
+
+		if(empty($aInfo['items']))
+            return MsgBox(_t($this->_sLangsPrefix . ($bProcessedFree ? 'msg_successfully_processed_free' : 'err_empty_order')));
+
+        $iPendingId = $this->_oDb->insertOrderPending($this->_iUserId, $sProvider, $aInfo);
+        if(empty($iPendingId))
+            return MsgBox(_t($this->_sLangsPrefix . 'err_access_db'));
+
+		/*
+		 * Perform Join WITHOUT processing via payment provider
+		 * if a client ISN'T logged in and has only ONE FREE item in the card.
+		 */
+		if((int)$aInfo['client_id'] == 0 && (int)$aInfo['items_count'] == 1) {
+			reset($aInfo['items']);
+			$aItem = current($aInfo['items']);
+
+			if(!empty($aItem) && $aItem['price'] == 0) {
+				$this->_oDb->updateOrderPending($iPendingId, array(
+		            'order' => $this->_oConfig->getLicense(),
+		            'error_code' => '1',
+		            'error_msg' => ''
+		        ));
+
+				$this->getObjectJoin()->performJoin($iPendingId);
+			}
+		}
+
+		$sError = $oProvider->initializeCheckout($iPendingId, $aInfo);
+		if(!empty($sError))
+			return MsgBox($sError);
+
+        return true;
+	}
+
+    public function actionFinalizeCheckout($sProvider, $mixedVendorId = "")
+    {
+        $aData = &$_REQUEST;
+
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false)
+        	return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $aResult = $oProvider->finalizeCheckout($aData);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) 
+        	return $this->_oTemplate->displayPageCodeError($aResult['message']);
+
+		$aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$aResult['pending_id']));
+
+		//--- Check "Pay Before Join" situation
+		if((int)$aPending['client_id'] == 0)
+			$this->getObjectJoin()->performJoin((int)$aPending['id'], $aResult);
+
+		//--- Register payment for purchased items in associated modules 
+		$this->getObjectCart()->updateInfo($aPending);
+
+		if($oProvider->needRedirect()) {
+			header('Location: ' . $this->_oConfig->getUrl('return'));
+			exit;
+		}
+
+		return $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+    }
+
+    public function actionCheckoutFinished($sProvider, $mixedVendorId = "")
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false)
+        	return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $aResult = $oProvider->checkoutFinished();
+
+        $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+        exit;
+    }
+
+
+    public function onProfileJoin($iProfileId)
+    {
+    	$this->getObjectJoin()->onProfileJoin($iProfileId);
+    }
+
+    public function onProfileDelete($iProfileId)
+    {
+		$this->_oDb->onProfileDelete($iProfileId);
+    }
+
+    public function isAllowedSell($aItem, $bPerform = false)
+    {
+		$iUserId = (int)$this->getProfileId();
+        if(!$iUserId)
+        	return false;
+
+		$aItemInfo = $this->callGetCartItem($aItem['module_id'], array($aItem['item_id']));
+		if(empty($aItemInfo))
+			return false;
+
+        if(isAdmin())
+            return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'sell', $this->getName(), $bPerform);
+        if((int)$aItemInfo['author_id'] == $iUserId && $aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
+			return true;
+
+        return $aCheckResult[CHECK_ACTION_MESSAGE];
+    }
+}
+
+/** @} */

+ 101 - 0
modules/boonex/payment/classes/BxPaymentOrders.php

@@ -0,0 +1,101 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentOrders extends BxBaseModPaymentOrders
+{
+    protected $_sLangsPrefix;
+
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+    }
+
+	/*
+     * Service methods
+     */
+	public function serviceGetBlockOrders($sType = '', $iUserId = BX_PAYMENT_EMPTY_ID)
+    {
+    	if(empty($sType))
+    		$sType = bx_get('type') !== false ? bx_process_input(bx_get('type')) : BX_PAYMENT_ORDERS_TYPE_PROCESSED;
+
+    	if(!$this->_oModule->isLogged())
+            return MsgBox(_t($this->_sLangsPrefix . 'err_required_login'));
+
+        $iUserId = $iUserId != BX_PAYMENT_EMPTY_ID ? $iUserId : $this->_oModule->getProfileId();
+        return array(
+        	'title' => _t($this->_sLangsPrefix . 'page_block_title_orders_' . $sType),
+        	'content' => $this->_oModule->_oTemplate->displayBlockOrders($sType, $iUserId),
+        	'menu' => $this->_oModule->_oConfig->getObject('menu_orders_submenu')
+        );
+    }
+
+	public function addOrder($aData)
+    {
+        $iSellerId = isset($aData['seller_id']) ? (int)$aData['seller_id'] : $this->_oModule->getProfileId();
+        if($iSellerId == $aData['client_id'])
+            return array('msg' => $this->_sLangsPrefix . 'err_purchase_from_yourself');
+
+        $sOrder = trim($aData['order']);
+        if(empty($sOrder))
+            return array('msg' => $this->_sLangsPrefix . 'form_processed_input_order_err');
+
+        $aCartInfo = array('vendor_id' => $iSellerId, 'items_price' => 0, 'items' => array());
+        foreach($aData['items'] as $aItem) {
+        	if(!$this->_oModule->isAllowedSell(array('module_id' => $aData['module_id'], 'item_id' => $aItem['id']), true))
+        		continue;
+
+            $aCartInfo['items_price'] += $aItem['price'] * $aItem['quantity'];
+            $aCartInfo['items'][] = array(
+                'vendor_id' => $iSellerId,
+                'module_id' => $aData['module_id'],
+                'id' => $aItem['id'],
+                'quantity' => $aItem['quantity']
+            );
+        }
+
+        $iPendingId = $this->_oModule->_oDb->insertOrderPending($aData['client_id'], $aData['provider'], $aCartInfo);
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrder,
+            'error_code' => $aData['error_code'],
+            'error_msg' => $aData['error_msg']
+        ));
+
+        return (int)$iPendingId;
+    }
+
+    public function getOrder($sType, $iId)
+    {
+        return $this->_oModule->_oTemplate->displayOrder($sType, $iId);
+    }
+
+    public function cancel($sType, $iOrderId)
+    {
+    	$sMethodName = "getOrder" . bx_gen_method_name($sType);
+    	$aOrder = $this->_oModule->_oDb->$sMethodName(array('type' => 'id', 'id' => $iOrderId));
+		if(empty($aOrder) || !is_array($aOrder))
+	    	return true;
+
+		if($sType == BX_PAYMENT_ORDERS_TYPE_PROCESSED && !BxDolService::call((int)$aOrder['module_id'], 'unregister_cart_item', array($aOrder['client_id'], $aOrder['seller_id'], $aOrder['item_id'], $aOrder['item_count'], $aOrder['order_id'])))
+			return false;
+
+		$sMethodName = "cancelOrder" . bx_gen_method_name($sType);
+		if(!$this->_oModule->_oDb->$sMethodName($iOrderId))
+			return false;
+
+        return true;
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/payment/classes/BxPaymentPageCart.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentPageCart extends BxTemplPage
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/payment/classes/BxPaymentPageDetails.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentPageDetails extends BxTemplPage
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/payment/classes/BxPaymentPageHistory.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentPageHistory extends BxTemplPage
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/payment/classes/BxPaymentPageJoin.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentPageJoin extends BxTemplPage
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/payment/classes/BxPaymentPageOrders.php

@@ -0,0 +1,20 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentPageOrders extends BxTemplPage
+{
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 143 - 0
modules/boonex/payment/classes/BxPaymentProvider2Checkout.php

@@ -0,0 +1,143 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+define('TUCO_MODE_LIVE', 1);
+define('TUCO_MODE_TEST', 2);
+
+define('TUCO_PAYMENT_METHOD_CC', 'CC');
+define('TUCO_PAYMENT_METHOD_CK', 'CK');
+define('TUCO_PAYMENT_METHOD_AL', 'AL');
+define('TUCO_PAYMENT_METHOD_PPI', 'PPI');
+
+class BxPaymentProvider2Checkout extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    protected $_sDataReturnUrl;
+
+    function __construct($aConfig)
+    {
+		$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_bRedirectOnResult = true;
+        $this->_sDataReturnUrl = $this->_oModule->_oConfig->getUrl('return_data') . $this->_sName . '/';
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0)
+    {
+    	$bTest = (int)$this->getOption('mode') == TUCO_MODE_TEST;
+
+        $aFormData = array(
+            'sid' => $this->getOption('account_id'),
+        	'mode' => '2CO',
+        	'demo' => $bTest ? 'Y' : '',
+        	'merchant_order_id' => $iPendingId,
+            'total' => sprintf("%.2f", (float)$aCartInfo['items_price']),
+        	'currency_code' => $aCartInfo['vendor_currency_code'],
+            'pay_method' => $this->getOption('payment_method'),
+            'x_receipt_link_url' => $this->_sDataReturnUrl . $aCartInfo['vendor_id']
+        );
+
+        $iIndex = 0;
+        foreach($aCartInfo['items'] as $aItem) {
+        	$aFormData['li_' . $iIndex . '_type'] = 'product';
+            $aFormData['li_' . $iIndex . '_name'] = $aItem['title'];
+            $aFormData['li_' . $iIndex . '_price'] = $aItem['price'];
+            $aFormData['li_' . $iIndex . '_quantity'] = $aItem['quantity'];
+            $aFormData['li_' . $iIndex . '_tangible'] = 'N';
+
+            $iIndex++;
+        }
+
+        $sActionURL = 'https://' . ($bTest ? 'sandbox' : 'www') . '.2checkout.com/checkout/purchase';
+        $this->_oModule->_oTemplate->displayPageCodeRedirect($sActionURL, $aFormData);
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        return $this->_registerCheckout($aData);
+    }
+
+	public function checkoutFinished() {}
+
+    /**
+     *
+     * @param $aData - data from payment provider.
+     * @param $bSubscription - Is not needed. May be used in the future for subscriptions.
+     * @param $iPendingId - Is not needed. May be used in the future for subscriptions.
+     * @return array with results.
+     */
+    protected function _registerCheckout(&$aData, $bSubscription = false, $iPendingId = 0)
+    {
+        if(empty($this->_aOptions) && isset($aData['merchant_order_id']))
+            $this->_aOptions = $this->getOptionsByPending($aData['merchant_order_id']);
+
+        if(empty($this->_aOptions))
+            return array('code' => 2, 'message' => _t('_payment_2co_err_no_vendor_given'));
+
+        $aResult = $this->_validateCheckout($aData);
+
+        if(empty($aResult['pending_id']))
+            return $aResult;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$aResult['pending_id']));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 6, 'message' => _t('_payment_2co_err_already_processed'));
+
+        $this->_oModule->_oDb->updateOrderPending((int)$aResult['pending_id'], array(
+            'order' => $aData['order_number'],
+            'error_code' => $aResult['code'],
+            'error_msg' => $aResult['message']
+        ));
+        return $aResult;
+    }
+
+    protected function _validateCheckout(&$aData)
+    {
+        if(empty($aData['order_number']) || empty($aData['total']) || empty($aData['key']) || empty($aData['merchant_order_id']))
+            return array('code' => 3, 'message' => _t('_payment_2co_err_no_data_given'));
+
+        $sOrder = bx_process_input($aData['order_number'], BX_TAGS_STRIP);
+        $sAmount = bx_process_input($aData['total'], BX_TAGS_STRIP);
+        $iPendingId = (int)$aData['merchant_order_id'];
+
+        if($aData['key'] != $this->_generateKey($sOrder, $sAmount))
+            return array('code' => 4, 'message' => _t('_payment_2co_err_wrong_key'), 'pending_id' => $iPendingId);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if((float)$sAmount != (float)$aPending['amount'])
+            return array('code' => 5, 'message' => _t('_payment_2co_err_wrong_payment'), 'pending_id' => $iPendingId);
+
+		$sBuyerFirstName = bx_process_input($aData['first_name'], BX_TAGS_STRIP);
+        $sBuyerLastName = bx_process_input($aData['last_name'], BX_TAGS_STRIP);
+        $sBuyerEmail = bx_process_input($aData['email'], BX_TAGS_STRIP);
+
+        return array(
+        	'code' => 1, 
+        	'message' => _t('_payment_2co_msg_verified'), 
+        	'pending_id' => $iPendingId,
+        	'payer_name' => _t('_payment_txt_buyer_name_mask', $sBuyerFirstName, $sBuyerLastName),
+        	'payer_email' => $sBuyerEmail
+        );
+    }
+
+    protected function _generateKey($sOrder, $sAmount)
+    {
+    	if((int)$this->getOption('mode') == TUCO_MODE_TEST)
+    		$sOrder = '1';
+
+        $sKey = $this->getOption('secret_word') . $this->getOption('account_id') . $sOrder . $sAmount;
+        return strtoupper(md5($sKey));
+    }
+}
+
+/** @} */

+ 585 - 0
modules/boonex/payment/classes/BxPaymentProviderBitPay.php

@@ -0,0 +1,585 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+define('BP_STATUS_NEW', 'new');
+define('BP_STATUS_PAID', 'paid');
+define('BP_STATUS_CONFIRMED', 'confirmed');
+define('BP_STATUS_COMPLETE', 'complete');
+define('BP_STATUS_EXPIRED', 'expired');
+define('BP_STATUS_INVALID', 'invalid');
+
+define('BP_SPEED_HIGH', 'high');
+define('BP_SPEED_MEDIUM', 'medium');
+define('BP_SPEED_LOW', 'low');
+
+class BxPaymentProviderBitPay extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_bRedirectOnResult = false;
+
+        $this->_initializeOptions();
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0)
+    {
+    	$this->aBpOptions['redirectURL'] .= $aCartInfo['vendor_id'];
+
+    	$this->aBpOptions['notificationURL'] .= $aCartInfo['vendor_id'];
+    	$this->aBpOptions['notificationURL'] = bx_append_url_params($this->aBpOptions['notificationURL'], array('bxssl' => 1));
+
+	    switch ($aCartInfo['vendor_currency_code']) {
+			case 'USD':
+			case 'EUR':
+			case 'BTC':
+				$this->aBpOptions['currency'] = $aCartInfo['vendor_currency_code'];
+		}
+
+		$aPosData = array(
+			'vnd' => (string)$aCartInfo['vendor_id'], 
+			'clt' => (string)$aCartInfo['client_id'], 
+			'pnd' => (string)$iPendingId
+		);
+		$aOptions = array(
+			'itemDesc' => 'Payment to ' . $aCartInfo['vendor_profile_name']
+		);
+		$aResponse = $this->createInvoice($iPendingId, (float)$aCartInfo['items_price'], $aPosData, $aOptions);
+		if(!empty($aResponse['error']))
+			return _t(is_array($aResponse['error']) ? $aResponse['error']['message'] : $aResponse['error']);
+
+		header('Location: ' . $aResponse['url']);
+		exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+    	$aData = $this->_verifyNotification();
+    	if($aData === false)
+    		return array('code' => 2, 'message' => _t('_payment_bp_err_no_data_given'));
+
+		if(empty($this->_aOptions) && isset($aData['posData']['d']['pnd'])) {
+            $this->_aOptions = $this->getOptionsByPending($aData['posData']['d']['pnd']);
+			if(empty($this->_aOptions))
+            	return array('code' => 3, 'message' => _t('_payment_bp_err_no_vendor_given'));
+
+            $this->_initializeOptions();
+		}
+
+		$aPosData = $this->_verifyPosData($aData['posData']);
+		if($aPosData === false)
+			return array('code' => 4, 'message' => _t('_payment_bp_err_incorrect_data'));
+
+		//--- Update pending transaction ---//
+		$sStatus = $aData['status'];
+		$sMessage = '';
+
+		$sResult = $this->_verifyAmount($aPosData, $aData['price']);
+		if($sResult === false) {
+			$sStatus = BP_STATUS_INVALID;
+			$sMessage = _t('_payment_bp_err_wrong_amount');
+		}
+
+		$iPendingId = (int)$aPosData['pnd'];
+		$sOrderId = Bx_process_input($aData['id']);
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrderId,
+            'error_code' => $sStatus,
+            'error_msg' => $sMessage
+        ));
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if((int)$aPending['processed'] != 0)
+            return array('code' => 6, 'message' => _t('_payment_bp_err_already_processed'));
+
+        //--- Process purchased items in the database if STATUS became CONFIRMED (HIGH and MEDIUM speed), COMPLETE (LOW speed)
+		$sSpeed = $this->aBpOptions['transactionSpeed'];
+		if((in_array($sSpeed, array(BP_SPEED_HIGH, BP_SPEED_MEDIUM)) && $sStatus == BP_STATUS_CONFIRMED) || ($sSpeed == BP_SPEED_LOW && $sStatus == BP_STATUS_COMPLETE))		
+	        return array('code' => 1, 'message' => '', 'pending_id' => $iPendingId);
+
+		return array('code' => 7, 'message' => _t('_payment_bp_err_no_confirmation_given'));
+    }
+
+    public function checkoutFinished()
+    {
+    	return array(
+    		'message' => _t('_payment_bp_msg_checkout_finished')
+    	);
+    }
+
+	/**
+	 *
+	 * Creates BitPay invoice via Bitpay::curl.
+	 *
+	 * @param string $orderId, string $price, string $posData, array $options
+	 * @return array $response
+	 * @throws Exception $e
+	 *
+	 */
+	public function createInvoice($orderId, $price, $posData, $options = array()) {
+		// $orderId: Used to display an orderID to the buyer. In the account summary view, this value is used to
+		// identify a ledger entry if present. Maximum length is 100 characters.
+		//
+		// $price: by default, $price is expressed in the currency you set in Bitpay::aOptions['currency'].
+		//
+		// $posData: this field is included in status updates or requests to get an invoice.  It is intended to be used by
+		// the merchant to uniquely identify an order associated with an invoice in their system.  Aside from that, Bit-Pay does
+		// not use the data in this field.  The data in this field can be anything that is meaningful to the merchant.
+		// Maximum length is 100 characters.
+		//
+		// Note:  Using the posData hash option will APPEND the hash to the posData field and could push you over the 100
+		//        character limit.
+		//
+		// $options keys can include any of:
+		//	'itemDesc', 'itemCode', 'notificationEmail', 'notificationURL', 'redirectURL', 'apiKey'
+		//	'currency', 'physical', 'fullNotifications', 'transactionSpeed', 'buyerName',
+		//	'buyerAddress1', 'buyerAddress2', 'buyerCity', 'buyerState', 'buyerZip', 'buyerEmail', 'buyerPhone'
+		//
+		// If a given option is not provided here, the value of that option will default to what is found in Bitpay::aOptions
+
+		try {
+			$options = array_merge($this->aBpOptions, $options);  // $options override any options found in Bitpay::aOptions
+			$pos = array('d' => $posData);
+
+			if ($this->aBpOptions['verifyPos']) 
+				$pos['h'] = $this->_hash(serialize($posData), $options['apiKey']);
+
+			$options['posData'] = json_encode($pos);
+			if(strlen($options['posData']) > 100)
+				return array('error' => '_payment_bp_err_posdata_exceed_limit');
+
+			$options['orderID'] = $orderId;
+			$options['price'] = $price;
+
+			$postOptions = array('orderID', 'itemDesc', 'itemCode', 'notificationEmail', 'notificationURL', 'redirectURL', 
+	        	'posData', 'price', 'currency', 'physical', 'fullNotifications', 'transactionSpeed', 'buyerName', 
+	            'buyerAddress1', 'buyerAddress2', 'buyerCity', 'buyerState', 'buyerZip', 'buyerEmail', 'buyerPhone');
+
+			foreach($postOptions as $o) {
+				if (array_key_exists($o, $options))
+					$post[$o] = $options[$o];
+			}
+			$post = json_encode($post);
+
+			$response = $this->_curl('https://bitpay.com/api/invoice/', $options['apiKey'], $post);
+
+			if($this->aBpOptions['useLogging']) {
+				$this->_log('Create Invoice: ');
+				$this->_log('-- Data: ' . $post);
+				$this->_log('Response: ');
+				$this->_log($response);
+			}
+
+			return $response;
+
+		}
+		catch (Exception $e) {
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: ' . $e->getMessage());
+
+			return array('error' => $e->getMessage());
+		}
+	}
+
+	/**
+	 *
+	 * Retrieves an invoice from BitPay.  $options can include 'apiKey'
+	 *
+	 * @param string $invoiceId, boolean $apiKey
+	 * @return mixed $json
+	 * @throws Exception $e
+	 *
+	 */
+	public function getInvoice($invoiceId, $apiKey=false) {
+		try {
+			if (!$apiKey)
+				$apiKey = $this->aBpOptions['apiKey'];
+
+			$response = $this->_curl('https://bitpay.com/api/invoice/'.$invoiceId, $apiKey);
+
+			if (is_string($response))
+				return $response; // error
+
+			$response['posData'] = json_decode($response['posData'], true);
+			$response['posData'] = $response['posData']['d'];
+
+			return $response;
+		}
+		catch (Exception $e) {
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: ' . $e->getMessage());
+
+			return 'Error: ' . $e->getMessage();
+		}
+	}
+
+	/**
+	 *
+	 * Retrieves a list of all supported currencies
+	 * and returns associative array.
+	 * 
+	 * @param none
+	 * @return array $currencies
+	 * @throws Exception $e
+	 * 
+	 */
+	function getCurrencyList() {
+		$currencies = array();
+		$rate_url = 'https://bitpay.com/api/rates';
+
+		try {
+			$clist = json_decode(file_get_contents($rate_url),true);
+
+			foreach($clist as $key => $value)
+				$currencies[$value['code']] = $value['name'];
+
+			return $currencies;
+		}
+		catch (Exception $e) {
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: ' . $e->getMessage());
+
+			return 'Error: ' . $e->getMessage();
+		}
+	}
+
+	/**
+	 * 
+	 * Retrieves the current rate based on $code.
+	 * The default code us USD, so calling the 
+	 * function without a parameter will return
+	 * the current BTC/USD price.
+	 * 
+	 * @param string $code
+	 * @return string $rate
+	 * @throws Exception $e
+	 * 
+	 */
+	public function getRate($code = 'USD') {
+		$rate_url = 'https://bitpay.com/api/rates';
+
+		try {
+			$clist = json_decode(file_get_contents($rate_url),true);
+
+			foreach($clist as $key => $value) {
+				if($value['code'] == $code)
+					$rate = number_format($value['rate'], 2, '.', '');
+			}
+
+			return $rate;
+		}
+		catch (Exception $e) {
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: ' . $e->getMessage());
+			return 'Error: ' . $e->getMessage();
+		}
+	}
+
+	protected function _initializeOptions() {
+		// REQUIRED Api key you created at bitpay.com
+		$this->aBpOptions['apiKey'] = $this->getOption('api_key');
+
+		// whether to verify POS data by hashing above api key.  If set to false, you should
+		// have some way of verifying that callback data comes from bitpay.com
+		// note: this option can only be changed here.  It cannot be set dynamically. 
+		$this->aBpOptions['verifyPos'] = true;
+
+		// email where invoice update notifications should be sent
+		$this->aBpOptions['notificationEmail'] = $this->getOption('notification_email');
+
+		// url where bit-pay server should send update notifications.  See API doc for more details.
+		// example: $bpNotificationUrl = 'http://www.example.com/callback.php';
+		$this->aBpOptions['notificationURL'] = $this->_oModule->_oConfig->getUrl('return_data', array(), true) . $this->_sName . '/';
+
+		// url where the customer should be directed to after paying for the order
+		// example: $bpNotificationUrl = 'http://www.example.com/confirmation.php';
+		$this->aBpOptions['redirectURL'] = BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'act_checkout_finished/' . $this->_sName . '/';
+
+		// This is the currency used for the price setting.  A list of other pricing
+		// currencies supported is found at bitpay.com
+		$this->aBpOptions['currency'] = 'BTC';
+
+		// Indicates whether anything is to be shipped with the order
+		// (if false, the buyer will be informed that nothing is to be shipped)
+		$this->aBpOptions['physical'] = false;
+
+		// If set to false, then notificaitions are only
+		// sent when an invoice is confirmed (according the the
+		// transactionSpeed setting). If set to true, then a notification
+		// will be sent on every status change
+		$this->aBpOptions['fullNotifications'] = $this->getOption('full_notifications') == 'on';
+
+		// transaction speed: low/medium/high.   See API docs for more details.
+		$this->aBpOptions['transactionSpeed'] = $this->getOption('transaction_speed'); 
+
+		// Logfile for use by the bpLog function.  Note: ensure the web server process has write access
+		// to this file and/or directory!
+		$this->aBpOptions['logFile'] = $GLOBALS['dir']['tmp'] . 'bx_payment_bp.log';
+
+		// Change to 'true' if you would like automatic logging of invoices and errors.
+		// Otherwise you will have to call the bpLog function manually to log any information.
+		$this->aBpOptions['useLogging'] = true;
+	}
+
+	/**
+	 *
+	 * Call from your notification handler to convert $_POST data to an object containing invoice data
+	 *
+	 * @param boolean $apiKey
+	 * @return mixed $json
+	 * @throws Exception $e
+	 *
+	 */
+	protected function _verifyNotification() {
+		try {
+			$this->_log('Notification received: ' . date("m.d.y H:i:s"));
+
+			$post = file_get_contents("php://input");
+			if(!$post) {
+				$this->_log('Error: No post data');
+				return false;
+			}
+
+			$json = json_decode($post, true);
+			$this->_log('-- Data: ' . $post);
+			$this->_log($json);
+
+			if(is_string($json))
+				return false;
+
+			if(!array_key_exists('posData', $json)) {
+				$this->_log('Error: No posData');
+				return false;
+			}
+
+			$json['posData'] = json_decode($json['posData'], true);
+			if(empty($json['posData']) || !is_array($json['posData'])) {
+				$this->_log('Error: Empty posData');
+				return false;
+			}
+
+			return $json;
+		}
+		catch (Exception $e) {
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: ' . $e->getMessage());
+
+			return false;
+		}
+	}
+
+	/**
+	 *
+	 * Call from your notification handler to verify posData
+	 *
+	 * @param array $aPosData
+	 * @return boolean
+	 *
+	 */
+	protected function _verifyPosData($aPosData) {
+		if(!$this->aBpOptions['verifyPos']) {
+			if(empty($aPosData['d']) || !is_array($aPosData['d'])) {
+				$this->_log('Error: Payment data cannot be found.');
+				return false;
+			}
+
+			return $aPosData['d'];
+		}
+
+		if($this->_hash(serialize($aPosData['d']), $this->aBpOptions['apiKey']) != $aPosData['h']) {
+			$this->_log('Error: Authentication failed (bad posData hash).');
+			return false;
+		}
+
+		return $aPosData['d'];
+	}
+
+	protected function _verifyAmount($aPosData, $fAmount) {
+    	$iPendingId = (int)$aPosData['pnd'];
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(empty($aPending) || !is_array($aPending) || $fAmount != (float)$aPending['amount'])
+            return false;	        	
+
+        return true;
+	}
+
+	/**
+	 * 
+	 * Decodes JSON response and returns
+	 * associative array.
+	 * 
+	 * @param string $response
+	 * @return array $arrResponse
+	 * @throws Exception $e
+	 * 
+	 */
+	protected function _decodeResponse($response) {
+		try {
+			if (empty($response) || !(is_string($response)))
+				return array('error' => 'BxPmtBitPay::_decodeResponse expects a string parameter.');
+
+			return json_decode($response, true);
+		} 
+		catch (Exception $e) {
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: ' . $e->getMessage());
+
+			return array('error' => $e->getMessage());
+		}
+	}
+
+	/**
+	 *
+	 * Generates a base64 encoded keyed hash.
+	 *
+	 * @param string $data, string $key
+	 * @return string $hmac
+	 * @throws Exception $e
+	 *
+	 */
+	protected function _hash($data, $key) {
+		try {
+			$hmac = base64_encode(hash_hmac('sha256', $data, $key, TRUE));
+			return strtr($hmac, array('+' => '-', '/' => '_', '=' => ''));
+		}
+		catch (Exception $e) {
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: ' . $e->getMessage());
+
+			return 'Error: ' . $e->getMessage();
+		}
+	}
+
+	/**
+	 *
+	 * Handles post/get to BitPay via curl.
+	 *
+	 * @param string $url, string $apiKey, boolean $post
+	 * @return mixed $response
+	 * @throws Exception $e
+	 *
+	 */
+	protected function _curl($url, $apiKey, $post = false) {
+		if(!isset($url) || trim($url) == '' || !isset($apiKey) || trim($apiKey) == '') {
+			// Invalid parameter specified
+			if($this->aBpOptions['useLogging'])
+				$this->_log('Error: You must supply non-empty url and apiKey parameters.');
+
+	    	return array('error' => 'You must supply non-empty url and apiKey parameters.');
+		}
+
+		try {
+			$curl = curl_init();
+			$length = 0;
+
+			if ($post) {
+				curl_setopt($curl, CURLOPT_POST, 1);
+				curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
+				$length = strlen($post);
+			}
+
+			$uname = base64_encode($apiKey);
+
+			if($uname) {
+				$header = array(
+					'Content-Type: application/json',
+					'Content-Length: ' . $length,
+					'Authorization: Basic ' . $uname,
+				);
+
+				curl_setopt($curl, CURLOPT_URL, $url);
+				curl_setopt($curl, CURLOPT_PORT, 443);
+				curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
+				curl_setopt($curl, CURLOPT_TIMEOUT, 10);
+				curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ) ;
+				curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1); // verify certificate
+				curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); // check existence of CN and verify that it matches hostname
+				curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
+				curl_setopt($curl, CURLOPT_FORBID_REUSE, 1);
+				curl_setopt($curl, CURLOPT_FRESH_CONNECT, 1);
+
+				$responseString = curl_exec($curl);
+
+				if($responseString == false) {
+					$response = array('error' => curl_error($curl));
+					if($this->aBpOptions['useLogging'])
+						$this->_log('Error: ' . curl_error($curl));
+				} 
+				else {
+					$response = json_decode($responseString, true);
+					if (!$response) {
+						$response = array('error' => 'invalid json: '.$responseString);
+						if($this->aBpOptions['useLogging'])
+							$this->_log('Error - Invalid JSON: ' . $responseString);
+					}
+				}
+
+				curl_close($curl);
+				return $response;
+			} 
+			else {
+				curl_close($curl);
+	
+				if($this->aBpOptions['useLogging'])
+					$this->_log('Invalid data found in apiKey value passed to Bitpay::curl method. (Failed: base64_encode(apikey))');
+
+				return array('error' => 'Invalid data found in apiKey value passed to Bitpay::curl method. (Failed: base64_encode(apikey))');
+			}
+		}
+		catch (Exception $e) {
+			@curl_close($curl);
+			if($this->aBpOptions['useLogging'])
+			$this->_log('Error: ' . $e->getMessage());
+			return array('error' => $e->getMessage());
+		}
+	}
+
+	/**
+	 *
+	 * Writes $contents to a log file specified in the bp_options file or, if missing,
+	 * defaults to a standard filename of 'bplog.txt'.
+	 *
+	 * @param mixed $contents
+	 * @return
+	 * @throws Exception $e 
+	 *
+	 */
+	protected function _log($contents) {
+		try {
+			if(isset($this->aBpOptions['logFile']) && $this->aBpOptions['logFile'] != '') {
+				$file = $this->aBpOptions['logFile'];
+	    	} 
+	    	else {
+				// Fallback to using a default logfile name in case the variable is
+				// missing or not set.
+				$file = dirname(__FILE__) . '/bplog.txt';
+			}
+
+			file_put_contents($file, date('m-d H:i:s').": ", FILE_APPEND);
+
+			if (is_array($contents))
+				$contents = var_export($contents, true);	
+			else if (is_object($contents))
+				$contents = json_encode($contents);
+
+			file_put_contents($file, $contents."\n", FILE_APPEND);
+	  	}
+	  	catch (Exception $e) {
+			echo 'Error: ' . $e->getMessage();
+	  	}
+	}
+}
+
+/** @} */

+ 269 - 0
modules/boonex/payment/classes/BxPaymentProviderPayPal.php

@@ -0,0 +1,269 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+define('PP_MODE_LIVE', 1);
+define('PP_MODE_TEST', 2);
+
+define('PP_PRC_TYPE_DIRECT', 1);
+define('PP_PRC_TYPE_PDT', 2);
+define('PP_PRC_TYPE_IPN', 3);
+
+define('PP_CNT_TYPE_SSL', 1);
+define('PP_CNT_TYPE_HTML', 2);
+
+class BxPaymentProviderPayPal extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    protected $_sDataReturnUrl;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_bRedirectOnResult = false;
+        $this->_sDataReturnUrl = $this->_oModule->_oConfig->getUrl('return_data') . $this->_sName . '/';
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0)
+    {
+        $iMode = (int)$this->getOption('mode');
+        $sActionURL = $iMode == PP_MODE_LIVE ? 'https://www.paypal.com/cgi-bin/webscr' : 'https://www.sandbox.paypal.com/cgi-bin/webscr';
+
+        if($bRecurring)
+            $aFormData = array(
+                'cmd' => '_xclick-subscriptions',
+                'a3' => sprintf("%.2f", (float)$aCartInfo['items_price']),
+                'p3' => $iRecurringDays,
+                't3' => 'D',
+                'src' => '1', // repeat billings unles member cancels subscription
+                'sra' => '1' // reattempt on failure
+            );
+        else
+            $aFormData = array(
+                'cmd' => '_xclick',
+                'amount' => sprintf( "%.2f", (float)$aCartInfo['items_price'])
+            );
+
+        $aFormData = array_merge($aFormData, array(
+            'business' => $iMode == PP_MODE_LIVE ? $this->getOption('business') : $this->getOption('sandbox'),
+            'bn' => 'Boonex_SP',
+            'item_name' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name']),
+            'item_number' => $iPendingId,
+            'currency_code' => $aCartInfo['vendor_currency_code'],
+            'no_note' => '1',
+            'no_shipping' => '1',
+            'custom' => md5($aCartInfo['vendor_id'] . $iPendingId)
+        ));
+
+        foreach($aCartInfo['items'] as $aItem)
+            $aFormData['item_name'] .= ' ' . $aItem['title'] . ',';
+		$aFormData['item_name'] = trim($aFormData['item_name'], ', ');
+
+        switch($this->getOption('prc_type')) {
+            case PP_PRC_TYPE_PDT:
+            case PP_PRC_TYPE_DIRECT:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->_sDataReturnUrl . $aCartInfo['vendor_id'],
+                    'rm' => '2'
+                ));
+                break;
+            case PP_PRC_TYPE_IPN:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->_oConfig->getUrl('return'),
+                    'notify_url' => $this->_sDataReturnUrl . $aCartInfo['vendor_id'],
+                    'rm' => '1'
+                ));
+                break;
+        }
+
+        $this->_oModule->_oTemplate->displayPageCodeRedirect($sActionURL, $aFormData);
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        if($aData['txn_type'] != 'web_accept' && !isset($aData['tx']))
+        	return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+
+		return $this->_registerCheckout($aData);
+    }
+
+	public function checkoutFinished() {}
+
+    /**
+     *
+     * @param $aData - data from payment provider.
+     * @param $bSubscription - Is not needed. May be used in the future for subscriptions.
+     * @param $iPendingId - Is not needed. May be used in the future for subscriptions.
+     * @return array with results.
+     */
+    protected function _registerCheckout(&$aData, $bSubscription = false, $iPendingId = 0)
+    {
+        if(empty($this->_aOptions) && isset($aData['item_number']))
+            $this->_aOptions = $this->getOptionsByPending($aData['item_number']);
+
+        if(empty($this->_aOptions))
+            return array('code' => 2, 'message' => $this->_sLangsPrefix . 'pp_err_no_vendor_given');
+
+        $iPrcType = (int)$this->getOption('prc_type');
+        if(($iPrcType == PP_PRC_TYPE_IPN || $iPrcType == PP_PRC_TYPE_DIRECT) && (!isset($aData['item_number']) || !isset($aData['txn_id'])))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+        else if($iPrcType == PP_PRC_TYPE_PDT && !isset($aData['tx']))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+
+        $aResult = $this->_validateCheckout($aData);
+
+        if(!$bSubscription || empty($iPendingId))
+            $iPendingId = (int)$aData['item_number'];
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 3, 'message' => $this->_sLangsPrefix . 'pp_err_already_processed');
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $aData['txn_id'],
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        $sBuyerFirstName = bx_process_input($aData['first_name']);
+        $sBuyerLastName = bx_process_input($aData['last_name']);
+        $sBuyerEmail = bx_process_input($aData['payer_email']);
+
+        $aResult['pending_id'] = $iPendingId;
+        $aResult['payer_name'] = _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $sBuyerFirstName, $sBuyerLastName); 
+		$aResult['payer_email'] = $sBuyerEmail;
+        return $aResult;
+    }
+
+    protected function _validateCheckout(&$aData)
+    {
+        $iMode = (int)$this->getOption('mode');
+        if($iMode == PP_MODE_LIVE) {
+           $sBusiness = $this->getOption('business');
+           $sConnectionUrl = 'www.paypal.com';
+        } else {
+            $sBusiness = $this->getOption('sandbox');
+            $sConnectionUrl = 'www.sandbox.paypal.com';
+        }
+
+        $iPrcType = $this->getOption('prc_type');
+        if($iPrcType == PP_PRC_TYPE_DIRECT || $iPrcType == PP_PRC_TYPE_IPN) {
+            if($aData['payment_status'] != 'Completed' )
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 5, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+
+            $sRequest = 'cmd=_notify-validate';
+            foreach($aData as $sKey => $sValue) {
+                if(in_array($sKey, array('cmd')))
+                    continue;
+
+                $sRequest .= '&' . urlencode($sKey) . '=' . urlencode(bx_process_pass($sValue));
+            }
+
+            $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
+            if((int)$aResponse['code'] !== 0)
+               return $aResponse;
+
+            array_walk($aResponse['content'], create_function('&$arg', "\$arg = trim(\$arg);"));
+            if(strcmp($aResponse['content'][0], "INVALID") == 0)
+                return array('code' => 7, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][0], "VERIFIED") != 0)
+                return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_verification_status');
+        } else if($iPrcType == PP_PRC_TYPE_PDT) {
+            $sRequest = "cmd=_notify-synch&tx=" . $aData['tx'] . "&at=" . $this->getOption('token');
+            $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
+
+            if((int)$aResponse['code'] !== 0)
+               return $aResponse;
+
+            if(strcmp($aResponse['content'][0], "FAIL") == 0)
+                return array('code' => 7, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][0], "SUCCESS") != 0)
+                return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_verification_status');
+
+            $aKeys = array();
+            foreach($aResponse['content'] as $sLine) {
+                list($sKey, $sValue) = explode("=", $sLine);
+                $aKeys[urldecode($sKey)] = urldecode($sValue);
+            }
+
+            $aData = array_merge($aData, $aKeys);
+
+            if($aData['payment_status'] != 'Completed' )
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 5, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+        }
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $aData['item_number']));
+        $aVendor = $this->_oModule->getVendorInfo($aPending['seller_id']);
+        $fAmount = (float)$this->_getReceivedAmount($aVendor['currency_code'], $aData);
+        if($fAmount != (float)$aPending['amount'])
+            return array('code' => 9, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_amount');
+
+        if($aData['custom'] != md5($aPending['seller_id'] . $aPending['id']))
+            return array('code' => 10, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_custom_data');
+
+        return array('code' => BX_PAYMENT_RESULT_SUCCESS, 'message' => $this->_sLangsPrefix . 'pp_msg_verified');
+    }
+
+    protected function _readValidationData($sConnectionUrl, $sRequest)
+    {
+        $sHeader = "POST /cgi-bin/webscr HTTP/1.0\r\n";
+        $sHeader .= "Host: " . $sConnectionUrl . "\r\n";
+        $sHeader .= "Content-Type: application/x-www-form-urlencoded\r\n";
+        $sHeader .= "Content-Length: " . strlen($sRequest) . "\r\n";
+        $sHeader .= "Connection: close\r\n\r\n";
+
+        $iErrCode = 0;
+        $sErrMessage = "";
+        if($this->getOption('cnt_type') == PP_CNT_TYPE_SSL)
+            $rSocket = fsockopen("ssl://" . $sConnectionUrl, 443, $iErrCode, $sErrMessage, 60);
+        else
+            $rSocket = fsockopen("tcp://" . $sConnectionUrl, 80, $iErrCode, $sErrMessage, 60);
+
+        if(!$rSocket)
+            return array('code' => 6, 'message' => $this->_sLangsPrefix . 'err_cannot_validate');
+
+        fputs($rSocket, $sHeader);
+        fputs($rSocket, $sRequest);
+
+        $sResponse = '';
+        while(!feof($rSocket))
+            $sResponse .= fread($rSocket, 1024);
+        fclose($rSocket);
+
+        list($sResponseHeader, $sResponseContent) = explode("\r\n\r\n", $sResponse);
+
+        return array('code' => 0, 'content' => explode("\n", $sResponseContent));
+    }
+    protected function _getReceivedAmount($sCurrencyCode, &$aResultData)
+    {
+        $fAmount = 0.00;
+
+        if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['payment_gross']) && !empty($aResultData['payment_gross']))
+            $fAmount = (float)$aResultData['payment_gross'];
+        else if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['mc_gross']) && !empty($aResultData['mc_gross']))
+            $fAmount = (float)$aResultData['mc_gross'];
+        else if($aResultData['settle_currency'] == $sCurrencyCode && isset($aResultData['settle_amount']) && !empty($aResultData['settle_amount']))
+            $fAmount = (float)$aResultData['settle_amount'];
+
+        return $fAmount;
+    }
+}
+
+/** @} */

+ 48 - 0
modules/boonex/payment/classes/BxPaymentResponse.php

@@ -0,0 +1,48 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Timeline Timeline
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentResponse extends BxDolAlertsResponse
+{
+	protected $MODULE;
+    protected $_oModule;
+
+	public function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct();
+
+        $this->_oModule = BxDolModule::getInstance($this->MODULE);
+    }
+
+	/**
+     * Overwtire the method of parent class.
+     *
+     * @param BxDolAlerts $oAlert an instance of alert.
+     */
+    public function response($oAlert)
+    {
+    	if($oAlert->sUnit != 'profile' || !in_array($oAlert->sAction, array('join', 'delete')))
+    		return;
+
+		switch($oAlert->sAction) {
+			case 'join':
+				$this->_oModule->onProfileJoin($oAlert->iObject);
+				break;
+
+			case 'delete':
+				$this->_oModule->onProfileDelete($oAlert->iObject);
+				break;
+		}
+    }
+}
+
+/** @} */

+ 317 - 0
modules/boonex/payment/classes/BxPaymentTemplate.php

@@ -0,0 +1,317 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentTemplate extends BxBaseModPaymentTemplate
+{
+	protected $_sLangsPrefix;
+
+    function __construct(&$oConfig, &$oDb)
+    {
+        parent::__construct($oConfig, $oDb);
+
+        $this->_sLangsPrefix = $this->_oConfig->getPrefix('langs');
+    }
+
+    public function addJsCssOrders()
+    {
+    	$this->addJs(array(
+    		'jquery-ui/jquery.ui.widget.min.js',
+    		'jquery-ui/jquery.ui.menu.min.js', 
+    		'jquery-ui/jquery.ui.autocomplete.min.js', 
+    		'jquery.form.min.js', 
+    		'jquery.anim.js', 
+    		'jquery.webForms.js', 
+    		'orders.js'
+    	));
+    	$this->addCss(array('orders.css'));
+    }
+
+    public function addJsCssCart()
+    {
+    	$this->addJsTranslation(array('_bx_payment_err_nothing_selected'));
+    	$this->addJs(array('jquery.anim.js', 'cart.js'));
+    	$this->addCss(array('orders.css', 'cart.css'));
+    }
+
+	public function displayCartJs($bWrapped = true)
+    {
+        $this->addJsCssCart();
+        return $this->displayJsCode('cart');
+    }
+
+    public function displayAddToCartJs($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false, $bWrapped = true)
+    {
+        $sJsCode = $this->displayCartJs($bWrapped);
+        $sJsMethod = $this->parseHtmlByName('add_to_cart_js.html', array(
+            'js_object' => $this->_oConfig->getJsObject('cart'),
+            'vendor_id' => $iVendorId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'need_redirect' => (int)$bNeedRedirect
+        ));
+
+        return array($sJsCode, $sJsMethod);
+    }
+
+    public function displayAddToCartLink($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false)
+    {
+        $this->addJsCssCart();
+        return $this->parseHtmlByName('add_to_cart.html', array(
+        	'js_object' => $this->_oConfig->getJsObject('cart'),
+        	'js_content' => $this->displayJsCode('cart'),
+        	'txt_add_to_cart' => _t($this->_sLangsPrefix . 'txt_add_to_cart'),
+            'vendor_id' => $iVendorId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'need_redirect' => (int)$bNeedRedirect
+        ));
+    }
+
+	public function displayBlockCart($aCartInfo, $iVendorId = BX_PAYMENT_EMPTY_ID)
+    {
+    	if(empty($aCartInfo))
+    		return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $sJsObject = $this->_oConfig->getJsObject('cart');
+
+        if($iVendorId != BX_PAYMENT_EMPTY_ID)
+            $aCartInfo = array($aCartInfo);
+
+        $aVendors = array();
+        foreach($aCartInfo as $aVendor) {
+            //--- Get Providers ---//
+            $aProviders = array();
+            $aVendorProviders = $this->_oDb->getVendorInfoProviders($aVendor['vendor_id']);
+            foreach($aVendorProviders as $aProvider)
+                $aProviders[] = array(
+                    'name' => $aProvider['name'],
+                    'caption' => _t($this->_sLangsPrefix . 'txt_cart_' . $aProvider['name']),
+                    'checked' => empty($aProviders) ? 'checked="checked"' : ''
+                );
+
+            //--- Get Items ---//
+            $aItems = array();
+            foreach($aVendor['items'] as $aItem)
+                $aItems[] = array(
+                    'vendor_id' => $aVendor['vendor_id'],
+                    'vendor_currency_code' => $aVendor['vendor_currency_code'],
+                    'module_id' => $aItem['module_id'],
+                    'item_id' => $aItem['id'],
+                    'item_title' => $aItem['title'],
+                    'item_url' => $aItem['url'],
+                    'item_quantity' => $aItem['quantity'],
+                	'bx_if:show_price_paid' => array(
+                		'condition' => (int)$aItem['price'] != 0,
+                		'content' => array(
+                			'item_price' => $aItem['quantity'] * $aItem['price'],
+                			'vendor_currency_code' => $aVendor['vendor_currency_code'],
+                		)
+                	),
+                	'bx_if:show_price_free' => array(
+                		'condition' => (int)$aItem['price'] == 0,
+                		'content' => array()
+                	),
+                    'js_object' => $sJsObject
+                );
+
+            //--- Get Control Panel ---//
+            $aButtons = array(
+                'bx-payment-checkout' => _t($this->_sLangsPrefix . 'form_cart_input_do_checkout'),
+                'bx-payment-delete' => _t($this->_sLangsPrefix . 'form_cart_input_do_delete')
+            );
+            $oSearchResult = new BxTemplSearchResult();
+            $sControlPanel = $oSearchResult->showAdminActionsPanel('items_from_' . $aVendor['vendor_id'], $aButtons, 'items', true, true);
+
+            //--- Get General ---//
+            $bVendorLink = !empty($aVendor['vendor_link']);
+            $sTxtShoppingCart = _t($this->_sLangsPrefix . 'txt_shopping_cart', $aVendor['vendor_name']);
+
+            $aVendors[] = array(
+                'vendor_id' => $aVendor['vendor_id'],
+                'bx_if:show_link' => array(
+                    'condition' => $bVendorLink,
+                    'content' => array(
+            			'txt_shopping_cart' => $sTxtShoppingCart,
+                        'vendor_url' => $aVendor['vendor_link'],
+                        'vendor_currency_code' => $aVendor['vendor_currency_code'],
+                        'items_count' => $aVendor['items_count'],
+                        'items_price' => $aVendor['items_price']
+                    )
+                ),
+                'bx_if:show_text' => array(
+                    'condition' => !$bVendorLink,
+                    'content' => array(
+                		'txt_shopping_cart' => $sTxtShoppingCart,
+                        'vendor_currency_code' => $aVendor['vendor_currency_code'],
+                        'items_count' => $aVendor['items_count'],
+                        'items_price' => $aVendor['items_price']
+                    )
+                ),
+                'vendor_icon' => $aVendor['vendor_icon'],
+                'bx_repeat:providers' => $aProviders,
+                'bx_repeat:items' => $aItems,
+                'js_object' => $sJsObject,
+                'process_url' => BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'cart_submit/',
+                'control_panel' => $sControlPanel
+            );
+        }
+
+        $this->addJsCssCart();
+        return $this->parseHtmlByName('cart.html', array(
+        	'js_content' => $this->displayJsCode('cart'),
+        	'bx_repeat:vendors' => $aVendors
+        ));
+    }
+
+    public function displayBlockHistory($iClientId, $iSellerId)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_history'));
+        if(!$oGrid || empty($iClientId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$oGrid->addQueryParam('client_id', $iClientId);
+		if(!empty($iSellerId))
+			$oGrid->addQueryParam('seller_id', $iSellerId);
+
+		$this->addJsCssOrders();
+        return $this->displayJsCode('history') . $oGrid->getCode();
+    }
+
+	public function displayBlockOrders($sType, $iSellerId)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_' . $sType));
+        if(!$oGrid || empty($iSellerId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$oGrid->addQueryParam('seller_id', $iSellerId);
+
+		$this->addJsCssOrders();
+        return $this->displayJsCode($sType) . $oGrid->getCode();
+    }
+
+	public function displayOrder($sType, $iId)
+    {
+        $sMethodName = 'getOrder' . bx_gen_method_name($sType);
+        $aOrder = $this->_oDb->$sMethodName(array('type' => 'id', 'id' => $iId));
+
+        $oModule = $this->_getModule();
+        $aSeller = $oModule->getVendorInfo((int)$aOrder['seller_id']);
+        $aClient = $oModule->getProfileInfo((int)$aOrder['client_id']);
+
+        $aResult = array(
+        	'txt_client' => _t($this->_sLangsPrefix . 'txt_client'),
+        	'txt_seller' => _t($this->_sLangsPrefix . 'txt_seller'),
+        	'txt_order' => _t($this->_sLangsPrefix . 'txt_order'),
+        	'txt_processed_with' => _t($this->_sLangsPrefix . 'txt_processed_with'),
+        	'txt_message' => _t($this->_sLangsPrefix . 'txt_message'),
+        	'txt_date' => _t($this->_sLangsPrefix . 'txt_date'),
+        	'txt_products' => _t($this->_sLangsPrefix . 'txt_products'),
+            'client_name' => $aClient['name'],
+            'client_url' => $aClient['link'],
+            'bx_if:show_link' => array(
+                'condition' => !empty($aSeller['link']),
+                'content' => array(
+                    'seller_name' => $aSeller['name'],
+                    'seller_url' => $aSeller['link'],
+                )
+            ),
+            'bx_if:show_text' => array(
+                'condition' => empty($aSeller['link']),
+                'content' => array(
+                    'seller_name' => $aSeller['name']
+                )
+            ),
+            'order' => $aOrder['order'],
+            'provider' => $aOrder['provider'],
+            'error' => $aOrder['error_msg'],
+            'date' => bx_time_js($aOrder['date']),
+            'bx_repeat:items' => array()
+        );
+
+        if($sType == BX_PAYMENT_ORDERS_TYPE_PENDING)
+            $aItems = $this->_oConfig->descriptorsM2A($aOrder['items']);
+        else
+            $aItems = $this->_oConfig->descriptorsM2A($this->_oConfig->descriptorA2S(array($aOrder['seller_id'], $aOrder['module_id'], $aOrder['item_id'], $aOrder['item_count'])));
+
+        foreach($aItems as $aItem) {
+            $aInfo = $oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id']));
+            if(!empty($aInfo) && is_array($aInfo))
+	            $aResult['bx_repeat:items'][] = array(
+	                'bx_if:link' => array(
+	                    'condition' => !empty($aInfo['url']),
+	                    'content' => array(
+	                        'title' => $aInfo['title'],
+	                        'url' => $aInfo['url']
+	                    )
+	                ),
+	                'bx_if:text' => array(
+	                    'condition' => empty($aInfo['url']),
+	                    'content' => array(
+	                        'title' => $aInfo['title'],
+	                    )
+	                ),
+	                'quantity' => $aItem['item_count'],
+	                'price' => $aInfo['price'],
+	                'currency_code' => $aSeller['currency_code']
+	            );
+        }
+
+        return $this->parseHtmlByName('order_' . $sType . '.html', $aResult);
+    }
+
+    public function displayItems($aItems = array())
+    {
+        $aTmplVarsItems = array();
+
+        foreach($aItems as $aItem) {
+            $aTmplVarsItems[] = array(
+                'id' => $aItem['id'],
+                'price' => $aItem['price'],
+                'bx_if:link' => array(
+                    'condition' => !empty($aItem['url']),
+                    'content' => array(
+                        'url' => $aItem['url'],
+                        'title' => $aItem['title']
+                    )
+                ),
+                'bx_if:text' => array(
+                    'condition' => empty($aItem['url']),
+                    'content' => array(
+                        'title' => $aItem['title']
+                    )
+                ),
+            );
+        }
+
+        if(empty($aTmplVarsItems))
+        	$aTmplVarsItems = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        return $this->parseHtmlByName('items.html', array(
+        	'html_id' => $this->_oConfig->getHtmlIds('processed', 'order_processed_items'),
+        	'bx_repeat:items' => $aTmplVarsItems
+        ));
+    }
+
+	protected function _getModule()
+    {
+        $sName = $this->_oConfig->getName();
+        return BxDolModule::getInstance($sName);
+    }
+
+    protected function _isSubscription($aOrder)
+    {
+    	return '';
+    }
+}
+
+/** @} */

+ 70 - 0
modules/boonex/payment/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+	'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_payment',
+    'title' => 'Payment',
+    'note' => 'Payment module.',
+    'version' => '8.0.0.DEV',
+    'vendor' => 'Boonex',
+    'help_url' => 'http://feed.boonex.com/?section={module_name}',
+
+    'compatible_with' => array(
+        '8.0.x'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/payment/',
+    'home_uri' => 'payment',
+
+    'db_prefix' => 'bx_payment_',
+    'class_prefix' => 'BxPayment',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Payment',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+	'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 30 - 0
modules/boonex/payment/install/installer.php

@@ -0,0 +1,30 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) BoonEx Pty Limited - http://www.boonex.com/
+ * CC-BY License - http://creativecommons.org/licenses/by/3.0/
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     TridentModules
+ *
+ * @{
+ */
+
+class BxPaymentInstaller extends BxDolStudioInstaller
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+	function enable($aParams)
+    {
+        $aResult = parent::enable($aParams);
+
+        if($aResult['result'])
+            BxDolService::call($this->_aConfig['name'], 'update_dependent_modules');
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 289 - 0
modules/boonex/payment/install/langs/en.xml

@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string name="_bx_payment"><![CDATA[Payment]]></string>
+
+	<!-- OPTIONS -->
+	<string name="_bx_payment_option_default_currency_code"><![CDATA[Currency code]]></string>
+	<string name="_bx_payment_option_err_default_currency_code"><![CDATA[Currency code cannot be empty.]]></string>
+	<string name="_bx_payment_option_default_currency_sign"><![CDATA[Currency sign]]></string>
+	<string name="_bx_payment_option_err_default_currency_sign"><![CDATA[Currency sign cannot be empty.]]></string>	
+	<string name="_bx_payment_option_site_admin"><![CDATA[Site administrator]]></string>
+
+	<!-- PAGES and BLOCKS -->
+	<string name="_bx_payment_page_title_sys_cart"><![CDATA[Shopping Cart]]></string>
+	<string name="_bx_payment_page_title_cart"><![CDATA[Shopping Cart]]></string>
+	<string name="_bx_payment_page_block_title_cart"><![CDATA[Shopping Cart]]></string>
+
+	<string name="_bx_payment_page_title_sys_history"><![CDATA[Shopping History]]></string>
+	<string name="_bx_payment_page_title_history"><![CDATA[Shopping History]]></string>
+	<string name="_bx_payment_page_block_title_history"><![CDATA[Shopping History]]></string>
+
+	<string name="_bx_payment_page_title_sys_orders"><![CDATA[Orders]]></string>
+	<string name="_bx_payment_page_title_orders"><![CDATA[Orders]]></string>
+	<string name="_bx_payment_page_block_title_orders"><![CDATA[Orders]]></string>
+
+	<string name="_bx_payment_page_title_sys_details"><![CDATA[Payment Details]]></string>
+	<string name="_bx_payment_page_title_details"><![CDATA[Payment Details]]></string>
+	<string name="_bx_payment_page_block_title_details"><![CDATA[Payment Details]]></string>
+
+	<string name="_bx_payment_page_block_title_orders_processed"><![CDATA[Processed Orders]]></string>
+	<string name="_bx_payment_page_block_title_orders_pending"><![CDATA[Pending Orders]]></string>
+
+	<string name="_bx_payment_page_title_response"><![CDATA[Payment Response]]></string>
+	<string name="_bx_payment_page_title_error"><![CDATA[Payment Error]]></string>
+
+	<string name="_bx_payment_page_title_sys_join"><![CDATA[Join]]></string>
+	<string name="_bx_payment_page_title_join"><![CDATA[Join]]></string>
+	<string name="_bx_payment_page_block_title_join"><![CDATA[Join]]></string>
+
+	<!--
+	<string name="_bx_payment_page_title_sys_"><![CDATA[]]></string>
+	<string name="_bx_payment_page_title_"><![CDATA[]]></string>
+	<string name="_bx_payment_page_block_title_"><![CDATA[]]></string>
+	-->
+
+	<!-- MENUS -->
+	<string name="_bx_payment_menu_title_orders_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_orders_submenu"><![CDATA[Orders Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_orders_processed"><![CDATA[Processed Orders]]></string>
+    <string name="_bx_payment_menu_item_title_orders_processed"><![CDATA[Processed]]></string>
+    <string name="_bx_payment_menu_item_title_system_orders_pending"><![CDATA[Pending Orders]]></string>
+    <string name="_bx_payment_menu_item_title_orders_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_payment_menu_item_title_system_details"><![CDATA[Payment Details]]></string>
+    <string name="_bx_payment_menu_item_title_details"><![CDATA[Settings]]></string>
+
+	<string name="_bx_payment_menu_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart"><![CDATA[Cart]]></string>
+    <string name="_bx_payment_menu_item_title_cart"><![CDATA[Cart]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart_history"><![CDATA[Cart History]]></string>
+    <string name="_bx_payment_menu_item_title_cart_history"><![CDATA[Cart History]]></string>
+
+	<!--
+	<string name="_bx_payment_menu_title_"><![CDATA[]]></string>
+    <string name="_bx_payment_menu_set_title_"><![CDATA[]]></string>
+    <string name="_bx_payment_menu_item_title_system_"><![CDATA[]]></string>
+    <string name="_bx_payment_menu_item_title_"><![CDATA[]]></string>
+    -->
+
+	<!-- FORMS -->
+	<string name="_bx_payment_form_cart_input_do_delete"><![CDATA[Delete]]></string>
+	<string name="_bx_payment_form_cart_input_do_checkout"><![CDATA[Checkout]]></string>
+	<string name="_bx_payment_form_details_input_do_submit"><![CDATA[Save]]></string>
+
+	<!-- GRIDS -->
+	<string name="_bx_payment_grid_orders_field_client_id"><![CDATA[Client]]></string>
+	<string name="_bx_payment_grid_orders_field_seller_id"><![CDATA[Seller]]></string>
+	<string name="_bx_payment_grid_orders_field_transaction"><![CDATA[Transaction]]></string>
+	<string name="_bx_payment_grid_orders_field_license"><![CDATA[License]]></string>
+	<string name="_bx_payment_grid_orders_field_amount"><![CDATA[Amount]]></string>
+	<string name="_bx_payment_grid_orders_field_date"><![CDATA[Date]]></string>
+
+	<string name="_bx_payment_grid_orders_action_add"><![CDATA[Manual Order]]></string>
+	<string name="_bx_payment_grid_orders_action_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_grid_orders_action_process"><![CDATA[Process]]></string>
+	<string name="_bx_payment_grid_orders_action_view_order"><![CDATA[View]]></string>
+
+	<string name="_bx_payment_grid_orders_popup_order_history_view"><![CDATA[Order]]></string>
+	<string name="_bx_payment_grid_orders_popup_order_pending_view"><![CDATA[Pending Order]]></string>
+	<string name="_bx_payment_grid_orders_popup_order_pending_process"><![CDATA[Process Pending Order]]></string>
+	<string name="_bx_payment_grid_orders_popup_order_processed_view"><![CDATA[Processed Order]]></string>
+	<string name="_bx_payment_grid_orders_popup_order_processed_add"><![CDATA[Manual Order]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+
+
+	<!-- FORMS -->
+	<string name="_bx_payment_form_pendings_form"><![CDATA[Pendings Form]]></string>
+	<string name="_bx_payment_form_processed_form"><![CDATA[Processed Form]]></string>
+	<string name="_bx_payment_form_pendings_display_process"><![CDATA[Process Pending Display]]></string>
+	<string name="_bx_payment_form_processed_display_add"><![CDATA[Add Processed Display]]></string>
+	<string name="_bx_payment_form_pendings_input_id_sys"><![CDATA[ID]]></string>
+	<string name="_bx_payment_form_pendings_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+	<string name="_bx_payment_form_pendings_input_order_sys"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_pendings_input_order"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_pendings_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+	<string name="_bx_payment_form_pendings_input_process_sys"><![CDATA[Process]]></string>
+	<string name="_bx_payment_form_pendings_input_process"><![CDATA[Process]]></string>
+	<string name="_bx_payment_form_pendings_input_cancel_sys"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_pendings_input_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_processed_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+	<string name="_bx_payment_form_processed_input_client_id_sys"><![CDATA[Client ID]]></string>
+	<string name="_bx_payment_form_processed_input_client_sys"><![CDATA[Client]]></string>
+	<string name="_bx_payment_form_processed_input_client"><![CDATA[Client]]></string>
+	<string name="_bx_payment_form_processed_input_client_err"><![CDATA[You need to enter a name of an existed member here.]]></string>
+	<string name="_bx_payment_form_processed_input_order_sys"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_processed_input_order"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_processed_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+	<string name="_bx_payment_form_processed_input_module_id_sys"><![CDATA[Module]]></string>
+	<string name="_bx_payment_form_processed_input_module_id"><![CDATA[Module]]></string>
+	<string name="_bx_payment_form_processed_input_module_id_err"><![CDATA[You need to select a module here.]]></string>
+	<string name="_bx_payment_form_processed_input_items_sys"><![CDATA[Items]]></string>
+	<string name="_bx_payment_form_processed_input_items"><![CDATA[Items]]></string>
+	<string name="_bx_payment_form_processed_input_items_err"><![CDATA[You need to select at least one item from the list here.]]></string>
+	<string name="_bx_payment_form_processed_input_add"><![CDATA[Add]]></string>
+	<string name="_bx_payment_form_processed_input_add_sys"><![CDATA[Add]]></string>
+	<string name="_bx_payment_form_processed_input_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_processed_input_cancel_sys"><![CDATA[Cancel]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+
+	<!-- ACL -->
+	<string name="_bx_payment_acl_action_purchase"><![CDATA[Purchase]]></string>
+	<string name="_bx_payment_acl_action_sell"><![CDATA[Sell]]></string>
+
+	<!-- EMAIL TEMPLATES -->
+	<string name="_bx_payment_et_txt_name_paid_need_join"><![CDATA[Paid and need to join.]]></string>
+	<string name="_bx_payment_et_txt_subject_paid_need_join"><![CDATA[Payment was accepted.]]></string>
+	<string name="_bx_payment_et_txt_body_paid_need_join"><![CDATA[<bx_include_auto:_email_header.html />
+<p><b>Dear {RealName}</b>,</p>
+<p>Your payment was accepted. If you did not fill in the join form yet, then you may do it using the following link.</p>
+<p><a href="{JoinLink}">Join Now</a></p>
+<bx_include_auto:_email_footer.html />]]></string>
+
+	<!-- MESSAGES, WARNINGS and ERRORS -->
+	<string name="_bx_payment_msg_no_results"><![CDATA[Empty]]></string>
+	<string name="_bx_payment_msg_redirecting"><![CDATA[Redirecting... Please wait.]]></string>
+	<string name="_bx_payment_msg_successfully_added"><![CDATA[The item was successfully added to your shopping cart.]]></string>
+	<string name="_bx_payment_msg_successfully_processed_free"><![CDATA[Free item was successfully processed]]></string>
+	<string name="_bx_payment_err_access_db"><![CDATA[Database access error.]]></string>
+	<string name="_bx_payment_err_cannot_validate"><![CDATA[Can't connect to remote host for validation.]]></string>
+	<string name="_bx_payment_err_empty_items"><![CDATA[There are no items selected.]]></string>
+	<string name="_bx_payment_err_empty_order"><![CDATA[The order is empty.]]></string>
+	<string name="_bx_payment_err_inactive_vendor"><![CDATA[The vendor status is not active.]]></string>
+	<string name="_bx_payment_err_incorrect_provider"><![CDATA[Incorrect or unavailable payment provider.]]></string>
+	<string name="_bx_payment_err_not_accept_payments"><![CDATA[The vendor does not accept payments.]]></string>
+	<string name="_bx_payment_err_nothing_selected"><![CDATA[You need to select at least one item.]]></string>
+	<string name="_bx_payment_err_purchase_from_yourself"><![CDATA[You cannot purchase your own item. It's just a bad luck thing, you know.]]></string>
+	<string name="_bx_payment_err_required_login"><![CDATA[You need to login.]]></string>
+	<string name="_bx_payment_err_unknown_vendor"><![CDATA[Unknown vendor.]]></string>
+	<string name="_bx_payment_err_wrong_data"><![CDATA[Incorrect input data.]]></string>
+	<string name="_bx_payment_err_not_found_pending"><![CDATA[Pending order was not found.]]></string>
+	<string name="_bx_payment_err_cannot_perform"><![CDATA[Cannot perform the action. Please report.]]></string>
+	<string name="_bx_payment_err_wrong_quantity"><![CDATA[Incorrect quantity specified.]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+
+
+	<!-- Other -->
+	<string name="_bx_payment_txt_shopping_cart"><![CDATA[{0}'s cart]]></string>
+	<string name="_bx_payment_txt_payment_to"><![CDATA[Payment to {0} for:]]></string>
+	<string name="_bx_payment_txt_client"><![CDATA[Client]]></string>
+	<string name="_bx_payment_txt_seller"><![CDATA[Seller]]></string>
+	<string name="_bx_payment_txt_order"><![CDATA[Order ID]]></string>
+	<string name="_bx_payment_txt_processed_with"><![CDATA[Processed with]]></string>
+	<string name="_bx_payment_txt_message"><![CDATA[Result]]></string>
+	<string name="_bx_payment_txt_date"><![CDATA[Date]]></string>
+	<string name="_bx_payment_txt_products"><![CDATA[Products]]></string>
+	
+	
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+	<string name=""><![CDATA[]]></string>
+
+	<!-- PayPal payment provider -->
+	<string name="_bx_payment_pp_cpt"><![CDATA[PayPal]]></string>
+	<string name="_bx_payment_pp_dsc"><![CDATA[PayPal payment provider]]></string>
+	<string name="_bx_payment_pp_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_pp_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_pp_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_pp_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_pp_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_pp_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_pp_business_cpt"><![CDATA[Business]]></string>
+	<string name="_bx_payment_pp_business_dsc"><![CDATA[Business email address]]></string>
+	<string name="_bx_payment_pp_prc_type_cpt"><![CDATA[Process type]]></string>
+	<string name="_bx_payment_pp_prc_type_dsc"><![CDATA[The type in which data is to be processed. In IPN mode use URL like the following http://www.your-site.com/your-path/m/payment/act_finalize_checkout/paypal as notify URL in your PayPal account]]></string>
+	<string name="_bx_payment_pp_prc_type_direct"><![CDATA[direct]]></string>
+	<string name="_bx_payment_pp_prc_type_pdt"><![CDATA[PDT]]></string>
+	<string name="_bx_payment_pp_prc_type_ipn"><![CDATA[IPN]]></string>
+	<string name="_bx_payment_pp_cnt_type_cpt"><![CDATA[Connection type]]></string>
+	<string name="_bx_payment_pp_cnt_type_dsc"><![CDATA[The type of connection to be used to transfer data]]></string>
+	<string name="_bx_payment_pp_cnt_type_ssl"><![CDATA[SSL]]></string>
+	<string name="_bx_payment_pp_cnt_type_http"><![CDATA[HTTP]]></string>
+	<string name="_bx_payment_pp_token_cpt"><![CDATA[Identity token]]></string>
+	<string name="_bx_payment_pp_token_dsc"><![CDATA[Identity token]]></string>
+	<string name="_bx_payment_pp_sandbox_cpt"><![CDATA[Sandbox]]></string>
+	<string name="_bx_payment_pp_sandbox_dsc"><![CDATA[Sandbox email address]]></string>
+	<string name="_bx_payment_pp_return_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_pp_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_pp_err_no_vendor_given"><![CDATA[Unknown vendor.]]></string>
+	<string name="_bx_payment_pp_err_not_completed"><![CDATA[Payment is not completed.]]></string>
+	<string name="_bx_payment_pp_err_wrong_business"><![CDATA[Wrong receiver email.]]></string>
+	<string name="_bx_payment_pp_err_wrong_transaction"><![CDATA[Transaction verification failed.]]></string>
+	<string name="_bx_payment_pp_err_wrong_verification_status"><![CDATA[No verification status received.]]></string>
+	<string name="_bx_payment_pp_err_wrong_amount"><![CDATA[Wrong amount.]]></string>
+	<string name="_bx_payment_pp_err_wrong_custom_data"><![CDATA[Incorrect custom data.]]></string>
+	<string name="_bx_payment_pp_err_already_processed"><![CDATA[This payment has already processed.]]></string>
+	<string name="_bx_payment_pp_msg_verified"><![CDATA[Payment was successfully accepted.]]></string>
+	<string name="_bx_payment_txt_cart_paypal"><![CDATA[PayPal]]></string>
+
+	<!-- 2Checkout payment provider -->
+	<string name="_bx_payment_2co_cpt"><![CDATA[2Checkout]]></string>
+	<string name="_bx_payment_2co_dsc"><![CDATA[2Checkout payment provider]]></string>
+	<string name="_bx_payment_2co_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_2co_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_2co_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_2co_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_2co_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_2co_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_2co_account_id_cpt"><![CDATA[Account number]]></string>
+	<string name="_bx_payment_2co_account_id_dsc"><![CDATA[Your 2Checkout vendor account number]]></string>
+	<string name="_bx_payment_2co_payment_method_cpt"><![CDATA[Payment Method]]></string>
+	<string name="_bx_payment_2co_payment_method_dsc"><![CDATA[This will set the default selection on the payment method step during the checkout process]]></string>
+	<string name="_bx_payment_2co_payment_method_cc"><![CDATA[Credit Card(CC)]]></string>
+	<string name="_bx_payment_2co_payment_method_ppi"><![CDATA[PayPal(PPI)]]></string>
+	<string name="_bx_payment_2co_secret_word_cpt"><![CDATA[Secret Word]]></string>
+	<string name="_bx_payment_2co_secret_word_dsc"><![CDATA[Secret word is used to calculate a check hash]]></string>
+	<string name="_bx_payment_2co_return_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_2co_err_no_vendor_given"><![CDATA[Unknown vendor]]></string>
+	<string name="_bx_payment_2co_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_2co_err_wrong_key"><![CDATA[Check key is incorrect.]]></string>
+	<string name="_bx_payment_2co_err_wrong_payment"><![CDATA[Wrong payment amount.]]></string>
+	<string name="_bx_payment_2co_err_already_processed"><![CDATA[This payment has already processed]]></string>
+	<string name="_bx_payment_2co_msg_verified"><![CDATA[Successfully verified.]]></string>
+	<string name="_bx_payment_txt_cart_2checkout"><![CDATA[2Checkout]]></string>
+
+	<!-- BitPay payment provider -->
+	<string name="_bx_payment_bp_cpt"><![CDATA[BitPay]]></string>
+	<string name="_bx_payment_bp_dsc"><![CDATA[BitPay payment provider]]></string>
+	<string name="_bx_payment_bp_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_bp_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_bp_active_err"><![CDATA[You should have SSL certificate (HTTPS connection) to activate and use BitPay on your site.]]></string>
+	<string name="_bx_payment_bp_api_key_cpt"><![CDATA[API Key]]></string>
+	<string name="_bx_payment_bp_api_key_dsc"><![CDATA[Your merchant BitPay API Access key]]></string>
+	<string name="_bx_payment_bp_transaction_speed_cpt"><![CDATA[Transaction speed]]></string>
+	<string name="_bx_payment_bp_transaction_speed_dsc"><![CDATA[Determines when an invoice is confirmed]]></string>
+	<string name="_bx_payment_bp_transaction_speed_high"><![CDATA[High]]></string>
+	<string name="_bx_payment_bp_transaction_speed_medium"><![CDATA[Medium]]></string>
+	<string name="_bx_payment_bp_transaction_speed_low"><![CDATA[Low]]></string>
+	<string name="_bx_payment_bp_full_notifications_cpt"><![CDATA[Enable full notifications]]></string>
+	<string name="_bx_payment_bp_full_notifications_dsc"><![CDATA[When enabled notifications will be sent on every status change, otherwise when an invoice is confirmed only.]]></string>
+	<string name="_bx_payment_bp_notification_email_cpt"><![CDATA[Notification Email]]></string>
+	<string name="_bx_payment_bp_notification_email_dsc"><![CDATA[Email where invoice update notifications will be sent. Leave empty to disable.]]></string>
+	<string name="_bx_payment_bp_err_posdata_exceed_limit"><![CDATA[The value of posData exceeds limit. Contact with administrator.]]></string>
+	<string name="_bx_payment_bp_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_bp_err_no_vendor_given"><![CDATA[Unknown vendor.]]></string>
+	<string name="_bx_payment_bp_err_incorrect_data"><![CDATA[Incorrect order data.]]></string>
+	<string name="_bx_payment_bp_err_wrong_amount"><![CDATA[Wrong payment amount.]]></string>
+	<string name="_bx_payment_bp_err_already_processed"><![CDATA[This payment has already processed.]]></string>
+	<string name="_bx_payment_bp_err_no_confirmation_given"><![CDATA[Payment is waiting for full confirmation from the Bitcoin network.]]></string>
+	<string name="_bx_payment_bp_msg_checkout_finished"><![CDATA[A payment has been confirmed. Once the transaction is fully confirmed on the Bitcoin network, the payment will be processed automatically here. Then the purchased product(s) will be displayed in shopping cart history.<br /><b>Note.</b> If it doesn't happen for some reason, you need to contact with product\'s vendor and provide him with your payment's details. He'll be able to process payment manually if the payment was received.]]></string>
+	<string name="_bx_payment_txt_cart_bitpay"><![CDATA[BitPay]]></string>
+</resources>

+ 39 - 0
modules/boonex/payment/install/sql/disable.sql

@@ -0,0 +1,39 @@
+SET @sName = 'bx_payment';
+
+
+-- OPTIONS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = @sName LIMIT 1);
+SET @iCategId = (SELECT `ID` FROM `sys_options_categories` WHERE `type_id` = @iTypeId LIMIT 1);
+DELETE FROM `sys_options` WHERE `category_id` = @iCategId;
+DELETE FROM `sys_options_categories` WHERE `type_id` = @iTypeId;
+DELETE FROM `sys_options_types` WHERE `id` = @iTypeId;
+
+
+-- PAGES & BLOCKS
+DELETE FROM `sys_objects_page` WHERE `module` = @sName;
+DELETE FROM `sys_pages_blocks` WHERE `module` = @sName;
+
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = @sName;
+DELETE FROM `sys_menu_sets` WHERE `module` = @sName;
+DELETE FROM `sys_menu_items` WHERE `module` = @sName;
+
+
+-- ALERTS
+SET @iHandlerId = (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = @sName LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandlerId;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandlerId LIMIT 1;
+
+
+-- ACL
+DELETE `sys_acl_actions`, `sys_acl_matrix` FROM `sys_acl_actions`, `sys_acl_matrix` WHERE `sys_acl_matrix`.`IDAction` = `sys_acl_actions`.`ID` AND `sys_acl_actions`.`Module` = @sName;
+DELETE FROM `sys_acl_actions` WHERE `Module` = @sName;
+
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Module` = @sName;
+
+
+-- PAYMENTS
+DELETE FROM `sys_objects_payments` WHERE `object` = @sName;

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff