AntonLV 1 год назад
Родитель
Сommit
f617060d35
100 измененных файлов с 23420 добавлено и 0 удалено
  1. 51 0
      modules/boonex/payment/updates/14.0.9_15.0.0/install/config.php
  2. 13 0
      modules/boonex/payment/updates/14.0.9_15.0.0/install/installer.php
  3. 12 0
      modules/boonex/payment/updates/14.0.9_15.0.0/install/langs/en.xml
  4. 5 0
      modules/boonex/payment/updates/14.0.9_15.0.0/install/sql/enable.sql
  5. 28 0
      modules/boonex/payment/updates/14.0.9_15.0.0/install/sql/install.sql
  6. 413 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentCart.php
  7. 371 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentConfig.php
  8. 891 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentDb.php
  9. 128 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentDetails.php
  10. 195 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentFormDetails.php
  11. 330 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentGridCart.php
  12. 2078 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentModule.php
  13. 188 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderAppleInApp.php
  14. 557 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderChargebee.php
  15. 437 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderChargebeeV3.php
  16. 281 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderCredits.php
  17. 313 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderPayPal.php
  18. 987 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderPayPalApi.php
  19. 750 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderStripeBasic.php
  20. 1192 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderStripeConnect.php
  21. 1186 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderStripeV3.php
  22. 568 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentSubscriptions.php
  23. 612 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentTemplate.php
  24. 70 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/install/config.php
  25. 695 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/install/langs/en.xml
  26. 32 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/install/sql/enable-app.sql
  27. 210 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/install/sql/enable.sql
  28. 692 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/install/sql/install.sql
  29. 110 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/js/stripe_v3.js
  30. 5 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/template/cart_quantity.html
  31. 1 0
      modules/boonex/payment/updates/14.0.9_15.0.0/source/template/details_form.html
  32. 59 0
      modules/boonex/persons/updates/14.0.6_15.0.0/install/config.php
  33. 30 0
      modules/boonex/persons/updates/14.0.6_15.0.0/install/installer.php
  34. 15 0
      modules/boonex/persons/updates/14.0.6_15.0.0/install/langs/en.xml
  35. 92 0
      modules/boonex/persons/updates/14.0.6_15.0.0/install/sql/enable.sql
  36. 72 0
      modules/boonex/persons/updates/14.0.6_15.0.0/install/sql/install.sql
  37. 254 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/classes/BxPersonsConfig.php
  38. 211 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/classes/BxPersonsSearchResult.php
  39. 21 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/classes/BxPersonsUploaderBadgeCrop.php
  40. 153 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/install/config.php
  41. 369 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/install/langs/en.xml
  42. 57 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/disable.sql
  43. 100 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/enable-app.sql
  44. 590 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/enable.sql
  45. 464 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/install.sql
  46. 56 0
      modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/uninstall.sql
  47. 51 0
      modules/boonex/photos/updates/14.0.2_15.0.0/install/config.php
  48. 13 0
      modules/boonex/photos/updates/14.0.2_15.0.0/install/installer.php
  49. 4 0
      modules/boonex/photos/updates/14.0.2_15.0.0/install/sql/enable.sql
  50. 12 0
      modules/boonex/photos/updates/14.0.2_15.0.0/install/sql/install.sql
  51. 213 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/classes/BxPhotosConfig.php
  52. 159 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/classes/BxPhotosSearchResult.php
  53. 194 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/classes/BxPhotosTemplate.php
  54. 136 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/install/config.php
  55. 77 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/enable-app.sql
  56. 477 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/enable.sql
  57. 451 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/install.sql
  58. 69 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/uninstall.sql
  59. 13 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/template/entry-photo.html
  60. 16 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/template/unit_full.html
  61. 30 0
      modules/boonex/photos/updates/14.0.2_15.0.0/source/template/unit_gallery.html
  62. 51 0
      modules/boonex/plyr/updates/14.0.1_15.0.0/install/config.php
  63. 13 0
      modules/boonex/plyr/updates/14.0.1_15.0.0/install/installer.php
  64. 74 0
      modules/boonex/plyr/updates/14.0.1_15.0.0/source/install/config.php
  65. 24 0
      modules/boonex/plyr/updates/14.0.1_15.0.0/source/template/css/main.css
  66. 51 0
      modules/boonex/polls/updates/14.0.2_15.0.0/install/config.php
  67. 13 0
      modules/boonex/polls/updates/14.0.2_15.0.0/install/installer.php
  68. 2 0
      modules/boonex/polls/updates/14.0.2_15.0.0/install/sql/enable.sql
  69. 12 0
      modules/boonex/polls/updates/14.0.2_15.0.0/install/sql/install.sql
  70. 224 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/classes/BxPollsFormEntry.php
  71. 148 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/classes/BxPollsSearchResult.php
  72. 333 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/classes/BxPollsTemplate.php
  73. 136 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/install/config.php
  74. 71 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/install/sql/enable-app.sql
  75. 478 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/install/sql/enable.sql
  76. 463 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/install/sql/install.sql
  77. 15 0
      modules/boonex/polls/updates/14.0.2_15.0.0/source/template/entry-text-subentries.html
  78. 51 0
      modules/boonex/posts/updates/14.0.1_15.0.0/install/config.php
  79. 13 0
      modules/boonex/posts/updates/14.0.1_15.0.0/install/installer.php
  80. 4 0
      modules/boonex/posts/updates/14.0.1_15.0.0/install/langs/en.xml
  81. 7 0
      modules/boonex/posts/updates/14.0.1_15.0.0/install/sql/enable.sql
  82. 12 0
      modules/boonex/posts/updates/14.0.1_15.0.0/install/sql/install.sql
  83. 249 0
      modules/boonex/posts/updates/14.0.1_15.0.0/source/classes/BxPostsConfig.php
  84. 137 0
      modules/boonex/posts/updates/14.0.1_15.0.0/source/classes/BxPostsSearchResult.php
  85. 155 0
      modules/boonex/posts/updates/14.0.1_15.0.0/source/install/config.php
  86. 367 0
      modules/boonex/posts/updates/14.0.1_15.0.0/source/install/langs/en.xml
  87. 104 0
      modules/boonex/posts/updates/14.0.1_15.0.0/source/install/sql/enable-app.sql
  88. 539 0
      modules/boonex/posts/updates/14.0.1_15.0.0/source/install/sql/enable.sql
  89. 716 0
      modules/boonex/posts/updates/14.0.1_15.0.0/source/install/sql/install.sql
  90. 51 0
      modules/boonex/profiler/updates/13.0.4_15.0.0/install/config.php
  91. 13 0
      modules/boonex/profiler/updates/13.0.4_15.0.0/install/installer.php
  92. 691 0
      modules/boonex/profiler/updates/13.0.4_15.0.0/source/classes/BxProfiler.php
  93. 69 0
      modules/boonex/profiler/updates/13.0.4_15.0.0/source/install/config.php
  94. 13 0
      modules/boonex/profiler/updates/13.0.4_15.0.0/source/template/images/icons/std-icon.svg
  95. 51 0
      modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/config.php
  96. 13 0
      modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/installer.php
  97. 4 0
      modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/langs/en.xml
  98. 2 0
      modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/sql/enable.sql
  99. 115 0
      modules/boonex/quoteofday/updates/13.0.1_15.0.0/source/classes/BxQuoteOfDayGridInternal.php
  100. 77 0
      modules/boonex/quoteofday/updates/13.0.1_15.0.0/source/install/config.php

+ 51 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Payment',
+    'version_from' => '14.0.9',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/payment/updates/update_14.0.9_15.0.0/',
+    'home_uri' => 'payment_update_1409_1500',
+
+    'module_dir' => 'boonex/payment/',
+    'module_uri' => 'payment',
+
+    'db_prefix' => 'bx_payment_',
+    'class_prefix' => 'BxPayment',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Payment',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPaymentUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 12 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/install/langs/en.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+	<string_add name="_bx_payment_menu_title_public_cart_submenu"><![CDATA[Carts]]></string_add>
+	<string_add name="_bx_payment_grid_action_title_crt_quantity_sub"><![CDATA[Decrease quantity]]></string_add>
+	<string_add name="_bx_payment_grid_action_title_crt_quantity_add"><![CDATA[Increase quantity]]></string_add>
+	<string_add name="_bx_payment_pp_api_err_wrong_item"><![CDATA[The product you want to subscribe to has incorrect data on PayPal end. Please report.]]></string_add>
+	<string_add name="_bx_payment_strp_cnnt_cpt"><![CDATA[Stripe Connect]]></string_add>
+	<string_add name="_bx_payment_strp_cnnt_dsc"><![CDATA[Payment provider which is working in pairs with Stripe Connect app.]]></string_add>
+	<string_add name="_bx_payment_strp_cnnt_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string_add>
+	<string_add name="_bx_payment_strp_cnnt_connect_cpt"><![CDATA[Connected account]]></string_add>
+	<string_add name="_bx_payment_strp_cnnt_live_account_id_cpt"><![CDATA[Account ID (live)]]></string_add>
+	<string_add name="_bx_payment_strp_cnnt_test_account_id_cpt"><![CDATA[Account ID (test)]]></string_add>
+</resources>

+ 5 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/install/sql/enable.sql

@@ -0,0 +1,5 @@
+SET @sName = 'bx_payment';
+
+
+-- MENUS
+UPDATE `sys_objects_menu` SET `title_public`='_bx_payment_menu_title_public_cart_submenu' WHERE `object`='bx_payment_menu_cart_submenu';

+ 28 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/install/sql/install.sql

@@ -0,0 +1,28 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+UPDATE `bx_payment_providers` SET `active`='0' WHERE `name`='generic';
+
+SET @iProviderId = (SELECT `id` FROM `bx_payment_providers` WHERE `name`='stripe_connect' LIMIT 1);
+DELETE FROM `bx_payment_providers` WHERE `id`=@iProviderId;
+DELETE FROM `bx_payment_providers_options` WHERE `provider_id`=@iProviderId;
+
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('stripe_connect', '_bx_payment_strp_cnnt_cpt', '_bx_payment_strp_cnnt_dsc', 'strp_cnnt_', 1, 1, 1, 1, 65, 'BxPaymentProviderStripeConnect');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'strp_cnnt_mode', 'value', '_bx_payment_strp_mode_cpt', '', '', '', '', '', 1),
+(@iProviderId, 'strp_cnnt_connect', 'custom', '_bx_payment_strp_cnnt_connect_cpt', '', '', '', '', '', 2),
+(@iProviderId, 'strp_cnnt_live_account_id', 'value', '_bx_payment_strp_cnnt_live_account_id_cpt', '', '', '', '', '', 3),
+(@iProviderId, 'strp_cnnt_test_account_id', 'value', '_bx_payment_strp_cnnt_test_account_id_cpt', '', '', '', '', '', 4);
+
+
+-- GRIDS
+UPDATE `sys_objects_grid` SET `source`='SELECT * FROM `bx_payment_providers` WHERE 1 ' WHERE `object`='bx_payment_grid_providers';
+
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_payment_grid_cart' AND `name` IN ('quantity_sub', 'quantity_add');
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_payment_grid_cart', 'single', 'quantity_sub', '_bx_payment_grid_action_title_crt_quantity_sub', 'minus', 1, 0, 2),
+('bx_payment_grid_cart', 'single', 'quantity_add', '_bx_payment_grid_action_title_crt_quantity_add', 'plus', 1, 0, 3);

+ 413 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentCart.php

@@ -0,0 +1,413 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentCart extends BxBaseModPaymentCart
+{
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+    }
+
+    /*
+     * Service methods
+     */
+    
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_carts get_block_carts
+     * 
+     * @code bx_srv('bx_payment', 'get_block_carts', [...], 'Cart'); @endcode
+     * 
+     * Get page block with shopping carts by vendors.
+     *
+     * @return an array describing a block to display on the site or an empty string if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentCart::serviceGetBlockCarts
+     */
+    /** 
+     * @ref bx_payment-get_block_carts "get_block_carts"
+     */
+    public function serviceGetBlockCarts()
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+        if($this->_oModule->_oConfig->isSingleSeller())
+            return MsgBox(_t($CNF['T']['MSG_SINGLE_SELLER_MODE'], $this->serviceGetCartUrl()));
+
+    	if(bx_get('seller_id') !== false)
+            return '';
+
+        $mixedContent = $this->_oModule->_oTemplate->displayBlockCarts($iUserId);
+
+        if($this->_bIsApi)
+            return [
+                bx_api_get_block('grid', $mixedContent)
+            ];
+
+        return [
+            'content' => $mixedContent
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_cart get_block_cart
+     * 
+     * @code bx_srv('bx_payment', 'get_block_cart', [...], 'Cart'); @endcode
+     * 
+     * Get page block with content of selected shopping cart.
+     *
+     * @return an array describing a block to display on the site or an empty string if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentCart::serviceGetBlockCart
+     */
+    /** 
+     * @ref bx_payment-get_block_cart "get_block_cart"
+     */
+    public function serviceGetBlockCart()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+    	if(!$this->_bSingleSeller && bx_get('seller_id') === false)
+            return $this->_bIsApi ? [bx_api_get_msg('')] : '';
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return $this->_bIsApi ? [bx_api_get_msg(_t($CNF['T']['ERR_REQUIRED_LOGIN']))] : [
+            	'content' => MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']))
+            ];
+
+    	$iSellerId = !$this->_bSingleSeller ? bx_process_input(bx_get('seller_id'), BX_DATA_INT) : $this->_oModule->_oConfig->getSiteAdmin();
+    	if(empty($iSellerId))
+            return $this->_bIsApi ? [bx_api_get_msg(_t($CNF['T']['ERR_UNKNOWN_VENDOR']))] : [
+                'content' => MsgBox(_t($CNF['T']['ERR_UNKNOWN_VENDOR']))
+            ];
+
+        $aSeller = $this->_oModule->getProfileInfo($iSellerId);
+
+        $sTitle = _t($CNF['T']['BLOCK_TITLE_CART'], $aSeller['name']);
+        $mixedContent = $this->_oModule->_oTemplate->displayBlockCart($iUserId, $iSellerId);
+
+        if($this->_bIsApi)
+            return [
+                'title' => $sTitle,
+                'content' => [bx_api_get_block('grid', $mixedContent)]
+            ];
+
+        return [
+            'title' => $sTitle,
+            'content' => $mixedContent
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_cart_history get_block_cart_history
+     * 
+     * @code bx_srv('bx_payment', 'get_block_cart_history', [...], 'Cart'); @endcode
+     * 
+     * Get page block with shopping cart history.
+     *
+     * @return an array describing a block to display on the site or an empty string if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentCart::serviceGetBlockCartHistory
+     */
+    /** 
+     * @ref bx_payment-get_block_cart_history "get_block_cart_history"
+     */
+    public function serviceGetBlockCartHistory()
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+		$iSellerId = bx_get('vendor') !== false ? (int)bx_get('vendor') : 0;
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return array(
+            	'content' => MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']))
+            );
+
+        return array(
+        	'content' => $this->_oModule->_oTemplate->displayBlockHistory($iUserId, $iSellerId),
+		);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-add_to_cart add_to_cart
+     * 
+     * @code bx_srv('bx_payment', 'add_to_cart', [...], 'Cart'); @endcode
+     * 
+     * Add an item described with method's params to shopping cart.
+     *
+     * @param $iSellerId integer value with seller ID.
+     * @param $mixedModuleId mixed value (ID, Name or URI) determining a module from which the action was initiated.
+     * @param $iItemId integer value with item ID.
+     * @param $iItemCount integer value with a number of items for purchasing.
+     * @param $aCustom array with custom data.
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentCart::serviceAddToCart
+     */
+    /** 
+     * @ref bx_payment-add_to_cart "add_to_cart"
+     */
+    public function serviceAddToCart($iSellerId, $mixedModuleId, $iItemId, $iItemCount, $aCustom = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$iModuleId = $this->_oModule->_oConfig->getModuleId($mixedModuleId);
+    	$iClientId = $this->_oModule->getProfileId();
+
+    	$mixedResult = $this->_oModule->checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount, $aCustom);
+    	if($mixedResult !== true)
+    		return $mixedResult;
+
+        $aSellerProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($iSellerId);
+        if(empty($aSellerProviders))
+            return array('code' => 5, 'message' => _t($CNF['T']['ERR_NOT_ACCEPT_PAYMENTS']));
+
+        $aCart = $this->_oModule->_oDb->getCartContent($iClientId);
+        $sCartItems = !empty($aCart['items']) ? $aCart['items'] : '';
+
+        $sCartItemsResult = false;
+        $this->_oModule->alert('before_add_to_cart', 0, $iClientId, [
+            'client_id' => $iClientId,
+            'seller_id' => $iSellerId, 
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+
+            'cart' => &$aCart,
+            'cart_items' => &$sCartItems,
+            'override_result' => &$sCartItemsResult,
+        ]);
+
+        $sCiDsc = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId));
+        if($sCartItemsResult === false) {            
+        if(strpos($sCartItems, $sCiDsc) !== false)
+                $sCartItemsResult = preg_replace_callback(
+                "/" . $this->_oModule->_oConfig->descriptorA2S(array(preg_quote($iSellerId, '/'), preg_quote($iModuleId, '/'), preg_quote($iItemId, '/'), '([0-9]+)')) . "/", function($aMatches) use($iSellerId, $iModuleId, $iItemId, $iItemCount) {
+                    return $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId, $aMatches[1] + $iItemCount));
+                },
+            	$sCartItems
+            );
+        else {
+            $sCartItem = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId, $iItemCount));
+                $sCartItemsResult = empty($sCartItems) ? $sCartItem : $sCartItems . $this->_oModule->_oConfig->getDivider('DIVIDER_DESCRIPTORS') . $sCartItem;
+            }
+        }
+
+        $aCartCustom = $aCart['customs'];
+        if(!empty($aCustom) && is_array($aCustom))
+            $aCartCustom[$sCiDsc] = !empty($aCartCustom[$sCiDsc]) && is_array($aCartCustom[$sCiDsc]) ? array_merge($aCartCustom[$sCiDsc], $aCustom) : $aCustom;
+
+        $this->_oModule->_oDb->setCartItems($iClientId, $sCartItemsResult, $aCartCustom);
+
+        $aInfo = $this->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId);
+        $iTotalQuantity = 0;
+        foreach($aInfo as $aCart)
+           $iTotalQuantity += $aCart['items_count'];
+
+        return array(
+        	'code' => 0, 
+        	'message' => _t($CNF['T']['MSG_ITEM_ADDED']), 
+        	'total_quantity' => $iTotalQuantity,
+	        //TODO: Update account submenu if it's needed.  
+        	'content' => '' //$this->_oModule->_oTemplate->displayToolbarSubmenu($aInfo)
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-delete_from_cart delete_from_cart
+     * 
+     * @code bx_srv('bx_payment', 'delete_from_cart', [...], 'Cart'); @endcode
+     * 
+     * Delete an item(s) from shopping cart.
+     *
+     * @param $iSellerId integer value with seller ID. The items owned by this seller will be removed only.
+     * @param $iModuleId (optional) integer value with module ID. If specified, the items related to this module will be removed only.
+     * @param $iItemId (optional) integer value with item ID. If specified, the item with this ID will be removed only.
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentCart::serviceDeleteFromCart
+     */
+    /** 
+     * @ref bx_payment-delete_from_cart "delete_from_cart"
+     */
+    public function serviceDeleteFromCart($iSellerId, $iModuleId = 0, $iItemId = 0)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+
+        $iClientId = $this->_oModule->getProfileId();
+        if(empty($iClientId))
+            return array('code' => 2, 'message' => _t($CNF['T']['ERR_REQUIRED_LOGIN']));
+
+        $aCart = $this->_oModule->_oDb->getCartContent($iClientId);
+
+        $aCartCustom = $aCart['customs'];
+        if(!empty($iModuleId) && !empty($iItemId)) {
+            $sCiDsc = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId));
+            if(!empty($aCartCustom[$sCiDsc]))
+                unset($aCartCustom[$sCiDsc]);
+        }
+        else {
+            $aCiDscs = array_keys($aCartCustom);
+            foreach($aCiDscs as $sCiDsc)
+                if(strpos($sCiDsc, $iSellerId . '_') === 0)
+                    unset($aCartCustom[$sCiDsc]);
+
+            $iModuleId = $iItemId = '[0-9\-]+';
+        }
+
+        $aCart['items'] = trim(preg_replace("'" . $this->_oModule->_oConfig->descriptorA2S(array(preg_quote($iSellerId, "'"), preg_quote($iModuleId, "'"), preg_quote($iItemId, "'"), '[0-9]+:?')) . "'", "", $aCart['items']), ":");
+        $this->_oModule->_oDb->setCartItems($iClientId, $aCart['items'], $aCartCustom);
+
+        $this->_oModule->alert('delete_from_cart', 0, 0, array(
+            'seller_id' => $iSellerId,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+        ));
+
+        return array('code' => 0, 'message' => _t($CNF['T']['MSG_ITEM_DELETED']));
+    }
+
+    public function getInfo($sType, $iUserId, $iSellerId = BX_PAYMENT_EMPTY_ID, $aItems = array())
+    {
+        if($iSellerId != BX_PAYMENT_EMPTY_ID && !empty($aItems))
+            return $this->_getInfo($sType, $iUserId, $iSellerId, $this->_oModule->_oConfig->descriptorsM2A($aItems));
+
+        $aContent = $this->_parseByVendor($iUserId);
+        if($iSellerId != BX_PAYMENT_EMPTY_ID)
+            return $this->_getInfo($sType, $iUserId, $iSellerId, (isset($aContent[$iSellerId]) ? $aContent[$iSellerId] : []));
+
+        $aResult = array();
+        foreach($aContent as $iSellerId => $aSellerItems)
+            $aResult[$iSellerId] = $this->_getInfo($sType, $iUserId, $iSellerId, $aSellerItems);
+
+        return $aResult;
+    }
+
+    /**
+     * Enter description here...
+     *
+     * @param  integer $iClientId client's ID
+     * @param  integer $iSellerId vendor's ID
+     * @param  array   $aItems    item descriptors(quaternions) from shopping cart.
+     * @return array   with full info about vendor and items.
+     */
+    protected function _getInfo($sType, $iClientId, $iSellerId, $aItems)
+    {
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+
+        $iItemsCount = 0;
+        $fItemsPrice = 0;
+        $aItemsInfo = array();
+        foreach($aItems as $aItem) {
+            $aCustom = isset($aItem['custom']) ? $aItem['custom'] : [];
+
+            //--- Get item main info
+            $aItemInfo = $this->_oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $iClientId, $aCustom));
+            if(empty($aItemInfo) || !is_array($aItemInfo)) {
+                if($bTypeSingle) {
+                    $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+                    $sCartItems = trim(preg_replace("'" . preg_quote($this->_oModule->_oConfig->descriptorA2S($aItem), "'") . ":?'", "", $sCartItems), ":");
+                    $this->_oModule->_oDb->setCartItems($iClientId, $sCartItems);
+                }
+
+                continue;
+            }
+
+            $aItemInfo['module_id'] = (int)$aItem['module_id'];
+            $aItemInfo['quantity'] = (int)$aItem['item_count'];
+
+            //--- Get item addons' info
+            $aItemAddons = array();
+            if(!empty($aItem['item_addons'])) {
+                $aAddons = $this->_oModule->_oConfig->s2a($aItem['item_addons']);
+                foreach($aAddons as $sAddon) {
+                    if(isset($aItemAddons[$sAddon])) {
+                        $aItemAddons[$sAddon]['quantity'] += 1;
+                        continue;
+                    }
+
+                    $aAddonInfo = $this->_oModule->callGetCartItem((int)$aItem['module_id'], array($sAddon, $iClientId, $aCustom));
+                    if(empty($aAddonInfo) || !is_array($aAddonInfo))
+                        continue;
+
+                    $aAddonInfo['module_id'] = (int)$aItem['module_id'];
+                    $aAddonInfo['quantity'] = 1;
+
+                    $aItemAddons[$sAddon] = $aAddonInfo;
+                }
+            }
+
+            $aItemInfo['addons'] = $aItemAddons;
+            $aItemsInfo[] = $aItemInfo;
+
+            //--- Update items' summary
+            $fAddonsPrice = 0;
+            foreach($aItemInfo['addons'] as $aAddonInfo)
+                $fAddonsPrice += $aAddonInfo['quantity'] * $this->_oModule->_oConfig->getPrice($sType, $aAddonInfo);
+
+            $iItemsCount += $aItemInfo['quantity'];
+            $fItemsPrice += $aItemInfo['quantity'] * ($this->_oModule->_oConfig->getPrice($sType, $aItemInfo) + $fAddonsPrice);
+        }
+
+        $aSeller = $this->_oModule->getVendorInfo((int)$iSellerId);
+        $aResult = array(
+            'client_id' => $iClientId,
+            'vendor_id' => $aSeller['id'],
+            'vendor_name' => $aSeller['name'],
+            'vendor_link' => $aSeller['link'],
+            'vendor_icon' => $aSeller['icon'],
+            'vendor_thumb' => $aSeller['thumb'],
+            'vendor_avatar' => $aSeller['avatar'],
+            'vendor_currency_code' => $aSeller['currency_code'],
+            'vendor_currency_sign' => $aSeller['currency_sign'],
+            'items_count' => $iItemsCount,
+            'items_price' => $fItemsPrice,
+            'items' => $aItemsInfo
+        );
+
+        $this->_oModule->alert('get_cart_info', 0, 0, array(
+           'type' => $sType,
+           'client_id' => $iClientId,
+           'seller_id' => $iSellerId,
+           'items' => $aItems,
+           'override_result' => &$aResult
+        ));
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 371 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentConfig.php

@@ -0,0 +1,371 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentConfig extends BxBaseModPaymentConfig
+{
+    protected $_bCreditsOnly;
+
+    protected $_iPayAttemptsMax;
+    protected $_iPayAttemptsInterval;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $sBaseUrl = BX_DOL_URL_ROOT . $this->getBaseUri();
+
+        $this->CNF = array_merge($this->CNF, [
+            // module icon
+            'ICON' => 'credit-card col-gray-dark',
+
+            // database tables
+            'TABLE_COMMISSIONS' => $aModule['db_prefix'] . 'commissions',
+            'TABLE_INVOICES' => $aModule['db_prefix'] . 'invoices',
+
+            // page URIs
+            'URL_JOIN' => 'page.php?i=payment-join',
+            'URL_CARTS' => 'page.php?i=payment-carts',
+            'URL_CART' => 'page.php?i=payment-cart',
+            'URL_CART_CHECKOUT' => $sBaseUrl . 'initialize_checkout/' . BX_PAYMENT_TYPE_SINGLE . '/',
+            'URL_AUTHORIZE' => $sBaseUrl . 'authorize_checkout/',
+            'URL_SUBSCRIBE' => $sBaseUrl . 'subscribe/',
+            'URL_SUBSCRIBE_JSON' => $sBaseUrl . 'subscribe_json/',
+            'URL_SUBSCRIPTIONS' => 'page.php?i=payment-sbs-list-my',
+            'URL_HISTORY' => 'page.php?i=payment-history',
+            'URL_ORDERS' => 'page.php?i=payment-orders',
+            'URL_INVOICES' => 'page.php?i=payment-invoices',
+            'URL_DETAILS' => 'page.php?i=payment-details',
+            'URL_RETURN' => 'page.php?i=payment-cart-thank-you',
+            'URL_RETURN_DATA' => $sBaseUrl . 'finalize_checkout/',
+            'URL_NOTIFY' => $sBaseUrl . 'notify/',
+            'URL_CHECKOUT_OFFLINE' => 'page.php?i=payment-checkout-offline',
+
+            'KEY_ARRAY_PRICE_SINGLE' => 'price_single',
+            'KEY_ARRAY_PRICE_RECURRING' => 'price_recurring',
+            'KEY_ARRAY_PERIOD_RECURRING' => 'period_recurring',
+            'KEY_ARRAY_PERIOD_UNIT_RECURRING' => 'period_unit_recurring',
+            'KEY_ARRAY_TRIAL_RECURRING' => 'trial_recurring',
+
+            // some params
+            'PARAM_CURRENCY_EXCHANGE_API' => 'bx_payment_currency_exchange_api',
+            'PARAM_CMSN_INVOICE_ISSUE_DAY' => 'bx_payment_inv_issue_day', //some day of month
+            'PARAM_CMSN_INVOICE_LIFETIME' => 'bx_payment_inv_lifetime', //in days
+            'PARAM_CMSN_INVOICE_EXPIRATION_NOTIFY' => 'bx_payment_inv_expiraction_notify', //in days, before expiration date
+
+            // objects
+            'OBJECT_FORM_PRELISTS_CURRENCIES' => 'bx_payment_currencies',
+            'OBJECT_PP_OFFLINE' => 'offline', //Offline payment provider
+            'OBJECT_PP_CREDITS' => 'credits', //Credits payment provider
+
+            'MODULE_CREDITS' => 'bx_credits',
+
+            // some language keys
+            'T' => [
+                'MSG_ITEM_ADDED' => '_bx_payment_msg_item_added',
+                'MSG_ITEM_DELETED' => '_bx_payment_msg_item_deleted',
+                'MSG_SINGLE_SELLER_MODE' => '_bx_payment_msg_single_seller',
+                'ERR_WRONG_DATA' => '_bx_payment_err_wrong_data',
+                'ERR_REQUIRED_LOGIN' => '_bx_payment_err_required_login',
+                'ERR_NOT_ACCEPT_PAYMENTS' => '_bx_payment_err_not_accept_payments',
+                'ERR_SELF_PURCHASE' => '_bx_payment_err_self_purchase',
+                'ERR_INACTIVE_VENDOR' => '_bx_payment_err_inactive_vendor',
+                'ERR_UNKNOWN_VENDOR' => '_bx_payment_err_unknown_vendor',
+
+                'BLOCK_TITLE_CART' => '_bx_payment_page_block_title_cart',
+
+                'POPUP_PROVIDERS_SELECT' => '_bx_payment_popup_title_crd_providers_select', 
+
+                'TXT_CART_PROVIDER' => '_bx_payment_txt_cart_'
+            ]
+        ]);
+
+        $this->_aHtmlIds = array(
+            'cart' => array(
+                'providers_select' => $this->_sName . '-cart-providers-select-',
+            ),
+            'history' => array(
+                'order_history_view' => $this->_sName . '-order-view-history',
+            ),
+            'subscription' => array(
+                'order_subscription_view' => $this->_sName . '-order-view-subscription',
+                'order_subscription_get_details' => $this->_sName . '-order-get-details-subscription',
+                'order_subscription_change_details' => $this->_sName . '-order-change-details-subscription',
+                'order_subscription_get_billing' => $this->_sName . '-order-get-billing-subscription',
+                'order_subscription_change_billing' => $this->_sName . '-order-change-billing-subscription',
+                'form_subscription_change_billing' => $this->_sName . '-form-change-billing-subscription',
+                'form_subscription_change_details' => $this->_sName . '-form-change-details-subscription',
+            ),
+            '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',	
+            ),
+            'commission' => array(
+                'popup_add' => $this->_sName . '-commission-popup-add',
+                'popup_edit' => $this->_sName . '-commission-popup-edit',
+            ),
+            'invoice' => array(
+                'popup_edit' => $this->_sName . '-invoice-popup-edit',
+            )
+        );
+
+        $this->_aPerPage = array(
+            'orders' => 10,
+            'history' => 10
+        );
+
+        $this->_aJsClasses = array(
+            'cart' => 'BxPaymentCart',
+            'history' => 'BxPaymentOrders',
+            'subscription' => 'BxPaymentSubscriptions',
+            'pending' => 'BxPaymentOrders',
+            'processed' => 'BxPaymentOrders',
+            'chargebee_v3' => 'BxPaymentProviderChargebeeV3',
+            'stripe' => 'BxPaymentProviderStripe',
+            'stripe_v3' => 'BxPaymentProviderStripeV3'
+        );
+
+        $this->_aJsObjects = array(
+            'cart' => 'oPaymentCart',
+            'history' => 'oPaymentOrders',
+            'subscription' => 'oBxPaymentSubscriptions',
+            'pending' => 'oPaymentOrders',
+            'processed' => 'oPaymentOrders',
+            'chargebee_v3' => 'oPaymentProviderChargebeeV3',
+            'stripe' => 'oPaymentProviderStripe',
+            'stripe_v3' => 'oPaymentProviderStripeV3'
+        );
+
+        $this->_bCreditsOnly = false;
+
+        $this->_iPayAttemptsMax = 3;
+        $this->_iPayAttemptsInterval = 86400; //--- in sec
+    }
+
+    public function init(&$oDb)
+    {
+        parent::init($oDb);
+
+        $sPrefix = $this->getPrefix('options');
+
+        $this->_bCreditsOnly = $this->_oDb->getParam($sPrefix . 'credits_only') == 'on';
+    }
+
+    public function isCreditsOnly()
+    {
+        return $this->_bCreditsOnly;
+    }
+
+    public function getPayAttemptsMax()
+    {
+        return $this->_iPayAttemptsMax;
+    }
+
+    public function getPayAttemptsInterval()
+    {
+        return $this->_iPayAttemptsInterval;
+    }
+
+    public function getPrice($sType, $aItem, $iPrecision = 2)
+    {
+    	$fPrice = 0;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_SINGLE')];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_RECURRING')];
+                break;
+        }
+
+        return round((float)$fPrice, $iPrecision);
+    }
+
+    public function getPeriod($sType, $aItem)
+    {
+        $mixedResult = false;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = [$aItem[$this->getKey('KEY_ARRAY_PERIOD_RECURRING')], $aItem[$this->getKey('KEY_ARRAY_PERIOD_UNIT_RECURRING')]];
+                break;
+        }
+
+        return $mixedResult;
+    }
+
+    public function getTrial($sType, $aItem)
+    {
+        $iTrial = 0;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_RECURRING:
+                $iTrial = $aItem[$this->getKey('KEY_ARRAY_TRIAL_RECURRING')];
+                break;
+        }
+
+        return (int)$iTrial;
+    }
+
+    public function getModuleId($mixedId)
+    {
+        if(is_numeric($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 a2s($a, $bEncodeString = true)
+    {
+        $s = json_encode($a);
+
+        return $bEncodeString ? base64_encode($s) : $s;
+    }
+
+    public function s2a($s, $bDecodeString = true)
+    {
+        if($bDecodeString)
+            $s = base64_decode($s);
+
+        return json_decode($s, true);
+    }
+
+    public function urlEncode($s)
+    {
+        return urlencode(base64_encode($s));
+    }
+
+    public function urlDecode($s)
+    {
+        return base64_decode(urldecode($s));
+    }
+
+    public function descriptorA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTOR'), $a);
+    }
+
+    public function descriptorS2A($s) 
+    {
+    	return explode($this->getDivider('DIVIDER_DESCRIPTOR'), $s);
+    }
+
+    public function descriptorsA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTORS'), $a);
+    }
+
+    /**
+     * 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)
+    {
+        $aResults = array();
+
+        if(is_string($mixed))
+           $aItems = explode($this->getDivider('DIVIDER_DESCRIPTORS'), $mixed);
+        else if(is_array($mixed))
+           $aItems = $mixed;
+        else
+            $aItems = array();
+
+        foreach($aItems as $mixedItem) {
+            $aItem = is_array($mixedItem) ? $mixedItem : $this->descriptorS2A($mixedItem);
+
+            $aResult = array('vendor_id' => $aItem[0], 'module_id' => $aItem[1], 'item_id' => $aItem[2], 'item_count' => $aItem[3]);
+            if(isset($aItem[4]))
+                $aResult['item_addons'] = $aItem[4];
+
+            $aResults[] = $aResult;
+        }
+
+        return $aResults;
+    }
+
+    public function putCustom($mDsc, $aCustom, &$aCustoms)
+    {
+        if(empty($aCustom) || !is_array($aCustom))
+            return;
+
+        if(is_array($mDsc))
+            $mDsc = $this->descriptorA2S(array_slice($mDsc, 0, 3));
+
+        $aCustoms[$mDsc] = !empty($aCustoms[$mDsc]) && is_array($aCustoms[$mDsc]) ? array_merge($aCustoms[$mDsc], $aCustom) : $aCustom;
+    }
+
+    public function getCustom($mDsc, &$aCustoms)
+    {
+        if(is_array($mDsc))
+            $mDsc = $this->descriptorA2S(array_slice($mDsc, 0, 3));
+
+        if(empty($aCustoms) || !is_array($aCustoms) || empty($aCustoms[$mDsc]))
+            return array();
+
+        return $aCustoms[$mDsc];
+    }
+
+    public function pullCustom($mDsc, &$aCustoms)
+    {
+        if(is_array($mDsc))
+            $mDsc = $this->descriptorA2S(array_slice($mDsc, 0, 3));
+
+        if(empty($aCustoms) || !is_array($aCustoms) || empty($aCustoms[$mDsc]))
+            return array();
+
+        $aResult = $aCustoms[$mDsc];
+        unset($aCustoms[$mDsc]);           
+
+        return $aResult;
+    }
+
+    public function http2https($s)
+    {
+    	if(strncmp($s, 'https://', 8) === 0)
+    		return $s;
+
+        return 'https://' . bx_ltrim_str($s, 'http://');
+    }
+
+    public function sortByColumn($sColumn, &$aValues)
+    {
+        return usort($aValues, function($aV1, $aV2) use ($sColumn) {
+            if($aV1[$sColumn] == $aV2[$sColumn])
+                return 0;
+
+            return $aV1[$sColumn] < $aV2[$sColumn] ? -1 : 1;
+        });
+    }
+}
+
+/** @} */

+ 891 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentDb.php

@@ -0,0 +1,891 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentDb extends BxBaseModPaymentDb
+{
+    function __construct(&$oConfig)
+    {
+        parent::__construct($oConfig);
+    }
+
+    public function getModulesWithPayments()
+    {
+    	$sQuery = $this->prepare("SELECT `name` FROM `" . $this->_sPrefix . "modules`");
+        return $this->getColumn($sQuery);
+    }
+
+    /**
+     * Payment details methods
+     */
+    public function getForm($sPaymentProvider = '')
+    {
+        $sWhereClause = '';
+
+        if(!empty($sPaymentProvider))
+            $sWhereClause .= $this->prepareAsString(" AND `tp`.`name`=?", $sPaymentProvider);
+        
+        $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`,
+                `tp`.`for_owner_only` AS `provider_for_owner_only`,
+                `tp`.`single_seller` AS `provider_single_seller`,
+                `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`
+            WHERE `tp`.`active`='1'" . $sWhereClause . "
+            ORDER BY `tp`.`order` ASC, `tpo`.`order` ASC";
+
+        return $this->getAll($sQuery);
+    }
+
+    public function getProviders($aParams = array())
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sWhereClause = $sOrderClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'by_name':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'name' => $aParams['name']
+                    );
+
+                    $sWhereClause = " AND `tp`.`name`=:name";
+                    break;
+
+                case 'for_single':
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = 'name';
+
+                    $sWhereClause = " AND `tp`.`for_single`='1'";
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause .= " AND `tp`.`active`='1'";
+
+                    if(isset($aParams['order']) && $aParams['order'] === true)
+                        $sOrderClause = "`tp`.`order` ASC";
+                    break;
+
+                case 'for_recurring':
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = 'name';
+
+                    $sWhereClause = " AND `tp`.`for_recurring`='1'";
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause .= " AND `tp`.`active`='1'";
+
+                    if(isset($aParams['order']) && $aParams['order'] === true)
+                        $sOrderClause = "`tp`.`order` ASC";
+                    break;
+
+                case 'all':
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = 'name';
+
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause = " AND `tp`.`active`='1'";
+
+                    if(isset($aParams['order']) && $aParams['order'] === true)
+                        $sOrderClause = "`tp`.`order` ASC";
+                    break;
+            }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = " ORDER BY " . $sOrderClause;
+                
+        $aMethod['params'][0] = "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`.`for_single` AS `for_single`,
+                `tp`.`for_recurring` AS `for_recurring`,
+                `tp`.`class_name` AS `class_name`,
+                `tp`.`class_file` AS `class_file`
+            FROM `" . $this->_sPrefix . "providers` AS `tp`
+            WHERE 1" . $sWhereClause . $sOrderClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getOption($aParams)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`tpo`.*";
+        $sJoinClause = $sWhereClause = "";
+        if(!empty($aParams['type']))
+	        switch($aParams['type']) {
+                    case 'by_pid_and_name':
+                        $aMethod['name'] = 'getRow';
+                        $aMethod['params'][1] = array(
+                            'provider_id' => $aParams['provider_id'],
+                            'name' => $aParams['name'],
+                        );
+
+                        $sWhereClause = " AND `tpo`.`provider_id`=:provider_id AND `tpo`.`name`=:name";
+                        break;
+                }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . $this->_sPrefix . "providers_options` AS `tpo` " . $sJoinClause . " WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getOptions($iUserId = BX_PAYMENT_EMPTY_ID, $iProviderId = 0)
+    {
+        $aBinding = [
+            'user_id' => $iUserId
+        ];
+
+        if($iUserId == BX_PAYMENT_EMPTY_ID && empty($iProviderId))
+           return $this->getAll("SELECT `id`, `name`, `type` FROM `" . $this->_sPrefix . "providers_options`");
+
+        $sWhereAddon = "";
+        if(!empty($iProviderId)) {
+            $aBinding['provider_id'] = $iProviderId;
+
+            $sWhereAddon = " AND `tpo`.`provider_id`=:provider_id";
+        }
+
+        $sQuery = "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`=:user_id ORDER BY `tpo`.`order`";
+
+        return $this->getAllWithKey($sQuery, 'name', $aBinding);
+    }
+
+    public function getOptionsByProvider($mixedProvider)
+    {
+        $aBindings = [
+            'provider' => $mixedProvider
+        ];
+
+        $sJoinClause = $sWhereClause = '';
+        if(!is_numeric($mixedProvider)) {
+            $sJoinClause = " LEFT JOIN `" . $this->_sPrefix . "providers` AS `tp` ON `tpo`.`provider_id`=`tp`.`id`";
+            $sWhereClause = " AND `tp`.`name`=:provider";
+        }
+        else
+            $sWhereClause = " AND `tpo`.`provider_id`=:provider";
+
+        return $this->getAll("SELECT `tpo`.`id`, `tpo`.`name`, `tpo`.`type` FROM `" . $this->_sPrefix . "providers_options` AS `tpo`" . $sJoinClause . " WHERE 1" . $sWhereClause, $aBindings);
+    }
+
+    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);
+    }
+
+    public function getCurrencyExchangeRate($sCode)
+    {
+        return $this->getOne("SELECT `rate` FROM `" . $this->_sPrefix . "currencies` WHERE `code`=:code LIMIT 1", [
+            'code' => $sCode
+        ]);
+    }
+
+    public function updateCurrencyExchangeRate($sCode, $fRate)
+    {
+        return $this->query("INSERT INTO `" . $this->_sPrefix . "currencies`(`code`, `rate`) VALUES(:code, :rate) ON DUPLICATE KEY UPDATE `rate`=:rate", [
+            'code' => $sCode,
+            'rate' => $fRate
+        ]);
+    }
+
+    public function deleteCurrencyExchangeRate($sCode)
+    {
+        return $this->query("DELETE FROM `" . $this->_sPrefix . "currencies` WHERE `code`=:code", [
+            'code' => $sCode
+        ]) !== false;
+    }
+
+    /**
+     * 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 getCartContent($iId)
+    {
+        $aCart = $this->getRow("SELECT * FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=:client_id LIMIT 1", [
+            'client_id' => $iId
+        ]);
+
+        if(empty($aCart) || !is_array($aCart))
+            $aCart = ['items' => '', 'customs' => []];
+
+        if(!empty($aCart['customs']))
+            $aCart['customs'] = is_string($aCart['customs']) ? $this->_oConfig->s2a($aCart['customs'], false) : $aCart['customs'];
+        else 
+            $aCart['customs'] = [];
+
+        return $aCart;
+    }
+
+    public function setCartItems($iId, $sItems, $aCustoms = array())
+    {
+        $sItems = trim($sItems, ":");
+        if(empty($sItems))
+            return $this->query("DELETE FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=:client_id LIMIT 1", array(
+                'client_id' => $iId
+            ));
+
+        return $this->query("REPLACE INTO `" . $this->_sPrefix . "cart` SET `client_id`=:client_id, `items`=:items, `customs`=:customs", array(
+            'client_id' => $iId,
+            'items' => $sItems,
+            'customs' => !empty($aCustoms) && is_array($aCustoms) ? $this->_oConfig->a2s($aCustoms, false) : ''
+        ));
+    }
+
+    public function getVendorInfoProvidersSingle($iVendorId, $bActiveOnly = false)
+    {
+        $aParams = ['type' => 'for_single', 'order' => true];
+        if($bActiveOnly)
+            $aParams['active'] = true;
+        
+    	return $this->getVendorInfoProviders($iVendorId, $aParams);
+    }
+
+    public function getVendorInfoProvidersRecurring($iVendorId, $bActiveOnly = false)
+    {
+        $aParams = ['type' => 'for_recurring', 'order' => true];
+        if($bActiveOnly)
+            $aParams['active'] = true;
+        
+    	return $this->getVendorInfoProviders($iVendorId, $aParams);
+    }
+
+    public function getVendorInfoProviders($iVendorId, $aParams = [])
+    {
+        if(empty($aParams))
+            $aParams = ['type' => 'all', 'order' => true];
+
+        $aProviders = $this->getProviders($aParams);
+        $aOptions = $this->getOptions($iVendorId);
+
+        $aResult = [];
+        foreach($aProviders as $sProvider => $aProvider) {
+            if(!isset($aOptions[$aProvider['option_prefix'] . 'active']) || $aOptions[$aProvider['option_prefix'] . 'active']['value'] != 'on') 
+                continue;
+
+            if(isset($aOptions[$aProvider['option_prefix'] . 'hidden']) && $aOptions[$aProvider['option_prefix'] . 'hidden']['value'] == 'on') 
+                continue;
+
+            foreach($aOptions as $sName => $aOption)
+                if(strpos($sName, $aProvider['option_prefix']) !== false)
+                    $aProvider['options'][$sName] = $aOption;
+
+            $aResult[$sProvider] = $aProvider;
+        }
+
+        return $aResult;
+    }
+
+    public function getAdminsIds()
+    {
+        $sQuery = "SELECT 
+        		`tp`.`id` AS `id`,
+        		`tp`.`type` AS `type`  
+        	FROM `sys_profiles` AS `tp` 
+        	INNER JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` AND `ta`.`role`&" . BX_DOL_ROLE_ADMIN . " 
+        	WHERE 
+        		`tp`.`type`<>'system' AND `tp`.`status`='active' 
+        	ORDER BY `tp`.`id` ASC";
+
+        $aAdmins = $this->getAllWithKey($sQuery, 'id');
+        foreach($aAdmins as $iId => $aAdmin)
+            if(!BxDolService::call($aAdmin['type'], 'act_as_profile'))
+                unset($aAdmins[$iId]);
+
+        return array_keys($aAdmins);
+    }
+
+
+	/*
+     * Pending Orders methods
+     */
+    public function getOrderPending($aParams)
+    {
+    	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
+
+    	$sWhereClause = $sLimitClause = '';
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['params'][1] = array(
+                	'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `id`=:id";
+                $sLimitClause = " LIMIT 1";
+                break;
+
+            case 'order':
+            	$aMethod['params'][1] = array(
+                	'order' => $aParams['order']
+                );
+
+            	$sWhereClause = " AND `order`=:order";
+                $sLimitClause = " LIMIT 1";
+                break;
+
+            case 'mixed':
+                $aMethod['name'] = 'getAll';
+
+                $sWhereClause = ' AND ' . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                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, $sType, $sProvider, $aCartInfo, $aCustom = [])
+    {
+        $sItems = "";
+        foreach($aCartInfo['items'] as $aItem) {
+            $sItems .= $this->_oConfig->descriptorA2S(array($aItem['author_id'], $aItem['module_id'], $aItem['id'], $aItem['quantity'])) . ':';
+
+            if(empty($aItem['addons']) || !is_array($aItem['addons']))
+                continue;
+
+            foreach($aItem['addons'] as $sAddon => $aAddon)
+                $sItems .= $this->_oConfig->descriptorA2S(array($aAddon['author_id'], $aAddon['module_id'], $aAddon['id'], $aAddon['quantity'])) . ':';
+        }
+
+        $sCurrency = $aCartInfo['vendor_currency_code'];
+        $sCurrencyDefault = $this->_oConfig->getDefaultCurrencyCode();
+
+        $aData = ['cur_def' => $sCurrencyDefault];
+        if(strcmp($sCurrency, $sCurrencyDefault) != 0)
+            $aData['cur_rate'] = $this->getCurrencyExchangeRate($sCurrency);
+
+        $aSet = [
+            'client_id' => $iClientId,
+            'seller_id' => $aCartInfo['vendor_id'],
+            'type' => $sType, 
+            'provider' => $sProvider,
+            'items' => trim($sItems, ':'),
+            'customs' => !empty($aCustom) && is_array($aCustom) ? $this->_oConfig->a2s($aCustom, false) : '',
+            'amount' => $aCartInfo['items_price'],
+            'currency' => $sCurrency,
+            'data' => !empty($aData) ? serialize($aData) : ''
+        ];
+
+        return (int)$this->query("INSERT INTO `" . $this->_sPrefix . "transactions_pending` SET " . $this->arrayToSQL($aSet) . ", `date`=UNIX_TIMESTAMP()") > 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 deleteOrderPending($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'));
+
+        $sSelectClause = "`tt`.`id`, `tt`.`license`, `ttp`.`type`, `tt`.`client_id`, `tt`.`seller_id`, `tt`.`author_id`, `tt`.`module_id`, `tt`.`item_id`, `tt`.`item_count`, `tt`.`amount`, `tt`.`date`, `ttp`.`order`, `ttp`.`error_msg`, `ttp`.`provider`";
+        $sWhereClause = $sGroupClause = "";
+
+        switch($aParams['type']) {
+            case 'id':
+            	$aMethod['params'][1] = array(
+                    'id' => $aParams['id']
+                );
+
+                $sWhereClause = " AND `tt`.`id`=:id";
+                break;
+
+            case 'new':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                    'seller_id' => $aParams['seller_id']
+                );
+
+                $sWhereClause = " AND `tt`.`seller_id`=:seller_id AND `tt`.`new`='1'";
+                break;
+
+            case 'pending_id':
+                if(empty($aParams['with_key'])) {
+                    $aMethod['name'] = 'getAll';
+                    $aMethod['params'][1] = array(
+                        'pending_id' => $aParams['pending_id']
+                    );
+                }
+                else {
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = $aParams['with_key'];
+                    $aMethod['params'][2] = array(
+                        'pending_id' => $aParams['pending_id']
+                    );
+                }
+
+                $sWhereClause = " AND `tt`.`pending_id`=:pending_id";
+                break;
+
+            case 'clients':
+                $aMethod['name'] = 'getColumn';
+                $aMethod['params'][1] = array(
+                    'seller_id' => $aParams['seller_id']
+                );
+
+                $sSelectClause = "DISTINCT `tt`.`client_id`";
+                $sWhereClause = " AND `tt`.`seller_id`=:seller_id";
+                break;
+
+            case 'authors':
+                $aMethod['name'] = 'getColumn';
+                $aMethod['params'][1] = array(
+                    'seller_id' => $aParams['seller_id']
+                );
+
+                $sSelectClause = "DISTINCT `tt`.`author_id`";
+                $sWhereClause = " AND `tt`.`seller_id`=:seller_id";
+                break;
+
+            case 'license':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                    'license' => $aParams['license']
+                );
+
+                $sWhereClause = " AND `tt`.`license`=:license";
+                break;
+            
+            case 'income':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                    'period_start' => $aParams['period_start'],
+                    'period_end' => $aParams['period_end']
+                );
+
+                $sSelectClause = '`tt`.`author_id` AS `id`, SUM(`tt`.`amount`) AS `amount`';
+                $sWhereClause = ' AND `tt`.`date`>=:period_start AND `tt`.`date`<=:period_end';
+                $sGroupClause = '`tt`.`author_id`';
+                break;
+
+            case 'mixed':
+                $aMethod['name'] = 'getAll';
+
+                $sWhereClause = ' AND ' . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+
+        }
+
+        if(!empty($sGroupClause))
+            $sGroupClause = ' GROUP BY ' . $sGroupClause;
+
+        $aMethod['params'][0] = "SELECT
+                " . $sSelectClause . "
+            FROM `" . $this->_sPrefix . "transactions` AS `tt`
+            LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id`
+            WHERE 1" . $sWhereClause . $sGroupClause;
+
+        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)
+    {        
+        return $this->updateOrdersProcessed($aValues, array('id' => $iId));
+    }
+
+    public function updateOrdersProcessed($aValues, $aWhere)
+    {
+        if(empty($aValues) || !is_array($aValues) || empty($aWhere) || !is_array($aWhere))
+            return false;
+
+        return (int)$this->query("UPDATE `" . $this->_sPrefix . "transactions` SET " . $this->arrayToSQL($aValues) . " WHERE " . $this->arrayToSQL($aWhere, ' AND ')) > 0;
+    }
+
+    public function deleteOrderProcessed($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);
+    }
+
+    /*
+     * Subscriptions methods
+     */
+    public function getOrderSubscription($aParams)
+    {
+        return $this->getOrderPending($aParams);
+    }
+
+    public function getSubscription($aParams)
+    {
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`ts`.*";
+    	$sJoinClause = $sWhereClause = $sLimitClause = '';
+        switch($aParams['type']) {
+            case 'pending_id':
+                $aMethod['name'] = 'getRow';
+            	$aMethod['params'][1] = array(
+                    'pending_id' => $aParams['pending_id']
+                );
+
+                $sWhereClause = " AND `ts`.`pending_id`=:pending_id";
+                $sLimitClause = " LIMIT 1";
+                break;
+
+            case 'mixed':
+                $sWhereClause = " AND " . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+
+            case 'mixed_ext':
+                $sSelectClause .= ", `ttp`.`client_id`, `ttp`.`seller_id`, `ttp`.`type`, `ttp`.`provider`, `ttp`.`order`";
+                $sJoinClause = "LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id`";
+                $sWhereClause = " AND " . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+
+            case 'time_tracker':
+                $aMethod['params'][1] = array(
+                    'status_active' => $aParams['status_active'],
+                    'status_trial' => $aParams['status_trial'],
+                    'status_unpaid' => $aParams['status_unpaid'],
+                    'pay_attempts_max' => $aParams['pay_attempts_max'],
+                    'pay_attempts_interval' => $aParams['pay_attempts_interval']
+                );
+
+                $sSelectClause .= ", `ttp`.`client_id`, `ttp`.`seller_id`, `ttp`.`type`, `ttp`.`provider`, `ttp`.`amount`, `ttp`.`order`";
+                $sJoinClause = "LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` INNER JOIN `" . $this->_sPrefix . "providers` AS `tp` ON `ttp`.`provider`=`tp`.`name` AND `tp`.`time_tracker`='1'";
+                $sWhereClause = " AND `ts`.`date_next`<>0 AND `ts`.`date_next`<=UNIX_TIMESTAMP() AND (`ts`.`status`=:status_active OR `ts`.`status`=:status_trial OR (`ts`.`status`=:status_unpaid AND `ts`.`pay_attempts`<:pay_attempts_max AND DATE_ADD(FROM_UNIXTIME(`ts`.`date_next`), INTERVAL `ts`.`pay_attempts`*:pay_attempts_interval SECOND)<=NOW()))";
+                break;
+        }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . $this->_sPrefix . "subscriptions` AS `ts` " . $sJoinClause . " WHERE 1 " . $sWhereClause . $sLimitClause;
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function isSubscriptionByPending($iPending)
+    {
+    	$aSubscription = $this->getSubscription(array(
+            'type' => 'pending_id', 
+            'pending_id' => $iPending
+    	));
+
+    	return !empty($aSubscription) && is_array($aSubscription);
+    }
+
+    public function insertSubscription($aValues)
+    {
+        if(empty($aValues) || !is_array($aValues))
+            return false;
+
+        $sSetClause = $this->arrayToSQL($aValues);
+        if(empty($aValues['date_add']))
+            $sSetClause .= ", `date_add`=UNIX_TIMESTAMP()";
+
+        return (int)$this->query("INSERT INTO `" . $this->_sPrefix . "subscriptions` SET " . $sSetClause) > 0;
+    }
+
+    public function updateSubscription($aValues, $aWhere)
+    {
+        if(empty($aValues) || !is_array($aValues) || empty($aWhere) || !is_array($aWhere))
+            return false;
+
+        return (int)$this->query("UPDATE `" . $this->_sPrefix . "subscriptions` SET " . $this->arrayToSQL($aValues) . " WHERE " . $this->arrayToSQL($aWhere, ' AND ')) > 0;
+    }
+
+    public function deleteSubscription($mixedId, $sReason)
+    {
+    	if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        //--- Move to deleted subscriptions table.   
+    	$sQuery = "INSERT IGNORE INTO `" . $this->_sPrefix . "subscriptions_deleted` SELECT *, :reason AS `reason`, UNIX_TIMESTAMP() AS `deleted` FROM `" . $this->_sPrefix . "subscriptions` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")";
+        $this->query($sQuery, array(
+            'reason' => $sReason
+        ));
+
+        return (int)$this->query("DELETE FROM `" . $this->_sPrefix . "subscriptions` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+
+    //--- 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);
+    }
+
+
+    /*
+     * Commissions methods
+     */
+    public function getCommissions($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`tc`.*";
+        $sWhereClause = $sOrderClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'max_order':
+                    $aMethod['name'] = 'getOne';
+                    $aMethod['params'][1] = array();
+
+                    $sSelectClause = "IFNULL(MAX(`tc`.`order`), 0)";
+                    break;
+
+                case 'id':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'id' => $aParams['id']
+                    );
+
+                    $sWhereClause = " AND `tc`.`id`=:id";
+                    break;
+
+                case 'acl_id':
+                    $aMethod['name'] = 'getAll';
+                    $aMethod['params'][1] = array(
+                        'acl_id' => $aParams['acl_id']
+                    );
+
+                    $sWhereClause = " AND (`tc`.`acl_id`=:acl_id OR `tc`.`acl_id`=0)";
+                    $sOrderClause = "`tc`.`order` ASC";
+                    break;
+
+                case 'all':
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause = " AND `tc`.`active`='1'";
+                    break;
+            }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = " ORDER BY " . $sOrderClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_COMMISSIONS'] . "` AS `tc`
+            WHERE 1" . $sWhereClause . $sOrderClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getInvoices($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`ti`.*";
+        $sWhereClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'index':
+                    $aMethod['name'] = 'getOne';
+                    $aMethod['params'][1] = array(
+                        'commissionaire_id' => $aParams['commissionaire_id'],
+                        'committent_id' => $aParams['committent_id'],
+                    );
+
+                    $sSelectClause = "COUNT(`ti`.`id`) + 1";
+                    $sWhereClause = " AND `ti`.`commissionaire_id`=:commissionaire_id AND `ti`.`committent_id`=:committent_id";
+                    break;
+
+                case 'id':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'id' => $aParams['id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`id`=:id";
+                    break;
+
+                case 'commissionaire_id':
+                    $aMethod['params'][1] = array(
+                        'commissionaire_id' => $aParams['commissionaire_id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`commissionaire_id`=:commissionaire_id";
+                    break;
+
+                case 'committent_id':
+                    $aMethod['params'][1] = array(
+                        'committent_id' => $aParams['committent_id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`committent_id`=:committent_id";
+
+                    if(!empty($aParams['period_start'])) {
+                        $aMethod['params'][1]['period_start'] = (int)$aParams['period_start'];
+
+                        $sWhereClause .= " AND `ti`.`period_start`=:period_start";
+                    }
+
+                    if(!empty($aParams['period_end'])) {
+                        $aMethod['params'][1]['period_end'] = (int)$aParams['period_end'];
+
+                        $sWhereClause .= " AND `ti`.`period_end`=:period_end";
+                    }
+                    break;
+
+                case 'expiring':
+                    $aMethod['params'][1] = array(
+                        'notify_days' => $this->_oConfig->getInvoiceExpirationNotify(),
+                        'status' => BX_PAYMENT_INV_STATUS_UNPAID
+                    );
+
+                    $sWhereClause = " AND DATE_SUB(FROM_UNIXTIME(`ti`.`date_due`), INTERVAL :notify_days DAY) < NOW() AND DATE_SUB(FROM_UNIXTIME(`ti`.`date_due`), INTERVAL (:notify_days - 1) DAY) > NOW() AND `ti`.`status`=:status";
+                    break;
+
+                case 'overdue':
+                    $aMethod['params'][1] = array(
+                        'status_unpaid' => BX_PAYMENT_INV_STATUS_UNPAID,
+                        'status_overdue' => BX_PAYMENT_INV_STATUS_OVERDUE
+                    );
+
+                    $sWhereClause = " AND `ti`.`date_due` < UNIX_TIMESTAMP() AND (`ti`.`status`=:status_unpaid OR (`ti`.`status`=:status_overdue AND `ti`.`ntf_due`='0'))";
+                    break;
+
+                case 'status':
+                    $aMethod['params'][1] = array(
+                        'status' => $aParams['status']
+                    );
+
+                    $sWhereClause = " AND `ti`.`status`=:status";
+                    
+                    if(isset($aParams['count']) && $aParams['count'] === true) {
+                        $sSelectClause = "COUNT(`ti`.`id`)";
+                        $aMethod['name'] = 'getOne';
+                    }
+
+                    if(isset($aParams['committent_id'])) {
+                        $aMethod['params'][1]['committent_id'] = $aParams['committent_id'];
+
+                        $sWhereClause .= " AND `ti`.`committent_id`=:committent_id";
+                    }
+                    break;
+
+                case 'all_count':
+                    $sSelectClause = "COUNT(`ti`.`id`)";
+                    $aMethod['name'] = 'getOne';
+                    break;
+                
+                case 'all':
+                    break;
+            }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_INVOICES'] . "` AS `ti`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertInvoice($aValues)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->query("INSERT INTO `" . $CNF['TABLE_INVOICES'] . "` SET " . $this->arrayToSQL($aValues));
+    }
+
+    public function updateInvoice($mixedId, $aValues)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("UPDATE `" . $CNF['TABLE_INVOICES'] . "` SET " . $this->arrayToSQL($aValues) . " WHERE `id` IN (" . $this->implode_escape($mixedId) . ')') > 0;
+    }
+
+    public function deleteInvoice($mixedId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $CNF['TABLE_INVOICES'] . "` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
+    
+    /**
+     * For Stripe integration only
+     */
+    public function getStrpPaymentPending($sSubscriptionId)
+    {
+        $aResult = $this->getRow("SELECT * FROM `" . $this->_sPrefix . "stripe_payments_pending` WHERE `subscription_id`=:subscription_id", [
+            'subscription_id' => $sSubscriptionId
+        ]);
+
+        if(!empty($aResult) && is_array($aResult))
+            $this->deleteStrpPaymentPending($sSubscriptionId);
+
+        return $aResult;
+    }
+
+    public function insertStrpPaymentPending($sSubscriptionId, $fAmount, $sCurrency)
+    {
+        return $this->query("INSERT IGNORE INTO `" . $this->_sPrefix . "stripe_payments_pending` SET " . $this->arrayToSQL([
+            'subscription_id' => $sSubscriptionId,
+            'amount' => $fAmount,
+            'currency' => $sCurrency
+        ])) !== false;
+    }
+
+    public function deleteStrpPaymentPending($sSubscriptionId)
+    {
+        return $this->query("DELETE FROM `" . $this->_sPrefix . "stripe_payments_pending` WHERE `subscription_id`=:subscription_id", [
+            'subscription_id' => $sSubscriptionId
+        ]) !== false;
+    }
+}
+
+/** @} */

+ 128 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentDetails.php

@@ -0,0 +1,128 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentDetails extends BxBaseModPaymentDetails
+{
+    protected $_bIsApi;
+    protected $_sLangsPrefix;
+
+    function __construct()
+    {
+        $this->MODULE = 'bx_payment';
+
+        parent::__construct();
+
+        $this->_bIsApi = bx_is_api();
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_details get_block_details
+     * 
+     * @code bx_srv('bx_payment', 'get_block_details', [...], 'Details'); @endcode
+     * 
+     * Get page block with payment providers' configuration settings represented as subforms.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentDetails::serviceGetBlockDetails
+     */
+    /** 
+     * @ref bx_payment-get_block_details "get_block_details"
+     */
+    public function serviceGetBlockDetails($iUserId = BX_PAYMENT_EMPTY_ID, $mixedPaymentProvider = false)
+    {
+        if(!$this->_oModule->isLogged())
+            return ($sMsg = $this->_sLangsPrefix . 'err_required_login') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox(_t($sMsg));
+
+        $iUserId = $iUserId != BX_PAYMENT_EMPTY_ID ? $iUserId : $this->_oModule->getProfileId();
+
+        $aPaymentProviders = [];
+        if(!$mixedPaymentProvider) {
+            $aPaymentProviders = $this->_oModule->_oDb->getProviders([
+                'type' => 'all', 
+                'active' => true, 
+                'order' => true
+            ]);
+
+            if(!empty($aPaymentProviders) && is_array($aPaymentProviders))
+                $aPaymentProviders = array_keys($aPaymentProviders);
+        }
+        else {
+            if(is_array($mixedPaymentProvider))
+                $aPaymentProviders = $mixedPaymentProvider;
+            else if(is_string($mixedPaymentProvider))
+                $aPaymentProviders = [$mixedPaymentProvider];
+        }
+
+        if(!$aPaymentProviders)
+            return ($sMsg = $this->_sLangsPrefix . 'msg_no_results') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox(_t($sMsg));
+
+        $mixedContent = $this->_bIsApi ? [] : '';
+        foreach($aPaymentProviders as $iIndex => $sPaymentProvider) {
+            $mixedForm = $this->getForm($iUserId, $sPaymentProvider);
+
+            if($this->_bIsApi)
+                $mixedContent[] = bx_api_get_block('form', $mixedForm, [
+                    'id' => $iIndex + 1,
+                    'ext' => [
+                        'name' => $this->MODULE, 
+                        'request' => ['url' => '/api.php?r=' . $this->MODULE . '/get_block_details/Details', 'immutable' => true]
+                    ]
+                ]);
+            else
+                $mixedContent .= $this->_oModule->_oTemplate->parseHtmlByName('details_form.html', [
+                    'provider' => str_replace('_', '-', $sPaymentProvider),
+                    'form' => $mixedForm
+                ]);
+        }
+
+        if(empty($mixedContent))
+            return ($sMsg = $this->_sLangsPrefix . 'msg_no_results') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : MsgBox(_t($sMsg));
+
+        return $this->_bIsApi ? $mixedContent : $mixedContent;
+    }
+
+    public function getForm($iProfileId, $sPaymentProvider)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = BxTemplFormView::getObjectInstance($CNF['OBJECT_FORM_DETAILES'], $CNF['OBJECT_FORM_DETAILES_EDIT']);
+        $oForm->initWithParams($iProfileId, $sPaymentProvider);
+        $oForm->initChecker();
+        if($oForm->isSubmitted()) {
+            if($oForm->isValid()) {
+                $aOptions = $this->_oModule->_oDb->getOptionsByProvider($sPaymentProvider);
+                foreach($aOptions as $aOption) {
+                    $sValue = bx_get($aOption['name']) !== false ? bx_get($aOption['name']) : '';
+                    $this->_oModule->_oDb->updateOption($iProfileId, $aOption['id'], bx_process_input($sValue));
+                }
+
+                header('Location: ' . bx_absolute_url(BxDolPermalinks::getInstance()->permalink('page.php?i=payment-details', ['pp' => $sPaymentProvider])));
+                return;
+            }
+            else
+                foreach($oForm->aInputs as $aInput)
+                    if(!empty($aInput['error']) && !empty($aInput['attrs']['bx-data-provider'])) {
+                        $sProviderBlock = 'provider_' . (int)$aInput['attrs']['bx-data-provider'] . '_begin';
+                        if(!empty($oForm->aInputs[$sProviderBlock]))
+                            $oForm->aInputs[$sProviderBlock]['collapsed'] = false;
+                    }
+        }
+
+        return $this->_bIsApi ? $oForm->getCodeAPI() : $oForm->getCode();
+    }
+}
+
+/** @} */

+ 195 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentFormDetails.php

@@ -0,0 +1,195 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentDetailsFormCheckerHelper extends BxDolFormCheckerHelper
+{
+    function checkHttps ($s)
+    {
+        return empty($s) || substr(BX_DOL_URL_ROOT, 0, 5) == 'https';
+    }
+}
+
+class BxPaymentFormDetails extends BxTemplFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_sLangsPrefix;
+    protected $_bCollapseFirst;
+    
+    protected $_iProfileId;
+    protected $_sPaymentProvider;
+
+    function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+
+        $this->_sModule = 'bx_payment';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+        $this->_bCollapseFirst = true;
+        
+        $this->_iProfileId = $this->_oModule->getProfileId();
+        $this->_sPaymentProvider = '';
+    }
+
+    public function setProfileId($iProfileId = BX_PAYMENT_EMPTY_ID)
+    {
+        if($iProfileId != BX_PAYMENT_EMPTY_ID)
+            $this->_iProfileId = $iProfileId;
+    }
+
+    public function setPaymentProvider($sPaymentProvider)
+    {
+        $this->_sPaymentProvider = $sPaymentProvider;
+
+        $this->aParams['db']['submit_name'] = $this->_getSubmitName();
+
+        $sName = $this->_getName();
+        $this->setId($sName);
+        $this->setName($sName);
+    }
+
+    public function init()
+    {
+        $this->aInputs = [];
+                
+        $aInputs = $this->_oModule->_oDb->getForm($this->_sPaymentProvider);
+        if(empty($aInputs))
+            return false;
+
+        $bSiteAdmin = $this->_oModule->_oConfig->isSiteAdmin();
+        $bSingleSeller = $this->_oModule->_oConfig->isSingleSeller();
+
+        $bCollapsed = $this->_bCollapseFirst;
+        $iProvider = 0;
+        $sProvider = "";
+        $oProvider = null;
+        foreach($aInputs as $aInput) {
+            if((int)$aInput['provider_for_owner_only'] != 0 && !$bSiteAdmin)
+                continue;
+
+            if((int)$aInput['provider_single_seller'] == 0 && $bSingleSeller)
+                continue;
+
+            if($iProvider != $aInput['provider_id']) {
+                $sBlockHeaderName = 'provider_' . $aInput['provider_id'] . '_begin';
+                $this->aInputs[$sBlockHeaderName] = array(
+                    'type' => 'block_header',
+                    'name' => $sBlockHeaderName,
+                    'caption' => _t($aInput['provider_caption']),
+                    'info' => _t($aInput['provider_description']),
+                    'collapsable' => true,
+                    'collapsed' => ($sSelected = bx_get('pp')) !== false && $sSelected == $aInput['provider_name'] ? false : $bCollapsed
+                );
+
+                $iProvider = $aInput['provider_id'];
+                $sProvider = $aInput['provider_name'];
+                $oProvider = $this->_oModule->getObjectProvider($sProvider, $this->_iProfileId);
+                $bCollapsed = true;
+            }
+
+            $this->aInputs[$aInput['name']] = array(
+                'type' => $aInput['type'],
+                'name' => $aInput['name'],
+                'caption' => _t($aInput['caption']),
+                'value' => $oProvider->getOption($aInput['name']),
+                'info' => _t($aInput['description']),
+            	'attrs' => array(
+                    'bx-data-provider' => $iProvider
+            	),
+                '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 = ['values' => []];
+
+                    if(BxDolService::isSerializedService($aInput['extra']))
+                        $aAddon['values'] = BxDolService::callSerialized($aInput['extra']);
+                    else {
+                        $aPairs = explode(',', $aInput['extra']);
+                        foreach($aPairs as $sPair) {
+                            $aPair = explode('|', $sPair);
+                            $aAddon['values'][] = ['key' => $aPair[0], 'value' => _t($aPair[1])];
+                        }
+                    }
+                    break;
+
+                case 'checkbox':
+                    $this->aInputs[$aInput['name']]['value'] = 'on';
+                    $aAddon = array('checked' => $oProvider->getOption($aInput['name']) == 'on');
+                    break;
+
+                case 'value':
+                       $sMethod = 'get' . bx_gen_method_name(str_replace($aInput['provider_option_prefix'], '', $aInput['name']));
+                       if(method_exists($oProvider, $sMethod))
+                            $this->aInputs[$aInput['name']]['value'] = $oProvider->$sMethod($this->_iProfileId);
+                       break;
+
+                case 'custom':
+                    $sMethod = 'get' . bx_gen_method_name(str_replace($aInput['provider_option_prefix'], '', $aInput['name']));
+                    if(method_exists($oProvider, $sMethod)) {
+                        $mixedContent = $oProvider->$sMethod($this->_iProfileId);
+                        if(is_array($mixedContent))
+                            $this->aInputs[$aInput['name']] = array_merge($this->aInputs[$aInput['name']], $mixedContent);
+                        else
+                            $this->aInputs[$aInput['name']]['content'] = $mixedContent;
+                    }
+                    break;
+            }
+
+            if(!empty($aAddon) && is_array($aAddon))
+                $this->aInputs[$aInput['name']] = array_merge($this->aInputs[$aInput['name']], $aAddon);
+        }
+
+        $sSubmitName = $this->_getSubmitName();
+        $this->aInputs[$sSubmitName] = [
+            'type' => 'submit',
+            'name' => $sSubmitName,
+            'value' => _t($this->_sLangsPrefix . 'form_details_input_do_submit'),
+        ];
+
+        $this->aInputs['provider_' . $iProvider . '_end'] = [
+            'type' => 'block_end'
+        ];
+
+        return true;
+    }
+
+    public function initWithParams($iProfileId, $sPaymentProvider)
+    {
+        $this->setProfileId($iProfileId);
+        $this->setPaymentProvider($sPaymentProvider);
+        $this->init();
+    }
+
+    protected function _getName()
+    {
+        return $this->_sModule . '_form_details' . ($this->_sPaymentProvider ? '_' . $this->_sPaymentProvider : '');
+    }
+
+    protected function _getSubmitName()
+    {
+        return 'submit' . ($this->_sPaymentProvider ? '_' . $this->_sPaymentProvider : '');
+    }
+}
+
+/** @} */

+ 330 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentGridCart.php

@@ -0,0 +1,330 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+
+class BxPaymentGridCart extends BxBaseModPaymentGridCarts
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_bSelectAll = true;
+    }
+    
+    public function getCodeAPI($bForceReturn = false)
+    {
+        $aData = parent::getCodeAPI($bForceReturn);
+        $aData['settings']['field_id'] = 'id';
+        foreach ($aData['data'] as &$aRow){
+            $aRow['id'] = $aRow['checkbox']['data'];
+            $aRow['title']['value'] = strip_tags($aRow['title']['value']);
+            $aRow['price_single']['value'] = str_replace('&#36; ','$', $aRow['price_single']['value']);
+            
+        }
+        return $aData;
+    }
+
+    public function performActionQuantitySub()
+    {
+        $sId = $this->_getItemId();
+        list($iVendorId, $iModuleId, $iItemId, $iItemCount) = $this->_oModule->_oConfig->descriptorS2A($sId);
+
+        if($iItemCount == 1)
+            return echoJson([]);
+        
+        $aResult = $this->_oModule->getObjectCart()->serviceAddToCart($iVendorId, $iModuleId, $iItemId, -1);
+        if($aResult['code'] != 0 && isset($aResult['message']))
+            return echoJson(['msg' => $aResult['message']]);
+
+        return echoJson(['grid' => $this->getCode(false), 'blink' => $sId]);
+    }
+
+    public function performActionQuantityAdd()
+    {
+        $sId = $this->_getItemId();
+        list($iVendorId, $iModuleId, $iItemId, $iItemCount) = $this->_oModule->_oConfig->descriptorS2A($sId);
+
+        $aResult = $this->_oModule->getObjectCart()->serviceAddToCart($iVendorId, $iModuleId, $iItemId, 1);
+        if($aResult['code'] != 0 && isset($aResult['message']))
+            return echoJson(['msg' => $aResult['message']]);
+
+        return echoJson(['grid' => $this->getCode(false), 'blink' => $sId]);
+    }
+
+    public function performActionCheckout()
+    {
+    	$aParams = array(
+            'seller_id' => bx_process_input(bx_get('seller_id'), BX_DATA_INT), 
+            'provider' => bx_process_input(bx_get('provider')), 
+            'items' => bx_process_input(bx_get('ids'))
+    	);
+
+    	if(empty($aParams['seller_id']) || empty($aParams['provider']))
+            return echoJson(array());
+
+        if(empty($aParams['items']) || !is_array($aParams['items'])) 
+            return echoJson(array('msg' => _t('_bx_payment_err_nothing_selected')));
+
+        $oProvider = $this->_oModule->getObjectProvider($aParams['provider'], $aParams['seller_id']);
+        if($oProvider !== false) {
+            if(method_exists($oProvider, 'overwriteCheckoutParamsSingle'))
+                return echoJson($oProvider->overwriteCheckoutParamsSingle($aParams, $this));
+
+            if(method_exists($oProvider, 'getCheckoutParamsSingle'))
+                $aParams = $oProvider->getCheckoutParamsSingle($aParams, $this);
+        }
+
+        echoJson(array(
+            'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onCartCheckout(oData);', 
+            'link' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), $aParams)
+        ));
+    }
+
+    protected function _getCellTitle($mixedValue, $sKey, $aField, $aRow)
+    {
+    	return parent::_getCellDefault($this->_oModule->_oTemplate->displayLink('link', array(
+            'href' => $aRow['url'],
+            'title' => bx_html_attribute($aRow['title']),
+            'content' => $aRow['title']
+    	)), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellPriceSingle($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t_format_currency_ext($mixedValue, ['sign' => $this->_sCurrencySign]), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellQuantity($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = $this->_oModule->_oTemplate->parseHtmlByName('cart_quantity.html', [
+            'sub' => $this->_getActionQuantity('sub', $aRow),
+            'quantity' => $mixedValue,
+            'add' => $this->_getActionQuantity('add', $aRow)
+        ]);
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionQuantitySub ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getActionQuantityAdd ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getActionQuantity($sAction, &$aRow)
+    {
+        $sAction = 'quantity_' . $sAction;
+        $aAction = array_merge($this->_aOptions['actions_single'][$sAction], ['attr' => [
+            'bx_grid_action_single' => $sAction,
+            'bx_grid_action_data' => $aRow[$this->_aOptions['field_id']],
+            'bx_grid_action_confirm' => $this->_aOptions['actions_single'][$sAction]['confirm'],
+            'bx_grid_action_reset_paginate' => 0
+        ]]);
+
+        return $this->_getActionDefault('single', $sAction, $aAction, false, false, $aRow);
+    }
+
+    protected function _getActionCheckout ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        return '';
+    }
+
+    protected function _getActions ($sType, $sActionData = false, $isSmall = false, $isDisabled = false, $isPermanentState = false, $aRow = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$sActions = '';
+    	if($sType == 'bulk' && !empty($this->_aQueryAppend['seller_id'])) {
+            $sActionName = 'checkout';
+
+            $iClientId = (int)$this->_aQueryAppend['client_id'];
+            $iSellerId = (int)$this->_aQueryAppend['seller_id'];
+            $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iSellerId);
+
+            $bCreditsOnly = $this->_oModule->_oConfig->isCreditsOnly();
+
+            $bPayForCredits = true;
+            if(!empty($aCartInfo['items']) && is_array($aCartInfo['items']))
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aModule = $this->_oModule->_oDb->getModuleById((int)$aItem['module_id']);
+                    if($aModule['name'] != $CNF['MODULE_CREDITS']) {
+                        $bPayForCredits = false;
+                        break;
+                    }
+                }
+
+            $aProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($iSellerId);
+            foreach($aProviders as $aProvider) {
+                $bProviderCredits = $aProvider['name'] == $CNF['OBJECT_PP_CREDITS'];
+
+                /*
+                 * Hide all non-Credits payment providers when 'credits only' mode is enabled 
+                 * and purchasing items aren't credits.
+                 */
+                if($bCreditsOnly && !$bProviderCredits && !$bPayForCredits)
+                    continue;
+
+                /*
+                 * Hide Credits payment provider when paying for credits.
+                 */
+                if($bProviderCredits && $bPayForCredits)
+                    continue;
+
+                $sAction = $this->_getActionDefault($sType, $sActionName, array(
+                    'title'=> _t('_bx_payment_grid_action_title_crt_checkout', _t($CNF['T']['TXT_CART_PROVIDER'] . $aProvider['name'])),
+                    'icon' => '',
+                    'icon_only' => 0,
+                    'confirm' => 0,
+                    'attr' => array(
+                        'bx_grid_action_' . $sType => $sActionName,
+                        'bx_grid_action_append' => json_encode(array('provider' => $aProvider['name'])),
+                        'bx_grid_action_confirm' => 0,
+                        'bx_grid_action_reset_paginate' => 0,
+                    )
+                ), $isSmall, $isDisabled, $aRow);
+
+                $oProvider = $this->_oModule->getObjectProvider($aProvider['name'], $iSellerId);
+                if($oProvider !== false && method_exists($oProvider, 'getButtonSingle')) {
+                    $aParams = array(
+                        'sObjNameGrid' => $this->getObject(),
+                        'aCartInfo' => $aCartInfo,
+                        'sAction' => $sAction
+                    );
+
+                    if(!empty($aCartInfo['items_price']) && !empty($aCartInfo['items']) && is_array($aCartInfo['items'])) {
+                        $aTitles = array();
+                        foreach ($aCartInfo['items'] as $aItem)
+                            $aTitles[] = $aItem['title'];
+
+                        $aParams = array_merge($aParams, array(
+                            'iAmount' => (int)round(100 * (float)$aCartInfo['items_price']),
+                            'sItemTitle' => implode(', ', $aTitles)
+                        ));
+                    }
+
+                    $mixedButton = $oProvider->getButtonSingle($iClientId, $iSellerId, $aParams);
+                    if($mixedButton !== false)
+                        $sAction = $mixedButton;
+                }
+
+                $sActions .= $sAction;
+            }
+    	}else{
+           if (bx_is_api())
+               return parent::_getActions ($sType, $sActionData, $isSmall, $isDisabled, $isPermanentState, $aRow);
+        }
+
+        
+    	return $sActions . parent::_getActions ($sType, $sActionData, $isSmall, $isDisabled, $isPermanentState, $aRow);
+    }
+
+    protected function _getActionsAPI($sType)
+    {
+        if($sType != 'bulk' || empty($this->_aQueryAppend['seller_id']))
+            return parent::_getActionsAPI($sType);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iClientId = (int)$this->_aQueryAppend['client_id'];
+        $iSellerId = (int)$this->_aQueryAppend['seller_id'];
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iSellerId);
+
+        $bCreditsOnly = $this->_oModule->_oConfig->isCreditsOnly();
+
+        $bPayForCredits = true;
+        if(!empty($aCartInfo['items']) && is_array($aCartInfo['items']))
+            foreach($aCartInfo['items'] as $aItem) {
+                $aModule = $this->_oModule->_oDb->getModuleById((int)$aItem['module_id']);
+                if($aModule['name'] != $CNF['MODULE_CREDITS']) {
+                    $bPayForCredits = false;
+                    break;
+                }
+            }
+
+        $aActions = [];
+        $aProviders = $this->_oModule->_oDb->getVendorInfoProvidersSingle($iSellerId);
+        foreach($aProviders as $aProvider) {
+            $bProviderCredits = $aProvider['name'] == $CNF['OBJECT_PP_CREDITS'];
+
+            /*
+             * Hide all non-Credits payment providers when 'credits only' mode is enabled 
+             * and purchasing items aren't credits.
+             */
+            if($bCreditsOnly && !$bProviderCredits && !$bPayForCredits)
+                continue;
+
+            /*
+             * Hide Credits payment provider when paying for credits.
+             */
+            if($bProviderCredits && $bPayForCredits)
+                continue;
+
+            $aActions[$aProvider['name']] = [
+                'name' => $aProvider['name'],
+                'title'=> _t('_bx_payment_grid_action_title_crt_checkout', _t($CNF['T']['TXT_CART_PROVIDER'] . $aProvider['name'])),
+                'icon' => '',
+                'icon_only' => 0,
+                'confirm' => 0,
+            ];
+        }
+        return $aActions;
+    }    
+
+    protected function _getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->_aQueryAppend['client_id']) || empty($this->_aQueryAppend['seller_id']))
+            return array();
+
+        $aCart = $this->_oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $this->_aQueryAppend['client_id'], $this->_aQueryAppend['seller_id']);
+        if(empty($aCart) || empty($aCart['items']) || !is_array($aCart['items']))
+            return array();
+
+        $this->_aOptions['source'] = array();
+        foreach($aCart['items'] as $aCartItem) {
+            $this->_aOptions['source'][] = array_merge($aCartItem, [
+                'descriptor' => $this->_oModule->_oConfig->descriptorA2S(array($aCartItem['author_id'], $aCartItem['module_id'], $aCartItem['id'], $aCartItem['quantity'])),
+                'description' => strip_tags($aCartItem['description']),
+                'currency_code' => $aCart['vendor_currency_code'],
+                'currency_sign' => $aCart['vendor_currency_sign']
+            ]);
+        }
+
+        return parent::_getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    protected function _delete($mixedId)
+    {
+    	list($iVendorId, $iModuleId, $iItemId) = $this->_oModule->_oConfig->descriptorS2A($mixedId);
+    	if(!$this->_oModule->isSingleSeller() && (int)$iVendorId != (int)$this->_aQueryAppend['seller_id'])
+            return false;
+
+    	return $this->_oCart->serviceDeleteFromCart($iVendorId, $iModuleId, $iItemId);
+    }
+
+    protected function _getItemId()
+    {
+        if(($aIds = bx_get('ids')) && is_array($aIds)) 
+            return array_shift($aIds);
+
+        if(($sId = bx_get('id')))
+            return $sId;
+
+        return false;
+    }
+}
+
+/** @} */

+ 2078 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentModule.php

@@ -0,0 +1,2078 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+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_RESULT_SUCCESS', 0);
+
+/*
+ * Subscriptions: statuses.
+ */
+define('BX_PAYMENT_SBS_STATUS_SCHEDULED', 'scheduled');
+define('BX_PAYMENT_SBS_STATUS_TRIAL', 'trial');
+define('BX_PAYMENT_SBS_STATUS_ACTIVE', 'active');
+define('BX_PAYMENT_SBS_STATUS_UNPAID', 'unpaid');
+define('BX_PAYMENT_SBS_STATUS_PAUSED', 'paused');
+define('BX_PAYMENT_SBS_STATUS_CANCELED', 'canceled');
+define('BX_PAYMENT_SBS_STATUS_UNKNOWN', 'unknown');
+
+/*
+ * Subscriptions: period units.
+ */
+define('BX_PAYMENT_SBS_PU_YEAR', 'year');
+define('BX_PAYMENT_SBS_PU_MONTH', 'month');
+define('BX_PAYMENT_SBS_PU_WEEK', 'week');
+define('BX_PAYMENT_SBS_PU_DAY', 'day');
+define('BX_PAYMENT_SBS_PU_HOUR', 'hour');
+define('BX_PAYMENT_SBS_PU_MINUTE', 'minute');
+
+/*
+ * Invoice: statuses.
+ */
+define('BX_PAYMENT_INV_STATUS_UNPAID', 'unpaid');
+define('BX_PAYMENT_INV_STATUS_PAID', 'paid');
+define('BX_PAYMENT_INV_STATUS_OVERDUE', 'overdue');
+
+
+/**
+ * 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($iSellerId) - 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($iSellerId, $mixedModuleId, $iItemId, $iItemCount));
+ *
+ * Check transaction(s) in database which satisty all conditions.
+ * @see BxPmtModule::serviceGetOrdersInfo
+ * BxDolService::call('payment', 'get_orders_info', array($aConditions), 'Orders');
+ *
+ * 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($sType, $iModuleId)
+    {
+    	$iSellerId = $this->getProfileId();
+        $aItems = $this->callGetCartItems((int)$iModuleId, array($iSellerId));
+        $aParams = [
+            'filter' => bx_get('filter')
+        ];
+
+        echoJson([
+            'code' => 0, 
+            'eval' => $this->_oConfig->getJsObject('processed') . '.onSelectModule(oData);', 
+            'data' => $this->_oTemplate->displayItems($iSellerId, $sType, $aItems, $aParams)
+        ]);
+    }
+
+    public function actionGetFilterValuesItem($iSellerId, $iModuleId)
+    {
+        $sItems = '<option value="">' . _t('_bx_payment_txt_all_items') . '</option>';
+
+        if(empty($iSellerId) || empty($iModuleId))
+            return echoJson(array('code' => 1, 'content' => $sItems));
+
+        $aItems = $this->callGetCartItems((int)$iModuleId, array($iSellerId));
+
+        $this->_oConfig->sortByColumn('title', $aItems);
+
+        foreach($aItems as $aItem)
+            $sItems .= '<option value="' . $aItem['id'] . '">' . $aItem['title'] . '</option>';
+
+        echoJson(array('code' => 0, 'content' => $sItems));
+    }
+
+    public function serviceGetSafeServices()
+    {
+        $a = parent::serviceGetSafeServices();
+        return array_merge($a, array (
+            'GetBlockJoin' => 'BxPaymentJoin',
+            'GetBlockCarts' => 'BxPaymentCart',
+            'GetBlockCart' => 'BxPaymentCart',
+            'GetBlockCartHistory' => 'BxPaymentCart',
+            'GetBlockListMy' => 'BxPaymentSubscriptions',
+            'GetBlockHistory' => 'BxPaymentSubscriptions',
+
+            'GetProviderOptions' => '',
+            'InitializeCheckoutApi' => '',
+            'StripeV3CreateSessionApi' => ''
+        ));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-get_modules_with_payments get_modules_with_payments
+     * 
+     * @code bx_srv('bx_payment', 'get_modules_with_payments', []); @endcode
+     * 
+     * Get modules with payments functionality
+     *
+     * @return array with modules names
+     * 
+     * @see BxPaymentModule::serviceGetModulesWithPayments
+     */
+    /** 
+     * @ref bx_payment-get_modules_with_payments "get_modules_with_payments"
+     */
+    public function serviceGetModulesWithPayments()
+    {
+        return $this->_oDb->getModulesWithPayments();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-is_credits_only is_credits_only
+     * 
+     * @code bx_srv('bx_payment', 'is_credits_only'); @endcode
+     * 
+     * Check whether the 'Credits Only' mode is enabled or not.
+     *
+     * @return boolean value determining the result of checking.
+     * 
+     * @see BxPaymentModule::serviceIsCreditsOnly
+     */
+    /** 
+     * @ref bx_payment-is_credits_only "is_credits_only"
+     */
+    public function serviceIsCreditsOnly()
+    {
+        return $this->_oConfig->isCreditsOnly();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-is_accepting_payments is_accepting_payments
+     * 
+     * @code bx_srv('bx_payment', 'is_accepting_payments', [...]); @endcode
+     * 
+     * Check whether the specified vendor has a configured payment provider or not.
+     *
+     * @param $iVendorId integer value with vendor ID.
+     * @param $sPaymentType (optional) string value with payment type. If specified then the vendor will be checked for having the payment provider of the requested type.
+     * @return boolean value determining the result of checking.
+     * 
+     * @see BxPaymentModule::serviceIsAcceptingPayments
+     */
+    /** 
+     * @ref bx_payment-is_accepting_payments "is_accepting_payments"
+     */
+    public function serviceIsAcceptingPayments($iVendorId, $sPaymentType = '')
+    {
+    	$bResult = false;
+
+    	switch($sPaymentType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aProvidersCart = $this->_oDb->getVendorInfoProvidersSingle($iVendorId);
+                $bResult = !empty($aProvidersCart);
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aProvidersSubscription = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+                $bResult = !empty($aProvidersSubscription);
+                break;
+
+            default:
+                $aProviders = $this->_oDb->getVendorInfoProviders($iVendorId);
+                $bResult = !empty($aProviders);
+    	}
+
+        return $bResult;
+    }
+
+    /** 
+     * @deprecated since version 11.0.0
+     * 
+     * @see BxPaymentModule::serviceIsProviderOptions
+     */
+    public function serviceIsPaymentProvider($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	return $this->serviceIsProviderOptions($iVendorId, $sVendorProvider, $sPaymentType);
+    }
+
+    /** 
+     * @deprecated since version 11.0.0
+     * 
+     * @see BxPaymentModule::serviceGetProviderOptions
+     */
+    public function serviceGetPaymentProvider($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	return $this->serviceGetProviderOptions($iVendorId, $sVendorProvider, $sPaymentType);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-is_provider_options is_provider_options
+     * 
+     * @code bx_srv('bx_payment', 'is_provider_options', [...]); @endcode
+     * 
+     * Check whether the specified vendor has configured the specified payment provider or not.
+     *
+     * @param $iVendorId integer value with vendor ID.
+     * @param $sVendorProvider string value with payment provider name.
+     * @param $sPaymentType (optional) string value with payment type. If specified then the vendor will be checked for having the payment provider of the requested type.
+     * @return boolean value determining the result of checking.
+     * 
+     * @see BxPaymentModule::serviceIsProviderOptions
+     */
+    /** 
+     * @ref bx_payment-is_provider_options "is_provider_options"
+     */
+    public function serviceIsProviderOptions($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	$aProvider = $this->serviceGetProviderOptions($iVendorId, $sVendorProvider, $sPaymentType);
+    	return $aProvider !== false;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-get_provider_options get_provider_options
+     * 
+     * @code bx_srv('bx_payment', 'get_provider_options', [...]); @endcode
+     * 
+     * Get configuration settings for the payment provider entered by the specified vendor.
+     *
+     * @param $iVendorId integer value with vendor ID.
+     * @param $sVendorProvider string value with payment provider name.
+     * @param $sPaymentType (optional) string value with payment type. If specified then the vendor will be checked for having the payment provider of the requested type.
+     * @return an array with special format describing the payment provider or false value if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceGetProviderOptions
+     */
+    /** 
+     * @ref bx_payment-get_provider_options "get_provider_options"
+     */
+    public function serviceGetProviderOptions($iVendorId, $sVendorProvider, $sPaymentType = '')
+    {
+    	$aProviders = array();
+    	switch($sPaymentType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aProviders = $this->_oDb->getVendorInfoProvidersSingle($iVendorId);
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aProviders = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+                break;
+
+            default:
+                $aProviders = $this->_oDb->getVendorInfoProviders($iVendorId);
+    	}
+
+    	return !empty($aProviders) && !empty($aProviders[$sVendorProvider]) && is_array(($aProviders[$sVendorProvider])) ? $aProviders[$sVendorProvider] : false;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_options_default_currency_code get_options_default_currency_code
+     * 
+     * @code bx_srv('bx_payment', 'get_options_default_currency_code', [...]); @endcode
+     * 
+     * Get an array with available currencies. Is used in forms.
+     *
+     * @return an array with available currencies represented as key => value pairs.
+     * 
+     * @see BxPaymentModule::serviceGetOptionsDefaultCurrencyCode
+     */
+    /** 
+     * @ref bx_payment-get_options_default_currency_code "get_options_default_currency_code"
+     */
+    public function serviceGetOptionsDefaultCurrencyCode()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aCurrencies = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_CURRENCIES']);
+
+        $aResult = array();
+        foreach($aCurrencies as $sKey => $sValue)
+            $aResult[] = array(
+                'key' => $sKey,
+                'value' => $sValue
+            );
+
+        return $aResult;
+    }
+
+    public function serviceGetOptionsPersonalCurrencyCode()
+    {
+        return array_merge([[
+            'key' => '',
+            'value' => _t('_bx_payment_gc_currency_code_default')
+        ]], $this->serviceGetOptionsDefaultCurrencyCode());
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_options_site_admin get_options_site_admin
+     * 
+     * @code bx_srv('bx_payment', 'get_options_site_admin', [...]); @endcode
+     * 
+     * Get an array with profiles which can be used as 'Site Admin (Owner)'. 'Site Admin' is a person who will be displayed to buyers when something is selling on behalf of the site.
+     *
+     * @return an array with profiles represented as key => value pairs.
+     * 
+     * @see BxPaymentModule::serviceGetOptionsSiteAdmin
+     */
+    /** 
+     * @ref bx_payment-get_options_site_admin "get_options_site_admin"
+     */
+    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;
+    }
+
+    public function serviceGetMenuAddonManageTools()
+    {
+        return array(
+            'counter1_value' => (int)$this->_oDb->getInvoices(array('type' => 'status', 'status' => BX_PAYMENT_INV_STATUS_PAID, 'count' => true)), 
+            'counter1_caption' => _t('_bx_payment_menu_item_title_admt_addon_counter1_caption'), 
+            'counter2_value' => (int)$this->_oDb->getInvoices(array('type' => 'status', 'status' => BX_PAYMENT_INV_STATUS_OVERDUE, 'count' => true)), 
+            'counter2_caption' => _t('_bx_payment_menu_item_title_admt_addon_counter2_caption'), 
+            'counter3_value' => (int)$this->_oDb->getInvoices(array('type' => 'all_count'))
+        );
+    }
+
+    public function serviceGetBlockCheckoutOffline()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $oBuyer = BxDolProfile::getInstance();
+        if(!$oBuyer)
+            return MsgBox(_t('_bx_payment_err_required_login'));
+        
+        $iSeller = (int)bx_get('seller');
+        $oSeller = BxDolProfile::getInstance($iSeller);
+        if(!$oSeller)
+            return MsgBox(_t('_bx_payment_err_unknown_vendor'));
+
+        $aData = array(
+            'seller' => $iSeller,
+            'currency' => array(
+                'code' => bx_process_input(bx_get('currency_code')),
+                'sign' => bx_process_input(bx_get('currency_sign')),
+            ),
+            'amount' => (float)bx_get('amount'),
+            'return_url' => bx_process_input(bx_get('return_url')),
+        );
+
+        if(empty($aData['currency']['code']))
+            $aData['currency']['code'] = $this->_oConfig->getDefaultCurrencyCode();
+
+        if(empty($aData['currency']['sign']))
+            $aData['currency']['sign'] = $this->_oConfig->getDefaultCurrencySign();
+
+        $sItems = '';
+        $iItemsCount = (int)bx_get('items_count');
+        for($i = 0; $i < $iItemsCount; $i++) {
+            $aItem = array(
+                'title' => bx_process_input(bx_get('item_title_' . $i)),
+                'quantity' => (int)bx_get('item_quantity_' . $i)
+            );
+
+            $sItems .= _t('_bx_payment_txt_checkout_item', $aItem['title'], $aItem['quantity']);
+            $aData['items'][] = $aItem;
+        }
+
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($this->_oConfig->getPrefix('general') . 'checkout_offline', array(
+            'profile_name' => $oBuyer->getDisplayName(),
+            'profile_link' => $oBuyer->getUrl(),
+            'items' => $sItems,
+            'amount' => $aData['currency']['sign'] . sprintf("%.2f", (float)($aData['amount'])),
+            'date' => bx_time_js(time(), BX_FORMAT_DATE, true),
+            'pending_orders_link' => $this->getObjectOrders()->serviceGetPendingOrdersUrl()
+        ), 0, $iSeller);
+
+        $sEmail = '';
+        $oProvider = $this->getObjectProvider($CNF['OBJECT_PP_OFFLINE'], $iSeller);
+        if($oProvider !== false && $oProvider->isActive())
+            $sEmail = $oProvider->getOption('checkout_email');
+
+        if(empty($sEmail))
+            $sEmail = $oBuyer->getAccountObject()->getEmail();
+
+        if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM))
+            return MsgBox(_t('_bx_payment_err_cannot_perform'));
+
+        return $this->_oTemplate->displayBlockCheckoutOffline($oBuyer, $oSeller, $aData);
+    }
+
+    /**
+     * Cart Processing Methods
+     */
+    public function actionAddToCart($iSellerId, $iModuleId, $iItemId, $iItemCount, $sCustom = '')
+    {
+        if(empty($sCustom) && ($sCustom = bx_get('custom')) !== false)
+            $sCustom = bx_process_input($sCustom);
+
+        $aCustom = [];
+        if(!empty($sCustom)) {
+            $aCustom = $this->_oConfig->s2a($sCustom);
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = [];
+        }
+
+        $aResult = $this->getObjectCart()->serviceAddToCart($iSellerId, $iModuleId, $iItemId, $iItemCount, $aCustom);
+        echoJson($aResult);
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionDeleteFromCart($iSellerId, $iModuleId, $iItemId)
+    {
+        echoJson($this->getObjectCart()->serviceDeleteFromCart($iSellerId, $iModuleId, $iItemId));
+    }
+
+    /**
+     * Isn't used yet.
+     */
+    public function actionEmptyCart($iSellerId)
+    {
+        echoJson($this->getObjectCart()->serviceDeleteFromCart($iSellerId));
+    }
+
+    public function actionSubscribe()
+    {
+    	$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+    	$sSellerProvider = bx_process_input(bx_get('seller_provider'));
+    	$iModuleId = bx_process_input(bx_get('module_id'), BX_DATA_INT);
+    	$iItemId = bx_process_input(bx_get('item_id'), BX_DATA_INT);
+    	$iItemCount = bx_process_input(bx_get('item_count'), BX_DATA_INT);
+    	if(empty($iItemCount))
+    		$iItemCount = 1;
+
+        $sRedirect = bx_process_input(bx_get('redirect'));
+        $sCustom = bx_process_input(bx_get('custom'));
+
+        $aCustom = array();
+        if(!empty($sCustom)) {
+            $aCustom = json_decode(base64_decode($sCustom), true);
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = array();
+        }
+
+        $aResult = $this->getObjectSubscriptions()->serviceSubscribe($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, $sRedirect, $aCustom);
+        $bRedirect = !empty($aResult['redirect']);
+
+        if(!empty($aResult['popup'])) {
+            $sContent = '';
+            $sContent .= $this->_oTemplate->displayCartJs(BX_PAYMENT_TYPE_RECURRING, $iSellerId);
+            $sContent .= !empty($aResult['popup']['html']) ? $aResult['popup']['html'] : $aResult['popup'];
+
+			return $this->_oTemplate->displayPageCodeResponse($sContent, false, true);
+        }
+
+		if(!empty($aResult['code']))
+			return $this->_oTemplate->displayPageCodeError($aResult['message']);
+
+		if(!empty($aResult['message']) && !$bRedirect)
+			return $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+
+        if($bRedirect) {
+            header('Location: ' . $aResult['redirect']);
+            exit;
+        }
+    }
+
+    public function actionSubscribeJson()
+    {
+    	$iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+    	$sSellerProvider = bx_process_input(bx_get('seller_provider'));
+    	$iModuleId = bx_process_input(bx_get('module_id'), BX_DATA_INT);
+    	$iItemId = bx_process_input(bx_get('item_id'), BX_DATA_INT);
+
+    	$iItemCount = bx_process_input(bx_get('item_count'), BX_DATA_INT);
+    	if(empty($iItemCount))
+            $iItemCount = 1;
+
+        $sItemAddons = '';
+        if(bx_get('item_addons') !== false) {
+            $sItemAddons = bx_process_input(bx_get('item_addons'));
+            if(is_array($sItemAddons))
+                $sItemAddons = $this->_oConfig->a2s($sItemAddons);
+        }
+
+        $sRedirect = bx_process_input(bx_get('redirect'));
+        $sCustom = bx_process_input(bx_get('custom'));
+
+        $aCustom = array();
+        if(!empty($sCustom)) {
+            $aCustom = $this->_oConfig->s2a($sCustom);
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = [];
+        }
+
+        echoJson($this->getObjectSubscriptions()->serviceSubscribeWithAddons($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, $sItemAddons, $sRedirect, $aCustom));
+    }
+
+    public function actionSubscriptionGetDetails($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionGetDetails($iId));
+    }
+
+    public function actionSubscriptionChangeDetails($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionChangeDetails($iId));
+    }
+
+    public function actionSubscriptionGetBilling($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionGetBilling($iId));
+    }
+
+    public function actionSubscriptionChangeBilling($iId)
+    {
+        echoJson($this->_oTemplate->displaySubscriptionChangeBilling($iId));
+    }
+
+    public function actionSubscriptionCancelation($iId)
+    {
+        $aResult = array('code' => 1, 'message' => _t('_bx_payment_err_cannot_perform'));
+
+        $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => $iId));
+        if(empty($aPending) || !is_array($aPending))
+            return echoJson($aResult);
+
+        $aSubscription = $this->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $iId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return echoJson($aResult);
+
+        $oRecipient = BxDolProfile::getInstance((int)$aPending['seller_id']);
+        if(!$oRecipient)
+            return echoJson($aResult);
+
+        $mixedResult = $this->isAllowedManage($aPending);
+        if($mixedResult !== true)
+            return echoJson(array('code' => 2, 'message' => $mixedResult));
+
+        $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($this->_oConfig->getPrefix('general') . 'cancelation_request', array(
+            'subscription_id' => $aSubscription['subscription_id'],
+            'subscription_customer' => $aSubscription['customer_id'],
+            'subscription_date' => bx_time_js($aSubscription['date_add'], BX_FORMAT_DATE, true)
+        ), 0, (int)$aPending['client_id']);
+
+        $sEmail = '';
+        $oProvider = $this->getObjectProvider($aPending['provider'], $aPending['seller_id']);
+        if($oProvider !== false && $oProvider->isActive())
+            $sEmail = $oProvider->getOption('cancellation_email');
+
+        if(empty($sEmail))
+            $sEmail = $oRecipient->getAccountObject()->getEmail();
+
+        if(!sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM))
+            return echoJson($aResult);
+
+        echoJson(array('code' => 0, 'message' => _t('_bx_payment_msg_cancelation_request_sent')));
+    }
+
+    public function actionSubscriptionCancel($iId, $mixedGridObject = false)
+    {
+        $aResult = array('code' => 1, 'message' => _t('_bx_payment_err_cannot_perform'));
+
+        $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => $iId));
+        if(empty($aPending) || !is_array($aPending))
+            return echoJson($aResult);
+
+        $mixedResult = $this->isAllowedManage($aPending);
+        if($mixedResult !== true)
+            return echoJson(array('code' => 2, 'message' => $mixedResult));
+
+        if(!$this->getObjectSubscriptions()->cancel($iId))
+            return echoJson($aResult);
+
+        if(empty($mixedGridObject) && bx_get('grid') !== false)
+            $mixedGridObject = bx_process_input(bx_get('grid'));
+
+        if(!empty($mixedGridObject) && $aPending['client_id'] == $this->getProfileId()) {
+            $oGrid = BxDolGrid::getObjectInstance($mixedGridObject, $this->_oTemplate);
+            $oGrid->addQueryParam('client_id', $aPending['client_id']);
+
+            return echoJson(array('object' => $mixedGridObject, 'grid' => $oGrid->getCode(false), 'blink' => array($iId)));
+        }
+        else
+            return echoJson(array('code' => 0, 'message' => _t('_bx_payment_msg_successfully_performed')));
+    }
+
+    /**
+     * Payment Processing Methods
+     */
+    public function actionAuthorizeCheckout($sType)
+    {
+    	if(!$this->isLogged())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+        if(bx_get('seller_id') === false || bx_get('provider') === false || bx_get('items') === false)
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_wrong_data');
+
+        $iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+        $sProvider = bx_process_input(bx_get('provider'));
+        $aItems = bx_process_input(bx_get('items'));
+
+        $mixedResult = $this->serviceAuthorizeCheckout($sType, $iSellerId, $sProvider, $aItems);
+        if(is_string($mixedResult))
+            return $this->_oTemplate->displayPageCodeError($mixedResult);
+
+        if(is_array($mixedResult) && !empty($mixedResult['redirect'])) {
+            header('Location: ' . $mixedResult['redirect']);
+            exit;
+        }
+
+        return $this->_oTemplate->displayPageCodeResponse($this->_sLangsPrefix . 'msg_successfully_performed');
+    }
+
+    public function actionCaptureAuthorizedCheckout($sType)
+    {
+        $iProfileId = bx_get_logged_profile_id();
+    	if(!$iProfileId)
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+        $sOrderAuth = '';
+        if(($sOrderAuth = bx_get('order')) !== false) 
+            $sOrderAuth = bx_process_input($sOrderAuth);
+
+        if(empty($sOrderAuth))
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_empty_order');
+
+        $aPending = $this->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrderAuth]);
+        if(empty($aPending) || !is_array($aPending))
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_empty_order');
+
+        if((int)$aPending['seller_id'] != $iProfileId)
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_wrong_vendor');
+
+        $mixedResult = $this->serviceCaptureAuthorizedCheckout($sType, $sOrderAuth);
+        if(is_string($mixedResult))
+            return $this->_oTemplate->displayPageCodeError($mixedResult);
+
+        if(!empty($mixedResult['redirect'])) {
+            header('Location: ' . base64_decode(urldecode($mixedResult['redirect'])));
+            exit;
+        }
+
+        return $this->_oTemplate->displayPageCodeResponse($mixedResult['message']);
+    }
+
+    public function actionInitializeCheckout($sType)
+    {
+    	if(!$this->isLogged())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_required_login');
+
+        if(bx_get('seller_id') !== false && bx_get('provider') !== false && bx_get('items') !== false) {
+            $iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+            $sProvider = bx_process_input(bx_get('provider'));
+            $aItems = bx_process_input(bx_get('items'));
+
+            $mixedResult = $this->serviceInitializeCheckout(BX_PAYMENT_TYPE_SINGLE, $iSellerId, $sProvider, $aItems);
+            if($mixedResult !== true)
+                return $this->_oTemplate->displayPageCodeError($mixedResult);
+        }
+
+        header('Location: ' . $this->_oConfig->getUrl('URL_CART'));
+        exit;
+    }
+
+    public function actionInitializeCheckoutJson($sType)
+    {
+    	if(!$this->isLogged())
+            return echoJson(['code' => 1, 'message' => _t($this->_sLangsPrefix . 'err_required_login')]);
+
+        if(bx_get('seller_id') !== false && bx_get('provider') !== false && bx_get('items') !== false) {
+            $iSellerId = bx_process_input(bx_get('seller_id'), BX_DATA_INT);
+            $sProvider = bx_process_input(bx_get('provider'));
+            $aItems = bx_process_input(bx_get('items'));
+
+            $mixedResult = $this->serviceInitializeCheckout(BX_PAYMENT_TYPE_SINGLE, $iSellerId, $sProvider, $aItems);
+            if($mixedResult === false)
+                return echoJson(['code' => 2, 'message' => _t($this->_sLangsPrefix . 'err_cannot_perform')]);
+            if(is_string($mixedResult))
+                return echoJson(['code' => 3, 'message' => $mixedResult]);
+            else if(is_array($mixedResult))
+                return echoJson($mixedResult);
+        }
+
+        return echoJson(['code' => 0, 'redirect' => $this->_oConfig->getUrl('URL_CART')]);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-authorize_checkout authorize_checkout
+     * 
+     * @code bx_srv('bx_payment', 'authorize_checkout', [...]); @endcode
+     * 
+     * Authorize order for future checkout.
+     * 
+     * @param $sType string value with payment type (single or recurring). 
+     * @param $iSellerId integer value with seller ID. 
+     * @param $sProvider string value with payment provider name. 
+     * @param $aItems (optional) an array with items to be purchased. 
+     * @param $sRedirect (optional) string value with redirect URL if it's needed.
+     * @return the result depends on the payment provider which is used for processing or represented as string value with error message if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceAuthorizeCheckout
+     */
+    /** 
+     * @ref bx_payment-authorize_checkout "authorize_checkout"
+     */
+    public function serviceAuthorizeCheckout($sType, $iSellerId, $sProvider, $aItems = [], $sRedirect = '')
+    {
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+        $bTypeRecurring = $sType == BX_PAYMENT_TYPE_RECURRING;
+
+        if(!is_array($aItems))
+            $aItems = [$aItems];
+
+        $iSellerId = (int)$iSellerId;
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return $this->_sLangsPrefix . 'err_unknown_vendor';
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_sLangsPrefix . 'err_incorrect_provider';
+
+        $aInfo = $this->getObjectCart()->getInfo($sType, $this->_iUserId, $iSellerId, $aItems);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        $this->alert('before_authorize', 0, $this->_iUserId, array(
+            'client_id' => $this->_iUserId,
+            'seller_id' => $iSellerId, 
+            'type' => &$sType,
+            'provider' => &$sProvider,
+            'cart_info' => &$aInfo,
+        ));
+
+        $iPendingId = $this->_oDb->insertOrderPending($this->_iUserId, $sType, $sProvider, $aInfo);
+        if(empty($iPendingId))
+            return $this->_sLangsPrefix . 'err_access_db';
+
+        return $oProvider->authorizeCheckout($iPendingId, $aInfo, $sRedirect);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-capture_authorized_checkout capture_authorized_checkout
+     * 
+     * @code bx_srv('bx_payment', 'capture_authorized_checkout', [...]); @endcode
+     * 
+     * Capture funds for previously authorized order.
+     * 
+     * @param $sType string value with payment type (single or recurring). 
+     * @param $sOrderAuth string value with order's authorization ID. 
+     * @return the result depends on the payment provider which is used for processing or represented as string value with error message if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceCaptureAuthorizedCheckout
+     */
+    /** 
+     * @ref bx_payment-capture_authorized_checkout "capture_authorized_checkout"
+     */
+    public function serviceCaptureAuthorizedCheckout($sType, $sOrderAuth, $sRedirect = '')
+    {
+        $aPending = $this->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrderAuth]);
+        if(empty($aPending) || !is_array($aPending))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        if((int)$aPending['processed'] != 0)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        $iClientId = (int)$aPending['client_id'];
+        $iSellerId = (int)$aPending['seller_id'];
+        $sProvider = $aPending['provider'];
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_sLangsPrefix . 'err_incorrect_provider';
+
+        $aInfo = $this->getObjectCart()->getInfo($sType, $iClientId, $iSellerId, $aPending['items']);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        $this->alert('before_capture_authorized', 0, $iClientId, array(
+            'order_auth' => $sOrderAuth,
+            'client_id' => $iClientId,
+            'seller_id' => $iSellerId, 
+            'type' => &$sType,
+            'provider' => &$sProvider,
+            'cart_info' => &$aInfo,
+        ));
+
+        $aResult = $oProvider->captureAuthorizedCheckout($sOrderAuth, $aPending, $aInfo, $sRedirect);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) 
+            return $aResult['message'];
+
+        //--- Get updated pending order
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => $aResult['pending_id']]);
+
+        //--- Register payment for purchased items in associated modules 
+        if(isset($aResult['paid']) && $aResult['paid'])
+            $this->registerPayment($aPending);
+
+        $this->alert('finalize_checkout', 0, bx_get_logged_profile_id(), array(
+            'pending' => $aPending,
+            'transactions' => $this->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => (int)$aPending['id'])),
+            'provider' => $oProvider,
+            'message' => &$aResult['message'],
+            'result' => &$aResult,
+        ));
+
+        if(empty($aResult['redirect']) && $oProvider->needRedirect())
+            $aResult['redirect'] = $oProvider->getReturnUrl();
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-initialize_checkout initialize_checkout
+     * 
+     * @code bx_srv('bx_payment', 'initialize_checkout', [...]); @endcode
+     * 
+     * Initialize the checkout process.
+     * 
+     * @param $sType string value with payment type (single or recurring). 
+     * @param $iSellerId integer value with seller ID. 
+     * @param $sProvider string value with payment provider name. 
+     * @param $aItems (optional) an array with items to be purchased. 
+     * @param $sRedirect (optional) string value with redirect URL if it's needed.
+     * @param $aCustom (optional) array with custom data to attach to a payment.
+     * @return the result depends on the payment provider which is used for processing or represented as string value with error message if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceInitializeCheckout
+     */
+    /** 
+     * @ref bx_payment-initialize_checkout "initialize_checkout"
+     */
+    public function serviceInitializeCheckout($sType, $iSellerId, $sProvider, $aItems = array(), $sRedirect = '', $aCustoms = array())
+    {
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+        $bTypeRecurring = $sType == BX_PAYMENT_TYPE_RECURRING;
+
+        if(!is_array($aItems))
+            $aItems = array($aItems);
+
+        $iSellerId = (int)$iSellerId;
+        if($iSellerId == BX_PAYMENT_EMPTY_ID)
+            return $this->_sLangsPrefix . 'err_unknown_vendor';
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_sLangsPrefix . 'err_incorrect_provider';
+
+        $aInfo = $this->getObjectCart()->getInfo($sType, $this->_iUserId, $iSellerId, $aItems);
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_order';
+
+        /*
+         * Process FREE (price = 0) items for LOGGED IN members
+         * WITHOUT processing via payment provider.
+         * Note. This section isn't used for now!
+         */
+        $bProcessedFree = false;
+        $sKeyPriceSingle = $this->_oConfig->getKey('KEY_ARRAY_PRICE_SINGLE');
+        $sKeyPriceRecurring = $this->_oConfig->getKey('KEY_ARRAY_PRICE_RECURRING');
+        foreach($aInfo['items'] as $iIndex => $aItem) {
+            if((int)$aInfo['client_id'] == 0)
+                continue;
+
+            //--- For Single time payments.
+            if($bTypeSingle && (float)$aItem[$sKeyPriceSingle] == 0) {
+                $aCart = $this->_oDb->getCartContent($aInfo['client_id']);
+                $aCartCustoms = $aCart['customs'];
+
+                $aCartItem = array($aInfo['vendor_id'], $aItem['module_id'], $aItem['id'], $aItem['quantity']);
+                $aCartItemCustom = $this->_oConfig->pullCustom($aCartItem, $aCartCustoms);
+
+                $aItemInfo = $this->callRegisterCartItem((int)$aItem['module_id'], array($aInfo['client_id'], $aInfo['vendor_id'], $aItem['id'], $aItem['quantity'], $this->_oConfig->getLicense(), $aCartItemCustom));
+                if(!empty($aItemInfo) && is_array($aItemInfo)) {
+                    if(!empty($aItemInfo['addons']) && is_array($aItemInfo['addons']))
+                        foreach($aItemInfo['addons'] as $sAddon => $aAddon)
+                            $this->callRegisterCartItem((int)$aAddon['module_id'], array($aInfo['client_id'], $aInfo['vendor_id'], $aAddon['id'], $aAddon['quantity'], $this->_oConfig->getLicense(), $aCartItemCustom));
+
+                    $bProcessedFree = true;
+                }
+
+                $aInfo['items_count'] -= 1;
+                unset($aInfo['items'][$iIndex]);
+
+                $aCart['items'] = trim(preg_replace("'" . $this->_oConfig->descriptorA2S($aCartItem) . ":?'", "", $aCart['items']), ":");
+                $this->_oDb->setCartItems($aInfo['client_id'], $aCart['items'], $aCartCustoms);
+            }
+
+            //--- For Recurring payments.
+            if($bTypeRecurring && (float)$aItem[$sKeyPriceRecurring] == 0) {
+                //TODO: Process FREE subscription here, if such situation will be possible.
+            }
+        }
+
+        if(empty($aInfo['items']))
+            return $this->_sLangsPrefix . ($bProcessedFree ? 'msg_successfully_processed_free' : 'err_empty_order');
+
+        if($bTypeSingle && (empty($aCustoms) || !is_array($aCustoms))) {
+            $aCart = $this->_oDb->getCartContent($aInfo['client_id']);
+            $aCartCustoms = $aCart['customs'];
+
+            $aCustoms = array();
+            foreach($aInfo['items'] as $aItem) {
+                $sCartItem = $this->_oConfig->descriptorA2S(array($aItem['author_id'], $aItem['module_id'], $aItem['id']));
+                $aCartItemCustom = $this->_oConfig->getCustom($sCartItem, $aCartCustoms);
+                $this->_oConfig->putCustom($sCartItem, $aCartItemCustom, $aCustoms);
+            }
+        }
+
+        $this->alert('before_pending', 0, bx_get_logged_profile_id(), array(
+            'client_id' => $this->_iUserId,
+            'seller_id' => $iSellerId, 
+            'type' => &$sType,
+            'provider' => &$sProvider,
+            'cart_info' => &$aInfo,
+            'custom' => &$aCustoms,
+        ));
+
+        $iPendingId = $this->_oDb->insertOrderPending($this->_iUserId, $sType, $sProvider, $aInfo, $aCustoms);
+        if(empty($iPendingId))
+            return $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.
+         * Note. This section isn't used for now because only a member can purchase!
+         */
+        if((int)$aInfo['client_id'] == 0 && (int)$aInfo['items_count'] == 1) {
+            reset($aInfo['items']);
+            $aItem = current($aInfo['items']);
+
+            if(!empty($aItem) && $this->_oConfig->getPrice($sType, $aItem)) {
+                $this->_oDb->updateOrderPending($iPendingId, array(
+                    'order' => $this->_oConfig->getLicense(),
+                    'error_code' => '1',
+                    'error_msg' => ''
+                ));
+
+                $this->getObjectJoin()->performJoin($iPendingId);
+            }
+        }
+
+        return $oProvider->initializeCheckout($iPendingId, $aInfo, $sRedirect);
+    }
+
+    public function serviceInitializeCheckoutApi($sType, $iSellerId, $sProvider, $aItems = [], $sRedirect = '', $aCustoms = [])
+    {
+        $mixedResult = $this->serviceInitializeCheckout($sType, $iSellerId, $sProvider, $aItems, $sRedirect, $aCustoms);
+        if(is_string($mixedResult))
+            return [bx_api_get_msg($mixedResult)];
+        
+        if(is_array($mixedResult)) {
+            if(isset($mixedResult['redirect'])) {
+                header('Location: ' . bx_api_get_relative_url($mixedResult['redirect']));
+                exit;
+            }
+
+            if(isset($mixedResult['message']))
+                return [bx_api_get_msg($mixedResult)];
+        }
+
+        return [];
+    }
+
+    public function actionFinalizeCheckout($sProvider, $mixedVendorId = "")
+    {
+        $aData = &$_REQUEST;
+
+        $aResult = $this->serviceFinalizeCheckout($sProvider, $mixedVendorId, $aData);
+        if(isset($aResult['error']))
+            return $this->_oTemplate->displayPageCodeError($aResult['error']);
+        else if(isset($aResult['redirect'])) {
+            header('Location: ' . $aResult['redirect']);
+            exit;
+        }
+        else
+            $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+    }
+    
+    public function serviceFinalizeCheckout($sProvider, $mixedVendorId = "", $aData = [])
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+            return ['error' => $this->_sLangsPrefix . 'err_incorrect_provider'];
+
+        $aResult = $oProvider->finalizeCheckout($aData);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) 
+            return ['error' => $aResult['message']];
+
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$aResult['pending_id']]);
+        $bTypeRecurring = $aPending['type'] == BX_PAYMENT_TYPE_RECURRING;
+        $bAuthorized = isset($aResult['authorized']) && $aResult['authorized'];
+        $bPaid = isset($aResult['paid']) && $aResult['paid'];
+        $bTrial = isset($aResult['trial']) && $aResult['trial'];
+
+        //--- Register subscription
+        if($bTypeRecurring) {
+            $sStatus = BX_PAYMENT_SBS_STATUS_UNPAID;
+            if($bPaid)
+                $sStatus = BX_PAYMENT_SBS_STATUS_ACTIVE;
+            else if($bTrial)
+                $sStatus = BX_PAYMENT_SBS_STATUS_TRIAL;
+
+            $aSubscription = array(
+                'customer_id' => $aResult['customer_id'], 
+                'subscription_id' => $aResult['subscription_id'],
+                'status' => $sStatus
+            );
+
+            if(!$this->getObjectSubscriptions()->register($aPending, $aSubscription))
+                return ['error' => $this->_sLangsPrefix . 'err_already_registered'];
+        }
+
+        $this->onPaymentRegisterBefore($aPending);
+
+        //--- Check "Pay Before Join" situation
+        if((int)$aPending['client_id'] == 0)
+            $this->getObjectJoin()->performJoin((int)$aPending['id'], isset($aResult['client_name']) ? $aResult['client_name'] : '', isset($aResult['client_email']) ? $aResult['client_email'] : '');
+
+        //--- Authorize order for selected items in associated modules 
+        if($bAuthorized)
+            $this->authorizePayment($aPending);
+
+        //--- Register payment for purchased items in associated modules 
+        if($bPaid || ($bTypeRecurring && $bTrial))
+            $this->registerPayment($aPending);
+
+        //--- Get updated pending order
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => $aPending['id']]);
+
+        $this->alert('finalize_checkout', 0, bx_get_logged_profile_id(), array(
+            'pending' => $aPending,
+            'transactions' => $this->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => (int)$aPending['id'])),
+            'provider' => $oProvider,
+            'message' => &$aResult['message'],
+            'result' => &$aResult,
+        ));
+
+        if($oProvider->needRedirect()) 
+            return ['redirect' => $oProvider->getReturnUrl()];
+
+        if(!empty($aResult['redirect'])) 
+            return ['redirect' => $this->_oConfig->urlDecode($aResult['redirect'])];
+
+        return ['message' => $aResult['message']];
+    }
+
+    public function actionFinalizedCheckout($sProvider, $mixedVendorId = "")
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $aResult = $oProvider->finalizedCheckout();
+        $this->_oTemplate->displayPageCodeResponse($aResult['message']);
+    }
+
+    public function actionNotify($sProvider, $mixedVendorId = "")
+    {
+    	$oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $oProvider->notify();
+    }
+    
+    /**
+     * The method is needed to pass direct action calls to necessary Payment Provider.
+     */
+    public function actionCall($sProvider, $sAction, $mixedVendorId = BX_PAYMENT_EMPTY_ID)
+    {
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false)
+            BxDolRequest::methodNotFound($sAction, $this->getName());
+
+         $sMethod = 'action' . bx_gen_method_name($sAction);
+         if(!method_exists($oProvider, $sMethod))
+             BxDolRequest::methodNotFound($sAction, $this->getName());
+
+        return call_user_func_array(array($oProvider, $sMethod), array_slice(func_get_args(), 2));
+    }
+
+    public function onProfileJoin($iProfileId)
+    {
+    	$this->getObjectJoin()->onProfileJoin($iProfileId);
+    }
+
+    public function onProfileDelete($iProfileId)
+    {
+        //--- Cancel subscriptions
+        $aSubscriptions = $this->_oDb->getSubscription(['type' => 'mixed_ext', 'conditions' => ['client_id' => $iProfileId]]);
+        if(!empty($aSubscriptions) && is_array($aSubscriptions)) 
+            foreach($aSubscriptions as $aSubscription)
+                $this->getObjectSubscriptions()->cancel($aSubscription['pending_id']);
+
+        //--- Clean DB
+        $this->_oDb->onProfileDelete($iProfileId);
+    }
+
+    public function isAllowedPurchase($aItem, $bPerform = false)
+    {
+        $iUserId = (int)$this->getProfileId();
+
+        $aItemInfo = $this->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $iUserId, isset($aItem['custom']) ? $aItem['custom'] : array()));
+        if(empty($aItemInfo))
+            return false;
+
+        if(isAdmin())
+            return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'purchase', $this->getName(), $bPerform);
+        if($aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
+            return true;
+
+        return $aCheckResult[CHECK_ACTION_MESSAGE];
+    }
+
+    public function isAllowedSell($aItem, $bPerform = false)
+    {
+        $iUserId = (int)$this->getProfileId();
+        if(!$iUserId)
+            return false;
+
+        $aItemInfo = $this->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $iUserId));
+        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];
+    }
+
+    public function isAllowedManage($aPending, $bPerform = false)
+    {
+        $iUserId = (int)$this->getProfileId();
+
+        if($iUserId == $aPending['client_id'] || $iUserId == $aPending['seller_id'] || isAdmin())
+            return true;
+
+        $aCheckResult = checkActionModule($iUserId, 'manage any purchase', $this->getName(), $bPerform);
+        if($aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
+            return true;
+
+        return $aCheckResult[CHECK_ACTION_MESSAGE];
+    }
+
+    public function isAllowedManageInvoices($bPerform = false)
+    {
+        if(BxDolAcl::getInstance()->isMemberLevelInSet(array(MEMBERSHIP_ID_MODERATOR, MEMBERSHIP_ID_ADMINISTRATOR)) || isAdmin())
+            return true;
+
+        return _t('_sys_txt_access_denied');
+    }
+
+    public function checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount, $aCustom = array())
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        if($iSellerId == BX_PAYMENT_EMPTY_ID || empty($iModuleId) || empty($iItemId) || empty($iItemCount))
+            return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+
+        $iClientId = $this->getProfileId();
+        if(empty($iClientId)) {
+            $sLoginUrl = BxDolPermalinks::getInstance()->permalink('page.php?i=login');
+            return array('code' => 2, 'eval' => 'window.open("' . $sLoginUrl . '", "_self");');
+        }
+
+        $mixedResult = $this->isAllowedPurchase(array('module_id' => $iModuleId, 'item_id' => $iItemId, 'custom' => $aCustom));
+        if($mixedResult !== true) {
+            if(is_string($mixedResult) && !empty($mixedResult))
+                return array('code' => 2, 'message' => $mixedResult);
+            else 
+                return array('code' => 1, 'message' => _t($CNF['T']['ERR_WRONG_DATA']));
+        }
+
+        if($iClientId == $iSellerId)
+            return array('code' => 3, 'message' => _t($CNF['T']['ERR_SELF_PURCHASE']));
+
+        $aSeller = $this->getVendorInfo($iSellerId);
+        if(!$aSeller['active'])
+            return array('code' => 4, 'message' => _t($CNF['T']['ERR_INACTIVE_VENDOR']));
+
+		return true;
+    }
+
+    public function authorizePayment($mixedPending)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+    	if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        $sType = $aPending['type'];
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+
+        if((int)$aPending['authorized'] == 1)
+            return true;
+
+        $iClientId = (int)$aPending['client_id'];
+
+        $aCart = array();
+        if($bTypeSingle)
+            $aCart = $this->_oDb->getCartContent($iClientId);
+        
+        $bResult = false;
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem) {
+            $sItem = $this->_oConfig->descriptorA2S([$aItem['vendor_id'], $aItem['module_id'], $aItem['item_id']]);
+            
+            $sMethod = $bTypeSingle ? 'callAuthorizeCartItem' : 'callAuthorizeSubscriptionItem';
+            $aItemInfo = $this->$sMethod((int)$aItem['module_id'], [$aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order']]);
+            if(empty($aItemInfo) || !is_array($aItemInfo))
+                continue;
+
+            if($bTypeSingle)
+            	$aCart['items'] = trim(preg_replace("'" . $this->_oConfig->descriptorA2S($aItem) . ":?'", "", $aCart['items']), ":");
+
+            $bResult = true;
+        }
+
+        if($bResult) {
+            $this->_oDb->updateOrderPending($aPending['id'], ['authorized' => 1]);
+
+            $this->onPaymentAuthorize($aPending);
+        }
+
+        return $bResult;
+    }
+    
+    public function registerPayment($mixedPending)
+    {
+    	$aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+    	if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        $sType = $aPending['type'];
+        $bTypeSingle = $sType == BX_PAYMENT_TYPE_SINGLE;
+
+        if($bTypeSingle && (int)$aPending['processed'] == 1)
+            return true;
+
+        $iClientId = (int)$aPending['client_id'];
+        $iSellerId = (int)$aPending['seller_id'];
+        $sLicense = $this->_oConfig->getLicense();
+        $aCustoms = !empty($aPending['customs']) ? $this->_oConfig->s2a($aPending['customs'], false) : [];
+        $aCart = $bTypeSingle ? $this->_oDb->getCartContent($iClientId) : [];
+
+        $bResult = false;
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem) {
+            $sItem = $this->_oConfig->descriptorA2S([$aItem['vendor_id'], $aItem['module_id'], $aItem['item_id']]);
+            $aItemCustom = $this->_oConfig->getCustom($sItem, $aCustoms);
+
+            $sMethod = $bTypeSingle ? 'callRegisterCartItem' : 'callRegisterSubscriptionItem';
+            $aItemInfo = $this->$sMethod((int)$aItem['module_id'], [$iClientId, $iSellerId, $aItem['item_id'], $aItem['item_count'], $aPending['order'], $sLicense, $aItemCustom]);
+            if(empty($aItemInfo) || !is_array($aItemInfo))
+                continue;
+
+            $this->_oDb->insertOrderProcessed([
+                'pending_id' => $aPending['id'],
+                'client_id' => $iClientId,
+                'seller_id' => $iSellerId,
+                'author_id' => (int)$aItem['vendor_id'],
+                'module_id' => (int)$aItem['module_id'],
+                'item_id' => (int)$aItem['item_id'],
+                'item_count' => (int)$aItem['item_count'],
+                'amount' => (int)$aItem['item_count'] * $this->_oConfig->getPrice($sType, $aItemInfo),
+                'currency' => !empty($aPending['currency']) ? $aPending['currency'] : $this->getVendorCurrencyCode($iSellerId),
+            	'license' => $sLicense,
+            ]);
+
+            if($bTypeSingle) {
+                $this->_oConfig->pullCustom($sItem, $aCart['customs']);
+
+            	$aCart['items'] = trim(preg_replace("'" . $this->_oConfig->descriptorA2S($aItem) . ":?'", "", $aCart['items']), ":");
+            }
+
+            $bResult = true;
+        }
+
+        if($bTypeSingle)
+            $this->_oDb->setCartItems($iClientId, $aCart['items'], $aCart['customs']);
+
+        if($bResult) {
+            $this->_oDb->updateOrderPending($aPending['id'], ['processed' => 1]);
+
+            $this->onPaymentRegister($aPending);
+        }
+
+        return $bResult;
+    }
+
+    public function refundPayment($mixedPending)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        $bTypeSingle = $aPending['type'] == BX_PAYMENT_TYPE_SINGLE;
+
+        $iCanceled = 0;
+        $aOrders = $this->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => (int)$aPending['id']));
+        foreach($aOrders as $aOrder) {
+            $sMethod = $bTypeSingle ? 'callUnregisterCartItem' : 'callUnregisterSubscriptionItem';
+            $bResult = $this->$sMethod((int)$aOrder['module_id'], array($aOrder['client_id'], $aOrder['seller_id'], $aOrder['item_id'], $aOrder['item_count'], $aPending['order'], $aOrder['license']));
+            if(!$bResult)
+                continue;
+
+            if($this->_oDb->deleteOrderProcessed($aOrder['id']))
+                $iCanceled++;
+        }
+
+        if($iCanceled != count($aOrders))
+                return false;
+
+        $bResult = $this->_oDb->deleteOrderPending($aPending['id']);
+        if($bResult)
+                $this->onPaymentRefund($aPending);
+
+        return $bResult;
+    }
+
+    /**
+     * @deprecated since version 12.0.0
+     * 
+     * @use BxPaymentSubscriptions::register instead.
+     */
+    public function registerSubscription($aPending, $aParams = array())
+    {
+        return $this->getObjectSubscriptions()->register($aPending, $aParams);
+    }
+
+    /**
+     * @deprecated since version 12.0.0
+     * 
+     * @use BxPaymentSubscriptions::cancelLocal instead.
+     */
+    public function cancelSubscription($mixedPending)
+    {
+        return $this->getObjectSubscriptions()->cancelLocal($mixedPending);
+    }
+
+    public function processCommissions()
+    {
+        if(!defined('BX_DOL_CRON_EXECUTE'))
+            return;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if((int)date('j') == $this->_oConfig->getInvoiceIssueDay())
+            $this->_invoicesIssue();
+
+        $this->_invoicesCheck();
+    }
+
+    protected function _invoicesIssue()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sInvoiceNameMask = 'INV-%d-%d-%d';
+
+        $iMonth = date('m');
+        $iYear = date('Y');
+        $iPeriodStart = mktime(0, 0, 0, $iMonth-1, 1, $iYear);
+        $iPeriodEnd = mktime(23, 59, 59, $iMonth, 0, $iYear);
+        $iDateIssue = time();
+        $iDateDue = $iDateIssue + 86400 * $this->_oConfig->getInvoiceLifetime();
+
+        $aCommissionsInfo = array();
+        $aAclLevels = BxDolAcl::getInstance()->getMemberships(false, true, false, true);
+        foreach($aAclLevels as $iAclLevelId => $sAclLevelTitle)
+            $aCommissionsInfo[$iAclLevelId] = $this->_oDb->getCommissions(array('type' => 'acl_id', 'acl_id' => $iAclLevelId));
+
+        $iMainSellerId = $this->_oConfig->getSiteAdmin();
+
+        $aVendors = $this->_oDb->getOrderProcessed(array('type' => 'income', 'period_start' => $iPeriodStart, 'period_end' => $iPeriodEnd));
+        foreach($aVendors as $aVendor) {
+            $iVendorId = (int)$aVendor['id'];
+            if($iVendorId == $iMainSellerId)
+                continue;
+
+            $aInvoice = $this->_oDb->getInvoices(array('type' => 'committent_id', 'committent_id' => $iVendorId, 'period_start' => $iPeriodStart, 'period_end' => $iPeriodEnd));
+            if(!empty($aInvoice) && is_array($aInvoice))
+                continue;
+
+            $aVendorAcl = BxDolAcl::getInstance()->getMemberMembershipInfo($iVendorId);
+            $aCommissions = $aCommissionsInfo[$aVendorAcl['id']];
+
+            $fCommission = 0;
+            foreach($aCommissions as $aCommission) {
+                if((float)$aCommission['percentage'] > 0)
+                    $fCommission += (float)$aVendor['amount'] * (float)$aCommission['percentage'] / 100;
+
+                if((float)$aCommission['installment'] > 0)
+                    $fCommission += (float)$aCommission['installment'];
+            }
+            
+            $this->alert('calculate_commission', 0, 0, array(
+                'vendor' => $aVendor,
+                'commissions' => $aCommissions,
+                'override_result' => &$fCommission,
+            ));
+
+            $this->_oDb->insertInvoice(array(
+                'name' => sprintf($sInvoiceNameMask, $iMainSellerId, $iVendorId, $this->_oDb->getInvoices(array(
+                    'type' => 'index', 
+                    'commissionaire_id' => $iMainSellerId, 
+                    'committent_id' => $iVendorId
+                ))),
+                'commissionaire_id' => $iMainSellerId, 
+                'committent_id' => $iVendorId,
+                'amount' => $fCommission,
+                'period_start' => $iPeriodStart,
+                'period_end' => $iPeriodEnd,
+                'date_issue' => $iDateIssue,
+                'date_due' => $iDateDue,
+                'status' => BX_PAYMENT_INV_STATUS_UNPAID
+            ));
+        }
+    }
+
+    protected function _invoicesCheck()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sPrefix = $this->_oConfig->getPrefix('general');
+        $oEmailTemplates = BxDolEmailTemplates::getInstance();
+
+        //--- Process expiring invoices.
+        $aInvoices = $this->_oDb->getInvoices(array('type' => 'expiring'));
+        if(!empty($aInvoices) && is_array($aInvoices))
+            foreach($aInvoices as $aInvoice) {
+                if((int)$aInvoice['ntf_exp'] > 0)
+                    continue;
+
+                $oCommittent = BxDolProfile::getInstance($aInvoice['committent_id']);
+                if(!$oCommittent)
+                    continue;
+
+                $bResult = sendMailTemplate($sPrefix . 'expiring_notification_committent', 0, (int)$aInvoice['committent_id'], array(
+                    'invoice' => $aInvoice['name'],
+                    'days' => $this->_oConfig->getInvoiceExpirationNotify(),
+                    'period_start' => $this->_oConfig->formatDate($aInvoice['period_start']),
+                    'period_end' => $this->_oConfig->formatDate($aInvoice['period_end']),
+                    'date_issue' => $this->_oConfig->formatDateTime($aInvoice['date_issue']),
+                    'date_due' => $this->_oConfig->formatDateTime($aInvoice['date_due']),
+                ), BX_EMAIL_NOTIFY, true);
+
+                if($bResult)
+                    $this->_oDb->updateInvoice($aInvoice['id'], array('ntf_exp' => 1));
+            }
+
+        //--- Process overdue invoices.
+        $aInvoices = $this->_oDb->getInvoices(array('type' => 'overdue'));
+        if(!empty($aInvoices) && is_array($aInvoices))
+            foreach($aInvoices as $aInvoice) {
+                if((int)$aInvoice['ntf_due'] > 0 && $aInvoice['status'] == BX_PAYMENT_INV_STATUS_OVERDUE)
+                    continue;
+
+                $oCommittent = BxDolProfile::getInstance($aInvoice['committent_id']);
+                if(!$oCommittent)
+                    continue;
+
+                $bResult = sendMailTemplate($sPrefix . 'overdue_notification_committent', 0, (int)$aInvoice['committent_id'], array(
+                    'invoice' => $aInvoice['name'],
+                    'period_start' => $this->_oConfig->formatDate($aInvoice['period_start']),
+                    'period_end' => $this->_oConfig->formatDate($aInvoice['period_end']),
+                    'date_issue' => $this->_oConfig->formatDateTime($aInvoice['date_issue']),
+                    'date_due' => $this->_oConfig->formatDateTime($aInvoice['date_due']),
+                ), BX_EMAIL_NOTIFY, true);
+
+                $this->_oDb->updateInvoice($aInvoice['id'], array(
+                    'status' => BX_PAYMENT_INV_STATUS_OVERDUE, 
+                    'ntf_due' => $bResult ? 1 : 0
+                ));
+            }
+    }
+
+    public function processTimeTracker()
+    {
+        if(!defined('BX_DOL_CRON_EXECUTE'))
+            return;
+
+        $aSubscriptions = $this->_oDb->getSubscription(array(
+            'type' => 'time_tracker',
+            'status_active' => BX_PAYMENT_SBS_STATUS_ACTIVE,
+            'status_trial' => BX_PAYMENT_SBS_STATUS_TRIAL,
+            'status_unpaid' => BX_PAYMENT_SBS_STATUS_UNPAID,
+            'pay_attempts_max' => $this->_oConfig->getPayAttemptsMax(),
+            'pay_attempts_interval' => $this->_oConfig->getPayAttemptsInterval()
+        ));
+
+        if(empty($aSubscriptions) || !is_array($aSubscriptions))
+            return;
+
+        foreach($aSubscriptions as $aSubscription) {
+            $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$aSubscription['pending_id']));
+            if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot process subscription.', BX_LOG_ERR);
+                continue;
+            }
+
+            $oProvider = $this->getObjectProvider($aPending['provider'], $aPending['seller_id']);
+            if($oProvider === false || !$oProvider->isActive() || !method_exists($oProvider, 'makePayment')) {
+                $this->log($aSubscription, 'Time Tracker', 'Payment provider unavailable or incorrect.', BX_LOG_ERR);
+                continue;
+            }
+
+            $this->_oDb->updateSubscription(['pay_attempts' => (int)$aSubscription['pay_attempts'] + 1], ['id' => $aSubscription['id']]);
+
+            if(($mixedResult = $oProvider->makePayment($aPending)) !== true) {
+                $this->_oDb->updateSubscription(['status' => BX_PAYMENT_SBS_STATUS_UNPAID], ['id' => $aSubscription['id']]);
+
+                $this->log($aSubscription, 'Time Tracker', 'Payment cannot be processed (code: ' . (!empty($mixedResult['code']) ? (int)$mixedResult['code'] : 0) . ').', BX_LOG_ERR);
+                continue;
+            }
+
+            if(!$this->getObjectSubscriptions()->prolong($aPending)) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot prolong subscription.', BX_LOG_ERR);
+                continue;
+            }
+
+            if(!$this->registerPayment($aPending)) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot register payment.', BX_LOG_ERR);
+                continue;
+            }
+        }
+    }
+
+    public function onPaymentRegisterBefore($aPending, $aResult = [])
+    {
+        $this->alert('before_register_payment', 0, $aPending['client_id'], array('pending' => $aPending));
+    }
+
+    public function onPaymentAuthorize($aPending, $aResult = [])
+    {
+        $this->alert('authorize_payment', 0, $aPending['client_id'], ['pending' => $aPending]);
+    }
+
+    public function onPaymentRegister($aPending, $aResult = [])
+    {
+        $bTypeSingle = $aPending['type'] == BX_PAYMENT_TYPE_SINGLE;
+
+        if($bTypeSingle) {
+            $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+            foreach($aItems as $aItem)
+                $this->isAllowedPurchase(['module_id' => $aItem['module_id'], 'item_id' => $aItem['item_id']], true);
+        }
+
+        $this->alert('register_payment', 0, $aPending['client_id'], ['pending' => $aPending]);
+    }
+
+    public function onPaymentRefund($aPending, $aResult = [])
+    {
+        $this->alert('refund_payment', 0, $aPending['client_id'], ['pending' => $aPending]);
+    }
+
+    public function onSubscriptionCreate($aPending, $aSubscription, $aResult = [])
+    {
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        $this->isAllowedPurchase(['module_id' => $aItems[0]['module_id'], 'item_id' => $aItems[0]['item_id']], true);
+
+        $this->alert('create_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function onSubscriptionProlong($aPending, $aSubscription, $aResult = [])
+    {
+        $this->alert('prolong_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function onSubscriptionOverdue($aPending, $aSubscription, $aResult = [])
+    {
+        $this->alert('overdue_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function onSubscriptionCancel($aPending, $aSubscription, $aResult = [])
+    {
+        $this->alert('cancel_subscription', 0, $aPending['client_id'], [
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ]);
+    }
+
+    public function setSiteSubmenu($sSubmenu, $sSelModule, $sSelName)
+    {
+        $oSiteSubmenu = BxDolMenu::getObjectInstance('sys_site_submenu');
+        if(!$oSiteSubmenu)
+            return;
+
+        $sModuleSubmenu = $this->_oConfig->getObject($sSubmenu);
+        $oModuleSubmenu = BxDolMenu::getObjectInstance($sModuleSubmenu);
+        if(!$oModuleSubmenu) 
+            return;
+
+        $oSiteSubmenu->setObjectSubmenu($sModuleSubmenu);
+        $oModuleSubmenu->setSelected($sSelModule, $sSelName);
+    }
+
+    public function getProviderButtonJs($aCartItem, $aProvider, $sRedirect = '', $aCustom = array())
+    {
+        $aButtonJs = array();
+        $iClientId = $this->getProfileId();
+
+        $sItemAddons = '';
+        if(count($aCartItem) == 5)
+            $sItemAddons = array_pop($aCartItem);
+
+        list($iSellerId, $iModuleId, $iItemId, $iItemCount) = $aCartItem;
+
+        $oProvider = $this->getObjectProvider($aProvider['name'], $iSellerId);
+        if($oProvider !== false && method_exists($oProvider, 'getButtonRecurring')) {
+            $aParams = array(
+                'sObjNameCart' => $this->_oConfig->getJsObject('cart'),
+                'iSellerId' => $iSellerId,
+                'iModuleId' => $iModuleId,
+                'iItemId' => $iItemId,
+                'iItemCount' => $iItemCount,
+                'sItemAddons' => $sItemAddons,
+                'sRedirect' => $sRedirect,
+                'sCustom' => base64_encode(json_encode($aCustom))
+            );
+
+            $aCartInfo = $this->getObjectCart()->getInfo(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iSellerId, $this->_oConfig->descriptorA2S($aCartItem));
+            if(!empty($aCartInfo['items_price']) && !empty($aCartInfo['items']) && is_array($aCartInfo['items'])) {
+                $aItem = array_shift($aCartInfo['items']);
+
+                $aParams = array_merge($aParams, array(
+                    'iAmount' => (int)round(100 * (float)$aCartInfo['items_price']),
+                    'sItemName' => $aItem['name'],
+                    'sItemTitle' => $aItem['title']
+                ));
+            }
+
+            $aButtonJs = $oProvider->getButtonRecurringJs($iClientId, $iSellerId, $aParams);
+        }
+
+        if(empty($aButtonJs) || !is_array($aButtonJs))
+            $aButtonJs = $this->getObjectSubscriptions()->serviceGetSubscribeJs($iSellerId, $aProvider['name'], $iModuleId, $iItemId, $iItemCount, $sRedirect, $aCustom);
+
+        return $aButtonJs;
+    }
+
+    /**
+     * Integration with itslef which is needed to pay an invoice.
+     */
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-get_payment_data get_payment_data
+     * 
+     * @code bx_srv('bx_payment', 'get_payment_data', [...]); @endcode
+     * 
+     * Get an array with module's description. Is needed for payments processing module.
+     * 
+     * @return an array with module's description.
+     * 
+     * @see BxPaymentModule::serviceGetPaymentData
+     */
+    /** 
+     * @ref bx_payment-get_payment_data "get_payment_data"
+     */
+    public function serviceGetPaymentData()
+    {
+        return $this->_aModule;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-get_cart_item get_cart_item
+     * 
+     * @code bx_srv('bx_payment', 'get_cart_item', [...]); @endcode
+     * 
+     * Get an array with prodict's description. Is used in Shopping Cart in payments processing module.
+     * 
+     * @param $mixedItemId product's ID or Unique Name.
+     * @return an array with prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceGetCartItem
+     */
+    /** 
+     * @ref bx_payment-get_cart_item "get_cart_item"
+     */
+    public function serviceGetCartItem($mixedItemId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        if(!$mixedItemId)
+            return array();
+
+        if(is_numeric($mixedItemId))
+            $aItem = $this->_oDb->getInvoices(array('type' => 'id', 'id' => (int)$mixedItemId));
+        else 
+            $aItem = $this->_oDb->getInvoices(array('type' => 'name', 'name' => $mixedItemId));
+
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        $oCommissionaire = BxDolProfile::getInstanceMagic($aItem['commissionaire_id']);
+
+        return array (
+            'id' => $aItem['id'],
+            'author_id' => $aItem['commissionaire_id'],
+            'name' => $aItem['name'],
+            'title' => _t('_bx_payment_txt_invoice_title', $aItem['name'], $oCommissionaire->getDisplayName()),
+            'description' => _t('_bx_payment_txt_invoice_description', bx_process_output($aItem['period_start'], BX_DATA_DATE_TS_UTC), bx_process_output($aItem['period_end'], BX_DATA_DATE_TS_UTC)),
+            'url' => '',
+            'price_single' => $aItem['amount'],
+            'price_recurring' => '',
+            'period_recurring' => 0,
+            'period_unit_recurring' => '',
+            'trial_recurring' => ''
+        );
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-get_cart_items get_cart_items
+     * 
+     * @code bx_srv('bx_payment', 'get_cart_items', [...]); @endcode
+     * 
+     * Get an array with prodicts' descriptions by seller. Is used in Manual Order Processing in payments processing module.
+     * 
+     * @param $iCommissionaireId commissionaire ID.
+     * @return an array with prodicts' descriptions. Empty array is returned if something is wrong or seller doesn't have any products.
+     * 
+     * @see BxPaymentModule::serviceGetCartItems
+     */
+    /** 
+     * @ref bx_payment-get_cart_items "get_cart_items"
+     */
+    public function serviceGetCartItems($iCommissionaireId)
+    {
+    	$CNF = &$this->_oConfig->CNF;
+
+        $iCommissionaireId = (int)$iCommissionaireId;
+        if(empty($iCommissionaireId))
+            return array();
+
+        $sCommissionaireName = BxDolProfile::getInstanceMagic($iCommissionaireId)->getDisplayName();
+
+        $aItems = $this->_oDb->getInvoices(array('type' => 'commissionaire_id', 'commissionaire_id' => $iCommissionaireId));      
+
+        $aResult = array();
+        foreach($aItems as $aItem)
+            $aResult[] = array(
+                'id' => $aItem['id'],
+                'author_id' => $aItem['commissionaire_id'],
+                'name' => $aItem['name'],
+                'title' => _t('_bx_payment_txt_invoice_title', $aItem['name'], $sCommissionaireName),
+                'description' => _t('_bx_payment_txt_invoice_description', bx_process_output($aItem['period_start'], BX_DATA_DATE_TS_UTC), bx_process_output($aItem['period_end'], BX_DATA_DATE_TS_UTC)),
+                'url' => '',
+                'price_single' => $aItem['amount'],
+                'price_recurring' => '',
+                'period_recurring' => 0,
+                'period_unit_recurring' => '',
+                'trial_recurring' => ''
+            );
+
+        return $aResult;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-register_cart_item register_cart_item
+     * 
+     * @code bx_srv('bx_payment', 'register_cart_item', [...]); @endcode
+     * 
+     * Register a processed single time payment inside the Payment module. Is called with payment processing module after the payment was registered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return an array with purchased prodict's description. Empty array is returned if something is wrong.
+     * 
+     * @see BxPaymentModule::serviceRegisterCartItem
+     */
+    /** 
+     * @ref bx_payment-register_cart_item "register_cart_item"
+     */
+    public function serviceRegisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aItem = $this->serviceGetCartItem($iItemId);
+        if(empty($aItem) || !is_array($aItem))
+            return array();
+
+        if(!$this->_oDb->updateInvoice($iItemId, array('status' => BX_PAYMENT_INV_STATUS_PAID)))
+            return array();
+
+        $this->alert('invoice_marked_as_paid', 0, false, array(
+            'product_id' => $iItemId,
+            'profile_id' => $iClientId,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'type' => BX_PAYMENT_TYPE_SINGLE,
+            'count' => $iItemCount,
+            'duration' => '',
+            'trial' => ''
+        ));
+
+        return $aItem;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-payments Payments
+     * @subsubsection bx_payment-unregister_cart_item unregister_cart_item
+     * 
+     * @code bx_srv('bx_payment', 'unregister_cart_item', [...]); @endcode
+     * 
+     * Unregister an earlier processed single time payment inside the Payment module. Is called with payment processing module after the payment was unregistered there.
+     * 
+     * @param $iClientId client ID.
+     * @param $iSellerId seller ID
+     * @param $iItemId item ID.
+     * @param $iItemCount the number of purchased items.
+     * @param $sOrder order number received from payment provider (PayPal, Stripe, etc)
+     * @param $sLicense license number genereted with payment processing module for internal usage
+     * @return boolean value determining where the payment was unregistered or not.
+     * 
+     * @see BxPaymentModule::serviceUnregisterCartItem
+     */
+    /** 
+     * @ref bx_payment-unregister_cart_item "unregister_cart_item"
+     */
+    public function serviceUnregisterCartItem($iClientId, $iSellerId, $iItemId, $iItemCount, $sOrder, $sLicense)
+    {
+        if(!$this->_oDb->updateInvoice($iItemId, array('status' => BX_PAYMENT_INV_STATUS_UNPAID)))
+            return false;
+
+        $this->alert('invoice_marked_as_unpaid', 0, false, array(
+            'product_id' => $iItemId,
+            'profile_id' => $iClientId,
+            'order' => $sOrder,
+            'license' => $sLicense,
+            'type' => BX_PAYMENT_TYPE_SINGLE,
+            'count' => $iItemCount
+        ));
+
+    	return true;
+    }
+
+    public function serviceStripeV3CreateSessionApi($mixedParams)
+    {
+        $aParams = is_array($mixedParams) ? $mixedParams : json_decode($mixedParams, true);
+        if(!isset($aParams['type'], $aParams['seller_id'], $aParams['items']))
+            return [bx_api_get_msg(_t($this->_sLangsPrefix . 'err_wrong_data'))];
+            
+        $sProvider = 'stripe_v3';
+        $iClientId = $this->getProfileId();
+        $iSellerId = (int)$aParams['seller_id'];
+        $sItems = $aParams['items'];
+
+        $oProvider = $this->getObjectProvider($sProvider, $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return [bx_api_get_msg(_t($this->_sLangsPrefix . 'err_incorrect_provider'))];
+
+        $aSessionParams = [];
+        if(!empty($aParams['return_url']))
+            $aSessionParams['return_url'] = $aParams['return_url'] . '/api.php?r=' . $this->getName() . '/initialize_checkout_api&params[]=' . implode('&params[]=', [$aParams['type'], $iSellerId, $sProvider, $sItems, $this->_oConfig->urlEncode($this->_oConfig->getUrl('URL_HISTORY'))]);
+        
+        $minxedSession = $oProvider->createSessionPaymentEmbedded($aParams['type'], $iClientId, $iSellerId, $sItems, $aSessionParams);
+        if($minxedSession === false)
+            return [bx_api_get_msg(_t($this->_sLangsPrefix . 'err_cannot_perform'))];
+
+        return [
+            'clientSecret' => $minxedSession
+        ];
+    }
+
+    public function serviceConvert($fAmount, $sCurrencyFrom, $sCurrencyTo, $fRate = false)
+    {
+        $sCurrencyDefault = $this->_oConfig->getDefaultCurrencyCode();
+        $bFromDefault = strcmp($sCurrencyFrom, $sCurrencyDefault) == 0;
+        $bToDefault = strcmp($sCurrencyTo, $sCurrencyDefault) == 0;
+
+        if(!$bFromDefault && !$bToDefault)
+            return false;
+
+        if($fRate === false)
+            $fRate = $this->_oDb->getCurrencyExchangeRate($bFromDefault ? $sCurrencyTo : $sCurrencyFrom);
+        if($fRate === false)
+            return false;
+
+        $fRate = (float)$fRate;
+        if($bToDefault)
+            $fRate = 1/$fRate;
+
+        return $fAmount * $fRate;
+    }
+
+    public function updateCurrencyExchangeRates()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sApiKey = getParam($CNF['PARAM_CURRENCY_EXCHANGE_API']);
+        if(empty($sApiKey))
+            return;
+
+        $sCurrency = $this->_oDb->getParam($CNF['PARAM_CURRENCY_CODE'], false);
+        $aCurrencies = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_CURRENCIES'], false, BX_DATA_VALUES_ADDITIONAL);
+        unset($aCurrencies[$sCurrency]);
+
+        $sApiEndpoint = 'https://api.apilayer.com/exchangerates_data/latest';
+        $aApiParams = [
+            'symbols' => implode(',', array_keys($aCurrencies)), 
+            'base' => $sCurrency
+        ];
+        $sResponse = bx_file_get_contents($sApiEndpoint, $aApiParams, 'get', [
+            'apikey: ' . $sApiKey
+        ]);
+
+        $aResponse = json_decode($sResponse, true);
+        if(empty($aResponse['rates']) || !is_array($aResponse['rates']))
+            return;
+
+        $this->_oDb->deleteCurrencyExchangeRate($sCurrency);
+
+        foreach($aResponse['rates'] as $sCode => $fRate)
+            $this->_oDb->updateCurrencyExchangeRate($sCode, $fRate);
+    }
+}
+
+/** @} */

+ 188 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderAppleInApp.php

@@ -0,0 +1,188 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentProviderAppleInApp extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    protected $_sSecret;
+
+    protected $_sVerifyReceipt;
+    protected $_sVerifyReceiptSandbox;
+
+    public function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_sVerifyReceipt = 'https://buy.itunes.apple.com/verifyReceipt';
+        $this->_sVerifyReceiptSandbox = 'https://sandbox.itunes.apple.com/verifyReceipt';
+    }
+
+    public function initOptions($aOptions)
+    {
+    	parent::initOptions($aOptions);
+
+        $this->_sSecret = $this->getOption('secret');
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+    	return $this->_sLangsPrefix . 'err_not_supported';
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_supported');
+    }
+
+    public function notify()
+    {
+        $iResult = $this->_processNotification();
+        http_response_code($iResult);
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        if(empty($aParams['id']))
+            return array();
+
+        $sPrefix = 'bx-payment-aina-';
+
+        return array(
+            array('id' => $sPrefix . 'cancel', 'name' => $sPrefix . 'cancel', 'class' => '', 'link' => 'https://apps.apple.com/account/subscriptions', 'target' => '_blank', 'title' => _t('_bx_payment_aina_menu_item_title_cancel'))
+        );
+    }
+
+    protected function _processNotification()
+    {
+        $sPath = "php://input"; //BX_DIRECTORY_PATH_TMP . "aina_renew.json"; // "aina_init.json";
+    	$sInput = @file_get_contents($sPath);
+        $aNotification = json_decode($sInput, true);
+        if(empty($aNotification) || !is_array($aNotification)) 
+            return 404;
+
+        $sType = $aNotification['notification_type'];
+        if(!in_array($sType, array('INITIAL_BUY_CUSTOM', 'DID_RENEW', 'REFUND', 'CANCEL')))
+            return 200;
+
+        $this->log($aNotification, 'Webhooks: ' . (!empty($sType) ? $sType : ''), BX_LOG_INFO);
+
+        $sMethod = '_processNotification' . bx_gen_method_name(strtolower($sType), array('.', '_', '-'));
+    	if(!method_exists($this, $sMethod))
+            return 200;
+
+    	return $this->$sMethod($aNotification) ? 200 : 403;
+    }
+
+    protected function _processNotificationInitialBuyCustom($aNotification)
+    {
+        if(!$this->_verifyNotification(array('rt' => $aNotification['original_data']['transactionReceipt'], 'pt' => $aNotification['product'], 'tx' => $aNotification['transaction'], 'txo' => $aNotification['original_transaction'])))
+            return false;
+
+        $sOrder = $aNotification['transaction'];
+        if(!empty($aNotification['original_transaction']))
+            $sOrder = $aNotification['original_transaction'];
+        $sOrder = bx_process_input($sOrder);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $sOrder));
+        if(!empty($aPending) && is_array($aPending) && (int)$aPending['processed'] == 1)
+            return false;
+
+        $sModule = bx_process_input($aNotification['module']);
+        $aModule = $this->_oModule->_oDb->getModuleByName($sModule);
+        if(empty($aModule) || !is_array($aModule))
+            return false;
+
+        $iClient = (int)$aNotification['profile_id'];
+
+        $aInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_RECURRING, $iClient, $this->_iVendor, array(
+            array($this->_iVendor, $aModule['id'], bx_process_input($aNotification['product']), (int)$aNotification['count'])
+        ));
+
+        if(empty($aInfo) || $aInfo['vendor_id'] == BX_PAYMENT_EMPTY_ID || empty($aInfo['items']))
+            return false;
+
+        $iPendingId = $this->_oModule->_oDb->insertOrderPending($iClient, BX_PAYMENT_TYPE_RECURRING, $this->_sName, $aInfo);
+        if(empty($iPendingId))
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+
+        $aSubscription = array(
+            'customer_id' => '', 
+            'subscription_id' => $sOrder,
+            'status' => BX_PAYMENT_SBS_STATUS_ACTIVE
+        );
+
+        if(!$this->_oModule->getObjectSubscriptions()->register($aPending, $aSubscription))
+            return false;
+
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrder,
+            'error_code' => 0,
+            'error_msg' => _t('_bx_payment_aina_msg_subscribed')
+        ));
+
+        return $this->_oModule->registerPayment($iPendingId);
+    }
+
+    protected function _processNotificationDidRenew(&$aNotification)
+    {
+        $aRenew = array_shift($aNotification['unified_receipt']['pending_renewal_info']);
+
+        if(!$this->_verifyNotification(array('rt' => $aNotification['unified_receipt']['latest_receipt'], 'pt' => $aRenew['product_id'], 'txo' => $aRenew['original_transaction_id'])))
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $aRenew['original_transaction_id']));
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+  
+        if($aPending['type'] == BX_PAYMENT_TYPE_RECURRING)
+            $this->_oModule->getObjectSubscriptions()->prolong($aPending);
+
+        return $this->_oModule->registerPayment($aPending);
+    }
+
+    protected function _processNotificationRefund(&$aNotification)
+    {
+        //TODO: We need to get 'PendingId' to process refund.
+    }
+
+    protected function _processNotificationCancel(&$aNotification)
+    {
+        //TODO: We need to get 'PendingId' to cancel the subscription.
+    }
+
+    protected function _verifyNotification($aParams)
+    {
+        $aRequest = array(
+            'receipt-data' => $aParams['rt'],
+            'password' => $this->_sSecret
+        );
+
+        $sInput = bx_file_get_contents($this->_sVerifyReceipt, $aRequest, 'post-json');
+        $aInput = json_decode($sInput, true);
+
+        if(isset($aInput['status']) && (int)$aInput['status'] == 21007) {
+            $sInput = bx_file_get_contents($this->_sVerifyReceiptSandbox, $aRequest, 'post-json');
+            $aInput = json_decode($sInput, true);
+        }
+
+        if(!empty($aInput['latest_receipt_info']) && is_array($aInput['latest_receipt_info']))
+            foreach($aInput['latest_receipt_info'] as $aRecipt)
+                if($aRecipt['product_id'] == $aParams['pt'] && ((isset($aParams['txo']) && $aRecipt['original_transaction_id'] == $aParams['txo']) || (isset($aParams['tx']) && $aRecipt['transaction_id'] == $aParams['tx'])))
+                    return true;
+
+        return false;
+    }
+}
+
+/** @} */

+ 557 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderChargebee.php

@@ -0,0 +1,557 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('CBEE_MODE_LIVE', 1);
+define('CBEE_MODE_TEST', 2);
+
+use ChargeBee\ChargeBee\Environment;
+use ChargeBee\ChargeBee\Models\Addon;
+use ChargeBee\ChargeBee\Models\Customer;
+use ChargeBee\ChargeBee\Models\HostedPage;
+use ChargeBee\ChargeBee\Models\Subscription;
+use ChargeBee\ChargeBee\Models\Invoice;
+
+class BxPaymentProviderChargebee extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    protected $_iMode;
+    protected $_bCheckAmount;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);   
+
+        $this->_aSbsStatuses = array(
+            'future' => BX_PAYMENT_SBS_STATUS_SCHEDULED, 
+            'in_trial' => BX_PAYMENT_SBS_STATUS_TRIAL, 
+            'active' => BX_PAYMENT_SBS_STATUS_ACTIVE, 
+            'non_renewing' => BX_PAYMENT_SBS_STATUS_ACTIVE, 
+            'paused' => BX_PAYMENT_SBS_STATUS_PAUSED,
+            'canceled' => BX_PAYMENT_SBS_STATUS_CANCELED,
+        );
+    }
+
+    public function initOptions($aOptions)
+    {
+    	parent::initOptions($aOptions);
+
+    	$this->_iMode = (int)$this->getOption('mode');
+        $this->_bCheckAmount = $this->getOption('check_amount') == 'on';
+        $this->_bUseSsl = $this->getOption('ssl') == 'on';
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo)
+    {
+    	$aItem = array_shift($aCartInfo['items']);
+    	if(empty($aItem) || !is_array($aItem))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $oPage = $this->createHostedPageRecurring($aItem, $aClient, $aVendor, $iPendingId);
+        if($oPage === false)
+            return $this->_sLangsPrefix . 'err_cannot_perform';
+
+        return array(
+            'code' => 0,
+            'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+            'redirect' => $oPage->url
+        );
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $sPageId = bx_process_input($aData['id']);
+        $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+
+        if(empty($sPageId) || empty($iPendingId))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $oPage = $this->retreiveHostedPage($sPageId);
+        if($oPage === false)
+                return $this->_sLangsPrefix . 'err_cannot_perform';
+
+        $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 . 'err_already_processed');
+
+        $oCustomer = $oPage->content()->customer();
+        $oSubscription = $oPage->content()->subscription();
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => $this->_sLangsPrefix . 'cbee_msg_subscribed',
+            'pending_id' => $iPendingId,
+            'customer_id' => $oCustomer->id,
+            'subscription_id' => $oSubscription->id,
+            'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $oCustomer->firstName, $oCustomer->lastName),
+            'client_email' => $oCustomer->email,
+            'paid' => false,
+            'trial' => $oSubscription->status == 'in_trial',
+        );
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $oSubscription->id,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function notify()
+    {
+        $iResult = $this->_processEvent();
+        http_response_code($iResult);
+    }
+
+    public function cancelRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        return $this->deleteSubscription($sSubscriptionId);
+    }
+
+    public function createHostedPageSingle($aItem, $aClient, $aVendor = array(), $iPendingId = 0)
+    {
+        $oPage = false;
+
+        try {
+            $aPage = [
+                'embed' => false, //--- Note. 'embed' should be disabled to allow payments via PayPal
+                'charges' => [
+                    [
+                        'amount' => $aItem['amount'], 
+                        'description' => $aItem['description'],
+                    ]
+                ],
+                'customer' => [
+                    'email' => $aClient['email'],
+                    'firstName' => $aClient['name']
+                ],
+            ];
+
+            if(!empty($aItem['addons']) && is_array($aItem['addons']))
+                $aPage['addons'] = $aItem['addons'];
+
+            if(!empty($aVendor) && is_array($aVendor) && !empty($aVendor))
+                $aPage['redirectUrl'] = bx_append_url_params($this->getReturnDataUrl($aVendor['id']), array(
+                    'pending_id' => $iPendingId
+                ));
+
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = HostedPage::checkoutOneTime($aPage);
+
+            $oPage = $oResult->hostedPage();
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Create Hosted Page Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $oPage;
+    }
+
+    public function createHostedPageRecurring($aItem, $aClient, $aVendor = array(), $iPendingId = 0)
+    {
+        $oPage = false;
+
+        try {
+            $aPage = [
+                'embed' => false, //--- Note. 'embed' should be disabled to allow payments via PayPal
+                'subscription' => [
+                    'planId' => $aItem['name']
+                ],
+                'customer' => [
+                    'email' => $aClient['email'],
+                    'firstName' => $aClient['name']
+                ], 
+            ];
+
+            if(!empty($aItem['addons']) && is_array($aItem['addons']))
+                $aPage['addons'] = $aItem['addons'];
+
+            if(!empty($aVendor) && is_array($aVendor) && !empty($aVendor))
+                $aPage['redirectUrl'] = bx_append_url_params($this->getReturnDataUrl($aVendor['id']), array(
+                    'pending_id' => $iPendingId
+                ));
+
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = HostedPage::checkoutNew($aPage);
+
+            $oPage = $oResult->hostedPage();
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Create Hosted Page Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $oPage;
+    }
+
+    public function retreiveHostedPage($sPageId)
+    {
+        $oPage = null;
+
+        try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = HostedPage::retrieve($sPageId);
+
+            $oPage = $oResult->hostedPage();
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Retrieve Hosted Page Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $oPage;
+    }
+
+    public function retrieveSubscription($sSubscriptionId)
+    {
+        $oSubscription = null;
+
+        try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = Subscription::retrieve($sSubscriptionId);
+
+            $oSubscription = $oResult->subscription();
+            if($oSubscription->id != $sSubscriptionId)
+                return false;
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Retrieve Subscription Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $oSubscription;
+    }
+
+    public function getSubscription($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = $this->retrieveSubscription($sSubscriptionId);
+        if($oSubscription === false)
+            return array();
+
+        $sStatus = $oSubscription->status;
+        $sStatus = isset($this->_aSbsStatuses[$sStatus]) ? $this->_aSbsStatuses[$sStatus] : BX_PAYMENT_SBS_STATUS_UNKNOWN;
+
+        return array(
+            'status' => $sStatus,
+            'created' => $oSubscription->createdAt,
+            'started' => $oSubscription->startedAt,
+            'trial_start' => $oSubscription->trialStart,
+            'trial_end' => $oSubscription->trialEnd,
+            'cperiod_start' => $oSubscription->currentTermStart,
+            'cperiod_end' => $oSubscription->currentTermEnd,
+        );
+    }
+    
+    public function deleteSubscription($sSubscriptionId)
+    {
+        try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = Subscription::cancel($sSubscriptionId);
+
+            $oSubscription = $oResult->subscription();
+            if($oSubscription->status != 'cancelled')
+                return false;
+        }
+        catch (Exception $oException) {
+            $aError = $oException->getJsonBody();
+
+            $this->log('Delete Subscription Error: ' . $aError['error']['message'], '', BX_LOG_ERR);
+            $this->log($aError, '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        $this->onDeleteSubscription($sSubscriptionId, $oSubscription->getValues());
+
+        return true;
+    }
+
+    public function retrieveInvoice($sInvoiceId)
+    {
+        $oInvoice = null;
+
+        try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = Invoice::retrieve($sInvoiceId);
+
+            $oInvoice = $oResult->invoice();
+            if($oInvoice->id != $sInvoiceId)
+                return false;
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Retrieve Invoice Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $oInvoice;
+    }
+
+    public function retrieveAddons($sStatus = 'active', $iLimit = 0)
+    {
+        $aAddons = array();
+
+        try {
+            $aParams = array();
+            if(!empty($sStatus))
+                $aParams['status[is]'] = $sStatus;
+            if(!empty($iLimit))
+                $aParams['limit'] = $iLimit;
+            
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResults = Addon::all($aParams);
+
+            foreach($oResults as $oResult)
+                $aAddons[] = $oResult->addon();
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Retrieve Addons Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $aAddons;
+    }
+
+    public function getAddons($sStatus = 'active', $iLimit = 0)
+    {
+        $aAddons = $this->retrieveAddons($sStatus, $iLimit);
+        if(empty($aAddons) || !is_array($aAddons))
+            return array();
+
+        $aResult = array();
+        foreach($aAddons as $oAddon)
+            $aResult[] = $oAddon->getValues();
+
+        return $aResult;
+    }
+
+    public function retrieveAddon($sId)
+    {
+        $oAddon = null;
+
+        try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = Addon::retrieve($sId);
+
+            $oAddon = $oResult->addon();
+            if($oAddon->id != $sId)
+                return false;
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Retrieve Addon Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $oAddon;
+    }
+
+    public function getAddon($sId)
+    {
+        $oAddon = $this->retrieveAddon($sId);
+        if($oAddon === false)
+            return array();
+
+        return $oAddon->getValues();
+    }
+
+    public function retrieveCustomer($sCustomerId)
+    {
+        $oCustomer = null;
+
+        try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = Customer::retrieve($sCustomerId);
+
+            $oCustomer = $oResult->customer();
+            if($oCustomer->id != $sCustomerId)
+                    return false;
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Retrieve Customer Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $oCustomer;
+    }
+
+    public function onDeleteSubscription($sSubscriptionId, $aSubscription)
+    {
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-chargebee_cancel_subscription 'bx_payment', 'chargebee_cancel_subscription' - hook after a subscription was canceled
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `chargebee_cancel_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `subscription_id` - [string] unique subscription id
+         *      - `subscription_info` - [array] subscription info
+         * @hook @ref hook-bx_payment-chargebee_cancel_subscription
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-chargebee_v3_cancel_subscription 'bx_payment', 'chargebee_v3_cancel_subscription' - hook after a subscription was canceled
+         * It's equivalent to @ref hook-bx_payment-chargebee_cancel_subscription
+         * @hook @ref hook-bx_payment-chargebee_v3_cancel_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_cancel_subscription', 0, false, [
+            'subscription_id' => $sSubscriptionId,
+            'subscription_info' => $aSubscription
+        ]);
+    }
+
+
+    protected function _getSite()
+    {
+        return $this->_iMode == CBEE_MODE_LIVE ? $this->getOption('live_site') : $this->getOption('test_site');
+    }
+
+    protected function _getApiKey()
+    {
+        return $this->_iMode == CBEE_MODE_LIVE ? $this->getOption('live_api_key') : $this->getOption('test_api_key');
+    }
+
+    protected function _processEvent()
+    {
+        $sInput = @file_get_contents("php://input");
+        $aEvent = json_decode($sInput, true);
+        if(empty($aEvent) || !is_array($aEvent)) 
+            return 404;
+
+        $sType = $aEvent['event_type'];
+        if(!in_array($sType, array('payment_succeeded', ' payment_refunded', 'subscription_cancelled')))
+            return 200;
+
+        $this->log('Webhooks: ' . (!empty($sType) ? $sType : ''), '', BX_LOG_INFO);
+        $this->log($aEvent, '', BX_LOG_INFO);
+
+        $sMethod = '_processEvent' . bx_gen_method_name($sType, array('.', '_', '-'));
+        if(!method_exists($this, $sMethod))
+            return 200;
+
+        return $this->$sMethod($aEvent) ? 200 : 403;
+    }
+
+    protected function _processEventPaymentSucceeded(&$aEvent)
+    {
+        $mixedResult = $this->_getDataTransaction($aEvent, 'success');
+        if($mixedResult === false)
+            return false;
+
+        list($aPending, $aTransaction) = $mixedResult;
+
+        $fTransactionAmount = (float)$aTransaction['amount'] / 100;
+        $sTransactionCurrency = strtoupper($aTransaction['currency_code']);
+        if($this->_bCheckAmount && ((float)$aPending['amount'] != $fTransactionAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sTransactionCurrency) !== 0))
+            return false;
+
+        if($aPending['type'] == BX_PAYMENT_TYPE_RECURRING)
+            $this->_oModule->getObjectSubscriptions()->prolong($aPending);
+
+        return $this->_oModule->registerPayment($aPending);
+    }
+
+    protected function _processEventPaymentRefunded(&$aEvent)
+    {
+        $mixedResult = $this->_getDataTransaction($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending) = $mixedResult;
+        return $this->_oModule->refundPayment($aPending);
+    }
+
+    protected function _processEventSubscriptionCancelled(&$aEvent)
+    {
+        $mixedResult = $this->_getDataSubscription($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending, $aSubscription) = $mixedResult;
+        $this->onDeleteSubscription($aSubscription['id'], $aSubscription);
+
+        return $this->_oModule->getObjectSubscriptions()->cancelLocal($aPending);
+    }
+
+    protected function _getDataTransaction(&$aEvent, $sWithStatusCheck = '')
+    {
+        $aTransaction = $aEvent['content']['transaction'];
+        if(empty($aTransaction) || (!empty($sWithStatusCheck) && $aTransaction['status'] != $sWithStatusCheck))
+            return false;
+
+        $sOrder = '';
+        if(isset($aTransaction['subscription_id']))
+            $sOrder = $aTransaction['subscription_id'];
+        else if(isset($aTransaction['id']))
+            $sOrder = $aTransaction['id'];
+
+        if(empty($sOrder))
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrder]);
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        return array($aPending, $aTransaction);
+    }
+
+    protected function _getDataSubscription(&$aEvent, $sWithStatusCheck = '')
+    {
+        $aSubscription = $aEvent['content']['subscription'];
+        if(empty($aSubscription) || (!empty($sWithStatusCheck) && $aSubscription['status'] != $sWithStatusCheck))
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $aSubscription['id']));
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        return array($aPending, $aSubscription);
+    }
+}
+
+/** @} */

+ 437 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderChargebeeV3.php

@@ -0,0 +1,437 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxPaymentProviderChargebee.php');
+
+use ChargeBee\ChargeBee\Environment;
+use ChargeBee\ChargeBee\Models\PortalSession;
+
+class BxPaymentProviderChargebeeV3 extends BxPaymentProviderChargebee
+{
+    function __construct($aConfig)
+    {
+        $this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'https://js.chargebee.com/v2/chargebee.js',
+            'main.js',
+            'chargebee_v3.js'
+        );
+
+        $this->_aIncludeCss = array(
+            'chargebee_v3.css'
+        );
+    }
+
+    public function actionGetHostedPageSingle($iClientId, $iVendorId)
+    {
+        $this->initOptionsByVendor($iVendorId);
+
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId);
+
+        $aItem = [
+            'amount' => 100 * $aCartInfo['items_price'], 
+            'description' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name'])
+        ];
+
+        $mixedItemAddons = bx_process_input(bx_get('addons'));
+        if(!empty($mixedItemAddons)) {
+            $aItemAddons = is_array($mixedItemAddons) ? $mixedItemAddons : $this->_oModule->_oConfig->s2a($mixedItemAddons);
+
+            foreach($aItemAddons as $sItemAddon)
+                if(!isset($aItem['addons'][$sItemAddon]))
+                    $aItem['addons'][$sItemAddon] = array(
+                        'id' => $sItemAddon,
+                        'quantity' => 1
+                    );
+                else 
+                    $aItem['addons'][$sItemAddon]['quantity'] += 1;
+
+            $aItem['addons'] = array_values($aItem['addons']);
+        }
+
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oPage = $this->createHostedPageSingle($aItem, $aClient);
+        if($oPage === false)
+            return echoJson(array());
+
+        header('Content-type: text/html; charset=utf-8');
+        echo $oPage->toJson();
+    }
+
+    public function actionGetHostedPageRecurring($iClientId, $iVendorId, $sItemName)
+    {
+        $this->initOptionsByVendor($iVendorId);
+
+        $aItem = array('name' => $sItemName);
+
+        $mixedItemAddons = bx_process_input(bx_get('addons'));
+        if(!empty($mixedItemAddons)) {
+            $aItemAddons = is_array($mixedItemAddons) ? $mixedItemAddons : $this->_oModule->_oConfig->s2a($mixedItemAddons);
+
+            foreach($aItemAddons as $sItemAddon)
+                if(!isset($aItem['addons'][$sItemAddon]))
+                    $aItem['addons'][$sItemAddon] = array(
+                        'id' => $sItemAddon,
+                        'quantity' => 1
+                    );
+                else 
+                    $aItem['addons'][$sItemAddon]['quantity'] += 1;
+
+            $aItem['addons'] = array_values($aItem['addons']);
+        }
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oPage = $this->createHostedPageRecurring($aItem, $aClient);
+        if($oPage === false)
+            return echoJson(array());
+
+        header('Content-type: text/html; charset=utf-8');
+        echo $oPage->toJson();
+    }
+
+    public function actionGetPortal($iPendingId)
+    {
+    	if(!isLogged())
+            return echoJson(array());
+
+    	$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+    	if(empty($aPending) || !is_array($aPending))
+            return echoJson(array());
+
+    	$this->initOptionsByVendor((int)$aPending['seller_id']);
+
+    	$aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $iPendingId));
+    	if(empty($aSubscription) || !is_array($aSubscription))
+            return echoJson(array());
+
+    	$oPortal = $this->getPortal($aSubscription['customer_id'], $aSubscription['subscription_id']);
+    	if($oPortal === false)
+            return echoJson(array());
+
+    	header('Content-type: text/html; charset=utf-8');
+    	echo $oPortal->toJson();
+    }
+
+    public function addJsCss()
+    {
+    	if(!$this->isActive())
+            return;
+
+        $this->_oModule->_oTemplate->addJs($this->_aIncludeJs);
+        $this->_oModule->_oTemplate->addCss($this->_aIncludeCss);
+    }
+
+    public function getJsObject($aParams = array())
+    {
+        $sJsObject = $this->_oModule->_oConfig->getJsObject($this->_sName);
+        if(isset($aParams['iModuleId'], $aParams['iSellerId'], $aParams['iItemId']))
+            $sJsObject .= '_' . md5($aParams['iModuleId'] . '-' . $aParams['iSellerId'] . '-' . $aParams['iItemId']);
+        
+        return $sJsObject;
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sPageId = bx_process_input(bx_get('page_id'));
+        if(empty($sPageId) || empty($iPendingId))
+            return $this->_sLangsPrefix . 'err_wrong_data';
+
+    	$aItem = array_shift($aCartInfo['items']);
+    	if(empty($aItem) || !is_array($aItem))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $oPage = $this->retreiveHostedPage($sPageId);
+        if($oPage === false)
+            return $this->_sLangsPrefix . 'err_cannot_perform';
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        $aResult = [];
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oInvoice = $oPage->content()->invoice();
+
+                $aResult = [
+                    'code' => 0,
+                    'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onCartCheckout(oData);',
+                    'link' => $this->getReturnDataUrl($aVendor['id'], [
+                        'order_id' => $oInvoice->id,
+                        'customer_id' => $oInvoice->customerId,
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ])
+                ];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aResult = [
+                    'code' => 0,
+                    'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+                    'redirect' => $this->getReturnDataUrl($aVendor['id'], [
+                        'order_id' => $oPage->content()->subscription()->id,
+                        'customer_id' => $oPage->content()->customer()->id,
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ])
+                ];
+                break;
+        }
+
+        return $aResult;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $sOrderId = bx_process_input($aData['order_id']);
+    	$sCustomerId = bx_process_input($aData['customer_id']);
+        $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+        if(empty($iPendingId))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $sRedirect = bx_process_input($aData['redirect']);
+
+        $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 . 'err_already_processed');
+
+        $oCustomer = $this->retrieveCustomer($sCustomerId);
+        if($oCustomer === false)
+            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+        $sOrder = '';
+        $aResult = [
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $oCustomer->firstName, $oCustomer->lastName),
+            'client_email' => $oCustomer->email,
+            'paid' => false,
+            'redirect' => $sRedirect
+        ];
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oInvoice = $this->retrieveInvoice($sOrderId);
+                if($oInvoice === false || empty($oInvoice->linkedPayments))
+                    return ['code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $sOrder = $oInvoice->linkedPayments[0]->txnId;
+                $aResult = array_merge($aResult, [
+                    'message' => $this->_sLangsPrefix . 'cbee_msg_charged',
+                    'paid' => $oInvoice->status == 'paid',
+                ]);
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $oSubscription = $this->retrieveSubscription($sOrderId);
+                if($oSubscription === false)
+                    return ['code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $sOrder = $oSubscription->id;
+                $aResult = array_merge($aResult, [
+                    'message' => $this->_sLangsPrefix . 'cbee_msg_subscribed',
+                    'customer_id' => $oCustomer->id,
+                    'subscription_id' => $oSubscription->id,
+                    'trial' => $oSubscription->status == 'in_trial',
+                ]);
+
+                break;
+        }
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, [
+            'order' => $sOrder,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ]);
+
+        return $aResult;
+    }
+
+    public function getPortal($sCustomerId, $sSubscriptionId)
+    {
+    	$oPortal = false;
+
+    	try {
+            Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = PortalSession::create(array(
+                'customer' => array(
+                    'id' => $sCustomerId
+                )
+            ));
+
+            $oPortal = $oResult->portalSession();
+    	}
+    	catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Get Portal Error: ' . $sError . '(' . $iError . ')', '', BX_LOG_ERR);
+
+            return false;
+    	}
+
+    	return $oPortal;
+    }
+
+    public function getJsCode($aParams = array())
+    {
+    	$sSite = '';
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-chargebee_v3_get_js_code 'bx_payment', 'chargebee_v3_get_js_code' - hook to override JavaScript code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `chargebee_v3_get_js_code`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `site` - [string] by ref, site name from ChargeBee account, can be overridden in hook processing
+         *      - `params` - [array] by ref, params array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-chargebee_v3_get_js_code
+         */
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_js_code', 0, 0, [
+            'site' => &$sSite,
+            'params' => &$aParams
+    	]);
+
+    	return $this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+            'sProvider' => $this->_sName,
+            'sSite' => !empty($sSite) ? $sSite : $this->_getSite()
+    	), $aParams));
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = [])
+    {
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+        $aItems = [];
+        $aCartItems = $oCart->getCartItems($iClientId, $iVendorId);
+        foreach($aCartItems as $aCartItem)
+            $aItems[] = $this->_oModule->_oConfig->descriptorA2S($aCartItem);
+
+    	return $this->_getButton(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, [
+            'iSellerId' => $iVendorId,
+            'aItems' => $aItems
+    	]));
+    }
+
+    public function getButtonSingleJs($iClientId, $iVendorId, $aParams = [])
+    {
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+        $aItems = [];
+        $aCartItems = $oCart->getCartItems($iClientId, $iVendorId);
+        foreach($aCartItems as $aCartItem)
+            $aItems[] = $this->_oModule->_oConfig->descriptorA2S($aCartItem);
+
+    	return $this->_getButtonJs(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, [
+            'iSellerId' => $iVendorId,
+            'aItems' => $aItems
+    	]));
+    }
+
+    public function getButtonRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        return $this->_getButton(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, $aParams);
+    }
+
+    public function getButtonRecurringJs($iClientId, $iVendorId, $aParams = array())
+    {
+        return $this->_getButtonJs(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, $aParams);
+    }
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);        
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('cbee_v3_button_' . $sType . '.html', array(
+            'type' => $sType,
+            'link' => 'javascript:void(0)',
+            'caption' => _t($this->_sLangsPrefix . 'cbee_txt_checkout_with_' . $sType, $this->_sCaption),
+            'onclick' => $sJsMethod,
+            'js_object' => $this->_oModule->_oConfig->getJsObject($this->_sName),
+            'js_code' => $sJsCode
+        ));
+    }
+    
+    protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        $sSite = '';
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-chargebee_v3_get_button 'bx_payment', 'chargebee_v3_get_button' - hook to override checkout/subscibe button
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `chargebee_v3_get_button`
+         * - $object_id - not used
+         * - $sender_id - client (buyer) profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] by ref, payment type ('single' or 'recurring'), can be overridden in hook processing
+         *      - `site` - [string] by ref, site name from ChargeBee account, can be overridden in hook processing
+         *      - `params` - [array] by ref, params array as key&value pairs, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-chargebee_v3_get_button
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, [
+            'type' => &$sType, 
+            'site' => &$sSite,
+            'params' => &$aParams
+        ]);
+
+        $sJsMethod = '';
+        $sJsObject = $this->getJsObject($aParams);
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sJsMethod = $sJsObject . '.checkout(this)';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sJsMethod = $sJsObject . '.subscribe(this)';
+                break;
+        }
+
+        return array($this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+            'js_object' => $sJsObject,
+            'sProvider' => $this->_sName,
+            'sSite' => !empty($sSite) ? $sSite : $this->_getSite(),
+            'iClientId' => $iClientId
+        ), $aParams)), $sJsMethod);
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        if(empty($aParams['id']))
+            return array();
+
+        $sPrefix = 'bx-payment-strp-';
+        $sJsObject = $this->_oModule->_oConfig->getJsObject($this->_sName);
+
+        return array(
+            array('id' => $sPrefix . 'manager', 'name' => $sPrefix . 'manager', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:return " . $sJsObject . ".manage(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_cbee_menu_item_title_manager'))
+        );
+    }
+}
+
+/** @} */

+ 281 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderCredits.php

@@ -0,0 +1,281 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Credits payment provider can be used when 
+ * Credits module is installed and active.
+ */
+
+class BxPaymentProviderCredits extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    protected $_sModuleCredits;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_sModuleCredits = $this->_oModule->_oConfig->CNF['MODULE_CREDITS'];
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        if(!BxDolModuleQuery::getInstance()->isEnabledByName($this->_sModuleCredits))
+            return $this->_sLangsPrefix . 'cdt_err_not_available';
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        $iSellerId = (int)$aCartInfo['vendor_id'];
+        $sCustomData = $this->_constructCustomData($aCartInfo['vendor_id'], $iPendingId);
+        $sReturnDataUrl = $this->getReturnDataUrl($iSellerId);
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aFormData = array(
+                    'currency_code' => $aCartInfo['vendor_currency_code'],
+                    'currency_sign' => $aCartInfo['vendor_currency_sign'],
+                    'seller' => $iSellerId,
+                    'amount' => (float)$aCartInfo['items_price'],
+                    'items_count' => count($aCartInfo['items']),
+                    'custom' => $sCustomData,
+                    'return_data_url' => $sReturnDataUrl,
+                );
+
+                $iIndex = 0;
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aFormData['item_title_' . $iIndex] = bx_process_output($aItem['title']);
+                    $aFormData['item_quantity_' . $iIndex] = $aItem['quantity'];
+
+                    $iIndex += 1;
+                }
+
+                $sCheckoutUrl = bx_srv($this->_sModuleCredits, 'get_checkout_url');
+                $this->_oModule->_oTemplate->displayPageCodeRedirect($sCheckoutUrl, $aFormData);
+                exit;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aItem = array_shift($aCartInfo['items']);
+
+                return array(
+                    'code' => 0,
+                    'popup' => array(
+                        'html' => bx_srv($this->_sModuleCredits, 'get_popup_subscribe', array(array(
+                            'currency_code' => $aCartInfo['vendor_currency_code'],
+                            'currency_sign' => $aCartInfo['vendor_currency_sign'],
+                            'seller' => $iSellerId,
+                            'title' => bx_process_output($aItem['title']),
+                            'amount' => $aItem['price_recurring'],
+                            'period' => $aItem['period_recurring'],
+                            'period_unit' => $aItem['period_unit_recurring'],
+                            'trial' => isset($aItem['trial_recurring']) ? $aItem['trial_recurring'] : 0,
+                            'custom' => $sCustomData,
+                            'return_data_url' => $sReturnDataUrl,
+                        ))),
+                        'options' => array(
+                            'closeOnOuterClick' => true,
+                            'removeOnClose' => true
+                        )
+                    )
+                );
+        }
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $aResult = $this->_finalizeCheckout($aData);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) {
+            $this->log('Finalize Checkout: Failed', '', BX_LOG_ERR);
+            $this->log($aData, '', BX_LOG_ERR);
+            $this->log($aResult, '', BX_LOG_ERR);
+        }
+
+        if(!empty($aResult['pending_id']))
+            $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], array(
+                'order' => $aResult['order'],
+                'error_code' => $aResult['code'],
+                'error_msg' => _t($aResult['message'])
+            ));
+
+        return $aResult;
+    }
+
+    public function makePayment($mixedPending)
+    {
+        if(!BxDolModuleQuery::getInstance()->isEnabledByName($this->_sModuleCredits))
+            return ['code' => 1, 'message' => $this->_sLangsPrefix . 'cdt_err_not_available'];
+
+        if(!is_array($mixedPending))
+            $mixedPending = $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+
+        if(empty($mixedPending) || !is_array($mixedPending))
+            return ['code' => 2, 'message' => $this->_sLangsPrefix . 'err_not_found_pending'];
+
+        $iClient = (int)$mixedPending['client_id'];
+        $oClient = BxDolProfile::getInstance($iClient);
+
+        $iSeller = (int)$mixedPending['seller_id'];
+        $oSeller = BxDolProfile::getInstance($iSeller);
+
+        if(!$oClient || !$oSeller)
+            return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_wrong_data'];
+
+        $fAmountM = $this->_getAmountByPending($mixedPending);
+        $fAmountC = bx_srv($this->_sModuleCredits, 'convert_money_to_credits', [$fAmountM]);
+
+        $fClientBalance = bx_srv($this->_sModuleCredits, 'get_profile_balance', [$iClient]);
+        if($fAmountC > $fClientBalance) {
+            $aSubscription = $this->_oModule->_oDb->getSubscription([
+                'type' => 'pending_id', 
+                'pending_id' => $mixedPending['id']
+            ]);
+
+            if(!empty($aSubscription) && is_array($aSubscription)) {
+                $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($this->_oModule->_oConfig->getPrefix('general') . 'wrong_balance', [
+                    'profile_name' => $oClient->getDisplayName(),
+                    'profile_link' => $oClient->getUrl(),
+                    'subscription_id' => $aSubscription['subscription_id'],
+                    'subscription_customer' => $aSubscription['customer_id'],
+                    'subscription_provider' => _t('_bx_payment_txt_name_' . $mixedPending['provider']),
+                    'subscription_date' => bx_time_js($aSubscription['date_add'], BX_FORMAT_DATE, true)
+                ], 0, $iClient);
+
+                if($aTemplate !== false)
+                    sendMail($oClient->getAccountObject()->getEmail(), $aTemplate['Subject'], $aTemplate['Body'], 0, [], BX_EMAIL_SYSTEM);
+            }
+
+            return ['code' => 4, 'message' => $this->_sLangsPrefix . 'cdt_err_wrong_balance'];
+        }
+
+        if(!bx_srv($this->_sModuleCredits, 'make_payment', [$iClient, $fAmountC, $iSeller, $mixedPending['order']]))
+            return ['code' => 5, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+        return true;        
+    }
+
+    public function cancelRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-credits_cancel_subscription 'bx_payment', 'credits_cancel_subscription' - hook after a subscription was canceled
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `credits_cancel_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `pending_id` - [string] pending transaction id
+         *      - `subscription_id` - [string] unique subscription id
+         * @hook @ref hook-bx_payment-credits_cancel_subscription
+         */
+        bx_alert($this->MODULE, $this->_sName . '_cancel_subscription', 0, false, [
+            'pending_id' => $iPendingId,
+            'subscription_id' => $sSubscriptionId,
+        ]);
+
+        return true;
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        return array();
+    }
+
+    protected function _finalizeCheckout(&$aData)
+    {
+        list($iSellerId, $iPendingId) = $this->_deconstructCustomData($aData['c']);
+
+        if(empty($this->_aOptions) && !empty($iPendingId))
+            $this->_aOptions = $this->getOptionsByPending((int)$iPendingId);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(empty($aPending) || !is_array($aPending))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_found_pending');
+
+        if(empty($this->_aOptions) || !BxDolModuleQuery::getInstance()->isEnabledByName($this->_sModuleCredits))
+            return array('code' => 2, 'message' => $this->_sLangsPrefix . 'err_incorrect_provider', 'pending_id' => $iPendingId);
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+                    return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+                $sOrder = $aData['o'];
+                $fAmount = $this->_getAmountByPending($aPending);
+                if(!bx_srv($this->_sModuleCredits, 'validate_checkout', array((int)$aPending['seller_id'], (int)$aPending['client_id'], $fAmount, $sOrder)))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'cdt_err_wrong_transaction', 'pending_id' => $iPendingId);
+
+                $aResult = array(
+                    'message' => $this->_sLangsPrefix . 'cdt_msg_charged',
+                    'order' => $sOrder,
+                    'paid' => true
+                );
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sSubscriptionId = bx_process_input($aData['sb']);
+
+                $aResult = array(
+                    'message' => $this->_sLangsPrefix . 'cdt_msg_subscribed',
+                    'customer_id' => bx_process_input($aData['cs']),
+                    'subscription_id' => $sSubscriptionId,
+                    'trial' => (bool)$aData['tr'],
+                    'order' => $sSubscriptionId,
+                );
+                break;
+        }
+
+        $oClient = BxDolProfile::getInstance($aPending['client_id']);
+        return array_merge(array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS, 
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'client_name' => $oClient->getDisplayName(),
+            'client_email' => $oClient->getAccountObject()->getEmail(),
+            'order' => ''
+        ), $aResult);
+    }
+
+    protected function _constructCustomData()
+    {
+        $aParams = func_get_args();
+        return urlencode(base64_encode(implode('|', $aParams)));
+    }
+
+    protected function _deconstructCustomData($data)
+    {
+        return explode('|', base64_decode(urldecode($data)));
+    }
+
+    protected function _getAmountByPending($aPending)
+    {
+        $fCurrencyRate = false;
+        $sCurrencyDefault = $this->_oModule->_oConfig->getDefaultCurrencyCode();
+        if(!empty($aPending['data'])) {
+            $aPendingData = unserialize($aPending['data']);
+
+            if(!empty($aPendingData['cur_rate']))
+                $fCurrencyRate = (float)$aPendingData['cur_rate'];
+
+            if(!empty($aPendingData['cur_def']))
+                $sCurrencyDefault = $aPendingData['cur_def'];
+        }
+
+        $fAmount = (float)$aPending['amount'];
+        if(strcmp($aPending['currency'], $sCurrencyDefault) != 0)
+            $fAmount = $this->_oModule->serviceConvert($fAmount, $aPending['currency'], $sCurrencyDefault, $fCurrencyRate);
+
+        return $fAmount;
+    }
+}
+
+/** @} */

+ 313 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderPayPal.php

@@ -0,0 +1,313 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Usefull links related to the integration:
+ * 
+ * HTML Form Basics for PayPal Payments Standard
+ * https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/formbasics/
+ * 
+ * HTML Variables for PayPal Payments Standard
+ * https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/
+ * 
+ */
+
+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);
+
+class BxPaymentProviderPayPal extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $bRecurring = false, $iRecurringDays = 0)
+    {
+        $iMode = (int)$this->getOption('mode');
+        $sItemName = _t($this->_sLangsPrefix . 'txt_payment_to_for', $aCartInfo['vendor_name']);
+        $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
+            );
+
+            foreach($aCartInfo['items'] as $aItem)
+                $sItemName .= ' ' . $aItem['title'] . ',';
+		    $sItemName = trim($sItemName, ', ');
+        }
+        else {
+            $aFormData = array(
+                'cmd' => '_cart',
+                'upload' => '1',
+                'item_name' => $sItemName,
+                'amount' => sprintf( "%.2f", (float)$aCartInfo['items_price'])
+            );
+
+            foreach($aCartInfo['items'] as $iIndex => $aItem) {
+                $i = $iIndex + 1; 
+
+                $aFormData['item_name_' . $i] = bx_process_output($aItem['title']);
+			    $aFormData['quantity_' . $i] = $aItem['quantity'];
+			    $aFormData['amount_' . $i] = $this->_oModule->_oConfig->getPrice(BX_PAYMENT_TYPE_SINGLE, $aItem);
+            }
+        }
+
+        $aFormData = array_merge($aFormData, array(
+            'business' => $iMode == PP_MODE_LIVE ? $this->getOption('business') : $this->getOption('sandbox'),
+            'currency_code' => $aCartInfo['vendor_currency_code'],
+            'no_note' => '1',
+            'no_shipping' => '1',
+            'custom' => $this->_constructCustomData($aCartInfo['vendor_id'], $iPendingId),
+        	'item_name' => $sItemName,
+            'item_number' => $iPendingId,
+        ));
+
+        switch($this->getOption('prc_type')) {
+            case PP_PRC_TYPE_PDT:
+            case PP_PRC_TYPE_DIRECT:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->getReturnDataUrl($aCartInfo['vendor_id']),
+                    'rm' => '2'
+                ));
+                break;
+            case PP_PRC_TYPE_IPN:
+                $aFormData = array_merge($aFormData, array(
+                    'return' => $this->getReturnUrl(),
+                    'notify_url' => $this->getReturnDataUrl($aCartInfo['vendor_id']),
+                    'rm' => '1'
+                ));
+                break;
+        }
+
+        $this->log('Initialize Checkout:', '', BX_LOG_INFO);
+        $this->log($aFormData, '', BX_LOG_INFO);
+
+        $this->_oModule->_oTemplate->displayPageCodeRedirect($sActionURL, $aFormData);
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $aResult = $this->_registerCheckout($aData);
+        if(!isset($aResult['code']) || (int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) {
+            $this->log('Finalize Checkout: Failed', '', BX_LOG_ERR);
+            $this->log($aData, '', BX_LOG_ERR);
+            $this->log($aResult, '', BX_LOG_ERR);
+        }
+
+        return $aResult;
+    }
+
+    /**
+     *
+     * @param $aData - data from payment provider.
+     * @return array with results.
+     */
+    protected function _registerCheckout(&$aData)
+    {
+        if(empty($this->_aOptions) && !empty($aData['item_number']))
+            $this->_aOptions = $this->getOptionsByPending((int)$aData['item_number']);
+
+        if(empty($this->_aOptions))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $iPrcType = (int)$this->getOption('prc_type');
+        if((in_array($iPrcType, array(PP_PRC_TYPE_DIRECT, PP_PRC_TYPE_IPN)) && !isset($aData['txn_id'])) || ($iPrcType == PP_PRC_TYPE_PDT && !isset($aData['tx'])))
+            return array('code' => 2, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+
+        $aPending = array();
+        $aResult = $this->_validateCheckout($aData, $aPending);
+
+        if(empty($aPending) || !is_array($aPending))
+            return $aResult;
+
+        if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+            return array('code' => 11, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aPending['id'], array(
+            'order' => $aData['txn_id'],
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        $aResult['pending_id'] = $aPending['id'];
+        $aResult['client_name'] = _t($this->_sLangsPrefix . 'txt_buyer_name_mask', bx_process_input($aData['first_name']), bx_process_input($aData['last_name'])); 
+		$aResult['client_email'] = bx_process_input($aData['payer_email']);
+		$aResult['paid'] = true;
+        return $aResult;
+    }
+
+    protected function _validateCheckout(&$aData, &$aPending)
+    {
+        $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' => 3, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+
+            $sRequest = 'cmd=_notify-validate';
+            foreach($aData as $sKey => $sValue) {
+                if(in_array($sKey, array('cmd', 'r')))
+                    continue;
+
+                $sRequest .= '&' . urlencode($sKey) . '=' . urlencode(bx_process_pass($sValue));
+            }
+
+            $aResponse = $this->_readValidationData($sConnectionUrl, $sRequest);
+            if((int)$aResponse['code'] !== 0)
+               return $aResponse;
+
+            foreach($aResponse['content'] as $iLine => $sLine)
+                $aResponse['content'][$iLine] = trim($sLine);
+
+            if(strcmp($aResponse['content'][0], "INVALID") === 0)
+                return array('code' => 6, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][0], "VERIFIED") !== 0)
+                return array('code' => 7, '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' => 6, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_transaction');
+            else if(strcmp($aResponse['content'][0], "SUCCESS") !== 0)
+                return array('code' => 7, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_verification_status');
+
+            $aKeys = array();
+            foreach($aResponse['content'] as $sLine) 
+                if(strpos($sLine, '=') !== false) {
+                    list($sKey, $sValue) = explode('=', $sLine);
+                    $aKeys[urldecode($sKey)] = urldecode($sValue);
+                }
+
+            $aData = array_merge($aData, $aKeys);
+
+            if($aData['payment_status'] != 'Completed' )
+                return array('code' => 3, 'message' => $this->_sLangsPrefix . 'pp_err_not_completed');
+
+            if($aData['business'] != $sBusiness)
+                return array('code' => 4, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_business');
+        }
+
+        if(empty($aData['custom']))
+            return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_custom_data');
+
+        list($iVendorId, $iPendingId) = $this->_deconstructCustomData($aData['custom']);
+        if(empty($iVendorId) || empty($iPendingId))
+            return array('code' => 8, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_custom_data');
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if((int)$iVendorId != (int)$aPending['seller_id'])
+            return array('code' => 9, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_vendor');
+
+        $aVendor = $this->_oModule->getVendorInfo($iVendorId);
+        $fAmount = (float)$this->_getReceivedAmount($aVendor['currency_code'], $aData);
+        if($fAmount != (float)$aPending['amount'])
+            return array('code' => 10, 'message' => $this->_sLangsPrefix . 'pp_err_wrong_amount');
+
+        return array('code' => BX_PAYMENT_RESULT_SUCCESS, 'message' => $this->_sLangsPrefix . 'pp_msg_verified');
+    }
+
+    protected function _readValidationData($sConnectionUrl, $sRequest)
+    {
+        $this->log('Validation Request: ', '', BX_LOG_INFO);
+        $this->log($sRequest, '', BX_LOG_INFO);
+
+		$rConnect = curl_init('https://' . $sConnectionUrl . '/cgi-bin/webscr');
+		curl_setopt($rConnect, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
+		curl_setopt($rConnect, CURLOPT_POST, 1);
+		curl_setopt($rConnect, CURLOPT_RETURNTRANSFER,1);
+		curl_setopt($rConnect, CURLOPT_POSTFIELDS, $sRequest);
+		curl_setopt($rConnect, CURLOPT_SSL_VERIFYPEER, 1);
+		curl_setopt($rConnect, CURLOPT_SSL_VERIFYHOST, 2);
+		curl_setopt($rConnect, CURLOPT_FORBID_REUSE, 1);
+		curl_setopt($rConnect, CURLOPT_HTTPHEADER, array('Connection: Close'));
+
+		$sResponse = curl_exec($rConnect);
+    	if(curl_errno($rConnect) == 60) { // CURLE_SSL_CACERT
+            curl_setopt($rConnect, CURLOPT_CAINFO, BX_DIRECTORY_PATH_PLUGINS . 'curl/cacert/cacert.pem');
+            $sResponse = curl_exec($rConnect);
+        }
+
+		if(!$sResponse) {
+		    $this->log('Validation Data: ' . curl_error($rConnect), '', BX_LOG_ERR);
+            $this->log($sResponse, '', BX_LOG_ERR);
+			curl_close($rConnect);
+
+			return array('code' => 5, 'message' => $this->_sLangsPrefix . 'err_cannot_validate');
+		}
+
+		curl_close($rConnect);
+
+		$aResponse = explode("\n", $sResponse);
+
+		$this->log('Validation Response: ', '', BX_LOG_INFO);
+        $this->log($aResponse, '', BX_LOG_INFO);
+		return array('code' => 0, 'content' => $aResponse);
+    }
+
+    protected function _getReceivedAmount($sCurrencyCode, &$aResultData)
+    {
+        $fAmount = 0.00;
+        $fTax = isset($aResultData['tax']) ? (float)$aResultData['tax'] : 0.00;
+
+        if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['payment_gross']) && !empty($aResultData['payment_gross']))
+            $fAmount = (float)$aResultData['payment_gross'] - $fTax;
+        else if($aResultData['mc_currency'] == $sCurrencyCode && isset($aResultData['mc_gross']) && !empty($aResultData['mc_gross']))
+            $fAmount = (float)$aResultData['mc_gross'] - $fTax;
+        else if($aResultData['settle_currency'] == $sCurrencyCode && isset($aResultData['settle_amount']) && !empty($aResultData['settle_amount']))
+            $fAmount = (float)$aResultData['settle_amount'] - $fTax;
+
+        return $fAmount;
+    }
+
+	protected function _constructCustomData()
+	{
+		$aParams = func_get_args();
+		return urlencode(base64_encode(implode('|', $aParams)));
+	}
+
+	protected function _deconstructCustomData($data)
+	{
+		return explode('|', base64_decode(urldecode($data)));
+	}
+}
+
+/** @} */

+ 987 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderPayPalApi.php

@@ -0,0 +1,987 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * 1. Set up server-side SDK:
+ * https://developer.paypal.com/docs/business/checkout/server-side-api-calls/set-up-sdk/
+ * 
+ * 2. Orders API
+ * https://developer.paypal.com/docs/api/orders/v2
+ * 
+ * 2.1. Checkout SDK in GitHUB
+ * https://github.com/paypal/Checkout-PHP-SDK/
+ * 
+ * 3. Subscriptions:
+ * https://developer.paypal.com/docs/subscriptions/
+ * https://developer.paypal.com/docs/business/subscriptions/
+ * 
+ * 3.1. API
+ * https://developer.paypal.com/docs/api/subscriptions/v1
+ * https://developer.paypal.com/docs/api/catalog-products/v1
+ * 
+ * 3.2. Integration
+ * https://developer.paypal.com/docs/subscriptions/integrate/
+ * 
+ * 3.3 WebHooks
+ * https://developer.paypal.com/docs/api-basics/notifications/webhooks/rest/
+ * 
+ * 4. Authorize Intent and Capture Authorized: 
+ * https://github.com/paypal/Checkout-PHP-SDK/tree/develop/samples
+ * 
+ */
+
+use PayPalHttp\HttpException;
+use PayPalCheckoutSdk\Core\PayPalHttpClient;
+use PayPalCheckoutSdk\Core\SandboxEnvironment;
+use PayPalCheckoutSdk\Core\ProductionEnvironment;
+use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
+use PayPalCheckoutSdk\Orders\OrdersGetRequest;
+use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
+use PayPalCheckoutSdk\Orders\OrdersAuthorizeRequest;
+use PayPalCheckoutSdk\Payments\AuthorizationsCaptureRequest;
+
+define('PP_API_MODE_LIVE', 1);
+define('PP_API_MODE_TEST', 2);
+define('PP_API_MODE_DEFAULT', PP_API_MODE_LIVE);
+
+define('PP_API_SBS_STATUS_APPROVAL_PENDING', 'APPROVAL_PENDING');
+define('PP_API_SBS_STATUS_APPROVED', 'APPROVED');
+define('PP_API_SBS_STATUS_ACTIVE', 'ACTIVE');
+
+class BxPaymentProviderPayPalApi extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+    protected $_oSession;
+    protected $_sSessionKeyOrder;
+    protected $_sSessionKeySubscription;
+
+    protected $_bCheckAmount;
+    protected $_iMode;
+    protected $_sEndpoint;
+    protected $_sToken;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_oSession = BxDolSession::getInstance();
+        $this->_sSessionKeyOrder = $this->MODULE . '_' . $this->_sPrefix . 'order';
+        $this->_sSessionKeySubscription = $this->MODULE . '_' . $this->_sPrefix . 'subscription';
+
+        $this->_bCheckAmount = true;
+        $this->_iMode = (int)$this->getOption('mode');
+        $this->_sEndpoint = 'https://api-m' . ($this->_iMode == PP_API_MODE_TEST ? '.sandbox' : '') . '.paypal.com/';
+    }
+
+    public function authorizeCheckout($iPendingId, $aCartInfo)
+    {
+        if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_createOrder($iPendingId, $aCartInfo, ['intent' => 'authorize']);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                $this->_setSessionOrder($mixedResult['order']);
+                return [
+                    'code' => BX_PAYMENT_RESULT_SUCCESS,
+                    'redirect' => $mixedResult['redirect']
+                ];
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return $this->_sLangsPrefix . 'err_not_supported';
+        }
+    }
+
+    public function captureAuthorizedCheckout($sOrderAuth, $mixedPending, $aInfo)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+        if(empty($aPending) || !is_array($aPending))
+            return ['code' => 2, 'message' => $this->_sLangsPrefix . 'err_empty_order'];
+
+        $mixedResult = false;
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_captureAuthorization($sOrderAuth);
+                if($mixedResult === false)
+                    return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return ['code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_supported'];
+        }
+
+        $aResult = [
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => $this->_sLangsPrefix . 'pp_api_msg_captured',
+            'pending_id' => $aPending['id'],
+            'paid' => true
+        ];
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], [
+            'order' => $mixedResult['order'],
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message']),
+        ]);
+
+        return $aResult;
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo)
+    {
+        if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_createOrder($iPendingId, $aCartInfo);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                $this->_setSessionOrder($mixedResult['order']);
+                header("Location: " . $mixedResult['redirect']);
+                exit;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = $this->_createSubscription($iPendingId, $aCartInfo);
+                if(is_string($mixedResult))
+                    return $mixedResult;
+
+                $this->_setSessionSubscription($mixedResult['subscription']);
+                return array(
+                    'code' => 0,
+                    'redirect' => $mixedResult['redirect'],
+                );
+        }
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $sMethod = '_finalizeCheckout' . bx_gen_method_name(!empty($aData['subscription_id']) && !empty('ba_token') ? BX_PAYMENT_TYPE_RECURRING : BX_PAYMENT_TYPE_SINGLE);
+
+        $aResult = $this->$sMethod($aData);
+        if(!isset($aResult['code']) || (int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) {
+            $this->log($aResult, 'Finalize Checkout Failed:', BX_LOG_ERR);
+            $this->log($aData, 'Finalize Checkout Input:', BX_LOG_ERR);
+        }
+
+        return $aResult;
+    }
+
+    public function notify()
+    {
+        $iResult = $this->_processEvent();
+        http_response_code($iResult);
+    }
+
+    public function getClientId()
+    {
+        return $this->getOption($this->_getMode() . '_client_id');
+    }
+
+    public function getSecret()
+    {
+        return $this->getOption($this->_getMode() . '_secret');
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        return [];
+    }
+
+    public function cancelRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        return $this->_cancelSubscription($sSubscriptionId);
+    }
+
+    protected function _finalizeCheckoutSingle(&$aData)
+    {
+        $sOrder = '';
+        if(!empty($aData['token']))
+            $sOrder = bx_process_input($aData['token']);
+        if(empty($sOrder))
+            $sOrder = $this->_getSessionOrder();
+        if(empty($sOrder))
+            return['code' => 1, 'message' => $this->_sLangsPrefix . 'err_empty_order'];
+
+        $aOrder = $this->_getOrder($sOrder);
+        if(empty($aOrder) || !is_array($aOrder))
+            return ['code' => 1, 'message' => $this->_sLangsPrefix . 'err_empty_order'];
+
+        $sMessage = '';
+        $bAuthorized = $bPaid = false;
+        switch($aOrder['intent']) {
+            case 'authorize':
+                $mixedResult = $this->_authorizeOrder($sOrder);
+                if($mixedResult === false)
+                    return ['code' => 2, 'message' => $this->_sLangsPrefix . 'pp_api_err_cannot_authorize'];
+
+                $sMessage = $this->_sLangsPrefix . 'pp_api_msg_authorized';
+                $bAuthorized = true;
+                break;
+
+            case 'capture':
+                $mixedResult = $this->_captureOrder($sOrder);
+                if($mixedResult === false)
+                    return ['code' => 2, 'message' => $this->_sLangsPrefix . 'pp_api_err_cannot_capture'];
+
+                $sMessage = $this->_sLangsPrefix . 'pp_api_msg_captured';
+                $bPaid = true;
+                break;
+        }
+
+        $aResult = [
+            'code' => BX_PAYMENT_RESULT_SUCCESS, 
+            'message' => $sMessage,
+            'pending_id' => $mixedResult['pending_id'],
+            'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $mixedResult['client_first_name'], $mixedResult['client_last_name']),
+            'client_email' => $mixedResult['client_email'],
+            'authorized' => $bAuthorized,
+            'paid' => $bPaid
+        ];
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], [
+            'order' => $mixedResult['order'],
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message']),
+        ]);
+
+        return $aResult;
+    }
+
+    protected function _finalizeCheckoutRecurring(&$aData)
+    {
+        $sSubscription = '';
+        if(!empty($aData['subscription_id']))
+            $sSubscription = bx_process_input($aData['subscription_id']);
+        if(empty($sSubscription))
+            $sSubscription = $this->_getSessionSubscription();
+        if(empty($sSubscription))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_api_err_no_subscription');
+
+        $aSubscription = $this->_getSubscription($sSubscription);
+        if(empty($aSubscription) || !in_array($aSubscription['status'], array(PP_API_SBS_STATUS_APPROVAL_PENDING, PP_API_SBS_STATUS_APPROVED, PP_API_SBS_STATUS_ACTIVE)))
+            return array('code' => 2, 'message' => $this->_sLangsPrefix . 'pp_api_err_no_subscription');
+
+        $aSubscriber = $this->_getClientInfo($aSubscription['subscriber']);
+        list($bPaid, $bTrial) = $this->_getBillingStatus($aSubscription['billing_info']);
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS, 
+            'message' => $this->_sLangsPrefix . 'pp_api_msg_subscribed',
+            'pending_id' => $aSubscription['custom_id'],
+            'customer_id' => $aSubscription['subscriber']['payer_id'], 
+            'subscription_id' => $sSubscription,
+            'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $aSubscriber['client_first_name'], $aSubscriber['client_last_name']),
+            'client_email' => $aSubscriber['client_email'],
+            'trial' => $bTrial,
+        );
+
+        if($aSubscription['status'] == PP_API_SBS_STATUS_APPROVAL_PENDING)       
+            $aResult = array_merge($aResult, array(
+                'code' => 3,
+                'message' => $this->_sLangsPrefix . 'pp_api_err_subscription_not_confirmed'
+            ));
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], array(
+            'order' => $sSubscription,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    /**
+     * Methods which use common HTTPS calls to process Recurring time payments.
+     */
+    protected function _createSubscription($iPendingId, $aCartInfo, $sReturnType = 'approve')
+    {
+        $aItem = array_shift($aCartInfo['items']);
+        if(empty($aItem) || !is_array($aItem))
+            return $this->_sLangsPrefix . 'pp_api_err_no_item';
+
+        $aItem['price_currency'] = $aCartInfo['vendor_currency_code'];
+
+        $aProduct = $this->_getProduct($aItem['name']);
+        if(empty($aProduct)) {
+            $aProduct = $this->_createProduct($aItem);
+            if($aProduct === false)
+                return $this->_sLangsPrefix . 'err_cannot_perform';
+        }
+
+        $aProductPlan = [];
+
+        $aPlans = $this->_getPlans($aProduct['id']);
+        if(!$this->_validateProduct($aItem, $aProduct, $aPlans))
+            return $this->_sLangsPrefix . 'pp_api_err_wrong_item';
+
+        if(!empty($aPlans)) 
+            foreach($aPlans as $aPlan)
+                if(strcmp($aPlan['name'], $aItem['name']) == 0) {
+                    $aProductPlan = $aPlan;
+                    break;
+                }
+        
+        if(empty($aProductPlan) || !is_array($aProductPlan)) {
+            $aProductPlan = $this->_createPlan($aProduct['id'], $aItem);
+            if($aProductPlan === false)
+                return $this->_sLangsPrefix . 'err_cannot_perform';
+        }
+
+        $mixedResult = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/billing/subscriptions', array(
+            'plan_id' => $aProductPlan['id'],
+            'custom_id' => $iPendingId,
+            'application_context' => array(
+                'cancel_url' => $aItem['url'],
+                'return_url' => $this->getReturnDataUrl($aCartInfo['vendor_id'])
+            )
+        ));
+
+        if($mixedResult === false || empty($mixedResult['id']) || empty($mixedResult['links'])) {
+            $this->log($mixedResult, 'Create Subscription:', BX_LOG_ERR);
+            
+            return $this->_sLangsPrefix . 'err_cannot_perform';
+        }
+
+        $mixedLink = false;
+        foreach($mixedResult['links'] as $aLink)
+            if($aLink['rel'] == $sReturnType) {
+                $mixedLink = $aLink['href'];
+                break;
+            }
+
+        return array(
+            'subscription' => $mixedResult['id'],
+            'redirect' => $mixedLink
+        );
+    }
+
+    protected function _getSubscription($sSubscriptionId)
+    {
+        $mixedResult = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/billing/subscriptions/' . $sSubscriptionId, array(), array(), 'get');
+        if($mixedResult === false || !isset($mixedResult['id'])) {
+            $this->log($mixedResult, 'Get Subscription:', BX_LOG_ERR);
+
+            return array();
+        }
+
+        return $mixedResult;
+    }
+
+    protected function _cancelSubscription($sSubscriptionId)
+    {
+        list($sCode, $sResponse) = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/billing/subscriptions/' . $sSubscriptionId . '/cancel', [
+            'reason' => 'Not needed anymore'
+        ], [], 'post-json', true);
+
+        if($sCode != 204) {
+            $this->log($sResponse, 'Cancel Subscription:', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return true;
+    }
+
+    protected function _createProduct($aItem)
+    {
+        if(empty($aItem['description']))
+            $aItem['description'] = _t('_bx_payment_txt_payment_description', getParam('site_title'));
+        $aItem['description'] = strmaxtextlen($aItem['description'], 60, '...');
+
+        $mixedResult = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/catalogs/products', array(
+            'id' => $aItem['name'],
+            'name' => $aItem['title'],
+            'description' => $aItem['description'],
+            'type' => 'DIGITAL',
+            'home_url' => $aItem['url'],
+        ), array(
+            'PayPal-Request-Id: bx_prod_' . $aItem['name']
+        ));
+
+        if($mixedResult === false || !isset($mixedResult['id'])) {
+            $this->log($mixedResult, 'Create Product:', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $mixedResult;
+    }
+    
+    protected function _getProduct($sProductId)
+    {
+        $mixedResult = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/catalogs/products/' . $sProductId, array(), array(), 'get');
+        if($mixedResult === false || !isset($mixedResult['id'])) {
+            $this->log($mixedResult, 'Get Product:', BX_LOG_ERR);
+
+            return array();
+        }
+
+        return $mixedResult;
+    }
+    
+    protected function _validateProduct($aItem, $aProduct, $aPlans)
+    {
+        //--- by date creation.
+        if(isset($aItem['added'], $aProduct['create_time']) && $aItem['added'] > strtotime($aProduct['create_time']))
+            return false;
+
+        return true;
+    }
+
+    protected function _createPlan($sProductId, $aItem)
+    {
+        $aCycles = array();
+
+        $sIntervalUnit = $this->_getIntervalUnit($aItem['period_unit_recurring']);
+        if($sIntervalUnit === false)
+            return false;
+
+        $iSequence = 1;
+
+        $iTrial = $this->_oModule->_oConfig->getTrial(BX_PAYMENT_TYPE_RECURRING, $aItem);
+        if(!empty($iTrial)) 
+            $aCycles[] = array(
+                'frequency' => array(
+                    'interval_unit' => $this->_getIntervalUnit(BX_PAYMENT_SBS_PU_DAY),
+                    'interval_count' => $iTrial
+                ),
+                'tenure_type' => 'TRIAL',
+                'sequence' => $iSequence++,
+                'total_cycles' => 1,
+            );
+
+        $aCycles[] = array(
+            'frequency' => array(
+                'interval_unit' => $sIntervalUnit,
+                'interval_count' => (int)$aItem['period_recurring']
+            ),
+            'tenure_type' => 'REGULAR',
+            'sequence' => $iSequence,
+            'total_cycles' => 0,
+            'pricing_scheme' => array(
+                'fixed_price' => array(
+                    'value' => $this->_oModule->_oConfig->getPrice(BX_PAYMENT_TYPE_RECURRING, $aItem),
+                    'currency_code' => $aItem['price_currency']
+                )
+            )
+        );
+
+        $mixedResult = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/billing/plans', array(
+            'product_id' => $sProductId,
+            'name' => $aItem['name'],
+            'description' => $aItem['title'],
+            'billing_cycles' => $aCycles,
+            'payment_preferences' => array(
+                'auto_bill_outstanding' => true,
+                'setup_fee' => array(
+                    'value' => 0,
+                    'currency_code' => $aItem['price_currency']
+                ),
+                'setup_fee_failure_action' => 'CONTINUE',
+                'payment_failure_threshold' => 3
+            ),
+        ), array(
+            'PayPal-Request-Id: bx_plan_' . $aItem['name']
+        ));
+
+        if($mixedResult === false || !isset($mixedResult['id'])) {
+            $this->log($mixedResult, 'Create Plan:', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $mixedResult;
+    }
+
+    protected function _getPlan($sPlanId)
+    {
+        $mixedResult = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/billing/plans/' . $sPlanId, array(), array(), 'get');
+        if($mixedResult === false || !isset($mixedResult['id'])) {
+            $this->log($mixedResult, 'Get Plan:', BX_LOG_ERR);
+
+            return array();
+        }
+
+        return $mixedResult;
+    }
+
+    protected function _getPlans($sProductId, $iStart = false, $iPerPage = false)
+    {
+        $aParams = array(
+            'product_id' => $sProductId,
+        );
+        
+        if($iStart !== false)
+            $aParams['page'] = (int)$iStart >= 1 && (int)$iStart <= 100000 ? $iStart : 1;
+        if($iPerPage !== false)
+            $aParams['page_size'] = (int)$iPerPage >= 1 && (int)$iPerPage <= 20 ? $iPerPage : 20;
+
+        $mixedResult = $this->_apiCallAuthorized($this->_sEndpoint . 'v1/billing/plans', $aParams, array(), 'get');
+        if(empty($mixedResult) || !is_array($mixedResult) || !isset($mixedResult['plans'])) {
+            $this->log($mixedResult, 'Get Plans:', BX_LOG_ERR);
+
+            return array();
+        }
+
+        return $mixedResult['plans'];
+    }
+
+    protected function _getToken()
+    {
+        $mixedResult = $this->_apiCallAuthorize($this->_sEndpoint . 'v1/oauth2/token', [
+            'grant_type' => 'client_credentials'
+        ], [
+            'user' => $this->getClientId(),
+            'password' => $this->getSecret()
+        ]);
+
+        if($mixedResult === false || empty($mixedResult['access_token'])) {
+            $this->log($mixedResult, 'Get Token:', BX_LOG_ERR);
+
+            return false;
+        }
+
+        return $mixedResult['access_token'];
+    }
+
+    protected function _apiCallAuthorize($sEndpoint, $aParams = [], $aBasicAuth = [], $sMethod = 'post')
+    {
+        $sResponse = $this->_apiCall($sEndpoint, $aParams, [], $sMethod, $aBasicAuth);
+
+        return !empty($sResponse) ? json_decode($sResponse, true) : false;
+    }
+
+    protected function _apiCallAuthorized($sEndpoint, $aParams = [], $aHeaders = [], $sMethod = 'post-json', $bRawResponse = false)
+    {
+        if(!$this->_sToken)
+            $this->_sToken = $this->_getToken();
+
+        $aHeaders = array_merge([
+            'Authorization: Bearer ' . $this->_sToken,
+            'Prefer: return=representation'
+        ], $aHeaders);
+
+        $sHttpCode = $bRawResponse ? true : null;
+
+        $sResponse = $this->_apiCall($sEndpoint, $aParams, $aHeaders, $sMethod, [], $sHttpCode);
+        if($bRawResponse)
+            return [$sHttpCode, $sResponse];
+
+        return !empty($sResponse) ? json_decode($sResponse, true) : false;
+    }
+
+    protected function _apiCall($sEndpoint, $aParams = [], $aHeaders = [], $sMethod = 'post-json', $aBasicAuth = [], &$sHttpCode = null)
+    {
+        $aHeaders = array_merge([
+            'Accept: application/json',
+            'Content-Type: application/json'
+        ], $aHeaders);
+
+        return bx_file_get_contents($sEndpoint, $aParams, $sMethod, $aHeaders, $sHttpCode, $aBasicAuth);
+    }
+
+    protected function _getIntervalUnit($sPeriodUnit)
+    {
+        $aIntervalUnits = array(
+            BX_PAYMENT_SBS_PU_DAY => 'DAY',
+            BX_PAYMENT_SBS_PU_WEEK => 'WEEK',
+            BX_PAYMENT_SBS_PU_MONTH => 'MONTH',
+            BX_PAYMENT_SBS_PU_YEAR => 'YEAR'
+        );
+
+        return isset($aIntervalUnits[$sPeriodUnit]) ? $aIntervalUnits[$sPeriodUnit] : false;
+    }
+
+
+    /**
+     * Methods which use 'Checkout SDK' to process Single time payments.
+     */
+    protected function _getClient()
+    {
+        $sClientId = $this->getClientId();
+        $sSecret = $this->getSecret();
+
+        if($this->_iMode == PP_API_MODE_LIVE)
+            $oEnvironment = new ProductionEnvironment($sClientId, $sSecret);
+        else 
+            $oEnvironment = new SandboxEnvironment($sClientId, $sSecret);
+
+        return new PayPalHttpClient($oEnvironment);
+    }
+
+    protected function _createOrder($iPendingId, $aCartInfo, $aParams = [])
+    {
+        $sReturnType = isset($aParams['return_type']) ? $aParams['return_type'] : 'approve';
+                
+        $aItems = array();
+        foreach($aCartInfo['items'] as $aItem)
+            $aItems[] = array(
+                'name' => $aItem['title'],
+                'unit_amount' => array(
+                    'value' => sprintf("%.2f", $this->_oModule->_oConfig->getPrice(BX_PAYMENT_TYPE_SINGLE, $aItem)),
+                    'currency_code' => $aCartInfo['vendor_currency_code']
+                ),
+                'quantity' => $aItem['quantity']
+            );
+
+        $sItemsPrice = sprintf("%.2f", round($aCartInfo['items_price'], 2));
+
+        $oRequest = new OrdersCreateRequest();
+        $oRequest->prefer('return=representation');
+        $oRequest->body = array(
+            'intent' => isset($aParams['intent']) ? strtoupper($aParams['intent']) : 'CAPTURE',
+            'purchase_units' => array(
+                array(
+                    'reference_id' => $iPendingId,
+                    'amount' => array(
+                        'currency_code' => $aCartInfo['vendor_currency_code'],
+                        'value' => $sItemsPrice,
+                        'breakdown' => array(
+                            'item_total' => array(
+                                'currency_code' => $aCartInfo['vendor_currency_code'],
+                                'value' => $sItemsPrice,
+                            )
+                        )
+                    ),
+                    'items' => $aItems
+                )
+            ),
+            'application_context' => array(
+                'cancel_url' => $this->_oModule->getObjectCart()->serviceGetCartUrl($aCartInfo['vendor_id']),
+                'return_url' => $this->getReturnDataUrl($aCartInfo['vendor_id'])
+            )
+        );
+
+        try {
+            $oResponse = $this->_getClient()->execute($oRequest);
+            if($oResponse->statusCode != 201)
+                return false;
+
+            $mixedLink = false;
+            foreach($oResponse->result->links as $oLink)
+                if($oLink->rel == $sReturnType) {
+                    $mixedLink = $oLink->href;
+                    break;
+                }
+
+            return array(
+                'order' => $oResponse->result->id,
+                'redirect' => $mixedLink,
+            );
+        }
+        catch (HttpException $oException) {
+            return $this->_processException('Create Order Error: ', $oException);
+        }
+    }
+
+    protected function _getOrder($sOrderId)
+    {
+        $oRequest = new OrdersGetRequest($sOrderId);
+
+        try {
+            $oResponse = $this->_getClient()->execute($oRequest);
+            if($oResponse->statusCode != 200 || strcmp(strtolower($oResponse->result->status), 'approved') != 0)
+                return false;
+
+            $oPurchase = current($oResponse->result->purchase_units);
+            return array_merge(array(
+                'id' => $oResponse->result->id,
+                'intent' => strtolower($oResponse->result->intent),
+                'pending_id' => (int)$oPurchase->reference_id,
+            ), $this->_getClientInfo($oResponse->result->payer));
+        }
+        catch (HttpException $oException) {
+            return $this->_processException('Get Order Error: ', $oException);
+        }
+        
+    }
+
+    protected function _authorizeOrder($sOrderId)
+    {
+        $oRequest = new OrdersAuthorizeRequest($sOrderId);
+
+        try {
+            $oResponse = $this->_getClient()->execute($oRequest);
+            if($oResponse->statusCode != 201 || strcmp(strtolower($oResponse->result->status), 'completed') != 0)
+                return false;
+
+            $oPurchase = current($oResponse->result->purchase_units);
+            $oAuthorization = current($oPurchase->payments->authorizations);
+            return array_merge(array(
+                'pending_id' => (int)$oPurchase->reference_id,
+                'order' => $oAuthorization->id,
+            ), $this->_getClientInfo($oResponse->result->payer));
+        }
+        catch (HttpException $oException) {
+            return $this->_processException('Authorize Order Error: ', $oException);
+        }
+    }
+
+    protected function _captureOrder($sOrderId)
+    {
+        $oRequest = new OrdersCaptureRequest($sOrderId);
+
+        try {
+            $oResponse = $this->_getClient()->execute($oRequest);
+            if($oResponse->statusCode != 201 || strcmp(strtolower($oResponse->result->status), 'completed') != 0)
+                return false;
+
+            $oPurchase = current($oResponse->result->purchase_units);
+            $oCapture = current($oPurchase->payments->captures);
+            return array_merge(array(
+                'pending_id' => (int)$oPurchase->reference_id,
+                'order' => $oCapture->id,
+            ), $this->_getClientInfo($oResponse->result->payer));
+        }
+        catch (HttpException $oException) {
+            return $this->_processException('Capture Order Error: ', $oException);
+        }
+    }
+    
+    protected function _captureAuthorization($sAuthorizationId)
+    {
+        $oRequest = new AuthorizationsCaptureRequest($sAuthorizationId);
+
+        try {
+            $oResponse = $this->_getClient()->execute($oRequest);
+            if($oResponse->statusCode != 201 || strcmp(strtolower($oResponse->result->status), 'completed') != 0)
+                return false;
+
+            return [
+                'order' => $oResponse->result->id
+            ];
+        }
+        catch (HttpException $oException) {
+            return $this->_processException('Capture Authorization Error: ', $oException);
+        }
+    }
+
+    protected function _processException($sMessage, &$oException)
+    {
+        $sDescription = '';
+        $aError = [];
+
+        $sMethod = 'getJsonBody';
+        if(method_exists($oException, $sMethod)) {
+            $aError = $oException->getJsonBody();
+            if(isset($aError['error']['message']))
+                $sDescription = $aError['error']['message'];
+        }
+
+        if(empty($sDescription))
+            $sDescription = $oException->getMessage();
+
+        $this->log($sMessage . $sDescription, '', BX_LOG_ERR);
+        if(!empty($aError))
+            $this->log($aError, '', BX_LOG_ERR);
+
+        return false;
+    }
+
+    /**
+     * Methods to process WebHooks
+     */
+    protected function _processEvent()
+    {
+        $sInput = @file_get_contents("php://input");
+        $aEvent = json_decode($sInput, true);
+        if(empty($aEvent) || !is_array($aEvent)) 
+            return 404;
+
+        $sType = $aEvent['event_type'];
+        if(!in_array($sType, array('PAYMENT.SALE.COMPLETED', 'PAYMENT.CAPTURE.REFUNDED', 'BILLING.SUBSCRIPTION.CANCELLED')))
+            return 200;
+
+        $this->log($aEvent, 'Webhooks: ' . (!empty($sType) ? $sType : ''), BX_LOG_INFO);
+
+        $sMethod = '_processEvent' . bx_gen_method_name(strtolower($sType), array('.', '_', '-'));
+    	if(!method_exists($this, $sMethod))
+            return 200;
+
+    	return $this->$sMethod($aEvent) ? 200 : 403;
+    }
+
+    protected function _processEventPaymentSaleCompleted($aEvent)
+    {
+        $mixedResult = $this->_getEventData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending, $aEventData) = $mixedResult;
+
+        $fChargeAmount = (float)$aEventData['amount']['total'];
+        $sChargeCurrency = strtoupper($aEventData['amount']['currency']);
+        if($this->_bCheckAmount && ((float)$aPending['amount'] != $fChargeAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sChargeCurrency) !== 0))
+            return false;
+
+        if($aPending['type'] == BX_PAYMENT_TYPE_RECURRING)
+            $this->_oModule->getObjectSubscriptions()->prolong($aPending);
+
+        return $this->_oModule->registerPayment($aPending);
+    }
+
+    protected function _processEventPaymentCaptureRefunded($aEvent)
+    {
+        $mixedResult = $this->_getEventData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending, $aEventData) = $mixedResult;
+        return $this->_oModule->refundPayment($aPending);
+    }
+
+    protected function _processEventBillingSubscriptionCancelled($aEvent)
+    {
+        $mixedResult = $this->_getEventData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending, $aEventData) = $mixedResult;
+        return $this->_oModule->getObjectSubscriptions()->cancelLocal($aPending);
+    }
+
+    protected function _getEventData($aEvent)
+    {
+        if(empty($aEvent['resource']) || !is_array($aEvent['resource']))
+            return false;
+
+        $aData = $aEvent['resource'];
+        if(empty($aData['billing_agreement_id']))
+            return false;       
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $aData['billing_agreement_id']));
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        return array($aPending, $aData);
+    }
+
+    /**
+     * Common methods for internal usage.
+     */
+    protected function _getMode()
+    {
+        if(empty($this->_iMode))
+            $this->_iMode = (int)$this->getOption('mode');
+
+        $aModeI2S = array(
+            PP_API_MODE_LIVE => 'live',
+            PP_API_MODE_TEST => 'test'
+        );
+
+        return isset($aModeI2S[$this->_iMode]) ? $aModeI2S[$this->_iMode] : $aModeI2S[PP_API_MODE_DEFAULT];
+    }
+
+    protected function _getSessionOrder()
+    {
+        return $this->_oSession->getUnsetValue($this->_sSessionKeyOrder);
+    }
+
+    protected function _setSessionOrder($sValue)
+    {
+        $this->_oSession->setValue($this->_sSessionKeyOrder, $sValue);
+    }
+
+    protected function _getSessionSubscription()
+    {
+        return $this->_oSession->getUnsetValue($this->_sSessionKeySubscription);
+    }
+
+    protected function _setSessionSubscription($sValue)
+    {
+        $this->_oSession->setValue($this->_sSessionKeySubscription, $sValue);
+    }
+
+    /**
+     * Retrieve 'Client Info' from a 'getSubscription' call's response.
+     */
+    protected function _getClientInfo($mixedClient)
+    {
+        $_sName = 'name';
+        $_sFirst = 'given_name';
+        $_sLast = 'surname';
+        $_sEmail = 'email_address';
+
+        $aResult = [];
+        if(is_object($mixedClient))
+            $aResult = [
+                'client_first_name' => $mixedClient->$_sName->$_sFirst,
+                'client_last_name' => $mixedClient->$_sName->$_sLast,
+                'client_email' => $mixedClient->$_sEmail,
+            ];
+        else
+            $aResult = [
+                'client_first_name' => $mixedClient[$_sName][$_sFirst],
+                'client_last_name' => $mixedClient[$_sName][$_sLast],
+                'client_email' => $mixedClient[$_sEmail],
+            ];
+
+        return $aResult;
+    }
+
+    /**
+     * Retrieve 'Billing Status' from a 'getSubscription' call's response.
+     */
+    protected function _getBillingStatus($mixedBillingInfo)
+    {
+        $bTrial = $bPaid = false;
+
+        $_sCycles = 'cycle_executions';
+        $_sCycleType = 'tenure_type';
+        $_sCyclesCompleted = 'cycles_completed';
+        $_sCyclesTotal = 'total_cycles';
+
+        $bByObject = is_object($mixedBillingInfo);
+        $aCycles = $bByObject ? $mixedBillingInfo->$_sCycles : $mixedBillingInfo[$_sCycles];
+        if(empty($aCycles) || !is_array($aCycles))
+            return [$bPaid, $bTrial];
+
+        foreach($aCycles as $mixedCycle) {
+            $sCycleType = $bByObject ? $mixedCycle->$_sCycleType : $mixedCycle[$_sCycleType];
+            $iCyclesCompleted = $bByObject ? $mixedCycle->$_sCyclesCompleted : (int)$mixedCycle[$_sCyclesCompleted];
+            $iCyclesTotal = $bByObject ? $mixedCycle->$_sCyclesTotal : (int)$mixedCycle[$_sCyclesTotal];
+
+            switch($sCycleType) {
+                case 'TRIAL':
+                    $bTrial = $iCyclesCompleted <= $iCyclesTotal;
+                    break;
+
+                case 'REGULAR':
+                    if($iCyclesCompleted == 0)
+                        break;
+
+                    $bPaid = true;
+                    $bTrial = false;
+                    break 2;
+            }
+        }
+
+        return [$bPaid, $bTrial];
+    }
+}
+
+/** @} */

+ 750 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderStripeBasic.php

@@ -0,0 +1,750 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define('STRP_MODE_LIVE', 1);
+define('STRP_MODE_TEST', 2);
+
+class BxPaymentProviderStripeBasic extends BxBaseModPaymentProvider
+{
+    protected $_sFormDetails;
+    protected $_sFormDisplayDetailsEdit;
+
+    protected $_sFormCard;
+    protected $_sFormDisplayCardAdd;
+
+    protected $_iMode;
+    protected $_bCheckAmount;
+    protected $_bProrate;
+
+    protected $_oCustomer;
+
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_aSbsStatuses = array(
+            'incomplete' => BX_PAYMENT_SBS_STATUS_UNPAID, 
+            'incomplete_expired' => BX_PAYMENT_SBS_STATUS_UNPAID, 
+            'trialing' => BX_PAYMENT_SBS_STATUS_TRIAL, 
+            'active' => BX_PAYMENT_SBS_STATUS_ACTIVE, 
+            'past_due' => BX_PAYMENT_SBS_STATUS_UNPAID,
+            'unpaid' => BX_PAYMENT_SBS_STATUS_UNPAID,
+            'canceled' => BX_PAYMENT_SBS_STATUS_CANCELED,
+        );
+
+        $this->_sFormDetails = 'bx_payment_form_strp_details';
+        $this->_sFormDisplayDetailsEdit = 'bx_payment_form_strp_details_edit';
+
+        $this->_sFormCard = 'bx_payment_form_strp_card';
+        $this->_sFormDisplayCardAdd = 'bx_payment_form_strp_card_add';
+
+        $this->_bProrate = false;
+
+        $this->_aIncludeJs = array(
+            'main.js',
+        );
+
+        $this->_aIncludeCss = array(
+            'stripe.css'
+        );
+
+        $this->_oCustomer = null;
+
+        \Stripe\Stripe::setApiKey($this->_getSecretKey());
+    }
+
+    public function initOptions($aOptions)
+    {
+    	parent::initOptions($aOptions);
+
+    	$this->_iMode = (int)$this->getOption('mode');
+    	$this->_bCheckAmount = $this->getOption('check_amount') == 'on';
+    	$this->_bUseSsl = $this->getOption('ssl') == 'on';
+    }
+
+    public function addJsCss()
+    {
+    	if(!$this->isActive())
+    		return;
+
+        $this->_oModule->_oTemplate->addJs($this->_aIncludeJs);
+        $this->_oModule->_oTemplate->addCss($this->_aIncludeCss);
+    }
+
+    public function getJsObject($aParams = array())
+    {
+        $sJsObject = $this->_oModule->_oConfig->getJsObject($this->_sName);
+        if(isset($aParams['iModuleId'], $aParams['iSellerId'], $aParams['iItemId']))
+            $sJsObject .= '_' . md5($aParams['iModuleId'] . '-' . $aParams['iSellerId'] . '-' . $aParams['iItemId']);
+        
+        return $sJsObject;
+    }
+
+    public function notify()
+    {
+        $iResult = $this->_processEvent();
+        http_response_code($iResult);
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
+    {
+        $aItems = array();
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId, $aItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+    	return $this->_getButton(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name']),
+            'sVendorCurrency' => $aCartInfo['vendor_currency_code'],
+            'sVendorIcon' => $aCartInfo['vendor_avatar'],
+    	)));
+    }
+
+    public function getButtonSingleJs($iClientId, $iVendorId, $aParams = array())
+    {
+        $aItems = array();
+        $aCartInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $iClientId, (int)$iVendorId, $aItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return '';
+
+    	return $this->_getButtonJs(BX_PAYMENT_TYPE_SINGLE, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aCartInfo['vendor_name']),
+            'sVendorCurrency' => $aCartInfo['vendor_currency_code'],
+            'sVendorIcon' => $aCartInfo['vendor_avatar'],
+    	)));
+    }
+
+    public function getButtonRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+    	$aVendor = $this->_oModule->getVendorInfo((int)$iVendorId);
+
+        return $this->_getButton(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aVendor['name']),
+            'sVendorCurrency' => $aVendor['currency_code'],
+            'sVendorIcon' => $aVendor['avatar'],
+        )));
+    }
+    
+    public function getButtonRecurringJs($iClientId, $iVendorId, $aParams = array())
+    {
+    	$aVendor = $this->_oModule->getVendorInfo((int)$iVendorId);
+
+        return $this->_getButtonJs(BX_PAYMENT_TYPE_RECURRING, $iClientId, $iVendorId, array_merge($aParams, array(
+            'sVendorName' => _t($this->_sLangsPrefix . 'txt_payment_to', $aVendor['name']),
+            'sVendorCurrency' => $aVendor['currency_code'],
+            'sVendorIcon' => $aVendor['avatar'],
+        )));
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        if(empty($aParams['order']))
+            return array();
+
+        $sJsObject = $this->_oModule->_oConfig->getJsObject(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION);
+
+        $sPrefix = 'bx-payment-strp-';
+        return array(
+            array('id' => $sPrefix . 'details', 'name' => $sPrefix . 'details', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".getDetails(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_details')),
+            array('id' => $sPrefix . 'details_change', 'name' => $sPrefix . 'details_change', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".changeDetails(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_details_change')),
+            array('id' => $sPrefix . 'billing', 'name' => $sPrefix . 'billing', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".getBilling(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_billing')),
+            array('id' => $sPrefix . 'billing_change', 'name' => $sPrefix . 'billing_change', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => "javascript:" . $sJsObject . ".changeBilling(this, '" . $aParams['id'] . "')", 'target' => '_self', 'title' => _t('_bx_payment_strp_menu_item_title_billing_change')),
+        );
+    }
+
+    public function getDetailsRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+        if($oSubscription === false)
+            return '';
+
+        $aSubscription = $oSubscription->jsonSerialize();
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return '';
+
+        $sName = '';
+        if(!empty($aSubscription['plan']['name']))
+            $sName = $aSubscription['plan']['name'];
+        else if(!empty($aSubscription['plan']['product'])){
+            $oProduct = $this->_retrieveProduct($aSubscription['plan']['product']);
+            if($oProduct !== false) 
+                $sName = $oProduct->name;
+        }
+
+        $sNone = _t('_bx_payment_txt_none');
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_details_recurring.html', array(
+            'plan' => $sName,
+            'cost' => _t('_bx_payment_strp_txt_cost_mask', (int)$aSubscription['plan']['amount'] / 100, $aSubscription['plan']['currency'], $aSubscription['plan']['interval']),
+            'status' => $aSubscription['status'],
+            'created' => bx_time_js($aSubscription['created'], BX_FORMAT_DATE_TIME, true),
+            'started' => !empty($aSubscription['start']) ? bx_time_js($aSubscription['start'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'trial_start' => !empty($aSubscription['trial_start']) ? bx_time_js($aSubscription['trial_start'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'trial_end' => !empty($aSubscription['trial_end']) ? bx_time_js($aSubscription['trial_end'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'cperiod_start' => !empty($aSubscription['current_period_start']) ? bx_time_js($aSubscription['current_period_start'], BX_FORMAT_DATE_TIME, true) : $sNone,
+            'cperiod_end' => !empty($aSubscription['current_period_end']) ? bx_time_js($aSubscription['current_period_end'], BX_FORMAT_DATE_TIME, true) : $sNone,
+        ));
+    }
+
+    public function changeDetailsRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oForm = BxDolForm::getObjectInstance($this->_sFormDetails, $this->_sFormDisplayDetailsEdit, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['id'] = $this->_oModule->_oConfig->getHtmlIds('subscription', 'form_subscription_change_details');
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'subscription_change_details/' . $iPendingId;
+
+        $oForm->aInputs['item_id']['values'] = $this->_getDataChangeDetailsRecurring($iPendingId);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $aResultError = array('code' => 1, 'message' => _t('_bx_payment_strp_err_details_changed'));
+
+            $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+            list($iVendorId, $iModuleId, $iItemId, $iItemCount) = $this->_oModule->_oConfig->descriptorS2A($aPending['items']);
+
+            $aItem = $this->_oModule->callGetCartItem($iModuleId, array($oForm->getCleanValue('item_id'), $aPending['client_id']));
+    		if(empty($aItem) || !is_array($aItem))
+    			return $aResultError;
+
+            $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+            if($oSubscription === false)
+                return $aResultError;
+
+            $oSubscription->plan = $aItem['name'];
+            $oSubscription->prorate = $this->_bProrate;
+            $oSubscription = $oSubscription->save();
+            if(strcmp($oSubscription->plan->id, $aItem['name']) !== 0)
+                return $aResultError;
+
+            $sItems = $this->_oModule->_oConfig->descriptorA2S(array($iVendorId, $iModuleId, $aItem['id'], $iItemCount));
+            if(!$this->_oModule->_oDb->updateOrderPending($iPendingId, array('items' => $sItems)))
+                return $aResultError;
+
+            $this->_oModule->callReregisterSubscriptionItem($iModuleId, array($aPending['client_id'], $aPending['seller_id'], $iItemId, $aItem['id'], $aPending['order']));
+
+            return array('code' => 0, 'message' => _t('_bx_payment_strp_msg_details_changed'));
+        }
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_details_change_recuring.html', array(
+            'object' => $this->_oModule->_oConfig->getJsObject('subscription'),
+            'form' => $oForm->getCode(),
+            'form_id' => $oForm->aFormAttrs['id'],
+        ));
+    }
+
+    public function getBillingRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $aCard = ['brand' => '', 'country' => '', 'funding' => '', 'last4' => '', 'exp_month' => '', 'exp_year' => '', 'cvc_check' => ''];
+
+        $oCard = $this->_retrieveCard($sCustomerId);
+        if($oCard === false && ($oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId)) !== false) {
+            $sPaymentMethodId = $oSubscription->default_payment_method;
+            if(!empty($sPaymentMethodId) && ($oPaymentMethod = $this->_retrievePaymentMethod($sPaymentMethodId)) !== false)
+                $oCard = $oPaymentMethod->card;
+        }
+
+        if(!empty($oCard))
+            $aCard = $oCard->jsonSerialize();
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_billing_recurring.html', array(
+            'brand' => $aCard['brand'],
+            'origin' => $aCard['country'],
+            'type' => $aCard['funding'],
+            'number' => _t('_bx_payment_strp_txt_card_number_mask', $aCard['last4']),
+            'expires' => _t('_bx_payment_strp_txt_card_expires_mask', $aCard['exp_month'], $aCard['exp_year']),
+            'cvc' => _t(!empty($aCard['cvc_check']) && strcmp($aCard['cvc_check'], 'pass') === 0 ? '_bx_payment_strp_txt_card_cvc_passed' : '_bx_payment_txt_none'),
+        ));
+    }
+
+    public function changeBillingRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oForm = BxDolForm::getObjectInstance($this->_sFormCard, $this->_sFormDisplayCardAdd, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['id'] = $this->_oModule->_oConfig->getHtmlIds('subscription', 'form_subscription_change_billing');
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'subscription_change_billing/' . $iPendingId;
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $aResultError = array('code' => 1, 'message' => _t('_bx_payment_strp_err_billing_changed'));
+
+            $aMatch = array();
+            if(!preg_match('/^([0-9]{2})\D([0-9]{4})$/i', $oForm->getCleanValue('card_expire'), $aMatch))
+                return $aResultError;
+
+            list($iMonth, $iYear) = array_slice($aMatch, 1);
+
+        	$aToken = $this->_createToken(array(
+                'number' => $oForm->getCleanValue('card_number'),
+                'exp_month' => $iMonth,
+                'exp_year' => $iYear,
+                'cvc' => $oForm->getCleanValue('card_cvv')
+            ));
+            if(empty($aToken) || !is_array($aToken))
+                return $aResultError;
+
+            $aCard = $this->_createCard(BX_PAYMENT_TYPE_RECURRING, $sCustomerId, $aToken['id']);
+            if(empty($aCard) || !is_array($aCard))
+                return $aResultError;
+
+            $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+            if($oCustomer === false)
+                return $aResultError;
+
+            $oCustomer->default_source = $aCard['id'];
+            $oCustomer->save();
+
+            return array('code' => 0, 'message' => _t('_bx_payment_strp_msg_billing_changed'));
+        }
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('strp_billing_change_recuring.html', array(
+            'object' => $this->_oModule->_oConfig->getJsObject('subscription'),
+            'form' => $oForm->getCode(),
+            'form_id' => $oForm->aFormAttrs['id'],
+        ));
+    }
+
+    public function cancelRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = $this->_cancelSubscription($sCustomerId, $sSubscriptionId);
+        if($oSubscription === false)
+            return false;
+
+        return true;
+    }
+
+    public function getSubscription($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+        if($oSubscription === false)
+            return array();
+
+        $aSubscription = $oSubscription->jsonSerialize();
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return array();
+
+        $sStatus = isset($this->_aSbsStatuses[$aSubscription['status']]) ? $this->_aSbsStatuses[$aSubscription['status']] : BX_PAYMENT_SBS_STATUS_UNKNOWN;
+
+        return array(
+            'status' => $sStatus,
+            'created' => $aSubscription['created'],
+            'started' => !empty($aSubscription['start']) ? $aSubscription['start'] : 0,
+            'trial_start' => !empty($aSubscription['trial_start']) ? $aSubscription['trial_start'] : 0,
+            'trial_end' => !empty($aSubscription['trial_end']) ? $aSubscription['trial_end'] : 0,
+            'cperiod_start' => !empty($aSubscription['current_period_start']) ? $aSubscription['current_period_start'] : 0,
+            'cperiod_end' => !empty($aSubscription['current_period_end']) ? $aSubscription['current_period_end'] : 0,
+        );
+    }
+
+    protected function _getPublicKey()
+    {
+        return $this->_iMode == STRP_MODE_LIVE ? $this->getOption('live_pub_key') : $this->getOption('test_pub_key');
+    }
+
+    protected function _getSecretKey()
+    {
+        return $this->_iMode == STRP_MODE_LIVE ? $this->getOption('live_sec_key') : $this->getOption('test_sec_key');
+    }
+
+    protected function _retrieveCustomer($sType, $sId)
+    {
+        $oCustomer = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_retrieve_customer 'bx_payment', 'stripe_retrieve_customer' - hook to override customer data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_retrieve_customer`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] payment type: single or recurring
+         *      - `customer_id` - [string] by ref, unique customer id, can be overridden in hook processing
+         *      - `customer_object` - [object] by ref, an instance of customer, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_retrieve_customer
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_customer', 0, false, [
+            'type' => $sType,
+            'customer_id' => &$sId,
+            'customer_object' => &$oCustomer
+        ]);
+
+        try {
+            if(empty($oCustomer))
+                $oCustomer = \Stripe\Customer::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Customer Error: ', $oException);
+        }
+
+        return $oCustomer;
+    }
+
+    protected function _retrieveCharge($sId)
+    {
+        $oCharge = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_retrieve_charge 'bx_payment', 'stripe_retrieve_charge' - hook to override charge data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_retrieve_charge`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] payment type: single or recurring
+         *      - `charge_id` - [string] by ref, unique charge id, can be overridden in hook processing
+         *      - `charge_object` - [object] by ref, an instance of charge, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_retrieve_charge
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_charge 'bx_payment', 'stripe_v3_retrieve_charge' - hook to override charge data retrieved from payment provider
+         * It's equivalent to @ref hook-bx_payment-stripe_retrieve_charge
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_charge
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_charge', 0, false, [
+            'charge_id' => &$sId,
+            'charge_object' => &$oCharge
+        ]);
+
+        try {
+            if(empty($oCharge))
+                $oCharge = \Stripe\Charge::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Charge Error: ', $oException);
+        }
+
+        return $oCharge;
+    }
+
+    protected function _retrieveSubscription($sCustomerId, $sSubscriptionId)
+    {
+        try {
+            $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+            $oSubscription = \Stripe\Subscription::retrieve($sSubscriptionId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Subscription Error: ', $oException);
+        }
+
+        return $oSubscription;
+    }
+
+    protected function _cancelSubscription($sCustomerId, $sSubscriptionId)
+    {
+        try {
+            $oSubscription = $this->_retrieveSubscription($sCustomerId, $sSubscriptionId);
+            $oSubscription = $oSubscription->cancel();
+        }
+        catch (Exception $oException) {
+                return $this->_processException('Cancel Subscription Error: ', $oException);
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_cancel_subscription 'bx_payment', 'stripe_cancel_subscription' - hook after a subscription was canceled
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_cancel_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `subscription_id` - [string] unique subscription id
+         *      - `subscription_object` - [object] an instance of subscription, redurned by payment provider
+         * @hook @ref hook-bx_payment-stripe_cancel_subscription
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_cancel_subscription 'bx_payment', 'stripe_v3_cancel_subscription' - hook after a subscription was canceled
+         * It's equivalent to @ref hook-bx_payment-stripe_cancel_subscription
+         * @hook @ref hook-bx_payment-stripe_v3_cancel_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_cancel_subscription', 0, false, [
+            'subscription_id' => $sSubscriptionId,
+            'subscription_object' => &$oSubscription
+        ]);
+
+        return $oSubscription;
+    }
+
+    protected function _retrievePaymentMethod($sPaymentMethodId)
+    {
+        return false;
+    }
+
+    protected function _retrieveProduct($sId)
+    {
+        $oProduct = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_retrieve_product 'bx_payment', 'stripe_retrieve_product' - hook to override product data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_retrieve_product`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `product_id` - [string] by ref, unique product id, can be overridden in hook processing
+         *      - `product_object` - [object] by ref, an instance of product, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_retrieve_product
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_product 'bx_payment', 'stripe_v3_retrieve_product' - hook to override product data retrieved from payment provider
+         * It's equivalent to @ref hook-bx_payment-stripe_retrieve_product
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_product
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_product', 0, false, [
+            'product_id' => &$sId,
+            'product_object' => &$oProduct
+        ]);
+
+        if(!empty($oProduct))
+            return $oProduct;
+
+        try {
+            $oProduct = \Stripe\Product::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Product Error: ', $oException);
+        }
+
+        return $oProduct;
+    }
+
+    protected function _listPlans($iLimit = 100)
+    {
+        if($iLimit <= 0)
+            $iLimit = 1;
+        if($iLimit > 100)
+            $iLimit = 100;
+
+        try {
+            $oPlans = \Stripe\Plan::all(array('limit' => $iLimit));
+        }
+        catch (Exception $oException) {
+            return $this->_processException('List Plans Error: ', $oException);
+        }
+
+        return $oPlans;
+    }
+
+    protected function _retrieveEvent($sId) {
+        try {
+            $oEvent = \Stripe\Event::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Event Error: ', $oException);
+        }
+
+        return $oEvent;
+    }
+
+    protected function _processEvent()
+    {
+        $sInput = @file_get_contents("php://input");
+        $aEvent = json_decode($sInput, true);
+        if(empty($aEvent) || !is_array($aEvent)) 
+            return 404;
+
+        $sType = $aEvent['type'];
+        if(!in_array($sType, array('invoice.payment_succeeded', 'charge.refunded', 'customer.subscription.deleted')))
+            return 200;
+
+        $this->log('Webhooks: ' . (!empty($sType) ? $sType : ''), '', BX_LOG_INFO);
+        $this->log($aEvent, '', BX_LOG_INFO);
+
+        $sMethod = '_processEvent' . bx_gen_method_name($sType, array('.', '_', '-'));
+    	if(!method_exists($this, $sMethod))
+            return 200;
+
+    	return $this->$sMethod($aEvent) ? 200 : 403;
+    }
+
+    protected function _processEventInvoicePaymentSucceeded(&$aEvent)
+    {
+        $mixedResult = $this->_getDataInvoicePaymentSucceeded($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($mixedPending, $aPaid) = $mixedResult;
+        if(empty($mixedPending) || empty($aPaid))
+            return false;
+
+        $fChargeAmount = (float)$aPaid['amount'] / 100;
+        $sChargeCurrency = strtoupper($aPaid['currency']);
+
+        if(is_string($mixedPending))
+            return $this->_oModule->_oDb->insertStrpPaymentPending($mixedPending, $fChargeAmount, $sChargeCurrency);
+
+        if($this->_bCheckAmount && ((float)$mixedPending['amount'] != $fChargeAmount || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $sChargeCurrency) !== 0))
+            return false;
+
+        if($mixedPending['type'] == BX_PAYMENT_TYPE_RECURRING)
+            $this->_oModule->getObjectSubscriptions()->prolong($mixedPending);
+
+        return $this->_oModule->registerPayment($mixedPending);
+    }
+
+    protected function _processEventChargeRefunded(&$aEvent)
+    {
+        $mixedResult = $this->_getData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending) = $mixedResult;
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        return $this->_oModule->refundPayment($aPending);
+    }
+
+    protected function _processEventCustomerSubscriptionDeleted(&$aEvent)
+    {
+        $mixedResult = $this->_getData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending) = $mixedResult;
+        if(empty($aPending) || !is_array($aPending))
+            return true;
+
+        return $this->_oModule->getObjectSubscriptions()->cancelLocal($aPending);
+    }
+
+    protected function _processException($sMessage, &$oException)
+    {
+        $aError = $oException->getJsonBody();
+
+        $sMessage = $aError['error']['message'];
+        if(empty($sMessage))
+            $sMessage = $oException->getMessage();
+
+        $this->log($sMessage . $aError['error']['message'], '', BX_LOG_ERR);
+        $this->log($aError, '', BX_LOG_ERR);
+
+        return false;
+    }
+
+    protected function _getData(&$aEvent, $bRetrieve = true)
+    {
+        if($bRetrieve)
+            $oEvent = $this->_retrieveEvent($aEvent['id']);
+        else 
+            $oEvent = \Stripe\Util\Util::convertToStripeObject($aEvent, array());
+
+        if(empty($oEvent))
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $oEvent->data->object->subscription));
+        $oCharge = $this->_retrieveCharge($oEvent->data->object->charge);
+
+        return array($aPending, $oCharge);
+    }
+
+    protected function _getDataInvoicePaymentSucceeded(&$aEvent, $bRetrieve = true)
+    {
+        if($bRetrieve)
+            $oEvent = $this->_retrieveEvent($aEvent['id']);
+        else 
+            $oEvent = \Stripe\Util\Util::convertToStripeObject($aEvent, array());
+
+        if(empty($oEvent))
+            return false;
+
+        /**
+         * Note. $oEvent->data->object->subscription and $oEvent->data->object->charge 
+         * are checked for backward compatibility.
+         */
+        $sSubscriptionId = '';
+        if(!empty($oEvent->data->object->subscription))
+            $sSubscriptionId = $oEvent->data->object->subscription;
+        else if(!empty($oEvent->data->object->parent) && $oEvent->data->object->parent->type == 'subscription_details')
+            $sSubscriptionId = $oEvent->data->object->parent->subscription_details->subscription;
+        if(!$sSubscriptionId)
+            return false;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $sSubscriptionId]);
+
+        $aPaid = ['amount' => 0, 'currency' => ''];
+        if(!empty($oEvent->data->object->charge)) {
+            $oCharge = $this->_retrieveCharge($oEvent->data->object->charge);
+            if($oCharge)
+                $aPaid = [
+                    'amount' => $oCharge->amount,
+                    'currency' => $oCharge->currency
+                ];
+        }
+        else {
+            if(!empty($oEvent->data->object->amount_paid)) 
+                $aPaid['amount'] = $oEvent->data->object->amount_paid;
+            if(!empty($oEvent->data->object->currency))
+                $aPaid['currency'] = $oEvent->data->object->currency;
+        }
+
+        return [!empty($aPending) && is_array($aPending) ? $aPending : $sSubscriptionId, $aPaid];
+    }
+
+    protected function _getDataChangeDetailsRecurring($iPendingId)
+    {
+        $aResult = array();
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        list($iVendorId, $iModuleId, $iItemId) = $this->_oModule->_oConfig->descriptorS2A($aPending['items']);
+        if(empty($iModuleId) || empty($iVendorId) || (int)$iVendorId != (int)$aPending['seller_id'])
+            return $aResult;
+
+        $aItems = $this->_oModule->callGetCartItems((int)$iModuleId, array($iVendorId));
+        if(empty($aItems) || !is_array($aItems))
+            return $aResult;
+
+        $oPlans = $this->_listPlans();
+        if($oPlans === false)
+            return $aResult;
+
+        $aPlans = $oPlans->jsonSerialize();
+        if(empty($aPlans) || !is_array($aPlans) || empty($aPlans['data']) || !is_array($aPlans['data']))
+            return $aResult;
+
+        $aPlans = $aPlans['data'];
+
+        $aPlanNames = array();
+        foreach($aPlans as $aPlan)
+            $aPlanNames[] = $aPlan['id'];
+        if(empty($aPlanNames) || !is_array($aPlanNames))
+            return $aResult;
+
+        foreach($aItems as $aItem) {
+            $fPrice = $this->_oModule->_oConfig->getPrice(BX_PAYMENT_TYPE_RECURRING, $aItem);
+            if($fPrice == 0 || (int)$aItem['id'] == (int)$iItemId || !in_array($aItem['name'], $aPlanNames))
+                continue;
+
+            $aResult[] = array('key' => $aItem['id'], 'value' => $aItem['title']);
+        }
+
+        return $aResult;
+    }
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);
+
+    	return $this->_oModule->_oTemplate->parseHtmlByName('strp_button_' . $sType . '.html', array(
+            'type' => $sType,
+            'caption' => _t($this->_sLangsPrefix . 'strp_txt_checkout_with_' . $sType, $this->_sCaption),  
+            'onclick' => $sJsMethod,
+            'js_object' => $this->_oModule->_oConfig->getJsObject($this->_sName),
+            'js_code' => $sJsCode,
+    	));
+    }
+}
+
+/** @} */

+ 1192 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderStripeConnect.php

@@ -0,0 +1,1192 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxPaymentProviderStripeBasic.php');
+
+class BxPaymentProviderStripeConnect extends BxPaymentProviderStripeBasic implements iBxBaseModPaymentProvider
+{
+    protected $_sModuleSc;
+
+    protected $_oStripe;
+
+    protected $_iAmountPrecision;
+
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'stripe_v3.js'
+        );
+
+        $this->_sModuleSc = 'bx_stripe_connect';
+                
+        $this->_oStripe = null;
+
+        $this->_iAmountPrecision = 2;
+    }
+
+    public function getMode($iVendorId, $aParams = [])
+    {
+        if(($sMethod = 'get_option_value_mode') && bx_is_srv($this->_sModuleSc, $sMethod))
+            return bx_srv($this->_sModuleSc, $sMethod, [$iVendorId, $aParams]);
+        else
+            return _t('_undefined');
+    }
+
+    public function getConnect($iVendorId, $aParams = [])
+    {
+        if(($sMethod = 'get_connect_code') && bx_is_srv($this->_sModuleSc, $sMethod))
+            return bx_srv($this->_sModuleSc, $sMethod, [$iVendorId, $aParams]);
+        else
+            return _t('_undefined');
+    }
+
+    public function getLiveAccountId($iVendorId, $aParams = [])
+    {
+        if(($sMethod = 'get_option_value_live_account_id') && bx_is_srv($this->_sModuleSc, $sMethod) && ($sAccountId = bx_srv($this->_sModuleSc, $sMethod, [$iVendorId, $aParams])))
+            return $sAccountId;
+        else
+            return _t('_undefined');
+    }
+
+    public function getTestAccountId($iVendorId, $aParams = [])
+    {
+        if(($sMethod = 'get_option_value_test_account_id') && bx_is_srv($this->_sModuleSc, $sMethod) && ($sAccountId = bx_srv($this->_sModuleSc, $sMethod, [$iVendorId, $aParams])))
+            return $sAccountId;
+        else
+            return _t('_undefined');
+    }
+
+    public function actionGetSessionRecurring()
+    {
+        $aClient = $this->_oModule->getProfileInfo();
+
+        $aParams = array(
+            'seller_id' => (int)bx_get('seller_id'),
+            'seller_provider' => bx_process_input(bx_get('seller_provider')),
+            'module_id' => (int)bx_get('module_id'),
+            'item_id' => (int)bx_get('item_id'),
+            'item_count' => (int)bx_get('item_count'),
+            'item_addons' => '',
+            'redirect' => bx_process_input(bx_get('redirect')),
+            'custom' => bx_process_input(bx_get('custom')),
+        );
+        
+        if(($mixedItemAddons = bx_get('item_addons')) !== false) {
+            $mixedItemAddons = bx_process_input($mixedItemAddons);
+            if(!is_array($mixedItemAddons))
+                $mixedItemAddons = strpos($mixedItemAddons, ',') !== false ? explode(',', $mixedItemAddons) : [$mixedItemAddons];
+
+            $aParams['item_addons'] = $this->_oModule->_oConfig->a2s($mixedItemAddons);
+        }
+
+        $aItems = array($this->_oModule->_oConfig->descriptorA2S(array(
+            'seller_id' => $aParams['seller_id'],
+            'module_id' => $aParams['module_id'],
+            'item_id' => $aParams['item_id'],
+            'item_count' => $aParams['item_count'],
+            'item_addons' => $aParams['item_addons'],
+        )));
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_RECURRING, $aClient['id'], $aParams['seller_id'], $aItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return echoJson(array('msg' => _t('_bx_payment_err_nothing_selected')));
+
+        $aItem = reset($aCartInfo['items']);
+
+        $aSessionParams = array(
+            'cancel_url' => $aItem['url'],
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_SUBSCRIBE_JSON'), array_merge($aParams, array(
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            )), false)
+        );
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_RECURRING, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return echoJson(array('msg' => _t('_bx_payment_err_cannot_perform')));
+
+        $sJsObject = $this->getJsObject(array(
+            'iModuleId' => $aParams['module_id'],
+            'iSellerId' => $aParams['seller_id'],
+            'iItemId' => $aParams['item_id']
+        ));
+
+        return echoJson(array(
+            'code' => 0, 
+            'session_id' => $mixedSession['id'],
+            'eval' => $sJsObject . '.onSubscribe(oData);'
+        ));
+    }
+
+    public function authorizeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sSessionId = bx_process_input(bx_get('session_id'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                return [
+                    'code' => BX_PAYMENT_RESULT_SUCCESS,
+                    'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
+                        'mode' => $mixedResult['mode'],
+                        'order_id' => $mixedResult['order_id'],
+                        'customer_id' => $mixedResult['customer_id'], 
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ))
+                ];
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return $this->_sLangsPrefix . 'err_not_supported';
+        }
+    }
+
+    public function captureAuthorizedCheckout($sOrderAuth, $mixedPending, $aInfo)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+        if(empty($aPending) || !is_array($aPending))
+            return ['code' => 2, 'message' => $this->_sLangsPrefix . 'err_empty_order'];
+
+        $bPaid = false;
+        $sOrder = '';
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oPaymentIntent = $this->_createPaymentIntent($sOrderAuth, $aInfo['items_price'], $aInfo['vendor_currency_code']);
+                if($oPaymentIntent === false)
+                    return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $aPaymentIntent = $oPaymentIntent->jsonSerialize();
+                if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
+                    return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $bPaid = $aPaymentIntent['status'] == 'succeeded';
+                $sOrder = $aPaymentIntent['id'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return ['code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_supported'];
+        }
+
+        $aResult = [
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => $this->_sLangsPrefix . 'strp_msg_charged',
+            'pending_id' => $aPending['id'],
+            'paid' => $bPaid
+        ];
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], [
+            'order' => $sOrder,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message']),
+        ]);
+
+        return $aResult;
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sSessionId = bx_process_input(bx_get('session_id'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
+                if($mixedResult === false || $mixedResult['status'] != 'paid')
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_RECURRING, $sSessionId);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+                break;
+        }
+
+        $aProcessed = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $mixedResult['order_id']]);
+        if(!empty($aProcessed) && is_array($aProcessed) && (int)$aProcessed['processed'] != 0 && $aProcessed['id'] != $iPendingId)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        $aData = [
+            'mode' => $mixedResult['mode'],
+            'order_id' => $mixedResult['order_id'],
+            'customer_id' => $mixedResult['customer_id'], 
+            'pending_id' => $aPending['id'],
+            'redirect' => $sRedirect
+        ];
+
+        if(bx_is_api())
+            return $this->_oModule->serviceFinalizeCheckout($this->_sName, $aVendor['id'], $aData);
+
+        header("Location: " . $this->getReturnDataUrl($aVendor['id'], $aData));
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $sMode = bx_process_input($aData['mode']);
+    	$sOrderId = bx_process_input($aData['order_id']);
+    	$sCustomerId = bx_process_input($aData['customer_id']);
+        $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+        if(empty($iPendingId))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $sRedirect = bx_process_input($aData['redirect']);
+
+        $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 . 'err_already_processed');
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'customer_id' => '',
+            'subscription_id' => '',
+            'client_name' => '',
+            'client_email' => '',
+            'authorized' => false,
+            'paid' => false,
+            'trial' => false,
+            'redirect' => $sRedirect
+        );
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_SINGLE, $sCustomerId);
+                if($oCustomer === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $sMessage = '';
+                $bPaid = $bAuthorized = false;
+                switch($sMode) {
+                    case 'setup':
+                        $oSetupIntent = $this->_retrieveSetupIntent($sOrderId);
+                        if($oSetupIntent === false)
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+                        
+                        $aSetupIntent = $oSetupIntent->jsonSerialize();
+                        if(empty($aSetupIntent) || !is_array($aSetupIntent))
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+                                
+                        $sMessage = $this->_sLangsPrefix . 'strp_msg_authorized';
+                        $bAuthorized = $aSetupIntent['status'] == 'succeeded';
+                        break;
+
+                    case 'payment':
+                        $oPaymentIntent = $this->_retrievePaymentIntent($sOrderId);
+                        if($oPaymentIntent === false)
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                        $aPaymentIntent = $oPaymentIntent->jsonSerialize();
+                        if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                        $sMessage = $this->_sLangsPrefix . 'strp_msg_charged';
+                        $bPaid = $aPaymentIntent['status'] == 'succeeded';
+                        break;
+                }
+
+                $aResult = array_merge($aResult, array(
+                    'message' => $sMessage,
+                    'client_email' => $aCustomer['email'],
+                    'authorized' => $bAuthorized,
+                    'paid' => $bPaid,
+                ));
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+                $oSubscription = $this->_retrieveSubscription($sCustomerId, $sOrderId);
+                if($oCustomer === false || $oSubscription === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                $aSubscription = $oSubscription->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer) || empty($aSubscription) || !is_array($aSubscription))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aResult = array_merge($aResult, [
+                    'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
+                    'customer_id' => $sCustomerId,
+                    'subscription_id' => $sOrderId,
+                    'client_email' => $aCustomer['email'],
+                    'trial' => $this->isSubscriptionStatus(BX_PAYMENT_SBS_STATUS_TRIAL, $aSubscription)
+                ]);
+
+                $aPaymentPending = $this->_oModule->_oDb->getStrpPaymentPending($sOrderId);
+                if(empty($aPaymentPending) || !is_array($aPaymentPending)) 
+                    break;
+
+                if($this->_bCheckAmount && ((float)$aPending['amount'] != (float)$aPaymentPending['amount'] || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $aPaymentPending['currency']) !== 0))
+                    break;
+
+                $aResult['paid'] = true;
+                break;
+        }
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrderId,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
+    {
+        if(!isset($aParams['sAction']))
+            return '';
+
+        return $aParams['sAction'] . parent::getButtonSingle($iClientId, $iVendorId, $aParams);
+    }
+
+    public function overwriteCheckoutParamsSingle($aParams, &$oGrid)
+    {
+        $aClient = $this->_oModule->getProfileInfo();
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $aClient['id'], $aParams['seller_id'], $aParams['items']);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return array('msg' => _t('_bx_payment_err_nothing_selected'));
+
+        $aSessionParams = array(
+            'cancel_url' => $oCart->serviceGetCartUrl($aParams['seller_id']),
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), array_merge($aParams, array(
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            )), false)
+        );
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_SINGLE, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return array('msg' => _t('_bx_payment_err_cannot_perform'));
+
+        return array(
+            'eval' => $this->_oModule->_oConfig->getJsObject($this->_sName) . '.onCartCheckout(oData);', 
+            'session_id' => $mixedSession['id']
+        );
+    }
+
+    /**
+     * Note. Isn't used for now in default version.
+     */
+    public function createSessionAuthorize($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
+    {
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return false;
+
+        $aSessionParams = array_merge([
+            'cancel_url' => $oCart->serviceGetCartUrl($iSellerId),
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_AUTHORIZE') . $sType . '/', [
+                'provider' => $this->_sName,
+                'seller_id' => $iSellerId,
+                'items' => $sItems,
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            ], false)
+        ], $aSessionParams);
+
+        $mixedSession = $this->_createSession('authorize', $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return false;
+
+        return $mixedSession['id'];
+    }
+
+    /*
+     * https://stripe.com/docs/checkout/embedded/quickstart?client=react&lang=php
+     */
+    public function createSessionPaymentEmbedded($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
+    {
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return false;
+
+        $aSessionParams = array_merge([
+            'ui_mode' => 'embedded',
+            'return_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), [
+                'provider' => $this->_sName,
+                'seller_id' => $iSellerId,
+                'items' => $sItems,
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            ], false)
+        ], $aSessionParams);
+
+        if(strpos($aSessionParams['return_url'], 'session_id') === false)
+            $aSessionParams['return_url'] .= '&session_id={CHECKOUT_SESSION_ID}';
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_SINGLE, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return false;
+
+        return $mixedSession['client_secret'];
+    }
+
+    public function createTax($sName, $fPercentage, $bInclusive = false)
+    {
+        $oTax = null;
+        $aTax = [
+            'display_name' => $sName,
+            'percentage' => $fPercentage,
+            'inclusive' => $bInclusive,
+        ];
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_tax 'bx_payment', 'stripe_v3_create_tax' - hook to override tax data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_tax`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
+         *      - `tax_params` - [array] by ref, array with tax parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_tax
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_tax', 0, false, [
+            'tax_object' => &$oTax, 
+            'tax_params' => &$aTax
+        ]);
+
+        try {
+            if(empty($oTax))
+                $oTax = $this->_getStripe()->taxRates->create($aTax);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Tax Error: ', $oException);
+        }
+
+        $aResult = $oTax->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult))
+            return false;
+
+        return $aResult['id'];
+    }
+
+    public function retrieveTax($sId)
+    {
+        $oTax = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_tax 'bx_payment', 'stripe_v3_retrieve_tax' - hook to override tax data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_tax`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `tax_id` - [string] by ref, unique tax id, can be overridden in hook processing
+         *      - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_tax
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_tax', 0, false, [
+            'tax_id' => &$sId,
+            'tax_object' => &$oTax
+        ]);
+
+        try {
+            if(empty($oTax))
+                $oTax = $this->_getStripe()->taxRates->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Tax Error: ', $oException);
+        }
+
+        return $oTax;
+    }
+
+    public function getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        $sCode = $this->_getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_get_code_session 'bx_payment', 'stripe_v3_get_code_session' - hook to override session verification code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_get_code_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `amount` - [float] session amount
+         *      - `currency` - [string] session currency code
+         *      - `override_result` - [string] by ref, verification code, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_get_code_session
+         */        
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_code_session', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'amount' => $fAmount,
+            'currency' => $sCurrency,
+            'override_result' => &$sCode
+        ]);
+
+        return $sCode;
+    }
+
+    public function checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
+    {
+        $bCheckResult = $this->_checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_verify_session 'bx_payment', 'stripe_v3_verify_session' - hook to override checking of session verification code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_verify_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `result` - [array] results array received from payment provider
+         *      - `override_result` - [boolean] by ref, is verification passed or not, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_verify_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_verify_session', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'result' => $aResult,
+            'override_result' => &$bCheckResult
+        ]);
+
+        return $bCheckResult;
+    }
+
+    protected function _getStripe()
+    {
+        if(empty($this->_oStripe))
+            $this->_oStripe = new \Stripe\StripeClient($this->_getSecretKey());
+
+        return $this->_oStripe;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/customers/retrieve
+     */
+    protected function _retrieveCustomer($sType, $sId)
+    {
+        $oCustomer = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_customer 'bx_payment', 'stripe_v3_retrieve_customer' - hook to override customer data retrieved from payment provider
+         * It's equivalent to @ref hook-bx_payment-stripe_retrieve_customer
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_customer
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_customer', 0, false, [
+            'type' => $sType,
+            'customer_id' => &$sId,
+            'customer_object' => &$oCustomer
+        ]);
+
+        try {
+            if(empty($oCustomer))
+                $oCustomer = $this->_getStripe()->customers->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Customer Error: ', $oException);
+        }
+
+        return $oCustomer;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/checkout/sessions/create
+     */
+    protected function _createSession($sType, $aParams, &$aClient, &$aCartInfo)
+    {
+        $sMode = '';
+        $aLineItems = $aMetaItems = [];
+        $bVerify = true;
+
+        switch($sType) {
+            case 'authorize':
+                $sMode = 'setup';
+                $bVerify = false;
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
+                    if(!empty($aItem['addons']) && is_array($aItem['addons']))
+                        foreach($aItem['addons'] as $aAddon)
+                            $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
+                }
+
+                $aParams['customer_creation'] = 'always';
+                break;
+
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sMode = 'payment';
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aProductData = [
+                        'name' => $aItem['title']
+                    ];
+                    if(!empty($aItem['description']))
+                        $aProductData['description'] = strmaxtextlen(strip_tags($aItem['description']), 60, '...');
+
+                    $aLineItems[] = [
+                        'price_data' => [
+                            'currency' => $aCartInfo['vendor_currency_code'],
+                            'product_data' => $aProductData,
+                            'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aItem, $this->_iAmountPrecision),
+                        ],
+                        'quantity' => $aItem['quantity'],
+                    ];
+
+                    $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
+
+                    if(!empty($aItem['addons']) && is_array($aItem['addons']))
+                        foreach($aItem['addons'] as $aAddon) {
+                            $aAddonData = [
+                                'name' => $aAddon['title']
+                            ];
+                            if(!empty($aAddon['description']))
+                                $aAddonData['description'] = strmaxtextlen(strip_tags($aAddon['description']), 60, '...');
+
+                            $aLineItems[] = [
+                                'price_data' => [
+                                    'currency' => $aCartInfo['vendor_currency_code'],
+                                    'product_data' => $aAddonData,
+                                    'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aAddon, $this->_iAmountPrecision),
+                                ],
+                                'quantity' => $aAddon['quantity'],
+                            ];
+
+                            $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
+                        }
+                }
+
+                $aParams['customer_creation'] = 'always';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sMode = 'subscription';
+                $iTrial = 0;
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aLineItems[] = [
+                        'price' => $aItem['name'],
+                        'quantity' => $aItem['quantity'],
+                    ];
+
+                    if((int)$aItem['trial_recurring'] > 0)
+                        $iTrial = (int)$aItem['trial_recurring'];
+
+                    $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
+                    
+                    if(!empty($aItem['addons']) && is_array($aItem['addons']))
+                        foreach($aItem['addons'] as $aAddon) {
+                            $aLineItems[] = [
+                                'price' => $aAddon['name'],
+                                'quantity' => $aAddon['quantity'],
+                            ];
+
+                            $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
+                        }
+                }
+
+                if($iTrial > 0) {
+                    $bVerify = false;
+
+                    $aParams['subscription_data'] = [
+                        'trial_period_days' => $iTrial
+                    ];
+                }
+
+                break;
+        }
+
+        $oSession = null;
+        $aSession = array_merge([
+            'mode' => $sMode,
+            'payment_method_types' => ['card'],
+            'customer_email' => !empty($aClient['email']) ? $aClient['email'] : ''
+        ], $aParams);
+
+        $bLineItems = !empty($aLineItems);
+        $aSession['line_items'] = $aLineItems;
+
+        $bMetaData = !empty($aMetaItems);
+        if($bMetaData) {
+            $aSession['metadata'] = [
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'type' => $sType, 
+                'items' => $this->_oModule->_oConfig->descriptorsA2S($aMetaItems)
+            ];
+
+            if($bVerify) {
+                $fAmount = 100 * round((float)$aCartInfo['items_price'], $this->_iAmountPrecision);
+                $aSession['metadata']['verification'] = $this->getVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code']);
+            }
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_session 'bx_payment', 'stripe_v3_create_session' - hook to override session data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_session`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
+         *      - `session_params` - [array] by ref, array with session parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_session', 0, false, [
+            'session_object' => &$oSession, 
+            'session_params' => &$aSession
+        ]);
+
+        try {
+            if(empty($oSession))
+                $oSession = $this->_getStripe()->checkout->sessions->create($aSession);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Session Error: ', $oException);
+        }
+
+        $aResult = $oSession->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult))
+            return false;
+
+        if($bVerify && !$this->checkVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $aResult))
+            return false;
+
+        return $aResult;
+    }
+
+    protected function _getSession($sType, $sId)
+    {
+        $oSession = $this->_retrieveSession($sId);
+        if($oSession === false)
+            return array();
+
+        $aSession = $oSession->jsonSerialize();
+        if(empty($aSession) || !is_array($aSession))
+            return array();
+
+        $sMode = 'payment';
+        if(!empty($aSession['mode']))
+            $sMode = $aSession['mode'];
+        
+        $aResult = array(
+            'id' => $aSession['id'],
+            'mode' => $sMode,
+            'order_id' => '',
+            'customer_id' => $aSession['customer'],
+            'status' => $aSession['payment_status']
+        );
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aResult['order_id'] = $aSession[($sMode == 'setup' ? 'setup' : 'payment') . '_intent'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aResult['order_id'] = $aSession['subscription'];
+                break;
+        }
+
+        return $aResult;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/checkout/sessions/retrieve
+     */
+    protected function _retrieveSession($sId)
+    {
+        $oSession = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_session 'bx_payment', 'stripe_v3_retrieve_session' - hook to override session data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `session_id` - [string] by ref, unique session id, can be overridden in hook processing
+         *      - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_session', 0, false, [
+            'session_id' => &$sId,
+            'session_object' => &$oSession
+        ]);
+
+        try {
+            if(empty($oSession))
+                $oSession = $this->_getStripe()->checkout->sessions->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Session Error: ', $oException);
+        }
+
+        return $oSession;
+    }
+    
+    
+    /*
+     * Related Docs: https://stripe.com/docs/api/setup_intents/retrieve
+     */
+    protected function _retrieveSetupIntent($sId)
+    {
+        $oSetupIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_setup_intent 'bx_payment', 'stripe_v3_retrieve_setup_intent' - hook to override SetupIntent data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_setup_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
+         *      - `setup_intent_object` - [object] by ref, an instance of SetupIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_setup_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_setup_intent', 0, false, [
+            'setup_intent_id' => &$sId,
+            'setup_intent_object' => &$oSetupIntent
+        ]);
+
+        try {
+            if(empty($oSetupIntent))
+                $oSetupIntent = $this->_getStripe()->setupIntents->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Setup Intent Error: ', $oException);
+        }
+
+        return $oSetupIntent;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_intents/create
+     */
+    protected function _createPaymentIntent($sSetupIntentId, $fAmount, $sCurrency, $bConfirm = true)
+    {
+        $oPaymentIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_payment_intent 'bx_payment', 'stripe_v3_create_payment_intent' - hook to override PaymentIntent data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_payment_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
+         *      - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_payment_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_payment_intent', 0, false, [
+            'setup_intent_id' => &$sSetupIntentId,
+            'payment_intent_object' => &$oPaymentIntent
+        ]);
+
+        try {
+            if(empty($oPaymentIntent)) {
+                $oSetupIntent = $this->_retrieveSetupIntent($sSetupIntentId);
+                if($oSetupIntent === false)
+                    return false;
+
+                $aSetupIntent = $oSetupIntent->jsonSerialize();
+                if(empty($aSetupIntent) || !is_array($aSetupIntent))
+                    return false;
+
+                $oPaymentIntent = $this->_getStripe()->paymentIntents->create([
+                    'amount' => 100 * round($fAmount, $this->_iAmountPrecision),
+                    'currency' => strtolower($sCurrency),
+                    'customer' => $aSetupIntent['customer'],
+                    'payment_method' => $aSetupIntent['payment_method'],
+                    'confirm' => $bConfirm
+                ]);
+            }
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Intent Error: ', $oException);
+        }
+
+        return $oPaymentIntent;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_intents/retrieve
+     */
+    protected function _retrievePaymentIntent($sId)
+    {
+        $oPaymentIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_payment_intent 'bx_payment', 'stripe_v3_retrieve_payment_intent' - hook to override PaymentIntent data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_payment_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `payment_intent_id` - [string] by ref, unique PaymentIntent id, can be overridden in hook processing
+         *      - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_payment_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_payment_intent', 0, false, [
+            'payment_intent_id' => &$sId,
+            'payment_intent_object' => &$oPaymentIntent
+        ]);
+
+        try {
+            if(empty($oPaymentIntent))
+                $oPaymentIntent = $this->_getStripe()->paymentIntents->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Intent Error: ', $oException);
+        }
+
+        return $oPaymentIntent;
+    }
+    
+    /*
+     * Related Docs: https://stripe.com/docs/api/subscriptions/retrieve
+     */
+    protected function _retrieveSubscription($sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_subscription 'bx_payment', 'stripe_v3_retrieve_subscription' - hook to override subscription data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `subscription_id` - [string] by ref, unique subscription id, can be overridden in hook processing
+         *      - `subscription_object` - [object] by ref, an instance of subscription, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_subscription', 0, false, [
+            'subscription_id' => &$sSubscriptionId,
+            'subscription_object' => &$oSubscription
+        ]);
+
+        try {
+            if(empty($oSubscription))
+                $oSubscription = $this->_getStripe()->subscriptions->retrieve($sSubscriptionId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Subscription Error: ', $oException);
+        }
+
+        return $oSubscription;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/tokens/create_card
+     */
+    protected function _createToken($aCard)
+    {
+        try {
+            $oToken = $this->_getStripe()->tokens->create(['card' => $aCard]);
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Token Error: ', $oException);
+        }
+
+        return $oToken->jsonSerialize();
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/cards/create
+     */
+    protected function _createCard($sType, $sCustomerId, $sToken)
+    {
+        try {
+            $oCard = $this->_getStripe()->customers->createSource($sCustomerId, [
+                'source' => $sToken
+            ]);
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Card Error: ', $oException);
+        }
+
+        return $oCard->jsonSerialize();
+    }
+
+    protected function _retrieveCard($sCustomerId, $sCardId = '')
+    {
+        try {
+            $oCustomer = $this->_getStripe()->customers->retrieve($sCustomerId);
+
+            if(empty($sCardId))
+                $sCardId = $oCustomer->default_source;
+            if(empty($sCardId))
+                return false;
+
+            $oCard = $this->_getStripe()->customers->retrieveSource($sCustomerId, $sCardId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Card Error: ', $oException);
+        }
+
+        return $oCard;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_methods/retrieve
+     */
+    protected function _retrievePaymentMethod($sPaymentMethodId)
+    {
+        try {
+            $oPaymentMethod = $this->_getStripe()->paymentMethods->retrieve($sPaymentMethodId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Method Error: ', $oException);
+        }
+
+        return $oPaymentMethod;
+    }
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);
+
+    	if($sType == BX_PAYMENT_TYPE_SINGLE)
+            return $sJsCode;
+
+        return parent::_getButton($sType, $iClientId, $iVendorId);
+    }
+
+    protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        $sClientEmail = '';
+    	if(!empty($iClientId) && ($oClient = BxDolProfile::getInstance($iClientId)) !== false)
+            $sClientEmail = $oClient->getAccountObject()->getEmail();
+
+        $sPublicKey = '';
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_get_button 'bx_payment', 'stripe_v3_get_button' - hook to override checkout/subscibe button
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_get_button`
+         * - $object_id - not used
+         * - $sender_id - client (buyer) profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] by ref, payment type ('single' or 'recurring'), can be overridden in hook processing
+         *      - `public_key` - [string] by ref, public key from Stripe account, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_get_button
+         */
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, [
+            'type' => &$sType, 
+            'public_key' => &$sPublicKey
+        ]);
+
+        $sJsMethod = '';
+        $sJsObject = $this->getJsObject($aParams);
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sJsMethod = 'void(0)';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sJsMethod = $sJsObject . '.subscribe(this)';
+                break;
+        }
+
+        return array($this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+            'js_object' => $sJsObject,
+            'sProvider' => $this->_sName,
+            'sPublicKey' => !empty($sPublicKey) ? $sPublicKey : $this->_getPublicKey(),
+            'sVendorName' => '',
+            'sVendorCurrency' => '',
+            'sVendorIcon' => '',
+            'sClientEmail' => $sClientEmail,
+        ), $aParams)), $sJsMethod);
+    }
+
+    protected function _getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        return md5(implode('#-#', array(
+            (int)$iVendorId,
+            (int)$iCustomerId,
+            (float)$fAmount,
+            strtoupper($sCurrency)
+        )));
+    }
+
+    protected function _checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
+    {
+        return !empty($aResult['metadata']['verification']) && $aResult['metadata']['verification'] == $this->getVerificationCodeSession($iVendorId, $iCustomerId, $aResult['amount_total'], $aResult['currency']);
+    }
+
+    protected function _processException($sMessage, &$oException)
+    {
+        if(method_exists($oException, 'getError')) {
+            $sError = $oException->getError()->message;
+            $aError = $oException->getError()->toArray();
+        }
+        else { 
+            $sError = $oException->getMessage();
+            $aError = array();
+        }
+
+        $this->log($sMessage . $sError, '', BX_LOG_ERR);
+        if(!empty($aError))
+            $this->log($aError, '', BX_LOG_ERR);
+
+        return false;
+    }
+}
+
+/** @} */

+ 1186 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentProviderStripeV3.php

@@ -0,0 +1,1186 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxPaymentProviderStripeBasic.php');
+
+class BxPaymentProviderStripeV3 extends BxPaymentProviderStripeBasic implements iBxBaseModPaymentProvider
+{
+    protected $_oStripe;
+
+    protected $_iAmountPrecision;
+
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'stripe_v3.js'
+        );
+
+        $this->_oStripe = null;
+
+        $this->_iAmountPrecision = 2;
+    }
+
+    public function actionGetSessionRecurring()
+    {
+        $aClient = $this->_oModule->getProfileInfo();
+
+        $aParams = array(
+            'seller_id' => (int)bx_get('seller_id'),
+            'seller_provider' => bx_process_input(bx_get('seller_provider')),
+            'module_id' => (int)bx_get('module_id'),
+            'item_id' => (int)bx_get('item_id'),
+            'item_count' => (int)bx_get('item_count'),
+            'item_addons' => '',
+            'redirect' => bx_process_input(bx_get('redirect')),
+            'custom' => bx_process_input(bx_get('custom')),
+        );
+        
+        if(($mixedItemAddons = bx_get('item_addons')) !== false) {
+            $mixedItemAddons = bx_process_input($mixedItemAddons);
+            if(!is_array($mixedItemAddons))
+                $mixedItemAddons = strpos($mixedItemAddons, ',') !== false ? explode(',', $mixedItemAddons) : [$mixedItemAddons];
+
+            $aParams['item_addons'] = $this->_oModule->_oConfig->a2s($mixedItemAddons);
+        }
+
+        $aItems = array($this->_oModule->_oConfig->descriptorA2S(array(
+            'seller_id' => $aParams['seller_id'],
+            'module_id' => $aParams['module_id'],
+            'item_id' => $aParams['item_id'],
+            'item_count' => $aParams['item_count'],
+            'item_addons' => $aParams['item_addons'],
+        )));
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_RECURRING, $aClient['id'], $aParams['seller_id'], $aItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return echoJson(array('msg' => _t('_bx_payment_err_nothing_selected')));
+
+        $aItem = reset($aCartInfo['items']);
+
+        $aSessionParams = array(
+            'cancel_url' => $aItem['url'],
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_SUBSCRIBE_JSON'), array_merge($aParams, array(
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            )), false)
+        );
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_RECURRING, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return echoJson(array('msg' => _t('_bx_payment_err_cannot_perform')));
+
+        $sJsObject = $this->getJsObject(array(
+            'iModuleId' => $aParams['module_id'],
+            'iSellerId' => $aParams['seller_id'],
+            'iItemId' => $aParams['item_id']
+        ));
+
+        return echoJson(array(
+            'code' => 0, 
+            'session_id' => $mixedSession['id'],
+            'eval' => $sJsObject . '.onSubscribe(oData);'
+        ));
+    }
+
+    public function authorizeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sSessionId = bx_process_input(bx_get('session_id'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                return [
+                    'code' => BX_PAYMENT_RESULT_SUCCESS,
+                    'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
+                        'mode' => $mixedResult['mode'],
+                        'order_id' => $mixedResult['order_id'],
+                        'customer_id' => $mixedResult['customer_id'], 
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ))
+                ];
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return $this->_sLangsPrefix . 'err_not_supported';
+        }
+    }
+
+    public function captureAuthorizedCheckout($sOrderAuth, $mixedPending, $aInfo)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+        if(empty($aPending) || !is_array($aPending))
+            return ['code' => 2, 'message' => $this->_sLangsPrefix . 'err_empty_order'];
+
+        $bPaid = false;
+        $sOrder = '';
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oPaymentIntent = $this->_createPaymentIntent($sOrderAuth, $aInfo['items_price'], $aInfo['vendor_currency_code']);
+                if($oPaymentIntent === false)
+                    return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $aPaymentIntent = $oPaymentIntent->jsonSerialize();
+                if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
+                    return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+                $bPaid = $aPaymentIntent['status'] == 'succeeded';
+                $sOrder = $aPaymentIntent['id'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                return ['code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_supported'];
+        }
+
+        $aResult = [
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => $this->_sLangsPrefix . 'strp_msg_charged',
+            'pending_id' => $aPending['id'],
+            'paid' => $bPaid
+        ];
+
+        //--- Update pending transaction
+        $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], [
+            'order' => $sOrder,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message']),
+        ]);
+
+        return $aResult;
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+        $sSessionId = bx_process_input(bx_get('session_id'));
+
+    	if(empty($aCartInfo['items']) || !is_array($aCartInfo['items']))
+            return $this->_sLangsPrefix . 'err_empty_items';
+
+        $aClient = $this->_oModule->getProfileInfo();
+        $aVendor = $this->_oModule->getProfileInfo($aCartInfo['vendor_id']);
+
+        $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 $this->_sLangsPrefix . 'err_already_processed';
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_SINGLE, $sSessionId);
+                if($mixedResult === false || $mixedResult['status'] != 'paid')
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_RECURRING, $sSessionId);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+                break;
+        }
+
+        $aProcessed = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $mixedResult['order_id']]);
+        if(!empty($aProcessed) && is_array($aProcessed) && (int)$aProcessed['processed'] != 0 && $aProcessed['id'] != $iPendingId)
+            return $this->_sLangsPrefix . 'err_already_processed';
+
+        $aData = [
+            'mode' => $mixedResult['mode'],
+            'order_id' => $mixedResult['order_id'],
+            'customer_id' => $mixedResult['customer_id'], 
+            'pending_id' => $aPending['id'],
+            'redirect' => $sRedirect
+        ];
+
+        if(bx_is_api())
+            return $this->_oModule->serviceFinalizeCheckout($this->_sName, $aVendor['id'], $aData);
+
+        header("Location: " . $this->getReturnDataUrl($aVendor['id'], $aData));
+        exit;
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $sMode = bx_process_input($aData['mode']);
+    	$sOrderId = bx_process_input($aData['order_id']);
+    	$sCustomerId = bx_process_input($aData['customer_id']);
+        $iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+        if(empty($iPendingId))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $sRedirect = bx_process_input($aData['redirect']);
+
+        $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 . 'err_already_processed');
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'customer_id' => '',
+            'subscription_id' => '',
+            'client_name' => '',
+            'client_email' => '',
+            'authorized' => false,
+            'paid' => false,
+            'trial' => false,
+            'redirect' => $sRedirect
+        );
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_SINGLE, $sCustomerId);
+                if($oCustomer === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $sMessage = '';
+                $bPaid = $bAuthorized = false;
+                switch($sMode) {
+                    case 'setup':
+                        $oSetupIntent = $this->_retrieveSetupIntent($sOrderId);
+                        if($oSetupIntent === false)
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+                        
+                        $aSetupIntent = $oSetupIntent->jsonSerialize();
+                        if(empty($aSetupIntent) || !is_array($aSetupIntent))
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+                                
+                        $sMessage = $this->_sLangsPrefix . 'strp_msg_authorized';
+                        $bAuthorized = $aSetupIntent['status'] == 'succeeded';
+                        break;
+
+                    case 'payment':
+                        $oPaymentIntent = $this->_retrievePaymentIntent($sOrderId);
+                        if($oPaymentIntent === false)
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                        $aPaymentIntent = $oPaymentIntent->jsonSerialize();
+                        if(empty($aPaymentIntent) || !is_array($aPaymentIntent))
+                            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                        $sMessage = $this->_sLangsPrefix . 'strp_msg_charged';
+                        $bPaid = $aPaymentIntent['status'] == 'succeeded';
+                        break;
+                }
+
+                $aResult = array_merge($aResult, array(
+                    'message' => $sMessage,
+                    'client_email' => $aCustomer['email'],
+                    'authorized' => $bAuthorized,
+                    'paid' => $bPaid,
+                ));
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_RECURRING, $sCustomerId);
+                $oSubscription = $this->_retrieveSubscription($sCustomerId, $sOrderId);
+                if($oCustomer === false || $oSubscription === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                $aSubscription = $oSubscription->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer) || empty($aSubscription) || !is_array($aSubscription))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aResult = array_merge($aResult, [
+                    'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
+                    'customer_id' => $sCustomerId,
+                    'subscription_id' => $sOrderId,
+                    'client_email' => $aCustomer['email'],
+                    'trial' => $this->isSubscriptionStatus(BX_PAYMENT_SBS_STATUS_TRIAL, $aSubscription)
+                ]);
+
+                $aPaymentPending = $this->_oModule->_oDb->getStrpPaymentPending($sOrderId);
+                if(empty($aPaymentPending) || !is_array($aPaymentPending)) 
+                    break;
+
+                if($this->_bCheckAmount && ((float)$aPending['amount'] != (float)$aPaymentPending['amount'] || strcasecmp($this->_oModule->_oConfig->getDefaultCurrencyCode(), $aPaymentPending['currency']) !== 0))
+                    break;
+
+                $aResult['paid'] = true;
+                break;
+        }
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrderId,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
+    {
+        if(!isset($aParams['sAction']))
+            return '';
+
+        return $aParams['sAction'] . parent::getButtonSingle($iClientId, $iVendorId, $aParams);
+    }
+
+    public function overwriteCheckoutParamsSingle($aParams, &$oGrid)
+    {
+        $aClient = $this->_oModule->getProfileInfo();
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo(BX_PAYMENT_TYPE_SINGLE, $aClient['id'], $aParams['seller_id'], $aParams['items']);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return array('msg' => _t('_bx_payment_err_nothing_selected'));
+
+        $aSessionParams = array(
+            'cancel_url' => $oCart->serviceGetCartUrl($aParams['seller_id']),
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), array_merge($aParams, array(
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            )), false)
+        );
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_SINGLE, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return array('msg' => _t('_bx_payment_err_cannot_perform'));
+
+        return array(
+            'eval' => $this->_oModule->_oConfig->getJsObject($this->_sName) . '.onCartCheckout(oData);', 
+            'session_id' => $mixedSession['id']
+        );
+    }
+
+    /**
+     * Note. Isn't used for now in default version.
+     */
+    public function createSessionAuthorize($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
+    {
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return false;
+
+        $aSessionParams = array_merge([
+            'cancel_url' => $oCart->serviceGetCartUrl($iSellerId),
+            'success_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_AUTHORIZE') . $sType . '/', [
+                'provider' => $this->_sName,
+                'seller_id' => $iSellerId,
+                'items' => $sItems,
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            ], false)
+        ], $aSessionParams);
+
+        $mixedSession = $this->_createSession('authorize', $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return false;
+
+        return $mixedSession['id'];
+    }
+
+    /*
+     * https://stripe.com/docs/checkout/embedded/quickstart?client=react&lang=php
+     */
+    public function createSessionPaymentEmbedded($sType, $iClientId, $iSellerId, $sItems, $aSessionParams = [])
+    {
+        $aClient = $this->_oModule->getProfileInfo($iClientId);
+
+        $oCart = $this->_oModule->getObjectCart();
+        $aCartInfo = $oCart->getInfo($sType, $aClient['id'], $iSellerId, $sItems);
+        if(empty($aCartInfo) || !is_array($aCartInfo))
+            return false;
+
+        $aSessionParams = array_merge([
+            'ui_mode' => 'embedded',
+            'return_url' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART_CHECKOUT'), [
+                'provider' => $this->_sName,
+                'seller_id' => $iSellerId,
+                'items' => $sItems,
+                'session_id' => '{CHECKOUT_SESSION_ID}'
+            ], false)
+        ], $aSessionParams);
+
+        if(strpos($aSessionParams['return_url'], 'session_id') === false)
+            $aSessionParams['return_url'] .= '&session_id={CHECKOUT_SESSION_ID}';
+
+        $mixedSession = $this->_createSession(BX_PAYMENT_TYPE_SINGLE, $aSessionParams, $aClient, $aCartInfo);
+        if($mixedSession === false)
+            return false;
+
+        return $mixedSession['client_secret'];
+    }
+
+    public function createTax($sName, $fPercentage, $bInclusive = false)
+    {
+        $oTax = null;
+        $aTax = [
+            'display_name' => $sName,
+            'percentage' => $fPercentage,
+            'inclusive' => $bInclusive,
+        ];
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_tax 'bx_payment', 'stripe_v3_create_tax' - hook to override tax data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_tax`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
+         *      - `tax_params` - [array] by ref, array with tax parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_tax
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_tax', 0, false, [
+            'tax_object' => &$oTax, 
+            'tax_params' => &$aTax
+        ]);
+
+        try {
+            if(empty($oTax))
+                $oTax = $this->_getStripe()->taxRates->create($aTax);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Tax Error: ', $oException);
+        }
+
+        $aResult = $oTax->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult))
+            return false;
+
+        return $aResult['id'];
+    }
+
+    public function retrieveTax($sId)
+    {
+        $oTax = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_tax 'bx_payment', 'stripe_v3_retrieve_tax' - hook to override tax data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_tax`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `tax_id` - [string] by ref, unique tax id, can be overridden in hook processing
+         *      - `tax_object` - [object] by ref, an instance of tax, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_tax
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_tax', 0, false, [
+            'tax_id' => &$sId,
+            'tax_object' => &$oTax
+        ]);
+
+        try {
+            if(empty($oTax))
+                $oTax = $this->_getStripe()->taxRates->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Tax Error: ', $oException);
+        }
+
+        return $oTax;
+    }
+
+    public function getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        $sCode = $this->_getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_get_code_session 'bx_payment', 'stripe_v3_get_code_session' - hook to override session verification code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_get_code_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `amount` - [float] session amount
+         *      - `currency` - [string] session currency code
+         *      - `override_result` - [string] by ref, verification code, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_get_code_session
+         */        
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_code_session', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'amount' => $fAmount,
+            'currency' => $sCurrency,
+            'override_result' => &$sCode
+        ]);
+
+        return $sCode;
+    }
+
+    public function checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
+    {
+        $bCheckResult = $this->_checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult);
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_verify_session 'bx_payment', 'stripe_v3_verify_session' - hook to override checking of session verification code
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_verify_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `provider` - [object] an instance of provider, @see BxBaseModPaymentProvider
+         *      - `vendor_id` - [int] vendor (seller) profile id
+         *      - `customer_id` - [int] customer (buyer) profile id
+         *      - `result` - [array] results array received from payment provider
+         *      - `override_result` - [boolean] by ref, is verification passed or not, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_verify_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_verify_session', 0, false, [
+            'provider' => $this,
+            'vendor_id' => $iVendorId, 
+            'customer_id' => $iCustomerId,
+            'result' => $aResult,
+            'override_result' => &$bCheckResult
+        ]);
+
+        return $bCheckResult;
+    }
+
+    protected function _getStripe()
+    {
+        if(empty($this->_oStripe))
+            $this->_oStripe = new \Stripe\StripeClient($this->_getSecretKey());
+
+        return $this->_oStripe;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/customers/retrieve
+     */
+    protected function _retrieveCustomer($sType, $sId)
+    {
+        $oCustomer = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_customer 'bx_payment', 'stripe_v3_retrieve_customer' - hook to override customer data retrieved from payment provider
+         * It's equivalent to @ref hook-bx_payment-stripe_retrieve_customer
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_customer
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_customer', 0, false, [
+            'type' => $sType,
+            'customer_id' => &$sId,
+            'customer_object' => &$oCustomer
+        ]);
+
+        try {
+            if(empty($oCustomer))
+                $oCustomer = $this->_getStripe()->customers->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Customer Error: ', $oException);
+        }
+
+        return $oCustomer;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/checkout/sessions/create
+     */
+    protected function _createSession($sType, $aParams, &$aClient, &$aCartInfo)
+    {
+        $sMode = '';
+        $aLineItems = $aMetaItems = [];
+        $bVerify = true;
+
+        switch($sType) {
+            case 'authorize':
+                $sMode = 'setup';
+                $bVerify = false;
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
+                    if(!empty($aItem['addons']) && is_array($aItem['addons']))
+                        foreach($aItem['addons'] as $aAddon)
+                            $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
+                }
+
+                $aParams['customer_creation'] = 'always';
+                break;
+
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sMode = 'payment';
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    list($_aLineItems, $_aMetaItems) = $this->_getLineItems($sType, $aItem, [
+                        'vendor_currency_code' => $aCartInfo['vendor_currency_code']
+                    ]);
+
+                    $aLineItems = array_merge($aLineItems, $_aLineItems);
+                    $aMetaItems = array_merge($aMetaItems, $_aMetaItems);
+                }
+
+                $aParams['customer_creation'] = 'always';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sMode = 'subscription';
+                $iTrial = 0;
+
+                foreach($aCartInfo['items'] as $aItem) {
+                    list($_aLineItems, $_aMetaItems) = $this->_getLineItems($sType, $aItem, [
+                        'vendor_currency_code' => $aCartInfo['vendor_currency_code']
+                    ]);
+
+                    $aLineItems = array_merge($aLineItems, $_aLineItems);
+                    $aMetaItems = array_merge($aMetaItems, $_aMetaItems);
+
+                    if((int)$aItem['trial_recurring'] > 0)
+                        $iTrial = (int)$aItem['trial_recurring'];
+                }
+
+                if($iTrial > 0) {
+                    $bVerify = false;
+
+                    $aParams['subscription_data'] = [
+                        'trial_period_days' => $iTrial
+                    ];
+                }
+
+                break;
+        }
+
+        $oSession = null;
+        $aSession = array_merge([
+            'mode' => $sMode,
+            'payment_method_types' => ['card'],
+            'customer_email' => !empty($aClient['email']) ? $aClient['email'] : ''
+        ], $aParams);
+
+        $bLineItems = !empty($aLineItems);
+        $aSession['line_items'] = $aLineItems;
+
+        $bMetaData = !empty($aMetaItems);
+        if($bMetaData) {
+            $aSession['metadata'] = [
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'type' => $sType, 
+                'items' => $this->_oModule->_oConfig->descriptorsA2S($aMetaItems)
+            ];
+
+            if($bVerify) {
+                $fAmount = 100 * round((float)$aCartInfo['items_price'], $this->_iAmountPrecision);
+                $aSession['metadata']['verification'] = $this->getVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code']);
+            }
+        }
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_session 'bx_payment', 'stripe_v3_create_session' - hook to override session data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_session`
+         * - $object_id - pending transaction id
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
+         *      - `session_params` - [array] by ref, array with session parameters, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_session', 0, false, [
+            'session_object' => &$oSession, 
+            'session_params' => &$aSession
+        ]);
+
+        try {
+            if(empty($oSession))
+                $oSession = $this->_getStripe()->checkout->sessions->create($aSession);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Session Error: ', $oException);
+        }
+
+        $aResult = $oSession->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult))
+            return false;
+
+        if($bVerify && !$this->checkVerificationCodeSession($aCartInfo['vendor_id'], $aClient['id'], $aResult))
+            return false;
+
+        return $aResult;
+    }
+
+    protected function _getSession($sType, $sId)
+    {
+        $oSession = $this->_retrieveSession($sId);
+        if($oSession === false)
+            return false;
+
+        $aSession = $oSession->jsonSerialize();
+        if(empty($aSession) || !is_array($aSession))
+            return array();
+
+        $sMode = 'payment';
+        if(!empty($aSession['mode']))
+            $sMode = $aSession['mode'];
+        
+        $aResult = array(
+            'id' => $aSession['id'],
+            'mode' => $sMode,
+            'order_id' => '',
+            'customer_id' => $aSession['customer'],
+            'status' => $aSession['payment_status']
+        );
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aResult['order_id'] = $aSession[($sMode == 'setup' ? 'setup' : 'payment') . '_intent'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aResult['order_id'] = $aSession['subscription'];
+                break;
+        }
+
+        return $aResult;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/checkout/sessions/retrieve
+     */
+    protected function _retrieveSession($sId)
+    {
+        $oSession = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_session 'bx_payment', 'stripe_v3_retrieve_session' - hook to override session data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_session`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `session_id` - [string] by ref, unique session id, can be overridden in hook processing
+         *      - `session_object` - [object] by ref, an instance of session, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_session
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_session', 0, false, [
+            'session_id' => &$sId,
+            'session_object' => &$oSession
+        ]);
+
+        try {
+            if(empty($oSession))
+                $oSession = $this->_getStripe()->checkout->sessions->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Session Error: ', $oException);
+        }
+
+        return $oSession;
+    }
+    
+    
+    /*
+     * Related Docs: https://stripe.com/docs/api/setup_intents/retrieve
+     */
+    protected function _retrieveSetupIntent($sId)
+    {
+        $oSetupIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_setup_intent 'bx_payment', 'stripe_v3_retrieve_setup_intent' - hook to override SetupIntent data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_setup_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
+         *      - `setup_intent_object` - [object] by ref, an instance of SetupIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_setup_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_setup_intent', 0, false, [
+            'setup_intent_id' => &$sId,
+            'setup_intent_object' => &$oSetupIntent
+        ]);
+
+        try {
+            if(empty($oSetupIntent))
+                $oSetupIntent = $this->_getStripe()->setupIntents->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Setup Intent Error: ', $oException);
+        }
+
+        return $oSetupIntent;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_intents/create
+     */
+    protected function _createPaymentIntent($sSetupIntentId, $fAmount, $sCurrency, $bConfirm = true)
+    {
+        $oPaymentIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_create_payment_intent 'bx_payment', 'stripe_v3_create_payment_intent' - hook to override PaymentIntent data redurned by payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_create_payment_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `setup_intent_id` - [string] by ref, unique SetupIntent id, can be overridden in hook processing
+         *      - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_create_payment_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_payment_intent', 0, false, [
+            'setup_intent_id' => &$sSetupIntentId,
+            'payment_intent_object' => &$oPaymentIntent
+        ]);
+
+        try {
+            if(empty($oPaymentIntent)) {
+                $oSetupIntent = $this->_retrieveSetupIntent($sSetupIntentId);
+                if($oSetupIntent === false)
+                    return false;
+
+                $aSetupIntent = $oSetupIntent->jsonSerialize();
+                if(empty($aSetupIntent) || !is_array($aSetupIntent))
+                    return false;
+
+                $oPaymentIntent = $this->_getStripe()->paymentIntents->create([
+                    'amount' => 100 * round($fAmount, $this->_iAmountPrecision),
+                    'currency' => strtolower($sCurrency),
+                    'customer' => $aSetupIntent['customer'],
+                    'payment_method' => $aSetupIntent['payment_method'],
+                    'confirm' => $bConfirm
+                ]);
+            }
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Intent Error: ', $oException);
+        }
+
+        return $oPaymentIntent;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_intents/retrieve
+     */
+    protected function _retrievePaymentIntent($sId)
+    {
+        $oPaymentIntent = null;
+
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_payment_intent 'bx_payment', 'stripe_v3_retrieve_payment_intent' - hook to override PaymentIntent data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_payment_intent`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `payment_intent_id` - [string] by ref, unique PaymentIntent id, can be overridden in hook processing
+         *      - `payment_intent_object` - [object] by ref, an instance of PaymentIntent, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_payment_intent
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_payment_intent', 0, false, [
+            'payment_intent_id' => &$sId,
+            'payment_intent_object' => &$oPaymentIntent
+        ]);
+
+        try {
+            if(empty($oPaymentIntent))
+                $oPaymentIntent = $this->_getStripe()->paymentIntents->retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Intent Error: ', $oException);
+        }
+
+        return $oPaymentIntent;
+    }
+    
+    /*
+     * Related Docs: https://stripe.com/docs/api/subscriptions/retrieve
+     */
+    protected function _retrieveSubscription($sCustomerId, $sSubscriptionId)
+    {
+        $oSubscription = null;
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_retrieve_subscription 'bx_payment', 'stripe_v3_retrieve_subscription' - hook to override subscription data retrieved from payment provider
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_retrieve_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `subscription_id` - [string] by ref, unique subscription id, can be overridden in hook processing
+         *      - `subscription_object` - [object] by ref, an instance of subscription, redurned by payment provider, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_retrieve_subscription
+         */
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_subscription', 0, false, [
+            'subscription_id' => &$sSubscriptionId,
+            'subscription_object' => &$oSubscription
+        ]);
+
+        try {
+            if(empty($oSubscription))
+                $oSubscription = $this->_getStripe()->subscriptions->retrieve($sSubscriptionId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Subscription Error: ', $oException);
+        }
+
+        return $oSubscription;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/tokens/create_card
+     */
+    protected function _createToken($aCard)
+    {
+        try {
+            $oToken = $this->_getStripe()->tokens->create(['card' => $aCard]);
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Token Error: ', $oException);
+        }
+
+        return $oToken->jsonSerialize();
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/cards/create
+     */
+    protected function _createCard($sType, $sCustomerId, $sToken)
+    {
+        try {
+            $oCard = $this->_getStripe()->customers->createSource($sCustomerId, [
+                'source' => $sToken
+            ]);
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Card Error: ', $oException);
+        }
+
+        return $oCard->jsonSerialize();
+    }
+
+    protected function _retrieveCard($sCustomerId, $sCardId = '')
+    {
+        try {
+            $oCustomer = $this->_getStripe()->customers->retrieve($sCustomerId);
+
+            if(empty($sCardId))
+                $sCardId = $oCustomer->default_source;
+            if(empty($sCardId))
+                return false;
+
+            $oCard = $this->_getStripe()->customers->retrieveSource($sCustomerId, $sCardId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Card Error: ', $oException);
+        }
+
+        return $oCard;
+    }
+
+    /*
+     * Related Docs: https://stripe.com/docs/api/payment_methods/retrieve
+     */
+    protected function _retrievePaymentMethod($sPaymentMethodId)
+    {
+        try {
+            $oPaymentMethod = $this->_getStripe()->paymentMethods->retrieve($sPaymentMethodId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Method Error: ', $oException);
+        }
+
+        return $oPaymentMethod;
+    }
+
+    protected function _getButton($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        list($sJsCode, $sJsMethod) = $this->_getButtonJs($sType, $iClientId, $iVendorId, $aParams);
+
+    	if($sType == BX_PAYMENT_TYPE_SINGLE)
+            return $sJsCode;
+
+        return parent::_getButton($sType, $iClientId, $iVendorId);
+    }
+
+    protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        $sClientEmail = '';
+    	if(!empty($iClientId) && ($oClient = BxDolProfile::getInstance($iClientId)) !== false)
+            $sClientEmail = $oClient->getAccountObject()->getEmail();
+
+        $sPublicKey = '';
+        $sConnectedAccountId = '';
+        
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-stripe_v3_get_button 'bx_payment', 'stripe_v3_get_button' - hook to override checkout/subscibe button
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `stripe_v3_get_button`
+         * - $object_id - not used
+         * - $sender_id - client (buyer) profile id
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `type` - [string] by ref, payment type ('single' or 'recurring'), can be overridden in hook processing
+         *      - `public_key` - [string] by ref, public key from Stripe account, can be overridden in hook processing
+         * @hook @ref hook-bx_payment-stripe_v3_get_button
+         */
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, [
+            'client_id' => $iClientId,
+            'vendor_id' => $iVendorId,
+            'type' => &$sType, 
+            'public_key' => &$sPublicKey,
+            'connected_account_id' => &$sConnectedAccountId
+        ]);
+
+        $sJsMethod = '';
+        $sJsObject = $this->getJsObject($aParams);
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $sJsMethod = 'void(0)';
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sJsMethod = $sJsObject . '.subscribe(this)';
+                break;
+        }
+
+        return [$this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge([
+            'js_object' => $sJsObject,
+            'sProvider' => $this->_sName,
+            'sPublicKey' => !empty($sPublicKey) ? $sPublicKey : $this->_getPublicKey(),
+            'sConnectedAccountId' => $sConnectedAccountId,
+            'sVendorName' => '',
+            'sVendorCurrency' => '',
+            'sVendorIcon' => '',
+            'sClientEmail' => $sClientEmail,
+        ], $aParams)), $sJsMethod];
+    }
+
+    protected function _getVerificationCodeSession($iVendorId, $iCustomerId, $fAmount, $sCurrency)
+    {
+        return md5(implode('#-#', array(
+            (int)$iVendorId,
+            (int)$iCustomerId,
+            (float)$fAmount,
+            strtoupper($sCurrency)
+        )));
+    }
+
+    protected function _checkVerificationCodeSession($iVendorId, $iCustomerId, $aResult)
+    {
+        return !empty($aResult['metadata']['verification']) && $aResult['metadata']['verification'] == $this->getVerificationCodeSession($iVendorId, $iCustomerId, $aResult['amount_total'], $aResult['currency']);
+    }
+
+    protected function _getLineItems($sType, $aItem, $aParams = [])
+    {
+        $aLineItems = $aMetaItems = [];
+
+        $bRecurring = $sType == BX_PAYMENT_TYPE_RECURRING;
+        $sCurrency = ($sKey = 'vendor_currency_code') && !empty($aParams[$sKey]) ? $aParams[$sKey] : $this->_oModule->_oConfig->getDefaultCurrencyCode();
+
+        $aProductData = [
+            'name' => $aItem['title']
+        ];
+        if(!empty($aItem['description']))
+            $aProductData['description'] = strmaxtextlen(strip_tags($aItem['description']), 60, '...');
+
+        $aLineItem = [
+            'price_data' => [
+                'currency' => $sCurrency,
+                'product_data' => $aProductData,
+                'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aItem, $this->_iAmountPrecision),
+            ],
+            'quantity' => $aItem['quantity'],
+        ];
+        
+        if($bRecurring && ($mixedPeriod = $this->_oModule->_oConfig->getPeriod($sType, $aItem)) !== false) {
+            list($iPeriod, $sPeriodUnit) = $mixedPeriod;
+            $aLineItem['price_data']['recurring'] = [
+                'interval' => $sPeriodUnit,
+                'interval_count' => $iPeriod
+            ];
+        }
+
+        $aLineItems[] = $aLineItem;
+        $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aItem['module_id'], $aItem['id']]);
+
+        if(!empty($aItem['addons']) && is_array($aItem['addons']))
+            foreach($aItem['addons'] as $aAddon) {
+                $aAddonData = [
+                    'name' => $aAddon['title']
+                ];
+                if(!empty($aAddon['description']))
+                    $aAddonData['description'] = strmaxtextlen(strip_tags($aAddon['description']), 60, '...');
+
+                $aLineItem = [
+                    'price_data' => [
+                        'currency' => $sCurrency,
+                        'product_data' => $aAddonData,
+                        'unit_amount' => 100 * $this->_oModule->_oConfig->getPrice($sType, $aAddon, $this->_iAmountPrecision),
+                    ],
+                    'quantity' => $aAddon['quantity'],
+                ];
+                
+                if($bRecurring && ($mixedPeriod = $this->_oModule->_oConfig->getPeriod($sType, $aAddon)) !== false) {
+                    list($iPeriod, $sPeriodUnit) = $mixedPeriod;
+                    $aLineItem['price_data']['recurring'] = [
+                        'interval' => $sPeriodUnit,
+                        'interval_count' => $iPeriod
+                    ];
+                }
+
+                $aLineItems[] = $aLineItem;
+                $aMetaItems[] = $this->_oModule->_oConfig->descriptorA2S([$aAddon['module_id'], $aAddon['id']]);
+            }
+
+        return [$aLineItems, $aMetaItems];
+    }
+
+    protected function _processException($sMessage, &$oException)
+    {
+        if(method_exists($oException, 'getError') && ($oError = $oException->getError())) {
+            $sError = $oError->message;
+            $aError = $oError->toArray();
+        }
+        else { 
+            $sError = $oException->getMessage();
+            $aError = array();
+        }
+
+        $this->log($sMessage . $sError, '', BX_LOG_ERR);
+        if(!empty($aError))
+            $this->log($aError, '', BX_LOG_ERR);
+
+        return false;
+    }
+}
+
+/** @} */

+ 568 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentSubscriptions.php

@@ -0,0 +1,568 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentSubscriptions extends BxBaseModPaymentSubscriptions
+{
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+    }
+
+    /*
+     * Service methods
+     */
+    
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_list_my get_block_list_my
+     * 
+     * @code bx_srv('bx_payment', 'get_block_list_my', [...], 'Subscriptions'); @endcode
+     * 
+     * Get page block with a list of currently logged in member's subscriptions.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentSubscriptions::serviceGetBlockListMy
+     */
+    /** 
+     * @ref bx_payment-get_block_list_my "get_block_list_my"
+     */
+    public function serviceGetBlockListMy()
+    {
+        return $this->_getBlock('list_my');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_list_all get_block_list_all
+     * 
+     * @code bx_srv('bx_payment', 'get_block_list_all', [...], 'Subscriptions'); @endcode
+     * 
+     * Get page block with a list of all subscriptions. It's available for authorized members only.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentSubscriptions::serviceGetBlockListAll
+     */
+    /** 
+     * @ref bx_payment-get_block_list_all "get_block_list_all"
+     */
+    public function serviceGetBlockListAll()
+    {
+        return $this->_getBlock('list_all');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_history get_block_history
+     * 
+     * @code bx_srv('bx_payment', 'get_block_history', [...], 'Subscriptions'); @endcode
+     * 
+     * Get page block with a list of payments related to subscriptions of currently logged in member.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentSubscriptions::serviceGetBlockHistory
+     */
+    /** 
+     * @ref bx_payment-get_block_history "get_block_history"
+     */
+    public function serviceGetBlockHistory()
+    {
+        return $this->_getBlock('history');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_subscription_orders_info get_subscription_orders_info
+     * 
+     * @code bx_srv('bx_payment', 'get_subscription_orders_info', [...], 'Subscriptions'); @endcode
+     * 
+     * Get subscription transaction(s) which meets all requirements.
+     *
+     * @param $aConditions an array of pears('key' => 'value'). The most useful keys are the following:
+     * a. client_id - client's ID (integer)
+     * b. seller_id - seller's ID (integer)
+     * c. type - transaction type: single or recurring (string)
+     * d. amount - transaction amount (float)
+     * e. order - order ID received from payment provider (string)
+     * f. provider - payment provider name (string)
+     * g. date - the date when the payment was established(UNIXTIME STAMP)
+     * h. processed - whether the payment was processed or not (integer, 0 or 1)
+     * @return an array of transactions. Each transaction has full info(client ID, seller ID, external transaction ID, date and so on)
+     * 
+     * @see BxPaymentSubscriptions::serviceGetSubscriptionOrdersInfo
+     */
+    /** 
+     * @ref bx_payment-get_subscription_orders_info "get_subscription_orders_info"
+     */
+    public function serviceGetSubscriptionOrdersInfo($aConditions)
+    {
+        if(empty($aConditions) || !is_array($aConditions))
+            return array();
+
+        return $this->_oModule->_oDb->getOrderSubscription(array('type' => 'mixed', 'conditions' => $aConditions));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_subscriptions_info get_subscriptions_info
+     * 
+     * @code bx_srv('bx_payment', 'get_subscriptions_info', [...], 'Subscriptions'); @endcode
+     * 
+     * Get subscription(s) which meets all requirements.
+     *
+     * @param $aConditions an array of pears('key' => 'value'). The most useful keys are the following:
+     * a. pending_id - pending transaction ID (integer)
+     * b. customer_id - customer ID from payment provider (string)
+     * c. subscription_id - subscription ID from payment provider (string)
+     * d. paid - flag determining whether the subscription paid or not (integer)
+     * e. date - the date when the subscription was established(UNIXTIME STAMP)
+     * @param $bCheckInProvider boolean value determining whether the subscription should be checked in associated payment provider.
+     * @return an array of subscriptions. Each subscription has full info(pending ID, customer ID, subscription ID and so on)
+     * 
+     * @see BxPaymentSubscriptions::serviceGetSubscriptionsInfo
+     */
+    /** 
+     * @ref bx_payment-get_subscriptions_info "get_subscriptions_info"
+     */
+    public function serviceGetSubscriptionsInfo($aConditions, $bCheckInProvider = false)
+    {
+        if(empty($aConditions) || !is_array($aConditions))
+            return array();
+
+        $aSubscriptions = $this->_oModule->_oDb->getSubscription(array('type' => 'mixed_ext', 'conditions' => $aConditions));
+        if(empty($aSubscriptions) || !is_array($aSubscriptions) || !$bCheckInProvider)
+            return $aSubscriptions;
+
+        foreach($aSubscriptions as $iKey => $aSubscription) {
+            if(empty($aSubscription['provider']) || $aSubscription['provider'] == 'manual')
+                continue;
+
+            $oProvider = $this->_oModule->getObjectProvider($aSubscription['provider'], $aSubscription['seller_id']);
+            if(!$oProvider)
+                continue;
+
+            $aSubscriptions[$iKey]['data'] = $oProvider->getSubscription($aSubscription['pending_id'], $aSubscription['customer_id'], $aSubscription['subscription_id']);
+        }
+
+        return $aSubscriptions;
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-subscribe subscribe
+     * 
+     * @code bx_srv('bx_payment', 'subscribe', [...], 'Subscriptions'); @endcode
+     * 
+     * Initialize subscription for specified item.
+     *
+     * @param $iSellerId integer value with seller ID.
+     * @param $sSellerProvider string value with a name of payment provider to be used for processing. Empty value means that payment provider selector should be shown.
+     * @param $iModuleId integer value with module ID.
+     * @param $iItemId integer value with item ID.
+     * @param $iItemCount integer value with a number of items for purchasing. It's equal to 1 in case of subscription.
+     * @param $sRedirect (optional) string value with redirect URL, if it's needed. 
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentSubscriptions::serviceSubscribe
+     */
+    /** 
+     * @ref bx_payment-subscribe "subscribe"
+     */
+    public function serviceSubscribe($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, $sRedirect = '', $aCustom = array())
+    {
+        return $this->serviceSubscribeWithAddons($iSellerId, $sSellerProvider, $iModuleId, $iItemId, $iItemCount, '', $sRedirect, $aCustom);
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-subscribe_with_addons subscribe_with_addons
+     * 
+     * @code bx_srv('bx_payment', 'subscribe_with_addons', [...], 'Subscriptions'); @endcode
+     * 
+     * Initialize subscription for specified item.
+     *
+     * @param $iSellerId integer value with seller ID.
+     * @param $sSellerProvider string value with a name of payment provider to be used for processing. Empty value means that payment provider selector should be shown.
+     * @param $iModuleId integer value with module ID.
+     * @param $iItemId integer value with item ID.
+     * @param $iItemCount integer value with a number of items for purchasing. It's equal to 1 in case of subscription.
+     * @param $sItemAddons (optional) string with attached addons.
+     * @param $sRedirect (optional) string value with redirect URL, if it's needed. 
+     * @return an array with special format which describes the result of operation.
+     * 
+     * @see BxPaymentSubscriptions::serviceSubscribeWithAddons
+     */
+    /** 
+     * @ref bx_payment-subscribe_with_addons "subscribe_with_addons"
+     */
+    public function serviceSubscribeWithAddons($iSellerId, $sSellerProvider, $mixedModuleId, $iItemId, $iItemCount, $sItemAddons = '', $sRedirect = '', $aCustom = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iModuleId = $this->_oModule->_oConfig->getModuleId($mixedModuleId);
+    	$iClientId = $this->_oModule->getProfileId();
+
+    	$mixedResult = $this->_oModule->checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount);
+    	if($mixedResult !== true)
+            return $mixedResult;
+
+        $aSellerProviders = $this->_oModule->_oDb->getVendorInfoProvidersRecurring($iSellerId, true);
+        if(empty($aSellerProviders))
+            return array('code' => 5, 'message' => _t($CNF['T']['ERR_NOT_ACCEPT_PAYMENTS']));
+
+        $aCartItem = array($iSellerId, $iModuleId, $iItemId, $iItemCount, $sItemAddons);
+
+        if(empty($sSellerProvider)) {
+            $sId = $this->_oModule->_oConfig->getHtmlIds('cart', 'providers_select') . BX_PAYMENT_TYPE_RECURRING;
+            $sTitle = _t($CNF['T']['POPUP_PROVIDERS_SELECT']);
+            return array('popup' => array(
+                'html' => BxTemplFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->displayProvidersSelector($aCartItem, $aSellerProviders, $sRedirect, $aCustom)), 
+                'options' => array('closeOnOuterClick' => true)
+            ));
+        }
+
+        $aCustoms = array();
+        $this->_oModule->_oConfig->putCustom($aCartItem, $aCustom, $aCustoms);
+
+        $sCartItem = $this->_oModule->_oConfig->descriptorA2S($aCartItem);
+        $mixedResult = $this->_oModule->serviceInitializeCheckout(BX_PAYMENT_TYPE_RECURRING, $iSellerId, $aSellerProviders[$sSellerProvider]['name'], array($sCartItem), $sRedirect, $aCustoms);
+        if(is_string($mixedResult))
+            return array('code' => 6, 'message' => _t($mixedResult));
+
+        return $mixedResult;
+    }
+    
+    public function serviceCancel($sOrder)
+    {
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrder]);
+        if(empty($aPending) || !is_array($aPending))
+            return ['code' => 1, 'message' => _t('_bx_payment_err_not_found_pending')];
+        
+        if(!$this->cancel((int)$aPending['id']))
+            return ['code' => 2, 'message' => _t('_bx_payment_err_cannot_perform')];
+
+        return ['code' => 0, 'message' => _t('_bx_payment_msg_successfully_performed')];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-purchase_processing Purchase Processing
+     * @subsubsection bx_payment-send_subscription_expiration_letters send_subscription_expiration_letters
+     * 
+     * @code bx_srv('bx_payment', 'send_subscription_expiration_letters', [...], 'Subscriptions'); @endcode
+     * 
+     * Send subscription expiration letters.
+     *
+     * @param $iPendingId integer value with pending transaction ID.
+     * @param $sOrderId string value with order ID.
+     * 
+     * @see BxPaymentSubscriptions::serviceSendSubscriptionExpirationLetters
+     */
+    /** 
+     * @ref bx_payment-send_subscription_expiration_letters "send_subscription_expiration_letters"
+     */
+    public function serviceSendSubscriptionExpirationLetters($iPendingId, $sOrderId)
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+        $sPrefix = $this->_oModule->_oConfig->getPrefix('general');
+
+        $aSubscription = $this->serviceGetSubscriptionsInfo(array('subscription_id' => $sOrderId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return;
+
+        $aSubscription = array_shift($aSubscription);
+
+        $oSeller = BxDolProfile::getInstance((int)$aSubscription['seller_id']);
+        $oClient = BxDolProfile::getInstance((int)$aSubscription['client_id']);
+
+        $aEtParams = array(
+            'subscription_id' => $aSubscription['subscription_id'],
+            'subscription_customer' => $aSubscription['customer_id'],
+            'subscription_date' => bx_time_js($aSubscription['date_add'], BX_FORMAT_DATE, true)
+        );
+
+        /**
+         * Notify seller.
+         */
+        if($oSeller !== false) {
+            $sEmail = '';
+            $oProvider = $this->_oModule->getObjectProvider($aSubscription['provider'], $aSubscription['seller_id']);
+            if($oProvider !== false && $oProvider->isActive())
+                $sEmail = $oProvider->getOption('expiration_email');
+
+            if(empty($sEmail))
+                $sEmail = $oSeller->getAccountObject()->getEmail();
+
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($sPrefix . 'expiration_notification_seller', $aEtParams, 0, (int)$aSubscription['client_id']);
+
+            sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM);
+        }
+
+        /**
+         * Notify client.
+         */
+        if($oClient !== false) {
+            $sEmail = $oClient->getAccountObject()->getEmail();
+            $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($sPrefix . 'expiration_notification_client', $aEtParams, 0, (int)$aSubscription['seller_id']);
+
+            sendMail($sEmail, $aTemplate['Subject'], $aTemplate['Body'], 0, array(), BX_EMAIL_SYSTEM);
+        }
+    }
+
+    public function register($aPending, $aParams = array())
+    {
+        if($this->_oModule->_oDb->isSubscriptionByPending($aPending['id']) || empty($aPending['items']))
+            return false;
+
+        $aInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_RECURRING, $aPending['client_id'], $aPending['seller_id'], $aPending['items']);
+        if(empty($aInfo['items']) || !is_array($aInfo['items']))
+            return false;
+
+        $aItem = array_shift($aInfo['items']);
+
+        $iPeriod = (int)$aItem['period_recurring'];
+        $iTrial = (int)$aItem['trial_recurring'];
+
+        $oDate = date_create();
+        $iNow = $iNext = date_format($oDate, 'U');
+
+        if((!empty($aParams['status']) && $aParams['status'] == BX_PAYMENT_SBS_STATUS_ACTIVE) || $iTrial > 0) {
+            $sInterval = $this->_getInterval($iPeriod, $aItem['period_unit_recurring'], $iTrial);
+            date_add($oDate, new DateInterval($sInterval));
+            $iNext = date_format($oDate, 'U');
+        }
+
+        $sUnique = genRndPwd(9, false);
+
+        $aSubscription = array(
+            'pending_id' => $aPending['id'],
+            'customer_id' => !empty($aParams['customer_id']) ? $aParams['customer_id'] : 'bx_cus_' . $sUnique,
+            'subscription_id' => !empty($aParams['subscription_id']) ? $aParams['subscription_id'] : 'bx_sub_' . $sUnique,
+            'period' => $iPeriod,
+            'period_unit' => $aItem['period_unit_recurring'],
+            'trial' => $iTrial,
+            'date_add' => $iNow,
+            'date_next' => $iNext,
+            'status' => !empty($aParams['status']) ? $aParams['status'] : ($iTrial > 0 ? BX_PAYMENT_SBS_STATUS_TRIAL : BX_PAYMENT_SBS_STATUS_UNPAID)
+        );
+
+        if(!$this->_oModule->_oDb->insertSubscription($aSubscription))
+            return false;
+
+        $this->_oModule->onSubscriptionCreate($aPending, $aSubscription);
+
+        return true;
+    }
+
+    public function prolong($aPending, $aParams = array())
+    {
+        if(empty($aPending['items']))
+            return false;
+
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $aInfo = $this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_RECURRING, $aPending['client_id'], $aPending['seller_id'], $aPending['items']);
+        if(empty($aInfo['items']) || !is_array($aInfo['items']))
+            return false;
+
+        $aItem = array_shift($aInfo['items']);
+        $iItemPeriod = (int)$aItem['period_recurring'];
+        $sItemPeriodUnit = $aItem['period_unit_recurring'];
+
+        $iDateNext = 0;
+        if(!empty($iItemPeriod) && !empty($sItemPeriodUnit)) {
+            $sInterval = $this->_getInterval($iItemPeriod, $sItemPeriodUnit);
+            if(empty($sInterval))
+                return false;
+
+            $oDate = date_create('@' . $aSubscription['date_next']);
+            date_add($oDate, new DateInterval($sInterval));
+            $iDateNext = date_format($oDate, 'U');
+        }
+
+        $this->_oModule->_oDb->updateSubscription(array_merge(array(
+            'date_next' => $iDateNext,
+            'pay_attempts' => 0,
+            'status' => BX_PAYMENT_SBS_STATUS_ACTIVE
+        ), $aParams), array(
+            'id' => $aSubscription['id']
+        ));
+
+        $this->_oModule->onSubscriptionProlong($aPending, $aSubscription);
+
+        return true;
+    }
+
+    public function overdue($aPending, $aParams = array())
+    {
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $this->_oModule->_oDb->updateSubscription(array_merge(array(
+            'status' => BX_PAYMENT_SBS_STATUS_UNPAID
+        ), $aParams), array(
+            'id' => $aSubscription['id']
+        ));
+
+        $this->_oModule->onSubscriptionOverdue($aPending, $aSubscription);
+
+        return true;
+    }
+
+    public function cancel($iPendingId)
+    {
+        if(!$this->cancelRemote($iPendingId))
+            return false;
+
+        if(!$this->cancelLocal($iPendingId))
+            return false;
+
+        return true;
+    }
+
+    public function cancelRemote($mixedPending)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+        if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING)
+            return false;
+
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $iSellerId = (int)$aPending['seller_id'];
+        $oProvider = $this->_oModule->getObjectProvider($aPending['provider'], $iSellerId);
+        if($oProvider === false || !$oProvider->isActive())
+            return false;
+
+        if(!$oProvider->cancelRecurring($aPending['id'], $aSubscription['customer_id'], $aSubscription['subscription_id']))
+            return false;
+
+        return true;
+    }
+
+    public function cancelLocal($mixedPending)
+    {
+        $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+        if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING)
+            return false;
+
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $aPending['id']));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        $aItems = $this->_oModule->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem)
+            $this->_oModule->callCancelSubscriptionItem((int)$aItem['module_id'], array($aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order']));
+
+        if(!$this->_oModule->_oDb->deleteSubscription($aSubscription['id'], 'cancel'))
+            return false;
+
+        $this->_oModule->onSubscriptionCancel($aPending, $aSubscription);
+
+        return true;
+    }
+
+    protected function _getBlock($sType)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sMethod = 'displayBlockSbs' . bx_gen_method_name($sType);
+        if(!$this->_oModule->_oTemplate->isMethodExists($sMethod))
+            return $this->_bIsApi ? [] : [
+                'content' => MsgBox(_t('_Empty'))
+            ];
+
+        $iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return $this->_bIsApi ? [] : [
+                'content' => MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']))
+            ];
+
+        $mixedBlockContent = $this->_oModule->_oTemplate->$sMethod($iUserId);
+
+        if($this->_bIsApi)
+            return !$mixedBlockContent ? [] : [
+                bx_api_get_block('grid', $mixedBlockContent)
+            ];
+
+        $this->_oModule->setSiteSubmenu('menu_dashboard', 'system', 'dashboard-subscriptions');
+
+        $sBlockSubmenu = $this->_oModule->_oConfig->getObject('menu_sbs_submenu');
+        $oBlockSubmenu = BxDolMenu::getObjectInstance($sBlockSubmenu);
+        if($oBlockSubmenu) 
+            $oBlockSubmenu->setSelected($this->MODULE, 'sbs-' . str_replace('_', '-', $sType));     
+
+        return [
+            'content' => $mixedBlockContent,
+            'menu' => $this->_oModule->_oConfig->getObject('menu_sbs_submenu')
+        ];
+    }
+
+    private function _getInterval($iPeriod, $sPeriodUnit, $iTrial = 0)
+    {
+        if((int)$iTrial > 0)
+            return 'P' . $iTrial . 'D';
+
+        $sInterval = '';
+        switch($sPeriodUnit) {
+            case BX_PAYMENT_SBS_PU_YEAR:
+                $sInterval = 'P' . $iPeriod . 'Y';
+                break;
+
+            case BX_PAYMENT_SBS_PU_MONTH:
+                $sInterval = 'P' . $iPeriod . 'M';
+                break;
+
+            case BX_PAYMENT_SBS_PU_WEEK:
+                $sInterval = 'P' . (7 * $iPeriod) . 'D';
+                break;
+
+            case BX_PAYMENT_SBS_PU_DAY:
+                $sInterval = 'P' . $iPeriod . 'D';
+                break;
+
+            case BX_PAYMENT_SBS_PU_HOUR:
+                $sInterval = 'PT' . $iPeriod . 'H';
+                break;
+
+            case BX_PAYMENT_SBS_PU_MINUTE:
+                $sInterval = 'PT' . $iPeriod . 'I';
+                break;
+        }
+
+        return $sInterval;
+    }
+}
+
+/** @} */

+ 612 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/classes/BxPaymentTemplate.php

@@ -0,0 +1,612 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentTemplate extends BxBaseModPaymentTemplate
+{
+    protected $_sLangsPrefix;
+
+    function __construct(&$oConfig, &$oDb)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($oConfig, $oDb);
+
+        $this->_sLangsPrefix = $this->_oConfig->getPrefix('langs');
+    }
+
+    public function addJsCssOrders()
+    {
+    	$this->addJs(array(
+            'jquery-ui/jquery-ui.min.js',
+            'jquery.form.min.js', 
+            'jquery.anim.js', 
+            'jquery.webForms.js',
+            'orders.js'
+    	));
+    	$this->addCss(array('orders.css'));
+    }
+
+    public function addJsCssSubscriptions()
+    {
+        $this->addJs(array('jquery.form.min.js', 'jquery.anim.js', 'jquery.webForms.js', 'main.js', 'subscriptions.js'));
+        $this->addCss(array('orders.css', 'subscriptions.css'));
+    }
+
+    public function addJsCssCart($sType = '', $iVendorId = 0)
+    {
+    	$this->addJsTranslation(array('_bx_payment_err_nothing_selected'));
+    	$this->addJs(array('jquery.anim.js', 'main.js', 'cart.js'));
+    	$this->addCss(array('orders.css', 'cart.css'));
+
+    	$oModule = $this->getModule();
+    	if(!empty($iVendorId)) {
+            $sMethod = 'getVendorInfoProviders' . bx_gen_method_name($sType);
+            $aProviders = $this->_oDb->$sMethod($iVendorId);
+            foreach($aProviders as $sProvider => $aProvider)
+                $oModule->getObjectProvider($sProvider, $iVendorId)->addJsCss();
+    	}
+    }
+
+    public function addJsCssInvoices()
+    {
+    	$this->addCss(array('invoices.css'));
+    }
+
+    public function displayBlockCheckoutOffline($oBuyer, $oSeller, $aData)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sTxtQt = _t('_bx_payment_txt_checkout_qt');
+
+        $aTmplVarsItems = array();
+        foreach($aData['items'] as $iIndex => $aItem)
+            $aTmplVarsItems[] = array(
+                'item_index' => $iIndex + 1,
+                'item_title' => $aItem['title'],
+                'item_quantity' => $aItem['quantity'] . $sTxtQt
+            );
+
+        $this->addCss(array('checkout.css'));
+        return $this->parseHtmlByName('checkout_offline.html', array(
+            'message' => _t('_bx_payment_txt_checkout_for', $oSeller->getDisplayName()),
+            'bx_repeat:items' => $aTmplVarsItems,
+            'amount' => $aData['currency']['sign'] . sprintf("%.2f", (float)($aData['amount'])),
+            'redirect_url' => $aData['return_url']
+        ));
+    }
+
+    public function displayCartJs($sType = '', $iVendorId = 0)
+    {
+        $this->addJsCssCart($sType, $iVendorId);
+        return $this->displayJsCode('cart');
+    }
+
+    public function displayAddToCartJs($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false, $aCustom = array())
+    {
+        $sJsCode = $this->displayCartJs(BX_PAYMENT_TYPE_SINGLE, $iVendorId);
+        $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,
+            'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+        ));
+
+        return array($sJsCode, $sJsMethod);
+    }
+
+    public function displayAddToCartLink($iVendorId, $iModuleId, $iItemId, $iItemCount, $bNeedRedirect = false, $aCustom = array())
+    {
+        $this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE, $iVendorId);
+        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,
+            'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+        ));
+    }
+
+    public function displaySubscribeJs($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1, $sRedirect = '', $aCustom = array())
+    {
+        return $this->displaySubscribeJsWithAddons($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount, '', $sRedirect, $aCustom);
+    }
+
+    public function displaySubscribeJsWithAddons($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1, $sItemAddons = '', $sRedirect = '', $aCustom = array())
+    {
+        $aSellerProviders = $this->_oDb->getVendorInfoProvidersRecurring($iVendorId);
+        if(empty($sVendorProvider) && count($aSellerProviders) == 1) {
+            $aCartItem = array($iVendorId, $iModuleId, $iItemId, $iItemCount, $sItemAddons);
+
+            $this->addJsCssCart(BX_PAYMENT_TYPE_RECURRING, $iVendorId);
+            return $this->getModule()->getProviderButtonJs($aCartItem, array_shift($aSellerProviders), $sRedirect, $aCustom);
+        }
+
+        return array(
+            $this->displayCartJs(BX_PAYMENT_TYPE_RECURRING, $iVendorId),
+            $this->parseHtmlByName('subscribe_js.html', array(
+                'js_object' => $this->_oConfig->getJsObject('cart'),
+                'vendor_id' => $iVendorId,
+                'vendor_provider' => $sVendorProvider,
+                'module_id' => $iModuleId,
+                'item_id' => $iItemId,
+                'item_count' => $iItemCount,
+                'redirect' => !empty($sRedirect) ? $sRedirect : '',
+                'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+            ))
+        );
+    }
+
+    public function displaySubscribeLink($iVendorId, $sVendorProvider, $iModuleId, $iItemId, $iItemCount = 1, $sRedirect = '', $aCustom = array())
+    {
+        $this->addJsCssCart(BX_PAYMENT_TYPE_RECURRING, $iVendorId);
+        return $this->parseHtmlByName('subscribe.html', array(
+            'js_object' => $this->_oConfig->getJsObject('cart'),
+            'js_content' => $this->displayJsCode('cart'),
+            'txt_add_to_cart' => _t($this->_sLangsPrefix . 'txt_subscribe'),
+            'vendor_id' => $iVendorId,
+            'vendor_provider' => $sVendorProvider,
+            'module_id' => $iModuleId,
+            'item_id' => $iItemId,
+            'item_count' => $iItemCount,
+            'redirect' => !empty($sRedirect) ? $sRedirect : '',
+            'custom' => !empty($aCustom) && is_array($aCustom) ? base64_encode(json_encode($aCustom)) : ''
+        ));
+    }
+
+    public function displaySubscriptionGetDetails($iId)
+    {
+    	return $this->_displaySubscriptionData('get_details', $iId);
+    }
+
+    public function displaySubscriptionChangeDetails($iId)
+    {
+    	return $this->_displaySubscriptionData('change_details', $iId);
+    }
+
+    public function displaySubscriptionGetBilling($iId)
+    {
+    	return $this->_displaySubscriptionData('get_billing', $iId);
+    }
+
+    public function displaySubscriptionChangeBilling($iId)
+    {
+    	return $this->_displaySubscriptionData('change_billing', $iId);
+    }
+
+    public function displayBlockCarts($iClientId)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_carts'));
+        if(!$oGrid)
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('client_id', $iClientId);
+        
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI();
+
+        $this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE);
+        return $this->displayJsCode('cart') . $oGrid->getCode();
+    }
+
+    public function displayBlockCart($iClientId, $iSellerId = 0)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_cart'));
+        if(!$oGrid || empty($iSellerId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('client_id', $iClientId);
+        $oGrid->addQueryParam('seller_id', $iSellerId);
+
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI();
+
+        $this->addJsCssCart(BX_PAYMENT_TYPE_SINGLE, $iSellerId);
+        return $this->displayJsCode('cart') . $oGrid->getCode();
+    }
+
+    public function displayBlockHistory($iClientId, $iSellerId)
+    {
+        return $this->_displayBlockHistory('grid_history', $iClientId, $iSellerId);
+    }
+
+    public function displayBlockSbsListMy($iClientId)
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_sbs_list_my'), $this->getModule()->_oTemplate);
+        if(!$oGrid || empty($iClientId))
+            return $this->_bIsApi ? false : MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('client_id', $iClientId);
+
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI(true);
+
+        $this->addJsCssSubscriptions();
+        return $this->displayJsCode(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION) . $oGrid->getCode();
+    }
+
+    public function displayBlockSbsListAll()
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_sbs_list_all'), $this->getModule()->_oTemplate);
+        if(!$oGrid)
+            return $this->_bIsApi ? false : MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        if($this->_bIsApi)
+            return $oGrid->getCodeAPI(true);
+
+        $this->addJsCssSubscriptions();
+        return $this->displayJsCode(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION) . $oGrid->getCode();
+    }
+
+    public function displayBlockSbsHistory($iClientId)
+    {
+        return $this->_displayBlockHistory('grid_sbs_history', $iClientId);
+    }
+
+    public function displayBlockSbsDetails($iClientId)
+    {
+        return 'Details would be here';
+    }
+
+    public function displayBlockOrders($sType, $iSellerId)
+    {
+        $sGrid = $this->_oConfig->getObject('grid_' . $sType);
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid || empty($iSellerId))
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $oGrid->addQueryParam('seller_id', $iSellerId);
+
+        $this->addJsCssOrders();
+        return $this->displayJsCode($sType, array(
+            'sObjNameGrid' => $sGrid,
+            'sParamsDivider' => $this->_oConfig->getDivider('DIVIDER_GRID_FILTERS'),
+            'sTextSearchInput' => _t('_sys_grid_search')
+        )) . $oGrid->getCode();
+    }
+
+    public function displayOrder($sType, $iId)
+    {
+        $sMethodName = 'getOrder' . bx_gen_method_name($sType);
+        $aOrder = $this->_oDb->$sMethodName(array('type' => 'id', 'id' => $iId));
+
+        if($this->_bIsApi)
+            return $this->displayOrderAPI($sType, $aOrder);
+
+        $oModule = $this->getModule();
+        $aSeller = $oModule->getVendorInfo((int)$aOrder['seller_id']);
+        $aClient = $oModule->getProfileInfo((int)$aOrder['client_id']);
+
+        $aTmplVarsLicense = array();
+        if(in_array($sType, array(BX_PAYMENT_ORDERS_TYPE_PROCESSED, BX_PAYMENT_ORDERS_TYPE_HISTORY)))
+            $aTmplVarsLicense = array(
+                'txt_license' => _t($this->_sLangsPrefix . 'txt_license'),
+                'license' => $aOrder['license']
+            );
+
+        $bTmplVarsShowSlrAtr = !empty($aOrder['author_id']) && $aOrder['seller_id'] != $aOrder['author_id'];
+
+        $aTmplVarsAuthor = array();
+        if($bTmplVarsShowSlrAtr) {
+            $aAuthor = $oModule->getProfileInfo((int)$aOrder['author_id']);
+
+            $aTmplVarsAuthor = array(
+                'txt_author' => _t($this->_sLangsPrefix . 'txt_author'),
+                'author_name' => $aAuthor['name'],
+                'author_url' => $aAuthor['link'],
+            );
+        }
+
+        $aTmplVarsSeller = array(
+            'txt_seller' => _t($this->_sLangsPrefix . 'txt_seller'),
+            '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']
+                )
+            ),
+        );
+        
+        $aResult = array_merge(array(
+            'txt_client' => _t($this->_sLangsPrefix . 'txt_client'),
+            '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_seller' => array(
+                'condition' => $bTmplVarsShowSlrAtr,
+                'content' => $aTmplVarsSeller
+            ),
+            'bx_if:show_license' => array(
+                'condition' => !empty($aTmplVarsLicense),
+                'content' => $aTmplVarsLicense
+            ),
+            'order' => $aOrder['order'],
+            'provider' => _t('_bx_payment_txt_name_' . $aOrder['provider']),
+            'error' => $aOrder['error_msg'],
+            'date' => bx_time_js($aOrder['date'], BX_FORMAT_DATE_TIME, true),
+            'bx_if:show_author' => array(
+                'condition' => $bTmplVarsShowSlrAtr,
+                'content' => $aTmplVarsAuthor
+            ),
+            'bx_repeat:items' => array()
+        ), $aTmplVarsSeller);
+
+        if(in_array($sType, array(BX_PAYMENT_ORDERS_TYPE_PENDING, BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION)))
+            $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'], $aOrder['client_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' => $this->_oConfig->getPrice($aOrder['type'], $aInfo),
+                    'currency_code' => $aSeller['currency_code']
+                );
+        }
+
+        if($this->_bIsApi)
+            return $aResult;
+
+        return $this->parseHtmlByName('order_' . $sType . '.html', $aResult);
+    }
+    
+    public function displayOrderAPI($sType, $aOrder)
+    {
+        $oModule = $this->getModule();
+        $aSeller = $oModule->getVendorInfo((int)$aOrder['seller_id']);
+
+        $aResult = [
+            [_t($this->_sLangsPrefix . 'txt_seller'), $aSeller['name']],
+            [_t($this->_sLangsPrefix . 'txt_order'), $aOrder['order']],           
+        ];
+
+        if(in_array($sType, [BX_PAYMENT_ORDERS_TYPE_PROCESSED, BX_PAYMENT_ORDERS_TYPE_HISTORY]))
+            $aResult[] = [_t($this->_sLangsPrefix . 'txt_license'), $aOrder['license']];
+
+        $aResult[] = [_t($this->_sLangsPrefix . 'txt_date'), $aOrder['date']];
+
+        if(in_array($sType, [BX_PAYMENT_ORDERS_TYPE_PENDING, BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION]))
+            $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'])));
+
+        $sProducts = '';
+        foreach($aItems as $aItem) {
+            $aInfo = $oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $aOrder['client_id']));
+            if(empty($aInfo) || !is_array($aInfo))
+                continue;
+
+            $sProducts .= $aInfo['title'] . ' (' . $aItem['item_count'] . ') - ' . $this->_oConfig->getPrice($aOrder['type'], $aInfo) . $aSeller['currency_code'] . ', ';
+        }
+
+        $aResult[] = [_t($this->_sLangsPrefix . 'txt_products'), trim($sProducts, ", ")];
+
+        return $aResult;
+    }
+
+    public function displayBlockInvoices()
+    {
+        $sGrid = $this->_oConfig->getObject('grid_invoices');
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $this->addJsCssInvoices();
+        return $oGrid->getCode();
+    }
+
+    public function displayItems($iSellerId, $sType, $aItems = [], $aParams = [])
+    {
+        $oModule = $this->getModule();
+        $oForm = new BxTemplFormView([]);
+
+        $sSign = !$this->_oConfig->isSingleSeller() ? $oModule->getVendorCurrencySign($iSellerId) : $this->_oConfig->getDefaultCurrencySign();
+
+        $bFilter = !empty($aParams['filter']);
+        $sFilter = $bFilter ? $aParams['filter'] : '';
+        
+        $aTmplVarsItems = [];
+        if(!empty($aItems) && is_array($aItems))
+            foreach($aItems as $aItem) {
+                if($bFilter && stripos($aItem['title'], $sFilter) === false)
+                    continue;
+
+                $fPrice = $this->_oConfig->getPrice($sType, $aItem);
+
+                $aInputCheckbox = array(
+                    'type' => 'checkbox',
+                    'name' => 'items[]',
+                    'value' => $aItem['id']
+                );
+                $aInputPrice = array(
+                    'type' => 'text',
+                    'name' => 'item-price-' . $aItem['id'],
+                    'value' => $fPrice
+                );
+                $aInputQuantity = array(
+                    'type' => 'text',
+                    'name' => 'item-quantity-' . $aItem['id'],
+                    'value' => 1
+                );
+
+                $aTmplVarsItems[$aItem['name']] = array(
+                    'id' => $aItem['id'],
+                    'price' => $fPrice,
+                    'price_f' => _t_format_currency_ext($fPrice, ['sign' => $sSign]),
+                    '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']
+                        )
+                    ),
+                    'input_checkbox' => $oForm->genInput($aInputCheckbox),
+                    'input_price' => $oForm->genInput($aInputPrice),
+                    'input_quantity' => $oForm->genInput($aInputQuantity),
+                );
+            }
+
+        
+        $bTmplVarsItems = !empty($aTmplVarsItems) && is_array($aTmplVarsItems);
+        if($bTmplVarsItems) {
+            ksort($aTmplVarsItems);
+            $aTmplVarsItems = array_values($aTmplVarsItems);
+        }
+        else 
+            $aTmplVarsItems = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        $sInputFilter = '';
+        if($bFilter || $bTmplVarsItems) {
+            $sJsMethod = 'javascript:' . $this->_oModule->_oConfig->getJsObject('processed') . '.filterItems(event, this);';
+            $aInputFilter = [
+                'type' => 'text',
+                'name' => 'filter',
+                'value' => $sFilter,
+                'attrs' => [
+                    'placeholder' => _t('_sys_search_placeholder'),
+                    'onkeydown' => $sJsMethod,
+                    'onpaste' => $sJsMethod
+                ]
+            ];
+            $sInputFilter = $oForm->genInput($aInputFilter);
+        }       
+
+        return $this->parseHtmlByName('items.html', array(
+            'html_id' => $this->_oConfig->getHtmlIds('processed', 'order_processed_items'),
+            'input_filter' => $sInputFilter,
+            'bx_repeat:items' => $aTmplVarsItems
+        ));
+    }
+
+    public function displayProvidersSelector($aCartItem, $aProviders, $sRedirect = '', $aCustom = array())
+    {
+    	$oModule = $this->getModule();
+
+        $aTmplVarsProviders = array();
+        foreach($aProviders as $sProvider => $aProvider) {
+            list($sJsCode, $sJsOnclick) = $oModule->getProviderButtonJs($aCartItem, $aProvider, $sRedirect, $aCustom);
+
+            $sCaptionKey = '_bx_payment_txt_subscribe_' . $aProvider['name'];
+            $sCaptionValue = _t($sCaptionKey);
+            if(strcmp($sCaptionKey, $sCaptionValue) == 0)
+                $sCaptionValue = _t($aProvider['caption']);
+
+            $aTmplVarsProviders[] = array(
+                'button' => $this->parseHtmlByName('providers_select_button.html', array(
+                    'onclick' => $sJsOnclick,
+                    'title' => _t('_bx_payment_txt_checkout_with', $sCaptionValue),
+                    'js_code' => $sJsCode
+                ))
+            );
+        }
+
+        return $this->parseHtmlByName('providers_select.html', array(
+            'bx_repeat:providers' => $aTmplVarsProviders
+        ));
+    }
+
+    protected function _displayBlockHistory($sObject, $iClientId, $iSellerId = 0)
+    {
+    	$oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject($sObject), $this->getModule()->_oTemplate);
+        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();
+        
+        if (bx_is_api()){
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+        }
+        
+        return $this->displayJsCode(BX_PAYMENT_ORDERS_TYPE_HISTORY) . $oGrid->getCode();
+    }
+
+    protected function _displaySubscriptionData($sType, $iId)
+    {
+        $aResult = array('code' => 1, 'message' => _t('_bx_payment_err_cannot_perform'));
+
+        $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => $iId));
+        if(empty($aPending) || !is_array($aPending))
+            return $aResult;
+
+        $aSubscription = $this->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $iId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return $aResult;
+
+        $mixedResult = $this->getModule()->isAllowedManage($aPending);
+        if($mixedResult !== true)
+            return array('code' => 2, 'message' => $mixedResult);
+            
+        $sMethod = bx_gen_method_name($sType) . 'Recurring';
+        $oProvider = $this->getModule()->getObjectProvider($aPending['provider'], $aPending['seller_id']);
+        if($oProvider === false || !$oProvider->isActive() || !method_exists($oProvider, $sMethod))
+        	return $aResult;
+
+        $mixedContent = $oProvider->$sMethod($iId, $aSubscription['customer_id'], $aSubscription['subscription_id']);
+        if(empty($mixedContent))
+            return $aResult;
+        else if(is_array($mixedContent))
+            return $mixedContent;
+
+        $sKey = 'order_' . BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION . '_' . $sType;
+    	$sId = $this->_oConfig->getHtmlIds(BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION, $sKey);
+    	$sTitle = _t($this->_sLangsPrefix . 'popup_title_ods_' . $sKey);
+    	return array('popup' => array(
+    		'html' => BxTemplFunctions::getInstance()->popupBox($sId, $sTitle, $mixedContent), 
+    		'options' => array('closeOnOuterClick' => 1)
+    	));
+    }
+}
+
+/** @} */

+ 70 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/install/config.php

@@ -0,0 +1,70 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_payment',
+    'title' => 'Payment',
+    'note' => 'Payment module.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * '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(),
+);
+
+/** @} */

+ 695 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/install/langs/en.xml

@@ -0,0 +1,695 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+    <string name="_bx_payment"><![CDATA[Payments]]></string>
+
+    <!-- OPTIONS -->
+    <string name="_bx_payment_options_category_general"><![CDATA[General]]></string>
+    <string name="_bx_payment_options_category_currency"><![CDATA[Сurrency]]></string>
+    <string name="_bx_payment_options_category_commissions"><![CDATA[Commissions]]></string>
+    <string name="_bx_payment_option_default_currency_code"><![CDATA[Currency]]></string>
+    <string name="_bx_payment_option_err_default_currency_code"><![CDATA[Currency code cannot be empty.]]></string>
+    <string name="_bx_payment_option_currency_exchange_api"><![CDATA[Exchange currency API key (by exchangeratesapi.io)]]></string>
+    <string name="_bx_payment_option_site_admin"><![CDATA[Main seller (To sell on behalf of the site)]]></string>
+    <string name="_bx_payment_option_credits_only"><![CDATA[Pay with Credits only mode ('Credits' app should be installed).]]></string>
+    <string name="_bx_payment_option_single_seller"><![CDATA[Single seller mode (To sell everything on behalf of the 'Main seller').]]></string>
+    <string name="_bx_payment_option_inv_issue_day"><![CDATA[Day of month when invoices are automatically generated (1, 2, 3, etc)]]></string>
+    <string name="_bx_payment_option_inv_lifetime"><![CDATA[Due date - days after invoice date]]></string>
+    <string name="_bx_payment_option_inv_expiraction_notify"><![CDATA[Number of days before invoice expiration to notify payer]]></string>
+
+    <!-- PAGES and BLOCKS -->
+    <string name="_bx_payment_page_title_sys_carts"><![CDATA[Shopping Cart]]></string>
+    <string name="_bx_payment_page_title_carts"><![CDATA[Shopping Cart]]></string>
+    <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_title_sys_cart_thank_you"><![CDATA[Thank you!]]></string>
+    <string name="_bx_payment_page_title_cart_thank_you"><![CDATA[Thank you!]]></string>
+    <string name="_bx_payment_page_block_title_carts"><![CDATA[Shopping Cart]]></string>
+    <string name="_bx_payment_page_block_title_cart"><![CDATA[{0}'s Shopping Cart]]></string>
+    <string name="_bx_payment_page_block_title_cart_thank_you"><![CDATA[Thank you!]]></string>
+    <string name="_bx_payment_page_block_content_cart_thank_you"><![CDATA[Thank you! Payment was successfully performed. The data will be processed shortly. Please wait.]]></string>
+
+    <string name="_bx_payment_page_title_sys_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+    <string name="_bx_payment_page_title_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+    <string name="_bx_payment_page_block_title_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+
+    <string name="_bx_payment_page_title_sys_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+    <string name="_bx_payment_page_title_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+    <string name="_bx_payment_page_block_title_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+
+    <string name="_bx_payment_page_title_sys_sbs_history"><![CDATA[My Payments]]></string>
+    <string name="_bx_payment_page_title_sbs_history"><![CDATA[My Payments]]></string>
+    <string name="_bx_payment_page_block_title_sbs_history"><![CDATA[My Payments]]></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[Payments Details]]></string>
+    <string name="_bx_payment_page_title_details"><![CDATA[Payments Details]]></string>
+    <string name="_bx_payment_page_block_title_details"><![CDATA[Payments 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_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_page_title_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_page_block_title_invoices"><![CDATA[Invoices]]></string>
+    
+    <string name="_bx_payment_page_title_sys_checkout_offline"><![CDATA[Offline Checkout]]></string>
+    <string name="_bx_payment_page_title_checkout_offline"><![CDATA[Offline Checkout]]></string>
+    <string name="_bx_payment_page_block_title_sys_checkout_offline"><![CDATA[Offline Checkout]]></string>
+    <string name="_bx_payment_page_block_title_checkout_offline"><![CDATA[]]></string>
+
+    <!-- MENUS -->
+    <string name="_bx_payment_lmi_cpt_providers"><![CDATA[Providers]]></string>
+    <string name="_bx_payment_lmi_cpt_commissions"><![CDATA[Commissions]]></string>
+
+    <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[Payments Details]]></string>
+    <string name="_bx_payment_menu_item_title_details"><![CDATA[Payments]]></string>
+    <string name="_bx_payment_menu_item_title_system_admt_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_menu_item_title_admt_invoices"><![CDATA[Invoices]]></string>
+    <string name="_bx_payment_menu_item_title_admt_addon_counter1_caption"><![CDATA[paid]]></string>
+    <string name="_bx_payment_menu_item_title_admt_addon_counter2_caption"><![CDATA[overdue]]></string>
+
+    <string name="_bx_payment_menu_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_title_public_cart_submenu"><![CDATA[Carts]]></string>
+    <string name="_bx_payment_menu_set_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart"><![CDATA[Checkout]]></string>
+    <string name="_bx_payment_menu_item_title_cart"><![CDATA[Checkout]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart_history"><![CDATA[Payment History]]></string>
+    <string name="_bx_payment_menu_item_title_cart_history"><![CDATA[Payment History]]></string>
+
+    <string name="_bx_payment_menu_title_sbs_submenu"><![CDATA[Subscriptions Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_sbs_submenu"><![CDATA[Subscriptions Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_list_my"><![CDATA[My Subscriptions List]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_list_my"><![CDATA[My Subscriptions]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_list_all"><![CDATA[All Subscriptions List]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_list_all"><![CDATA[All Subscriptions]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_history"><![CDATA[My Payments History]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_history"><![CDATA[My Payments]]></string>
+
+    <string name="_bx_payment_menu_title_sbs_actions"><![CDATA[Subscription Actions]]></string>
+    <string name="_bx_payment_menu_set_title_sbs_actions"><![CDATA[Subscription Actions]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_request_cancelation"><![CDATA[Request Cancellation]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_request_cancelation"><![CDATA[Request Cancellation]]></string>
+    <string name="_bx_payment_menu_item_title_system_sbs_cancel"><![CDATA[Cancel Subscription]]></string>
+    <string name="_bx_payment_menu_item_title_sbs_cancel"><![CDATA[Cancel Subscription]]></string>
+
+    <!-- GRIDS -->
+    <string name="_bx_payment_grid_column_title_pdrs_caption"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_for_visitor"><![CDATA[For visitors]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_for_single"><![CDATA[One Time]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_for_recurring"><![CDATA[Recurring]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_single_seller"><![CDATA[Single Seller]]></string>
+    <string name="_bx_payment_grid_column_title_pdrs_time_tracker"><![CDATA[Time Tracker]]></string>
+    <string name="_bx_payment_grid_column_title_ods_client_id"><![CDATA[Client]]></string>
+    <string name="_bx_payment_grid_column_title_ods_seller_id"><![CDATA[Seller]]></string>
+    <string name="_bx_payment_grid_column_title_ods_author_id"><![CDATA[Author]]></string>
+    <string name="_bx_payment_grid_column_title_ods_transaction"><![CDATA[Transaction]]></string>
+    <string name="_bx_payment_grid_column_title_ods_license"><![CDATA[License]]></string>
+    <string name="_bx_payment_grid_column_title_ods_item"><![CDATA[Product]]></string>
+    <string name="_bx_payment_grid_column_title_ods_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_grid_column_title_ods_date"><![CDATA[Date]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_seller_id"><![CDATA[Seller]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_client_id"><![CDATA[Client]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_client_email"><![CDATA[Email]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_customer_id"><![CDATA[Customer ID]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_subscription_id"><![CDATA[Subscription]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_transaction"><![CDATA[Transaction]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_license"><![CDATA[License]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_provider"><![CDATA[Provider]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_status"><![CDATA[Status]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_date"><![CDATA[Date]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_date_add"><![CDATA[Created]]></string>
+    <string name="_bx_payment_grid_column_title_sbs_date_next"><![CDATA[Next Payment]]></string>
+    <string name="_bx_payment_grid_column_title_crts_vendor_id"><![CDATA[Vendor]]></string>
+    <string name="_bx_payment_grid_column_title_crts_items_count"><![CDATA[Count]]></string>
+    <string name="_bx_payment_grid_column_title_crts_items_price"><![CDATA[Price]]></string>
+    <string name="_bx_payment_grid_column_title_crt_title"><![CDATA[Product]]></string>
+    <string name="_bx_payment_grid_column_title_crt_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_grid_column_title_crt_quantity"><![CDATA[Quantity]]></string>
+    <string name="_bx_payment_grid_column_title_crt_price"><![CDATA[Price]]></string>
+    <string name="_bx_payment_grid_column_title_cms_caption"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_grid_column_title_cms_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_grid_column_title_cms_acl_id"><![CDATA[Membership]]></string>
+    <string name="_bx_payment_grid_column_title_cms_percentage"><![CDATA[Percentage]]></string>
+    <string name="_bx_payment_grid_column_title_cms_installment"><![CDATA[Fixed fee]]></string>
+    <string name="_bx_payment_grid_column_title_inv_commissionaire_id"><![CDATA[Payee]]></string>
+    <string name="_bx_payment_grid_column_title_inv_committent_id"><![CDATA[Payer]]></string>
+    <string name="_bx_payment_grid_column_title_inv_name"><![CDATA[Name]]></string>
+    <string name="_bx_payment_grid_column_title_inv_period_start"><![CDATA[Period start]]></string>
+    <string name="_bx_payment_grid_column_title_inv_period_end"><![CDATA[Period end]]></string>
+    <string name="_bx_payment_grid_column_title_inv_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_grid_column_title_inv_date_issue"><![CDATA[Issue date]]></string>
+    <string name="_bx_payment_grid_column_title_inv_date_due"><![CDATA[Due date]]></string>
+    <string name="_bx_payment_grid_column_title_inv_status"><![CDATA[Status]]></string>
+
+    <string name="_bx_payment_grid_action_title_ods_add"><![CDATA[Manual Order]]></string>
+    <string name="_bx_payment_grid_action_title_ods_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_grid_action_title_ods_process"><![CDATA[Process]]></string>
+    <string name="_bx_payment_grid_action_title_ods_view_order"><![CDATA[View]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_view_order"><![CDATA[View]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_grid_action_title_sbs_delete"><![CDATA[Remove]]></string>
+    <string name="_bx_payment_grid_action_title_crts_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_crts_continue"><![CDATA[Continue to checkout]]></string>
+    <string name="_bx_payment_grid_action_title_crt_checkout"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_grid_action_title_crt_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_crt_quantity_sub"><![CDATA[Decrease quantity]]></string>
+    <string name="_bx_payment_grid_action_title_crt_quantity_add"><![CDATA[Increase quantity]]></string>
+    <string name="_bx_payment_grid_action_title_cms_add"><![CDATA[Add]]></string>
+    <string name="_bx_payment_grid_action_title_cms_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_payment_grid_action_title_cms_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_inv_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_payment_grid_action_title_inv_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_payment_grid_action_title_inv_pay"><![CDATA[Pay]]></string>
+
+    <string name="_bx_payment_popup_title_ods_order_subscription_view"><![CDATA[Subscription]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_get_details"><![CDATA[Subscription Details]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_change_details"><![CDATA[Change Subscription Details]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_get_billing"><![CDATA[Billing Information]]></string>
+    <string name="_bx_payment_popup_title_ods_order_subscription_change_billing"><![CDATA[Change Billing Information]]></string>
+    <string name="_bx_payment_popup_title_ods_order_history_view"><![CDATA[Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_pending_view"><![CDATA[Pending Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_pending_process"><![CDATA[Process Pending Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_processed_view"><![CDATA[Processed Order]]></string>
+    <string name="_bx_payment_popup_title_ods_order_processed_add"><![CDATA[Manual Order]]></string>
+    <string name="_bx_payment_popup_title_crd_providers_select"><![CDATA[Select Payment Method]]></string>
+    <string name="_bx_payment_popup_title_cms_add"><![CDATA[Add Monthly Commission]]></string>
+    <string name="_bx_payment_popup_title_cms_edit"><![CDATA[Edit Monthly Commission]]></string>
+    <string name="_bx_payment_popup_title_inv_edit"><![CDATA[Edit Invoice]]></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>
+
+    <string name="_bx_payment_form_details_form"><![CDATA[Details Form]]></string>
+    <string name="_bx_payment_form_details_display_edit"><![CDATA[Edit Details Display]]></string>
+
+    <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[]]></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="_bx_payment_form_commissions_form"><![CDATA[Commissions Form]]></string>
+    <string name="_bx_payment_form_commissions_display_add"><![CDATA[Add Commission Display]]></string>
+    <string name="_bx_payment_form_commissions_display_edit"><![CDATA[Edit Commission Display]]></string>
+    <string name="_bx_payment_form_commissions_input_caption_sys"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_form_commissions_input_caption"><![CDATA[Caption]]></string>
+    <string name="_bx_payment_form_commissions_input_caption_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_payment_form_commissions_input_description_sys"><![CDATA[Description]]></string>
+    <string name="_bx_payment_form_commissions_input_description"><![CDATA[Description]]></string>
+    <string name="_bx_payment_form_commissions_input_acl_id_sys"><![CDATA[Membership Level]]></string>
+    <string name="_bx_payment_form_commissions_input_acl_id"><![CDATA[Membership Level]]></string>
+    <string name="_bx_payment_form_commissions_input_percentage_sys"><![CDATA[Percentage]]></string>
+    <string name="_bx_payment_form_commissions_input_percentage"><![CDATA[Percentage]]></string>
+    <string name="_bx_payment_form_commissions_input_installment_sys"><![CDATA[Fixed fee]]></string>
+    <string name="_bx_payment_form_commissions_input_installment"><![CDATA[Fixed fee]]></string>
+    <string name="_bx_payment_form_commissions_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_commissions_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_commissions_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_commissions_input_cancel"><![CDATA[Cancel]]></string>
+    
+    <string name="_bx_payment_form_invoices_form"><![CDATA[Invoices Form]]></string>
+    <string name="_bx_payment_form_invoices_display_edit"><![CDATA[Edit Invoice Display]]></string>
+    <string name="_bx_payment_form_invoices_input_amount_sys"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_form_invoices_input_amount"><![CDATA[Amount]]></string>
+    <string name="_bx_payment_form_invoices_input_amount_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due_sys"><![CDATA[Due date]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due"><![CDATA[Due date]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_payment_form_invoices_input_status_sys"><![CDATA[Status]]></string>
+    <string name="_bx_payment_form_invoices_input_status"><![CDATA[Status]]></string>
+    <string name="_bx_payment_form_invoices_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_invoices_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_invoices_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_invoices_input_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_payment_form_input_email_err_cor_or_emp"><![CDATA[Use correct email address or leave empty.]]></string>
+
+    <!-- Predefined Values -->
+    <string name="_bx_payment_pre_lists_currencies"><![CDATA[Currencies]]></string>
+
+    <!-- ACL -->
+    <string name="_bx_payment_acl_action_purchase"><![CDATA[Purchase]]></string>
+    <string name="_bx_payment_acl_action_sell"><![CDATA[Sell]]></string>
+    <string name="_bx_payment_acl_action_manage_any_purchase"><![CDATA[Manage Any Purchase]]></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 processed.]]></string>
+    <string name="_bx_payment_et_txt_body_paid_need_join"><![CDATA[{email_header}
+<p>Hello, {RealName}.</p>
+<p>Your payment was processed. 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>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_cancelation_request"><![CDATA[Subscription cancellation request.]]></string>
+    <string name="_bx_payment_et_txt_subject_cancelation_request"><![CDATA[Subscription cancellation request.]]></string>
+    <string name="_bx_payment_et_txt_body_cancelation_request"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>A user with {profile_name} profile name requested cancellation for a subscription.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Date: {subscription_date}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_expiration_notification_seller"><![CDATA[Subscription expiration notification (for seller).]]></string>
+    <string name="_bx_payment_et_txt_subject_expiration_notification_seller"><![CDATA[Subscription expiration notification.]]></string>
+    <string name="_bx_payment_et_txt_body_expiration_notification_seller"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>A subscription purchased by '{profile_name}' expired.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Date: {subscription_date}</p>
+<p><b>Note</b>. An associated data will be removed shortly.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_expiration_notification_client"><![CDATA[Subscription expiration notification (for client).]]></string>
+    <string name="_bx_payment_et_txt_subject_expiration_notification_client"><![CDATA[Subscription expiration notification.]]></string>
+    <string name="_bx_payment_et_txt_body_expiration_notification_client"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>Your subscription purchased from '{profile_name}' expired.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Date: {subscription_date}</p>
+<p><b>Note</b>. An associated data will be removed shortly.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_expiring_notification_committent"><![CDATA[Invoice expiring notification.]]></string>
+    <string name="_bx_payment_et_txt_subject_expiring_notification_committent"><![CDATA[Invoice expiring notification.]]></string>
+    <string name="_bx_payment_et_txt_body_expiring_notification_committent"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>Your invoice '{invoice}' is expiring in '{days}' day(s).</p>
+<p>Invoice info:<br />Period start: {period_start}<br />Period end: {period_end}<br />Issue date: {date_issue}<br />Due date: {date_due}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_overdue_notification_committent"><![CDATA[Overdue invoice notification.]]></string>
+    <string name="_bx_payment_et_txt_subject_overdue_notification_committent"><![CDATA[Overdue invoice notification.]]></string>
+    <string name="_bx_payment_et_txt_body_overdue_notification_committent"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>Your invoice '{invoice}' is overdue '{date_due}'.</p>
+<p>Invoice info:<br />Period start: {period_start}<br />Period end: {period_end}<br />Issue date: {date_issue}<br />Due date: {date_due}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_checkout_offline"><![CDATA[Offline checkout attempt.]]></string>
+    <string name="_bx_payment_et_txt_subject_checkout_offline"><![CDATA[An attempt to pay with cash.]]></string>
+    <string name="_bx_payment_et_txt_body_checkout_offline"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>A site member <a href="{profile_link}">{profile_name}</a> wanted to pay you with cash for:</p>
+<p>{items}</p>
+<p>Amount: {amount}<br />Date: {date}</p>
+<p>Go to the <a href="{pending_orders_link}">pending orders page</a> to process the order once the payment is received.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_wrong_balance"><![CDATA[Insufficient funds to write off.]]></string>
+    <string name="_bx_payment_et_txt_subject_wrong_balance"><![CDATA[Insufficient funds to write off.]]></string>
+    <string name="_bx_payment_et_txt_body_wrong_balance"><![CDATA[{email_header}
+<p>Hello,</p>
+<p>You have insufficient funds to write off for paying a subscription.</p>
+<p>Subscription info:<br />ID: {subscription_id}<br />Customer: {subscription_customer}<br />Payment provider: {subscription_provider}<br />Date: {subscription_date}</p>
+{email_footer}]]></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_item_added"><![CDATA[The item was successfully added to your shopping cart.]]></string>
+    <string name="_bx_payment_msg_item_deleted"><![CDATA[The item was successfully deleted from your shopping cart.]]></string>
+    <string name="_bx_payment_msg_successfully_performed"><![CDATA[The action was successfully performed.]]></string>
+    <string name="_bx_payment_msg_successfully_processed_free"><![CDATA[Free item was successfully processed]]></string>
+    <string name="_bx_payment_msg_cancelation_request_sent"><![CDATA[Cancellation request was sent. Please wait.]]></string>
+    <string name="_bx_payment_msg_confirm_cancelation"><![CDATA[Are you sure you want to cancel your subscription?]]></string>
+    <string name="_bx_payment_msg_single_seller"><![CDATA[Single seller mode is enabled. <a href="{0}">Got to</a> single shopping cart.]]></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_self_purchase"><![CDATA[Buying from your own store is not permitted.]]></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_vendor"><![CDATA[Incorrect 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="_bx_payment_err_already_processed"><![CDATA[This payment has already processed.]]></string>
+    <string name="_bx_payment_err_already_registered"><![CDATA[Subscription with the same data was already registered.]]></string>
+    <string name="_bx_payment_err_not_supported"><![CDATA[Operation isn't supported.]]></string>
+
+    <!-- Other -->
+    <string name="_bx_payment_txt_add_to_cart"><![CDATA[Add to Cart]]></string>
+    <string name="_bx_payment_txt_subscribe"><![CDATA[Subscribe]]></string>
+    <string name="_bx_payment_txt_payment_to"><![CDATA[Payment to {0}]]></string>
+    <string name="_bx_payment_txt_payment_to_for"><![CDATA[Payment to {0} for:]]></string>
+    <string name="_bx_payment_txt_checkout_to"><![CDATA[Continue checkouting to {0}]]></string>
+    <string name="_bx_payment_txt_checkout_with"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_txt_checkout_with_cash"><![CDATA[Checkout with cash]]></string>
+    <string name="_bx_payment_txt_checkout_for"><![CDATA[A message was sent to the seller ({0}), that you want to pay with cash for the following items. He should contact you shortly.]]></string>
+    <string name="_bx_payment_txt_checkout_qt"><![CDATA[qt.]]></string>
+    <string name="_bx_payment_txt_checkout_item"><![CDATA[{0} ({1}qt.)<br />]]></string>
+    <string name="_bx_payment_txt_client"><![CDATA[Client]]></string>
+    <string name="_bx_payment_txt_license"><![CDATA[License]]></string>
+    <string name="_bx_payment_txt_seller"><![CDATA[Seller]]></string>
+    <string name="_bx_payment_txt_author"><![CDATA[Author]]></string>
+    <string name="_bx_payment_txt_item"><![CDATA[Product]]></string>
+    <string name="_bx_payment_txt_quantity"><![CDATA[Qt.]]></string>
+    <string name="_bx_payment_txt_order"><![CDATA[Order ID]]></string>
+    <string name="_bx_payment_txt_price"><![CDATA[Price]]></string>
+    <string name="_bx_payment_txt_price_sold"><![CDATA[Sold Price]]></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="_bx_payment_txt_buyer_name_mask"><![CDATA[{0} {1}]]></string>
+    <string name="_bx_payment_txt_none"><![CDATA[none]]></string>
+    <string name="_bx_payment_txt_name_manual"><![CDATA[Manually]]></string>
+    <string name="_bx_payment_txt_yes"><![CDATA[Yes]]></string>
+    <string name="_bx_payment_txt_no"><![CDATA[No]]></string>
+    <string name="_bx_payment_txt_unsubscribe_yes"><![CDATA[Cancel automatically]]></string>
+    <string name="_bx_payment_txt_unsubscribe_no"><![CDATA[Do not cancel]]></string>
+    <string name="_bx_payment_txt_all_authors"><![CDATA[All Authors]]></string>
+    <string name="_bx_payment_txt_all_clients"><![CDATA[All Clients]]></string>
+    <string name="_bx_payment_txt_all_modules"><![CDATA[All Modules]]></string>
+    <string name="_bx_payment_txt_all_items"><![CDATA[All Items]]></string>
+    <string name="_bx_payment_txt_status_scheduled"><![CDATA[Scheduled]]></string>
+    <string name="_bx_payment_txt_status_trial"><![CDATA[Trial]]></string>
+    <string name="_bx_payment_txt_status_active"><![CDATA[Active]]></string>
+    <string name="_bx_payment_txt_status_paid"><![CDATA[Paid]]></string>
+    <string name="_bx_payment_txt_status_unpaid"><![CDATA[Unpaid]]></string>
+    <string name="_bx_payment_txt_status_overdue"><![CDATA[Overdue]]></string>
+    <string name="_bx_payment_txt_status_paused"><![CDATA[Paused]]></string>
+    <string name="_bx_payment_txt_status_canceled"><![CDATA[Canceled]]></string>
+    <string name="_bx_payment_txt_status_unknown"><![CDATA[Unknown]]></string>
+    <string name="_bx_payment_txt_invoice_title"><![CDATA[Invoice {0} from {1}]]></string>
+    <string name="_bx_payment_txt_invoice_description"><![CDATA[For a period between {0} and {1}]]></string>
+    <string name="_bx_payment_txt_payment_description"><![CDATA[Payment on {0} site.]]></string>
+
+    <!-- Generic payment provider -->
+    <string name="_bx_payment_gc_cpt"><![CDATA[Generic]]></string>
+    <string name="_bx_payment_gc_dsc"><![CDATA[Isn't used to process payments directly. Is needed to store personal settings for usage in the other providers.]]></string>
+    <string name="_bx_payment_gc_currency_code_cpt"><![CDATA[Currency]]></string>
+    <string name="_bx_payment_gc_currency_code_dsc"><![CDATA[Select your own currency instead the default one]]></string>
+    <string name="_bx_payment_gc_currency_code_default"><![CDATA[Default]]></string>
+    <string name="_bx_payment_gc_err_not_available"><![CDATA[Generic payment provider isn't available for payments.]]></string>
+
+    <!-- Offline payment provider -->
+    <string name="_bx_payment_off_cpt"><![CDATA[Offline]]></string>
+    <string name="_bx_payment_off_dsc"><![CDATA[For offline payments like cash, etransfer, etc.]]></string>
+    <string name="_bx_payment_off_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_off_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+    <string name="_bx_payment_off_checkout_email_cpt"><![CDATA[Email]]></string>
+    <string name="_bx_payment_off_checkout_email_dsc"><![CDATA[Email to send notifications about checkout attempts to. Leave empty to receive notifications on your profile email.]]></string>
+    <string name="_bx_payment_off_err_not_available"><![CDATA[Offline payment provider isn't available for online payments.]]></string>
+    <string name="_bx_payment_txt_name_offline"><![CDATA[Cash]]></string>
+    <string name="_bx_payment_txt_cart_offline"><![CDATA[Cash]]></string>
+
+    <!-- Credits payment provider -->
+    <string name="_bx_payment_cdt_cpt"><![CDATA[Credits]]></string>
+    <string name="_bx_payment_cdt_dsc"><![CDATA[Credits payment provider]]></string>
+    <string name="_bx_payment_cdt_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_cdt_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+    <string name="_bx_payment_cdt_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_cdt_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_cdt_err_not_available"><![CDATA[Checkout with Credits isn't available now.]]></string>
+    <string name="_bx_payment_cdt_err_wrong_balance"><![CDATA[Insufficient funds to write off.]]></string>
+    <string name="_bx_payment_cdt_err_wrong_transaction"><![CDATA[Transaction verification failed.]]></string>
+    <string name="_bx_payment_txt_name_credits"><![CDATA[Credits]]></string>
+    <string name="_bx_payment_txt_cart_credits"><![CDATA[Credits]]></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]]></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_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_data_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_not_completed"><![CDATA[Payment is not completed.]]></string>
+    <string name="_bx_payment_pp_err_wrong_vendor"><![CDATA[Wrong vendor.]]></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_msg_verified"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_txt_name_paypal"><![CDATA[PayPal]]></string>
+    <string name="_bx_payment_txt_cart_paypal"><![CDATA[PayPal]]></string>
+
+    <!-- PayPal API payment provider -->
+    <string name="_bx_payment_pp_api_cpt"><![CDATA[PayPal API]]></string>
+    <string name="_bx_payment_pp_api_dsc"><![CDATA[PayPal payment provider (API based integration)]]></string>
+    <string name="_bx_payment_pp_api_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_pp_api_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+    <string name="_bx_payment_pp_api_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_pp_api_hidden_dsc"><![CDATA[Hide provider if you don't want to accept new payments but already have active subscriptions.]]></string>
+    <string name="_bx_payment_pp_api_mode_cpt"><![CDATA[Mode]]></string>
+    <string name="_bx_payment_pp_api_mode_dsc"><![CDATA[Mode to process payments]]></string>
+    <string name="_bx_payment_pp_api_mode_live"><![CDATA[live]]></string>
+    <string name="_bx_payment_pp_api_mode_test"><![CDATA[test]]></string>
+    <string name="_bx_payment_pp_api_live_account_cpt"><![CDATA[Account (live)]]></string>
+    <string name="_bx_payment_pp_api_live_account_dsc"><![CDATA[Email address which is used to access your PayPal account.]]></string>
+    <string name="_bx_payment_pp_api_live_client_id_cpt"><![CDATA[Client ID (live)]]></string>
+    <string name="_bx_payment_pp_api_live_client_id_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_live_secret_cpt"><![CDATA[Secret (live)]]></string>
+    <string name="_bx_payment_pp_api_live_secret_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_test_account_cpt"><![CDATA[Account (test)]]></string>
+    <string name="_bx_payment_pp_api_test_account_dsc"><![CDATA[Email address which is used to access your PayPal account.]]></string>
+    <string name="_bx_payment_pp_api_test_client_id_cpt"><![CDATA[Client ID (test)]]></string>
+    <string name="_bx_payment_pp_api_test_client_id_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_test_secret_cpt"><![CDATA[Secret (test)]]></string>
+    <string name="_bx_payment_pp_api_test_secret_dsc"><![CDATA[A part of application's credentials.]]></string>
+    <string name="_bx_payment_pp_api_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+    <string name="_bx_payment_pp_api_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+    <string name="_bx_payment_pp_api_err_cannot_authorize"><![CDATA[Can't authorize the approved order.]]></string>
+    <string name="_bx_payment_pp_api_err_cannot_capture"><![CDATA[Can't finalize checkout.]]></string>
+    <string name="_bx_payment_pp_api_err_no_item"><![CDATA[There is nothing to subscribe.]]></string>
+    <string name="_bx_payment_pp_api_err_wrong_item"><![CDATA[The product you want to subscribe to has incorrect data on PayPal end. Please report.]]></string>
+    <string name="_bx_payment_pp_api_err_no_subscription"><![CDATA[The subscription data isn't available or incorrect.]]></string>
+    <string name="_bx_payment_pp_api_err_subscription_not_confirmed"><![CDATA[Subscription wasn't confirmed.]]></string>
+    <string name="_bx_payment_pp_api_msg_authorized"><![CDATA[The order was successfully authorized.]]></string>
+    <string name="_bx_payment_pp_api_msg_captured"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_pp_api_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_txt_name_paypal_api"><![CDATA[PayPal]]></string>
+    <string name="_bx_payment_txt_cart_paypal_api"><![CDATA[PayPal]]></string>
+    <string name="_bx_payment_txt_subscribe_paypal_api"><![CDATA[PayPal]]></string>
+
+    <!-- Chargebee payment provider -->
+    <string name="_bx_payment_cbee_cpt"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_cbee_dsc"><![CDATA[If enabled, users can checkout using Chargebee's hosted pages.]]></string>
+    <string name="_bx_payment_cbee_v3_cpt"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_cbee_v3_dsc"><![CDATA[If enabled, users can checkout using Chargebee's drop-in script.]]></string>
+    <string name="_bx_payment_cbee_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_cbee_active_dsc"><![CDATA[Activate(Deactivate) provider. Note. It's recommended to use SSL for better payment processing.]]></string>
+    <string name="_bx_payment_cbee_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_cbee_hidden_dsc"><![CDATA[Hide provider if you don't want to accept new payments but already have active subscriptions.]]></string>
+    <string name="_bx_payment_cbee_mode_cpt"><![CDATA[Mode]]></string>
+    <string name="_bx_payment_cbee_mode_dsc"><![CDATA[Mode to process payments]]></string>
+    <string name="_bx_payment_cbee_mode_live"><![CDATA[live]]></string>
+    <string name="_bx_payment_cbee_mode_test"><![CDATA[test]]></string>
+    <string name="_bx_payment_cbee_live_site_cpt"><![CDATA[Site (live)]]></string>
+    <string name="_bx_payment_cbee_live_site_dsc"><![CDATA[Your site name registered in Chargebee for 'live' mode]]></string>
+    <string name="_bx_payment_cbee_live_api_key_cpt"><![CDATA[API Key (live)]]></string>
+    <string name="_bx_payment_cbee_live_api_key_dsc"><![CDATA[Your Chargebee API Access key for 'live' mode]]></string>
+    <string name="_bx_payment_cbee_test_site_cpt"><![CDATA[Site (test)]]></string>
+    <string name="_bx_payment_cbee_test_site_dsc"><![CDATA[Your site name registered in Chargebee for 'test' mode]]></string>
+    <string name="_bx_payment_cbee_test_api_key_cpt"><![CDATA[API Key (test)]]></string>
+    <string name="_bx_payment_cbee_test_api_key_dsc"><![CDATA[Your Chargebee API Access key for 'test' mode]]></string>
+    <string name="_bx_payment_cbee_check_amount_cpt"><![CDATA[Enable amount checking]]></string>
+    <string name="_bx_payment_cbee_check_amount_dsc"><![CDATA[Enable amount checking for Chargebee Webhooks (recomended). However checking should be disabled when discounts and coupons are used.]]></string>
+    <string name="_bx_payment_cbee_ssl_cpt"><![CDATA[Enable SSL]]></string>
+    <string name="_bx_payment_cbee_ssl_dsc"><![CDATA[Enable SSL connection to communicate with Chargebee. Note. URLs below will be updated after saving.]]></string>
+    <string name="_bx_payment_cbee_cancellation_email_cpt"><![CDATA[Cancellation Email]]></string>
+    <string name="_bx_payment_cbee_expiration_email_cpt"><![CDATA[Expiration Email]]></string>
+    <string name="_bx_payment_cbee_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+    <string name="_bx_payment_cbee_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+    <string name="_bx_payment_cbee_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_cbee_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_cbee_txt_checkout_with_single"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_cbee_txt_checkout_with_recurring"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_cbee_menu_item_title_manager"><![CDATA[Self-serve Portal]]></string>
+    <string name="_bx_payment_txt_name_chargebee"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_txt_name_chargebee_v3"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_txt_cart_chargebee"><![CDATA[Chargebee]]></string>
+    <string name="_bx_payment_txt_cart_chargebee_v3"><![CDATA[Chargebee]]></string>
+
+    <!-- Stripe payment provider -->
+    <string name="_bx_payment_strp_cpt"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_strp_dsc"><![CDATA[Stripe payment provider]]></string>
+    <string name="_bx_payment_strp_v3_cpt"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_strp_v3_dsc"><![CDATA[Stripe payment provider with 3D Secure authentication for Strong Customer Authentication (SCA) support. Note, it doesn't allow to use recurring payments with trial period.]]></string>
+    <string name="_bx_payment_strp_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_strp_active_dsc"><![CDATA[Activate(Deactivate) provider. Note. It's recommended to use SSL for better payment processing.]]></string>
+    <string name="_bx_payment_strp_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_strp_hidden_dsc"><![CDATA[Hide provider if you don't want to accept new payments but already have active subscriptions.]]></string>
+    <string name="_bx_payment_strp_mode_cpt"><![CDATA[Mode]]></string>
+    <string name="_bx_payment_strp_mode_dsc"><![CDATA[Mode to process payments]]></string>
+    <string name="_bx_payment_strp_mode_live"><![CDATA[live]]></string>
+    <string name="_bx_payment_strp_mode_test"><![CDATA[test]]></string>
+    <string name="_bx_payment_strp_live_pub_key_cpt"><![CDATA[Public Key (live)]]></string>
+    <string name="_bx_payment_strp_live_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'live' mode]]></string>
+    <string name="_bx_payment_strp_live_sec_key_cpt"><![CDATA[Secret Key (live)]]></string>
+    <string name="_bx_payment_strp_live_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'live' mode]]></string>
+    <string name="_bx_payment_strp_test_pub_key_cpt"><![CDATA[Public Key (test)]]></string>
+    <string name="_bx_payment_strp_test_pub_key_dsc"><![CDATA[Your Public Key generated in Stripe for 'test' mode]]></string>
+    <string name="_bx_payment_strp_test_sec_key_cpt"><![CDATA[Secret Key (test)]]></string>
+    <string name="_bx_payment_strp_test_sec_key_dsc"><![CDATA[Your Stripe Secret Key for 'test' mode]]></string>
+    <string name="_bx_payment_strp_check_amount_cpt"><![CDATA[Enable amount checking]]></string>
+    <string name="_bx_payment_strp_check_amount_dsc"><![CDATA[Enable amount checking for Stripe Webhooks (recomended). However checking should be disabled when discounts and coupons are used.]]></string>
+    <string name="_bx_payment_strp_ssl_cpt"><![CDATA[Enable SSL]]></string>
+    <string name="_bx_payment_strp_ssl_dsc"><![CDATA[Enable SSL connection to communicate with Stripe. Note. URLs below will be updated after saving.]]></string>
+    <string name="_bx_payment_strp_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+    <string name="_bx_payment_strp_cancellation_email_cpt"><![CDATA[Cancellation Email]]></string>
+    <string name="_bx_payment_strp_expiration_email_cpt"><![CDATA[Expiration Email]]></string>
+    <string name="_bx_payment_strp_msg_authorized"><![CDATA[The order was successfully authorized.]]></string>
+    <string name="_bx_payment_strp_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_strp_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_strp_msg_details_changed"><![CDATA[Subscription details were changed.]]></string>
+    <string name="_bx_payment_strp_err_details_changed"><![CDATA[Cannot change subscription details. Recheck provided data and try again.]]></string>
+    <string name="_bx_payment_strp_msg_billing_changed"><![CDATA[Billing information was changed.]]></string>
+    <string name="_bx_payment_strp_err_billing_changed"><![CDATA[Cannot change billing information. Recheck provided data and try again.]]></string>
+    <string name="_bx_payment_strp_txt_checkout_with_single"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_strp_txt_checkout_with_recurring"><![CDATA[Checkout with {0}]]></string>
+    <string name="_bx_payment_strp_menu_item_title_details"><![CDATA[Details]]></string>
+    <string name="_bx_payment_strp_menu_item_title_details_change"><![CDATA[Change Details]]></string>
+    <string name="_bx_payment_strp_menu_item_title_billing"><![CDATA[Billing Info]]></string>
+    <string name="_bx_payment_strp_menu_item_title_billing_change"><![CDATA[Change Billing Info]]></string>
+    <string name="_bx_payment_strp_txt_plan"><![CDATA[Plan]]></string>
+    <string name="_bx_payment_strp_txt_cost"><![CDATA[Cost]]></string>
+    <string name="_bx_payment_strp_txt_cost_mask"><![CDATA[{0} {1} / {2}]]></string>
+    <string name="_bx_payment_strp_txt_status"><![CDATA[Status]]></string>
+    <string name="_bx_payment_strp_txt_created"><![CDATA[Created]]></string>
+    <string name="_bx_payment_strp_txt_started"><![CDATA[Started]]></string>
+    <string name="_bx_payment_strp_txt_trial_start"><![CDATA[Trial start]]></string>
+    <string name="_bx_payment_strp_txt_trial_end"><![CDATA[Trial end]]></string>
+    <string name="_bx_payment_strp_txt_cperiod_start"><![CDATA[Current period start]]></string>
+    <string name="_bx_payment_strp_txt_cperiod_end"><![CDATA[Current period end]]></string>
+    <string name="_bx_payment_strp_txt_card_brand"><![CDATA[Brand]]></string>
+    <string name="_bx_payment_strp_txt_card_origin"><![CDATA[Origin]]></string>
+    <string name="_bx_payment_strp_txt_card_type"><![CDATA[Type]]></string>
+    <string name="_bx_payment_strp_txt_card_number"><![CDATA[Number]]></string>
+    <string name="_bx_payment_strp_txt_card_number_mask"><![CDATA[....{0}]]></string>
+    <string name="_bx_payment_strp_txt_card_expires"><![CDATA[Expires]]></string>
+    <string name="_bx_payment_strp_txt_card_expires_mask"><![CDATA[{0} / {1}]]></string>
+    <string name="_bx_payment_strp_txt_card_cvc"><![CDATA[CVC check]]></string>
+    <string name="_bx_payment_strp_txt_card_cvc_passed"><![CDATA[passed]]></string>
+
+    <string name="_bx_payment_form_strp_details"><![CDATA[Stripe: Details Form]]></string>
+    <string name="_bx_payment_form_strp_details_display_edit"><![CDATA[Stripe: Edit Details Display]]></string>
+    <string name="_bx_payment_form_strp_details_input_item_id_sys"><![CDATA[Plan]]></string>
+    <string name="_bx_payment_form_strp_details_input_item_id"><![CDATA[Plan]]></string>
+    <string name="_bx_payment_form_strp_details_input_item_id_err"><![CDATA[You need to select some plan here]]></string>
+    <string name="_bx_payment_form_strp_details_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_details_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_details_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_strp_details_input_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_payment_form_strp_card"><![CDATA[Stripe: Card Form]]></string>
+    <string name="_bx_payment_form_strp_card_display_add"><![CDATA[Stripe: Add Card Display]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number_sys"><![CDATA[Card Number]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number"><![CDATA[Card Number]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number_inf"><![CDATA[16 digits without spaces describing your card number]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_number_err"><![CDATA[You need to enter card number here]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_sys"><![CDATA[Expiry Date]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire"><![CDATA[Expiry Date]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_month"><![CDATA[Month]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_year"><![CDATA[Year]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_inf"><![CDATA[Use 'mm yyyy' format]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_expire_err"><![CDATA[You need to enter expiry date in specified format here]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv_sys"><![CDATA[CVV]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv"><![CDATA[CVV]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv_inf"><![CDATA[Three digits from the back side of your card.]]></string>
+    <string name="_bx_payment_form_strp_card_input_card_cvv_err"><![CDATA[You need to enter card CVV here]]></string>
+    <string name="_bx_payment_form_strp_card_input_submit_sys"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_card_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_strp_card_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_strp_card_input_cancel"><![CDATA[Cancel]]></string>
+
+    <string name="_bx_payment_txt_name_stripe"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_txt_cart_stripe"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_txt_name_stripe_v3"><![CDATA[Stripe]]></string>
+    <string name="_bx_payment_txt_cart_stripe_v3"><![CDATA[Stripe]]></string>
+
+    <!-- Stripe Connect payment provider -->
+    <string name="_bx_payment_strp_cnnt_cpt"><![CDATA[Stripe Connect]]></string>
+    <string name="_bx_payment_strp_cnnt_dsc"><![CDATA[Payment provider which is working in pairs with Stripe Connect app.]]></string>
+    <string name="_bx_payment_strp_cnnt_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string>
+    <string name="_bx_payment_strp_cnnt_connect_cpt"><![CDATA[Connected account]]></string>
+    <string name="_bx_payment_strp_cnnt_live_account_id_cpt"><![CDATA[Account ID (live)]]></string>
+    <string name="_bx_payment_strp_cnnt_test_account_id_cpt"><![CDATA[Account ID (test)]]></string>   
+
+    <!-- _bx_payment_aina_mode_live payment provider -->
+    <string name="_bx_payment_aina_cpt"><![CDATA[Apple In-App]]></string>
+    <string name="_bx_payment_aina_dsc"><![CDATA[Apple In-App payment provider]]></string>
+    <string name="_bx_payment_aina_active_cpt"><![CDATA[Active]]></string>
+    <string name="_bx_payment_aina_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string>
+    <string name="_bx_payment_aina_hidden_cpt"><![CDATA[Hidden]]></string>
+    <string name="_bx_payment_aina_hidden_dsc"><![CDATA[Recommended. The provider should be hidden in WEB because it can be used in mobile app only.]]></string>
+    <string name="_bx_payment_aina_secret_cpt"><![CDATA[Shared Secret]]></string>
+    <string name="_bx_payment_aina_secret_dsc"><![CDATA[It's the app-specific unique code to receive receipts for auto-renewable subscriptions.]]></string>
+    <string name="_bx_payment_aina_notify_url_cpt"><![CDATA[URL for App Store Server Notifications]]></string>
+    <string name="_bx_payment_aina_menu_item_title_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_aina_msg_charged"><![CDATA[Payment was successfully processed.]]></string>
+    <string name="_bx_payment_aina_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+    <string name="_bx_payment_txt_name_apple_in_app"><![CDATA[Apple In-App]]></string>
+    <string name="_bx_payment_txt_cart_apple_in_app"><![CDATA[Apple In-App]]></string>
+</resources>

+ 32 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/install/sql/enable-app.sql

@@ -0,0 +1,32 @@
+-- PAGES: config_api
+
+
+-- PAGES: active_api
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_join' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_join';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_carts' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_carts';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_cart' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_cart';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_cart_thank_you' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_cart_thank_you';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_history' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_history';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_sbs_list_my' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_sbs_list_my';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_sbs_list_all' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_sbs_list_all';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_sbs_history' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_sbs_history';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_orders' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_orders';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_details' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_details';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_invoices' AND `module`='bx_payment' AND `title_system`='' AND `title`='_bx_payment_page_block_title_invoices';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_payment_checkout_offline' AND `module`='bx_payment' AND `title_system`='_bx_payment_page_block_title_sys_checkout_offline' AND `title`='_bx_payment_page_block_title_checkout_offline';
+
+
+-- MENUS:
+
+-- MENUS: config_api
+
+-- MENUS: active_api
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_account_settings' AND `module`='bx_payment' AND `name`='payment-details';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_cart_submenu' AND `module`='bx_payment' AND `name`='cart';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_cart_submenu' AND `module`='bx_payment' AND `name`='cart-history';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_sbs_submenu' AND `module`='bx_payment' AND `name`='sbs-list-all';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_sbs_submenu' AND `module`='bx_payment' AND `name`='sbs-list-my';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_sbs_submenu' AND `module`='bx_payment' AND `name`='sbs-history';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_sbs_actions' AND `module`='bx_payment' AND `name`='sbs-request-cancelation';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_orders_submenu' AND `module`='bx_payment' AND `name`='orders-processed';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_payment_menu_orders_submenu' AND `module`='bx_payment' AND `name`='orders-pending';

+ 210 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/install/sql/enable.sql

@@ -0,0 +1,210 @@
+SET @sName = 'bx_payment';
+
+
+-- OPTIONS
+SET @iTypeOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_options_types` WHERE `group` = 'modules');
+INSERT INTO `sys_options_types`(`group`, `name`, `caption`, `icon`, `order`) VALUES 
+('modules', @sName, '_bx_payment', 'bx_payment@modules/boonex/payment/|std-icon.svg', @iTypeOrder + 1);
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_payment_general', '_bx_payment_options_category_general', 1);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_site_admin', '', @iCategoryId, '_bx_payment_option_site_admin', 'select', '', '', '', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:22:"get_options_site_admin";}', 1),
+('bx_payment_credits_only', '', @iCategoryId, '_bx_payment_option_credits_only', 'checkbox', '', '', '', '', 10),
+('bx_payment_single_seller', '', @iCategoryId, '_bx_payment_option_single_seller', 'checkbox', '', '', '', '', 11);
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_payment_currency', '_bx_payment_options_category_currency', 5);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_default_currency_code', 'USD', @iCategoryId, '_bx_payment_option_default_currency_code', 'select', 'Avail', '', '_bx_payment_option_err_default_currency_code', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:33:"get_options_default_currency_code";}', 1),
+('bx_payment_currency_exchange_api', '', @iCategoryId, '_bx_payment_option_currency_exchange_api', 'digit', '', '', '', '', 10);
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_payment_commissions', '_bx_payment_options_category_commissions', 10);
+SET @iCategoryId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_inv_issue_day', '1', @iCategoryId, '_bx_payment_option_inv_issue_day', 'digit', '', '', '', '', 1),
+('bx_payment_inv_lifetime', '4', @iCategoryId, '_bx_payment_option_inv_lifetime', 'digit', '', '', '', '', 2),
+('bx_payment_inv_expiraction_notify', '1', @iCategoryId, '_bx_payment_option_inv_expiraction_notify', 'digit', '', '', '', '', 3);
+
+
+-- PAGES & BLOCKS
+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_payment_join', '_bx_payment_page_title_sys_join', '_bx_payment_page_title_join', @sName, 5, 2147483647, 1, 'payment-join', 'page.php?i=payment-join', '', '', '', 0, 1, 0, 'BxPaymentPageJoin', 'modules/boonex/payment/classes/BxPaymentPageJoin.php'),
+
+('bx_payment_carts', '_bx_payment_page_title_sys_carts', '_bx_payment_page_title_carts', @sName, 5, 2147483647, 1, 'payment-carts', 'page.php?i=payment-carts', '', '', '', 0, 1, 0, 'BxPaymentPageCart', 'modules/boonex/payment/classes/BxPaymentPageCart.php'),
+('bx_payment_cart', '_bx_payment_page_title_sys_cart', '_bx_payment_page_title_cart', @sName, 5, 2147483647, 1, 'payment-cart', 'page.php?i=payment-cart', '', '', '', 0, 1, 0, 'BxPaymentPageCart', 'modules/boonex/payment/classes/BxPaymentPageCart.php'),
+('bx_payment_cart_thank_you', '_bx_payment_page_title_sys_cart_thank_you', '_bx_payment_page_title_cart_thank_you', @sName, 5, 2147483647, 1, 'payment-cart-thank-you', 'page.php?i=payment-cart-thank-you', '', '', '', 0, 1, 0, 'BxPaymentPageCart', 'modules/boonex/payment/classes/BxPaymentPageCart.php'),
+('bx_payment_history', '_bx_payment_page_title_sys_history', '_bx_payment_page_title_history', @sName, 5, 2147483647, 1, 'payment-history', 'page.php?i=payment-history', '', '', '', 0, 1, 0, 'BxPaymentPageHistory', 'modules/boonex/payment/classes/BxPaymentPageHistory.php'),
+
+('bx_payment_sbs_list_my', '_bx_payment_page_title_sys_sbs_list_my', '_bx_payment_page_title_sbs_list_my', @sName, 5, 2147483647, 1, 'payment-sbs-list-my', 'page.php?i=payment-sbs-list-my', '', '', '', 0, 1, 0, 'BxPaymentPageSubscriptions', 'modules/boonex/payment/classes/BxPaymentPageSubscriptions.php'),
+('bx_payment_sbs_list_all', '_bx_payment_page_title_sys_sbs_list_all', '_bx_payment_page_title_sbs_list_all', @sName, 5, 192, 1, 'payment-sbs-list-all', 'page.php?i=payment-sbs-list-all', '', '', '', 0, 1, 0, 'BxPaymentPageSubscriptions', 'modules/boonex/payment/classes/BxPaymentPageSubscriptions.php'),
+('bx_payment_sbs_history', '_bx_payment_page_title_sys_sbs_history', '_bx_payment_page_title_sbs_history', @sName, 5, 2147483647, 1, 'payment-sbs-history', 'page.php?i=payment-sbs-history', '', '', '', 0, 1, 0, 'BxPaymentPageSubscriptions', 'modules/boonex/payment/classes/BxPaymentPageSubscriptions.php'),
+
+('bx_payment_orders', '_bx_payment_page_title_sys_orders', '_bx_payment_page_title_orders', @sName, 5, 2147483647, 1, 'payment-orders', 'page.php?i=payment-orders', '', '', '', 0, 1, 0, 'BxPaymentPageOrders', 'modules/boonex/payment/classes/BxPaymentPageOrders.php'),
+('bx_payment_details', '_bx_payment_page_title_sys_details', '_bx_payment_page_title_details', @sName, 5, 2147483647, 1, 'payment-details', 'page.php?i=payment-details', '', '', '', 0, 1, 0, 'BxPaymentPageDetails', 'modules/boonex/payment/classes/BxPaymentPageDetails.php'),
+
+('bx_payment_invoices', '_bx_payment_page_title_sys_invoices', '_bx_payment_page_title_invoices', @sName, 5, 2147483647, 1, 'payment-invoices', 'page.php?i=payment-invoices', '', '', '', 0, 1, 0, 'BxPaymentPageInvoices', 'modules/boonex/payment/classes/BxPaymentPageInvoices.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_payment_join', 1, @sName, '_bx_payment_page_block_title_join', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:14:"get_block_join";s:6:"params";a:0:{}s:5:"class";s:4:"Join";}', 0, 0, 1),
+
+('bx_payment_carts', 1, @sName, '_bx_payment_page_block_title_carts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:15:"get_block_carts";s:6:"params";a:0:{}s:5:"class";s:4:"Cart";}', 0, 0, 1),
+('bx_payment_cart', 1, @sName, '_bx_payment_page_block_title_cart', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:14:"get_block_cart";s:6:"params";a:0:{}s:5:"class";s:4:"Cart";}', 0, 0, 1),
+('bx_payment_cart_thank_you', 1, @sName, '_bx_payment_page_block_title_cart_thank_you', 11, 2147483647, 'lang', '_bx_payment_page_block_content_cart_thank_you', 0, 0, 1),
+('bx_payment_history', 1, @sName, '_bx_payment_page_block_title_history', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:22:"get_block_cart_history";s:6:"params";a:0:{}s:5:"class";s:4:"Cart";}', 0, 0, 1),
+
+('bx_payment_sbs_list_my', 1, @sName, '_bx_payment_page_block_title_sbs_list_my', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:17:"get_block_list_my";s:6:"params";a:0:{}s:5:"class";s:13:"Subscriptions";}', 0, 0, 1),
+('bx_payment_sbs_list_all', 1, @sName, '_bx_payment_page_block_title_sbs_list_all', 11, 192, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:18:"get_block_list_all";s:6:"params";a:0:{}s:5:"class";s:13:"Subscriptions";}', 0, 0, 1),
+('bx_payment_sbs_history', 1, @sName, '_bx_payment_page_block_title_sbs_history', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:17:"get_block_history";s:6:"params";a:0:{}s:5:"class";s:13:"Subscriptions";}', 0, 0, 1),
+
+('bx_payment_orders', 1, @sName, '_bx_payment_page_block_title_orders', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:16:"get_block_orders";s:6:"params";a:0:{}s:5:"class";s:6:"Orders";}', 0, 0, 1),
+('bx_payment_details', 1, @sName, '_bx_payment_page_block_title_details', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:17:"get_block_details";s:6:"params";a:0:{}s:5:"class";s:7:"Details";}', 0, 0, 1),
+
+('bx_payment_invoices', 1, @sName, '_bx_payment_page_block_title_invoices', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:10:"bx_payment";s:6:"method";s:18:"get_block_invoices";s:6:"params";a:0:{}s:5:"class";s:11:"Commissions";}', 0, 0, 1);
+
+-- PAGE: offline checkout
+INSERT INTO `sys_objects_page`(`object`, `uri`, `title_system`, `title`, `module`, `type_id`, `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_payment_checkout_offline', 'payment-checkout-offline', '_bx_payment_page_title_sys_checkout_offline', '_bx_payment_page_title_checkout_offline', 'bx_payment', 2, 5, 2147483647, 1, 'page.php?i=payment-checkout-offline', '', '', '', 0, 1, 0, '', '');
+
+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_payment_checkout_offline', 1, 'bx_payment', '_bx_payment_page_block_title_sys_checkout_offline', '_bx_payment_page_block_title_checkout_offline', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:26:"get_block_checkout_offline";}', 0, 0, 1, 0);
+
+
+-- MENU: cart submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `title_public`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_cart_submenu', '_bx_payment_menu_title_cart_submenu', '_bx_payment_menu_title_public_cart_submenu', 'bx_payment_menu_cart_submenu', 'bx_payment', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_cart_submenu', 'bx_payment', '_bx_payment_menu_set_title_cart_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_cart_submenu', 'bx_payment', 'cart', '_bx_payment_menu_item_title_system_cart', '_bx_payment_menu_item_title_cart', 'page.php?i=payment-carts', '', '_self', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_payment_menu_cart_submenu', 'bx_payment', 'cart-history', '_bx_payment_menu_item_title_system_cart_history', '_bx_payment_menu_item_title_cart_history', 'page.php?i=payment-history', '', '_self', '', '', '', 2147483647, 1, 0, 1, 2);
+
+-- MENU: subscriptions submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_sbs_submenu', '_bx_payment_menu_title_sbs_submenu', 'bx_payment_menu_sbs_submenu', 'bx_payment', 6, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_sbs_submenu', 'bx_payment', '_bx_payment_menu_set_title_sbs_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_sbs_submenu', 'bx_payment', 'sbs-list-all', '_bx_payment_menu_item_title_system_sbs_list_all', '_bx_payment_menu_item_title_sbs_list_all', 'page.php?i=payment-sbs-list-all', '', '_self', '', '', '', 192, 1, 0, 1, 1),
+('bx_payment_menu_sbs_submenu', 'bx_payment', 'sbs-list-my', '_bx_payment_menu_item_title_system_sbs_list_my', '_bx_payment_menu_item_title_sbs_list_my', 'page.php?i=payment-sbs-list-my', '', '_self', '', '', '', 2147483646, 1, 0, 1, 2),
+('bx_payment_menu_sbs_submenu', 'bx_payment', 'sbs-history', '_bx_payment_menu_item_title_system_sbs_history', '_bx_payment_menu_item_title_sbs_history', 'page.php?i=payment-sbs-history', '', '_self', '', '', '', 2147483646, 1, 0, 1, 3);
+
+-- MENU: subscription actions
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_sbs_actions', '_bx_payment_menu_title_sbs_actions', 'bx_payment_menu_sbs_actions', 'bx_payment', 6, 0, 1, 'BxPaymentMenuSbsActions', 'modules/boonex/payment/classes/BxPaymentMenuSbsActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_sbs_actions', 'bx_payment', '_bx_payment_menu_set_title_sbs_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_sbs_actions', 'bx_payment', 'sbs-request-cancelation', '_bx_payment_menu_item_title_system_sbs_request_cancelation', '_bx_payment_menu_item_title_sbs_request_cancelation', 'javascript:void(0)', '{js_object}.requestCancelation(this, {id})', '_self', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_payment_menu_sbs_actions', 'bx_payment', 'sbs-cancel', '_bx_payment_menu_item_title_system_sbs_cancel', '_bx_payment_menu_item_title_sbs_cancel', 'javascript:void(0)', '{js_object}.cancel(this, {id}, \'{grid}\')', '_self', '', '', '', 2147483647, 0, 0, 1, 2);
+
+-- MENU: orders submenu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_payment_menu_orders_submenu', '_bx_payment_menu_title_orders_submenu', 'bx_payment_menu_orders_submenu', 'bx_payment', 6, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_payment_menu_orders_submenu', 'bx_payment', '_bx_payment_menu_set_title_orders_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_payment_menu_orders_submenu', 'bx_payment', 'orders-processed', '_bx_payment_menu_item_title_system_orders_processed', '_bx_payment_menu_item_title_orders_processed', 'page.php?i=payment-orders&type=processed', '', '_self', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_payment_menu_orders_submenu', 'bx_payment', 'orders-pending', '_bx_payment_menu_item_title_system_orders_pending', '_bx_payment_menu_item_title_orders_pending', 'page.php?i=payment-orders&type=pending', '', '_self', '', '', '', 2147483647, 1, 0, 1, 2);
+
+-- MENU: account settings menu
+SET @iMoAccountSettings = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_settings' AND `order` < 9999 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`, `editable`, `order`) VALUES
+('sys_account_settings', 'bx_payment', 'payment-details', '_bx_payment_menu_item_title_system_details', '_bx_payment_menu_item_title_details', 'page.php?i=payment-details', '', '_self', 'credit-card col-gray-dark', '', '', 2147483646, 1, 0, 1, @iMoAccountSettings + 1);
+
+-- 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_payment', 'payment-invoices', '_bx_payment_menu_item_title_system_admt_invoices', '_bx_payment_menu_item_title_admt_invoices', 'page.php?i=payment-invoices', '', '_self', 'credit-card', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers`(`name`, `class`, `file`, `service_call`) VALUES 
+(@sName, 'BxPaymentResponse', 'modules/boonex/payment/classes/BxPaymentResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'join', @iHandler),
+('profile', 'delete', @iHandler);
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'purchase', NULL, '_bx_payment_acl_action_purchase', '', 1, 3);
+SET @iIdActionPurchase = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'sell', NULL, '_bx_payment_acl_action_sell', '', 1, 3);
+SET @iIdActionSell = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+(@sName, 'manage any purchase', NULL, '_bx_payment_acl_action_manage_any_purchase', '', 1, 3);
+SET @iIdActionManageAnyPurchase = 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
+
+-- purchase
+(@iStandard, @iIdActionPurchase),
+(@iModerator, @iIdActionPurchase),
+(@iAdministrator, @iIdActionPurchase),
+(@iPremium, @iIdActionPurchase),
+
+-- sell
+(@iStandard, @iIdActionSell),
+(@iModerator, @iIdActionSell),
+(@iAdministrator, @iIdActionSell),
+(@iPremium, @iIdActionSell),
+
+-- manage any purchase
+(@iModerator, @iIdActionManageAnyPurchase),
+(@iAdministrator, @iIdActionManageAnyPurchase);
+
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES 
+(@sName, '_bx_payment_et_txt_name_paid_need_join', 'bx_payment_paid_need_join', '_bx_payment_et_txt_subject_paid_need_join', '_bx_payment_et_txt_body_paid_need_join'),
+(@sName, '_bx_payment_et_txt_name_cancelation_request', 'bx_payment_cancelation_request', '_bx_payment_et_txt_subject_cancelation_request', '_bx_payment_et_txt_body_cancelation_request'),
+(@sName, '_bx_payment_et_txt_name_expiration_notification_seller', 'bx_payment_expiration_notification_seller', '_bx_payment_et_txt_subject_expiration_notification_seller', '_bx_payment_et_txt_body_expiration_notification_seller'),
+(@sName, '_bx_payment_et_txt_name_expiration_notification_client', 'bx_payment_expiration_notification_client', '_bx_payment_et_txt_subject_expiration_notification_client', '_bx_payment_et_txt_body_expiration_notification_client'),
+(@sName, '_bx_payment_et_txt_name_expiring_notification_committent', 'bx_payment_expiring_notification_committent', '_bx_payment_et_txt_subject_expiring_notification_committent', '_bx_payment_et_txt_body_expiring_notification_committent'),
+(@sName, '_bx_payment_et_txt_name_overdue_notification_committent', 'bx_payment_overdue_notification_committent', '_bx_payment_et_txt_subject_overdue_notification_committent', '_bx_payment_et_txt_body_overdue_notification_committent'),
+(@sName, '_bx_payment_et_txt_name_checkout_offline', 'bx_payment_checkout_offline', '_bx_payment_et_txt_subject_checkout_offline', '_bx_payment_et_txt_body_checkout_offline'),
+(@sName, '_bx_payment_et_txt_name_wrong_balance', 'bx_payment_wrong_balance', '_bx_payment_et_txt_subject_wrong_balance', '_bx_payment_et_txt_body_wrong_balance');
+
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_payment_commissions', '0 * * * *', 'BxPaymentCronCommissions', 'modules/boonex/payment/classes/BxPaymentCronCommissions.php', ''),
+('bx_payment_currency', '0 0 * * *', 'BxPaymentCronCurrency', 'modules/boonex/payment/classes/BxPaymentCronCurrency.php', ''),
+('bx_payment_time_tracker', '* * * * *', 'BxPaymentCronTimeTracker', 'modules/boonex/payment/classes/BxPaymentCronTimeTracker.php', '');
+
+
+-- PAYMENTS
+INSERT INTO `sys_objects_payments` (`object`, `title`, `uri`) VALUES
+(@sName, '_bx_payment', 'payment');

+ 692 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/install/sql/install.sql

@@ -0,0 +1,692 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_payment_currencies` (
+  `id` int(11) NOT NULL auto_increment,
+  `code` varchar(4) NOT NULL default '',
+  `rate` float NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `code`(`code`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_providers` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) NOT NULL default '',
+  `caption` varchar(128) NOT NULL default '',
+  `description` varchar(128) NOT NULL default '',
+  `option_prefix` varchar(32) NOT NULL default '',
+  `for_visitor` tinyint(4) NOT NULL default '0',
+  `for_owner_only` tinyint(4) NOT NULL default '0',
+  `for_single` tinyint(4) NOT NULL default '0',
+  `for_recurring` tinyint(4) NOT NULL default '0',
+  `single_seller` tinyint(4) NOT NULL default '0',
+  `time_tracker` tinyint(4) NOT NULL default '0',
+  `active` tinyint(4) NOT NULL default '0',
+  `order` tinyint(4) NOT NULL default '0',
+  `class_name` varchar(128) NOT NULL default '',
+  `class_file` varchar(255) NOT NULL  default '',
+  PRIMARY KEY(`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_providers_options` (
+  `id` int(11) NOT NULL auto_increment,
+  `provider_id` varchar(64) NOT NULL default '',
+  `name` varchar(64) NOT NULL default '',
+  `type` varchar(64) NOT NULL default 'text',
+  `caption` varchar(255) NOT NULL default '',
+  `description` text NOT NULL default '',
+  `extra` varchar(255) NOT NULL default '',
+  `check_type` varchar(64) NOT NULL default '',
+  `check_params` varchar(128) NOT NULL default '',
+  `check_error` varchar(128) NOT NULL default '',
+  `order` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `name`(`name`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_user_values` (
+  `id` int(11) NOT NULL auto_increment,
+  `user_id` int(11) NOT NULL default '0',
+  `option_id` int(11) NOT NULL default '0',  
+  `value` varchar(255) NOT NULL default '',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `value`(`user_id`, `option_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_cart` (
+  `client_id` int(11) NOT NULL default '0',
+  `items` text NOT NULL default '',
+  `customs` text NOT NULL default '',
+  PRIMARY KEY(`client_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_transactions` (
+  `id` int(11) NOT NULL auto_increment,
+  `pending_id` int(11) NOT NULL default '0',
+  `client_id` int(11) NOT NULL default '0',
+  `seller_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `module_id` int(11) NOT NULL default '0',  
+  `item_id` int(11) NOT NULL default '0',
+  `item_count` int(11) NOT NULL default '0',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  `license` varchar(16) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  `new` tinyint(1) NOT NULL default '1',
+  PRIMARY KEY(`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_subscriptions` (
+  `id` int(11) NOT NULL auto_increment,
+  `pending_id` int(11) NOT NULL default '0',
+  `customer_id` varchar(32) NOT NULL default '',
+  `subscription_id` varchar(32) NOT NULL default '',
+  `period` int(11) unsigned NOT NULL default '1',
+  `period_unit` varchar(32) NOT NULL default '',
+  `trial` int(11) unsigned NOT NULL default '0',
+  `date_add` int(11) NOT NULL default '0',
+  `date_next` int(11) NOT NULL default '0',
+  `pay_attempts` tinyint(4) NOT NULL default '0',
+  `status` varchar(32) NOT NULL default 'unpaid',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `pending_id` (`pending_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_subscriptions_deleted` (
+  `id` int(11) NOT NULL auto_increment,
+  `pending_id` int(11) NOT NULL default '0',
+  `customer_id` varchar(32) NOT NULL default '',
+  `subscription_id` varchar(32) NOT NULL default '',
+  `period` int(11) unsigned NOT NULL default '1',
+  `period_unit` varchar(32) NOT NULL default '',
+  `trial` int(11) unsigned NOT NULL default '0',
+  `date_add` int(11) NOT NULL default '0',
+  `date_next` int(11) NOT NULL default '0',
+  `pay_attempts` tinyint(4) NOT NULL default '0',
+  `status` varchar(32) NOT NULL default 'unpaid',
+  `reason` varchar(16) NOT NULL default '',
+  `deleted` int(11) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `pending_id` (`pending_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_transactions_pending` (
+  `id` int(10) unsigned NOT NULL auto_increment,
+  `client_id` int(11) NOT NULL default '0',
+  `seller_id` int(11) NOT NULL default '0',
+  `type` varchar(16) NOT NULL default 'single',
+  `provider` varchar(32) NOT NULL default '',
+  `items` text NOT NULL default '',
+  `customs` text NOT NULL default '',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  `order` varchar(32) NOT NULL default '',
+  `data` text NOT NULL,
+  `error_code` varchar(16) NOT NULL default '',
+  `error_msg` varchar(255) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  `authorized` tinyint(4) NOT NULL default '0',
+  `processed` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_modules` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(32) NOT NULL default '',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `uri`(`name`)
+);
+
+INSERT INTO `bx_payment_modules`(`name`) VALUES
+(@sName);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_commissions` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) NOT NULL default '',
+  `caption` varchar(128) NOT NULL default '',
+  `description` varchar(128) NOT NULL default '',
+  `acl_id` int(11) NOT NULL default '0',
+  `percentage` float NOT NULL default '0',
+  `installment` float NOT NULL default '0',
+  `active` tinyint(4) NOT NULL default '0',
+  `order` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `name`(`name`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_invoices` (
+  `id` int(11) NOT NULL auto_increment,
+  `name` varchar(64) NOT NULL default '',
+  `commissionaire_id` varchar(32) NOT NULL default '',
+  `committent_id` varchar(32) NOT NULL default '',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  `period_start` int(11) NOT NULL default '0',
+  `period_end` int(11) NOT NULL default '0',
+  `date_issue` int(11) NOT NULL default '0',
+  `date_due` int(11) NOT NULL default '0',
+  `status` varchar(32) NOT NULL default 'unpaid',
+  `ntf_exp` tinyint(4) NOT NULL default '0',
+  `ntf_due` tinyint(4) NOT NULL default '0',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `name`(`name`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_payment_stripe_payments_pending` (
+  `id` int(11) NOT NULL auto_increment,
+  `subscription_id` varchar(32) NOT NULL default '',
+  `amount` float NOT NULL default '0',
+  `currency` varchar(4) NOT NULL default '',
+  PRIMARY KEY(`id`),
+  UNIQUE KEY `subscription_id` (`subscription_id`)
+);
+
+-- Generic payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `time_tracker`, `active`, `order`, `class_name`) VALUES
+('generic', '_bx_payment_gc_cpt', '_bx_payment_gc_dsc', 'gc_', 0, 0, 0, 0, 0, 0, 0, 'BxPaymentProviderGeneric');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'gc_currency_code', 'select', '_bx_payment_gc_currency_code_cpt', '_bx_payment_gc_currency_code_dsc', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:34:"get_options_personal_currency_code";}', '', '', '', 1);
+
+-- Offline payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `time_tracker`, `active`, `order`, `class_name`) VALUES
+('offline', '_bx_payment_off_cpt', '_bx_payment_off_dsc', 'off_', 0, 1, 0, 0, 0, 1, 5, 'BxPaymentProviderOffline');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'off_active', 'checkbox', '_bx_payment_off_active_cpt', '_bx_payment_off_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'off_checkout_email', 'text', '_bx_payment_off_checkout_email_cpt', '_bx_payment_off_checkout_email_dsc', '', 'EmailOrEmpty', '', '_sys_form_account_input_email_error', 2);
+
+
+-- Credits payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `time_tracker`, `active`, `order`, `class_name`) VALUES
+('credits', '_bx_payment_cdt_cpt', '_bx_payment_cdt_dsc', 'cdt_', 0, 1, 1, 1, 1, 1, 6, 'BxPaymentProviderCredits');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'cdt_active', 'checkbox', '_bx_payment_cdt_active_cpt', '_bx_payment_cdt_active_dsc', '', '', '', '', 1);
+
+
+-- PayPal payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `active`, `order`, `class_name`) VALUES
+('paypal', '_bx_payment_pp_cpt', '_bx_payment_pp_dsc', 'pp_', 1, 1, 0, 1, 1, 10, 'BxPaymentProviderPayPal');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'pp_active', 'checkbox', '_bx_payment_pp_active_cpt', '_bx_payment_pp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'pp_mode', 'select', '_bx_payment_pp_mode_cpt', '_bx_payment_pp_mode_dsc', '1|_bx_payment_pp_mode_live,2|_bx_payment_pp_mode_test', '', '', '', 2),
+(@iProviderId, 'pp_business', 'text', '_bx_payment_pp_business_cpt', '_bx_payment_pp_business_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 3),
+(@iProviderId, 'pp_prc_type', 'select', '_bx_payment_pp_prc_type_cpt', '_bx_payment_pp_prc_type_dsc', '1|_bx_payment_pp_prc_type_direct,2|_bx_payment_pp_prc_type_pdt,3|_bx_payment_pp_prc_type_ipn', '', '', '', 4),
+(@iProviderId, 'pp_token', 'text', '_bx_payment_pp_token_cpt', '_bx_payment_pp_token_dsc', '', '', '', '', 5),
+(@iProviderId, 'pp_sandbox', 'text', '_bx_payment_pp_sandbox_cpt', '_bx_payment_pp_sandbox_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 6),
+(@iProviderId, 'pp_return_data_url', 'value', '_bx_payment_pp_return_data_url_cpt', '', '', '', '', '', 7);
+
+-- PayPal API payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `single_seller`, `active`, `order`, `class_name`) VALUES
+('paypal_api', '_bx_payment_pp_api_cpt', '_bx_payment_pp_api_dsc', 'pp_api_', 1, 1, 1, 1, 1, 15, 'BxPaymentProviderPayPalApi');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'pp_api_active', 'checkbox', '_bx_payment_pp_api_active_cpt', '_bx_payment_pp_api_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'pp_api_hidden', 'checkbox', '_bx_payment_pp_api_hidden_cpt', '_bx_payment_pp_api_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'pp_api_mode', 'select', '_bx_payment_pp_api_mode_cpt', '_bx_payment_pp_api_mode_dsc', '1|_bx_payment_pp_api_mode_live,2|_bx_payment_pp_api_mode_test', '', '', '', 3),
+(@iProviderId, 'pp_api_live_account', 'text', '_bx_payment_pp_api_live_account_cpt', '_bx_payment_pp_api_live_account_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 4),
+(@iProviderId, 'pp_api_live_client_id', 'text', '_bx_payment_pp_api_live_client_id_cpt', '_bx_payment_pp_api_live_client_id_dsc', '', '', '', '', 5),
+(@iProviderId, 'pp_api_live_secret', 'text', '_bx_payment_pp_api_live_secret_cpt', '_bx_payment_pp_api_live_secret_dsc', '', '', '', '', 6),
+(@iProviderId, 'pp_api_test_account', 'text', '_bx_payment_pp_api_test_account_cpt', '_bx_payment_pp_api_test_account_dsc', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 7),
+(@iProviderId, 'pp_api_test_client_id', 'text', '_bx_payment_pp_api_test_client_id_cpt', '_bx_payment_pp_api_test_client_id_dsc', '', '', '', '', 8),
+(@iProviderId, 'pp_api_test_secret', 'text', '_bx_payment_pp_api_test_secret_cpt', '_bx_payment_pp_api_test_secret_dsc', '', '', '', '', 9),
+(@iProviderId, 'pp_api_return_data_url', 'value', '_bx_payment_pp_api_return_data_url_cpt', '', '', '', '', '', 10),
+(@iProviderId, 'pp_api_notify_url', 'value', '_bx_payment_pp_api_notify_url_cpt', '', '', '', '', '', 11);
+
+-- Chargebee payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('chargebee', '_bx_payment_cbee_cpt', '_bx_payment_cbee_dsc', 'cbee_', 1, 0, 1, 1, 40, 'BxPaymentProviderChargebee');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'cbee_active', 'checkbox', '_bx_payment_cbee_active_cpt', '_bx_payment_cbee_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'cbee_hidden', 'checkbox', '_bx_payment_cbee_hidden_cpt', '_bx_payment_cbee_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'cbee_mode', 'select', '_bx_payment_cbee_mode_cpt', '_bx_payment_cbee_mode_dsc', '1|_bx_payment_cbee_mode_live,2|_bx_payment_cbee_mode_test', '', '', '', 3),
+(@iProviderId, 'cbee_live_site', 'text', '_bx_payment_cbee_live_site_cpt', '_bx_payment_cbee_live_site_dsc', '', '', '', '', 4),
+(@iProviderId, 'cbee_live_api_key', 'text', '_bx_payment_cbee_live_api_key_cpt', '_bx_payment_cbee_live_api_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'cbee_test_site', 'text', '_bx_payment_cbee_test_site_cpt', '_bx_payment_cbee_test_site_dsc', '', '', '', '', 6),
+(@iProviderId, 'cbee_test_api_key', 'text', '_bx_payment_cbee_test_api_key_cpt', '_bx_payment_cbee_test_api_key_dsc', '', '', '', '', 7),
+(@iProviderId, 'cbee_check_amount', 'checkbox', '_bx_payment_cbee_check_amount_cpt', '_bx_payment_cbee_check_amount_dsc', '', '', '', '', 8),
+(@iProviderId, 'cbee_ssl', 'checkbox', '_bx_payment_cbee_ssl_cpt', '_bx_payment_cbee_ssl_dsc', '', '', '', '', 9),
+(@iProviderId, 'cbee_cancellation_email', 'text', '_bx_payment_cbee_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 10),
+(@iProviderId, 'cbee_expiration_email', 'text', '_bx_payment_cbee_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 11),
+(@iProviderId, 'cbee_return_data_url', 'value', '_bx_payment_cbee_return_data_url_cpt', '', '', '', '', '', 12),
+(@iProviderId, 'cbee_notify_url', 'value', '_bx_payment_cbee_notify_url_cpt', '', '', '', '', '', 13);
+
+-- Chargebee V3 payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('chargebee_v3', '_bx_payment_cbee_v3_cpt', '_bx_payment_cbee_v3_dsc', 'cbee_v3_', 1, 1, 1, 1, 41, 'BxPaymentProviderChargebeeV3');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'cbee_v3_active', 'checkbox', '_bx_payment_cbee_active_cpt', '_bx_payment_cbee_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'cbee_v3_hidden', 'checkbox', '_bx_payment_cbee_hidden_cpt', '_bx_payment_cbee_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'cbee_v3_mode', 'select', '_bx_payment_cbee_mode_cpt', '_bx_payment_cbee_mode_dsc', '1|_bx_payment_cbee_mode_live,2|_bx_payment_cbee_mode_test', '', '', '', 3),
+(@iProviderId, 'cbee_v3_live_site', 'text', '_bx_payment_cbee_live_site_cpt', '_bx_payment_cbee_live_site_dsc', '', '', '', '', 4),
+(@iProviderId, 'cbee_v3_live_api_key', 'text', '_bx_payment_cbee_live_api_key_cpt', '_bx_payment_cbee_live_api_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'cbee_v3_test_site', 'text', '_bx_payment_cbee_test_site_cpt', '_bx_payment_cbee_test_site_dsc', '', '', '', '', 6),
+(@iProviderId, 'cbee_v3_test_api_key', 'text', '_bx_payment_cbee_test_api_key_cpt', '_bx_payment_cbee_test_api_key_dsc', '', '', '', '', 7),
+(@iProviderId, 'cbee_v3_check_amount', 'checkbox', '_bx_payment_cbee_check_amount_cpt', '_bx_payment_cbee_check_amount_dsc', '', '', '', '', 8),
+(@iProviderId, 'cbee_v3_ssl', 'checkbox', '_bx_payment_cbee_ssl_cpt', '_bx_payment_cbee_ssl_dsc', '', '', '', '', 9),
+(@iProviderId, 'cbee_v3_cancellation_email', 'text', '_bx_payment_cbee_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 10),
+(@iProviderId, 'cbee_v3_expiration_email', 'text', '_bx_payment_cbee_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 11),
+(@iProviderId, 'cbee_v3_return_data_url', 'value', '_bx_payment_cbee_return_data_url_cpt', '', '', '', '', '', 12),
+(@iProviderId, 'cbee_v3_notify_url', 'value', '_bx_payment_cbee_notify_url_cpt', '', '', '', '', '', 13);
+
+-- Stripe payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('stripe', '_bx_payment_strp_cpt', '_bx_payment_strp_dsc', 'strp_', 1, 1, 1, 1, 60, 'BxPaymentProviderStripe');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'strp_active', 'checkbox', '_bx_payment_strp_active_cpt', '_bx_payment_strp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'strp_hidden', 'checkbox', '_bx_payment_strp_hidden_cpt', '_bx_payment_strp_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'strp_mode', 'select', '_bx_payment_strp_mode_cpt', '_bx_payment_strp_mode_dsc', '1|_bx_payment_strp_mode_live,2|_bx_payment_strp_mode_test', '', '', '', 3),
+(@iProviderId, 'strp_live_pub_key', 'text', '_bx_payment_strp_live_pub_key_cpt', '_bx_payment_strp_live_pub_key_dsc', '', '', '', '', 4),
+(@iProviderId, 'strp_live_sec_key', 'text', '_bx_payment_strp_live_sec_key_cpt', '_bx_payment_strp_live_sec_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'strp_test_pub_key', 'text', '_bx_payment_strp_test_pub_key_cpt', '_bx_payment_strp_test_pub_key_dsc', '', '', '', '', 6),
+(@iProviderId, 'strp_test_sec_key', 'text', '_bx_payment_strp_test_sec_key_cpt', '_bx_payment_strp_test_sec_key_dsc', '', '', '', '', 7),
+(@iProviderId, 'strp_check_amount', 'checkbox', '_bx_payment_strp_check_amount_cpt', '_bx_payment_strp_check_amount_dsc', '', '', '', '', 8),
+(@iProviderId, 'strp_ssl', 'checkbox', '_bx_payment_strp_ssl_cpt', '_bx_payment_strp_ssl_dsc', '', '', '', '', 9),
+(@iProviderId, 'strp_cancellation_email', 'text', '_bx_payment_strp_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 10),
+(@iProviderId, 'strp_expiration_email', 'text', '_bx_payment_strp_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 11),
+(@iProviderId, 'strp_notify_url', 'value', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 12);
+
+-- Stripe V3 payment provider (with 3D Secure authentication for Strong Customer Authentication (SCA) support)
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('stripe_v3', '_bx_payment_strp_v3_cpt', '_bx_payment_strp_v3_dsc', 'strp_v3_', 1, 1, 1, 1, 61, 'BxPaymentProviderStripeV3');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'strp_v3_active', 'checkbox', '_bx_payment_strp_active_cpt', '_bx_payment_strp_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'strp_v3_hidden', 'checkbox', '_bx_payment_strp_hidden_cpt', '_bx_payment_strp_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'strp_v3_mode', 'select', '_bx_payment_strp_mode_cpt', '_bx_payment_strp_mode_dsc', '1|_bx_payment_strp_mode_live,2|_bx_payment_strp_mode_test', '', '', '', 3),
+(@iProviderId, 'strp_v3_live_pub_key', 'text', '_bx_payment_strp_live_pub_key_cpt', '_bx_payment_strp_live_pub_key_dsc', '', '', '', '', 4),
+(@iProviderId, 'strp_v3_live_sec_key', 'text', '_bx_payment_strp_live_sec_key_cpt', '_bx_payment_strp_live_sec_key_dsc', '', '', '', '', 5),
+(@iProviderId, 'strp_v3_test_pub_key', 'text', '_bx_payment_strp_test_pub_key_cpt', '_bx_payment_strp_test_pub_key_dsc', '', '', '', '', 6),
+(@iProviderId, 'strp_v3_test_sec_key', 'text', '_bx_payment_strp_test_sec_key_cpt', '_bx_payment_strp_test_sec_key_dsc', '', '', '', '', 7),
+(@iProviderId, 'strp_v3_check_amount', 'checkbox', '_bx_payment_strp_check_amount_cpt', '_bx_payment_strp_check_amount_dsc', '', '', '', '', 8),
+(@iProviderId, 'strp_v3_ssl', 'checkbox', '_bx_payment_strp_ssl_cpt', '_bx_payment_strp_ssl_dsc', '', '', '', '', 9),
+(@iProviderId, 'strp_v3_cancellation_email', 'text', '_bx_payment_strp_cancellation_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 10),
+(@iProviderId, 'strp_v3_expiration_email', 'text', '_bx_payment_strp_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_bx_payment_form_input_email_err_cor_or_emp', 11),
+(@iProviderId, 'strp_v3_notify_url', 'value', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 12);
+
+-- Stripe Connect payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('stripe_connect', '_bx_payment_strp_cnnt_cpt', '_bx_payment_strp_cnnt_dsc', 'strp_cnnt_', 1, 1, 1, 1, 65, 'BxPaymentProviderStripeConnect');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'strp_cnnt_mode', 'value', '_bx_payment_strp_mode_cpt', '', '', '', '', '', 1),
+(@iProviderId, 'strp_cnnt_connect', 'custom', '_bx_payment_strp_cnnt_connect_cpt', '', '', '', '', '', 2),
+(@iProviderId, 'strp_cnnt_live_account_id', 'value', '_bx_payment_strp_cnnt_live_account_id_cpt', '', '', '', '', '', 3),
+(@iProviderId, 'strp_cnnt_test_account_id', 'value', '_bx_payment_strp_cnnt_test_account_id_cpt', '', '', '', '', '', 4);
+
+-- Apple In-App payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_owner_only`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('apple_in_app', '_bx_payment_aina_cpt', '_bx_payment_aina_dsc', 'aina_', 0, 1, 1, 1, 1, 70, 'BxPaymentProviderAppleInApp');
+SET @iProviderId = LAST_INSERT_ID();
+
+INSERT INTO `bx_payment_providers_options`(`provider_id`, `name`, `type`, `caption`, `description`, `extra`, `check_type`, `check_params`, `check_error`, `order`) VALUES
+(@iProviderId, 'aina_active', 'checkbox', '_bx_payment_aina_active_cpt', '_bx_payment_aina_active_dsc', '', '', '', '', 1),
+(@iProviderId, 'aina_hidden', 'checkbox', '_bx_payment_aina_hidden_cpt', '_bx_payment_aina_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'aina_secret', 'text', '_bx_payment_aina_secret_cpt', '_bx_payment_aina_secret_dsc', '', '', '', '', 3),
+(@iProviderId, 'aina_notify_url', 'value', '_bx_payment_aina_notify_url_cpt', '', '', '', '', '', 4);
+
+-- GRIDS
+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`, `visible_for_levels`, `show_total_count`, `override_class_name`, `override_class_file`) VALUES
+('bx_payment_grid_providers', 'Sql', 'SELECT * FROM `bx_payment_providers` WHERE 1 ', 'bx_payment_providers', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'name', 'caption,description', 'auto', '', '', 192, 0, 'BxPaymentGridProviders', 'modules/boonex/payment/classes/BxPaymentGridProviders.php'),
+
+('bx_payment_grid_carts', 'Array', '', '', 'vendor_id', '', '', '', 20, NULL, 'start', '', '', '', 'like', '', '', 2147483647, 1, 'BxPaymentGridCarts', 'modules/boonex/payment/classes/BxPaymentGridCarts.php'),
+('bx_payment_grid_cart', 'Array', '', '', 'descriptor', '', '', '', 20, NULL, 'start', '', 'title,description', '', 'like', '', '', 2147483647, 1, 'BxPaymentGridCart', 'modules/boonex/payment/classes/BxPaymentGridCart.php'),
+
+('bx_payment_grid_sbs_list_my', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`seller_id` AS `seller_id`, `ts`.`customer_id` AS `customer_id`, `ts`.`subscription_id` AS `subscription_id`, `ttp`.`provider` AS `provider`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status` FROM `bx_payment_subscriptions` AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridSbsList', 'modules/boonex/payment/classes/BxPaymentGridSbsList.php'),
+('bx_payment_grid_sbs_list_all', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tac`.`email` AS `client_email`, `ttp`.`seller_id` AS `seller_id`, `ts`.`customer_id` AS `customer_id`, `ts`.`subscription_id` AS `subscription_id`, `ttp`.`provider` AS `provider`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status` FROM `bx_payment_subscriptions` AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` LEFT JOIN `sys_profiles` AS `tpc` ON `ttp`.`client_id`=`tpc`.`id` LEFT JOIN `sys_accounts` AS `tac` ON `tpc`.`account_id`=`tac`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'tac`.`email,ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 192, 0, 'BxPaymentGridSbsAdministration', 'modules/boonex/payment/classes/BxPaymentGridSbsAdministration.php'),
+('bx_payment_grid_sbs_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`seller_id` AS `seller_id`, `ttp`.`order` AS `transaction`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridSbsHistory', 'modules/boonex/payment/classes/BxPaymentGridSbsHistory.php'),
+
+('bx_payment_grid_orders_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `ttp`.`order` AS `transaction`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''single'' ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridHistory', 'modules/boonex/payment/classes/BxPaymentGridHistory.php'),
+('bx_payment_grid_orders_processed', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`author_id` AS `author_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `tt`.`item_count` AS `item_count`, `ttp`.`order` AS `transaction`, `ttp`.`error_msg` AS `error_msg`, `ttp`.`provider` AS `provider`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` LEFT JOIN `sys_profiles` AS `tup` ON `tt`.`client_id`=`tup`.`id` LEFT JOIN `sys_accounts` AS `tua` ON `tup`.`account_id`=`tua`.`id` WHERE 1 ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date,tua`.`name,tua`.`email', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridProcessed', 'modules/boonex/payment/classes/BxPaymentGridProcessed.php'),
+('bx_payment_grid_orders_pending', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`items` AS `items`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`order` AS `transaction`, `tt`.`error_msg` AS `error_msg`, `tt`.`provider` AS `provider`, `tt`.`date` AS `date` FROM `bx_payment_transactions_pending` AS `tt` LEFT JOIN `sys_profiles` AS `tup` ON `tt`.`client_id`=`tup`.`id` LEFT JOIN `sys_accounts` AS `tua` ON `tup`.`account_id`=`tua`.`id` WHERE 1 AND (ISNULL(`tt`.`order`) OR (NOT ISNULL(`tt`.`order`) AND `tt`.`error_code`<>''0'')) ', 'bx_payment_transactions_pending', 'id', 'date', '', '', 100, NULL, 'start', '', 'tt`.`order,tt`.`amount,tt`.`date,tua`.`name,tua`.`email', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridPending', 'modules/boonex/payment/classes/BxPaymentGridPending.php'),
+
+('bx_payment_grid_commissions', 'Sql', 'SELECT * FROM `bx_payment_commissions` WHERE 1 ', 'bx_payment_commissions', 'id', 'order', 'active', '', 100, NULL, 'start', '', 'name', 'caption,description', 'auto', '', '', 192, 1, 'BxPaymentGridCommissions', 'modules/boonex/payment/classes/BxPaymentGridCommissions.php'),
+('bx_payment_grid_invoices', 'Sql', 'SELECT * FROM `bx_payment_invoices` WHERE 1 ', 'bx_payment_invoices', 'id', '', '', '', 100, NULL, 'start', '', '', '', 'auto', '', '', 2147483647, 1, 'BxPaymentGridInvoices', 'modules/boonex/payment/classes/BxPaymentGridInvoices.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_payment_grid_providers', 'order', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_providers', 'switcher', '', '8%', 0, '0', '', 2),
+('bx_payment_grid_providers', 'caption', '_bx_payment_grid_column_title_pdrs_caption', '20%', 1, '16', '', 3),
+('bx_payment_grid_providers', 'description', '_bx_payment_grid_column_title_pdrs_description', '30%', 1, '32', '', 4),
+('bx_payment_grid_providers', 'for_visitor', '_bx_payment_grid_column_title_pdrs_for_visitor', '8%', 0, '8', '', 5),
+('bx_payment_grid_providers', 'for_single', '_bx_payment_grid_column_title_pdrs_for_single', '8%', 0, '8', '', 6),
+('bx_payment_grid_providers', 'for_recurring', '_bx_payment_grid_column_title_pdrs_for_recurring', '8%', 0, '8', '', 7),
+('bx_payment_grid_providers', 'single_seller', '_bx_payment_grid_column_title_pdrs_single_seller', '8%', 0, '8', '', 8),
+('bx_payment_grid_providers', 'time_tracker', '_bx_payment_grid_column_title_pdrs_time_tracker', '8%', 0, '8', '', 9),
+
+('bx_payment_grid_carts', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_carts', 'vendor_id', '_bx_payment_grid_column_title_crts_vendor_id', '40%', 0, '36', '', 2),
+('bx_payment_grid_carts', 'items_count', '_bx_payment_grid_column_title_crts_items_count', '20%', 0, '16', '', 3),
+('bx_payment_grid_carts', 'items_price', '_bx_payment_grid_column_title_crts_items_price', '20%', 0, '16', '', 4),
+('bx_payment_grid_carts', 'actions', '', '18%', 0, '', '', 5),
+
+('bx_payment_grid_cart', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_cart', 'title', '_bx_payment_grid_column_title_crt_title', '25%', 0, '24', '', 2),
+('bx_payment_grid_cart', 'description', '_bx_payment_grid_column_title_crt_description', '35%', 0, '48', '', 3),
+('bx_payment_grid_cart', 'quantity', '_bx_payment_grid_column_title_crt_quantity', '10%', 0, '16', '', 4),
+('bx_payment_grid_cart', 'price_single', '_bx_payment_grid_column_title_crt_price', '10%', 0, '16', '', 5),
+('bx_payment_grid_cart', 'actions', '', '18%', 0, '', '', 6),
+
+('bx_payment_grid_sbs_list_my', 'checkbox', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_sbs_list_my', 'seller_id', '_bx_payment_grid_column_title_sbs_seller_id', '16%', 0, '0', '', 2),
+('bx_payment_grid_sbs_list_my', 'customer_id', '_bx_payment_grid_column_title_sbs_customer_id', '10%', 0, '8', '', 3),
+('bx_payment_grid_sbs_list_my', 'subscription_id', '_bx_payment_grid_column_title_sbs_subscription_id', '10%', 0, '0', '', 4),
+('bx_payment_grid_sbs_list_my', 'provider', '_bx_payment_grid_column_title_sbs_provider', '10%', 0, '16', '', 5),
+('bx_payment_grid_sbs_list_my', 'date_add', '_bx_payment_grid_column_title_sbs_date_add', '14%', 0, '10', '', 6),
+('bx_payment_grid_sbs_list_my', 'date_next', '_bx_payment_grid_column_title_sbs_date_next', '14%', 0, '10', '', 7),
+('bx_payment_grid_sbs_list_my', 'status', '_bx_payment_grid_column_title_sbs_status', '6%', 0, '8', '', 8),
+('bx_payment_grid_sbs_list_my', 'actions', '', '18%', 0, '0', '', 9),
+
+('bx_payment_grid_sbs_list_all', 'seller_id', '_bx_payment_grid_column_title_sbs_seller_id', '12%', 0, '0', '', 1),
+('bx_payment_grid_sbs_list_all', 'client_id', '_bx_payment_grid_column_title_sbs_client_id', '12%', 0, '0', '', 2),
+('bx_payment_grid_sbs_list_all', 'client_email', '_bx_payment_grid_column_title_sbs_client_email', '15%', 0, '24', '', 3),
+('bx_payment_grid_sbs_list_all', 'customer_id', '_bx_payment_grid_column_title_sbs_customer_id', '5%', 0, '8', '', 4),
+('bx_payment_grid_sbs_list_all', 'subscription_id', '_bx_payment_grid_column_title_sbs_subscription_id', '5%', 0, '0', '', 5),
+('bx_payment_grid_sbs_list_all', 'provider', '_bx_payment_grid_column_title_sbs_provider', '5%', 0, '16', '', 6),
+('bx_payment_grid_sbs_list_all', 'date_add', '_bx_payment_grid_column_title_sbs_date_add', '12%', 0, '10', '', 7),
+('bx_payment_grid_sbs_list_all', 'date_next', '_bx_payment_grid_column_title_sbs_date_next', '12%', 0, '10', '', 8),
+('bx_payment_grid_sbs_list_all', 'status', '_bx_payment_grid_column_title_sbs_status', '6%', 0, '8', '', 9),
+('bx_payment_grid_sbs_list_all', 'actions', '', '16%', 0, '0', '', 10),
+
+('bx_payment_grid_sbs_history', 'seller_id', '_bx_payment_grid_column_title_sbs_seller_id', '24%', 0, '0', '', 1),
+('bx_payment_grid_sbs_history', 'transaction', '_bx_payment_grid_column_title_sbs_transaction', '22%', 0, '18', '', 2),
+('bx_payment_grid_sbs_history', 'license', '_bx_payment_grid_column_title_sbs_license', '22%', 0, '18', '', 3),
+('bx_payment_grid_sbs_history', 'amount', '_bx_payment_grid_column_title_sbs_amount', '10%', 1, '10', '', 4),
+('bx_payment_grid_sbs_history', 'date', '_bx_payment_grid_column_title_sbs_date', '10%', 0, '10', '', 5),
+('bx_payment_grid_sbs_history', 'actions', '', '12%', 0, '', '', 6),
+
+('bx_payment_grid_orders_history', 'seller_id', '_bx_payment_grid_column_title_ods_seller_id', '24%', 0, '0', '', 1),
+('bx_payment_grid_orders_history', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '22%', 0, '18', '', 2),
+('bx_payment_grid_orders_history', 'item', '_bx_payment_grid_column_title_ods_item', '22%', 0, '18', '', 3),
+('bx_payment_grid_orders_history', 'amount', '_bx_payment_grid_column_title_ods_amount', '10%', 1, '10', '', 4),
+('bx_payment_grid_orders_history', 'date', '_bx_payment_grid_column_title_ods_date', '10%', 0, '10', '', 5),
+('bx_payment_grid_orders_history', 'actions', '', '12%', 0, '', '', 6),
+
+('bx_payment_grid_orders_processed', 'checkbox', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_orders_processed', 'client_id', '_bx_payment_grid_column_title_ods_client_id', '16%', 0, '0', '', 2),
+('bx_payment_grid_orders_processed', 'author_id', '_bx_payment_grid_column_title_ods_author_id', '16%', 0, '0', '', 3),
+('bx_payment_grid_orders_processed', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '10%', 0, '8', '', 4),
+('bx_payment_grid_orders_processed', 'item', '_bx_payment_grid_column_title_ods_item', '20%', 0, '', '', 5),
+('bx_payment_grid_orders_processed', 'amount', '_bx_payment_grid_column_title_ods_amount', '10%', 1, '10', '', 6),
+('bx_payment_grid_orders_processed', 'date', '_bx_payment_grid_column_title_ods_date', '10%', 0, '10', '', 7),
+('bx_payment_grid_orders_processed', 'actions', '', '16%', 0, '0', '', 8),
+
+('bx_payment_grid_orders_pending', 'checkbox', '', '2%', 0, '', '', 1),
+('bx_payment_grid_orders_pending', 'client_id', '_bx_payment_grid_column_title_ods_client_id', '25%', 0, '0', '', 2),
+('bx_payment_grid_orders_pending', 'transaction', '_bx_payment_grid_column_title_ods_transaction', '25%', 0, '25', '', 3),
+('bx_payment_grid_orders_pending', 'amount', '_bx_payment_grid_column_title_ods_amount', '14%', 1, '14', '', 4),
+('bx_payment_grid_orders_pending', 'date', '_bx_payment_grid_column_title_ods_date', '14%', 0, '14', '', 5),
+('bx_payment_grid_orders_pending', 'actions', '', '20%', 0, '', '', 6),
+
+('bx_payment_grid_commissions', 'order', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_commissions', 'switcher', '', '8%', 0, '0', '', 2),
+('bx_payment_grid_commissions', 'caption', '_bx_payment_grid_column_title_cms_caption', '15%', 1, '16', '', 3),
+('bx_payment_grid_commissions', 'description', '_bx_payment_grid_column_title_cms_description', '20%', 1, '16', '', 4),
+('bx_payment_grid_commissions', 'acl_id', '_bx_payment_grid_column_title_cms_acl_id', '15%', 0, '16', '', 5),
+('bx_payment_grid_commissions', 'percentage', '_bx_payment_grid_column_title_cms_percentage', '10%', 0, '0', '', 6),
+('bx_payment_grid_commissions', 'installment', '_bx_payment_grid_column_title_cms_installment', '10%', 0, '0', '', 7),
+('bx_payment_grid_commissions', 'actions', '', '20%', 0, '0', '', 8),
+
+('bx_payment_grid_invoices', 'checkbox', '', '2%', 0, '0', '', 1),
+('bx_payment_grid_invoices', 'commissionaire_id', '_bx_payment_grid_column_title_inv_commissionaire_id', '10%', 1, '0', '', 2),
+('bx_payment_grid_invoices', 'committent_id', '_bx_payment_grid_column_title_inv_committent_id', '10%', 1, '0', '', 3),
+('bx_payment_grid_invoices', 'name', '_bx_payment_grid_column_title_inv_name', '8%', 1, '0', '', 4),
+('bx_payment_grid_invoices', 'period_start', '_bx_payment_grid_column_title_inv_period_start', '10%', 0, '0', '', 5),
+('bx_payment_grid_invoices', 'period_end', '_bx_payment_grid_column_title_inv_period_end', '10%', 0, '0', '', 6),
+('bx_payment_grid_invoices', 'amount', '_bx_payment_grid_column_title_inv_amount', '6%', 0, '0', '', 7),
+('bx_payment_grid_invoices', 'date_issue', '_bx_payment_grid_column_title_inv_date_issue', '10%', 0, '0', '', 8),
+('bx_payment_grid_invoices', 'date_due', '_bx_payment_grid_column_title_inv_date_due', '10%', 0, '0', '', 9),
+('bx_payment_grid_invoices', 'status', '_bx_payment_grid_column_title_inv_status', '6%', 0, '8', '', 10),
+('bx_payment_grid_invoices', 'actions', '', '18%', 0, '0', '', 11);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_payment_grid_carts', 'bulk', 'delete', '_bx_payment_grid_action_title_crts_delete', '', 0, 1, 1),
+('bx_payment_grid_carts', 'single', 'continue', '_bx_payment_grid_action_title_crts_continue', 'far credit-card', 1, 0, 1),
+('bx_payment_grid_carts', 'single', 'delete', '_bx_payment_grid_action_title_crts_delete', 'remove', 1, 1, 2),
+
+('bx_payment_grid_cart', 'bulk', 'checkout', '_bx_payment_grid_action_title_crt_checkout', '', 0, 0, 1),
+('bx_payment_grid_cart', 'single', 'delete', '_bx_payment_grid_action_title_crt_delete', 'remove', 1, 1, 1),
+('bx_payment_grid_cart', 'single', 'quantity_sub', '_bx_payment_grid_action_title_crt_quantity_sub', 'minus', 1, 0, 2),
+('bx_payment_grid_cart', 'single', 'quantity_add', '_bx_payment_grid_action_title_crt_quantity_add', 'plus', 1, 0, 3),
+
+('bx_payment_grid_sbs_list_my', 'single', 'view_order', '_bx_payment_grid_action_title_sbs_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_sbs_list_my', 'single', 'actions', '_bx_payment_grid_action_title_sbs_actions', 'cog', 1, 0, 2),
+
+('bx_payment_grid_sbs_list_all', 'single', 'view_order', '_bx_payment_grid_action_title_sbs_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_sbs_list_all', 'single', 'cancel', '_bx_payment_grid_action_title_sbs_cancel', 'ban', 1, 1, 2),
+('bx_payment_grid_sbs_list_all', 'single', 'delete', '_bx_payment_grid_action_title_sbs_delete', 'times', 1, 1, 3),
+
+('bx_payment_grid_sbs_history', 'single', 'view_order', '_bx_payment_grid_action_title_sbs_view_order', 'ellipsis-h', 1, 0, 1),
+
+('bx_payment_grid_orders_history', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+
+('bx_payment_grid_orders_processed', 'independent', 'add', '_bx_payment_grid_action_title_ods_add', '', 0, 0, 1),
+('bx_payment_grid_orders_processed', 'bulk', 'cancel', '_bx_payment_grid_action_title_ods_cancel', '', 0, 1, 1),
+('bx_payment_grid_orders_processed', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_orders_processed', 'single', 'cancel', '_bx_payment_grid_action_title_ods_cancel', 'times', 1, 1, 2),
+
+('bx_payment_grid_orders_pending', 'bulk', 'cancel', '_bx_payment_grid_action_title_ods_cancel', '', 0, 1, 1),
+('bx_payment_grid_orders_pending', 'single', 'view_order', '_bx_payment_grid_action_title_ods_view_order', 'ellipsis-h', 1, 0, 1),
+('bx_payment_grid_orders_pending', 'single', 'process', '_bx_payment_grid_action_title_ods_process', 'sync', 1, 0, 2),
+('bx_payment_grid_orders_pending', 'single', 'cancel', '_bx_payment_grid_action_title_ods_cancel', 'times', 1, 1, 3),
+
+('bx_payment_grid_commissions', 'independent', 'add', '_bx_payment_grid_action_title_cms_add', '', 0, 0, 1),
+('bx_payment_grid_commissions', 'bulk', 'delete', '_bx_payment_grid_action_title_cms_delete', '', 0, 1, 1),
+('bx_payment_grid_commissions', 'single', 'edit', '_bx_payment_grid_action_title_cms_edit', 'pencil-alt', 1, 0, 1),
+('bx_payment_grid_commissions', 'single', 'delete', '_bx_payment_grid_action_title_cms_delete', 'remove', 1, 1, 2),
+
+('bx_payment_grid_invoices', 'bulk', 'delete', '_bx_payment_grid_action_title_inv_delete', '', 0, 1, 1),
+('bx_payment_grid_invoices', 'single', 'pay', '_bx_payment_grid_action_title_inv_pay', 'credit-card', 1, 0, 1),
+('bx_payment_grid_invoices', 'single', 'edit', '_bx_payment_grid_action_title_inv_edit', 'pencil-alt', 1, 0, 2),
+('bx_payment_grid_invoices', 'single', 'delete', '_bx_payment_grid_action_title_inv_delete', 'remove', 1, 1, 3);
+
+
+-- FORMS
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_payment_form_details', @sName, '_bx_payment_form_details_form', '', '', 'submit', '', 'id', '', '', 'a:1:{s:14:"checker_helper";s:33:"BxPaymentDetailsFormCheckerHelper";}', 0, 1, 'BxPaymentFormDetails', 'modules/boonex/payment/classes/BxPaymentFormDetails.php'),
+
+('bx_payment_form_pendings', @sName, '_bx_payment_form_pendings_form', '', '', 'do_submit', 'bx_payment_transactions_pending', 'id', '', '', '', 0, 1, 'BxPaymentFormView', 'modules/boonex/payment/classes/BxPaymentFormView.php'),
+('bx_payment_form_processed', @sName, '_bx_payment_form_processed_form', '', '', 'do_submit', 'bx_payment_transactions', 'id', '', '', '', 0, 1, 'BxPaymentFormView', 'modules/boonex/payment/classes/BxPaymentFormView.php'),
+
+('bx_payment_form_commissions', @sName, '_bx_payment_form_commissions_form', '', '', 'do_submit', 'bx_payment_commissions', 'id', '', '', '', 0, 1, 'BxPaymentFormCommissions', 'modules/boonex/payment/classes/BxPaymentFormCommissions.php'),
+('bx_payment_form_invoices', @sName, '_bx_payment_form_invoices_form', '', '', 'do_submit', 'bx_payment_invoices', 'id', '', '', '', 0, 1, 'BxPaymentFormInvoices', 'modules/boonex/payment/classes/BxPaymentFormInvoices.php'),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card', @sName, '_bx_payment_form_rcrl_card', '', '', 'do_submit', '', '', '', '', '', 0, 1, '', ''),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details', @sName, '_bx_payment_form_strp_details', '', '', 'do_submit', '', '', '', '', '', 0, 1, '', ''),
+('bx_payment_form_strp_card', @sName, '_bx_payment_form_strp_card', '', '', 'do_submit', '', '', '', '', '', 0, 1, '', '');
+
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_payment_form_details_edit', @sName, 'bx_payment_form_details', '_bx_payment_form_details_display_edit', 0),
+
+('bx_payment_form_pendings_process', @sName, 'bx_payment_form_pendings', '_bx_payment_form_pendings_display_process', 0),
+('bx_payment_form_processed_add', @sName, 'bx_payment_form_processed', '_bx_payment_form_processed_display_add', 0),
+
+('bx_payment_form_commissions_add', @sName, 'bx_payment_form_commissions', '_bx_payment_form_commissions_display_add', 0),
+('bx_payment_form_commissions_edit', @sName, 'bx_payment_form_commissions', '_bx_payment_form_commissions_display_edit', 0),
+
+('bx_payment_form_invoices_edit', @sName, 'bx_payment_form_invoices', '_bx_payment_form_invoices_display_edit', 0),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card_add', @sName, 'bx_payment_form_rcrl_card', '_bx_payment_form_rcrl_card_display_add', 0),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details_edit', @sName, 'bx_payment_form_strp_details', '_bx_payment_form_strp_details_display_edit', 0),
+('bx_payment_form_strp_card_add', @sName, 'bx_payment_form_strp_card', '_bx_payment_form_strp_card_display_add', 0);
+
+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_payment_form_pendings', @sName, 'id', '0', '', 0, 'hidden', '_bx_payment_form_pendings_input_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'seller_id', '0', '', 0, 'hidden', '_bx_payment_form_pendings_input_seller_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'order', '', '', 0, 'text', '_bx_payment_form_pendings_input_order_sys', '_bx_payment_form_pendings_input_order', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_pendings_input_order_err', 'Xss', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'do_submit', '_bx_payment_form_pendings_input_process', '', 0, 'submit', '_bx_payment_form_pendings_input_process_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_pendings', @sName, 'do_cancel', '_bx_payment_form_pendings_input_cancel', '', 0, 'button', '_bx_payment_form_pendings_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_processed', @sName, 'seller_id', '0', '', 0, 'hidden', '_bx_payment_form_processed_input_seller_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'client_id', '0', '', 0, 'hidden', '_bx_payment_form_processed_input_client_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'client', '0', '', 0, 'custom', '_bx_payment_form_processed_input_client_sys', '_bx_payment_form_processed_input_client', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_client_err', 'Xss', '', 0, 0),
+('bx_payment_form_processed', @sName, 'order', '0', '', 0, 'text', '_bx_payment_form_processed_input_order_sys', '_bx_payment_form_processed_input_order', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_order_err', 'Xss', '', 0, 0),
+('bx_payment_form_processed', @sName, 'module_id', '0', '', 0, 'select', '_bx_payment_form_processed_input_module_id_sys', '_bx_payment_form_processed_input_module_id', '', 0, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_processed_input_module_id_err', 'Int', '', 0, 0),
+('bx_payment_form_processed', @sName, 'items', '0', '', 0, 'custom', '_bx_payment_form_processed_input_items_sys', '_bx_payment_form_processed_input_items', '', 0, 0, 0, '', '', '', '', '', '_bx_payment_form_processed_input_items_err', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'do_submit', '_bx_payment_form_processed_input_add', '', 0, 'submit', '_bx_payment_form_processed_input_add_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_processed', @sName, 'do_cancel', '_bx_payment_form_processed_input_cancel', '', 0, 'button', '_bx_payment_form_processed_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_commissions', @sName, 'caption', '0', '', 0, 'text_translatable', '_bx_payment_form_commissions_input_caption_sys', '_bx_payment_form_commissions_input_caption', '', 1, 0, 0, '', '', '', 'AvailTranslatable', 'a:1:{i:0;s:7:"caption";}', '_bx_payment_form_commissions_input_caption_err', 'Xss', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'description', '0', '', 0, 'textarea_translatable', '_bx_payment_form_commissions_input_description_sys', '_bx_payment_form_commissions_input_description', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'acl_id', '0', '', 0, 'select', '_bx_payment_form_commissions_input_acl_id_sys', '_bx_payment_form_commissions_input_acl_id', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'percentage', '0', '', 0, 'text', '_bx_payment_form_commissions_input_percentage_sys', '_bx_payment_form_commissions_input_percentage', '', 0, 0, 0, '', '', '', '', '', '', 'Float', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'installment', '0', '', 0, 'text', '_bx_payment_form_commissions_input_installment_sys', '_bx_payment_form_commissions_input_installment', '', 0, 0, 0, '', '', '', '', '', '', 'Float', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'do_submit', '_bx_payment_form_commissions_input_submit', '', 0, 'submit', '_bx_payment_form_commissions_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_commissions', @sName, 'do_cancel', '_bx_payment_form_commissions_input_cancel', '', 0, 'button', '_bx_payment_form_commissions_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_invoices', @sName, 'amount', '0', '', 0, 'text', '_bx_payment_form_invoices_input_amount_sys', '_bx_payment_form_invoices_input_amount', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_invoices_input_amount_err', 'Float', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'date_due', '', '', 0, 'datepicker', '_bx_payment_form_invoices_input_date_due_sys', '_bx_payment_form_invoices_input_date_due', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_invoices_input_date_due_err', 'DateUtc', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'status', '', '', 0, 'select', '_bx_payment_form_invoices_input_status_sys', '_bx_payment_form_invoices_input_status', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'do_submit', '_bx_payment_form_invoices_input_submit', '', 0, 'submit', '_bx_payment_form_invoices_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_invoices', @sName, 'do_cancel', '_bx_payment_form_invoices_input_cancel', '', 0, 'button', '_bx_payment_form_invoices_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card', @sName, 'pending_id', '0', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_pending_id_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'item', '', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_item_sys', '', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'token', '', '', 0, 'hidden', '_bx_payment_form_rcrl_card_input_token_sys', '', '', 0, 0, 0, 'a:1:{s:12:"data-recurly";s:5:"token";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'first_name', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_first_name_sys', '_bx_payment_form_rcrl_card_input_first_name', '', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:10:"first_name";}', '', '', 'Avail', '', '_bx_payment_form_rcrl_card_input_first_name_err', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'last_name', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_last_name_sys', '_bx_payment_form_rcrl_card_input_last_name', '', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:9:"last_name";}', '', '', 'Avail', '', '_bx_payment_form_rcrl_card_input_last_name_err', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'email', '', '', 0, 'text', '_bx_payment_form_rcrl_card_input_email_sys', '_bx_payment_form_rcrl_card_input_email', '', 1, 0, 0, '', '', '', 'Email', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_number', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_number_sys', '_bx_payment_form_rcrl_card_input_card_number', '_bx_payment_form_rcrl_card_input_card_number_inf', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:6:"number";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_expire', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_expire_sys', '_bx_payment_form_rcrl_card_input_card_expire', '_bx_payment_form_rcrl_card_input_card_expire_inf', 1, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'card_cvv', '', '', 0, 'custom', '_bx_payment_form_rcrl_card_input_card_cvv_sys', '_bx_payment_form_rcrl_card_input_card_cvv', '_bx_payment_form_rcrl_card_input_card_cvv_inf', 1, 0, 0, 'a:1:{s:12:"data-recurly";s:3:"cvv";}', '', '', '', '', '', 'Xss', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'do_submit', '_bx_payment_form_rcrl_card_input_submit', '', 0, 'submit', '_bx_payment_form_rcrl_card_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_rcrl_card', @sName, 'do_cancel', '_bx_payment_form_rcrl_card_input_cancel', '', 0, 'button', '_bx_payment_form_rcrl_card_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details', @sName, 'item_id', '', '', 0, 'select', '_bx_payment_form_strp_details_input_item_id_sys', '_bx_payment_form_strp_details_input_item_id', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_details_input_item_id_err', 'Int', '', 0, 0),
+('bx_payment_form_strp_details', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_details', @sName, 'do_submit', '_bx_payment_form_strp_details_input_submit', '', 0, 'submit', '_bx_payment_form_strp_details_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_details', @sName, 'do_cancel', '_bx_payment_form_strp_details_input_cancel', '', 0, 'button', '_bx_payment_form_strp_details_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+
+('bx_payment_form_strp_card', @sName, 'card_number', '', '', 0, 'text', '_bx_payment_form_strp_card_input_card_number_sys', '_bx_payment_form_strp_card_input_card_number', '_bx_payment_form_strp_card_input_card_number_inf', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_card_input_card_number_err', 'Xss', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'card_expire', '', '', 0, 'text', '_bx_payment_form_strp_card_input_card_expire_sys', '_bx_payment_form_strp_card_input_card_expire', '_bx_payment_form_strp_card_input_card_expire_inf', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_card_input_card_expire_err', 'Xss', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'card_cvv', '', '', 0, 'text', '_bx_payment_form_strp_card_input_card_cvv_sys', '_bx_payment_form_strp_card_input_card_cvv', '_bx_payment_form_strp_card_input_card_cvv_inf', 1, 0, 0, '', '', '', 'Avail', '', '_bx_payment_form_strp_card_input_card_cvv_err', 'Xss', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'do_submit', '_bx_payment_form_strp_card_input_submit', '', 0, 'submit', '_bx_payment_form_strp_card_input_submit_sys', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_payment_form_strp_card', @sName, 'do_cancel', '_bx_payment_form_strp_card_input_cancel', '', 0, 'button', '_bx_payment_form_strp_card_input_cancel_sys', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_payment_form_pendings_process', 'id', 2147483647, 1, 1),
+('bx_payment_form_pendings_process', 'seller_id', 2147483647, 1, 2),
+('bx_payment_form_pendings_process', 'order', 2147483647, 1, 3),
+('bx_payment_form_pendings_process', 'controls', 2147483647, 1, 4),
+('bx_payment_form_pendings_process', 'do_submit', 2147483647, 1, 5),
+('bx_payment_form_pendings_process', 'do_cancel', 2147483647, 1, 6),
+
+('bx_payment_form_processed_add', 'seller_id', 2147483647, 1, 2),
+('bx_payment_form_processed_add', 'client_id', 2147483647, 1, 3),
+('bx_payment_form_processed_add', 'client', 2147483647, 1, 4),
+('bx_payment_form_processed_add', 'order', 2147483647, 1, 5),
+('bx_payment_form_processed_add', 'module_id', 2147483647, 1, 6),
+('bx_payment_form_processed_add', 'items', 2147483647, 1, 7),
+('bx_payment_form_processed_add', 'controls', 2147483647, 1, 8),
+('bx_payment_form_processed_add', 'do_submit', 2147483647, 1, 9),
+('bx_payment_form_processed_add', 'do_cancel', 2147483647, 1, 10),
+
+('bx_payment_form_commissions_add', 'caption', 2147483647, 1, 1),
+('bx_payment_form_commissions_add', 'description', 2147483647, 1, 2),
+('bx_payment_form_commissions_add', 'acl_id', 2147483647, 1, 3),
+('bx_payment_form_commissions_add', 'percentage', 2147483647, 1, 4),
+('bx_payment_form_commissions_add', 'installment', 2147483647, 1, 5),
+('bx_payment_form_commissions_add', 'controls', 2147483647, 1, 6),
+('bx_payment_form_commissions_add', 'do_submit', 2147483647, 1, 7),
+('bx_payment_form_commissions_add', 'do_cancel', 2147483647, 1, 8),
+
+('bx_payment_form_commissions_edit', 'caption', 2147483647, 1, 1),
+('bx_payment_form_commissions_edit', 'description', 2147483647, 1, 2),
+('bx_payment_form_commissions_edit', 'acl_id', 2147483647, 1, 3),
+('bx_payment_form_commissions_edit', 'percentage', 2147483647, 1, 4),
+('bx_payment_form_commissions_edit', 'installment', 2147483647, 1, 5),
+('bx_payment_form_commissions_edit', 'controls', 2147483647, 1, 6),
+('bx_payment_form_commissions_edit', 'do_submit', 2147483647, 1, 7),
+('bx_payment_form_commissions_edit', 'do_cancel', 2147483647, 1, 8),
+
+('bx_payment_form_invoices_edit', 'amount', 2147483647, 1, 1),
+('bx_payment_form_invoices_edit', 'date_due', 2147483647, 1, 2),
+('bx_payment_form_invoices_edit', 'status', 2147483647, 1, 3),
+('bx_payment_form_invoices_edit', 'controls', 2147483647, 1, 4),
+('bx_payment_form_invoices_edit', 'do_submit', 2147483647, 1, 5),
+('bx_payment_form_invoices_edit', 'do_cancel', 2147483647, 1, 6),
+
+-- FORMS: Recurly
+('bx_payment_form_rcrl_card_add', 'pending_id', 2147483647, 1, 1),
+('bx_payment_form_rcrl_card_add', 'item', 2147483647, 1, 2),
+('bx_payment_form_rcrl_card_add', 'token', 2147483647, 1, 3),
+('bx_payment_form_rcrl_card_add', 'first_name', 2147483647, 1, 4),
+('bx_payment_form_rcrl_card_add', 'last_name', 2147483647, 1, 5),
+('bx_payment_form_rcrl_card_add', 'email', 2147483647, 1, 6),
+('bx_payment_form_rcrl_card_add', 'card_number', 2147483647, 1, 7),
+('bx_payment_form_rcrl_card_add', 'card_expire', 2147483647, 1, 8),
+('bx_payment_form_rcrl_card_add', 'card_cvv', 2147483647, 1, 9),
+('bx_payment_form_rcrl_card_add', 'controls', 2147483647, 1, 10),
+('bx_payment_form_rcrl_card_add', 'do_submit', 2147483647, 1, 11),
+('bx_payment_form_rcrl_card_add', 'do_cancel', 2147483647, 1, 12),
+
+-- FORMS: Stripe
+('bx_payment_form_strp_details_edit', 'item_id', 2147483647, 1, 1),
+('bx_payment_form_strp_details_edit', 'controls', 2147483647, 1, 2),
+('bx_payment_form_strp_details_edit', 'do_submit', 2147483647, 1, 3),
+('bx_payment_form_strp_details_edit', 'do_cancel', 2147483647, 1, 4),
+
+('bx_payment_form_strp_card_add', 'card_number', 2147483647, 1, 1),
+('bx_payment_form_strp_card_add', 'card_expire', 2147483647, 1, 2),
+('bx_payment_form_strp_card_add', 'card_cvv', 2147483647, 1, 3),
+('bx_payment_form_strp_card_add', 'controls', 2147483647, 1, 4),
+('bx_payment_form_strp_card_add', 'do_submit', 2147483647, 1, 5),
+('bx_payment_form_strp_card_add', 'do_cancel', 2147483647, 1, 6);
+
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`, `extendable`) VALUES
+('bx_payment_currencies', '_bx_payment_pre_lists_currencies', 'bx_payment', '0', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_payment_currencies', 'AUD', 1, 'AUD', 'A&#36;'),
+('bx_payment_currencies', 'CAD', 2, 'CAD', 'C&#36;'),
+('bx_payment_currencies', 'EUR', 3, 'EUR', '&#8364;'),
+('bx_payment_currencies', 'GBP', 4, 'GBP', '&#163;'),
+('bx_payment_currencies', 'USD', 5, 'USD', '&#36;'),
+('bx_payment_currencies', 'JPY', 6, 'YEN', '&#165;');
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, @sName, '_bx_payment', '_bx_payment', 'bx_payment@modules/boonex/payment/|std-icon.svg');
+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`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, @sName, 'extensions', '{url_studio}module.php?name=bx_payment', '', 'bx_payment@modules/boonex/payment/|std-icon.svg', '_bx_payment', '', '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));

+ 110 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/js/stripe_v3.js

@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxPaymentProviderStripeV3(oOptions) {
+    this.init(oOptions);
+}
+
+BxPaymentProviderStripeV3.prototype = new BxPaymentMain();
+
+BxPaymentProviderStripeV3.prototype.init = function(oOptions) {
+    this._sProvider = oOptions.sProvider;
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oPaymentProviderStripeV3' : oOptions.sObjName;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+
+    //-- For Stripe Connect payments
+    this._sConnectedAccountId = oOptions.sConnectedAccountId == undefined ? '' : oOptions.sConnectedAccountId;
+
+    //--- For Single payment
+    this._sObjNameGrid = oOptions.sObjNameGrid;
+
+    //--- For Recurring payment
+    this._sObjNameCart = oOptions.sObjNameCart;
+    this._iSellerId  = oOptions.iSellerId;
+    this._iModuleId  = oOptions.iModuleId;
+    this._iItemId  = oOptions.iItemId;
+    this._iItemCount  = oOptions.iItemCount;
+    this._sItemAddons  = oOptions.sItemAddons == undefined ? '' : oOptions.sItemAddons;
+    this._sRedirect  = oOptions.sRedirect;
+    this._sCustom  = oOptions.sCustom;
+
+    var $this = this;
+    var oConnectedAccount = this._sConnectedAccountId ? {stripeAccount: this._sConnectedAccountId} : {};
+    if(window.Stripe === undefined) {
+        $.getScript('https://js.stripe.com/v3/', function() {
+            $this._rHandler = Stripe(oOptions.sPublicKey, oConnectedAccount);
+        });
+    }
+    else
+        this._rHandler = Stripe(oOptions.sPublicKey, oConnectedAccount);
+};
+
+BxPaymentProviderStripeV3.prototype.onCartCheckout = function(oData) {
+    this._rHandler.redirectToCheckout({
+        sessionId: oData.session_id
+    }).then(function (oResult) {
+        if(oResult.error)
+            bx_alert(oResult.error.message);
+    }).catch(function(oError) {
+        console.error('Error:', oError);
+    });
+};
+
+BxPaymentProviderStripeV3.prototype.subscribe = function(oLink) {
+    return this.subscribeWithAddons(oLink);
+};
+    
+BxPaymentProviderStripeV3.prototype.subscribeWithAddons = function(oLink, mixedAddons) {
+    var oDate = new Date();
+
+    oLink = jQuery(oLink);
+    if(oLink.hasClass('bx-btn-disabled'))
+        return;
+
+    oLink.addClass('bx-btn-disabled');
+
+    this.loadingInPopup(oLink, true);
+
+    var aParams = {
+        seller_id: this._iSellerId,
+        seller_provider: this._sProvider,
+        module_id: this._iModuleId,
+        item_id: this._iItemId,
+        item_count: this._iItemCount,
+        item_addons: mixedAddons != undefined ? mixedAddons : this._sItemAddons,
+        redirect: this._sRedirect,
+        custom: this._sCustom,
+        _t: oDate.getTime()
+    };
+
+    $.post(this._sActionsUrl + 'call/' + this._sProvider + '/get_session_recurring/' + this._iSellerId + '/', aParams, function(oData) {
+        if(oData && oData.code != undefined && parseInt(oData.code) == 0)
+            oData.params = aParams;
+
+        oLink.removeClass('bx-btn-disabled');
+
+        processJsonData(oData);
+    }, 'json');
+};
+
+BxPaymentProviderStripeV3.prototype.onSubscribe = function(oData) {
+    this._rHandler.redirectToCheckout({
+        sessionId: oData.session_id
+    }).then(function (oResult) {
+        if(oResult.error)
+            bx_alert(oResult.error.message);
+    }).catch(function(oError) {
+        console.error('Error:', oError);
+    });
+};
+
+/** @} */

+ 5 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/template/cart_quantity.html

@@ -0,0 +1,5 @@
+<div class="bx-payment-cart-quantity flex items-center">
+    <div>__sub__</div>
+    <div class="px-2">__quantity__</div>
+    <div>__add__</div>
+</div>

+ 1 - 0
modules/boonex/payment/updates/14.0.9_15.0.0/source/template/details_form.html

@@ -0,0 +1 @@
+<div class="bx-payment-details bx-payment-details-__provider__ pt-4 first:pt-0">__form__</div>

+ 59 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/install/config.php

@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Persons',
+    'version_from' => '14.0.6',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/persons/updates/update_14.0.6_15.0.0/',
+    'home_uri' => 'persons_update_1406_1500',
+
+    'module_dir' => 'boonex/persons/',
+    'module_uri' => 'persons',
+
+    'db_prefix' => 'bx_persons_',
+    'class_prefix' => 'BxPersons',
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_persons_badge'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Persons',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 30 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/install/installer.php

@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPersonsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_persons_data', 'badge'))
+                $this->oDb->query("ALTER TABLE `bx_persons_data` ADD `badge` int(11) NOT NULL default '0' AFTER `cover_data`");
+            if(!$this->oDb->isFieldExists('bx_persons_data', 'badge_link'))
+                $this->oDb->query("ALTER TABLE `bx_persons_data` ADD `badge_link` varchar(255) NOT NULL default '' AFTER `badge`");
+            if(!$this->oDb->isFieldExists('bx_persons_data', 'rrate'))
+                $this->oDb->query("ALTER TABLE `bx_persons_data` ADD `rrate` float NOT NULL default '0' AFTER `votes`");
+            if(!$this->oDb->isFieldExists('bx_persons_data', 'rvotes'))
+                $this->oDb->query("ALTER TABLE `bx_persons_data` ADD `rvotes` int(11) NOT NULL default '0' AFTER `rrate`");
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+
+}

+ 15 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/install/langs/en.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_persons_option_friends"><![CDATA[Friendship]]></string_add>
+	<string_add name="_bx_persons_form_profile_input_sys_badge"><![CDATA[Badge Image]]></string_add>
+	<string_add name="_bx_persons_form_profile_input_badge"><![CDATA[Upload New Badge Image]]></string_add>
+	<string_add name="_bx_persons_form_profile_input_sys_badge_link"><![CDATA[Badge Link]]></string_add>
+	<string_add name="_bx_persons_form_profile_input_badge_link"><![CDATA[Badge Link]]></string_add>
+	<string_add name="_bx_persons_acl_action_change_badge"><![CDATA[Change Person's Profile Badge]]></string_add>
+	<string_add name="_bx_persons_page_title_sys_edit_profile_badge"><![CDATA[Edit Badge]]></string_add>
+	<string_add name="_bx_persons_page_title_edit_profile_badge"><![CDATA[Edit Badge]]></string_add>
+	<string_add name="_bx_persons_page_block_title_edit_profile_badge"><![CDATA[Edit Badge]]></string_add>
+	<string_add name="_bx_persons_menu_title_public_submenu"><![CDATA[Persons]]></string_add>
+	<string_add name="_bx_persons_menu_item_title_system_edit_badge"><![CDATA[Edit Badge]]></string_add>
+	<string_add name="_bx_persons_menu_item_title_edit_badge"><![CDATA[Edit Badge]]></string_add>
+</resources>

+ 92 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/install/sql/enable.sql

@@ -0,0 +1,92 @@
+SET @sName = 'bx_persons';
+
+
+-- SETTINGS
+SET @iCategId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_persons' LIMIT 1);
+DELETE FROM `sys_options` WHERE `name`='bx_persons_friends';
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_persons_friends', 'on', @iCategId, '_bx_persons_option_friends', 'checkbox', '', '', '', 30);
+
+
+-- PAGES
+DELETE FROM `sys_objects_page` WHERE `object`='bx_persons_edit_badge';
+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_persons_edit_badge', 'edit-persons-badge', '_bx_persons_page_title_sys_edit_profile_badge', '_bx_persons_page_title_edit_profile_badge', 'bx_persons', 5, 2147483647, 1, 'page.php?i=edit-persons-badge', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.php');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_persons_edit_badge';
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_persons_edit_badge', 1, 'bx_persons', '_bx_persons_page_block_title_edit_profile_badge', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:17:"entity_edit_badge";}', 0, 0, 0);
+
+
+-- MENUS
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_persons_view_actions_more' AND `name`='edit-persons-badge';
+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_persons_view_actions_more', 'bx_persons', 'edit-persons-badge', '_bx_persons_menu_item_title_system_edit_badge', '_bx_persons_menu_item_title_edit_badge', 'page.php?i=edit-persons-badge&id={content_id}', '', '', 'fa-certificate', '', 2147483647, 1, 0, 32);
+
+
+
+
+
+DELETE FROM `sys_menu_items` WHERE `set_name`= 'bx_persons_view_actions_all' AND `name` IN ('profile-friends', 'profile-relations', 'profile-subscriptions', 'reaction');
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_persons_view_actions_all', 'bx_persons', 'profile-friends', '_bx_persons_menu_item_title_system_friends', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-relations', '_bx_persons_menu_item_title_system_relations', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-subscriptions', '_bx_persons_menu_item_title_system_subscriptions', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_persons_view_actions_all', 'bx_persons', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 217);
+
+UPDATE `sys_menu_items` SET `order`='12', `active`='0' WHERE `set_name`='bx_persons_view_actions_all' AND `name`='profile-friend-add';
+UPDATE `sys_menu_items` SET `order`='14', `active`='0' WHERE `set_name`='bx_persons_view_actions_all' AND `name`='profile-friend-remove';
+UPDATE `sys_menu_items` SET `order`='22', `active`='0' WHERE `set_name`='bx_persons_view_actions_all' AND `name`='profile-relation-add';
+UPDATE `sys_menu_items` SET `order`='24', `active`='0' WHERE `set_name`='bx_persons_view_actions_all' AND `name`='profile-relation-remove';
+UPDATE `sys_menu_items` SET `order`='32', `active`='0' WHERE `set_name`='bx_persons_view_actions_all' AND `name`='profile-subscribe-add';
+UPDATE `sys_menu_items` SET `order`='34', `active`='0' WHERE `set_name`='bx_persons_view_actions_all' AND `name`='profile-subscribe-remove';
+UPDATE `sys_menu_items` SET `active`='0' WHERE `set_name`='bx_persons_view_actions_all' AND `name`='score';
+
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_persons_view_meta' AND `name` IN ('reactions', 'scores');
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_persons_view_meta', 'bx_persons', 'reactions', '_sys_menu_item_title_system_sm_reactions', '_sys_menu_item_title_sm_reactions', '', '', '', '', '', 0, 2147483647, '', 0, 0, 43),
+('bx_persons_view_meta', 'bx_persons', 'scores', '_sys_menu_item_title_system_sm_scores', '_sys_menu_item_title_sm_scores', '', '', '', '', '', 0, 2147483647, '', 0, 0, 46);
+
+UPDATE `sys_objects_menu` SET `title_public`='_bx_persons_menu_title_public_submenu' WHERE `object`='bx_persons_submenu';
+
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_persons_snippet_meta' AND `name` IN ('votes', 'reactions', 'scores', 'obj-friends', 'obj-subscriptions');
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `hidden_on_cxt`, `active`, `copyable`, `editable`, `order`) VALUES
+('bx_persons_snippet_meta', 'bx_persons', 'votes', '_sys_menu_item_title_system_sm_votes', '_sys_menu_item_title_sm_votes', '', '', '', '', '', 2147483647, '', 0, 0, 1, 16),
+('bx_persons_snippet_meta', 'bx_persons', 'reactions', '_sys_menu_item_title_system_sm_reactions', '_sys_menu_item_title_sm_reactions', '', '', '', '', '', 2147483647, '', 0, 0, 1, 17),
+('bx_persons_snippet_meta', 'bx_persons', 'scores', '_sys_menu_item_title_system_sm_scores', '_sys_menu_item_title_sm_scores', '', '', '', '', '', 2147483647, '', 0, 0, 1, 18),
+('bx_persons_snippet_meta', 'bx_persons', 'obj-friends', '_sys_menu_item_title_system_sm_friends', '', '', '', '', '', '', 2147483647, 'recom_friends,recom_subscriptions', 1, 0, 1, 60),
+('bx_persons_snippet_meta', 'bx_persons', 'obj-subscriptions', '_sys_menu_item_title_system_sm_subscriptions', '', '', '', '', '', '', 2147483647, 'recom_friends,recom_subscriptions', 1, 0, 1, 70);
+
+UPDATE `sys_menu_items` SET `hidden_on_cxt`='all!recom_friends', `order`='62' WHERE `set_name`='bx_persons_snippet_meta' AND `name`='befriend';
+UPDATE `sys_menu_items` SET `order`='64', `active`='0' WHERE `set_name`='bx_persons_snippet_meta' AND `name`='unfriend';
+UPDATE `sys_menu_items` set `hidden_on_cxt`='all!recom_subscriptions', `order`='72' WHERE `set_name`='bx_persons_snippet_meta' AND `name`='subscribe';
+UPDATE `sys_menu_items` SET `order`='74', `active`='0' WHERE `set_name`='bx_persons_snippet_meta' AND `name`='unsubscribe';
+
+UPDATE `sys_menu_items` SET `visibility_custom`='a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:17:"is_enable_friends";}' WHERE `set_name`='sys_account_notifications' AND `module`='bx_persons' AND `name`='notifications-friend-requests';
+
+UPDATE `sys_menu_items` SET `visibility_custom`='a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:17:"is_enable_friends";}' WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-friend-requests';
+
+
+-- ACL
+SET @iIdActionChangeBadge = (SELECT `ID` FROM `sys_acl_actions` WHERE `Module`='bx_persons' AND `Name`='change badge' LIMIT 1);
+DELETE FROM `sys_acl_actions` WHERE `ID`=@iIdActionChangeBadge;
+DELETE FROM `sys_acl_matrix` WHERE `IDAction`=@iIdActionChangeBadge;
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_persons', 'change badge', NULL, '_bx_persons_acl_action_change_badge', '', 1, 3);
+SET @iIdActionChangeBadge = LAST_INSERT_ID();
+
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+(@iModerator, @iIdActionChangeBadge),
+(@iAdministrator, @iIdActionChangeBadge),
+(@iPremium, @iIdActionChangeBadge);
+
+
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object`='bx_persons_badge_crop';
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_persons_badge_crop', 1, 'BxPersonsUploaderBadgeCrop', 'modules/boonex/persons/classes/BxPersonsUploaderBadgeCrop.php');

+ 72 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/install/sql/install.sql

@@ -0,0 +1,72 @@
+SET @sName = 'bx_persons';
+
+
+-- TABLES
+CREATE TABLE IF NOT EXISTS `bx_persons_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_transcoder` WHERE `object`='bx_persons_badge';
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`) VALUES 
+('bx_persons_badge', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0');
+
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object`='bx_persons_badge';
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_persons_badge', 'Resize', 'a:3:{s:1:"w";s:2:"32";s:1:"h";s:2:"32";s:13:"square_resize";s:1:"1";}', '0');
+
+
+-- FORMS
+DELETE FROM `sys_form_displays` WHERE `display_name`='bx_person_edit_badge';
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_person', 'bx_person_edit_badge', 'bx_persons', 0, '_bx_persons_form_profile_display_edit_badge');
+
+DELETE FROM `sys_form_inputs` WHERE `object`='bx_person' AND `name` IN ('do_cancel', 'controls', 'badge', 'badge_link');
+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`, `rateable`) VALUES 
+('bx_person', 'bx_persons', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'badge', 'a:1:{i:0;s:21:"bx_persons_badge_crop";}', 'a:1:{s:21:"bx_persons_badge_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_badge', '_bx_persons_form_profile_input_badge', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'badge_link', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_badge_link', '_bx_persons_form_profile_input_badge_link', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0, '');
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name`='bx_person_edit' AND `input_name` IN ('controls', 'do_submit', 'do_cancel');
+SET @iOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_form_display_inputs` WHERE `display_name`='bx_person_edit');
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_person_edit', 'controls', 2147483647, 1, @iOrder+1),
+('bx_person_edit', 'do_submit', 2147483647, 1, @iOrder+2),
+('bx_person_edit', 'do_cancel', 2147483647, 1, @iOrder+3);
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name`='bx_person_edit_badge' AND `input_name` IN ('badge', 'badge_link', 'do_submit');
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_person_edit_badge', 'badge', 2147483647, 1, 1),
+('bx_person_edit_badge', 'badge_link', 2147483647, 1, 2),
+('bx_person_edit_badge', 'do_submit', 2147483647, 1, 3);
+
+
+-- VOTES
+
+DELETE FROM `sys_objects_vote` WHERE `Name`='bx_persons_reactions';
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_persons_reactions', 'bx_persons', 'bx_persons_reactions', 'bx_persons_reactions_track', '604800', '1', '1', '1', '1', 'bx_persons_data', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', '');
+
+
+-- SCORES
+UPDATE `sys_objects_score` SET `is_on`='1' WHERE `name`='bx_persons';

+ 254 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/classes/BxPersonsConfig.php

@@ -0,0 +1,254 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Persons Persons
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPersonsConfig extends BxBaseModProfileConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $this->_aMenuItems2MethodsSubmenu = array_merge($this->_aMenuItems2MethodsSubmenu, array(
+            'persons-profile-friends' => 'checkAllowedFriendsView',
+            'persons-profile-relations' => 'checkAllowedRelationsView',
+            'persons-profile-subscriptions' => 'checkAllowedSubscriptionsView'
+        ));
+
+        $this->_aMenuItems2MethodsActions = array_merge($this->_aMenuItems2MethodsActions, array(
+            'view-persons-profile' => 'checkAllowedView',
+            'edit-persons-profile' => 'checkAllowedEdit',
+            'edit-persons-cover' => 'checkAllowedChangeCover',
+            'edit-persons-badge' => 'checkAllowedChangeBadge',
+            'delete-persons-profile' => 'checkAllowedDelete',
+        ));
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'user col-blue3',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'data',
+            'TABLE_ENTRIES_FULLTEXT' => 'search_fields',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_NAME' => 'fullname',
+            'FIELD_LAST_NAME' => 'last_name',
+            'FIELD_TITLE' => 'fullname',
+            'FIELD_TEXT' => 'description',
+            'FIELD_PICTURE' => 'picture',
+            'FIELD_COVER' => 'cover',
+            'FIELD_COVER_POSITION' => 'cover_data',
+            'FIELD_BADGE' => 'badge',
+            'FIELD_BADGE_LINK' => 'badge_link',
+            'FIELD_BIRTHDAY' => 'birthday',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_ALLOW_POST_TO' => 'allow_post_to',
+            'FIELD_ALLOW_CONTACT_TO' => 'allow_contact_to',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_VOTES' => 'votes',
+            'FIELD_REACTIONS' => 'rvotes',
+            'FIELD_SCORE' => 'score',
+            'FIELD_SCORE_UP' => 'sc_up',
+            'FIELD_SCORE_DOWN' => 'sc_down',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELDS_QUICK_SEARCH' => array('fullname', 'last_name'),
+            'FIELD_LOCATION' => 'location',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELD_LABELS' => 'labels',
+            '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-persons-profile',
+            'URI_VIEW_FRIENDS' => 'persons-profile-friends',
+            'URI_VIEW_FRIEND_REQUESTS' => 'persons-friend-requests',
+            'URI_VIEW_FAVORITES' => 'persons-profile-favorites',
+            'URI_ADD_ENTRY' => 'create-persons-profile',
+            'URI_EDIT_ENTRY' => 'edit-persons-profile',
+            'URI_MANAGE_COMMON' => 'persons-manage',
+            'URI_VIEW_SUBSCRIPTIONS' => 'persons-profile-subscriptions',
+
+            'URL_HOME' => 'page.php?i=persons-home',
+            'URL_CREATE' => 'page.php?i=create-persons-profile',
+            'URL_MANAGE_COMMON' => 'page.php?i=persons-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=persons-administration',
+
+            // some params
+            'ALLOW_AS_CONTEXT' => defined('BX_PERSONS_AS_CONTEXT'),
+
+            'PARAM_AUTOAPPROVAL' => 'bx_persons_autoapproval',
+            'PARAM_ENABLE_ACTIVATION_LETTER' => 'bx_persons_enable_profile_activation_letter',
+            'PARAM_DEFAULT_ACL_LEVEL' => 'bx_persons_default_acl_level',
+            'PARAM_NUM_RSS' => 'bx_persons_num_rss',
+            'PARAM_NUM_CONNECTIONS_QUICK' => 'bx_persons_num_connections_quick',
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_persons_searchable_fields',
+            'PARAM_FRIENDS' => 'bx_persons_friends',
+            'PARAM_PUBLIC_SBSN' => 'bx_persons_public_subscriptions',
+            'PARAM_PUBLIC_SBSD' => 'bx_persons_public_subscribed_me',
+            'PARAM_REDIRECT_AADD' => 'bx_persons_redirect_aadd',
+            'PARAM_REDIRECT_AADD_CUSTOM_URL' => 'bx_persons_redirect_aadd_custom_url',
+            'PARAM_PER_PAGE_BROWSE_SHOWCASE' => 'bx_persons_per_page_browse_showcase',
+            'PARAM_PER_PAGE_BROWSE_RECOMMENDED' => 'bx_persons_per_page_browse_recommended',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_persons_pictures',
+            'OBJECT_STORAGE_COVER' => 'bx_persons_pictures',
+            'OBJECT_STORAGE_BADGE' => 'bx_persons_pictures',
+            'OBJECT_IMAGES_TRANSCODER_THUMB' => 'bx_persons_thumb',
+            'OBJECT_IMAGES_TRANSCODER_ICON' => 'bx_persons_icon',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR' => 'bx_persons_avatar',
+            'OBJECT_IMAGES_TRANSCODER_AVATAR_BIG' => 'bx_persons_avatar_big',
+            'OBJECT_IMAGES_TRANSCODER_PICTURE' => 'bx_persons_picture',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_persons_cover',
+            'OBJECT_IMAGES_TRANSCODER_COVER_THUMB' => 'bx_persons_cover_thumb',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_persons_gallery',
+            'OBJECT_IMAGES_TRANSCODER_BADGE' => 'bx_persons_badge',
+            'OBJECT_VIEWS' => 'bx_persons',
+            'OBJECT_VOTES' => 'bx_persons',
+            'OBJECT_REACTIONS' => 'bx_persons_reactions',
+            'OBJECT_SCORES' => 'bx_persons',
+            'OBJECT_FAVORITES' => 'bx_persons',
+            'OBJECT_FEATURED' => 'bx_persons',
+            'OBJECT_COMMENTS' => 'bx_persons',
+            'OBJECT_NOTES' => 'bx_persons_notes',
+            'OBJECT_REPORTS' => 'bx_persons',
+            'OBJECT_METATAGS' => 'bx_persons',
+            'OBJECT_FORM_ENTRY' => 'bx_person',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_person_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW_FULL' => 'bx_person_view_full', // for "info" tab on view profile page 
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_person_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_person_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT_COVER' => 'bx_person_edit_cover',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT_BADGE' => 'bx_person_edit_badge',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_person_delete',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_persons_view_actions', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_MORE' => 'bx_persons_view_actions_more', // actions menu on view entry page for "more" popup
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_persons_view_actions_all', // all actions menu on view entry page
+            'OBJECT_MENU_SUBMENU' => 'bx_persons_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_persons_view_submenu',  // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'persons-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_MANAGE_VIEW_ENTRY' => '',
+            'OBJECT_MENU_VIEW_ENTRY_META' => 'bx_persons_view_meta', // meta menu on view entry page
+            'OBJECT_MENU_SNIPPET_META' => 'bx_persons_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_persons_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_PAGE_VIEW_ENTRY' => 'bx_persons_view_profile',
+            'OBJECT_PAGE_VIEW_ENTRY_CLOSED' => 'bx_persons_view_profile_closed',
+            'OBJECT_PAGE_JOINED_ENTRY' => 'bx_persons_join_profile',
+            'OBJECT_PRIVACY_VIEW' => 'bx_persons_allow_view_to',
+            'OBJECT_PRIVACY_POST' => 'bx_persons_allow_post_to',
+            'OBJECT_PRIVACY_CONTACT' => 'bx_persons_allow_contact_to',
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_persons_administration',
+            'OBJECT_GRID_COMMON' => 'bx_persons_common',
+            'OBJECT_UPLOADERS_COVER' => array('bx_persons_cover_crop'),
+            'OBJECT_UPLOADERS_PICTURE' => array('bx_persons_picture_crop'),
+            'OBJECT_UPLOADERS_BADGE' => array('bx_persons_badge_crop'),
+            
+            'BADGES_AVALIABLE' => true,
+
+            'EMAIL_FRIEND_REQUEST' => 'bx_persons_friend_request',
+
+            'TRIGGER_MENU_PROFILE_VIEW_SUBMENU' => 'trigger_profile_view_submenu',
+            'TRIGGER_MENU_PROFILE_SNIPPET_META' => 'trigger_profile_snippet_meta',
+            'TRIGGER_MENU_PROFILE_VIEW_ACTIONS' => 'trigger_profile_view_actions',
+        	'TRIGGER_PAGE_VIEW_ENTRY' => 'trigger_page_profile_view_entry',
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_persons_view_submenu' => $this->_aMenuItems2MethodsSubmenu,
+                'bx_persons_view_actions' => $this->_aMenuItems2MethodsActions,
+                'bx_persons_view_actions_more' => $this->_aMenuItems2MethodsActions,
+                'bx_persons_view_actions_all' => $this->_aMenuItems2MethodsActions,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'status' => array (
+                    'name' => 'bx-persons-status-not-active',
+                    'map' => array (
+                        BX_PROFILE_STATUS_PENDING => '_bx_persons_txt_account_pending',
+                        BX_PROFILE_STATUS_SUSPENDED => '_bx_persons_txt_account_suspended',
+                    ),
+                ),
+                'status_moderation' => array (
+                    'name' => 'bx-persons-status-not-active-moderation',
+                    'map' => array (
+                        BX_PROFILE_STATUS_PENDING => '_bx_persons_txt_account_pending_moderation',
+                        BX_PROFILE_STATUS_SUSPENDED => '_bx_persons_txt_account_suspended_moderation',
+                    ),
+                ),
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_persons_txt_sample_single',
+            	'txt_sample_comment_single' => '_bx_persons_txt_sample_comment_single',
+                'txt_sample_vote_single' => '_bx_persons_txt_sample_vote_single',
+                'txt_sample_score_up_single' => '_bx_persons_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_persons_txt_sample_score_down_single',
+            	'txt_sample_pp_single' => '_bx_persons_txt_sample_pp_single',
+            	'txt_sample_pp_single_with_article' => '_bx_persons_txt_sample_pp_single_with_article',
+                'txt_sample_pc_single' => '_bx_persons_txt_sample_pc_single',
+            	'txt_sample_pc_single_with_article' => '_bx_persons_txt_sample_pc_single_with_article',
+            	'txt_sample_pi_action' => '_bx_persons_txt_sample_pi_action',
+            	'txt_sample_pi_action_user' => '_bx_persons_txt_sample_pi_action_user',
+                'txt_N_fans' => '_bx_persons_txt_N_friends',
+            	'txt_ntfs_timeline_post_common' => '_bx_persons_txt_ntfs_timeline_post_common',
+            	'form_field_picture' => '_bx_persons_form_profile_input_picture_search',
+                'form_field_online' => '_bx_persons_form_profile_input_online_search',
+                'menu_item_title_befriend_sent' => '_bx_persons_menu_item_title_befriend_sent',
+                'menu_item_title_unfriend_cancel_request' => '_bx_persons_menu_item_title_unfriend_cancel_request',
+                'menu_item_title_befriend_confirm' => '_bx_persons_menu_item_title_befriend_confirm',
+                'menu_item_title_unfriend_reject_request' => '_bx_persons_menu_item_title_unfriend_reject_request',
+                'menu_item_title_befriend' => '_bx_persons_menu_item_title_befriend',
+                'menu_item_title_unfriend' => '_bx_persons_menu_item_title_unfriend',
+            	'grid_action_err_delete' => '_bx_persons_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_persons_grid_txt_account_manager',
+            	'filter_item_active' => '_bx_persons_grid_filter_item_title_adm_active',
+            	'filter_item_pending' => '_bx_persons_grid_filter_item_title_adm_pending',
+            	'filter_item_suspended' => '_bx_persons_grid_filter_item_title_adm_suspended',
+                'filter_item_unconfirmed' => '_bx_persons_grid_filter_item_title_adm_unconfirmed',
+            	'filter_item_select_one_filter1' => '_bx_persons_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_persons_grid_filter_item_title_adm_select_one_filter2',
+            	'menu_item_manage_my' => '_bx_persons_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_persons_menu_item_title_manage_all',
+            	'txt_browse_favorites' => '_bx_persons_page_title_browse_favorites',
+                'option_redirect_aadd_profile' => '_bx_persons_option_redirect_aadd_profile',
+            	'option_redirect_aadd_last' => '_bx_persons_option_redirect_aadd_last',
+            	'option_redirect_aadd_custom' => '_bx_persons_option_redirect_aadd_custom',
+                'option_redirect_aadd_homepage' => '_bx_persons_option_redirect_aadd_homepage',
+                'option_activation_on' => '_bx_persons_option_activation_on',
+            	'option_activation_off' => '_bx_persons_option_activation_off',
+            	'option_activation_add' => '_bx_persons_option_activation_add',
+                'option_activation_edit' => '_bx_persons_option_activation_edit'
+            ),
+
+        );
+
+        $this->_aJsClasses = array(
+        	'manage_tools' => 'BxPersonsManageTools'
+        );
+
+        $this->_aJsObjects = array(
+        	'manage_tools' => 'oBxPersonsManageTools'
+        );
+
+        $this->_aGridObjects = array(
+        	'common' => $this->CNF['OBJECT_GRID_COMMON'],
+        	'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        	
+        );
+    }
+}
+
+/** @} */

+ 211 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/classes/BxPersonsSearchResult.php

@@ -0,0 +1,211 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Persons Persons
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPersonsSearchResult extends BxBaseModProfileSearchResult
+{
+    function __construct($sMode = '', $aParams = false)
+    {
+        parent::__construct($sMode, $aParams);        
+        
+        $this->aCurrent =  array(
+            'name' => 'bx_persons',
+            'module_name' => 'bx_persons',
+            'object_metatags' => 'bx_persons',
+            'title' => _t('_bx_persons_page_title_browse'),
+            'table' => 'sys_profiles',
+            'tableSearch' => 'bx_persons_data',
+            'ownFields' => array(),
+            'searchFields' => array(),
+            'restriction' => array(
+                'account_id' => array('value' => '', 'field' => 'account_id', 'operator' => '='),
+                'perofileStatus' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'perofileType' => array('value' => 'bx_persons', 'field' => 'type', 'operator' => '='),
+                'owner' => array('value' => '', 'field' => 'author', 'operator' => '=', 'table' => 'bx_persons_data'),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>', 'table' => 'bx_persons_data'),
+                'online' => array('value' => '', 'field' => 'date', 'operator' => '>', 'table' => 'sys_sessions'),
+            ),
+            'join' => array (
+                'profile' => array(
+                    'type' => 'INNER',
+                    'table' => 'bx_persons_data',
+                    'mainField' => 'content_id',
+                    'onField' => 'id',
+                    'joinFields' => array('id', 'fullname', 'last_name', 'picture', 'cover', 'cover_data', 'badge', 'badge_link', 'added', 'author', 'allow_view_to'),
+                ),
+                'account' => array(
+                    'type' => 'INNER',
+                    'table' => 'sys_accounts',
+                    'mainField' => 'account_id',
+                    'onField' => 'id',
+                    'joinFields' => array(),
+                ),
+            ),
+            'paginate' => array('perPage' => getParam('bx_persons_per_page_browse'), 'start' => 0),
+            'sorting' => 'active',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'fullname',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => 'fullname',
+                    'Image' => 'picture',
+                ),
+            ),
+            'ident' => 'id'
+        );
+
+        $this->sFilterName = 'bx_persons_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+        
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $this->_setAccountConfirmationConditions($aParams);
+
+        switch ($sMode) {
+
+            case 'connections':
+                if ($this->_setConnectionsConditions($aParams)) {
+                    $oProfile = BxDolProfile::getInstance($aParams['profile']);
+                    $oProfile2 = isset($aParams['profile2']) ? BxDolProfile::getInstance($aParams['profile2']) : null;
+
+                    if (isset($aParams['type']) && $aParams['type'] == 'common' && $oProfile && $oProfile2)
+                        $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_connections_mutual', $oProfile->getDisplayName(), $oProfile2->getDisplayName());
+                    elseif ((!isset($aParams['type']) || $aParams['type'] != 'common') && $oProfile)
+                        $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_connections', $oProfile->getDisplayName());
+
+                    $this->aCurrent['rss']['link'] = 'modules/?r=persons/rss/' . $sMode . '/' . $aParams['object'] . '/' . $aParams['type'] . '/' . (int)$aParams['profile'] . '/' . (int)$aParams['profile2'] . '/' . (int)$aParams['mutual'];
+                }
+                break;
+
+            case 'familiar':
+                if($this->_setFamiliarConnectionsConditions($aParams)) {
+                    $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_familiar');
+                    unset($this->aCurrent['rss']);
+                }
+                break;
+
+            case 'acl':
+                if ($this->_setAclConditions($aParams)) {
+                    $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_by_acl', implode(', ', $this->aCurrent['title']));
+                    unset($this->aCurrent['rss']);
+                }
+                break;
+
+            case 'favorite':
+                $oProfileAuthor = null;
+                if(!$this->_setFavoriteConditions($sMode, $aParams, $oProfileAuthor)) {
+                    $this->isError = true;
+                    break;
+                }
+                break;
+
+            case 'recent':
+                $this->aCurrent['rss']['link'] = 'modules/?r=persons/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_recent');
+                $this->aCurrent['sorting'] = 'last';
+                $this->sBrowseUrl = 'page.php?i=persons-home';
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_featured');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=persons/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                break;
+                
+            case 'recommended':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_groups_page_title_browse_recommended');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=groups/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'recommended';
+                $this->_setConditionsForRecommended();
+                break;    
+            
+            case 'active':
+                $this->aCurrent['rss']['link'] = 'modules/?r=persons/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_active');
+                $this->aCurrent['sorting'] = 'active';
+                $this->sBrowseUrl = 'page.php?i=persons-active';
+                break;
+
+            case 'online':
+                $this->aCurrent['rss']['link'] = 'modules/?r=persons/rss/' . $sMode;
+                $this->aCurrent['title'] = _t('_bx_persons_page_title_browse_online');
+                $this->aCurrent['restriction']['online']['value'] = time() - 60 * (int)getParam('sys_account_online_time');
+                $this->aCurrent['restriction_sql'] = ' AND `sys_accounts`.`profile_id`=`sys_profiles`.`id`';
+                $this->aCurrent['join']['session'] = array(
+                    'type' => 'INNER',
+                    'table' => 'sys_sessions',
+                    'mainField' => 'account_id',
+                    'onField' => 'user_id',
+                    'joinFields' => array('date'),
+                    'groupTable' => $this->aCurrent['table'],
+                    'groupField' => 'id'
+                );
+                $this->aCurrent['sorting'] = 'online';
+                $this->sBrowseUrl = 'page.php?i=persons-online';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_persons');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $this->isError = true;
+        }
+
+        $this->sCenterContentUnitSelector = false;
+    }
+
+    function getAlterOrder()
+    {
+        switch ($this->aCurrent['sorting']) {
+            case 'featured':
+                return array('order' => ' ORDER BY `bx_persons_data`.`featured` DESC ');
+            case 'recommended':
+                return array('order' => ' ORDER BY RAND() ');
+            case 'none':
+                return array();
+	        case 'active':
+	            return array('order' => ' ORDER BY `sys_accounts`.`logged` DESC ');
+			case 'online':
+	            return array('order' => ' ORDER BY `sys_sessions`.`date` DESC ');
+	        case 'last':
+	        default:
+	            return array('order' => ' ORDER BY `bx_persons_data`.`added` DESC ');
+        }
+    }
+
+    function _getPseud ()
+    {
+        return array(
+            'id' => 'id',
+            'fullname' => 'fullname',
+            'added' => 'added',
+            'author' => 'author',
+            'picture' => 'picture',
+        );
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/classes/BxPersonsUploaderBadgeCrop.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Persons Persons
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPersonsUploaderBadgeCrop extends BxBaseModProfileUploaderBadgeCrop
+{
+    public function __construct ($aObject, $sStorageObject, $sUniqId, $oTemplate)
+    {
+        $this->_oModule = BxDolModule::getInstance('bx_persons');
+        parent::__construct($aObject, $sStorageObject, $sUniqId, $oTemplate);
+    }
+}
+
+/** @} */

+ 153 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/install/config.php

@@ -0,0 +1,153 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Persons Persons
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_persons',
+    'title' => 'Persons',
+    'note' => 'Basic person profiles functionality.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/persons/',
+    'home_uri' => 'persons',
+
+    'db_prefix' => 'bx_persons_',
+    'class_prefix' => 'BxPersons',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Persons',
+
+    /**
+     * Connections.
+     */
+    'connections' => array(
+        'sys_profiles_friends' => array ('type' => 'profiles'),
+        'sys_profiles_subscriptions' => array ('type' => 'profiles'),
+        'sys_profiles_relations' => array ('type' => 'profiles'),
+    ),
+
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_profile_snippet_meta',
+    	'trigger_profile_view_actions',
+    ),
+
+	/**
+     * Page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry', 
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_persons_pictures'
+    ),
+
+	/**
+     * Transcoders.
+     */
+    'transcoders' => array(
+    	'bx_persons_icon',
+    	'bx_persons_thumb',
+    	'bx_persons_avatar',
+        'bx_persons_avatar_big',
+    	'bx_persons_picture',
+    	'bx_persons_cover',
+    	'bx_persons_cover_thumb',
+        'bx_persons_gallery',
+        'bx_persons_badge'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_persons',
+    	'bx_persons_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 1,
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    	'process_connections' => 1,
+    	'process_deleted_profiles' => 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,
+    	'process_page_triggers' => 1,
+    	'process_esearches' => 1,
+    	'register_transcoders' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'unregister_transcoders' => 1,
+    	'update_relations' => 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',
+    ),
+);
+
+/** @} */

+ 369 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/install/langs/en.xml

@@ -0,0 +1,369 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+    <string name="_bx_persons"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_cmts"><![CDATA[Persons' Comments]]></string>
+
+    <string name="_bx_persons_option_autoapproval"><![CDATA[Activate all persons automatically]]></string>
+    <string name="_bx_persons_option_default_acl_level"><![CDATA[Default member's level to assign after person's profile creation]]></string>
+    <string name="_bx_persons_option_enable_profile_activation_letter"><![CDATA[Enable profile activation letter]]></string>
+    <string name="_bx_persons_option_redirect_aadd"><![CDATA[Redirect after person's profile creation to]]></string>
+    <string name="_bx_persons_option_redirect_aadd_profile"><![CDATA[Profile Page]]></string>
+    <string name="_bx_persons_option_redirect_aadd_last"><![CDATA[Last Page]]></string>
+    <string name="_bx_persons_option_redirect_aadd_custom"><![CDATA[Custom Page]]></string>
+    <string name="_bx_persons_option_redirect_aadd_homepage"><![CDATA[Homepage]]></string>
+    <string name="_bx_persons_option_redirect_aadd_custom_url"><![CDATA[URL for 'Custom Page' redirect]]></string>
+    <string name="_bx_persons_option_activation_on"><![CDATA[After creation & after editing]]></string>
+    <string name="_bx_persons_option_activation_add"><![CDATA[After creation only]]></string>
+    <string name="_bx_persons_option_activation_edit"><![CDATA[After editing only]]></string>
+    <string name="_bx_persons_option_activation_off"><![CDATA[Manual activation]]></string>
+    <string name="_bx_persons_option_num_connections_quick"><![CDATA[Number of items in friends block]]></string>
+    <string name="_bx_persons_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_persons_option_num_rss"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_persons_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_persons_option_friends"><![CDATA[Friendship]]></string>
+    <string name="_bx_persons_option_public_subscriptions"><![CDATA[Public following list]]></string>
+    <string name="_bx_persons_option_public_subscribed_me"><![CDATA[Public followers list]]></string>
+
+    <string name="_bx_persons_form_profile"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_form_profile_display_add"><![CDATA[Add Person]]></string>
+    <string name="_bx_persons_form_profile_display_edit"><![CDATA[Edit Person]]></string>
+    <string name="_bx_persons_form_profile_display_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_form_profile_display_delete"><![CDATA[Delete Person]]></string>
+    <string name="_bx_persons_form_profile_display_view"><![CDATA[View Person]]></string>
+    <string name="_bx_persons_form_profile_display_view_full"><![CDATA[Full View Person]]></string>
+    <string name="_bx_persons_form_profile_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_persons_form_profile_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_persons_form_profile_input_sys_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_persons_form_profile_input_allow_view_to"><![CDATA[Visible to]]></string>
+    <string name="_bx_persons_form_profile_input_sys_allow_post_to"><![CDATA[Who can post to my profile]]></string>
+    <string name="_bx_persons_form_profile_input_allow_post_to"><![CDATA[Who can post to my profile]]></string>
+    <string name="_bx_persons_form_profile_input_sys_allow_contact_to"><![CDATA[Who can contact me]]></string>
+    <string name="_bx_persons_form_profile_input_allow_contact_to"><![CDATA[Who can contact me]]></string>
+    <string name="_bx_persons_form_profile_input_sys_fullname"><![CDATA[Name]]></string>
+    <string name="_bx_persons_form_profile_input_fullname"><![CDATA[Name]]></string>
+    <string name="_bx_persons_form_profile_input_sys_last_name"><![CDATA[Last Name]]></string>
+    <string name="_bx_persons_form_profile_input_last_name"><![CDATA[Last Name]]></string>
+    <string name="_bx_persons_form_profile_input_fullname_err"><![CDATA[Profile name is mandatory and and cannot start with @]]></string>
+    <string name="_bx_persons_form_profile_input_sys_desc"><![CDATA[Description]]></string>
+    <string name="_bx_persons_form_profile_input_desc"><![CDATA[Description]]></string>
+    <string name="_bx_persons_form_profile_input_sys_picture"><![CDATA[Profile Picture]]></string>
+    <string name="_bx_persons_form_profile_input_picture"><![CDATA[Upload a profile picture]]></string>
+    <string name="_bx_persons_form_profile_input_picture_err"><![CDATA[Profile picture is mandatory.]]></string>
+    <string name="_bx_persons_form_profile_input_picture_search"><![CDATA[With photo]]></string>
+    <string name="_bx_persons_form_profile_input_online_search"><![CDATA[Online only]]></string>
+    <string name="_bx_persons_form_profile_input_sys_cover"><![CDATA[Cover Picture]]></string>
+    <string name="_bx_persons_form_profile_input_cover"><![CDATA[Upload New Cover Picture]]></string>
+    <string name="_bx_persons_form_profile_input_sys_badge"><![CDATA[Badge Image]]></string>
+    <string name="_bx_persons_form_profile_input_badge"><![CDATA[Upload New Badge Image]]></string>
+    <string name="_bx_persons_form_profile_input_sys_badge_link"><![CDATA[Badge Link]]></string>
+    <string name="_bx_persons_form_profile_input_badge_link"><![CDATA[Badge Link]]></string>
+    <string name="_bx_persons_form_profile_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_persons_form_profile_input_delete_confirm"><![CDATA[I am sure I want to delete this profile]]></string>
+    <string name="_bx_persons_form_profile_input_delete_confirm_info"><![CDATA[This action can not be undone.]]></string>
+    <string name="_bx_persons_form_profile_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete your profile.]]></string>
+    <string name="_bx_persons_form_profile_input_sys_birthday"><![CDATA[Birthday]]></string>
+    <string name="_bx_persons_form_profile_input_birthday_err"><![CDATA[Age between 18 and 99]]></string>
+    <string name="_bx_persons_form_profile_input_birthday"><![CDATA[Birthday]]></string>
+    <string name="_bx_persons_form_profile_input_sys_gender"><![CDATA[Gender]]></string>
+    <string name="_bx_persons_form_profile_input_gender"><![CDATA[Gender]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_email"><![CDATA[Email]]></string>
+    <string name="_bx_persons_form_profile_input_profile_email"><![CDATA[Email]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_status"><![CDATA[Status]]></string>
+    <string name="_bx_persons_form_profile_input_profile_status"><![CDATA[Status]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_ip"><![CDATA[IP]]></string>
+    <string name="_bx_persons_form_profile_input_profile_ip"><![CDATA[IP]]></string>
+    <string name="_bx_persons_form_profile_input_sys_profile_last_active"><![CDATA[Last account activity]]></string>
+    <string name="_bx_persons_form_profile_input_profile_last_active"><![CDATA[Last account activity]]></string>
+    <string name="_bx_persons_form_profile_input_sys_skills"><![CDATA[Skills]]></string>
+    <string name="_bx_persons_form_profile_input_skills"><![CDATA[Skills]]></string>
+    <string name="_bx_persons_form_profile_input_sys_date_added"><![CDATA[Added]]></string>
+    <string name="_bx_persons_form_profile_input_date_added"><![CDATA[Added]]></string>
+    <string name="_bx_persons_form_profile_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_persons_form_profile_input_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_persons_form_profile_input_sys_friends_count"><![CDATA[Friends count]]></string>
+    <string name="_bx_persons_form_profile_input_friends_count"><![CDATA[Friends count]]></string>
+    <string name="_bx_persons_form_profile_input_sys_followers_count"><![CDATA[Followers count]]></string>
+    <string name="_bx_persons_form_profile_input_followers_count"><![CDATA[Followers count]]></string>
+
+    <string name="_bx_persons_skills_form_profile"><![CDATA[Skills]]></string>
+    <string name="_bx_persons_skills_form_profile_display_add"><![CDATA[Add Skill]]></string>
+    <string name="_bx_persons_skills_form_profile_display_view"><![CDATA[View Skill]]></string>
+    <string name="_bx_persons_skills_form_profile_input_sys_skill_name"><![CDATA[Name]]></string>
+    <string name="_bx_persons_skills_form_profile_input_skill_name"><![CDATA[Name]]></string>
+    <string name="_bx_persons_skills_form_profile_input_skill_name_err"><![CDATA[This information is essential. Please, fill in this field.]]></string>
+
+    <string name="_bx_persons_acl_action_create_profile"><![CDATA[Create Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_delete_profile"><![CDATA[Delete Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_view_profile"><![CDATA[View Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_change_badge"><![CDATA[Change Person's Profile Badge]]></string>
+    <string name="_bx_persons_acl_action_edit_any_profile"><![CDATA[Edit Any Person's Profile]]></string>
+    <string name="_bx_persons_acl_action_delete_any_profile"><![CDATA[Delete Any Person's Profile]]></string>
+
+    <string name="_bx_persons_page_title_sys_create_profile"><![CDATA[Create a Profile - Person]]></string>
+    <string name="_bx_persons_page_title_create_profile"><![CDATA[Create a Profile - Person]]></string>
+    <string name="_bx_persons_page_title_sys_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_page_title_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_page_title_sys_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_page_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_page_title_sys_edit_profile_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_page_title_edit_profile_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_page_title_sys_delete_profile"><![CDATA[Delete Profile]]></string>
+    <string name="_bx_persons_page_title_delete_profile"><![CDATA[Delete Profile]]></string>
+    <string name="_bx_persons_page_title_sys_view_profile"><![CDATA[View Profile]]></string>
+    <string name="_bx_persons_page_title_sys_view_profile_closed"><![CDATA[View Profile with Limited Visibility]]></string>
+    <string name="_bx_persons_page_title_view_profile"><![CDATA[{display_name}]]></string>
+    <string name="_bx_persons_page_title_browse"><![CDATA[People]]></string>
+    <string name="_bx_persons_page_title_browse_featured"><![CDATA[Featured People]]></string>
+    <string name="_bx_persons_page_title_browse_active"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_title_browse_online"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_title_browse_recent"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_title_browse_connections"><![CDATA[{0} connections]]></string>
+    <string name="_bx_persons_page_title_browse_connections_mutual"><![CDATA[{0} and {1} mutual connections]]></string>
+    <string name="_bx_persons_page_title_browse_familiar"><![CDATA[People You May Know]]></string>
+    <string name="_bx_persons_page_title_browse_favorites"><![CDATA[{0} favorites]]></string>
+    <string name="_bx_persons_page_title_browse_by_acl"><![CDATA[{0} People]]></string>
+    <string name="_bx_persons_page_title_browse_by_cmts"><![CDATA[People's Comments]]></string>
+    <string name="_bx_persons_page_title_sys_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_title_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_title_sys_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_title_sys_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_bx_persons_page_title_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_bx_persons_page_title_sys_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_page_title_profile_subscriptions"><![CDATA[Following & Followers]]></string>
+    <string name="_bx_persons_page_title_sys_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_title_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_title_sys_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_page_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_page_title_sys_profile_info"><![CDATA[Profile Info]]></string>
+    <string name="_bx_persons_page_title_profile_info"><![CDATA[Info about {display_name}]]></string>
+    <string name="_bx_persons_page_title_sys_recent"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_title_recent"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_title_sys_manage"><![CDATA[Manage Own People]]></string>
+    <string name="_bx_persons_page_title_sys_manage_administration"><![CDATA[Manage All People]]></string>
+    <string name="_bx_persons_page_title_manage"><![CDATA[Manage People]]></string>
+    <string name="_bx_persons_page_title_sys_active"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_title_active"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_title_sys_online"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_title_online"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_persons_page_title_entries_search"><![CDATA[Search]]></string>
+
+    <string name="_bx_persons_page_block_title_profile_private"><![CDATA[Private Profile]]></string>
+    <string name="_bx_persons_page_block_title_choose_type"><![CDATA[Choose Profile Type]]></string>
+    <string name="_bx_persons_page_block_title_create_profile"><![CDATA[Create a Profile - Person]]></string>
+    <string name="_bx_persons_page_block_title_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_page_block_title_edit_profile_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_page_block_title_edit_profile_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_page_block_title_delete_profile"><![CDATA[Delete Profile]]></string>
+    <string name="_bx_persons_page_block_title_profile_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_persons_page_block_title_profile_info_link"><![CDATA[About <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_persons_page_block_title_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_page_block_title_profile_membership"><![CDATA[Membership]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_membership"><![CDATA[Membership]]></string>
+    <string name="_bx_persons_page_block_title_profile_description"><![CDATA[Description]]></string>
+    <string name="_bx_persons_page_block_title_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_favorites"><![CDATA[Favorite persons]]></string>
+    <string name="_bx_persons_page_block_title_profile_friends_link"><![CDATA[Friends of <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_persons_page_block_title_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_block_title_profile_friends_mutual"><![CDATA[Mutual Friends]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_page_block_title_friend_requests_link"><![CDATA[Friend Requests for <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_persons_page_block_title_system_friend_requests"><![CDATA[Friend Requests]]></string>
+    <string name="_bx_persons_page_block_title_profile_location"><![CDATA[Location]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_page_block_title_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_page_block_title_profile_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_block_title_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_page_block_title_system_profile_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_page_block_title_profile_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_page_block_title_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_persons_page_block_title_profile_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_persons_page_block_title_featured_profiles"><![CDATA[Featured People]]></string>
+    <string name="_bx_persons_page_block_title_profile_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_persons_page_block_title_profile_calendar"><![CDATA[Calendar]]></string>
+    <string name="_bx_persons_page_block_title_latest_profiles"><![CDATA[New People]]></string>
+    <string name="_bx_persons_page_block_title_system_manage"><![CDATA[Manage Own People]]></string>
+    <string name="_bx_persons_page_block_title_system_manage_administration"><![CDATA[Manage All People]]></string>
+    <string name="_bx_persons_page_block_title_manage"><![CDATA[Manage People]]></string>
+    <string name="_bx_persons_page_block_title_sys_active_profiles"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_block_title_active_profiles"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_block_title_online_profiles"><![CDATA[Online People]]></string>
+    <string name="_bx_persons_page_block_title_sys_familiar_profiles"><![CDATA[Familiar People]]></string>
+    <string name="_bx_persons_page_block_title_familiar_profiles"><![CDATA[People You May Know]]></string>
+    <string name="_bx_persons_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_persons_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_persons_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_persons_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_persons_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured People (Showcase View)]]></string>
+    <string name="_bx_persons_page_block_title_featured_entries_view_showcase"><![CDATA[Featured People]]></string>
+    <string name="_bx_persons_page_block_title_sys_recommended_entries_view_showcase"><![CDATA[Recommended People (Showcase View)]]></string>
+    <string name="_bx_persons_page_block_title_recommended_entries_view_showcase"><![CDATA[Recommended People]]></string>
+    <string name="_bx_persons_page_block_title_sys_active_entries_view_showcase"><![CDATA[Active People (Showcase View)]]></string>
+    <string name="_bx_persons_page_block_title_active_entries_view_showcase"><![CDATA[Active People]]></string>
+    <string name="_bx_persons_page_block_title_sys_cover_block"><![CDATA[Cover]]></string>
+    <string name="_bx_persons_page_block_title_cover_block"><![CDATA[Cover]]></string>
+
+    <string name="_bx_persons_menu_title_submenu"><![CDATA[Persons Submenu]]></string>
+    <string name="_bx_persons_menu_title_public_submenu"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_set_title_submenu"><![CDATA[Persons Submenu]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_actions"><![CDATA[Person Actions]]></string>
+    <string name="_bx_persons_menu_title_view_profile_actions"><![CDATA[Person Actions]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_actions_more"><![CDATA[Person More Actions]]></string>
+    <string name="_bx_persons_menu_title_view_profile_actions_more"><![CDATA[Person More Actions]]></string>
+    <string name="_bx_persons_menu_title_view_profile_meta"><![CDATA[Person Meta]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_meta"><![CDATA[Person Meta]]></string>
+    <string name="_bx_persons_menu_set_title_view_profile_submenu"><![CDATA[View Person Submenu]]></string>
+    <string name="_bx_persons_menu_title_view_profile_submenu"><![CDATA[View Person Submenu]]></string>
+    <string name="_bx_persons_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_persons_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_with_content"><![CDATA[Delete with Data]]></string>
+    <string name="_bx_persons_menu_item_title_delete_with_content"><![CDATA[Delete with Data]]></string>
+    <string name="_bx_persons_menu_item_title_system_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_persons_menu_item_title_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_persons_menu_item_title_system_manage_cf"><![CDATA[Manage audience]]></string>
+    <string name="_bx_persons_menu_item_title_manage_cf"><![CDATA[Manage audience]]></string>
+    <string name="_bx_persons_menu_item_title_system_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_menu_item_title_edit_cover"><![CDATA[Edit Cover]]></string>
+    <string name="_bx_persons_menu_item_title_system_edit_profile"><![CDATA[Edit Person]]></string>
+    <string name="_bx_persons_menu_item_title_edit_profile"><![CDATA[Edit Profile]]></string>
+    <string name="_bx_persons_menu_item_title_system_edit_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_menu_item_title_edit_badge"><![CDATA[Edit Badge]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_profile"><![CDATA[Delete Profile and Data]]></string>
+    <string name="_bx_persons_menu_item_title_delete_profile"><![CDATA[Delete Profile and Data]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_persons_menu_item_title_delete_account"><![CDATA[Delete Account]]></string>
+    <string name="_bx_persons_menu_item_title_system_delete_account_content"><![CDATA[Delete Account and Data]]></string>
+    <string name="_bx_persons_menu_item_title_delete_account_content"><![CDATA[Delete Account and Data]]></string>
+    <string name="_bx_persons_menu_item_title_system_profile_type"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_profile_type"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_system_create_profile"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_create_profile"><![CDATA[Person]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_info"><![CDATA[Info]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_view"><![CDATA[Profile]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_view"><![CDATA[Profile]]></string>
+    <string name="_bx_persons_menu_item_title_system_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_persons_menu_item_title_view_profile_more_auto"><![CDATA[More]]></string>
+    <string name="_bx_persons_menu_item_title_system_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_persons_menu_item_title_befriend"><![CDATA[Add friend]]></string>
+    <string name="_bx_persons_menu_item_title_befriend_sent"><![CDATA[Add friend (requested)]]></string>
+    <string name="_bx_persons_menu_item_title_befriend_confirm"><![CDATA[Accept friend request]]></string>
+    <string name="_bx_persons_menu_item_title_system_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_persons_menu_item_title_unfriend"><![CDATA[Unfriend]]></string>
+    <string name="_bx_persons_menu_item_title_unfriend_cancel_request"><![CDATA[Cancel friend request]]></string>
+    <string name="_bx_persons_menu_item_title_unfriend_reject_request"><![CDATA[Reject friend request]]></string>
+    <string name="_bx_persons_menu_item_title_system_subscribe"><![CDATA[Follow]]></string>
+    <string name="_bx_persons_menu_item_title_subscribe"><![CDATA[Follow]]></string>
+    <string name="_bx_persons_menu_item_title_system_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_bx_persons_menu_item_title_unsubscribe"><![CDATA[Unfollow]]></string>
+    <string name="_bx_persons_menu_item_title_system_relation_add"><![CDATA[Add Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_relation_add"><![CDATA[Add Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_system_relation_delete"><![CDATA[Remove Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_relation_delete"><![CDATA[Remove Relationship]]></string>
+    <string name="_bx_persons_menu_item_title_system_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_persons_menu_item_title_more_actions"><![CDATA[]]></string>
+    <string name="_bx_persons_menu_item_title_system_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_friends"><![CDATA[Friends]]></string>
+    <string name="_bx_persons_menu_item_title_system_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_system_friend_requests"><![CDATA[Friend requests number]]></string>
+    <string name="_bx_persons_menu_item_title_friend_requests"><![CDATA[Friend requests]]></string>
+    <string name="_bx_persons_menu_item_title_system_manage_my_profiles"><![CDATA[My profiles]]></string>
+    <string name="_bx_persons_menu_item_title_manage_my_profiles"><![CDATA[Profiles]]></string>
+    <string name="_bx_persons_menu_item_title_system_favorites"><![CDATA[Favorite Persons]]></string>
+    <string name="_bx_persons_menu_item_title_favorites"><![CDATA[Favorite persons]]></string>    
+    <string name="_bx_persons_menu_item_title_system_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_subscriptions"><![CDATA[Following]]></string>
+    <string name="_bx_persons_menu_item_title_system_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_menu_item_title_subscribed_me"><![CDATA[Followers]]></string>
+    <string name="_bx_persons_menu_item_title_system_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_relations"><![CDATA[Relationships]]></string>
+    <string name="_bx_persons_menu_item_title_system_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_menu_item_title_related_me"><![CDATA[Relationships with Me]]></string>
+    <string name="_bx_persons_menu_item_title_system_followings"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_item_title_followings"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_persons_menu_item_title_entries_recent"><![CDATA[New]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_persons_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_persons_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_persons_menu_item_title_system_entries_home"><![CDATA[Persons]]></string>
+    <string name="_bx_persons_menu_item_title_entries_home"><![CDATA[People]]></string>
+	<string name="_bx_persons_menu_item_title_system_admt_persons"><![CDATA[Profiles]]></string>
+	<string name="_bx_persons_menu_item_title_admt_persons"><![CDATA[Profiles]]></string>
+	<string name="_bx_persons_menu_item_title_manage_my"><![CDATA[My Profiles]]></string>
+	<string name="_bx_persons_menu_item_title_manage_all"><![CDATA[All Profiles]]></string>   
+	<string name="_bx_persons_menu_item_title_system_entries_active"><![CDATA[Active]]></string>
+	<string name="_bx_persons_menu_item_title_entries_active"><![CDATA[Active]]></string>
+	<string name="_bx_persons_menu_item_title_system_entries_online"><![CDATA[Online]]></string>
+	<string name="_bx_persons_menu_item_title_entries_online"><![CDATA[Online]]></string>
+
+    <string name="_bx_persons_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_select_one_filter2"><![CDATA[All]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_suspended"><![CDATA[Suspended]]></string>
+    <string name="_bx_persons_grid_filter_item_title_adm_unconfirmed"><![CDATA[Unconfirmed]]></string>
+    <string name="_bx_persons_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_persons_grid_column_title_adm_fullname"><![CDATA[Name]]></string>
+    <string name="_bx_persons_grid_column_title_adm_last_online"><![CDATA[Last Logged]]></string>
+    <string name="_bx_persons_grid_column_title_adm_account"><![CDATA[Account]]></string>
+    <string name="_bx_persons_grid_action_title_adm_delete_with_content"><![CDATA[Delete With Content]]></string>
+    <string name="_bx_persons_grid_action_title_adm_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_persons_grid_action_title_adm_set_acl_level"><![CDATA[Set Membership]]></string>
+    <string name="_bx_persons_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_persons_grid_action_title_adm_audit_content"><![CDATA[Audit actions with profile]]></string>
+    <string name="_bx_persons_grid_action_title_adm_audit_profile"><![CDATA[Audit profile actions]]></string>
+    <string name="_bx_persons_grid_action_title_adm_manage_cf"><![CDATA[Manage audience]]></string>
+    
+    <string name="_bx_persons_grid_action_err_delete"><![CDATA[Cannot delete the selected person(s).]]></string>
+    <string name="_bx_persons_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_persons_chart_growth"><![CDATA[Persons: Growth]]></string>
+    <string name="_bx_persons_chart_growth_speed"><![CDATA[Persons: Growth Speed]]></string>
+
+    <string name="_bx_persons_search_extended"><![CDATA[Persons Search]]></string>
+    <string name="_bx_persons_search_extended_cmts"><![CDATA[Persons Comments Search]]></string>
+
+    <string name="_bx_persons_alert_action_profile_cover_changed"><![CDATA[cover changed]]></string>
+    <string name="_bx_persons_alert_action_profile_picture_changed"><![CDATA[picture changed]]></string>
+
+    <string name="_bx_persons_txt_account_pending"><![CDATA[This profile is pending approval, please wait until it is activated.]]></string>
+    <string name="_bx_persons_txt_account_pending_moderation"><![CDATA[This <a href="{0}">profile</a> is pending approval.]]></string>
+    <string name="_bx_persons_txt_account_suspended"><![CDATA[This profile is suspended.]]></string>
+    <string name="_bx_persons_txt_account_suspended_moderation"><![CDATA[This <a href="{0}">profile</a> is suspended.]]></string>
+    <string name="_bx_persons_txt_N_friends"><![CDATA[{0} friends]]></string>
+    <string name="_bx_persons_txt_ntfs_timeline_post_common"><![CDATA[New post <b class="bx-ntfs-content-entry">{subentry_sample}</b> in <b class="bx-ntfs-content-profile">{owner_name}</b> profile timeline]]></string>
+    <string name="_bx_persons_txt_sample_single"><![CDATA[person]]></string>
+    <string name="_bx_persons_txt_sample_comment_single"><![CDATA[comment to person]]></string>
+    <string name="_bx_persons_txt_sample_vote_single"><![CDATA[vote to person]]></string>
+    <string name="_bx_persons_txt_sample_score_up_single"><![CDATA[score up vote to person]]></string>
+    <string name="_bx_persons_txt_sample_score_down_single"><![CDATA[score down vote to person]]></string>
+    <string name="_bx_persons_txt_sample_pp_single"><![CDATA[profile picture]]></string>
+    <string name="_bx_persons_txt_sample_pp_single_with_article"><![CDATA[a profile picture]]></string>
+    <string name="_bx_persons_txt_sample_pc_single"><![CDATA[profile cover]]></string>
+    <string name="_bx_persons_txt_sample_pc_single_with_article"><![CDATA[a profile cover]]></string>
+    <string name="_bx_persons_txt_sample_pi_action"><![CDATA[changed {0}]]></string>
+    <string name="_bx_persons_txt_sample_pi_action_user"><![CDATA[{0} changed {1}]]></string>
+
+    <string name="_bx_persons_email_friend_request"><![CDATA[Friend request]]></string>
+    <string name="_bx_persons_email_friend_request_subject"><![CDATA[Friendship Request]]></string>
+    <string name="_bx_persons_email_friend_request_body"><![CDATA[{email_header}
+<p><a href="{SenderUrl}">{SenderDisplayName}</a> wants to be friends with you. <a href="{FriendsLink}">Respond</a>.</p>
+{email_footer}]]></string>
+</resources>

+ 57 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/disable.sql

@@ -0,0 +1,57 @@
+
+-- SETTINGS
+
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_persons' 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_persons';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_persons' OR `object` IN('bx_persons_create_profile', 'bx_persons_delete_profile', 'bx_persons_edit_profile', 'bx_persons_edit_badge', 'bx_persons_view_profile', 'bx_persons_view_profile_closed', 'bx_persons_profile_info', 'bx_persons_profile_friends', 'bx_persons_friend_requests', 'bx_persons_profile_favorites', 'bx_persons_profile_subscriptions', 'bx_persons_profile_comments', 'bx_persons_home', 'bx_persons_search', 'bx_persons_manage');
+
+-- MENU
+
+DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_persons';
+DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_persons';
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_persons' OR `set_name` IN('bx_persons_view_submenu', 'bx_persons_submenu', 'bx_persons_view_actions', 'bx_persons_view_actions_more', 'bx_persons_view_actions_all', 'bx_persons_view_meta', 'bx_persons_snippet_meta', 'bx_persons_menu_manage_tools');
+
+-- 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_persons';
+DELETE FROM `sys_acl_actions` WHERE `Module` = 'bx_persons';
+
+-- METATAGS
+DELETE FROM `sys_objects_metatags` WHERE `object` = 'bx_persons';
+
+-- SEARCH
+DELETE FROM `sys_objects_search` WHERE `ObjectName` IN ('bx_persons', 'bx_persons_cmts');
+
+-- STATS
+DELETE FROM `sys_statistics` WHERE `name` LIKE 'bx_persons%';
+
+-- CHARTS
+DELETE FROM `sys_objects_chart` WHERE `object` LIKE 'bx_persons%';
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_persons_administration', 'bx_persons_common');
+DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_persons_administration', 'bx_persons_common');
+DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_persons_administration', 'bx_persons_common');
+
+-- LIVE UPDATES
+DELETE FROM `sys_objects_live_updates` WHERE `name` LIKE 'bx_persons%';
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_persons' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object` IN ('bx_persons_allow_view_to', 'bx_persons_allow_post_to', 'bx_persons_allow_contact_to');
+
+-- EMAIL TEMPLATES
+DELETE FROM `sys_email_templates` WHERE `Module` = 'bx_persons';
+
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object` IN ('bx_persons_cover_crop', 'bx_persons_picture_crop', 'bx_persons_badge_crop');

+ 100 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/enable-app.sql

@@ -0,0 +1,100 @@
+-- PAGES: 
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `class`, `submenu`, `tabs`, `async`, `visible_for_levels`, `hidden_on`, `type`, `content`, `content_empty`, `text`, `text_updated`, `help`, `cache_lifetime`, `config_api`, `deletable`, `copyable`, `active`, `active_api`, `order`) VALUES
+('bx_persons_view_profile', 1, 'system', '_sys_page_block_title_sys_create_post', '_sys_page_block_title_create_post', 11, '', '', 1, 4, 2147483644, '0', 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:20:"get_create_post_form";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}s:5:"class";s:13:"TemplServices";}', '', '', 0, '', 0, '', 1, 0, 0, 1, 0);
+
+-- PAGES: config_api
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'profile\', \r\n    blocks: {\r\n        col0: {\r\n            name: \'system:get_create_post_form\',\r\n           \r\n        },\r\n        col1: {\r\n            name: \'bx_timeline:get_block_view_profile\',\r\n            \r\n            perLine: 1,\r\n        },\r\n        col3: {\r\n            name: \'bx_persons:entity_info\',\r\n           \r\n            sidebar: true,\r\n        },\r\n    },\r\n    headerSettings: {\r\n    \r\n        hideLeftmenu: true,\r\n        showAltTopMenu: true,\r\n    },\r\n}' WHERE `object`='bx_persons_view_profile';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'profile-alt\',\r\n    blocks: {\r\n        col4: {\r\n            name: \'bx_linguriamods:profile_cover\', \r\n            showTitle: false, \r\n            showBg: false, \r\n            sidebar: false, \r\n            leftbar: true \r\n        },\r\n        col5: { \r\n            name: \'bx_persons:private_profile_msg\', \r\n            showTitle: false, \r\n            showBg: true, \r\n            sidebar: false, \r\n            perLine: 1 \r\n        },\r\n    },\r\n    headerSettings: { \r\n        offset: false, \r\n        header: false, \r\n        cover: \'profile\', \r\n        hideLeftmenu: true, \r\n        showAltTopMenu: true \r\n    }\r\n}' WHERE `object`='bx_persons_view_profile_closed';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'profile-alt\',\r\n    blocks: {\r\n        col1: {\r\n            name: \'bx_persons:entity_edit\',\r\n            showTitle: false,\r\n            showBg: true,\r\n            sidebar: false,\r\n            perLine: 1\r\n        },\r\n        col4: { \r\n            name: \'bx_linguriamods:profile_cover\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            sidebar: false,\r\n            leftbar: true\r\n        },\r\n    },\r\n    headerSettings: {\r\n        offset: false,\r\n        header: false,\r\n        cover: \'profile\',\r\n        hideLeftmenu: true,\r\n        showAltTopMenu: true\r\n    }\r\n}' WHERE `object`='bx_persons_edit_profile';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'profile\',\r\n    blocks: {\r\n        col1: {\r\n            name: \'bx_persons:entity_info_full\',\r\n            showTitle: false,\r\n            showBg: true,\r\n            showPad: true,\r\n            leftbar: true,\r\n        },\r\n        col2: {\r\n            name: \'bx_persons:entity_text_block\',\r\n            showTitle: false,\r\n            showBg: true,\r\n            sidebar: false,\r\n        },\r\n    },\r\n    headerSettings: {\r\n        offset: false,\r\n        header: false,\r\n        cover: \'profile\',\r\n        hideLeftmenu: true,\r\n        showAltTopMenu: true,\r\n    },\r\n}' WHERE `object`='bx_persons_profile_info';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'profile\',\r\n    blocks: {\r\n        col2: {\r\n            name: \'system:connections_table\',\r\n            showTitle: false,\r\n            showBg: true,\r\n            sidebar: false,\r\n        },\r\n    },\r\n    headerSettings: {\r\n        offset: false,\r\n        header: false,\r\n        cover: \'profile\',\r\n        hideLeftmenu: true,\r\n        showAltTopMenu: true,\r\n    },\r\n}' WHERE `object`='bx_persons_profile_friends';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'profile\',\r\n    blocks: {\r\n        col2: {\r\n            name: \'system:subscribed_me_table\',\r\n            showTitle: false,\r\n            showBg: true,\r\n            sidebar: false,\r\n        },\r\n    },\r\n    headerSettings: {\r\n        offset: false,\r\n        header: false,\r\n        cover: \'profile\',\r\n        hideLeftmenu: true,\r\n        showAltTopMenu: true,\r\n    },\r\n}' WHERE `object`='bx_persons_profile_subscriptions';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'profile-alt\',\r\n    blocks: {\r\n        col4: { \r\n            name: \'bx_linguriamods:profile_cover\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            sidebar: false,\r\n            leftbar: true\r\n        },\r\n        comments: {\r\n            name: \'bx_linguriamods:persons_reviews\',\r\n            showTitle: false,\r\n            showBg: true\r\n        },\r\n        col5: {\r\n            name: \'bx_persons:private_profile_msg\',\r\n            showTitle: false,\r\n            showBg: true,\r\n            sidebar: false,\r\n            perLine: 1\r\n        },\r\n    },\r\n    headerSettings: {\r\n        offset: false,\r\n        header: false,\r\n        cover: \'profile\',\r\n        hideLeftmenu: true,\r\n        showAltTopMenu: true\r\n    }\r\n}' WHERE `object`='bx_persons_profile_comments';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'navigator\',\r\n    blocks: {\r\n        browse: { name: \'system:get_results\', showTitle: false, showBg: false, perLine: 2 },\r\n        search: { name: \'system:get_form\', showTitle: false, showBg: false, sidebar: false, leftbar: true },\r\n    },\r\n    headerSettings: { hideLeftmenu: true },\r\n}' WHERE `object`='bx_persons_home';
+
+-- PAGES: active_api
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_create_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_create_profile';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_sys_cover_block' AND `title`='_bx_persons_page_block_title_cover_block';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_profile_friends';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_profile_relations';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_profile_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_profile_membership';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_profile_location';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile_closed' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_profile_private';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_edit_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_edit_profile';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_edit_badge' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_edit_profile_badge';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_delete_profile' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_delete_profile';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_info' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_profile_info' AND `title`='_bx_persons_page_block_title_profile_info_link';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_info' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_profile_description';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_friends' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_profile_friends' AND `title`='_bx_persons_page_block_title_profile_friends_link';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_friend_requests' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_friend_requests' AND `title`='_bx_persons_page_block_title_friend_requests_link';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_favorites' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_profile_favorites' AND `title`='_bx_persons_page_block_title_profile_favorites';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_subscriptions' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_profile_subscribed_me' AND `title`='_bx_persons_page_block_title_profile_subscribed_me';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_relations' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_profile_relations' AND `title`='_bx_persons_page_block_title_profile_relations';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_relations' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_profile_related_me' AND `title`='_bx_persons_page_block_title_profile_related_me';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_home' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_featured_profiles';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_home' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_latest_profiles';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_active' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_active_profiles';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_online' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_online_profiles';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_search' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_search_form';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_search' AND `module`='bx_persons' AND `title_system`='' AND `title`='_bx_persons_page_block_title_search_results';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_manage' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_manage' AND `title`='_bx_persons_page_block_title_manage';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_administration' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_manage_administration' AND `title`='_bx_persons_page_block_title_manage';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_profile_subscriptions1' AND `module`='bx_persons' AND `title_system`='_bx_persons_page_block_title_system_profile_subscriptions' AND `title`='_bx_persons_page_block_title_profile_subscriptions';
+
+-- MENUS:
+
+-- MENUS: config_api
+
+-- MENUS: active_api
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_homepage' AND `module`='bx_persons' AND `name`='persons-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_add_profile_links' AND `module`='bx_persons' AND `name`='create-persons-profile';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-friend-requests';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-manage-profiles';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-favorite-persons';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-subscriptions';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-subscribed-me';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-relations';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_persons' AND `name`='profile-stats-related-me';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_followings' AND `module`='bx_persons' AND `name`='persons';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions' AND `module`='bx_persons' AND `name`='profile-friend-add';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions' AND `module`='bx_persons' AND `name`='profile-subscribe-add';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions' AND `module`='bx_persons' AND `name`='profile-set-acl-level';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions' AND `module`='bx_persons' AND `name`='profile-set-badges';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions' AND `module`='bx_persons' AND `name`='profile-actions-more';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_more' AND `module`='bx_persons' AND `name`='edit-persons-profile';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_more' AND `module`='bx_persons' AND `name`='edit-persons-badge';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_more' AND `module`='bx_persons' AND `name`='delete-persons-profile';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_more' AND `module`='bx_persons' AND `name`='delete-persons-account';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_all' AND `module`='bx_persons' AND `name`='profile-friend-add';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_all' AND `module`='bx_persons' AND `name`='profile-friend-remove';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_all' AND `module`='bx_persons' AND `name`='profile-subscribe-add';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_all' AND `module`='bx_persons' AND `name`='profile-subscribe-remove';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_all' AND `module`='bx_persons' AND `name`='profile-set-acl-level';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_all' AND `module`='bx_persons' AND `name`='profile-set-badges';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_actions_all' AND `module`='bx_persons' AND `name`='feature';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_meta' AND `module`='bx_persons' AND `name`='membership';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_meta' AND `module`='bx_persons' AND `name`='badges';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_meta' AND `module`='bx_persons' AND `name`='friends';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_meta' AND `module`='bx_persons' AND `name`='subscribers';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_meta' AND `module`='bx_persons' AND `name`='views';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_meta' AND `module`='bx_persons' AND `name`='votes';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_meta' AND `module`='bx_persons' AND `name`='comments';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_submenu' AND `module`='bx_persons' AND `name`='persons-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_submenu' AND `module`='bx_persons' AND `name`='persons-active';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_submenu' AND `module`='bx_persons' AND `name`='persons-online';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_submenu' AND `module`='bx_persons' AND `name`='persons-search';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_submenu' AND `module`='bx_persons' AND `name`='persons-manage';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_submenu' AND `module`='bx_persons' AND `name`='view-persons-profile';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_submenu' AND `module`='bx_persons' AND `name`='persons-profile-info';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_submenu' AND `module`='bx_persons' AND `name`='persons-profile-friends';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_view_submenu' AND `module`='bx_persons' AND `name`='persons-profile-subscriptions';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_snippet_meta' AND `module`='bx_persons' AND `name`='befriend';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_snippet_meta' AND `module`='bx_persons' AND `name`='subscribe';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_snippet_meta' AND `module`='bx_persons' AND `name`='ignore-befriend';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_snippet_meta' AND `module`='bx_persons' AND `name`='ignore-subscribe';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_snippet_meta' AND `module`='bx_persons' AND `name`='unfriend';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_snippet_meta' AND `module`='bx_persons' AND `name`='unsubscribe';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_menu_manage_tools' AND `module`='bx_persons' AND `name`='clear-reports';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_menu_manage_tools' AND `module`='bx_persons' AND `name`='manage-cf';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_persons_menu_manage_tools' AND `module`='bx_persons' AND `name`='delete-with-content';

+ 590 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/enable.sql

@@ -0,0 +1,590 @@
+
+-- 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_persons', '_bx_persons', 'bx_persons@modules/boonex/persons/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_persons', '_bx_persons', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
+('bx_persons_autoapproval', 'on', @iCategId, '_bx_persons_option_autoapproval', 'select', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:22:"get_options_activation";}', '', '', 1),
+('bx_persons_default_acl_level', '3', @iCategId, '_bx_persons_option_default_acl_level', 'select', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:15:"get_memberships";s:6:"params";a:4:{s:11:"purchasable";b:0;s:6:"active";b:1;s:9:"translate";b:1;s:22:"filter_out_auto_levels";b:1;}s:5:"class";s:16:"TemplAclServices";}', '', '', 2),
+('bx_persons_redirect_aadd', 'profile', @iCategId, '_bx_persons_option_redirect_aadd', 'select', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:30:"get_options_redirect_after_add";}', '', '', 3),
+('bx_persons_redirect_aadd_custom_url', '', @iCategId, '_bx_persons_option_redirect_aadd_custom_url', 'digit', '', '', '', 4),
+('bx_persons_num_connections_quick', '6', @iCategId, '_bx_persons_option_num_connections_quick', 'digit', '', '', '', 10),
+('bx_persons_per_page_browse', '24', @iCategId, '_bx_persons_option_per_page_browse', 'digit', '', '', '', 11),
+('bx_persons_num_rss', '10', @iCategId, '_bx_persons_option_num_rss', 'digit', '', '', '', 12),
+('bx_persons_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 15),
+('bx_persons_per_page_browse_recommended', '10', @iCategId, '_sys_option_per_page_browse_recommended', 'digit', '', '', '', 16),
+('bx_persons_searchable_fields', 'fullname,description', @iCategId, '_bx_persons_option_searchable_fields', 'list', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:21:"get_searchable_fields";}', '', '', 20),
+('bx_persons_friends', 'on', @iCategId, '_bx_persons_option_friends', 'checkbox', '', '', '', 30),
+('bx_persons_public_subscriptions', '', @iCategId, '_bx_persons_option_public_subscriptions', 'checkbox', '', '', '', 35),
+('bx_persons_public_subscribed_me', '', @iCategId, '_bx_persons_option_public_subscribed_me', 'checkbox', '', '', '', 36),
+('bx_persons_enable_profile_activation_letter', 'on', @iCategId, '_bx_persons_option_enable_profile_activation_letter', 'checkbox', '', '', '', 40);
+
+-- PAGES
+
+-- PAGE: create profile
+
+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_persons_create_profile', 'create-persons-profile', '_bx_persons_page_title_sys_create_profile', '_bx_persons_page_title_create_profile', 'bx_persons', 5, 2147483647, 1, 'page.php?i=create-persons-profile', '', '', '', 0, 1, 0, '', '');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_persons_create_profile', 1, 'bx_persons', '_bx_persons_page_block_title_choose_type', 11, 2147483647, 'menu', 'sys_add_profile_vertical', 0, 1, 0, 0),
+('bx_persons_create_profile', 1, 'bx_persons', '_bx_persons_page_block_title_create_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:13:\"entity_create\";}', 0, 1, 1, 1);
+
+-- PAGE: view profile
+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_persons_view_profile', 'view-persons-profile', '_bx_persons_page_title_sys_view_profile', '_bx_persons_page_title_view_profile', 'bx_persons', 7, 2147483647, 1, 'page.php?i=view-persons-profile', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_view_profile', 0, 'bx_persons', '_bx_persons_page_block_title_sys_cover_block', '_bx_persons_page_block_title_cover_block', 3, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:12:\"entity_cover\";}', 0, 0, 1, 0),
+('bx_persons_view_profile', 0, 'bx_persons', '', '_bx_persons_page_block_title_profile_friends_mutual', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:22:\"profile_friends_mutual\";}', 0, 0, 1, 0),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_subscriptions', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:21:\"profile_subscriptions\";}', 0, 1, 0, 0),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_subscribed_me', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:21:\"profile_subscribed_me\";}', 0, 1, 0, 0),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_related_me', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:18:"profile_related_me";}', 0, 1, 0, 0),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 0, 0),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_description', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 1),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_friends', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:15:\"profile_friends\";}', 0, 1, 1, 2),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_relations', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:17:"profile_relations";}', 0, 1, 1, 3),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_profile_calendar', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:15:\"entity_calendar\";}', 0, 0, 0, 4),
+('bx_persons_view_profile', 3, 'bx_persons', '', '_bx_persons_page_block_title_profile_location', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:15:\"entity_location\";}', 0, 0, 0, 0),
+('bx_persons_view_profile', 3, 'bx_persons', '', '_bx_persons_page_block_title_profile_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 1),
+('bx_persons_view_profile', 3, 'bx_persons', '', '_bx_persons_page_block_title_profile_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:18:"entity_all_actions";}', 0, 0, 0, 0),
+('bx_persons_view_profile', 3, 'bx_persons', '', '_bx_persons_page_block_title_profile_membership', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:18:\"profile_membership\";}', 0, 0, 1, 2),
+('bx_persons_view_profile', 3, 'bx_persons', '', '_bx_persons_page_block_title_profile_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:10:\"bx_persons\";i:1;s:12:\"{content_id}\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 0, 1, 3),
+('bx_persons_view_profile', 2, 'bx_persons', '', '_bx_persons_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+-- PAGE: view closed profile 
+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_persons_view_profile_closed', 'view-person-profile-closed', '_bx_persons_page_title_sys_view_profile_closed', '_bx_persons_page_title_view_profile', 'bx_persons', 10, 2147483647, 1, 'page.php?i=view-person-profile', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_view_profile_closed', 1, 'bx_persons', '', '_bx_persons_page_block_title_profile_private', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:19:\"private_profile_msg\";}', 0, 1, 1, 0);
+
+-- PAGE: edit profile
+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_persons_edit_profile', 'edit-persons-profile', '_bx_persons_page_title_sys_edit_profile', '_bx_persons_page_title_edit_profile', 'bx_persons', 5, 2147483647, 1, 'page.php?i=edit-persons-profile', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_persons_edit_profile', 1, 'bx_persons', '_bx_persons_page_block_title_edit_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:11:\"entity_edit\";}', 0, 0, 0);
+
+-- PAGE: edit badge
+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_persons_edit_badge', 'edit-persons-badge', '_bx_persons_page_title_sys_edit_profile_badge', '_bx_persons_page_title_edit_profile_badge', 'bx_persons', 5, 2147483647, 1, 'page.php?i=edit-persons-badge', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_persons_edit_badge', 1, 'bx_persons', '_bx_persons_page_block_title_edit_profile_badge', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:17:"entity_edit_badge";}', 0, 0, 0);
+
+-- PAGE: delete profile
+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_persons_delete_profile', 'delete-persons-profile', '_bx_persons_page_title_sys_delete_profile', '_bx_persons_page_title_delete_profile', 'bx_persons', 5, 2147483647, 1, 'page.php?i=delete-persons-profile', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_persons_delete_profile', 1, 'bx_persons', '_bx_persons_page_block_title_delete_profile', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:13:\"entity_delete\";}', 0, 0, 0);
+
+-- PAGE: profile info
+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_persons_profile_info', 'persons-profile-info', '_bx_persons_page_title_sys_profile_info', '_bx_persons_page_title_profile_info', 'bx_persons', 5, 2147483647, 1, 'page.php?i=persons-profile-info', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_profile_info', 1, 'bx_persons', '_bx_persons_page_block_title_system_profile_info', '_bx_persons_page_block_title_profile_info_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:16:\"entity_info_full\";}', 0, 0, 1, 1),
+('bx_persons_profile_info', 1, 'bx_persons', '', '_bx_persons_page_block_title_profile_description', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 2);
+
+-- PAGE: profile friends
+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_persons_profile_friends', 'persons-profile-friends', '_bx_persons_page_title_sys_profile_friends', '_bx_persons_page_title_profile_friends', 'bx_persons', 5, 2147483647, 1, 'page.php?i=persons-profile-friends', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_profile_friends', 1, 'bx_persons', '_bx_persons_page_block_title_system_profile_friends', '_bx_persons_page_block_title_profile_friends_link', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:17:"connections_table";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}s:5:"class";s:23:"TemplServiceConnections";}', 0, 0, 1, 1);
+
+-- PAGE: profile friend requests
+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_persons_friend_requests', 'persons-friend-requests', '_bx_persons_page_title_sys_friend_requests', '_bx_persons_page_title_friend_requests', 'bx_persons', 5, 2147483647, 1, 'page.php?i=persons-friend-requests', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_friend_requests', 1, 'bx_persons', '_bx_persons_page_block_title_system_friend_requests', '_bx_persons_page_block_title_friend_requests_link', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:25:\"connections_request_table\";s:5:\"class\";s:23:\"TemplServiceConnections\";}', 0, 0, 1, 1);
+
+-- PAGE: profile favorites
+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_persons_profile_favorites', 'persons-profile-favorites', '_bx_persons_page_title_sys_profile_favorites', '_bx_persons_page_title_profile_favorites', 'bx_persons', 5, 2147483647, 1, 'page.php?i=persons-profile-favorites', '', '', '', 0, 1, 0, 'BxPersonsPageBrowse', 'modules/boonex/persons/classes/BxPersonsPageBrowse.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_persons_profile_favorites', 1, 'bx_persons', '_bx_persons_page_block_title_system_profile_favorites', '_bx_persons_page_block_title_profile_favorites', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:15:"browse_favorite";}', 0, 1, 1, 1);
+
+-- PAGE: profile subscriptions
+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_persons_profile_subscriptions', 'persons-profile-subscriptions', '_bx_persons_page_title_sys_profile_subscriptions', '_bx_persons_page_title_profile_subscriptions', 'bx_persons', 5, 2147483647, 1, 'page.php?i=persons-profile-subscriptions', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_profile_subscriptions', 1, 'bx_persons', '_bx_persons_page_block_title_system_profile_subscriptions', '_bx_persons_page_block_title_profile_subscriptions', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:19:\"subscriptions_table\";s:5:\"class\";s:23:\"TemplServiceConnections\";}', 0, 0, 1, 1),
+('bx_persons_profile_subscriptions', 1, 'bx_persons', '_bx_persons_page_block_title_system_profile_subscribed_me', '_bx_persons_page_block_title_profile_subscribed_me', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:6:\"system\";s:6:\"method\";s:19:\"subscribed_me_table\";s:5:\"class\";s:23:\"TemplServiceConnections\";}', 0, 0, 1, 2);
+
+-- PAGE: profile relations
+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_persons_profile_relations', 'persons-profile-relations', '_bx_persons_page_title_sys_profile_relations', '_bx_persons_page_title_profile_relations', 'bx_persons', 5, 2147483647, 1, 'page.php?i=persons-profile-relations', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_profile_relations', 1, 'bx_persons', '_bx_persons_page_block_title_system_profile_relations', '_bx_persons_page_block_title_profile_relations', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:15:"relations_table";s:5:"class";s:23:"TemplServiceConnections";}', 0, 0, 1, 1),
+('bx_persons_profile_relations', 1, 'bx_persons', '_bx_persons_page_block_title_system_profile_related_me', '_bx_persons_page_block_title_profile_related_me', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:16:"related_me_table";s:5:"class";s:23:"TemplServiceConnections";}', 0, 0, 1, 2);
+
+-- 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_persons_profile_comments', '_bx_persons_page_title_sys_profile_comments', '_bx_persons_page_title_profile_comments', 'bx_persons', 5, 2147483647, 1, 'persons-profile-comments', '', '', '', '', 0, 1, 0, 'BxPersonsPageEntry', 'modules/boonex/persons/classes/BxPersonsPageEntry.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_persons_profile_comments', 1, 'bx_persons', '_bx_persons_page_block_title_profile_comments', '_bx_persons_page_block_title_profile_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 0, 1);
+
+
+-- PAGE: module home
+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_persons_home', '_bx_persons_page_title_sys_recent', '_bx_persons_page_title_recent', 'bx_persons', 5, 2147483647, 1, 'persons-home', 'page.php?i=persons-home', '', '', '', 0, 1, 0, 'BxPersonsPageBrowse', 'modules/boonex/persons/classes/BxPersonsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_persons_home', 1, 'bx_persons', '_bx_persons_page_block_title_featured_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_persons";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 0),
+('bx_persons_home', 1, 'bx_persons', '_bx_persons_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:22:\"browse_recent_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 1);
+
+-- PAGE: active profiles
+
+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_persons_active', '_bx_persons_page_title_sys_active', '_bx_persons_page_title_active', 'bx_persons', 5, 2147483647, 1, 'persons-active', 'page.php?i=persons-active', '', '', '', 0, 1, 0, 'BxPersonsPageBrowse', 'modules/boonex/persons/classes/BxPersonsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_persons_active', 1, 'bx_persons', '_bx_persons_page_block_title_active_profiles', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_persons";s:6:"method";s:22:"browse_active_profiles";s:6:"params";a:2:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:1;}}', 0, 1, 0);
+
+-- PAGE: online profiles
+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_persons_online', '_bx_persons_page_title_sys_online', '_bx_persons_page_title_online', 'bx_persons', 5, 2147483647, 1, 'persons-online', 'page.php?i=persons-online', '', '', '', 0, 1, 0, 'BxPersonsPageBrowse', 'modules/boonex/persons/classes/BxPersonsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_persons_online', 1, 'bx_persons', '_bx_persons_page_block_title_online_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:22:\"browse_online_profiles\";s:6:"params";a:1:{i:0;b:1;}}', 0, 1, 0);
+
+-- PAGE: search for 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_persons_search', '_bx_persons_page_title_sys_entries_search', '_bx_persons_page_title_entries_search', 'bx_persons', 5, 2147483647, 1, 'persons-search', 'page.php?i=persons-search', '', '', '', 0, 1, 0, 'BxPersonsPageBrowse', 'modules/boonex/persons/classes/BxPersonsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_persons_search', 1, 'bx_persons', '_bx_persons_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:10:"bx_persons";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_persons_search', 1, 'bx_persons', '_bx_persons_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:10:"bx_persons";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_persons_search', 1, 'bx_persons', '_bx_persons_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:15:"bx_persons_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_persons_search', 1, 'bx_persons', '_bx_persons_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:15:"bx_persons_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- 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_persons_manage', '_bx_persons_page_title_sys_manage', '_bx_persons_page_title_manage', 'bx_persons', 5, 2147483647, 1, 'persons-manage', 'page.php?i=persons-manage', '', '', '', 0, 1, 0, 'BxPersonsPageBrowse', 'modules/boonex/persons/classes/BxPersonsPageBrowse.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_persons_manage', 1, 'bx_persons', '_bx_persons_page_block_title_system_manage', '_bx_persons_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:10:\"bx_persons\";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_persons_administration', '_bx_persons_page_title_sys_manage_administration', '_bx_persons_page_title_manage', 'bx_persons', 5, 192, 1, 'persons-administration', 'page.php?i=persons-administration', '', '', '', 0, 1, 0, 'BxPersonsPageBrowse', 'modules/boonex/persons/classes/BxPersonsPageBrowse.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_persons_administration', 1, 'bx_persons', '_bx_persons_page_block_title_system_manage_administration', '_bx_persons_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";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_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES
+('sys_home', 1, 'bx_persons', '' , '_bx_persons_page_block_title_latest_profiles', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:22:"browse_recent_profiles";}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1),
+('sys_home', 1, 'bx_persons', '_bx_persons_page_block_title_sys_recommended_entries_view_showcase', '_bx_persons_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:18:\"browse_recommended\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 2);
+
+-- 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_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('', 0, 'bx_persons', '_bx_persons_page_block_title_sys_featured_entries_view_showcase', '_bx_persons_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, 'bx_persons', '_bx_persons_page_block_title_sys_recommended_entries_view_showcase', '_bx_persons_page_block_title_recommended_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:18:\"browse_recommended\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, 'bx_persons', '_bx_persons_page_block_title_sys_active_entries_view_showcase', '_bx_persons_page_block_title_active_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:22:\"browse_active_profiles\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:16:\"showcase_wo_info\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, 'bx_persons', '_bx_persons_page_block_title_sys_active_profiles', '_bx_persons_page_block_title_active_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:22:\"browse_active_profiles\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:12:\"unit_wo_info\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, 'bx_persons', '_bx_persons_page_block_title_sys_familiar_profiles', '_bx_persons_page_block_title_familiar_profiles', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_persons\";s:6:\"method\";s:24:\"browse_familiar_profiles\";s:6:\"params\";a:4:{s:10:\"connection\";s:20:\"sys_profiles_friends\";s:9:\"unit_view\";s:4:\"unit\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:1;}}', 0, 1, 1, IFNULL(@iBlockOrder, 0) + 5);
+
+-- MENU
+
+-- MENU: add to site menu
+
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 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_persons', 'persons-home', '_bx_persons_menu_item_title_system_entries_home', '_bx_persons_menu_item_title_entries_home', 'page.php?i=persons-home', '', '', 'user col-blue3', 'bx_persons_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_persons', 'persons-home', '_bx_persons_menu_item_title_system_entries_home', '_bx_persons_menu_item_title_entries_home', 'page.php?i=persons-home', '', '', 'user col-blue3', 'bx_persons_submenu', 2147483647, 1, 1, IFNULL(@iHomepageMenuOrder, 0) + 1);
+
+-- SET @iCreateProfileMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_profiles_create' 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_profiles_create', 'bx_persons', 'create-person-profile', '_bx_persons_menu_item_title_system_profile_type', '_bx_persons_menu_item_title_profile_type', 'page.php?i=create-persons-profile', '', '', 'user', '', 2147483647, 1, 1, IFNULL(@iCreateProfileMenuOrder, 0) + 1);
+
+SET @iAddMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_add_profile_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_profile_links', 'bx_persons', 'create-persons-profile', '_bx_persons_menu_item_title_system_create_profile', '_bx_persons_menu_item_title_create_profile', 'page.php?i=create-persons-profile', '', '', 'user col-blue3', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: view actions
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_persons_view_actions', '_bx_persons_menu_title_view_profile_actions', 'bx_persons_view_actions', 'bx_persons', 9, 0, 1, 'BxPersonsMenuViewActions', 'modules/boonex/persons/classes/BxPersonsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_view_actions', 'bx_persons', '_bx_persons_menu_set_title_view_profile_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_persons_view_actions', 'bx_persons', 'profile-friend-add', '_bx_persons_menu_item_title_system_befriend', '{title_add_friend}', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_friends\', \'add\', \'{profile_id}\')', '', 'user-plus', '', 0, 2147483647, '', 1, 0, 10),
+('bx_persons_view_actions', 'bx_persons', 'profile-friend-remove', '_bx_persons_menu_item_title_system_unfriend', '{title_remove_friend}', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_friends\', \'remove\', \'{profile_id}\')', '', 'user-times', '', 0, 2147483647, '', 1, 0, 11),
+('bx_persons_view_actions', 'bx_persons', 'profile-relation-add', '_bx_persons_menu_item_title_system_relation_add', '_bx_persons_menu_item_title_relation_add', 'javascript:void(0)', 'bx_menu_popup(''sys_add_relation'', window, {}, {profile_id: {profile_id}});', '', 'sync', '', 0, 2147483647, '', 1, 0, 15),
+('bx_persons_view_actions', 'bx_persons', 'profile-relation-remove', '_bx_persons_menu_item_title_system_relation_delete', '_bx_persons_menu_item_title_relation_delete', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_relations\', \'remove\', \'{profile_id}\')', '', 'sync', '', 0, 2147483647, '', 1, 0, 16),
+('bx_persons_view_actions', 'bx_persons', 'profile-subscribe-add', '_bx_persons_menu_item_title_system_subscribe', '_bx_persons_menu_item_title_subscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'add\', \'{profile_id}\')', '', 'check', '', 0, 2147483647, '', 1, 0, 20),
+('bx_persons_view_actions', 'bx_persons', 'profile-subscribe-remove', '_bx_persons_menu_item_title_system_unsubscribe', '_bx_persons_menu_item_title_unsubscribe', 'javascript:void(0)', 'bx_conn_action(this, \'sys_profiles_subscriptions\', \'remove\', \'{profile_id}\')', '', 'check', '', 0, 2147483647, '', 1, 0, 21),
+('bx_persons_view_actions', 'bx_persons', 'profile-set-acl-level', '_sys_menu_item_title_system_set_acl_level', '_sys_menu_item_title_set_acl_level', 'javascript:void(0)', 'bx_menu_popup(''sys_set_acl_level'', window, {id:{value:''sys_acl_set_{profile_id}'', force:true}, closeOnOuterClick: false, removeOnClose: true, displayMode: ''box'', cssClass: ''''}, {profile_id: {profile_id}});', '', 'certificate', '', 0, 2147483647, '', 1, 0, 30),
+('bx_persons_view_actions', 'bx_persons', 'profile-set-badges', '_sys_menu_item_title_system_set_badges', '_sys_menu_item_title_set_badges', 'javascript:void(0)', 'bx_menu_popup(''sys_set_badges'', window, {}, {module: ''bx_persons'', content_id: {content_id}});', '', 'check-circle', '', 0, 192, 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 30),
+('bx_persons_view_actions', 'bx_persons', 'profile-actions-more', '_bx_persons_menu_item_title_system_more_actions', '_bx_persons_menu_item_title_more_actions', 'javascript:void(0)', 'bx_menu_popup(''bx_persons_view_actions_more'', this, {}, {profile_id:{profile_id}});', '', 'cog', 'bx_persons_view_actions_more', 1, 2147483647, '', 1, 0, 9999);
+
+-- MENU: view actions more
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_persons_view_actions_more', '_bx_persons_menu_title_view_profile_actions_more', 'bx_persons_view_actions_more', 'bx_persons', 6, 0, 1, 'BxPersonsMenuViewActions', 'modules/boonex/persons/classes/BxPersonsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_view_actions_more', 'bx_persons', '_bx_persons_menu_set_title_view_profile_actions_more', 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_persons_view_actions_more', 'bx_persons', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', 192, 1, 0, 10),
+('bx_persons_view_actions_more', 'bx_persons', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_persons&content_id={content_id}', '', '', 'history', '', 192, 1, 0, 20),
+('bx_persons_view_actions_more', 'bx_persons', 'edit-persons-profile', '_bx_persons_menu_item_title_system_edit_profile', '_bx_persons_menu_item_title_edit_profile', 'page.php?i=edit-persons-profile&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 30),
+('bx_persons_view_actions_more', 'bx_persons', 'edit-persons-badge', '_bx_persons_menu_item_title_system_edit_badge', '_bx_persons_menu_item_title_edit_badge', 'page.php?i=edit-persons-badge&id={content_id}', '', '', 'fa-certificate', '', 2147483647, 1, 0, 32),
+('bx_persons_view_actions_more', 'bx_persons', 'delete-persons-profile', '_bx_persons_menu_item_title_system_delete_profile', '_bx_persons_menu_item_title_delete_profile', 'page.php?i=delete-persons-profile&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 40),
+('bx_persons_view_actions_more', 'bx_persons', 'delete-persons-account', '_bx_persons_menu_item_title_system_delete_account', '_bx_persons_menu_item_title_delete_account', 'page.php?i=account-settings-delete&id={account_id}&content=0', '', '', 'user-times', '', 128, 1, 0, 50),
+('bx_persons_view_actions_more', 'bx_persons', 'delete-persons-account-content', '_bx_persons_menu_item_title_system_delete_account_content', '_bx_persons_menu_item_title_delete_account_content', 'page.php?i=account-settings-delete&id={account_id}&content=1', '', '', 'trash', '', 128, 1, 0, 60);
+
+-- MENU: all actions menu for view entry 
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `persistent`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_persons_view_actions_all', '_sys_menu_title_view_actions', 'bx_persons_view_actions_all', 'bx_persons', 15, 1, 0, 1, 'BxPersonsMenuViewActionsAll', 'modules/boonex/persons/classes/BxPersonsMenuViewActionsAll.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_view_actions_all', 'bx_persons', '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_persons_view_actions_all', 'bx_persons', 'profile-friends', '_bx_persons_menu_item_title_system_friends', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-friend-add', '_bx_persons_menu_item_title_system_befriend', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 12),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-friend-remove', '_bx_persons_menu_item_title_system_unfriend', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 14),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-relations', '_bx_persons_menu_item_title_system_relations', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-relation-add', '_bx_persons_menu_item_title_system_relation_add', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 22),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-relation-remove', '_bx_persons_menu_item_title_system_relation_delete', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 24),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-subscriptions', '_bx_persons_menu_item_title_system_subscriptions', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-subscribe-add', '_bx_persons_menu_item_title_system_subscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 32),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-subscribe-remove', '_bx_persons_menu_item_title_system_unsubscribe', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 34),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-set-acl-level', '_sys_menu_item_title_system_set_acl_level', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 50),
+('bx_persons_view_actions_all', 'bx_persons', 'profile-set-badges', '_sys_menu_item_title_system_set_badges', '', '', '', '', '', '', '', 0, 192, 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 60),
+('bx_persons_view_actions_all', 'bx_persons', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 200),
+('bx_persons_view_actions_all', 'bx_persons', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 210),
+('bx_persons_view_actions_all', 'bx_persons', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 215),
+('bx_persons_view_actions_all', 'bx_persons', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 217),
+('bx_persons_view_actions_all', 'bx_persons', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 220),
+('bx_persons_view_actions_all', 'bx_persons', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 230),
+('bx_persons_view_actions_all', 'bx_persons', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 240),
+('bx_persons_view_actions_all', 'bx_persons', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 250),
+('bx_persons_view_actions_all', 'bx_persons', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, '', 1, 0, 9999);
+
+-- MENU: meta (counters) 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_persons_view_meta', '_bx_persons_menu_title_view_profile_meta', 'bx_persons_view_meta', 'bx_persons', 15, 0, 1, 'BxPersonsMenuViewMeta', 'modules/boonex/persons/classes/BxPersonsMenuViewMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_view_meta', 'bx_persons', '_bx_persons_menu_set_title_view_profile_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_persons_view_meta', 'bx_persons', 'membership', '_sys_menu_item_title_system_vm_membership', '_sys_menu_item_title_vm_membership', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_persons_view_meta', 'bx_persons', 'badges', '_sys_menu_item_title_system_vm_badges', '_sys_menu_item_title_vm_badges', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_persons_view_meta', 'bx_persons', 'friends', '_sys_menu_item_title_system_sm_friends', '_sys_menu_item_title_sm_friends', '', '', '', '', '', 0, 2147483647, '', 1, 0, 23),
+('bx_persons_view_meta', 'bx_persons', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_sys_menu_item_title_sm_subscribers', '', '', '', '', '', 0, 2147483647, '', 1, 0, 25),
+('bx_persons_view_meta', 'bx_persons', 'relations', '_sys_menu_item_title_system_sm_relations', '_sys_menu_item_title_sm_relations', '', '', '', '', '', 0, 2147483647, '', 0, 0, 27),
+('bx_persons_view_meta', 'bx_persons', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_persons_view_meta', 'bx_persons', 'votes', '_sys_menu_item_title_system_sm_votes', '_sys_menu_item_title_sm_votes', '', '', '', '', '', 0, 2147483647, '', 1, 0, 40),
+('bx_persons_view_meta', 'bx_persons', 'reactions', '_sys_menu_item_title_system_sm_reactions', '_sys_menu_item_title_sm_reactions', '', '', '', '', '', 0, 2147483647, '', 0, 0, 43),
+('bx_persons_view_meta', 'bx_persons', 'scores', '_sys_menu_item_title_system_sm_scores', '_sys_menu_item_title_sm_scores', '', '', '', '', '', 0, 2147483647, '', 0, 0, 46),
+('bx_persons_view_meta', 'bx_persons', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 0, 2147483647, '', 1, 0, 50);
+
+-- MENU: module sub-menu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `title_public`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_persons_submenu', '_bx_persons_menu_title_submenu', '_bx_persons_menu_title_public_submenu', 'bx_persons_submenu', 'bx_persons', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_submenu', 'bx_persons', '_bx_persons_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_persons_submenu', 'bx_persons', 'persons-home', '_bx_persons_menu_item_title_system_entries_recent', '_bx_persons_menu_item_title_entries_recent', 'page.php?i=persons-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_persons_submenu', 'bx_persons', 'persons-active', '_bx_persons_menu_item_title_system_entries_active', '_bx_persons_menu_item_title_entries_active', 'page.php?i=persons-active', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_persons_submenu', 'bx_persons', 'persons-online', '_bx_persons_menu_item_title_system_entries_online', '_bx_persons_menu_item_title_entries_online', 'page.php?i=persons-online', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_persons_submenu', 'bx_persons', 'persons-search', '_bx_persons_menu_item_title_system_entries_search', '_bx_persons_menu_item_title_entries_search', 'page.php?i=persons-search', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_persons_submenu', 'bx_persons', 'persons-manage', '_bx_persons_menu_item_title_system_entries_manage', '_bx_persons_menu_item_title_entries_manage', 'page.php?i=persons-manage', '', '', '', '', 2147483646, 1, 1, 5);
+
+-- MENU: view submenu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_persons_view_submenu', '_bx_persons_menu_title_view_profile_submenu', 'bx_persons_view_submenu', 'bx_persons', 18, 0, 1, 'BxPersonsMenuView', 'modules/boonex/persons/classes/BxPersonsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_view_submenu', 'bx_persons', '_bx_persons_menu_set_title_view_profile_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_persons_view_submenu', 'bx_persons', 'view-persons-profile', '_bx_persons_menu_item_title_system_view_profile_view', '_bx_persons_menu_item_title_view_profile_view', 'page.php?i=view-persons-profile&id={content_id}', '', '', 'user col-blue3', '', '', 0, 2147483647, 1, 0, 1),
+('bx_persons_view_submenu', 'bx_persons', 'persons-profile-info', '_bx_persons_menu_item_title_system_view_profile_info', '_bx_persons_menu_item_title_view_profile_info', 'page.php?i=persons-profile-info&id={content_id}', '', '', 'info-circle col-gray', '', '', 0, 2147483647, 1, 0, 2),
+('bx_persons_view_submenu', 'bx_persons', 'persons-profile-friends', '_bx_persons_menu_item_title_system_view_profile_friends', '_bx_persons_menu_item_title_view_profile_friends', 'page.php?i=persons-profile-friends&profile_id={profile_id}', '', '', 'users col-blue3', '', '', 0, 2147483647, 1, 0, 3),
+('bx_persons_view_submenu', 'bx_persons', 'persons-profile-relations', '_bx_persons_menu_item_title_system_view_profile_relations', '_bx_persons_menu_item_title_view_profile_relations', 'page.php?i=persons-profile-relations&profile_id={profile_id}', '', '', 'sync col-blue3', '', '', 0, 2147483647, 1, 0, 4),
+('bx_persons_view_submenu', 'bx_persons', 'persons-profile-subscriptions', '_bx_persons_menu_item_title_system_view_profile_subscriptions', '_bx_persons_menu_item_title_view_profile_subscriptions', 'page.php?i=persons-profile-subscriptions&profile_id={profile_id}', '', '', 'check col-blue3', '', '', 0, 2147483647, 1, 0, 5),
+('bx_persons_view_submenu', 'bx_persons', 'persons-profile-comments', '_bx_persons_menu_item_title_system_view_profile_comments', '_bx_persons_menu_item_title_view_profile_comments', 'page.php?i=persons-profile-comments&id={content_id}', '', '', '', '', '', 0, 2147483647, 0, 0, 6),
+('bx_persons_view_submenu', 'bx_persons', 'more-auto', '_bx_persons_menu_item_title_system_view_profile_more_auto', '_bx_persons_menu_item_title_view_profile_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, 1, 0, 9999);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_persons_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_persons_snippet_meta', 'bx_persons', 15, 0, 1, 'BxPersonsMenuSnippetMeta', 'modules/boonex/persons/classes/BxPersonsMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_snippet_meta', 'bx_persons', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `hidden_on_cxt`, `active`, `copyable`, `editable`, `order`) VALUES
+('bx_persons_snippet_meta', 'bx_persons', 'friends-mutual', '_sys_menu_item_title_system_sm_friends_mutual', '_sys_menu_item_title_sm_friends_mutual', '', '', '', '', '', 2147483647, 'all!recom_friends', 1, 0, 1, 0),
+('bx_persons_snippet_meta', 'bx_persons', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, '', 0, 0, 1, 5),
+('bx_persons_snippet_meta', 'bx_persons', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, '', 0, 0, 1, 10),
+('bx_persons_snippet_meta', 'bx_persons', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, '', 0, 0, 1, 15),
+('bx_persons_snippet_meta', 'bx_persons', 'votes', '_sys_menu_item_title_system_sm_votes', '_sys_menu_item_title_sm_votes', '', '', '', '', '', 2147483647, '', 0, 0, 1, 16),
+('bx_persons_snippet_meta', 'bx_persons', 'reactions', '_sys_menu_item_title_system_sm_reactions', '_sys_menu_item_title_sm_reactions', '', '', '', '', '', 2147483647, '', 0, 0, 1, 17),
+('bx_persons_snippet_meta', 'bx_persons', 'scores', '_sys_menu_item_title_system_sm_scores', '_sys_menu_item_title_sm_scores', '', '', '', '', '', 2147483647, '', 0, 0, 1, 18),
+('bx_persons_snippet_meta', 'bx_persons', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, '', 0, 0, 1, 20),
+('bx_persons_snippet_meta', 'bx_persons', 'friends', '_sys_menu_item_title_system_sm_friends', '_sys_menu_item_title_sm_friends', '', '', '', '', '', 2147483647, 'recom_friends,recom_subscriptions', 1, 0, 1, 30),
+('bx_persons_snippet_meta', 'bx_persons', 'subscribers', '_sys_menu_item_title_system_sm_subscribers', '_sys_menu_item_title_sm_subscribers', '', '', '', '', '', 2147483647, 'recom_friends', 1, 0, 1, 40),
+('bx_persons_snippet_meta', 'bx_persons', 'membership', '_sys_menu_item_title_system_sm_membership', '_sys_menu_item_title_sm_membership', '', '', '', '', '', 2147483647, '', 0, 0, 1, 50),
+('bx_persons_snippet_meta', 'bx_persons', 'nl', '_sys_menu_item_title_system_sm_nl', '_sys_menu_item_title_sm_nl', '', '', '', '', '', 2147483647, '', 1, 0, 1, 55),
+('bx_persons_snippet_meta', 'bx_persons', 'obj-friends', '_sys_menu_item_title_system_sm_friends', '', '', '', '', '', '', 2147483647, 'recom_friends,recom_subscriptions', 1, 0, 1, 60),
+('bx_persons_snippet_meta', 'bx_persons', 'befriend', '_sys_menu_item_title_system_sm_befriend', '_sys_menu_item_title_sm_befriend', '', '', '', '', '', 2147483647, 'all!recom_friends', 1, 0, 1, 62),
+('bx_persons_snippet_meta', 'bx_persons', 'unfriend', '_sys_menu_item_title_system_sm_unfriend', '_sys_menu_item_title_sm_unfriend', '', '', '', '', '', 2147483647, 'recom_friends,recom_subscriptions', 0, 0, 1, 64),
+('bx_persons_snippet_meta', 'bx_persons', 'obj-subscriptions', '_sys_menu_item_title_system_sm_subscriptions', '', '', '', '', '', '', 2147483647, 'recom_friends,recom_subscriptions', 1, 0, 1, 70),
+('bx_persons_snippet_meta', 'bx_persons', 'subscribe', '_sys_menu_item_title_system_sm_subscribe', '_sys_menu_item_title_sm_subscribe', '', '', '', '', '', 2147483647, 'all!recom_subscriptions', 1, 0, 1, 72),
+('bx_persons_snippet_meta', 'bx_persons', 'unsubscribe', '_sys_menu_item_title_system_sm_unsubscribe', '_sys_menu_item_title_sm_unsubscribe', '', '', '', '', '', 2147483647, 'recom_friends,recom_subscriptions', 0, 0, 1, 74),
+('bx_persons_snippet_meta', 'bx_persons', 'ignore-befriend', '_sys_menu_item_title_system_sm_ignore_befriend', '_sys_menu_item_title_sm_ignore', '', '', '', '', '', 2147483647, 'all!recom_friends', 1, 0, 1, 80),
+('bx_persons_snippet_meta', 'bx_persons', 'ignore-subscribe', '_sys_menu_item_title_system_sm_ignore_subscribe', '_sys_menu_item_title_sm_ignore', '', '', '', '', '', 2147483647, 'all!recom_subscriptions', 1, 0, 1, 85);
+
+-- MENU: notifications menu in account popup
+SET @iNotifMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name` = 'sys_account_notifications' AND `active` = 1 AND `order` < 9999 ORDER BY `order` DESC LIMIT 1);
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES
+('sys_account_notifications', 'bx_persons', 'notifications-friend-requests', '_bx_persons_menu_item_title_system_friends', '_bx_persons_menu_item_title_friends', 'page.php?i=persons-profile-friends&profile_id={member_id}', '', '', 'users col-blue3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:31:"get_unconfirmed_connections_num";s:6:"params";a:1:{i:0;s:20:"sys_profiles_friends";}s:5:"class";s:23:"TemplServiceConnections";}', '', 2147483646, 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:17:"is_enable_friends";}', 1, 0, @iNotifMenuOrder + 1),
+('sys_account_notifications', 'bx_persons', 'notifications-relation-requests', '_bx_persons_menu_item_title_system_relations', '_bx_persons_menu_item_title_relations', 'page.php?i=persons-profile-relations&profile_id={member_id}', '', '', 'sync col-blue3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:31:"get_unconfirmed_connections_num";s:6:"params";a:1:{i:0;s:22:"sys_profiles_relations";}s:5:"class";s:23:"TemplServiceConnections";}', '', 2147483646, 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:19:"is_enable_relations";}', 1, 0, @iNotifMenuOrder + 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`, `visibility_custom`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_persons', 'profile-stats-friend-requests', '_bx_persons_menu_item_title_system_friend_requests', '_bx_persons_menu_item_title_friend_requests', 'page.php?i=persons-profile-friends&profile_id={member_id}', '', '', 'users col-blue3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:31:"get_unconfirmed_connections_num";s:6:"params";a:1:{i:0;s:20:"sys_profiles_friends";}s:5:"class";s:23:"TemplServiceConnections";}', '', 2147483646, 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:17:"is_enable_friends";}', 0, 0, @iNotifMenuOrder + 1),
+('sys_profile_stats', 'bx_persons', 'profile-stats-manage-profiles', '_bx_persons_menu_item_title_system_manage_my_profiles', '_bx_persons_menu_item_title_manage_my_profiles', 'page.php?i=persons-manage', '', '_self', 'users col-blue3', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:41:"get_menu_addon_manage_tools_profile_stats";}', '', 2147483646, '', 1, 0, @iNotifMenuOrder + 2),
+('sys_profile_stats', 'bx_persons', 'profile-stats-favorite-persons', '_bx_persons_menu_item_title_system_favorites', '_bx_persons_menu_item_title_favorites', 'page.php?i=persons-profile-favorites&profile_id={member_id}', '', '', 'star col-blue3', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:38:"get_menu_addon_favorites_profile_stats";}', '', 2147483646, '', 1, 0, @iNotifMenuOrder + 3);
+
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `addon_cache`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_persons', 'profile-stats-subscriptions', '_bx_persons_menu_item_title_system_subscriptions', '_bx_persons_menu_item_title_subscriptions', 'page.php?i=persons-profile-subscriptions&profile_id={member_id}#subscriptions', '', '_self', 'rss col-blue3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_connected_content_num";s:6:"params";a:1:{i:0;s:26:"sys_profiles_subscriptions";}s:5:"class";s:23:"TemplServiceConnections";}', 0, '', 2147483646, '', 0, 0, @iNotifMenuOrder + 4),
+('sys_profile_stats', 'bx_persons', 'profile-stats-subscribed-me', '_bx_persons_menu_item_title_system_subscribed_me', '_bx_persons_menu_item_title_subscribed_me', 'page.php?i=persons-profile-subscriptions&profile_id={member_id}#subscribers', '', '_self', 'rss col-blue3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:28:"get_connected_initiators_num";s:6:"params";a:1:{i:0;s:26:"sys_profiles_subscriptions";}s:5:"class";s:23:"TemplServiceConnections";}', 1, '', 2147483646, '', 0, 0, @iNotifMenuOrder + 5);
+
+INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES
+('sys_profile_stats', 'bx_persons', 'profile-stats-relations', '_bx_persons_menu_item_title_system_relations', '_bx_persons_menu_item_title_relations', 'page.php?i=persons-profile-relations&profile_id={member_id}#relations', '', '_self', 'sync col-blue3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_connected_content_num";s:6:"params";a:3:{i:0;s:22:"sys_profiles_relations";i:1;i:0;i:2;i:1;}s:5:"class";s:23:"TemplServiceConnections";}', '', 2147483646, 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:19:"is_enable_relations";}', 1, 0, @iNotifMenuOrder + 6),
+('sys_profile_stats', 'bx_persons', 'profile-stats-related-me', '_bx_persons_menu_item_title_system_related_me', '_bx_persons_menu_item_title_related_me', 'page.php?i=persons-profile-relations&profile_id={member_id}#related-me', '', '_self', 'sync col-blue3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:28:"get_connected_initiators_num";s:6:"params";a:3:{i:0;s:22:"sys_profiles_relations";i:1;i:0;i:2;i:1;}s:5:"class";s:23:"TemplServiceConnections";}', '', 2147483646, 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:19:"is_enable_relations";}', 1, 0, @iNotifMenuOrder + 7);
+
+-- MENU: profile followings
+SET @iFollowingsMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_profile_followings' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `collapsed`, `active`, `copyable`, `order`) VALUES 
+('sys_profile_followings', 'bx_persons', 'persons', '_bx_persons_menu_item_title_system_followings', '_bx_persons_menu_item_title_followings', 'javascript:void(0)', '', '_self', 'users col-blue3', '', '', 2147483647, 0, 1, 0, @iFollowingsMenuOrder + 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_persons_menu_manage_tools', '_bx_persons_menu_title_manage_tools', 'bx_persons_menu_manage_tools', 'bx_persons', 6, 0, 1, 'BxPersonsMenuManageTools', 'modules/boonex/persons/classes/BxPersonsMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_persons_menu_manage_tools', 'bx_persons', '_bx_persons_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_persons_menu_manage_tools', 'bx_persons', 'clear-reports', '_bx_persons_menu_item_title_system_clear_reports', '_bx_persons_menu_item_title_clear_reports', 'javascript:void(0)', 'javascript:{js_object}.onClickClearReports({content_id});', '_self', 'eraser', '', 2147483647, 1, 0, 1),
+('bx_persons_menu_manage_tools', 'bx_persons', 'manage-cf', '_bx_persons_menu_item_title_system_manage_cf', '_bx_persons_menu_item_title_manage_cf', 'javascript:void(0)', 'javascript:{js_object}.onClickManageCf({content_id});', '_self', 'filter', '', 2147483647, 1, 0, 6),
+('bx_persons_menu_manage_tools', 'bx_persons', 'delete-with-content', '_bx_persons_menu_item_title_system_delete_with_content', '_bx_persons_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 2147483647, 1, 0, 99);
+
+-- 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_persons', 'persons-administration', '_bx_persons_menu_item_title_system_admt_persons', '_bx_persons_menu_item_title_admt_persons', 'page.php?i=persons-administration', '', '_self', 'user', 'a:2:{s:6:"module";s:10:"bx_persons";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
+
+
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_persons', 'create entry', NULL, '_bx_persons_acl_action_create_profile', '', 1, 1);
+SET @iIdActionProfileCreate = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_persons', 'delete entry', NULL, '_bx_persons_acl_action_delete_profile', '', 1, 1);
+SET @iIdActionProfileDelete = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_persons', 'view entry', NULL, '_bx_persons_acl_action_view_profile', '', 1, 0);
+SET @iIdActionProfileView = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_persons', 'change badge', NULL, '_bx_persons_acl_action_change_badge', '', 1, 3);
+SET @iIdActionChangeBadge = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_persons', 'edit any entry', NULL, '_bx_persons_acl_action_edit_any_profile', '', 1, 3);
+SET @iIdActionProfileEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_persons', 'delete any entry', NULL, '_bx_persons_acl_action_delete_any_profile', '', 1, 3);
+SET @iIdActionProfileDeleteAny = 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
+
+-- profile create
+(@iAccount, @iIdActionProfileCreate),
+(@iStandard, @iIdActionProfileCreate),
+(@iUnconfirmed, @iIdActionProfileCreate),
+(@iPending, @iIdActionProfileCreate),
+(@iModerator, @iIdActionProfileCreate),
+(@iAdministrator, @iIdActionProfileCreate),
+(@iPremium, @iIdActionProfileCreate),
+
+-- profile delete
+(@iAccount, @iIdActionProfileDelete),
+(@iStandard, @iIdActionProfileDelete),
+(@iUnconfirmed, @iIdActionProfileDelete),
+(@iPending, @iIdActionProfileDelete),
+(@iModerator, @iIdActionProfileDelete),
+(@iAdministrator, @iIdActionProfileDelete),
+(@iPremium, @iIdActionProfileDelete),
+
+-- profile view
+(@iUnauthenticated, @iIdActionProfileView),
+(@iAccount, @iIdActionProfileView),
+(@iStandard, @iIdActionProfileView),
+(@iUnconfirmed, @iIdActionProfileView),
+(@iPending, @iIdActionProfileView),
+(@iModerator, @iIdActionProfileView),
+(@iAdministrator, @iIdActionProfileView),
+(@iPremium, @iIdActionProfileView),
+
+-- set profile badge
+(@iModerator, @iIdActionChangeBadge),
+(@iAdministrator, @iIdActionChangeBadge),
+(@iPremium, @iIdActionChangeBadge),
+
+-- any profile edit
+(@iModerator, @iIdActionProfileEditAny),
+(@iAdministrator, @iIdActionProfileEditAny),
+
+-- any profile delete
+(@iAdministrator, @iIdActionProfileDeleteAny);
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_persons', 'bx_persons', 'bx_persons_meta_keywords', 'bx_persons_meta_locations', 'bx_persons_meta_mentions', '', '');
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_persons', '_bx_persons', @iSearchOrder + 1, 'BxPersonsSearchResult', 'modules/boonex/persons/classes/BxPersonsSearchResult.php'),
+('bx_persons_cmts', '_bx_persons_cmts', @iSearchOrder + 2, 'BxPersonsCmtsSearchResult', 'modules/boonex/persons/classes/BxPersonsCmtsSearchResult.php');
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_persons', 'bx_persons', '_bx_persons', 'page.php?i=persons-home', 'user col-blue3', 'SELECT COUNT(*) FROM `bx_persons_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_persons'' WHERE 1 AND `tp`.`status`=''active''', @iMaxOrderStats + 1);
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_persons_growth', '_bx_persons_chart_growth', 'bx_persons_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_persons'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_persons_growth_speed', '_bx_persons_chart_growth_speed', 'bx_persons_data', 'added', '', '', 'SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} LEFT JOIN `sys_profiles` AS `tp` ON {table}.`id` = `tp`.`content_id` AND `tp`.`type`=''bx_persons'' WHERE 1 AND `tp`.`status`=''active'' {where_inteval} GROUP BY `period` ORDER BY {table}.{field_date} ASC', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+-- GRIDS: administration
+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`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_persons_administration', 'Sql', 'SELECT `td`.*, `ta`.`email` AS `account`, `ta`.`logged` AS `last_online`, `tp`.`status` AS `status`, `tp`.`id` as `profile_id` FROM `bx_persons_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_persons'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_persons_data', 'id', 'last_online', 'status', '', 20, NULL, 'start', '', 'fullname,email', '', 'like', 'reports', '', 192, 'BxPersonsGridAdministration', 'modules/boonex/persons/classes/BxPersonsGridAdministration.php'),
+('bx_persons_common', 'Sql', 'SELECT `td`.*, `ta`.`email` AS `account`, `ta`.`logged` AS `last_online`, `tp`.`status` AS `status` FROM `bx_persons_data` AS `td` LEFT JOIN `sys_profiles` AS `tp` ON `td`.`id`=`tp`.`content_id` AND `tp`.`type`=''bx_persons'' LEFT JOIN `sys_accounts` AS `ta` ON `tp`.`account_id`=`ta`.`id` WHERE 1 ', 'bx_persons_data', 'id', 'last_online', 'status', '', 20, NULL, 'start', '', 'fullname', '', 'like', '', '', 2147483647, 'BxPersonsGridCommon', 'modules/boonex/persons/classes/BxPersonsGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_persons_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_persons_administration', 'switcher', '_bx_persons_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_persons_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_persons_administration', 'fullname', '_bx_persons_grid_column_title_adm_fullname', '25%', 0, '', '', 4),
+('bx_persons_administration', 'last_online', '_bx_persons_grid_column_title_adm_last_online', '20%', 1, '25', '', 5),
+('bx_persons_administration', 'account', '_bx_persons_grid_column_title_adm_account', '20%', 0, '25', '', 6),
+('bx_persons_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_persons_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_persons_common', 'fullname', '_bx_persons_grid_column_title_adm_fullname', '48%', 0, '', '', 2),
+('bx_persons_common', 'last_online', '_bx_persons_grid_column_title_adm_last_online', '30%', 1, '25', '', 3),
+('bx_persons_common', 'actions', '', '20%', 0, '', '', 4);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_persons_administration', 'bulk', 'set_acl_level', '_bx_persons_grid_action_title_adm_set_acl_level', '', 0, 0, 1),
+('bx_persons_administration', 'bulk', 'delete_with_content', '_bx_persons_grid_action_title_adm_delete_with_content', '', 0, 1, 2),
+('bx_persons_administration', 'bulk', 'clear_reports', '_bx_persons_grid_action_title_adm_clear_reports', '', 0, 1, 3),
+('bx_persons_administration', 'single', 'set_acl_level', '_bx_persons_grid_action_title_adm_set_acl_level', 'certificate', 1, 0, 1),
+('bx_persons_administration', 'single', 'settings', '_bx_persons_grid_action_title_adm_more_actions', 'cog', 1, 0, 2),
+('bx_persons_administration', 'single', 'audit_content', '_bx_persons_grid_action_title_adm_audit_content', 'search', 1, 0, 3),
+('bx_persons_administration', 'single', 'audit_profile', '_bx_persons_grid_action_title_adm_audit_profile', 'search-location', 1, 0, 4),
+
+('bx_persons_common', 'bulk', 'delete_with_content', '_bx_persons_grid_action_title_adm_delete_with_content', '', 0, 1, 1),
+('bx_persons_common', 'single', 'settings', '_bx_persons_grid_action_title_adm_more_actions', 'cog', 1, 0, 1);
+
+-- LIVE UPDATES
+INSERT INTO `sys_objects_live_updates`(`name`, `frequency`, `service_call`, `active`) VALUES
+('bx_persons_friend_requests', 1, 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:40:"get_live_updates_unconfirmed_connections";s:6:"params";a:5:{i:0;s:10:"bx_persons";i:1;s:20:"sys_profiles_friends";i:2;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:7:"account";}i:3;a:2:{s:11:"menu_object";s:25:"sys_account_notifications";s:9:"menu_item";s:29:"notifications-friend-requests";}i:4;s:7:"{count}";}s:5:"class";s:23:"TemplServiceConnections";}', 1),
+('bx_persons_friend_requests_new', 1, 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:44:"get_live_updates_unconfirmed_connections_new";s:6:"params";a:5:{i:0;s:10:"bx_persons";i:1;s:20:"sys_profiles_friends";i:2;a:0:{}i:3;a:0:{}i:4;s:7:"{count}";}s:5:"class";s:23:"TemplServiceConnections";}', 1);
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_persons', 'BxPersonsAlertsResponse', 'modules/boonex/persons/classes/BxPersonsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('sys_profiles_friends', 'connection_added', @iHandler),
+('bx_timeline', 'post_common', @iHandler),
+('bx_persons_pictures', 'file_deleted', @iHandler),
+('bx_persons', 'timeline_view', @iHandler),
+('bx_persons', 'timeline_post', @iHandler),
+('bx_persons', 'timeline_delete', @iHandler),
+('bx_persons', 'timeline_comment', @iHandler),
+('bx_persons', 'timeline_vote', @iHandler),
+('bx_persons', 'timeline_score', @iHandler),
+('bx_persons', 'timeline_report', @iHandler),
+('bx_persons', 'timeline_repost', @iHandler),
+('bx_persons', 'timeline_pin', @iHandler),
+('bx_persons', 'timeline_promote', @iHandler);
+
+-- PRIVACY 
+INSERT INTO `sys_objects_privacy` (`object`, `module`, `action`, `title`, `default_group`, `spaces`, `table`, `table_field_id`, `table_field_author`, `override_class_name`, `override_class_file`) VALUES
+('bx_persons_allow_view_to', 'bx_persons', 'view', '_bx_persons_form_profile_input_allow_view_to', '3', '', 'bx_persons_data', 'id', 'author', 'BxPersonsPrivacy', 'modules/boonex/persons/classes/BxPersonsPrivacy.php'),
+('bx_persons_allow_post_to', 'bx_persons', 'post', '_bx_persons_form_profile_input_allow_post_to', '5', '', 'bx_persons_data', 'id', 'author', 'BxPersonsPrivacyPost', 'modules/boonex/persons/classes/BxPersonsPrivacyPost.php'),
+('bx_persons_allow_contact_to', 'bx_persons', 'contact', '_bx_persons_form_profile_input_allow_contact_to', '3', '', 'bx_persons_data', 'id', 'author', 'BxPersonsPrivacyContact', 'modules/boonex/persons/classes/BxPersonsPrivacyContact.php');
+
+-- EMAIL TEMPLATES
+INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `Body`) VALUES
+('bx_persons', '_bx_persons_email_friend_request', 'bx_persons_friend_request', '_bx_persons_email_friend_request_subject', '_bx_persons_email_friend_request_body');
+
+-- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_persons_cover_crop', 1, 'BxPersonsUploaderCoverCrop', 'modules/boonex/persons/classes/BxPersonsUploaderCoverCrop.php'),
+('bx_persons_picture_crop', 1, 'BxPersonsUploaderPictureCrop', 'modules/boonex/persons/classes/BxPersonsUploaderPictureCrop.php'),
+('bx_persons_badge_crop', 1, 'BxPersonsUploaderBadgeCrop', 'modules/boonex/persons/classes/BxPersonsUploaderBadgeCrop.php');

+ 464 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/install.sql

@@ -0,0 +1,464 @@
+
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+-- TABLE: PROFILES
+CREATE TABLE IF NOT EXISTS `bx_persons_data` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(10) unsigned NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `picture` int(11) NOT NULL,
+  `cover` int(11) NOT NULL,
+  `cover_data` varchar(50) NOT NULL,
+  `badge` int(11) NOT NULL default '0',
+  `badge_link` varchar(255) NOT NULL default '',
+  `fullname` varchar(255) NOT NULL,
+  `last_name` varchar(255) NOT NULL,
+  `description` text NOT NULL,
+  `gender` varchar(255) DEFAULT NULL,
+  `birthday` date DEFAULT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` int(11) NOT NULL default '0',
+  `score` int(11) NOT NULL default '0',
+  `sc_up` int(11) NOT NULL default '0',
+  `sc_down` int(11) NOT NULL default '0',
+  `favorites` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `allow_view_to` varchar(16) NOT NULL DEFAULT '3',
+  `allow_post_to` varchar(16) NOT NULL DEFAULT '5',
+  `allow_contact_to` varchar(16) NOT NULL DEFAULT '3',
+  `settings` text NOT NULL,
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `search_fields` (`fullname`,`description`)
+);
+
+-- TABLE: STORAGES & TRANSCODERS
+CREATE TABLE IF NOT EXISTS `bx_persons_pictures` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) NOT NULL,
+  `dimensions` varchar(12) 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_persons_pictures_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_persons_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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  `cmt_cf` int(11) NOT NULL default '1',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_cmts_notes` (
+  `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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+-- TABLE: VIEWS
+CREATE TABLE IF NOT EXISTS `bx_persons_views_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `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',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: VOTES
+CREATE TABLE IF NOT EXISTS `bx_persons_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: favorites
+CREATE TABLE IF NOT EXISTS `bx_persons_favorites_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_persons_reports` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_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',
+  `checked_by` int(11) NOT NULL default '0',
+  `status` tinyint(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE IF NOT EXISTS `bx_persons_meta_keywords` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_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,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+);
+
+CREATE TABLE `bx_persons_meta_mentions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_persons_scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_persons_scores_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(8) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+CREATE TABLE `bx_persons_skills` (
+  `skill_id` int(11) NOT NULL AUTO_INCREMENT,
+  `skill_name` varchar(500) DEFAULT NULL,
+  `content_id` int(11) NOT NULL,
+  PRIMARY KEY (`skill_id`),
+  KEY `content_id` (`content_id`)
+);
+
+
+-- 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_persons_pictures', @sStorageEngine, '', 360, 2592000, 3, 'bx_persons_pictures', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+('bx_persons_pictures_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_persons_pictures_resized', 'allow-deny', '{image}', '', 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_persons_icon', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_thumb', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_avatar', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_avatar_big', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_picture', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_cover', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_cover_thumb', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_gallery', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0'),
+('bx_persons_badge', 'bx_persons_pictures_resized', 'Storage', 'a:1:{s:6:"object";s:19:"bx_persons_pictures";}', 'no', '1', '2592000', '0');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_persons_icon', 'Resize', 'a:3:{s:1:"w";s:2:"30";s:1:"h";s:2:"30";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_persons_thumb', 'Resize', 'a:3:{s:1:"w";s:2:"50";s:1:"h";s:2:"50";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_persons_avatar', 'Resize', 'a:3:{s:1:"w";s:3:"100";s:1:"h";s:3:"100";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_persons_avatar_big', 'Resize', 'a:3:{s:1:"w";s:3:"200";s:1:"h";s:3:"200";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_persons_picture', 'Resize', 'a:3:{s:1:"w";s:4:"1024";s:1:"h";s:4:"1024";s:13:"square_resize";s:1:"0";}', '0'),
+('bx_persons_cover', 'Resize', 'a:2:{s:1:"w";s:3:"960";s:1:"h";s:3:"480";}', '0'),
+('bx_persons_cover_thumb', 'Resize', 'a:3:{s:1:"w";s:2:"48";s:1:"h";s:2:"48";s:13:"square_resize";s:1:"1";}', '0'),
+('bx_persons_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0'),
+('bx_persons_badge', 'Resize', 'a:3:{s:1:"w";s:2:"32";s:1:"h";s:2:"32";s:13:"square_resize";s:1:"1";}', '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`, `parent_form`) VALUES 
+('bx_person', 'bx_persons', '_bx_persons_form_profile', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_persons_data', 'id', '', '', 'do_submit', '', 0, 1, 'BxPersonsFormEntry', 'modules/boonex/persons/classes/BxPersonsFormEntry.php', ''),
+('bx_person_skills', 'bx_persons', '_bx_persons_skills_form_profile', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_persons_skills', 'skill_id', '', '', 'do_submit', '', 0, 1, 'BxDolFormNested', 'inc/classes/BxDolFormNested.php', 'bx_person');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_person', 'bx_person_add', 'bx_persons', 0, '_bx_persons_form_profile_display_add'),
+('bx_person', 'bx_person_delete', 'bx_persons', 0, '_bx_persons_form_profile_display_delete'),
+('bx_person', 'bx_person_edit', 'bx_persons', 0, '_bx_persons_form_profile_display_edit'),
+('bx_person', 'bx_person_edit_cover', 'bx_persons', 0, '_bx_persons_form_profile_display_edit_cover'),
+('bx_person', 'bx_person_edit_badge', 'bx_persons', 0, '_bx_persons_form_profile_display_edit_badge'),
+('bx_person', 'bx_person_view', 'bx_persons', 1, '_bx_persons_form_profile_display_view'),
+('bx_person', 'bx_person_view_full', 'bx_persons', 1, '_bx_persons_form_profile_display_view_full'),
+
+('bx_person_skills', 'bx_person_skills', 'bx_persons', 0, '_bx_persons_skills_form_profile_display_add'),
+('bx_person_skills', 'bx_person_skills_view', 'bx_persons', 1, '_bx_persons_skills_form_profile_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`, `rateable`) VALUES 
+('bx_person', 'bx_persons', 'allow_view_to', 3, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_view_to', '_bx_persons_form_profile_input_allow_view_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'allow_post_to', 5, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_post_to', '_bx_persons_form_profile_input_allow_post_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'allow_contact_to', 3, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_contact_to', '_bx_persons_form_profile_input_allow_contact_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_persons_form_profile_input_sys_delete_confirm', '_bx_persons_form_profile_input_delete_confirm', '_bx_persons_form_profile_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_persons_form_profile_input_delete_confirm_error', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'do_submit', '_bx_persons_form_profile_input_submit', '', 0, 'submit', '_bx_persons_form_profile_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'description', '', '', 0, 'textarea', '_bx_persons_form_profile_input_sys_desc', '_bx_persons_form_profile_input_desc', '', 0, 0, 1, '', '', '', '', '', '', 'XssHtml', '', 1, 1, ''),
+('bx_person', 'bx_persons', 'fullname', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_fullname', '_bx_persons_form_profile_input_fullname', '', 1, 0, 0, '', '', '', 'ProfileName', '', '_bx_persons_form_profile_input_fullname_err', 'Xss', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'last_name', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_last_name', '_bx_persons_form_profile_input_last_name', '', 1, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'cover', 'a:1:{i:0;s:21:"bx_persons_cover_crop";}', 'a:1:{s:21:"bx_persons_cover_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_cover', '_bx_persons_form_profile_input_cover', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'picture', 'a:1:{i:0;s:23:"bx_persons_picture_crop";}', 'a:1:{s:23:"bx_persons_picture_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_picture', '_bx_persons_form_profile_input_picture', '', 0, 0, 0, '', '', '', '', '', '_bx_persons_form_profile_input_picture_err', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'badge', 'a:1:{i:0;s:21:"bx_persons_badge_crop";}', 'a:1:{s:21:"bx_persons_badge_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_badge', '_bx_persons_form_profile_input_badge', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'badge_link', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_badge_link', '_bx_persons_form_profile_input_badge_link', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'birthday', '0', '', 0, 'datepicker', '_bx_persons_form_profile_input_sys_birthday', '_bx_persons_form_profile_input_birthday', '', 1, 0, 0, '', '', '', 'date_range', 'a:3:{s:3:"min";i:18;s:3:"max";i:99;s:8:"required";b:0;}', '_bx_persons_form_profile_input_birthday_err', 'Date', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'gender', '', '#!Sex', 0, 'select', '_bx_persons_form_profile_input_sys_gender', '_bx_persons_form_profile_input_gender', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'profile_email', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_email', '_bx_persons_form_profile_input_profile_email', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'profile_status', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_status', '_bx_persons_form_profile_input_profile_status', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'profile_ip', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_ip', '_bx_persons_form_profile_input_profile_ip', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'profile_last_active', '', '', 0, 'datetime', '_bx_persons_form_profile_input_sys_profile_last_active', '_bx_persons_form_profile_input_profile_last_active', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'skills', 'bx_person_skills', '', 0, 'nested_form', '_bx_persons_form_profile_input_sys_skills', '_bx_persons_form_profile_input_skills', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, 'sys_form_fields_votes'),
+('bx_person', 'bx_persons', 'added', '', '', 0, 'datetime', '_bx_persons_form_profile_input_sys_date_added', '_bx_persons_form_profile_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'changed', '', '', 0, 'datetime', '_bx_persons_form_profile_input_sys_date_changed', '_bx_persons_form_profile_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'friends_count', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_friends_count', '_bx_persons_form_profile_input_friends_count', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'followers_count', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_followers_count', '_bx_persons_form_profile_input_followers_count', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+
+('bx_person_skills', 'bx_persons', 'skill_name', '', '', 0, 'text', '_bx_persons_skills_form_profile_input_sys_skill_name', '_bx_persons_skills_form_profile_input_skill_name', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_persons_skills_form_profile_input_skill_name_err', 'Xss', '', 1, 0, '');
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_person_add', 'picture', 2147483647, 1, 1),
+('bx_person_add', 'gender', 2147483647, 1, 2),
+('bx_person_add', 'birthday', 2147483647, 1, 3),
+('bx_person_add', 'fullname', 2147483647, 1, 4),
+('bx_person_add', 'last_name', 2147483647, 0, 5),
+('bx_person_add', 'description', 2147483647, 1, 6),
+('bx_person_add', 'location', 2147483647, 1, 7),
+('bx_person_add', 'allow_view_to', 2147483647, 1, 8),
+('bx_person_add', 'allow_post_to', 2147483647, 1, 9),
+('bx_person_add', 'allow_contact_to', 2147483647, 1, 10),
+('bx_person_add', 'do_submit', 2147483647, 1, 11),
+
+('bx_person_delete', 'cover', 2147483647, 0, 0),
+('bx_person_delete', 'picture', 2147483647, 0, 0),
+('bx_person_delete', 'delete_confirm', 2147483647, 1, 0),
+('bx_person_delete', 'do_submit', 2147483647, 1, 1),
+('bx_person_delete', 'fullname', 2147483647, 0, 2),
+
+('bx_person_edit', 'picture', 2147483647, 1, 1),
+('bx_person_edit', 'gender', 2147483647, 1, 2),
+('bx_person_edit', 'birthday', 2147483647, 1, 3),
+('bx_person_edit', 'fullname', 2147483647, 1, 4),
+('bx_person_edit', 'last_name', 2147483647, 0, 5),
+('bx_person_edit', 'description', 2147483647, 1, 6),
+('bx_person_edit', 'location', 2147483647, 1, 7),
+('bx_person_edit', 'allow_view_to', 2147483647, 1, 8),
+('bx_person_edit', 'allow_post_to', 2147483647, 1, 9),
+('bx_person_edit', 'allow_contact_to', 2147483647, 1, 10),
+('bx_person_edit', 'controls', 2147483647, 1, 11),
+('bx_person_edit', 'do_submit', 2147483647, 1, 12),
+('bx_person_edit', 'do_cancel', 2147483647, 1, 13),
+
+('bx_person_edit_cover', 'delete_confirm', 2147483647, 0, 1),
+('bx_person_edit_cover', 'fullname', 2147483647, 0, 2),
+('bx_person_edit_cover', 'picture', 2147483647, 0, 3),
+('bx_person_edit_cover', 'cover', 2147483647, 1, 7),
+('bx_person_edit_cover', 'do_submit', 2147483647, 1, 8),
+
+('bx_person_edit_badge', 'badge', 2147483647, 1, 1),
+('bx_person_edit_badge', 'badge_link', 2147483647, 1, 2),
+('bx_person_edit_badge', 'do_submit', 2147483647, 1, 3),
+
+('bx_person_view', 'gender', 2147483647, 1, 1),
+('bx_person_view', 'birthday', 2147483647, 1, 2),
+('bx_person_view', 'fullname', 2147483647, 1, 3),
+('bx_person_view', 'last_name', 2147483647, 0, 4),
+('bx_person_view', 'profile_email', 192, 1, 5),
+('bx_person_view', 'profile_status', 192, 1, 6),
+('bx_person_view', 'profile_ip', 192, 1, 7),
+('bx_person_view', 'profile_last_active', 192, 1, 8),
+('bx_person_view', 'added', 192, 1, 9),
+('bx_person_view', 'changed', 192, 1, 10),
+('bx_person_view', 'friends_count', 2147483647, 1, 11),
+('bx_person_view', 'followers_count', 2147483647, 1, 12),
+
+('bx_person_view_full', 'gender', 2147483647, 1, 1),
+('bx_person_view_full', 'birthday', 2147483647, 1, 2),
+('bx_person_view_full', 'fullname', 2147483647, 1, 3),
+('bx_person_view_full', 'last_name', 2147483647, 0, 4),
+('bx_person_view_full', 'description', 2147483647, 0, 5),
+('bx_person_view_full', 'profile_email', 192, 1, 6),
+('bx_person_view_full', 'profile_status', 192, 1, 7),
+('bx_person_view_full', 'profile_last_active', 192, 1, 8),
+
+('bx_person_skills', 'skill_name', 2147483647, 1, 1),
+('bx_person_skills_view', 'skill_name', 2147483647, 1, 1);
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_persons', 'bx_persons', 'bx_persons_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-persons-profile&id={object_id}', '', 'bx_persons_data', 'id', 'author', 'fullname', 'comments', 'BxPersonsCmts', 'modules/boonex/persons/classes/BxPersonsCmts.php'),
+('bx_persons_notes', 'bx_persons', 'bx_persons_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_persons_data', 'id', 'author', 'fullname', '', 'BxTemplCmtsNotes', '');
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_persons', 'bx_persons', 'bx_persons_views_track', '86400', '1', 'bx_persons_data', 'id', 'author', 'views', '', '');
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_persons', 'bx_persons', 'bx_persons_votes', 'bx_persons_votes_track', '604800', '1', '1', '0', '1', 'bx_persons_data', 'id', '', 'rate', 'votes', 'BxPersonsVote', 'modules/boonex/persons/classes/BxPersonsVote.php'),
+('bx_persons_reactions', 'bx_persons', 'bx_persons_reactions', 'bx_persons_reactions_track', '604800', '1', '1', '1', '1', 'bx_persons_data', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', '');
+
+-- SCORES
+INSERT INTO `sys_objects_score` (`name`, `module`, `table_main`, `table_track`, `post_timeout`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_score`, `trigger_field_cup`, `trigger_field_cdown`, `class_name`, `class_file`) VALUES 
+('bx_persons', 'bx_persons', 'bx_persons_scores', 'bx_persons_scores_track', '604800', '1', 'bx_persons_data', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
+-- FAFORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `is_on`, `is_undo`, `is_public`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_persons', 'bx_persons_favorites_track', '1', '1', '0', 'page.php?i=view-persons-profile&id={object_id}', 'bx_persons_data', 'id', 'author', 'favorites', 'BxPersonsFavorite', 'modules/boonex/persons/classes/BxPersonsFavorite.php');
+
+-- FEATURED
+INSERT INTO `sys_objects_feature` (`name`, `module`, `is_on`, `is_undo`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_flag`, `class_name`, `class_file`) VALUES 
+('bx_persons', 'bx_persons', '1', '1', 'page.php?i=view-persons-profile&id={object_id}', 'bx_persons_data', 'id', 'author', 'featured', '', '');
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `module`, `table_main`, `table_track`, `is_on`, `base_url`, `object_comment`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_persons', 'bx_persons', 'bx_persons_reports', 'bx_persons_reports_track', '1', 'page.php?i=view-persons-profile&id={object_id}', 'bx_persons_notes', 'bx_persons_data', 'id', 'author', 'reports', 'BxPersonsReport', 'modules/boonex/persons/classes/BxPersonsReport.php');
+
+-- CONTENT INFO
+INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_action_add`, `alert_action_update`, `alert_action_delete`, `class_name`, `class_file`) VALUES
+('bx_persons', '_bx_persons', 'bx_persons', 'added', 'edited', 'deleted', '', ''),
+('bx_persons_cmts', '_bx_persons_cmts', 'bx_persons', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_persons', 'bx_persons_administration', 'td`.`id', '', ''),
+('bx_persons', 'bx_persons_common', 'td`.`id', '', '');
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_persons', 'bx_persons', 'bx_persons', '_bx_persons_search_extended', 1, '', ''),
+('bx_persons_cmts', 'bx_persons_cmts', 'bx_persons', '_bx_persons_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+-- STUDIO PAGE & WIDGET
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_persons', '_bx_persons', '_bx_persons', 'bx_persons@modules/boonex/persons/|std-icon.svg');
+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`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_persons', 'users', '{url_studio}module.php?name=bx_persons', '', 'bx_persons@modules/boonex/persons/|std-icon.svg', '_bx_persons', '', '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));
+

+ 56 - 0
modules/boonex/persons/updates/14.0.6_15.0.0/source/install/sql/uninstall.sql

@@ -0,0 +1,56 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_persons_data`,`bx_persons_pictures`, `bx_persons_pictures_resized`, `bx_persons_cmts`, `bx_persons_cmts_notes`, `bx_persons_views_track`, `bx_persons_votes`, `bx_persons_votes_track`, `bx_persons_reactions`, `bx_persons_reactions_track`, `bx_persons_favorites_track`, `bx_persons_reports`, `bx_persons_reports_track`, `bx_persons_meta_keywords`, `bx_persons_meta_locations`, `bx_persons_meta_mentions`, `bx_persons_scores`, `bx_persons_scores_track`, `bx_persons_skills`;
+
+-- PROFILES
+DELETE FROM sys_profiles WHERE `type` = 'bx_persons';
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_storage` WHERE `object` IN('bx_persons_pictures', 'bx_persons_pictures_resized');
+DELETE FROM `sys_storage_tokens` WHERE `object` IN('bx_persons_pictures', 'bx_persons_pictures_resized');
+
+DELETE FROM `sys_objects_transcoder` WHERE `object` IN('bx_persons_icon', 'bx_persons_thumb', 'bx_persons_avatar', 'bx_persons_avatar_big', 'bx_persons_picture', 'bx_persons_cover', 'bx_persons_cover_thumb', 'bx_persons_gallery', 'bx_persons_badge');
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` IN('bx_persons_icon', 'bx_persons_thumb', 'bx_persons_avatar', 'bx_persons_avatar_big', 'bx_persons_picture', 'bx_persons_cover', 'bx_persons_cover_thumb', 'bx_persons_gallery', 'bx_persons_badge');
+DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` IN('bx_persons_icon', 'bx_persons_thumb', 'bx_persons_avatar', 'bx_persons_avatar_big', 'bx_persons_picture', 'bx_persons_cover', 'bx_persons_cover_thumb', 'bx_persons_gallery', 'bx_persons_badge');
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_persons';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_persons';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_persons';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN('bx_person_add', 'bx_person_delete', 'bx_person_edit', 'bx_person_edit_cover', 'bx_person_edit_badge', 'bx_person_view', 'bx_person_view_full', 'bx_person_skills', 'bx_person_skills_view');
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` LIKE 'bx_persons%';
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name` = 'bx_persons';
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` IN ('bx_persons', 'bx_persons_reactions');
+
+-- SCORES
+DELETE FROM `sys_objects_score` WHERE `name` = 'bx_persons';
+
+-- FAFORITES
+DELETE FROM `sys_objects_favorite` WHERE `name` = 'bx_persons';
+
+-- FEATURED
+DELETE FROM `sys_objects_feature` WHERE `name` = 'bx_persons';
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `name` = 'bx_persons';
+
+-- CONTENT INFO
+DELETE FROM `sys_objects_content_info` WHERE `name` IN ('bx_persons', 'bx_persons_cmts');
+
+DELETE FROM `sys_content_info_grids` WHERE `object` IN ('bx_persons');
+
+
+-- SEARCH EXTENDED
+DELETE FROM `sys_objects_search_extended` WHERE `module` = 'bx_persons';
+
+
+-- STUDIO PAGE & WIDGET
+DELETE FROM `tp`, `tw`, `twb`, `tpw` 
+USING `sys_std_pages` AS `tp` LEFT JOIN `sys_std_widgets` AS `tw` ON `tp`.`id` = `tw`.`page_id` LEFT JOIN `sys_std_widgets_bookmarks` AS `twb` ON `tw`.`id` = `twb`.`widget_id` LEFT JOIN `sys_std_pages_widgets` AS `tpw` ON `tw`.`id` = `tpw`.`widget_id`
+WHERE  `tp`.`name` = 'bx_persons';

+ 51 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Photos',
+    'version_from' => '14.0.2',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/photos/updates/update_14.0.2_15.0.0/',
+    'home_uri' => 'photos_update_1402_1500',
+
+    'module_dir' => 'boonex/photos/',
+    'module_uri' => 'photos',
+
+    'db_prefix' => 'bx_photos_',
+    'class_prefix' => 'BxPhotos',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Photos',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPhotosUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/install/sql/enable.sql

@@ -0,0 +1,4 @@
+-- MENUS
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_photos_view_actions' AND `name`='set-badges';
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_photos_view_actions', 'bx_photos', 'set-badges', '_sys_menu_item_title_system_set_badges', '_sys_menu_item_title_set_badges', 'javascript:void(0)', 'bx_menu_popup(''sys_set_badges'', window, {}, {module: ''bx_photos'', content_id: {content_id}});', '', 'check-circle', '', '', 0, 2147483647, 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 40);

+ 12 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/install/sql/install.sql

@@ -0,0 +1,12 @@
+-- FORMS
+DELETE FROM `sys_form_inputs` WHERE `object`='bx_photos' AND `name` IN ('do_cancel', 'controls');
+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_photos', 'bx_photos', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_photos', 'bx_photos', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name`='bx_photos_entry_edit' AND `input_name` IN ('controls', 'do_submit', 'do_cancel');
+SET @iOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_form_display_inputs` WHERE `display_name`='bx_photos_entry_edit');
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_photos_entry_edit', 'controls', 2147483647, 1, @iOrder+1),
+('bx_photos_entry_edit', 'do_submit', 2147483647, 1, @iOrder+2),
+('bx_photos_entry_edit', 'do_cancel', 2147483647, 1, @iOrder+3);

+ 213 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/classes/BxPhotosConfig.php

@@ -0,0 +1,213 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Photos Photos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPhotosConfig extends BxBaseModTextConfig
+{
+    protected $_aHtmlIds;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'approve' => 'checkAllowedApprove',
+            'edit-photo' => 'checkAllowedEdit',
+            'delete-photo' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'camera-retro col-blue1',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'entries',
+            'TABLE_ENTRIES_FULLTEXT' => 'title_text',
+            'TABLE_FILES' => $aModule['db_prefix'] . 'photos',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_TITLE' => 'title',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'photo-text',
+            'FIELD_CATEGORY' => 'cat',
+            'FIELD_DURATION' => 'duration',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_FOR_STORING_FILE_ID' => 'thumb',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELD_LABELS' => 'labels',
+            'FIELD_LOCATION' => 'location',
+            'FIELD_EXIF' => 'exif',
+            '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
+			
+            // some params
+            'PARAM_PER_PAGE_FOR_FAVORITES_LISTS' => 'bx_photos_per_page_for_favorites_lists',
+            
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-photo',
+            'URI_AUTHOR_ENTRIES' => 'photos-author',
+            'URI_ENTRIES_BY_CONTEXT' => 'photos-context',
+            'URI_ADD_ENTRY' => 'create-photo',
+            'URI_EDIT_ENTRY' => 'edit-photo',
+            'URI_MANAGE_COMMON' => 'photos-manage',
+            'URI_FAVORITES_LIST' => 'photos-favorites',
+
+            'URL_HOME' => 'page.php?i=photos-home',
+            'URL_POPULAR' => 'page.php?i=photos-popular',
+            'URL_TOP' => 'page.php?i=photos-top',
+            'URL_UPDATED' => 'page.php?i=photos-updated',
+            'URL_MANAGE_COMMON' => 'page.php?i=photos-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=photos-administration',
+
+            // some params
+            'PARAM_AUTO_APPROVE' => 'bx_photos_enable_auto_approve',
+            'PARAM_CHARS_SUMMARY' => 'bx_photos_summary_chars',
+            'PARAM_CHARS_SUMMARY_PLAIN' => 'bx_photos_plain_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_photos_rss_num',
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_photos_searchable_fields',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_photos_photos',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_photos_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_photos_gallery',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_photos_cover',
+            'OBJECT_REPORTS' => 'bx_photos',
+            'OBJECT_VIEWS' => 'bx_photos',
+            'OBJECT_VOTES' => 'bx_photos',
+            'OBJECT_VOTES_STARS' => 'bx_photos_stars',
+            'OBJECT_REACTIONS' => 'bx_photos_reactions',
+            'OBJECT_SCORES' => 'bx_photos',
+            'OBJECT_FAVORITES' => 'bx_photos',
+            'OBJECT_FEATURED' => 'bx_photos',
+            'OBJECT_METATAGS' => 'bx_photos',
+            'OBJECT_METATAGS_MEDIA_CAMERA' => 'bx_photos_camera',
+            'OBJECT_COMMENTS' => 'bx_photos',
+            'OBJECT_NOTES' => 'bx_photos_notes',
+            'OBJECT_CATEGORY' => 'bx_photos_cats',
+            'OBJECT_PRIVACY_VIEW' => 'bx_photos_allow_view_to',
+            'OBJECT_PRIVACY_LIST_VIEW' => 'bx_photos_allow_view_favorite_list',
+            'OBJECT_FORM_ENTRY' => 'bx_photos',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_photos_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_photos_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_photos_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_photos_entry_delete',
+            'OBJECT_PAGE_VIEW_ENTRY_BRIEF' => 'bx_photos_view_entry_brief', // brief view page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_photos_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_photos_view_actions', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_photos_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_photos_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_photos_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'photos-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_SNIPPET_META' => 'bx_photos_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_photos_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_photos_administration',
+            'OBJECT_GRID_COMMON' => 'bx_photos_common',
+            'OBJECT_UPLOADERS' => array('sys_html5'),
+            
+            'FUNCTION_FOR_GET_ITEM_INFO' => 'getContentInfoById',
+
+            'BADGES_AVALIABLE' => true,
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_photos_my' => array (
+                    'create-photo' => 'checkAllowedAdd',
+                ),
+                'bx_photos_view' => $aMenuItems2Methods,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'approving' => array (
+                    'name' => 'bx-photos-approving',
+                    'map' => array (
+                        'pending' => array('msg' => '_bx_photos_txt_msg_status_pending', 'type' => BX_INFORMER_ALERT),
+                        'hidden' => array('msg' => '_bx_photos_txt_msg_status_hidden', 'type' => BX_INFORMER_ERROR),
+                    ),
+                ),
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_photos_txt_sample_single',
+            	'txt_sample_single_with_article' => '_bx_photos_txt_sample_single_with_article',
+            	'txt_sample_comment_single' => '_bx_photos_txt_sample_comment_single',
+            	'txt_sample_vote_single' => '_bx_photos_txt_sample_vote_single',
+                'txt_sample_reaction_single' => '_bx_photos_txt_sample_reaction_single',
+                'txt_sample_score_up_single' => '_bx_photos_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_photos_txt_sample_score_down_single',
+                'form_field_author' => '_bx_photos_form_entry_input_author',
+                'form_entry_upload_single_for_update' => '_bx_photos_form_entry_input_pictures_upload',
+            	'grid_action_err_delete' => '_bx_photos_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_photos_grid_txt_account_manager',
+                'filter_item_active' => '_bx_photos_grid_filter_item_title_adm_active',
+            	'filter_item_hidden' => '_bx_photos_grid_filter_item_title_adm_hidden',
+                'filter_item_pending' => '_bx_photos_grid_filter_item_title_adm_pending',
+            	'filter_item_select_one_filter1' => '_bx_photos_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_photos_grid_filter_item_title_adm_select_one_filter2',
+            	'menu_item_manage_my' => '_bx_photos_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_photos_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_photos_txt_all_entries_by',
+                'txt_all_entries_in' => '_bx_photos_txt_all_entries_in',
+                'txt_all_entries_by_author' => '_bx_photos_page_title_browse_by_author',
+                'txt_all_entries_by_context' => '_bx_photos_page_title_browse_by_context',
+            	'txt_pict_use_as_thumb' => '_bx_photos_form_entry_input_picture_use_as_thumb',
+                'txt_media_exif_camera' => '_bx_photos_txt_camera',
+                'txt_media_exif_focal_length' => '_bx_photos_txt_focal_length',
+                'txt_media_exif_focal_length_value' => '_bx_photos_txt_focal_length_value',
+                'txt_media_exif_aperture' => '_bx_photos_txt_aperture',
+                'txt_media_exif_shutter_speed' => '_bx_photos_txt_shutter_speed',
+                'txt_media_exif_shutter_speed_value' => '_bx_photos_txt_shutter_speed_value',
+                'txt_media_exif_iso' => '_bx_photos_txt_iso',
+            ),
+        );
+
+        $this->_aJsClasses = array(
+            'main' => 'BxPhotosMain',
+            'manage_tools' => 'BxPhotosManageTools'
+        );
+
+        $this->_aJsObjects = array(
+            'main' => 'oBxPhotosMain',
+            'manage_tools' => 'oBxPhotosManageTools'
+        );
+
+        $this->_aGridObjects = array(
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION']
+        );
+
+        $sHtmlPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = array(
+        	'view_entry_brief_popup' => $sHtmlPrefix . '-view-entry-brief-popup'
+        );
+    }
+
+    public function getHtmlIds($sKey = '')
+    {
+        if(empty($sKey))
+            return $this->_aHtmlIds;
+
+        return isset($this->_aHtmlIds[$sKey]) ? $this->_aHtmlIds[$sKey] : '';
+    }
+}
+
+/** @} */

+ 159 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/classes/BxPhotosSearchResult.php

@@ -0,0 +1,159 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Photos Photos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPhotosSearchResult extends BxBaseModTextSearchResult
+{
+    public $aParams;
+
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aParams = $aParams;
+        $this->aCurrent = array(
+            'name' => 'bx_photos',
+            'module_name' => 'bx_photos',
+            'object_metatags' => 'bx_photos',
+            'title' => _t('_bx_photos_page_title_browse'),
+            'table' => 'bx_photos_entries',
+            'ownFields' => array('id', 'title', 'text', 'thumb', 'author', 'added', 'views'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+                'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_photos_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',
+            		'Image' => 'thumb'
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_photos_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $oProfileAuthor = null;
+
+        switch ($sMode) {
+            case 'author':
+                if(empty($this->aParams['author']) && bx_get('author') !== false)
+                    $this->aParams['author'] = bx_process_input(bx_get('author'));
+
+                if(!$this->_updateCurrentForAuthor($sMode, $this->aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'context':
+                if(!$this->_updateCurrentForContext($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'followed_contexts':
+                if(!$this->_updateCurrentForFollowedContexts($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'favorite':
+                if(empty($this->aParams['author']) && bx_get('author') !== false)
+                    $this->aParams['author'] = bx_process_input(bx_get('author'));
+
+                if(!$this->_updateCurrentForFavorite($sMode, $this->aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_photos_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=photos/rss/' . $sMode;
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_photos_page_title_browse_featured');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=photos/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_photos_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=photos/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'top':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP']);
+                $this->aCurrent['title'] = _t('_bx_photos_page_title_browse_top');
+                $this->aCurrent['rss']['link'] = 'modules/?r=photos/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'top';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_photos_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=photos/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_photos');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+
+    function getSearchData ()
+    {
+        $aResult = parent::getSearchData();
+        if(empty($aResult) || !is_array($aResult))
+            return $aResult;
+
+		if(!empty($this->aParams) && is_array($this->aParams))
+        	$this->aUnitParams = array_merge($this->aUnitParams, $this->aParams);
+
+        $this->aUnitParams['start'] = $this->aCurrent['paginate']['start'];
+        $this->aUnitParams['per_page'] = $this->aCurrent['paginate']['perPage'];
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 194 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/classes/BxPhotosTemplate.php

@@ -0,0 +1,194 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Photos Photos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxPhotosTemplate extends BxBaseModTextTemplate
+{
+    /**
+     * Constructor
+     */
+    public function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_photos';
+        parent::__construct($oConfig, $oDb);
+    }
+
+    public function entryPhoto ($aContentInfo, $bAsArray = false)
+    {
+        $aTmplVars = BxBaseModGeneralTemplate::getTmplVarsText($aContentInfo);
+
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        if(empty($aContentInfo[$CNF['FIELD_THUMB']]))
+            return $bAsArray || $this->_bIsApi ? [] : false;
+
+        $iImage = (int)$aContentInfo[$CNF['FIELD_THUMB']];
+
+        $oImagesTranscoder = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_IMAGES_TRANSCODER_COVER']);
+        if($oImagesTranscoder)
+            $sImage = $oImagesTranscoder->getFileUrl($iImage);
+        
+        if(empty($sImage)) {
+            $oStorage = BxDolStorage::getObjectInstance($CNF['OBJECT_STORAGE']);
+            if($oStorage)
+                $sImage = $oStorage->getFileUrlById($iImage);
+        }
+
+        if(empty($sImage))
+            return $bAsArray || $this->_bIsApi ? [] : '';
+
+        if($this->_bIsApi)
+            return array_merge($aTmplVars, [
+                'image' => bx_api_get_image($CNF['OBJECT_STORAGE'], $iImage)
+            ]);
+        
+        $aTmplVars = array_merge($aTmplVars, array(
+            'content_description_before' => '',
+            'entry_photo' => $sImage,
+            'entry_title_attr' => bx_html_attribute($this->getTitle($aContentInfo)),
+            'content_description_after' => ''
+        ));
+
+        if(($sKey = 'OBJECT_REACTIONS') && !empty($CNF[$sKey]) && ($oReactions = BxDolVote::getObjectInstance($CNF[$sKey], $aContentInfo[$CNF['FIELD_ID']])))
+            $aTmplVars['content_description_after'] .= $oReactions->getCounter([
+                'show_counter' => true,
+                'show_counter_empty' => false
+            ]);
+
+        return $bAsArray ? $aTmplVars : $this->parseHtmlByName('entry-photo.html', $aTmplVars);
+    }
+
+    public function entryPhotoSwitcher($aContentInfo, $sMode = '')
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $sJsObject = $this->_oConfig->getJsObject('main');
+
+        $sParams = '';
+        $iIdPrw = $iIdNxt = 0;
+        $bIdPrw = $bIdNxt = false;
+        if(!empty($sMode)) {
+            bx_import('SearchResult', $this->_oModule->_aModule);
+            $sSearch = $this->_oConfig->getClassPrefix() . 'SearchResult';
+            $oSearch = new $sSearch($sMode);
+
+            $aData = $oSearch->getSearchData();
+            $iData = count($aData);
+
+            for($i = 0; $i < $iData; $i++) 
+                if((int)$aData[$i]['id'] == $aContentInfo[$CNF['FIELD_ID']]) {
+                    if(isset($aData[$i - 1])) {
+                        $iIdPrw = (int)$aData[$i - 1]['id'];
+                        $bIdPrw = !empty($iIdPrw);
+                    }
+
+                    if(isset($aData[$i + 1])) {
+                        $iIdNxt = (int)$aData[$i + 1]['id'];
+                        $bIdNxt = !empty($iIdNxt);
+                    }
+
+                    break;
+                }
+
+            if($bIdPrw || $bIdNxt) {
+                $aParams = $oSearch->aParams;
+
+                if(isset($oSearch->aCurrent['paginate']['start']))
+                    $aParams['start'] = (int)$oSearch->aCurrent['paginate']['start'];
+
+                if(isset($oSearch->aCurrent['paginate']['perPage']))
+                    $aParams['per_page'] = (int)$oSearch->aCurrent['paginate']['perPage'];
+
+                if(!empty($aParams))
+                    $sParams = bx_html_attribute(json_encode($aParams));
+            }
+        }
+
+        return $this->parseHtmlByName('entry-photo-switcher.html', array_merge($this->entryPhoto($aContentInfo, true), array(
+            'bx_if:show_arrow_previous' => array(
+                'condition' => $bIdPrw,
+        		'content' => array(
+                    'js_object' => $sJsObject,
+                    'id' => $iIdPrw,
+                    'mode' => $sMode,
+            		'params' => $sParams,
+                )
+            ),
+            'bx_if:show_arrow_next' => array(
+                'condition' => $bIdNxt,
+        		'content' => array(
+                    'js_object' => $sJsObject,
+                    'id' => $iIdNxt,
+                    'mode' => $sMode,
+            		'params' => $sParams,
+                )
+            )
+        )));
+    }
+
+    public function entryRating($aData)
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+    	$sVotes = '';
+        $oVotes = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_STARS'], $aData[$CNF['FIELD_ID']]);
+        if($oVotes) {
+			$sVotes = $oVotes->getElementBlock(array('show_counter' => true, 'show_legend' => true));
+			if(!empty($sVotes))
+				$sVotes = $this->parseHtmlByName('entry-rating.html', array(
+		    		'content' => $sVotes,
+		    	));
+        }
+
+    	return $sVotes; 
+    }
+
+    public function getJsCode($sType, $aParams = array(), $bWrap = true)
+    {
+        $aParams = array_merge(array(
+            'aHtmlIds' => $this->_oConfig->getHtmlIds()
+        ), $aParams);
+
+        return parent::getJsCode($sType, $aParams, $bWrap);
+    }
+
+    protected function getUnit ($aData, $aParams = array())
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $sMode = '';
+        if(isset($aParams['context'])) {
+            $sMode = $aParams['context'];
+            unset($aParams['context']);
+        }
+
+        if(isset($CNF['FIELD_TITLE']) && empty($aData[$CNF['FIELD_TITLE']]))
+            $aData[$CNF['FIELD_TITLE']] = _t('_sys_txt_no_title');
+
+        $aResult = parent::getUnit($aData, $aParams);
+        $aResult['bx_if:thumb']['content']['content_onclick'] = !empty($sMode) ? $this->_oConfig->getJsObject('main') . ".viewEntry(" . $aData[$CNF['FIELD_ID']] . ", '" . $sMode . "', " . bx_html_attribute(json_encode($aParams)) . "); return false;" : "";
+
+        return $aResult;
+    }
+    
+    public function getTitle($aData, $mixedProcessOutput = BX_DATA_TEXT)
+    {
+        $sTitle = parent::getTitle($aData, $mixedProcessOutput);
+        if(!empty($sTitle))
+            return $sTitle;
+
+        return _t('_sys_txt_no_title');
+    }
+}
+
+/** @} */

+ 136 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/install/config.php

@@ -0,0 +1,136 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Photos Photos
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_photos',
+    'title' => 'Photos',
+    'note' => 'Basic photo posting module.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/photos/',
+    'home_uri' => 'photos',
+
+    'db_prefix' => 'bx_photos_',
+    'class_prefix' => 'BxPhotos',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Photos',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+        'trigger_group_view_submenu'
+    ),
+
+    /**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_photos_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_photos_preview',
+        'bx_photos_gallery',
+        'bx_photos_cover'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_photos',
+    	'bx_photos_cmts'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 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,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 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(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 77 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/enable-app.sql

@@ -0,0 +1,77 @@
+-- PAGES: config_api
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'post\',\r\n    top: true,\r\n    blocks: {\r\n        author: {\r\n            name: \'bx_photos:entity_author\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n            forHeader: true,\r\n        },\r\n        text: {\r\n            name: \'bx_photos:entity_text_block\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        attachments: {\r\n            name: \'bx_photos:entity_attachments\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        actions: {\r\n            name: \'bx_photos:entity_all_actions\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        \'comments-empty\': {\r\n            name: \'static:comments_empty\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        comments: {\r\n            name: \'bx_photos:entity_comments\',\r\n            showTitle: false,\r\n            showBg: false,\r\n        },\r\n    },\r\n    headerSettings: {\r\n        header: false,\r\n        footer: false,\r\n        offset: false,\r\n        backButton: true,\r\n        title: false,\r\n    },\r\n}' WHERE `object`='bx_photos_view_entry';
+
+-- PAGES: active_api
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_create_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_create_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_edit_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_edit_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_delete_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_delete_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_photo';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_text';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_sys_entry_context' AND `title`='_bx_photos_page_block_title_entry_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_media_exif';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_all_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_comments';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_location';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_featured_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_reports';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry_brief' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_photo';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry_brief' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry_brief' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entry_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_view_entry_comments' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_entry_comments' AND `title`='_bx_photos_page_block_title_entry_comments_link';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_popular' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_popular_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_top' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_top_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_updated' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_updated_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_author' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_entries_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_author' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_sys_favorites_of_author' AND `title`='_bx_photos_page_block_title_favorites_of_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_author' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_sys_entries_of_author' AND `title`='_bx_photos_page_block_title_entries_of_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_author' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_sys_entries_in_context' AND `title`='_bx_photos_page_block_title_entries_in_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_favorites' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_sys_favorites_entries' AND `title`='_bx_photos_page_block_title_favorites_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_favorites' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_favorites_entries_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_favorites' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_favorites_entries_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_context' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_sys_entries_in_context' AND `title`='_bx_photos_page_block_title_entries_in_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_home' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_featured_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_home' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_recent_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_home' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_popular_keywords';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_home' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_cats';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_search' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_search_form';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_search' AND `module`='bx_photos' AND `title_system`='' AND `title`='_bx_photos_page_block_title_search_results';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_manage' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_system_manage' AND `title`='_bx_photos_page_block_title_manage';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_photos_administration' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_system_manage_administration' AND `title`='_bx_photos_page_block_title_manage';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_photos' AND `title_system`='_bx_photos_page_block_title_sys_my_entries' AND `title`='_bx_photos_page_block_title_my_entries';
+
+
+-- MENUS:
+
+-- MENUS: config_api
+
+-- MENUS: active_api
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_homepage' AND `module`='bx_photos' AND `name`='photos-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_photos' AND `name`='profile-stats-my-photos';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_account_dashboard_manage_tools' AND `module`='bx_photos' AND `name`='photos-administration';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view' AND `module`='bx_photos' AND `name`='edit-photo';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view' AND `module`='bx_photos' AND `name`='delete-photo';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view' AND `module`='bx_photos' AND `name`='approve';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='edit-photo';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='delete-photo';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='approve';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='view';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='reaction';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='score';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='favorite';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='feature';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='repost';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='report';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='notes';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='audit';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='social-sharing';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_view_actions' AND `module`='bx_photos' AND `name`='more-auto';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_my' AND `module`='bx_photos' AND `name`='create-photo';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_submenu' AND `module`='bx_photos' AND `name`='photos-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_submenu' AND `module`='bx_photos' AND `name`='photos-popular';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_submenu' AND `module`='bx_photos' AND `name`='photos-top';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_submenu' AND `module`='bx_photos' AND `name`='photos-search';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_submenu' AND `module`='bx_photos' AND `name`='photos-manage';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_snippet_meta' AND `module`='bx_photos' AND `name`='rating';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_photos_snippet_meta' AND `module`='bx_photos' AND `name`='comments';

+ 477 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/enable.sql

@@ -0,0 +1,477 @@
+
+-- 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_photos', '_bx_photos', 'bx_photos@modules/boonex/photos/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_photos', '_bx_photos', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_photos_enable_auto_approve', 'on', @iCategId, '_bx_photos_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_photos_summary_chars', '700', @iCategId, '_bx_photos_option_summary_chars', 'digit', '', '', '', 1),
+('bx_photos_plain_summary_chars', '240', @iCategId, '_bx_photos_option_plain_summary_chars', 'digit', '', '', '', 2),
+('bx_photos_per_page_browse', '12', @iCategId, '_bx_photos_option_per_page_browse', 'digit', '', '', '', 10),
+('bx_photos_per_page_profile', '6', @iCategId, '_bx_photos_option_per_page_profile', 'digit', '', '', '', 12),
+('bx_photos_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 15),
+('bx_photos_per_page_for_favorites_lists', '5', @iCategId, '_bx_photos_option_per_page_for_favorites_lists', 'digit', '', '', '', 17),
+('bx_photos_rss_num', '10', @iCategId, '_bx_photos_option_rss_num', 'digit', '', '', '', 20),
+('bx_photos_searchable_fields', 'title,text', @iCategId, '_bx_photos_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:21:"get_searchable_fields";}', 30);
+
+
+-- 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_photos_create_entry', '_bx_photos_page_title_sys_create_entry', '_bx_photos_page_title_create_entry', 'bx_photos', 5, 2147483647, 1, 'create-photo', 'page.php?i=create-photo', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_photos_create_entry', 1, 'bx_photos', '_bx_photos_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";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_photos_edit_entry', '_bx_photos_page_title_sys_edit_entry', '_bx_photos_page_title_edit_entry', 'bx_photos', 5, 2147483647, 1, 'edit-photo', '', '', '', '', 0, 1, 0, 'BxPhotosPageEntry', 'modules/boonex/photos/classes/BxPhotosPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_photos_edit_entry', 1, 'bx_photos', '_bx_photos_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";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_photos_delete_entry', '_bx_photos_page_title_sys_delete_entry', '_bx_photos_page_title_delete_entry', 'bx_photos', 5, 2147483647, 1, 'delete-photo', '', '', '', '', 0, 1, 0, 'BxPhotosPageEntry', 'modules/boonex/photos/classes/BxPhotosPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_photos_delete_entry', 1, 'bx_photos', '_bx_photos_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";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_photos_view_entry', '_bx_photos_page_title_sys_view_entry', '_bx_photos_page_title_view_entry', 'bx_photos', 12, 2147483647, 1, 'view-photo', '', '', '', '', 0, 1, 0, 'BxPhotosPageEntry', 'modules/boonex/photos/classes/BxPhotosPageEntry.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_photos_view_entry', 1, 'bx_photos', '', '_bx_photos_page_block_title_entry_photo', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:18:"entity_photo_block";}', 0, 0, 1, 0),
+('bx_photos_view_entry', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:17:"entity_text_block";}', 0, 0, 1, 1),
+('bx_photos_view_entry', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"entity_author";}', 0, 0, 1, 3),
+('bx_photos_view_entry', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_rating', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"entity_rating";}', 0, 0, 0, 0),
+('bx_photos_view_entry', 3, 'bx_photos', '_bx_photos_page_block_title_sys_entry_context', '_bx_photos_page_block_title_entry_context', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_photos\";s:6:\"method\";s:14:\"entity_context\";}', 0, 0, 1, 1),
+('bx_photos_view_entry', 3, 'bx_photos', '', '_bx_photos_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:11:"entity_info";}', 0, 0, 1, 2),
+('bx_photos_view_entry', 3, 'bx_photos', '', '_bx_photos_page_block_title_entry_media_exif', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_photos\";s:6:\"method\";s:10:\"media_exif\";}', 0, 0, 1, 5),
+('bx_photos_view_entry', 3, 'bx_photos', '', '_bx_photos_page_block_title_entry_location', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"entity_location";}', 0, 0, 0, 0),
+('bx_photos_view_entry', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:18:"entity_all_actions";}', 0, 0, 1, 2),
+('bx_photos_view_entry', 4, 'bx_photos', '', '_bx_photos_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:14:"entity_actions";}', 0, 0, 0, 0),
+('bx_photos_view_entry', 4, 'bx_photos', '', '_bx_photos_page_block_title_entry_social_sharing', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:21:"entity_social_sharing";}', 0, 0, 0, 0),
+('bx_photos_view_entry', 4, 'bx_photos', '', '_bx_photos_page_block_title_entry_attachments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:18:"entity_attachments";}', 0, 0, 0, 0),
+('bx_photos_view_entry', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"entity_comments";}', 0, 0, 1, 4),
+('bx_photos_view_entry', 3, 'bx_photos', '', '_bx_photos_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_photos";i:1;s:4:"{id}";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 0, 1, 3),
+('bx_photos_view_entry', 3, 'bx_photos', '', '_bx_photos_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 0, 1, 4),
+('bx_photos_view_entry', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_photos\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+
+-- PAGE: view entry "brief"
+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_photos_view_entry_brief', '_bx_photos_page_title_sys_view_entry_brief', '_bx_photos_page_title_view_entry_brief', 'bx_photos', 2, 2147483647, 1, 'quick-view-photo', '', '', '', '', 0, 1, 0, 'BxPhotosPageEntryBrief', 'modules/boonex/photos/classes/BxPhotosPageEntryBrief.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_photos_view_entry_brief', 1, 'bx_photos', '', '_bx_photos_page_block_title_entry_photo', 0, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:27:"entity_photo_switcher_block";}', 0, 0, 1, 1),
+('bx_photos_view_entry_brief', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:11:"entity_info";}', 0, 0, 1, 1),
+('bx_photos_view_entry_brief', 2, 'bx_photos', '', '_bx_photos_page_block_title_entry_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"entity_author";}', 0, 0, 1, 2);
+
+-- 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_photos_view_entry_comments', '_bx_photos_page_title_sys_view_entry_comments', '_bx_photos_page_title_view_entry_comments', 'bx_photos', 5, 2147483647, 1, 'view-photo-comments', '', '', '', '', 0, 1, 0, 'BxPhotosPageEntry', 'modules/boonex/photos/classes/BxPhotosPageEntry.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_photos_view_entry_comments', 1, 'bx_photos', '_bx_photos_page_block_title_entry_comments', '_bx_photos_page_block_title_entry_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"entity_comments";}', 0, 0, 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_photos_popular', '_bx_photos_page_title_sys_entries_popular', '_bx_photos_page_title_entries_popular', 'bx_photos', 5, 2147483647, 1, 'photos-popular', 'page.php?i=photos-popular', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_photos_popular', 1, 'bx_photos', '_bx_photos_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";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: top 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_photos_top', '_bx_photos_page_title_sys_entries_top', '_bx_photos_page_title_entries_top', 'bx_photos', 5, 2147483647, 1, 'photos-top', 'page.php?i=photos-top', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_photos_top', 1, 'bx_photos', '_bx_photos_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:10:"browse_top";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_photos_updated', '_bx_photos_page_title_sys_entries_updated', '_bx_photos_page_title_entries_updated', 'bx_photos', 5, 2147483647, 1, 'photos-updated', 'page.php?i=photos-updated', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_photos_updated', 1, 'bx_photos', '_bx_photos_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";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_photos_author', 'photos-author', '_bx_photos_page_title_sys_entries_of_author', '_bx_photos_page_title_entries_of_author', 'bx_photos', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxPhotosPageAuthor', 'modules/boonex/photos/classes/BxPhotosPageAuthor.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_photos_author', 1, 'bx_photos', '', '_bx_photos_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:18:"my_entries_actions";}', 0, 0, 1, 1),
+('bx_photos_author', 1, 'bx_photos', '_bx_photos_page_block_title_sys_favorites_of_author', '_bx_photos_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:21:"browse_favorite_lists";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1, 2),
+('bx_photos_author', 1, 'bx_photos', '_bx_photos_page_block_title_sys_entries_of_author', '_bx_photos_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"browse_author";}', 0, 0, 1, 3),
+('bx_photos_author', 1, 'bx_photos', '_bx_photos_page_block_title_sys_entries_in_context', '_bx_photos_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:14:"browse_context";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";i:0;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 1, 4);
+
+
+-- PAGE: favorites by list
+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_photos_favorites', '_bx_photos_page_title_sys_entries_favorites', '_bx_photos_page_title_entries_favorites', 'bx_photos', 12, 2147483647, 1, 'photos-favorites', 'page.php?i=photos-favorites', '', '', '', 0, 1, 0, 'BxPhotosPageListEntry', 'modules/boonex/photos/classes/BxPhotosPageListEntry.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_photos_favorites', 2, 'bx_photos', '_bx_photos_page_block_title_sys_favorites_entries', '_bx_photos_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"browse_favorite";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1),
+('bx_photos_favorites', 3, 'bx_photos', '', '_bx_photos_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_photos_favorites', 3, 'bx_photos', '', '_bx_photos_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+
+-- PAGE: entries in context
+
+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_photos_context', 'photos-context', '_bx_photos_page_title_sys_entries_in_context', '_bx_photos_page_title_entries_in_context', 'bx_photos', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxPhotosPageAuthor', 'modules/boonex/photos/classes/BxPhotosPageAuthor.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_photos_context', 1, 'bx_photos', '_bx_photos_page_block_title_sys_entries_in_context', '_bx_photos_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:9:\"bx_photos\";s:6:\"method\";s:14:\"browse_context\";}', 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_photos_home', 'photos-home', '_bx_photos_page_title_sys_home', '_bx_photos_page_title_home', 'bx_photos', 2, 2147483647, 1, 'page.php?i=photos-home', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.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_photos_home', 1, 'bx_photos', '', '_bx_photos_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 1, 0),
+('bx_photos_home', 1, 'bx_photos', '', '_bx_photos_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:7:"gallery";}}', 0, 1, 1, 1),
+('bx_photos_home', 2, 'bx_photos', '', '_bx_photos_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_photos";i:1;s:9:"bx_photos";}s:5:"class";s:20:"TemplServiceMetatags";}', 0, 1, 1, 0),
+('bx_photos_home', 2, 'bx_photos', '', '_bx_photos_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_photos_cats";i:1;a:1:{s:10:"show_empty";b:1;}}s:5:"class";s:20:"TemplServiceCategory";}', 0, 1, 1, 1);
+
+-- PAGE: search for 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_photos_search', '_bx_photos_page_title_sys_entries_search', '_bx_photos_page_title_entries_search', 'bx_photos', 5, 2147483647, 1, 'photos-search', 'page.php?i=photos-search', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_photos_search', 1, 'bx_photos', '_bx_photos_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:9:"bx_photos";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_photos_search', 1, 'bx_photos', '_bx_photos_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:9:"bx_photos";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_photos_search', 1, 'bx_photos', '_bx_photos_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:14:"bx_photos_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_photos_search', 1, 'bx_photos', '_bx_photos_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:14:"bx_photos_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- 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_photos_manage', '_bx_photos_page_title_sys_manage', '_bx_photos_page_title_manage', 'bx_photos', 5, 2147483647, 1, 'photos-manage', 'page.php?i=photos-manage', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.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_photos_manage', 1, 'bx_photos', '_bx_photos_page_block_title_system_manage', '_bx_photos_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:9:"bx_photos";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_photos_administration', '_bx_photos_page_title_sys_manage_administration', '_bx_photos_page_title_manage', 'bx_photos', 5, 192, 1, 'photos-administration', 'page.php?i=photos-administration', '', '', '', 0, 1, 0, 'BxPhotosPageBrowse', 'modules/boonex/photos/classes/BxPhotosPageBrowse.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_photos_administration', 1, 'bx_photos', '_bx_photos_page_block_title_system_manage_administration', '_bx_photos_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";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_photos', '_bx_photos_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"browse_public";s:6:"params";a:2:{i:0;b:0;i:1;b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1);
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 3;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_photos', '_bx_photos_page_block_title_sys_my_entries', '_bx_photos_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:26:"bx_photos_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0);
+
+-- 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_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('', 0, 'bx_photos', '', '_bx_photos_page_block_title_recent_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, 'bx_photos', '', '_bx_photos_page_block_title_recent_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";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_photos', '', '_bx_photos_page_block_title_popular_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";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_photos', '', '_bx_photos_page_block_title_popular_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, 'bx_photos', '', '_bx_photos_page_block_title_featured_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 5),
+('', 0, 'bx_photos', '', '_bx_photos_page_block_title_featured_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:9:"bx_photos";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 6),
+('', 0, 'bx_photos', '_bx_photos_page_block_title_sys_recent_entries_view_showcase', '_bx_photos_page_block_title_recent_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_photos\";s:6:\"method\";s:13:\"browse_public\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 7),
+('', 0, 'bx_photos', '_bx_photos_page_block_title_sys_popular_entries_view_showcase', '_bx_photos_page_block_title_popular_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_photos\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 8),
+('', 0, 'bx_photos', '_bx_photos_page_block_title_sys_featured_entries_view_showcase', '_bx_photos_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:9:\"bx_photos\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 9);
+
+
+-- MENU: add to site menu
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 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_photos', 'photos-home', '_bx_photos_menu_item_title_system_entries_home', '_bx_photos_menu_item_title_entries_home', 'page.php?i=photos-home', '', '', 'camera-retro col-blue1', 'bx_photos_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_photos', 'photos-home', '_bx_photos_menu_item_title_system_entries_home', '_bx_photos_menu_item_title_entries_home', 'page.php?i=photos-home', '', '', 'camera-retro col-blue1', 'bx_photos_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_photos', 'create-photo', '_bx_photos_menu_item_title_system_create_entry', '_bx_photos_menu_item_title_create_entry', 'page.php?i=create-photo', '', '', 'camera-retro col-blue1', '', 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_photos_view', '_bx_photos_menu_title_view_entry', 'bx_photos_view', 'bx_photos', 9, 0, 1, 'BxPhotosMenuView', 'modules/boonex/photos/classes/BxPhotosMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_photos_view', 'bx_photos', '_bx_photos_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_photos_view', 'bx_photos', 'edit-photo', '_bx_photos_menu_item_title_system_edit_entry', '_bx_photos_menu_item_title_edit_entry', 'page.php?i=edit-photo&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 1),
+('bx_photos_view', 'bx_photos', 'delete-photo', '_bx_photos_menu_item_title_system_delete_entry', '_bx_photos_menu_item_title_delete_entry', 'page.php?i=delete-photo&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 2),
+('bx_photos_view', 'bx_photos', 'approve', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, 1, 0, 3);
+
+-- MENU: all 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_photos_view_actions', '_sys_menu_title_view_actions', 'bx_photos_view_actions', 'bx_photos', 15, 0, 1, 'BxPhotosMenuViewActions', 'modules/boonex/photos/classes/BxPhotosMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_photos_view_actions', 'bx_photos', '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_photos_view_actions', 'bx_photos', 'edit-photo', '_bx_photos_menu_item_title_system_edit_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_photos_view_actions', 'bx_photos', 'delete-photo', '_bx_photos_menu_item_title_system_delete_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_photos_view_actions', 'bx_photos', 'approve', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_photos_view_actions', 'bx_photos', 'set-badges', '_sys_menu_item_title_system_set_badges', '_sys_menu_item_title_set_badges', 'javascript:void(0)', 'bx_menu_popup(''sys_set_badges'', window, {}, {module: ''bx_photos'', content_id: {content_id}});', '', 'check-circle', '', '', 0, 2147483647, 'a:2:{s:6:"module";s:9:"bx_photos";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 40),
+('bx_photos_view_actions', 'bx_photos', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 200),
+('bx_photos_view_actions', 'bx_photos', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 210),
+('bx_photos_view_actions', 'bx_photos', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 220),
+('bx_photos_view_actions', 'bx_photos', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 225),
+('bx_photos_view_actions', 'bx_photos', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 230),
+('bx_photos_view_actions', 'bx_photos', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 240),
+('bx_photos_view_actions', 'bx_photos', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 250),
+('bx_photos_view_actions', 'bx_photos', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 260),
+('bx_photos_view_actions', 'bx_photos', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 270),
+('bx_photos_view_actions', 'bx_photos', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, '', 1, 0, 280),
+('bx_photos_view_actions', 'bx_photos', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_photos&content_id={content_id}', '', '', 'history', '', '', 0, 192, '', 1, 0, 290),
+('bx_photos_view_actions', 'bx_photos', 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, '', 1, 0, 300),
+('bx_photos_view_actions', 'bx_photos', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, '', 1, 0, 9999);
+
+-- 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_photos_my', '_bx_photos_menu_title_entries_my', 'bx_photos_my', 'bx_photos', 9, 0, 1, 'BxPhotosMenu', 'modules/boonex/photos/classes/BxPhotosMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_photos_my', 'bx_photos', '_bx_photos_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_photos_my', 'bx_photos', 'create-photo', '_bx_photos_menu_item_title_system_create_entry', '_bx_photos_menu_item_title_create_entry', 'page.php?i=create-photo', '', '', '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_photos_submenu', '_bx_photos_menu_title_submenu', 'bx_photos_submenu', 'bx_photos', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_photos_submenu', 'bx_photos', '_bx_photos_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_photos_submenu', 'bx_photos', 'photos-home', '_bx_photos_menu_item_title_system_entries_public', '_bx_photos_menu_item_title_entries_public', 'page.php?i=photos-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_photos_submenu', 'bx_photos', 'photos-popular', '_bx_photos_menu_item_title_system_entries_popular', '_bx_photos_menu_item_title_entries_popular', 'page.php?i=photos-popular', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_photos_submenu', 'bx_photos', 'photos-top', '_bx_photos_menu_item_title_system_entries_top', '_bx_photos_menu_item_title_entries_top', 'page.php?i=photos-top', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_photos_submenu', 'bx_photos', 'photos-search', '_bx_photos_menu_item_title_system_entries_search', '_bx_photos_menu_item_title_entries_search', 'page.php?i=photos-search', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_photos_submenu', 'bx_photos', 'photos-manage', '_bx_photos_menu_item_title_system_entries_manage', '_bx_photos_menu_item_title_entries_manage', 'page.php?i=photos-manage', '', '', '', '', 2147483646, 1, 1, 5);
+
+-- 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_photos_view_submenu', '_bx_photos_menu_title_view_entry_submenu', 'bx_photos_view_submenu', 'bx_photos', 8, 0, 1, 'BxPhotosMenuView', 'modules/boonex/photos/classes/BxPhotosMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_photos_view_submenu', 'bx_photos', '_bx_photos_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_photos_view_submenu', 'bx_photos', 'view-photo', '_bx_photos_menu_item_title_system_view_entry', '_bx_photos_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-photo&id={content_id}', '', '', '', '', 2147483647, 0, 0, 1),
+('bx_photos_view_submenu', 'bx_photos', 'view-photo-comments', '_bx_photos_menu_item_title_system_view_entry_comments', '_bx_photos_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-photo-comments&id={content_id}', '', '', '', '', 2147483647, 0, 0, 2);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_photos_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_photos_snippet_meta', 'bx_photos', 15, 0, 1, 'BxPhotosMenuSnippetMeta', 'modules/boonex/photos/classes/BxPhotosMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_photos_snippet_meta', 'bx_photos', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_photos_snippet_meta', 'bx_photos', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 0, 0, 1, 1),
+('bx_photos_snippet_meta', 'bx_photos', 'rating', '_sys_menu_item_title_system_sm_rating', '_sys_menu_item_title_sm_rating', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_photos_snippet_meta', 'bx_photos', 'author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 0, 0, 1, 3),
+('bx_photos_snippet_meta', 'bx_photos', 'category', '_sys_menu_item_title_system_sm_category', '_sys_menu_item_title_sm_category', '', '', '', '', '', 2147483647, 0, 0, 1, 4),
+('bx_photos_snippet_meta', 'bx_photos', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, 0, 0, 1, 5),
+('bx_photos_snippet_meta', 'bx_photos', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 0, 0, 1, 6),
+('bx_photos_snippet_meta', 'bx_photos', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 1, 0, 1, 7);
+
+-- 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_photos', 'profile-stats-my-photos', '_bx_photos_menu_item_title_system_manage_my_photos', '_bx_photos_menu_item_title_manage_my_photos', 'page.php?i=photos-author&profile_id={member_id}', '', '_self', 'camera-retro col-blue1', 'a:2:{s:6:"module";s:9:"bx_photos";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_photos_menu_manage_tools', '_bx_photos_menu_title_manage_tools', 'bx_photos_menu_manage_tools', 'bx_photos', 6, 0, 1, 'BxPhotosMenuManageTools', 'modules/boonex/photos/classes/BxPhotosMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_photos_menu_manage_tools', 'bx_photos', '_bx_photos_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_photos_menu_manage_tools', 'bx_photos', 'delete-with-content', '_bx_photos_menu_item_title_system_delete_with_content', '_bx_photos_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 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_photos', 'photos-administration', '_bx_photos_menu_item_title_system_admt_photos', '_bx_photos_menu_item_title_admt_photos', 'page.php?i=photos-administration', '', '_self', 'camera-retro', 'a:2:{s:6:"module";s:9:"bx_photos";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_photos', 'photos-author', '_bx_photos_menu_item_title_system_view_entries_author', '_bx_photos_menu_item_title_view_entries_author', 'page.php?i=photos-author&profile_id={profile_id}', '', '', 'camera-retro col-blue1', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', 'bx_photos', 'photos-context', '_bx_photos_menu_item_title_system_view_entries_in_context', '_bx_photos_menu_item_title_view_entries_in_context', 'page.php?i=photos-context&profile_id={profile_id}', '', '', 'camera-retro col-blue1', '', 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_photos_allow_view_to', 'bx_photos', 'view', '_bx_photos_form_entry_input_allow_view_to', '3', 'bx_photos_entries', 'id', 'author', 'BxPhotosPrivacy', 'modules/boonex/photos/classes/BxPhotosPrivacy.php'),
+('bx_photos_allow_view_favorite_list', 'bx_photos', 'view_favorite_list', '_bx_photos_form_entry_input_allow_view_favorite_list', '3', 'bx_photos_favorites_lists', 'id', 'author_id', 'BxPhotosPrivacy', 'modules/boonex/photos/classes/BxPhotosPrivacy.php');
+-- ACL
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_photos', 'create entry', NULL, '_bx_photos_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_photos', 'delete entry', NULL, '_bx_photos_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_photos', 'view entry', NULL, '_bx_photos_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_photos', 'set thumb', NULL, '_bx_photos_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_photos', 'edit any entry', NULL, '_bx_photos_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_photos', 'delete any entry', NULL, '_bx_photos_acl_action_delete_any_entry', '', 1, 3);
+SET @iIdActionEntryDeleteAny = 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),
+
+-- delete any entry
+(@iAdministrator, @iIdActionEntryDeleteAny);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_photos', '_bx_photos', @iSearchOrder + 1, 'BxPhotosSearchResult', 'modules/boonex/photos/classes/BxPhotosSearchResult.php'),
+('bx_photos_cmts', '_bx_photos_cmts', @iSearchOrder + 2, 'BxPhotosCmtsSearchResult', 'modules/boonex/photos/classes/BxPhotosCmtsSearchResult.php');
+
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_photos', 'bx_photos', 'bx_photos_meta_keywords', 'bx_photos_meta_locations', 'bx_photos_meta_mentions', '', ''),
+('bx_photos_camera', 'bx_photos', 'bx_photos_meta_keywords_camera', '', '', '', '');
+
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `module`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_photos_cats', 'bx_photos', 'bx_photos', 'bx_photos', 'bx_photos_cats', 'bx_photos_entries', 'cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`id` = `bx_photos_entries`.`author`)', 'AND `sys_profiles`.`status` = ''active''', '', '');
+
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_photos', 'bx_photos', '_bx_photos', 'page.php?i=photos-home', 'camera-retro col-blue1', 'SELECT COUNT(*) FROM `bx_photos_entries` WHERE 1 AND `status` = ''active'' AND `status_admin` = ''active''', @iMaxOrderStats + 1);
+
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_photos_growth', '_bx_photos_chart_growth', 'bx_photos_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_photos_growth_speed', '_bx_photos_chart_growth_speed', 'bx_photos_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+
+-- 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`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_photos_administration', 'Sql', 'SELECT * FROM `bx_photos_entries` WHERE 1 ', 'bx_photos_entries', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'title,text', '', 'like', 'reports', '', 192, 'BxPhotosGridAdministration', 'modules/boonex/photos/classes/BxPhotosGridAdministration.php'),
+('bx_photos_common', 'Sql', 'SELECT * FROM `bx_photos_entries` WHERE 1 ', 'bx_photos_entries', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 2147483647, 'BxPhotosGridCommon', 'modules/boonex/photos/classes/BxPhotosGridCommon.php');
+
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_photos_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_photos_administration', 'switcher', '_bx_photos_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_photos_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_photos_administration', 'title', '_bx_photos_grid_column_title_adm_title', '25%', 0, '25', '', 4),
+('bx_photos_administration', 'added', '_bx_photos_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_photos_administration', 'author', '_bx_photos_grid_column_title_adm_author', '20%', 0, '25', '', 6),
+('bx_photos_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_photos_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_photos_common', 'switcher', '_bx_photos_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_photos_common', 'title', '_bx_photos_grid_column_title_adm_title', '40%', 0, '35', '', 3),
+('bx_photos_common', 'added', '_bx_photos_grid_column_title_adm_added', '15%', 1, '25', '', 4),
+('bx_photos_common', 'status_admin', '_bx_photos_grid_column_title_adm_status_admin', '15%', 0, '16', '', 5),
+('bx_photos_common', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_photos_administration', 'bulk', 'delete', '_bx_photos_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_photos_administration', 'bulk', 'clear_reports', '_bx_photos_grid_action_title_adm_clear_reports', '', 0, 1, 2),
+('bx_photos_administration', 'single', 'edit', '_bx_photos_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_photos_administration', 'single', 'delete', '_bx_photos_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_photos_administration', 'single', 'settings', '_bx_photos_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_photos_administration', 'single', 'audit_content', '_bx_photos_grid_action_title_adm_audit_content', 'search', 1, 0, 4),
+('bx_photos_administration', 'single', 'clear_reports', '_bx_photos_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5),
+('bx_photos_common', 'bulk', 'delete', '_bx_photos_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_photos_common', 'single', 'edit', '_bx_photos_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_photos_common', 'single', 'delete', '_bx_photos_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_photos_common', 'single', 'settings', '_bx_photos_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+
+-- UPLOADERS
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_photos_html5', 1, 'BxPhotosUploaderHTML5', 'modules/boonex/photos/classes/BxPhotosUploaderHTML5.php');
+
+
+-- ALERTS
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_photos', 'BxPhotosAlertsResponse', 'modules/boonex/photos/classes/BxPhotosAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'delete', @iHandler);

+ 451 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/install.sql

@@ -0,0 +1,451 @@
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_photos_entries` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(10) unsigned NOT NULL default '0',
+  `added` int(11) NOT NULL default '0',
+  `changed` int(11) NOT NULL default '0',
+  `thumb` int(11) NOT NULL default '0',
+  `title` varchar(255) NOT NULL,
+  `cat` int(11) NOT NULL,
+  `text` text NOT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `srate` float NOT NULL default '0',
+  `svotes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` int(11) NOT NULL default '0',
+  `score` int(11) NOT NULL default '0',
+  `sc_up` int(11) NOT NULL default '0',
+  `sc_down` int(11) NOT NULL default '0',
+  `favorites` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `allow_view_to` varchar(16) NOT NULL DEFAULT '3',
+  `cf` int(11) NOT NULL default '1',
+  `status` enum('active','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  `exif` text NOT NULL,
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_photos_photos` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_photos_media_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_photos_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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  `cmt_cf` int(11) NOT NULL default '1',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_cmts_notes` (
+  `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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+-- TABLE: votes
+CREATE TABLE IF NOT EXISTS `bx_photos_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_svotes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_svotes_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: views
+CREATE TABLE `bx_photos_views_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `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',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE `bx_photos_meta_keywords` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE `bx_photos_meta_keywords_camera` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE `bx_photos_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,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+);
+
+CREATE TABLE `bx_photos_meta_mentions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_photos_reports` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_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',
+  `checked_by` int(11) NOT NULL default '0',
+  `status` tinyint(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: favorites
+CREATE TABLE `bx_photos_favorites_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `list_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+CREATE TABLE `bx_photos_favorites_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `allow_view_favorite_list_to` varchar(16) NOT NULL DEFAULT '3',
+  PRIMARY KEY (`id`)
+);
+
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_photos_scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_photos_scores_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(8) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+
+-- STORAGES & TRANSCODERS
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+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_photos_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_photos_photos', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+('bx_photos_media_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_photos_media_resized', 'allow-deny', '{imagevideo}', '', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES 
+('bx_photos_preview', 'bx_photos_media_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_photos_photos";}', 'no', 1, 2592000, 0, '', ''),
+('bx_photos_gallery', 'bx_photos_media_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_photos_photos";}', 'no', 1, 2592000, 0, '', ''),
+('bx_photos_cover', 'bx_photos_media_resized', 'Storage', 'a:1:{s:6:"object";s:16:"bx_photos_photos";}', 'no', 1, 2592000, 0, '', '');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_photos_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_photos_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0'),
+('bx_photos_cover', 'Resize', 'a:1:{s:1:"w";s:4:"1200";}', '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_photos', 'bx_photos', '_bx_photos_form_entry', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_photos_entries', 'id', '', '', 'a:2:{i:0;s:9:"do_submit";i:1;s:10:"do_publish";}', '', 0, 1, 'BxPhotosFormEntry', 'modules/boonex/photos/classes/BxPhotosFormEntry.php'),
+('bx_photos_upload', 'bx_photos', '_bx_photos_form_upload', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_photos_entries', 'id', '', '', 'do_submit', '', 0, 1, 'BxPhotosFormUpload', 'modules/boonex/photos/classes/BxPhotosFormUpload.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_photos_upload', 'bx_photos_entry_upload', 'bx_photos', 0, '_bx_photos_form_upload_display_upload'),
+('bx_photos', 'bx_photos_entry_delete', 'bx_photos', 0, '_bx_photos_form_entry_display_delete'),
+('bx_photos', 'bx_photos_entry_edit', 'bx_photos', 0, '_bx_photos_form_entry_display_edit'),
+('bx_photos', 'bx_photos_entry_view', 'bx_photos', 1, '_bx_photos_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_photos', 'bx_photos', 'cf', '1', '#!sys_content_filter', 0, 'select', '_sys_form_entry_input_sys_cf', '_sys_form_entry_input_cf', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_photos', 'bx_photos', 'allow_view_to', '', '', 0, 'custom', '_bx_photos_form_entry_input_sys_allow_view_to', '_bx_photos_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_photos_form_entry_input_sys_delete_confirm', '_bx_photos_form_entry_input_delete_confirm', '_bx_photos_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_photos_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'do_publish', '_bx_photos_form_entry_input_do_publish', '', 0, 'submit', '_bx_photos_form_entry_input_sys_do_publish', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'do_submit', '_bx_photos_form_entry_input_do_submit', '', 0, 'submit', '_bx_photos_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_photos', 'bx_photos', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_photos', 'bx_photos', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'pictures', 'a:1:{i:0;s:15:"bx_photos_html5";}', 'a:1:{s:15:"bx_photos_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_photos_form_entry_input_sys_picture', '_bx_photos_form_entry_input_picture', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_photos_form_entry_input_picture_err', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'text', '', '', 0, 'textarea', '_bx_photos_form_entry_input_sys_text', '_bx_photos_form_entry_input_text', '', 0, 0, 3, '', '', '', '', '', '', 'XssHtml', '', 1, 0),
+('bx_photos', 'bx_photos', 'title', '', '', 0, 'text', '_bx_photos_form_entry_input_sys_title', '_bx_photos_form_entry_input_title', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_photos_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_photos', 'bx_photos', 'cat', '', '#!bx_photos_cats', 0, 'select', '_bx_photos_form_entry_input_sys_cat', '_bx_photos_form_entry_input_cat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_photos_form_entry_input_cat_err', 'Xss', '', 1, 0),
+('bx_photos', 'bx_photos', 'added', '', '', 0, 'datetime', '_bx_photos_form_entry_input_sys_date_added', '_bx_photos_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'changed', '', '', 0, 'datetime', '_bx_photos_form_entry_input_sys_date_changed', '_bx_photos_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos', 'bx_photos', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+
+('bx_photos_upload', 'bx_photos', 'pictures', 'a:1:{i:0;s:15:"bx_photos_html5";}', 'a:1:{s:15:"bx_photos_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_photos_form_entry_input_sys_pictures', '_bx_photos_form_entry_input_pictures', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_photos_form_entry_input_pictures_err', '', '', 1, 0),
+('bx_photos_upload', 'bx_photos', 'cat', '', '#!bx_photos_cats', 0, 'select', '_bx_photos_form_entry_input_sys_cat', '_bx_photos_form_entry_input_cat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_photos_form_entry_input_cat_err', 'Xss', '', 1, 0),
+('bx_photos_upload', 'bx_photos', 'cf', '', '#!sys_content_filter', 0, 'select', '_sys_form_entry_input_sys_cf', '_sys_form_entry_input_cf', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_photos_upload', 'bx_photos', 'allow_view_to', '', '', 0, 'custom', '_bx_photos_form_entry_input_sys_allow_view_to', '_bx_photos_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos_upload', 'bx_photos', 'do_submit', '_bx_photos_form_entry_input_do_submit', '', 0, 'submit', '_bx_photos_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_photos_upload', 'bx_photos', 'profile_id', '0', '', 0, 'hidden', '_bx_photos_form_entry_input_sys_profile_id', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_photos_entry_upload', 'profile_id', 2147483647, 1, 1),
+('bx_photos_entry_upload', 'pictures', 2147483647, 1, 2),
+('bx_photos_entry_upload', 'cat', 2147483647, 1, 3),
+('bx_photos_entry_upload', 'allow_view_to', 2147483647, 1, 4),
+('bx_photos_entry_upload', 'cf', 2147483647, 1, 5),
+('bx_photos_entry_upload', 'do_submit', 2147483647, 1, 6),
+
+('bx_photos_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_photos_entry_delete', 'do_submit', 2147483647, 1, 2),
+
+('bx_photos_entry_edit', 'title', 2147483647, 1, 1),
+('bx_photos_entry_edit', 'cat', 2147483647, 1, 2),
+('bx_photos_entry_edit', 'text', 2147483647, 1, 3),
+('bx_photos_entry_edit', 'pictures', 2147483647, 1, 4),
+('bx_photos_entry_edit', 'allow_view_to', 2147483647, 1, 5),
+('bx_photos_entry_edit', 'cf', 2147483647, 1, 6),
+('bx_photos_entry_edit', 'location', 2147483647, 1, 7),
+('bx_photos_entry_edit', 'controls', 2147483647, 1, 8),
+('bx_photos_entry_edit', 'do_submit', 2147483647, 1, 9),
+('bx_photos_entry_edit', 'do_cancel', 2147483647, 1, 10),
+
+('bx_photos_entry_view', 'cat', 2147483647, 1, 2),
+('bx_photos_entry_view', 'added', 2147483647, 1, 3),
+('bx_photos_entry_view', 'changed', 2147483647, 1, 4);
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_photos_cats', '_bx_photos_pre_lists_cats', 'bx_photos', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_photos_cats', '', 0, '_sys_please_select', ''),
+('bx_photos_cats', '1', 1, '_bx_photos_cat_animals_and_pets', ''),
+('bx_photos_cats', '2', 2, '_bx_photos_cat_education', ''),
+('bx_photos_cats', '3', 3, '_bx_photos_cat_entertainment', ''),
+('bx_photos_cats', '4', 4, '_bx_photos_cat_film_and_animation', ''),
+('bx_photos_cats', '5', 5, '_bx_photos_cat_music', ''),
+('bx_photos_cats', '6', 6, '_bx_photos_cat_news', ''),
+('bx_photos_cats', '7', 7, '_bx_photos_cat_people_and_blogs', ''),
+('bx_photos_cats', '8', 8, '_bx_photos_cat_sports', ''),
+('bx_photos_cats', '9', 9, '_bx_photos_cat_travel', '');
+
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_photos', 'bx_photos', 'bx_photos_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-photo&id={object_id}', '', 'bx_photos_entries', 'id', 'author', 'title', 'comments', '', ''),
+('bx_photos_notes', 'bx_photos', 'bx_photos_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-photo&id={object_id}', '', 'bx_photos_entries', 'id', 'author', 'title', '', 'BxTemplCmtsNotes', '');
+
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_photos', 'bx_photos', 'bx_photos_votes', 'bx_photos_votes_track', '604800', '1', '1', '0', '1', 'bx_photos_entries', 'id', 'author', 'rate', 'votes', '', ''),
+('bx_photos_stars', 'bx_photos', 'bx_photos_svotes', 'bx_photos_svotes_track', '604800', '1', '5', '0', '1', 'bx_photos_entries', 'id', 'author', 'srate', 'svotes', 'BxPhotosVoteStars', 'modules/boonex/photos/classes/BxPhotosVoteStars.php'),
+('bx_photos_reactions', 'bx_photos', 'bx_photos_reactions', 'bx_photos_reactions_track', '604800', '1', '1', '1', '1', 'bx_photos_entries', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', '');
+
+
+-- SCORES
+INSERT INTO `sys_objects_score` (`name`, `module`, `table_main`, `table_track`, `post_timeout`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_score`, `trigger_field_cup`, `trigger_field_cdown`, `class_name`, `class_file`) VALUES 
+('bx_photos', 'bx_photos', 'bx_photos_scores', 'bx_photos_scores_track', '604800', '0', 'bx_photos_entries', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `module`, `table_main`, `table_track`, `is_on`, `base_url`, `object_comment`,  `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_photos', 'bx_photos', 'bx_photos_reports', 'bx_photos_reports_track', '1', 'page.php?i=view-photo&id={object_id}', 'bx_photos_notes', 'bx_photos_entries', 'id', 'author', 'reports', '', '');
+
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_photos', 'bx_photos', 'bx_photos_views_track', '86400', '1', 'bx_photos_entries', 'id', 'author', 'views', '', '');
+
+
+-- FAVORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `table_lists`, `is_on`, `is_undo`, `is_public`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_photos', 'bx_photos_favorites_track', 'bx_photos_favorites_lists', '1', '1', '1', 'page.php?i=view-photo&id={object_id}', 'bx_photos_entries', 'id', 'author', 'favorites', '', '');
+
+
+-- FEATURED
+INSERT INTO `sys_objects_feature` (`name`, `module`, `is_on`, `is_undo`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_flag`, `class_name`, `class_file`) VALUES 
+('bx_photos', 'bx_photos', '1', '1', 'page.php?i=view-photo&id={object_id}', 'bx_photos_entries', 'id', 'author', 'featured', '', '');
+
+
+-- CONTENT INFO
+INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_action_add`, `alert_action_update`, `alert_action_delete`, `class_name`, `class_file`) VALUES
+('bx_photos', '_bx_photos', 'bx_photos', 'added', 'edited', 'deleted', '', ''),
+('bx_photos_cmts', '_bx_photos_cmts', 'bx_photos', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_photos', 'bx_photos_administration', 'id', '', ''),
+('bx_photos', 'bx_photos_common', 'id', '', '');
+
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_photos', 'bx_photos', 'bx_photos', '_bx_photos_search_extended', 1, '', ''),
+('bx_photos_cmts', 'bx_photos_cmts', 'bx_photos', '_bx_photos_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_photos', '_bx_photos', '_bx_photos', 'bx_photos@modules/boonex/photos/|std-icon.svg');
+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`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_photos', 'content', '{url_studio}module.php?name=bx_photos', '', 'bx_photos@modules/boonex/photos/|std-icon.svg', '_bx_photos', '', '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));

+ 69 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/install/sql/uninstall.sql

@@ -0,0 +1,69 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_photos_entries`, `bx_photos_photos`, `bx_photos_media_resized`, `bx_photos_cmts`, `bx_photos_cmts_notes`, `bx_photos_votes`, `bx_photos_votes_track`, `bx_photos_svotes`, `bx_photos_svotes_track`, `bx_photos_reactions`, `bx_photos_reactions_track`, `bx_photos_views_track`, `bx_photos_meta_keywords_camera`, `bx_photos_meta_keywords`, `bx_photos_meta_locations`, `bx_photos_meta_mentions`, `bx_photos_reports`, `bx_photos_reports_track`, `bx_photos_favorites_track`, bx_photos_favorites_lists, `bx_photos_scores`, `bx_photos_scores_track`;
+
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_storage` WHERE `object` IN ('bx_photos_photos', 'bx_photos_media_resized');
+DELETE FROM `sys_storage_tokens` WHERE `object` IN ('bx_photos_photos', 'bx_photos_media_resized');
+
+DELETE FROM `sys_objects_transcoder` WHERE `object` IN('bx_photos_preview', 'bx_photos_gallery', 'bx_photos_cover');
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` IN('bx_photos_preview', 'bx_photos_gallery', 'bx_photos_cover');
+DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` IN('bx_photos_preview', 'bx_photos_gallery', 'bx_photos_cover');
+
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_photos';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_photos';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_photos';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN ('bx_photos_entry_add', 'bx_photos_entry_edit', 'bx_photos_entry_view', 'bx_photos_entry_delete', 'bx_photos_entry_upload');
+
+
+-- PRE-VALUES
+DELETE FROM `sys_form_pre_lists` WHERE `module` = 'bx_photos';
+
+DELETE FROM `sys_form_pre_values` WHERE `Key` IN('bx_photos_cats');
+
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` IN ('bx_photos', 'bx_photos_notes');
+
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` IN ('bx_photos', 'bx_photos_stars', 'bx_photos_reactions');
+
+
+-- SCORES
+DELETE FROM `sys_objects_score` WHERE `name` = 'bx_photos';
+
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `name` = 'bx_photos';
+
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name` = 'bx_photos';
+
+
+-- FAFORITES
+DELETE FROM `sys_objects_favorite` WHERE `name` = 'bx_photos';
+
+
+-- FEATURED
+DELETE FROM `sys_objects_feature` WHERE `name` = 'bx_photos';
+
+
+-- CONTENT INFO
+DELETE FROM `sys_objects_content_info` WHERE `name` IN ('bx_photos', 'bx_photos_cmts');
+
+DELETE FROM `sys_content_info_grids` WHERE `object` IN ('bx_photos');
+
+
+-- SEARCH EXTENDED
+DELETE FROM `sys_objects_search_extended` WHERE `module` = 'bx_photos';
+
+
+-- STUDIO: page & widget
+DELETE FROM `tp`, `tw`, `twb`, `tpw` 
+USING `sys_std_pages` AS `tp` LEFT JOIN `sys_std_widgets` AS `tw` ON `tp`.`id` = `tw`.`page_id` LEFT JOIN `sys_std_widgets_bookmarks` AS `twb` ON `tw`.`id` = `twb`.`widget_id` LEFT JOIN `sys_std_pages_widgets` AS `tpw` ON `tw`.`id` = `tpw`.`widget_id`
+WHERE  `tp`.`name` = 'bx_photos';

+ 13 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/template/entry-photo.html

@@ -0,0 +1,13 @@
+<div class="bx-content-description-before">__content_description_before__</div>
+<div class="bx-content-description">
+    <div class="bx-photos-entity-photo bx-def-align-center">
+        <img class="bx-def-border-radius-block" src="__entry_photo__" title="__entry_title_attr__" />
+    </div>
+    <div class="bx-base-text-entity-content bx-def-constraint-list bx-def-constraint-pre bx-def-constraint-object bx-def-constraint-iframe bx-def-constraint-img bx-def-vanilla-html max-w-none">
+        <div class="bx-base-text-title-bages">
+            <h1 class="text-ellipsis overflow-hidden">__entry_title__</h1>
+            <div class="bx-base-bages-container absolute flex -translate-y-5/4">__badges__</div>
+        </div>
+    </div>
+</div>
+<div class="bx-content-description-after">__content_description_after__</div>

+ 16 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/template/unit_full.html

@@ -0,0 +1,16 @@
+<div class="bx-base-text-unit bx-base-text-unit-ext bx-def-margin-bottom">
+    <bx_if:thumb>
+        <div class="bx-base-text-unit-cover">
+            <img class="bx-base-text-unit-cover bx-def-round-corners" alt="__title__" src="__thumb_url__" />
+        </div>
+    </bx_if:thumb>
+    <div class="bx-base-text-unit-title flex items-center space-x-2 pt-2">
+        <a href="__content_url__">__title__</a>__badges__
+    </div>
+    <div class="bx-base-text-unit-info">
+	    <bx_if:meta><div class="bx-base-general-unit-meta">__meta__</div></bx_if:meta>
+	</div>
+    <div class="bx-base-text-unit-summary bx-def-margin-sec-top bx-clearfix">
+        __text__
+    </div> 
+</div>

+ 30 - 0
modules/boonex/photos/updates/14.0.2_15.0.0/source/template/unit_gallery.html

@@ -0,0 +1,30 @@
+<div class="__class__ bx-base-text-unit bx-base-text-unit-gallery bx-def-gal-unit-size flex flex-col w-full p-2 box-border">
+    <div class="bx-base-text-unit-cnt bx-def-box bx-def-round-corners bx-def-color-bg-box bx-def-box-sizing h-full">
+        <bx_if:thumb>
+            <a href="__content_url__" onclick="__content_onclick__" title="__summary_attr__">
+                <div class="bx-base-text-unit-thumb bx-def-gal-div-size bx-def-round-corners bx-def-font-middle bg-cover bg-no-repeat bg-center" style="background-image:url(__gallery_url__)">
+                    <div class="bx-base-text-unit-strecher">__strecher__</div>
+                </div>
+            </a>
+        </bx_if:thumb>
+        <bx_if:no_thumb>
+            <div class="bx-def-gal-img-column">
+                <div class="bx-base-text-unit-no-thumb bx-def-gal-div-size bx-def-font-middle bx-def-font-grayed bx-def-padding bx-def-box-sizing">
+                    __summary_plain__
+                    <div class="bx-base-text-unit-strecher">__strecher__</div>
+                </div>
+            </div>
+        </bx_if:no_thumb>
+        <div class="bx-base-text-unit-text flex flex-col flex-1 p-3 md:p-4 lg:p-6 pt-1 md:pt-2 lg:pt-3 box-border">
+            <div class="bx-base-text-unit-badges pb-1 lg:pb-2">__badges__</div>
+            <div class="bx-base-text-unit-title flex-auto max-h-14">
+                <div class="bx-base-tut-title truncate text-left">
+                    <a href="__content_url__">__title__</a>
+                </div>
+            </div>
+            <div class="bx-base-text-unit-info bx-def-font-small">
+                <bx_if:meta><div class="bx-base-general-unit-meta">__meta__</div></bx_if:meta>
+            </div>
+        </div>
+    </div>
+</div>

+ 51 - 0
modules/boonex/plyr/updates/14.0.1_15.0.0/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Plyr',
+    'version_from' => '14.0.1',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/plyr/updates/update_14.0.1_15.0.0/',
+    'home_uri' => 'plyr_update_1401_1500',
+
+    'module_dir' => 'boonex/plyr/',
+    'module_uri' => 'plyr',
+
+    'db_prefix' => 'bx_plyr_',
+    'class_prefix' => 'BxPlyr',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Plyr',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/plyr/updates/14.0.1_15.0.0/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPlyrUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 74 - 0
modules/boonex/plyr/updates/14.0.1_15.0.0/source/install/config.php

@@ -0,0 +1,74 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Plyr Plyr player integration
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_plyr',
+    'title' => 'Plyr',
+    'note' => 'Plyr player integration.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/plyr/',
+    'home_uri' => 'plyr',
+
+    'db_prefix' => 'bx_plyr_',
+    'class_prefix' => 'BxPlyr',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Plyr',
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(),
+    
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 24 - 0
modules/boonex/plyr/updates/14.0.1_15.0.0/source/template/css/main.css

@@ -0,0 +1,24 @@
+
+.bx-player-plyr {
+    width:100%;
+}
+
+.plyr video {
+    margin-top:0;
+}
+
+.bx-page-iframe .plyr,
+.bx-page-iframe .plyr__video-wrapper,
+.bx-page-iframe .plyr video {
+    width:100vw;
+    height:100vh;
+}
+
+.bx-tl-item-attachment .bx-player-plyr-wrapper {
+    width: 100%;
+    aspect-ratio: 16 / 9;
+}
+.bx-base-general-attachment .bx-player-plyr-wrapper {
+    width:100%;
+    height:100%;
+}

+ 51 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Polls',
+    'version_from' => '14.0.2',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/polls/updates/update_14.0.2_15.0.0/',
+    'home_uri' => 'polls_update_1402_1500',
+
+    'module_dir' => 'boonex/polls/',
+    'module_uri' => 'polls',
+
+    'db_prefix' => 'bx_polls_',
+    'class_prefix' => 'BxPolls',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Polls',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPollsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 2 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/install/sql/enable.sql

@@ -0,0 +1,2 @@
+-- MENUS
+UPDATE `sys_pages_blocks` SET `designbox_id`='13' WHERE `object`='bx_polls_view_entry' AND `title`='_bx_polls_page_block_title_entry_text_and_subentries';

+ 12 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/install/sql/install.sql

@@ -0,0 +1,12 @@
+-- FORMS
+DELETE FROM `sys_form_inputs` WHERE `object`='bx_polls' AND `name` IN ('do_cancel', 'controls');
+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_polls', 'bx_polls', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_polls', 'bx_polls', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name`='bx_polls_entry_edit' AND `input_name` IN ('controls', 'do_submit', 'do_cancel');
+SET @iOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_form_display_inputs` WHERE `display_name`='bx_polls_entry_edit');
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_polls_entry_edit', 'controls', 2147483647, 1, @iOrder+1),
+('bx_polls_entry_edit', 'do_submit', 2147483647, 1, @iOrder+2),
+('bx_polls_entry_edit', 'do_cancel', 2147483647, 1, @iOrder+3);

+ 224 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/classes/BxPollsFormEntry.php

@@ -0,0 +1,224 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Polls Polls
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPollsFormEntryCheckerHelper extends BxDolFormCheckerHelper
+{
+    static public function checkAvailSubentries ($s)
+    {
+        if(bx_is_api() && is_string($s)) 
+            $s = explode(',', $s);
+
+        return !self::_isEmptyArray($s) && count($s) >= 2;
+    }
+}
+/**
+ * Create/Edit entry form
+ */
+class BxPollsFormEntry extends BxBaseModTextFormEntry
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_polls';
+        $this->_aFieldsCheckForSpam = array('subentries');
+        parent::__construct($aInfo, $oTemplate);
+    }
+
+    public function getCode($bDynamicMode = false)
+    {
+        $sJs = $this->_oModule->_oTemplate->addJs(array('form.js'), $bDynamicMode);
+
+        $sCode = '';
+        if($bDynamicMode)
+        	$sCode .= $sJs;
+
+		$sCode .= $this->_oModule->_oTemplate->getJsCode('form');
+		$sCode .= parent::getCode($bDynamicMode);
+
+        return $sCode;
+    }
+
+    function initChecker ($aValues = array (), $aSpecificValues = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(isset($this->aInputs[$CNF['FIELD_SUBENTRIES']]) && !empty($aValues['id'])) {
+            $aSubentries = $this->_oModule->_oDb->getSubentries(array(
+                'type' => 'entry_id_pairs',
+                'entry_id' => $aValues['id']
+            ));
+
+            $this->aInputs[$CNF['FIELD_SUBENTRIES']]['value'] = array_values($aSubentries);
+            $this->aInputs[$CNF['FIELD_SUBENTRIES']]['value_ids'] = array_keys($aSubentries);
+        }
+
+        return parent::initChecker($aValues, $aSpecificValues);
+    }
+
+    public function insert ($aValsToAdd = array(), $isIgnore = false)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iContentId = parent::insert($aValsToAdd, $isIgnore);
+        if(!empty($iContentId))
+            $this->processSubentriesAdd($CNF['FIELD_SUBENTRIES'], $iContentId);
+
+        return $iContentId;
+    }
+
+    public function update ($iContentId, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $iResult = parent::update($iContentId, $aValsToAdd, $aTrackTextFieldsChanges);
+
+        $this->processSubentriesUpdate($CNF['FIELD_SUBENTRIES'], $iContentId);
+
+        return $iResult;
+    }
+
+    public function getCleanValue ($sName)
+    {
+        $mixedValue = parent::getCleanValue($sName);
+        
+        if($this->_bIsApi && !empty($mixedValue) && in_array($sName, ['subentries', 'subentries_ids']))
+            $mixedValue = explode(',', $mixedValue);
+
+        return $mixedValue;
+    }
+
+    public function processSubentriesAdd ($sField, $iContentId = 0)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!isset($this->aInputs[$sField]))
+            return true;
+
+        $aSubentries = $this->getCleanValue($sField);
+        if(empty($aSubentries) || !is_array($aSubentries))
+            return true;
+
+        foreach($aSubentries as $iIndex => $sSubentry)
+            if($sSubentry != '' && get_mb_len($sSubentry) > 0)
+                $this->_oModule->_oDb->insertSubentry(array(
+                    'entry_id' => $iContentId,
+                    'title' => bx_process_input($sSubentry),
+                    'order' => $iIndex
+                ));
+
+        return true;
+    }
+
+    public function processSubentriesUpdate($sField, $iContentId = 0)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(!isset($this->aInputs[$sField]))
+            return true;
+
+        $aSubentriesIds = $this->getCleanValue($sField . '_ids');
+        $aSubentriesValues = $this->getCleanValue($sField);
+
+        //--- Remove deleted
+        $aSubentriesDb = $this->_oModule->_oDb->getSubentries(array('type' => 'entry_id_pairs', 'entry_id' => $iContentId));
+        $this->_oModule->_oDb->deleteSubentryById(array_diff(array_keys($aSubentriesDb), $aSubentriesIds));
+
+        //--- Update existed and remove empty
+        foreach($aSubentriesIds as $iIndex => $iId)
+            if($aSubentriesValues[$iIndex] != '' && get_mb_len($aSubentriesValues[$iIndex]) > 0)
+                $this->_oModule->_oDb->updateSubentry(array('title' => bx_process_input($aSubentriesValues[$iIndex])), array('id' => (int)$iId));
+            else 
+                $this->_oModule->_oDb->deleteSubentry(array('id' => (int)$iId));
+
+        //--- Add new
+        $iSubentriesIds = count($aSubentriesIds);
+        $iSubentriesValues = count($aSubentriesValues);
+        if($iSubentriesValues > $iSubentriesIds) {
+            $iMaxOrder = (int)$this->_oModule->_oDb->getSubentries(array('type' => 'entry_id_max_order', 'entry_id' => $iContentId));
+
+            $aSubentriesValues = array_slice($aSubentriesValues, $iSubentriesIds);
+            foreach($aSubentriesValues as $sSubentriesValue)
+                if($sSubentriesValue != '' && get_mb_len($sSubentriesValue) > 0)
+                    $this->_oModule->_oDb->insertSubentry(array(
+                        'entry_id' => $iContentId,
+                        'title' => bx_process_input($sSubentriesValue),
+                        'order' => ++$iMaxOrder
+                    ));
+        }
+
+        return true;
+    }
+
+    protected function genCustomInputSubentries(&$aInput)
+    {
+        if($this->_bIsApi)
+            return array_merge($aInput, [
+                'type' => 'multi_field',
+                'subtype' => 'text'
+            ]);
+
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('form');
+
+        if(!empty($aInput['value']) && is_array($aInput['value'])) {
+            $aTmplVarsSubentries = array();
+            foreach($aInput['value'] as $iKey => $sValue) {
+                $sInput = $this->genCustomInputSubentriesText($aInput, $sValue);
+                if(!empty($aInput['value_ids'][$iKey]))
+                    $sInput .= $this->genCustomInputSubentriesHidden($aInput, (int)$aInput['value_ids'][$iKey]);
+
+                $aTmplVarsSubentries[] = array('js_object' => $sJsObject, 'input_text' => $sInput);
+            }
+        }
+        else 
+            $aTmplVarsSubentries = array(
+                array('js_object' => $sJsObject, 'input_text' => $this->genCustomInputSubentriesText($aInput)),
+                array('js_object' => $sJsObject, 'input_text' => $this->genCustomInputSubentriesText($aInput))
+            );
+
+        return $this->_oModule->_oTemplate->parseHtmlByName('form_subentries.html', array(
+            'bx_repeat:subentries' => $aTmplVarsSubentries,
+            'btn_add' => $this->genCustomInputSubentriesButton($aInput)
+        ));
+    }
+    
+    protected function genCustomInputSubentriesText($aInput, $mixedValue = '')
+    {
+        $aInput['type'] = 'text';
+        $aInput['name'] .= '[]';
+        $aInput['value'] = $mixedValue;
+        $aInput['attrs']['class'] = 'bx-def-margin-sec-top-auto';
+        
+        return $this->genInput($aInput);
+    }
+
+    protected function genCustomInputSubentriesHidden($aInput, $mixedValue = '')
+    {
+        $aInput['type'] = 'hidden';
+        $aInput['name'] .= '_ids[]';
+        $aInput['value'] = $mixedValue;
+
+        return $this->genInput($aInput);
+    }
+
+    protected function genCustomInputSubentriesButton($aInput)
+    {
+        $sName = $aInput['name'];
+
+        $aInput['type'] = 'button';
+        $aInput['name'] .= '_add';
+        $aInput['value'] = _t('_bx_polls_form_entry_input_subentries_add');
+        $aInput['attrs']['class'] = 'bx-def-margin-sec-top';
+        $aInput['attrs']['onclick'] = $this->_oModule->_oConfig->getJsObject('form') . ".subentryAdd(this, '" . $sName . "');";
+
+        return $this->genInputButton($aInput);
+    }
+}
+
+/** @} */

+ 148 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/classes/BxPollsSearchResult.php

@@ -0,0 +1,148 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Polls Polls
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPollsSearchResult extends BxBaseModTextSearchResult
+{
+    protected $sUnitViewDefault = 'extended';
+
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_polls',
+            'module_name' => 'bx_polls',
+            'object_metatags' => 'bx_polls',
+            'title' => _t('_bx_polls_page_title_browse'),
+            'table' => 'bx_polls_entries',
+            'ownFields' => array('id', 'text', 'thumb', 'author', 'anonymous', 'hidden_results', 'comments', 'added'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+        		'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+        		'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+        		'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_polls_per_page_browse'), 'start' => 0),
+            'sorting' => 'last',
+            'rss' => array(
+                'title' => '',
+                'link' => '',
+                'image' => '',
+                'profile' => 0,
+                'fields' => array (
+                    'Guid' => 'link',
+                    'Link' => 'link',
+                    'Title' => 'text',
+                    'DateTimeUTS' => 'added',
+                    'Desc' => '',
+            		'Image' => 'thumb'
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_polls_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $oProfileAuthor = null;
+
+        switch ($sMode) {
+            case 'author':
+                if(!$this->_updateCurrentForAuthor($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'context':
+                if(!$this->_updateCurrentForContext($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+                
+            case 'favorite':
+                if(!$this->_updateCurrentForFavorite($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_polls_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=polls/rss/' . $sMode;
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_polls_page_title_browse_featured');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=polls/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_polls_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=polls/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'top':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP']);
+                $this->aCurrent['title'] = _t('_bx_polls_page_title_browse_top');
+                $this->aCurrent['rss']['link'] = 'modules/?r=polls/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'top';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_polls_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=polls/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_polls');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+
+    function displaySearchUnit ($aData)
+    {
+        if(empty($aData['salt']))
+            $aData['salt'] = $this->oModule->_oConfig->getSalt();
+
+        return parent::displaySearchUnit($aData);
+    }
+
+    function addCustomParts ()
+    {
+        $this->oModule->_oTemplate->addJs(array('entry.js'));
+        $this->oModule->_oTemplate->addCss(array('entry.css'));
+
+        return $this->oModule->_oTemplate->getJsCode('entry');
+    }
+}
+
+/** @} */

+ 333 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/classes/BxPollsTemplate.php

@@ -0,0 +1,333 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Polls Polls
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/*
+ * Module representation.
+ */
+class BxPollsTemplate extends BxBaseModTextTemplate
+{
+    /**
+     * Constructor
+     */
+    function __construct(&$oConfig, &$oDb)
+    {
+        $this->MODULE = 'bx_polls';
+        parent::__construct($oConfig, $oDb);
+    }
+
+    public function embedEntry($mixedContentInfo, $aParams = array())
+    {
+        $oModule = $this->getModule();
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $aContentInfo = is_array($mixedContentInfo) ? $mixedContentInfo : $this->_oDb->getContentInfoById((int)$mixedContentInfo);
+        if(empty($aContentInfo) || !is_array($aContentInfo))
+            return;
+
+        /**
+         * Anonymous voting MUST be enabled for Embeded poll,
+         * because a list of voters cannot be correctly displayed
+         * in Embeded iframe.
+         */
+        $aContentInfo[$CNF['FIELD_ANONYMOUS_VOTING']] = 1;
+
+        $aBlock = $this->{$oModule->isPerformed((int)$aContentInfo[$CNF['FIELD_ID']]) ? 'entryResults' : 'entrySubentries'}($aContentInfo);
+
+        $this->addJs(array('entry.js'));
+        $this->addCss(array('entry.css'));
+
+        $oTemplate = BxDolTemplate::getInstance();
+        $oTemplate->addCssStyle($CNF['STYLES_POLLS_EMBED_CLASS'], $CNF['STYLES_POLLS_EMBED_CONTENT']);
+        $oTemplate->setPageNameIndex(BX_PAGE_EMBED);
+        $oTemplate->setPageHeader($this->getTitleAuto($aContentInfo));
+        $oTemplate->setPageContent('page_main_code', $this->getJsCode('entry', array(
+            'bEmbed' => true
+        )) . $aBlock['content']);
+        $oTemplate->getPageCode();
+        exit;
+    }
+
+    public function getJsCode($sType, $aParams = array(), $bWrap = true)
+    {
+        $aParams = array_merge(array(
+            'aHtmlIds' => $this->_oConfig->getHtmlIds()
+        ), $aParams);
+
+        return parent::getJsCode($sType, $aParams, $bWrap);
+    }
+
+    public function entrySubentries ($aData, $bDynamic = false)
+    {
+        $mixedContent = $this->_getGetBlockContentSubentries($aData, $bDynamic);
+        if($this->_bIsApi)
+            return $mixedContent;
+
+        if(empty($mixedContent))
+            return '';
+
+    	return array(
+            'content' => $mixedContent,
+            'menu' => $this->_getGetBlockMenu($aData, 'subentries')
+        );
+    }
+
+    public function entryResults($aData, $bDynamic = false)
+    {
+        $mixedContent = $this->_getGetBlockContentResults($aData, $bDynamic);
+        if($this->_bIsApi)
+            return $mixedContent;
+
+        if(empty($mixedContent))
+            return '';
+
+        return array(
+            'content' => $mixedContent,
+            'menu' => $this->_getGetBlockMenu($aData, 'results')
+        );
+    }
+
+    public function entryTextAndSubentries($aData, $bForceDisplaySubentries = false)
+    {
+        $oModule = $this->getModule();
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $aTmplVars = parent::getTmplVarsText($aData);
+
+        if($this->_bIsApi) {
+            $bPerformed = $oModule->isPerformed($aData['id']);
+
+            return [
+                'id' => $aData['id'],
+                'title' => $this->_oConfig->getTitle($aData),
+                'image' => !empty($aTmplVars['image']) ? $aTmplVars['image'] : '',
+                'object' => $CNF['OBJECT_VOTES_SUBENTRIES'],
+                'subentries' => $this->_getGetBlockContentSubentries($aData),
+                'results' => $this->_getGetBlockContentResults($aData),
+                'is_hidden_results' => (int)$aData[$CNF['FIELD_HIDDEN_RESULTS']] == 1,
+                'is_performed' => $bPerformed,
+                'value' => $bPerformed ? $oModule->getPerformedValue($aData['id']) : 0
+            ];
+        }
+
+        $sMethod = '_getGetBlockContent';
+        $sMenuItem = '';
+        if(!$bForceDisplaySubentries && $oModule->isPerformed($aData[$CNF['FIELD_ID']])) {
+            $sMethod .= 'Results';
+            $sMenuItem = 'results';
+        }
+        else {
+            $sMethod .= 'Subentries';
+            $sMenuItem = 'subentries';
+        };
+
+        $sSubentries = $this->$sMethod($aData);
+
+        $aTmplVars = array_merge($aTmplVars, array(
+            'menu' => 'delete',
+            'bx_if:show_subentries' => array(
+                'condition' => !empty($sSubentries),
+                'content' => array(
+                    'entry_subentries' => $sSubentries
+                )
+            )
+        ));
+
+        return array(
+            'content' => $this->parseHtmlByName('entry-text-subentries.html', $aTmplVars),
+            'menu' => $this->_getGetBlockMenu($aData, $sMenuItem)
+        );
+    }
+
+    public function getTitleAuto($aData, $iMaxLen = 32, $sEllipsisSign = '...')
+    {
+        $sResult = $this->getTitle($aData);
+        if(strlen($sResult) > 0 && $iMaxLen > 0)
+            $sResult = strmaxtextlen($sResult, $iMaxLen, $sEllipsisSign);
+
+        return $sResult;
+    }
+
+    public function getTitle($aData, $mixedProcessOutput = BX_DATA_TEXT)
+    {
+        $sResult = $this->_oConfig->getTitle($aData);
+        if($mixedProcessOutput !== false && !empty($sResult))
+            $sResult = bx_process_output($sResult, (int)$mixedProcessOutput);
+
+        return $sResult;
+    }
+
+    protected function getSummary($aData, $sTitle = '', $sText = '', $sUrl = '')
+    {
+        $oModule = $this->getModule();
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $aBlock = $this->{$oModule->isPerformed($aData[$CNF['FIELD_ID']]) ? 'entryResults' : 'entrySubentries'}($aData);
+
+        return $aBlock['content'];
+    }
+
+    protected function getUnit ($aData, $aParams = [])
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $aResult = parent::getUnit($aData, $aParams);
+
+        $sTemplate = 'unit';
+        if(isset($aParams['template_name']))
+            $sTemplate = $this->_getUnitName($aData, $aParams['template_name']);
+
+        if(in_array($sTemplate, ['unit', 'unit_full']) && $aResult['bx_if:thumb']['condition']) {
+            $oImagesTranscoder = BxDolTranscoderImage::getObjectInstance($CNF['OBJECT_IMAGES_TRANSCODER_COVER']);
+            if($oImagesTranscoder && ($sPhotoCover = $oImagesTranscoder->getFileUrl($aData[$CNF['FIELD_THUMB']])))
+                $aResult['bx_if:thumb']['content'] = array_merge($aResult['bx_if:thumb']['content'], [
+                    'thumb_url' => $sPhotoCover,
+                    'gallery_url' => $sPhotoCover
+                ]);
+        }
+
+        if(($oMenuMeta = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SNIPPET_META'], $this)) !== false) {
+            $oMenuMeta->setContent($aData);
+
+            $aResult = array_merge($aResult, [
+                'bx_if:meta' => [
+                    'condition' => true,
+                    'content' => [
+                        'meta' => $oMenuMeta->getCode()
+                    ]
+                ],
+            ]);
+        }
+
+        return $aResult;
+    }
+
+    protected function getUnitThumbAndGallery ($aData)
+    {
+        list($sPhotoThumb, $sPhotoGallery) = parent::getUnitThumbAndGallery($aData);
+
+        return array($sPhotoGallery, $sPhotoGallery);
+    }
+
+    protected function _getGetBlockMenu($aData, $sSelected = '')
+    {
+        $oModule = $this->getModule();
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $sJsObject = $this->_oConfig->getJsObject('entry');
+        $iContentId = $aData[$CNF['FIELD_ID']];
+
+        $aBlocks = array(
+            'subentries' => true, 
+            'results' => (int)$aData[$CNF['FIELD_HIDDEN_RESULTS']] == 0 || $oModule->isPerformed($iContentId)
+        );
+
+        $aMenu = array();
+        foreach($aBlocks as $sBlock => $bActive) {
+            if(!$bActive) 
+                continue;
+
+            $sId = $this->_oConfig->getHtmlIds('block_link_' . $sBlock) . $aData['salt'];
+            if(!empty($sSelected) && $sSelected == $sBlock)
+                $sSelected = $sId;
+
+            $aMenu[] = array('id' => $sId, 'name' => $sId, 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:' . $sJsObject . '.changeBlock(this, \'' . $sBlock . '\', ' . bx_js_string(json_encode(array('content_id' => $iContentId, 'salt' => $aData['salt']))) . ')', 'target' => '_self', 'title' => _t('_bx_polls_menu_item_view_' . $sBlock));
+        }
+
+        if(count($aMenu) <= 1)
+            return '';
+
+        $sMenu = $this->_oConfig->getHtmlIds('block_menu');
+        $oMenu = new BxTemplMenuInteractive(array('object' => $sMenu, 'menu_id' => $sMenu . '-' . $aData['salt'], 'menu_items' => $aMenu, 'template' => 'menu_interactive_vertical.html'));
+        if(!empty($sSelected))
+            $oMenu->setSelected('', $sSelected);
+
+        return $oMenu;
+    }
+    
+    protected function _getGetBlockContentSubentries($aData, $bDynamic = false)
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $aSubentries = $this->_oDb->getSubentries(array('type' => 'entry_id', 'entry_id' => $aData[$CNF['FIELD_ID']]));
+		if($this->_bIsApi)
+            return $aSubentries;
+
+        if(empty($aSubentries) || !is_array($aSubentries))
+            return '';
+
+        $aTmplVarsSubentries = array();
+        foreach($aSubentries as $aSubentry) {
+            $oVotes = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_SUBENTRIES'], $aSubentry['id']);
+            $oVotes->setEntry($aData);
+
+            $aTmplVarsSubentries[] = array(
+                'subentry' => $oVotes->getElementBlock(array(
+                    'dynamic_mode' => $bDynamic
+                ))
+            );
+        }
+
+    	return $this->parseHtmlByName('subentries.html', array(
+            'html_id' => $this->_oConfig->getHtmlIds('content') . $aData[$CNF['FIELD_ID']],
+            'bx_repeat:subentries' => $aTmplVarsSubentries,
+            'bx_if:show_public' => array(
+                'condition' => (int)$aData[$CNF['FIELD_ANONYMOUS_VOTING']] == 0,
+                'content' => array()
+            )
+        ));
+    }
+    
+    protected function _getGetBlockContentResults($aData, $bDynamic = false)
+    {
+        $oModule = $this->getModule();
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $bAnonymous = (int)$aData[$CNF['FIELD_ANONYMOUS_VOTING']] == 1;
+        $bHiddenResults = (int)$aData[$CNF['FIELD_HIDDEN_RESULTS']] == 1;
+
+        $iContentId = (int)$aData[$CNF['FIELD_ID']];
+        $aSubentries = $this->_oDb->getSubentries(['type' => 'entry_id', 'entry_id' => $iContentId]);
+        if(empty($aSubentries) || !is_array($aSubentries))
+            return $this->_bIsApi ? [] : '';
+
+        if($bHiddenResults && !$oModule->isPerformed($iContentId))
+            return $this->_bIsApi ? [] : '';
+        
+        $iTotal = 0;
+        foreach($aSubentries as $aSubentry)
+            $iTotal += $aSubentry['votes'];
+
+        $aTmplVarsSubentries = array();
+        foreach($aSubentries as $aSubentry) {
+            $oVotes = BxDolVote::getObjectInstance($CNF['OBJECT_VOTES_SUBENTRIES'], $aSubentry['id']);
+            $oVotes->setEntry($aData);
+
+            $fPercent = $iTotal > 0 ? 100 * (float)$aSubentry['votes']/$iTotal : 0;
+            $aTmplVarsSubentries[] = array_merge([
+                'title' => bx_process_output($aSubentry['title']),
+                'width' => (int)round($fPercent) . '%',
+                'percent' => _t('_bx_polls_txt_subentry_vote_percent', $iTotal > 0 ? round($fPercent, 2) : 0),
+            ], ($this->_bIsApi ? [
+                'votes' => $oVotes->getCounterAPI(['show_counter_empty' => true, 'show_counter_in_brackets' => false]),
+            ] : [
+                'votes' => $oVotes->getCounter(['show_counter_empty' => true, 'show_counter_in_brackets' => false]),
+                'js_code' => $oVotes->getJsScript(['dynamic_mode' => $bDynamic])
+            ]));
+        }
+
+        return $this->_bIsApi ? $aTmplVarsSubentries : $this->parseHtmlByName('subentries_results.html', array(
+            'html_id' => $this->_oConfig->getHtmlIds('content') . $iContentId,
+            'bx_repeat:subentries' => $aTmplVarsSubentries,
+        ));
+    }
+}
+
+/** @} */

+ 136 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/install/config.php

@@ -0,0 +1,136 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Polls Polls
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_polls',
+    'title' => 'Polls',
+    'note' => 'Basic poll module.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/polls/',
+    'home_uri' => 'polls',
+
+    'db_prefix' => 'bx_polls_',
+    'class_prefix' => 'BxPolls',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Polls',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+    	'trigger_profile_view_submenu',
+        'trigger_group_view_submenu'
+    ),
+
+	/**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+    	'bx_polls_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_polls_preview',
+        'bx_polls_gallery',
+        'bx_polls_cover'
+    ),
+
+	/**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_polls',
+    	'bx_polls_cmts',
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 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,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 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(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 71 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/install/sql/enable-app.sql

@@ -0,0 +1,71 @@
+-- PAGES: config_api
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'post\',\r\n    top: true,\r\n    blocks: {\r\n        author: {\r\n            name: \'bx_polls:entity_author\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n            forHeader: true,\r\n        },\r\n        text: {\r\n            name: \'bx_polls:get_block_text_and_subentries\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        attachments: {\r\n            name: \'bx_polls:entity_attachments\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        actions: {\r\n            name: \'bx_polls:entity_all_actions\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        \'comments-empty\': {\r\n            name: \'static:comments_empty\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        comments: {\r\n            name: \'bx_polls:entity_comments\',\r\n            showTitle: false,\r\n            showBg: false,\r\n        },\r\n    },\r\n    headerSettings: {\r\n        header: false,\r\n        footer: false,\r\n        offset: false,\r\n        backButton: true,\r\n        title: false,\r\n    },\r\n}' WHERE `object`='bx_polls_view_entry';
+
+-- PAGES: active_api
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_create_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_create_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_edit_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_edit_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_delete_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_delete_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_entry_text_and_subentries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_entry_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_sys_entry_context' AND `title`='_bx_polls_page_block_title_entry_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_entry_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_entry_all_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_entry_comments';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_entry_location';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_featured_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_view_entry_comments' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_entry_comments' AND `title`='_bx_polls_page_block_title_entry_comments_link';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_popular' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_popular_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_top' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_top_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_updated' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_updated_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_author' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_entries_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_author' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_sys_favorites_of_author' AND `title`='_bx_polls_page_block_title_favorites_of_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_author' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_sys_entries_of_author' AND `title`='_bx_polls_page_block_title_entries_of_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_author' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_sys_entries_in_context' AND `title`='_bx_polls_page_block_title_entries_in_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_favorites' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_sys_favorites_entries' AND `title`='_bx_polls_page_block_title_favorites_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_favorites' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_favorites_entries_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_favorites' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_favorites_entries_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_context' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_sys_entries_in_context' AND `title`='_bx_polls_page_block_title_entries_in_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_home' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_recent_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_search' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_search_form';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_search' AND `module`='bx_polls' AND `title_system`='' AND `title`='_bx_polls_page_block_title_search_results';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_manage' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_system_manage' AND `title`='_bx_polls_page_block_title_manage';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_polls_administration' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_system_manage_administration' AND `title`='_bx_polls_page_block_title_manage';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_persons_view_profile' AND `module`='bx_polls' AND `title_system`='_bx_polls_page_block_title_sys_my_entries' AND `title`='_bx_polls_page_block_title_my_entries';
+
+
+-- MENUS:
+
+-- MENUS: config_api
+
+-- MENUS: active_api
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_homepage' AND `module`='bx_polls' AND `name`='polls-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_add_content_links' AND `module`='bx_polls' AND `name`='create-poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_polls' AND `name`='profile-stats-my-polls';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_account_dashboard_manage_tools' AND `module`='bx_polls' AND `name`='polls-administration';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view' AND `module`='bx_polls' AND `name`='edit-poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view' AND `module`='bx_polls' AND `name`='delete-poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view' AND `module`='bx_polls' AND `name`='approve';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='edit-poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='delete-poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='approve';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='view';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='reaction';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='score';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='favorite';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='feature';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='repost';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='report';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='notes';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='audit';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='social-sharing';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_view_actions' AND `module`='bx_polls' AND `name`='more-auto';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_my' AND `module`='bx_polls' AND `name`='create-poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_submenu' AND `module`='bx_polls' AND `name`='polls-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_submenu' AND `module`='bx_polls' AND `name`='polls-popular';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_submenu' AND `module`='bx_polls' AND `name`='polls-top';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_submenu' AND `module`='bx_polls' AND `name`='polls-search';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_submenu' AND `module`='bx_polls' AND `name`='polls-manage';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_snippet_meta' AND `module`='bx_polls' AND `name`='date';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_snippet_meta' AND `module`='bx_polls' AND `name`='comments';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_snippet_meta' AND `module`='bx_polls' AND `name`='author';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_polls_snippet_meta' AND `module`='bx_polls' AND `name`='actions';

+ 478 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/install/sql/enable.sql

@@ -0,0 +1,478 @@
+
+-- 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_polls', '_bx_polls', 'bx_polls@modules/boonex/polls/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_polls', '_bx_polls', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_polls_enable_auto_approve', 'on', @iCategId, '_bx_polls_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_polls_title_chars', '200', @iCategId, '_bx_polls_option_title_chars', 'digit', '', '', '', 1),
+('bx_polls_per_page_browse', '12', @iCategId, '_bx_polls_option_per_page_browse', 'digit', '', '', '', 10),
+('bx_polls_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 15),
+('bx_polls_per_page_for_favorites_lists', '5', @iCategId, '_bx_polls_option_per_page_for_favorites_lists', 'digit', '', '', '', 17),
+('bx_polls_rss_num', '10', @iCategId, '_bx_polls_option_rss_num', 'digit', '', '', '', 20),
+('bx_polls_searchable_fields', 'text', @iCategId, '_bx_polls_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:8:"bx_polls";s:6:"method";s:21:"get_searchable_fields";}', 30);
+
+
+-- 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_polls_create_entry', '_bx_polls_page_title_sys_create_entry', '_bx_polls_page_title_create_entry', 'bx_polls', 5, 2147483647, 1, 'create-poll', 'page.php?i=create-poll', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_polls_create_entry', 1, 'bx_polls', '_bx_polls_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_polls";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_polls_edit_entry', '_bx_polls_page_title_sys_edit_entry', '_bx_polls_page_title_edit_entry', 'bx_polls', 5, 2147483647, 1, 'edit-poll', '', '', '', '', 0, 1, 0, 'BxPollsPageEntry', 'modules/boonex/polls/classes/BxPollsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_polls_edit_entry', 1, 'bx_polls', '_bx_polls_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_polls";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_polls_delete_entry', '_bx_polls_page_title_sys_delete_entry', '_bx_polls_page_title_delete_entry', 'bx_polls', 5, 2147483647, 1, 'delete-poll', '', '', '', '', 0, 1, 0, 'BxPollsPageEntry', 'modules/boonex/polls/classes/BxPollsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_polls_delete_entry', 1, 'bx_polls', '_bx_polls_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_polls";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_polls_view_entry', '_bx_polls_page_title_sys_view_entry', '_bx_polls_page_title_view_entry', 'bx_polls', 12, 2147483647, 1, 'view-poll', '', '', '', '', 0, 1, 0, 'BxPollsPageEntry', 'modules/boonex/polls/classes/BxPollsPageEntry.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_polls_view_entry', 2, 'bx_polls', '', '_bx_polls_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 0, 0),
+('bx_polls_view_entry', 2, 'bx_polls', '', '_bx_polls_page_block_title_entry_text_and_subentries', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:29:\"get_block_text_and_subentries\";}', 0, 0, 1, 2),
+('bx_polls_view_entry', 1, 'bx_polls', '', '_bx_polls_page_block_title_entry_subentries', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:20:\"get_block_subentries\";}', 0, 0, 0, 0),
+('bx_polls_view_entry', 2, 'bx_polls', '', '_bx_polls_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:13:\"entity_author\";}', 0, 0, 1, 1),
+('bx_polls_view_entry', 3, 'bx_polls', '_bx_polls_page_block_title_sys_entry_context', '_bx_polls_page_block_title_entry_context', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:14:\"entity_context\";}', 0, 0, 1, 1),
+('bx_polls_view_entry', 3, 'bx_polls', '', '_bx_polls_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 2),
+('bx_polls_view_entry', 3, 'bx_polls', '', '_bx_polls_page_block_title_entry_location', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:15:\"entity_location\";}', 0, 0, 0, 0),
+('bx_polls_view_entry', 2, 'bx_polls', '', '_bx_polls_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:18:\"entity_all_actions\";}', 0, 0, 1, 3),
+('bx_polls_view_entry', 4, 'bx_polls', '', '_bx_polls_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:14:\"entity_actions\";}', 0, 0, 0, 0),
+('bx_polls_view_entry', 4, 'bx_polls', '', '_bx_polls_page_block_title_entry_social_sharing', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:21:\"entity_social_sharing\";}', 0, 0, 0, 0),
+('bx_polls_view_entry', 4, 'bx_polls', '', '_bx_polls_page_block_title_entry_attachments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:18:\"entity_attachments\";}', 0, 0, 0, 0),
+('bx_polls_view_entry', 2, 'bx_polls', '', '_bx_polls_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 1, 4),
+('bx_polls_view_entry', 3, 'bx_polls', '', '_bx_polls_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:8:\"bx_polls\";i:1;s:4:\"{id}\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 0, 1, 3),
+('bx_polls_view_entry', 3, 'bx_polls', '', '_bx_polls_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 0, 1, 4),
+('bx_polls_view_entry', 2, 'bx_polls', '', '_bx_polls_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+
+
+-- 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_polls_view_entry_comments', '_bx_polls_page_title_sys_view_entry_comments', '_bx_polls_page_title_view_entry_comments', 'bx_polls', 5, 2147483647, 1, 'view-poll-comments', '', '', '', '', 0, 1, 0, 'BxPollsPageEntry', 'modules/boonex/polls/classes/BxPollsPageEntry.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_polls_view_entry_comments', 1, 'bx_polls', '_bx_polls_page_block_title_entry_comments', '_bx_polls_page_block_title_entry_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 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_polls_popular', '_bx_polls_page_title_sys_entries_popular', '_bx_polls_page_title_entries_popular', 'bx_polls', 5, 2147483647, 1, 'polls-popular', 'page.php?i=polls-popular', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_polls_popular', 1, 'bx_polls', '_bx_polls_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:14:"browse_popular";s:6:"params";a:3:{s:9:"unit_view";s:8:"extended";s:13:"empty_message";b:1;s:13:"ajax_paginate";b:0;}}', 0, 1, 1);
+
+
+-- PAGE: top 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_polls_top', '_bx_polls_page_title_sys_entries_top', '_bx_polls_page_title_entries_top', 'bx_polls', 5, 2147483647, 1, 'polls-top', 'page.php?i=polls-top', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_polls_top', 1, 'bx_polls', '_bx_polls_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:10:"browse_top";s:6:"params";a:3:{s:9:"unit_view";s:8:"extended";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_polls_updated', '_bx_polls_page_title_sys_entries_updated', '_bx_polls_page_title_entries_updated', 'bx_polls', 5, 2147483647, 1, 'polls-updated', 'page.php?i=polls-updated', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_polls_updated', 1, 'bx_polls', '_bx_polls_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:14:"browse_updated";s:6:"params";a:3:{s:9:"unit_view";s:8:"extended";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_polls_author', 'polls-author', '_bx_polls_page_title_sys_entries_of_author', '_bx_polls_page_title_entries_of_author', 'bx_polls', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxPollsPageAuthor', 'modules/boonex/polls/classes/BxPollsPageAuthor.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_polls_author', 1, 'bx_polls', '', '_bx_polls_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:18:\"my_entries_actions\";}', 0, 0, 1, 1),
+('bx_polls_author', 1, 'bx_polls', '_bx_polls_page_block_title_sys_favorites_of_author', '_bx_polls_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:21:"browse_favorite_lists";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1, 2),
+('bx_polls_author', 1, 'bx_polls', '_bx_polls_page_block_title_sys_entries_of_author', '_bx_polls_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:13:\"browse_author\";}', 0, 0, 1, 3),
+('bx_polls_author', 1, 'bx_polls', '_bx_polls_page_block_title_sys_entries_in_context', '_bx_polls_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:14:"browse_context";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";i:0;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 1, 4);
+
+
+-- PAGE: favorites by list
+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_polls_favorites', '_bx_polls_page_title_sys_entries_favorites', '_bx_polls_page_title_entries_favorites', 'bx_polls', 12, 2147483647, 1, 'polls-favorites', 'page.php?i=polls-favorites', '', '', '', 0, 1, 0, 'BxPollsPageListEntry', 'modules/boonex/polls/classes/BxPollsPageListEntry.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_polls_favorites', 2, 'bx_polls', '_bx_polls_page_block_title_sys_favorites_entries', '_bx_polls_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:15:"browse_favorite";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1),
+('bx_polls_favorites', 3, 'bx_polls', '', '_bx_polls_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_polls";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_polls_favorites', 3, 'bx_polls', '', '_bx_polls_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_polls";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+
+-- PAGE: entries in context
+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_polls_context', 'polls-context', '_bx_polls_page_title_sys_entries_in_context', '_bx_polls_page_title_entries_in_context', 'bx_polls', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxPollsPageAuthor', 'modules/boonex/polls/classes/BxPollsPageAuthor.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_polls_context', 1, 'bx_polls', '_bx_polls_page_block_title_sys_entries_in_context', '_bx_polls_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:14:\"browse_context\";}', 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_polls_home', 'polls-home', '_bx_polls_page_title_sys_home', '_bx_polls_page_title_home', 'bx_polls', 2, 2147483647, 1, 'page.php?i=polls-home', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.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_polls_home', 1, 'bx_polls', '', '_bx_polls_page_block_title_featured_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1, 0),
+('bx_polls_home', 1, 'bx_polls', '', '_bx_polls_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1, 1),
+('bx_polls_home', 2, 'bx_polls', '', '_bx_polls_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:8:\"bx_polls\";i:1;s:8:\"bx_polls\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 1, 1, 0),
+('bx_polls_home', 2, 'bx_polls', '', '_bx_polls_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:13:\"bx_polls_cats\";i:1;a:1:{s:10:\"show_empty\";b:1;}}s:5:\"class\";s:20:\"TemplServiceCategory\";}', 0, 1, 1, 1);
+
+-- PAGE: search for 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_polls_search', '_bx_polls_page_title_sys_entries_search', '_bx_polls_page_title_entries_search', 'bx_polls', 5, 2147483647, 1, 'polls-search', 'page.php?i=polls-search', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_polls_search', 1, 'bx_polls', '_bx_polls_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:8:"bx_polls";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_polls_search', 1, 'bx_polls', '_bx_polls_page_block_title_search_results', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:27:"get_results_search_extended";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:8:"bx_polls";s:10:"show_empty";b:1;}}}', 0, 1, 1, 2),
+('bx_polls_search', 1, 'bx_polls', '_bx_polls_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:13:"bx_polls_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_polls_search', 1, 'bx_polls', '_bx_polls_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:13:"bx_polls_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+-- 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_polls_manage', '_bx_polls_page_title_sys_manage', '_bx_polls_page_title_manage', 'bx_polls', 5, 2147483647, 1, 'polls-manage', 'page.php?i=polls-manage', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.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_polls_manage', 1, 'bx_polls', '_bx_polls_page_block_title_system_manage', '_bx_polls_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_polls\";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_polls_administration', '_bx_polls_page_title_sys_manage_administration', '_bx_polls_page_title_manage', 'bx_polls', 5, 192, 1, 'polls-administration', 'page.php?i=polls-administration', '', '', '', 0, 1, 0, 'BxPollsPageBrowse', 'modules/boonex/polls/classes/BxPollsPageBrowse.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_polls_administration', 1, 'bx_polls', '_bx_polls_page_block_title_system_manage_administration', '_bx_polls_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_polls\";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_polls', '_bx_polls_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:13:"browse_public";s:6:"params";a:2:{i:0;b:0;i:1;b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1);
+
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 3;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_polls', '_bx_polls_page_block_title_sys_my_entries', '_bx_polls_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:1:{s:13:"empty_message";b:0;}}}}', 0, 0, 0);
+
+
+-- 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_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('', 0, 'bx_polls', '', '_bx_polls_page_block_title_recent_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 1),
+('', 0, 'bx_polls', '', '_bx_polls_page_block_title_popular_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_polls";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 2),
+('', 0, 'bx_polls', '_bx_polls_page_block_title_sys_recent_entries_view_showcase', '_bx_polls_page_block_title_recent_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:13:\"browse_public\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 3),
+('', 0, 'bx_polls', '_bx_polls_page_block_title_sys_popular_entries_view_showcase', '_bx_polls_page_block_title_popular_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, 'bx_polls', '_bx_polls_page_block_title_sys_featured_entries_view_showcase', '_bx_polls_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_polls\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 5);
+
+
+-- MENU: add to site menu
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 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_polls', 'polls-home', '_bx_polls_menu_item_title_system_entries_home', '_bx_polls_menu_item_title_entries_home', 'page.php?i=polls-home', '', '', 'tasks col-green1', 'bx_polls_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_polls', 'polls-home', '_bx_polls_menu_item_title_system_entries_home', '_bx_polls_menu_item_title_entries_home', 'page.php?i=polls-home', '', '', 'tasks col-green1', 'bx_polls_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_polls', 'create-poll', '_bx_polls_menu_item_title_system_create_entry', '_bx_polls_menu_item_title_create_entry', 'page.php?i=create-poll', '', '', 'tasks col-green1', '', 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_polls_view', '_bx_polls_menu_title_view_entry', 'bx_polls_view', 'bx_polls', 9, 0, 1, 'BxPollsMenuView', 'modules/boonex/polls/classes/BxPollsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_polls_view', 'bx_polls', '_bx_polls_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_polls_view', 'bx_polls', 'edit-poll', '_bx_polls_menu_item_title_system_edit_entry', '_bx_polls_menu_item_title_edit_entry', 'page.php?i=edit-poll&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 1),
+('bx_polls_view', 'bx_polls', 'delete-poll', '_bx_polls_menu_item_title_system_delete_entry', '_bx_polls_menu_item_title_delete_entry', 'page.php?i=delete-poll&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 2),
+('bx_polls_view', 'bx_polls', 'approve', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, 1, 0, 3);
+
+-- MENU: all 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_polls_view_actions', '_sys_menu_title_view_actions', 'bx_polls_view_actions', 'bx_polls', 15, 0, 1, 'BxPollsMenuViewActions', 'modules/boonex/polls/classes/BxPollsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_polls_view_actions', 'bx_polls', '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('bx_polls_view_actions', 'bx_polls', 'edit-poll', '_bx_polls_menu_item_title_system_edit_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 10),
+('bx_polls_view_actions', 'bx_polls', 'delete-poll', '_bx_polls_menu_item_title_system_delete_entry', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 20),
+('bx_polls_view_actions', 'bx_polls', 'approve', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 30),
+('bx_polls_view_actions', 'bx_polls', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 200),
+('bx_polls_view_actions', 'bx_polls', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 210),
+('bx_polls_view_actions', 'bx_polls', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, 0, 0, 220),
+('bx_polls_view_actions', 'bx_polls', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 225),
+('bx_polls_view_actions', 'bx_polls', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 230),
+('bx_polls_view_actions', 'bx_polls', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 240),
+('bx_polls_view_actions', 'bx_polls', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 250),
+('bx_polls_view_actions', 'bx_polls', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 260),
+('bx_polls_view_actions', 'bx_polls', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 270),
+('bx_polls_view_actions', 'bx_polls', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, 1, 0, 280),
+('bx_polls_view_actions', 'bx_polls', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_polls&content_id={content_id}', '', '', 'history', '', '', 0, 192, 1, 0, 290),
+('bx_polls_view_actions', 'bx_polls', 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, 1, 0, 300),
+('bx_polls_view_actions', 'bx_polls', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, 1, 0, 9999);
+
+-- 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_polls_my', '_bx_polls_menu_title_entries_my', 'bx_polls_my', 'bx_polls', 9, 0, 1, 'BxPollsMenu', 'modules/boonex/polls/classes/BxPollsMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_polls_my', 'bx_polls', '_bx_polls_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_polls_my', 'bx_polls', 'create-poll', '_bx_polls_menu_item_title_system_create_entry', '_bx_polls_menu_item_title_create_entry', 'page.php?i=create-poll', '', '', '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_polls_submenu', '_bx_polls_menu_title_submenu', 'bx_polls_submenu', 'bx_polls', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_polls_submenu', 'bx_polls', '_bx_polls_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_polls_submenu', 'bx_polls', 'polls-home', '_bx_polls_menu_item_title_system_entries_public', '_bx_polls_menu_item_title_entries_public', 'page.php?i=polls-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_polls_submenu', 'bx_polls', 'polls-popular', '_bx_polls_menu_item_title_system_entries_popular', '_bx_polls_menu_item_title_entries_popular', 'page.php?i=polls-popular', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_polls_submenu', 'bx_polls', 'polls-top', '_bx_polls_menu_item_title_system_entries_top', '_bx_polls_menu_item_title_entries_top', 'page.php?i=polls-top', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_polls_submenu', 'bx_polls', 'polls-search', '_bx_polls_menu_item_title_system_entries_search', '_bx_polls_menu_item_title_entries_search', 'page.php?i=polls-search', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_polls_submenu', 'bx_polls', 'polls-manage', '_bx_polls_menu_item_title_system_entries_manage', '_bx_polls_menu_item_title_entries_manage', 'page.php?i=polls-manage', '', '', '', '', 2147483646, 1, 1, 5);
+
+-- 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_polls_view_submenu', '_bx_polls_menu_title_view_entry_submenu', 'bx_polls_view_submenu', 'bx_polls', 8, 0, 1, 'BxPollsMenuView', 'modules/boonex/polls/classes/BxPollsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_polls_view_submenu', 'bx_polls', '_bx_polls_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_polls_view_submenu', 'bx_polls', 'view-poll', '_bx_polls_menu_item_title_system_view_entry', '_bx_polls_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-poll&id={content_id}', '', '', '', '', 2147483647, 0, 0, 1),
+('bx_polls_view_submenu', 'bx_polls', 'view-poll-comments', '_bx_polls_menu_item_title_system_view_entry_comments', '_bx_polls_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-poll-comments&id={content_id}', '', '', '', '', 2147483647, 0, 0, 2);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_polls_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_polls_snippet_meta', 'bx_polls', 15, 0, 1, 'BxPollsMenuSnippetMeta', 'modules/boonex/polls/classes/BxPollsMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_polls_snippet_meta', 'bx_polls', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_polls_snippet_meta', 'bx_polls', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_polls_snippet_meta', 'bx_polls', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_polls_snippet_meta', 'bx_polls', 'author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 1, 0, 1, 3),
+('bx_polls_snippet_meta', 'bx_polls', 'category', '_sys_menu_item_title_system_sm_category', '_sys_menu_item_title_sm_category', '', '', '', '', '', 2147483647, 0, 0, 1, 4),
+('bx_polls_snippet_meta', 'bx_polls', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, 0, 0, 1, 5),
+('bx_polls_snippet_meta', 'bx_polls', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 0, 0, 1, 6),
+('bx_polls_snippet_meta', 'bx_polls', 'actions', '_sys_menu_item_title_system_sm_actions', '_sys_menu_item_title_sm_actions', '', '', '', '', '', 2147483647, 1, 0, 1, 7);
+
+-- 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_polls', 'profile-stats-my-polls', '_bx_polls_menu_item_title_system_manage_my_polls', '_bx_polls_menu_item_title_manage_my_polls', 'page.php?i=polls-author&profile_id={member_id}', '', '_self', 'tasks col-green1', 'a:2:{s:6:"module";s:8:"bx_polls";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_polls_menu_manage_tools', '_bx_polls_menu_title_manage_tools', 'bx_polls_menu_manage_tools', 'bx_polls', 6, 0, 1, 'BxPollsMenuManageTools', 'modules/boonex/polls/classes/BxPollsMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_polls_menu_manage_tools', 'bx_polls', '_bx_polls_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_polls_menu_manage_tools', 'bx_polls', 'delete-with-content', '_bx_polls_menu_item_title_system_delete_with_content', '_bx_polls_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 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_polls', 'polls-administration', '_bx_polls_menu_item_title_system_admt_polls', '_bx_polls_menu_item_title_admt_polls', 'page.php?i=polls-administration', '', '_self', 'tasks', 'a:2:{s:6:"module";s:8:"bx_polls";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_polls', 'polls-author', '_bx_polls_menu_item_title_system_view_entries_author', '_bx_polls_menu_item_title_view_entries_author', 'page.php?i=polls-author&profile_id={profile_id}', '', '', 'tasks col-green1', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', 'bx_polls', 'polls-context', '_bx_polls_menu_item_title_system_view_entries_in_context', '_bx_polls_menu_item_title_view_entries_in_context', 'page.php?i=polls-context&profile_id={profile_id}', '', '', 'tasks col-green1', '', 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_polls_allow_view_to', 'bx_polls', 'view', '_bx_polls_form_entry_input_allow_view_to', '3', 'bx_polls_entries', 'id', 'author', '', ''),
+('bx_polls_allow_view_favorite_list', 'bx_polls', 'view_favorite_list', '_bx_polls_form_entry_input_allow_view_favorite_list', '3', 'bx_polls_favorites_lists', 'id', 'author_id', '', '');
+
+
+-- ACL
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_polls', 'create entry', NULL, '_bx_polls_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_polls', 'delete entry', NULL, '_bx_polls_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_polls', 'view entry', NULL, '_bx_polls_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_polls', 'vote entry', NULL, '_bx_polls_acl_action_vote_entry', '', 1, 0);
+SET @iIdActionEntryVote = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_polls', 'set thumb', NULL, '_bx_polls_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_polls', 'edit any entry', NULL, '_bx_polls_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_polls', 'delete any entry', NULL, '_bx_polls_acl_action_delete_any_entry', '', 1, 3);
+SET @iIdActionEntryDeleteAny = 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),
+
+-- entry vote
+(@iStandard, @iIdActionEntryVote),
+(@iModerator, @iIdActionEntryVote),
+(@iAdministrator, @iIdActionEntryVote),
+(@iPremium, @iIdActionEntryVote),
+
+-- set entry thumb
+(@iStandard, @iIdActionSetThumb),
+(@iModerator, @iIdActionSetThumb),
+(@iAdministrator, @iIdActionSetThumb),
+(@iPremium, @iIdActionSetThumb),
+
+-- edit any entry
+(@iModerator, @iIdActionEntryEditAny),
+(@iAdministrator, @iIdActionEntryEditAny),
+
+-- delete any entry
+(@iAdministrator, @iIdActionEntryDeleteAny);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_polls', '_bx_polls', @iSearchOrder + 1, 'BxPollsSearchResult', 'modules/boonex/polls/classes/BxPollsSearchResult.php'),
+('bx_polls_cmts', '_bx_polls_cmts', @iSearchOrder + 2, 'BxPollsCmtsSearchResult', 'modules/boonex/polls/classes/BxPollsCmtsSearchResult.php');
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_polls', 'bx_polls', 'bx_polls_meta_keywords', 'bx_polls_meta_locations', 'bx_polls_meta_mentions', '', '');
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `module`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_polls_cats', 'bx_polls', 'bx_polls', 'bx_polls', 'bx_polls_cats', 'bx_polls_entries', 'cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`id` = `bx_polls_entries`.`author`)', 'AND `sys_profiles`.`status` = ''active''', '', '');
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_polls', 'bx_polls', '_bx_polls', 'page.php?i=polls-home', 'tasks col-green1', 'SELECT COUNT(*) FROM `bx_polls_entries` WHERE 1 AND `status` = ''active'' AND `status_admin` = ''active''', @iMaxOrderStats + 1);
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_polls_growth', '_bx_polls_chart_growth', 'bx_polls_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_polls_growth_speed', '_bx_polls_chart_growth_speed', 'bx_polls_entries', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+-- 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`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_polls_administration', 'Sql', 'SELECT * FROM `bx_polls_entries` WHERE 1 ', 'bx_polls_entries', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'text', '', 'like', 'reports', '', 192, 'BxPollsGridAdministration', 'modules/boonex/polls/classes/BxPollsGridAdministration.php'),
+('bx_polls_common', 'Sql', 'SELECT * FROM `bx_polls_entries` WHERE 1 ', 'bx_polls_entries', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'text', '', 'like', '', '', 2147483647, 'BxPollsGridCommon', 'modules/boonex/polls/classes/BxPollsGridCommon.php');
+
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_polls_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_polls_administration', 'switcher', '_bx_polls_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_polls_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_polls_administration', 'text', '_bx_polls_grid_column_title_adm_title', '25%', 0, '25', '', 4),
+('bx_polls_administration', 'added', '_bx_polls_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_polls_administration', 'author', '_bx_polls_grid_column_title_adm_author', '20%', 0, '25', '', 6),
+('bx_polls_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_polls_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_polls_common', 'switcher', '_bx_polls_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_polls_common', 'text', '_bx_polls_grid_column_title_adm_title', '40%', 0, '35', '', 3),
+('bx_polls_common', 'added', '_bx_polls_grid_column_title_adm_added', '15%', 1, '25', '', 4),
+('bx_polls_common', 'status_admin', '_bx_polls_grid_column_title_adm_status_admin', '15%', 0, '16', '', 5),
+('bx_polls_common', 'actions', '', '20%', 0, '', '', 6);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_polls_administration', 'bulk', 'delete', '_bx_polls_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_polls_administration', 'bulk', 'clear_reports', '_bx_polls_grid_action_title_adm_clear_reports', '', 0, 1, 2),
+('bx_polls_administration', 'single', 'edit', '_bx_polls_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_polls_administration', 'single', 'delete', '_bx_polls_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_polls_administration', 'single', 'settings', '_bx_polls_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_polls_administration', 'single', 'audit_content', '_bx_polls_grid_action_title_adm_audit_content', 'search', 1, 0, 4),
+('bx_polls_administration', 'single', 'clear_reports', '_bx_polls_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5),
+
+('bx_polls_common', 'bulk', 'delete', '_bx_polls_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_polls_common', 'single', 'edit', '_bx_polls_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_polls_common', 'single', 'delete', '_bx_polls_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_polls_common', 'single', 'settings', '_bx_polls_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+-- ALERTS
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_polls', 'BxPollsAlertsResponse', 'modules/boonex/polls/classes/BxPollsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'delete', @iHandler);
+

+ 463 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/install/sql/install.sql

@@ -0,0 +1,463 @@
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_polls_entries` (
+  `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,
+  `text` text NOT NULL,
+  `cat` int(11) NOT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` int(11) NOT NULL default '0',
+  `score` int(11) NOT NULL default '0',
+  `sc_up` int(11) NOT NULL default '0',
+  `sc_down` int(11) NOT NULL default '0',
+  `favorites` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `cf` int(11) NOT NULL default '1',
+  `allow_view_to` varchar(16) NOT NULL DEFAULT '3',
+  `anonymous` tinyint(4) NOT NULL DEFAULT '0',
+  `hidden_results` tinyint(4) NOT NULL DEFAULT '0',
+  `status` enum('active','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `search_fields` (`text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_subentries` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `entry_id` int(11) unsigned NOT NULL default '0',
+  `title` varchar(255) NOT NULL,
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `order` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title` (`title`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_polls_files` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_polls_photos_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_polls_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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  `cmt_cf` int(11) NOT NULL default '1',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_cmts_notes` (
+  `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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+-- TABLE: votes
+CREATE TABLE IF NOT EXISTS `bx_polls_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_votes_subentries` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_votes_subentries_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: views
+CREATE TABLE `bx_polls_views_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `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',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE `bx_polls_meta_keywords` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE `bx_polls_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,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+);
+
+CREATE TABLE `bx_polls_meta_mentions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_polls_reports` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_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',
+  `checked_by` int(11) NOT NULL default '0',
+  `status` tinyint(11) NOT NULL default '0',	
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: favorites
+CREATE TABLE `bx_polls_favorites_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `list_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+CREATE TABLE `bx_polls_favorites_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `allow_view_favorite_list_to` varchar(16) NOT NULL DEFAULT '3',
+  PRIMARY KEY (`id`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_polls_scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_polls_scores_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(8) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+
+-- STORAGES & TRANSCODERS
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+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_polls_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_polls_files', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+('bx_polls_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_polls_photos_resized', 'allow-deny', '{image}', '', 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_polls_preview', 'bx_polls_photos_resized', 'Storage', 'a:1:{s:6:"object";s:14:"bx_polls_files";}', 'no', '1', '2592000', '0'),
+('bx_polls_gallery', 'bx_polls_photos_resized', 'Storage', 'a:1:{s:6:"object";s:14:"bx_polls_files";}', 'no', '1', '2592000', '0'),
+('bx_polls_cover', 'bx_polls_photos_resized', 'Storage', 'a:1:{s:6:"object";s:14:"bx_polls_files";}', 'no', '1', '2592000', '0');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_polls_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_polls_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0'),
+('bx_polls_cover', 'Resize', 'a:1:{s:1:"w";s:4:"1200";}', '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_polls', 'bx_polls', '_bx_polls_form_entry', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_polls_entries', 'id', '', '', 'a:2:{i:0;s:9:"do_submit";i:1;s:10:"do_publish";}', 'a:1:{s:14:"checker_helper";s:29:"BxPollsFormEntryCheckerHelper";}', 0, 1, 'BxPollsFormEntry', 'modules/boonex/polls/classes/BxPollsFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_polls', 'bx_polls_entry_add', 'bx_polls', 0, '_bx_polls_form_entry_display_add'),
+('bx_polls', 'bx_polls_entry_delete', 'bx_polls', 0, '_bx_polls_form_entry_display_delete'),
+('bx_polls', 'bx_polls_entry_edit', 'bx_polls', 0, '_bx_polls_form_entry_display_edit'),
+('bx_polls', 'bx_polls_entry_view', 'bx_polls', 1, '_bx_polls_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_polls', 'bx_polls', 'cf', '1', '#!sys_content_filter', 0, 'select', '_sys_form_entry_input_sys_cf', '_sys_form_entry_input_cf', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_polls', 'bx_polls', 'allow_view_to', '', '', 0, 'custom', '_bx_polls_form_entry_input_sys_allow_view_to', '_bx_polls_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_polls_form_entry_input_sys_delete_confirm', '_bx_polls_form_entry_input_delete_confirm', '_bx_polls_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_polls_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'do_publish', '_bx_polls_form_entry_input_do_publish', '', 0, 'submit', '_bx_polls_form_entry_input_sys_do_publish', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'do_submit', '_bx_polls_form_entry_input_do_submit', '', 0, 'submit', '_bx_polls_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_polls', 'bx_polls', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_polls', 'bx_polls', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'pictures', 'a:1:{i:0;s:9:"sys_html5";}', 'a:1:{s:9:"sys_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_polls_form_entry_input_sys_pictures', '_bx_polls_form_entry_input_pictures', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'text', '', '', 0, 'textarea', '_bx_polls_form_entry_input_sys_text', '_bx_polls_form_entry_input_text', '', 1, 0, 2, '', '', '', 'Avail', '', '_bx_polls_form_entry_input_text_err', 'Xss', '', 1, 0),
+('bx_polls', 'bx_polls', 'subentries', '', '', 0, 'custom', '_bx_polls_form_entry_input_sys_subentries', '_bx_polls_form_entry_input_subentries', '', 1, 0, 0, '', '', '', 'AvailSubentries', '', '_bx_polls_form_entry_input_subentries_err', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'cat', '', '#!bx_polls_cats', 0, 'select', '_bx_polls_form_entry_input_sys_cat', '_bx_polls_form_entry_input_cat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_polls_form_entry_input_cat_err', 'Xss', '', 1, 0),
+('bx_polls', 'bx_polls', 'anonymous', 1, '', 1, 'switcher', '_bx_polls_form_profile_input_sys_anonymous', '_bx_polls_form_profile_input_anonymous', '_bx_polls_form_profile_input_anonymous_info', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_polls', 'bx_polls', 'hidden_results', 1, '', 0, 'switcher', '_bx_polls_form_profile_input_sys_hidden_results', '_bx_polls_form_profile_input_hidden_results', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_polls', 'bx_polls', 'added', '', '', 0, 'datetime', '_bx_polls_form_entry_input_sys_date_added', '_bx_polls_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'changed', '', '', 0, 'datetime', '_bx_polls_form_entry_input_sys_date_changed', '_bx_polls_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_polls', 'bx_polls', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0);
+
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_polls_entry_add', 'cat', 2147483647, 1, 1),
+('bx_polls_entry_add', 'text', 2147483647, 1, 2),
+('bx_polls_entry_add', 'subentries', 2147483647, 1, 3),
+('bx_polls_entry_add', 'pictures', 2147483647, 1, 4),
+('bx_polls_entry_add', 'allow_view_to', 2147483647, 1, 5),
+('bx_polls_entry_add', 'cf', 2147483647, 1, 6),
+('bx_polls_entry_add', 'anonymous', 2147483647, 1, 7),
+('bx_polls_entry_add', 'hidden_results', 2147483647, 1, 8),
+('bx_polls_entry_add', 'location', 2147483647, 1, 9),
+('bx_polls_entry_add', 'do_publish', 2147483647, 1, 10),
+
+('bx_polls_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_polls_entry_delete', 'do_submit', 2147483647, 1, 2),
+
+('bx_polls_entry_edit', 'cat', 2147483647, 1, 1),
+('bx_polls_entry_edit', 'text', 2147483647, 1, 2),
+('bx_polls_entry_edit', 'subentries', 2147483647, 1, 3),
+('bx_polls_entry_edit', 'pictures', 2147483647, 1, 4),
+('bx_polls_entry_edit', 'allow_view_to', 2147483647, 1, 5),
+('bx_polls_entry_edit', 'cf', 2147483647, 1, 6),
+('bx_polls_entry_edit', 'hidden_results', 2147483647, 1, 7),
+('bx_polls_entry_edit', 'location', 2147483647, 1, 8),
+('bx_polls_entry_edit', 'controls', 2147483647, 1, 9),
+('bx_polls_entry_edit', 'do_submit', 2147483647, 1, 10),
+('bx_polls_entry_edit', 'do_cancel', 2147483647, 1, 11),
+
+('bx_polls_entry_view', 'cat', 2147483647, 1, 1),
+('bx_polls_entry_view', 'added', 2147483647, 1, 2),
+('bx_polls_entry_view', 'changed', 2147483647, 1, 3);
+
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_polls_cats', '_bx_polls_pre_lists_cats', 'bx_polls', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_polls_cats', '', 0, '_sys_please_select', ''),
+('bx_polls_cats', '1', 1, '_bx_polls_cat_beauty_and_style', ''),
+('bx_polls_cats', '2', 2, '_bx_polls_cat_business_and_money', ''),
+('bx_polls_cats', '3', 3, '_bx_polls_cat_cars_and_transportation', ''),
+('bx_polls_cats', '4', 4, '_bx_polls_cat_computers_and_internet', ''),
+('bx_polls_cats', '5', 5, '_bx_polls_cat_food_and_dining', ''),
+('bx_polls_cats', '6', 6, '_bx_polls_cat_education', ''),
+('bx_polls_cats', '7', 7, '_bx_polls_cat_electronics', ''),
+('bx_polls_cats', '8', 8, '_bx_polls_cat_entertainment', ''),
+('bx_polls_cats', '9', 9, '_bx_polls_cat_family_and_relationships', ''),
+('bx_polls_cats', '10', 10, '_bx_polls_cat_games', ''),
+('bx_polls_cats', '11', 11, '_bx_polls_cat_health_and_fitness', ''),
+('bx_polls_cats', '12', 12, '_bx_polls_cat_home_and_garden', ''),
+('bx_polls_cats', '13', 13, '_bx_polls_cat_news_and_events', ''),
+('bx_polls_cats', '14', 14, '_bx_polls_cat_pets', ''),
+('bx_polls_cats', '15', 15, '_bx_polls_cat_politics_and_government', ''),
+('bx_polls_cats', '16', 16, '_bx_polls_cat_pregnancy_and_parenting', ''),
+('bx_polls_cats', '17', 17, '_bx_polls_cat_sports', ''),
+('bx_polls_cats', '18', 18, '_bx_polls_cat_misc', ''),
+('bx_polls_cats', '19', 19, '_bx_polls_cat_would_you_rather', ''),
+('bx_polls_cats', '20', 20, '_bx_polls_cat_yes_or_no', '');
+
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_polls', 'bx_polls', 'bx_polls_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-poll&id={object_id}', '', 'bx_polls_entries', 'id', 'author', 'text', 'comments', '', ''),
+('bx_polls_notes', 'bx_polls', 'bx_polls_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_polls_entries', 'id', 'author', 'text', '', 'BxTemplCmtsNotes', '');
+
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_polls', 'bx_polls', 'bx_polls_votes', 'bx_polls_votes_track', '604800', '1', '1', '0', '1', 'bx_polls_entries', 'id', 'author', 'rate', 'votes', '', ''),
+('bx_polls_subentries', 'bx_polls', 'bx_polls_votes_subentries', 'bx_polls_votes_subentries_track', '604800', '1', '1', '0', '1', 'bx_polls_subentries', 'id', 'author', 'rate', 'votes', 'BxPollsVoteSubentries', 'modules/boonex/polls/classes/BxPollsVoteSubentries.php'),
+
+('bx_polls_reactions', 'bx_polls', 'bx_polls_reactions', 'bx_polls_reactions_track', '604800', '1', '1', '1', '1', 'bx_polls_entries', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', '');
+
+
+-- SCORES
+INSERT INTO `sys_objects_score` (`name`, `module`, `table_main`, `table_track`, `post_timeout`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_score`, `trigger_field_cup`, `trigger_field_cdown`, `class_name`, `class_file`) VALUES 
+('bx_polls', 'bx_polls', 'bx_polls_scores', 'bx_polls_scores_track', '604800', '0', 'bx_polls_entries', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `module`, `table_main`, `table_track`, `is_on`, `base_url`, `object_comment`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_polls', 'bx_polls', 'bx_polls_reports', 'bx_polls_reports_track', '1', 'page.php?i=view-poll&id={object_id}', 'bx_polls_notes', 'bx_polls_entries', 'id', 'author', 'reports', '', '');
+
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_polls', 'bx_polls', 'bx_polls_views_track', '86400', '1', 'bx_polls_entries', 'id', 'author', 'views', '', '');
+
+
+-- FAFORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `table_lists`, `is_on`, `is_undo`, `is_public`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_polls', 'bx_polls_favorites_track', 'bx_polls_favorites_lists', '1', '1', '1', 'page.php?i=view-poll&id={object_id}', 'bx_polls_entries', 'id', 'author', 'favorites', '', '');
+
+
+-- FEATURED
+INSERT INTO `sys_objects_feature` (`name`, `module`, `is_on`, `is_undo`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_flag`, `class_name`, `class_file`) VALUES 
+('bx_polls', 'bx_polls', '1', '1', 'page.php?i=view-poll&id={object_id}', 'bx_polls_entries', 'id', 'author', 'featured', '', '');
+
+
+-- CONTENT INFO
+INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_action_add`, `alert_action_update`, `alert_action_delete`, `class_name`, `class_file`) VALUES
+('bx_polls', '_bx_polls', 'bx_polls', 'added', 'edited', 'deleted', '', ''),
+('bx_polls_cmts', '_bx_polls_cmts', 'bx_polls', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_polls', 'bx_polls_administration', 'id', '', ''),
+('bx_polls', 'bx_polls_common', 'id', '', '');
+
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_polls', 'bx_polls', 'bx_polls', '_bx_polls_search_extended', 1, '', ''),
+('bx_polls_cmts', 'bx_polls_cmts', 'bx_polls', '_bx_polls_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_polls', '_bx_polls', '_bx_polls', 'bx_polls@modules/boonex/polls/|std-icon.svg');
+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`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_polls', 'content', '{url_studio}module.php?name=bx_polls', '', 'bx_polls@modules/boonex/polls/|std-icon.svg', '_bx_polls', '', '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));

+ 15 - 0
modules/boonex/polls/updates/14.0.2_15.0.0/source/template/entry-text-subentries.html

@@ -0,0 +1,15 @@
+<div class="bx-content-description-before">__content_description_before__</div>
+<div class="bx-content-description">
+    <div class="bx-pull-combined-entity-content bx-base-text-entity-content bx-def-constraint-list bx-def-constraint-pre bx-def-constraint-object bx-def-constraint-iframe bx-def-constraint-img bx-def-vanilla-html">
+        __entry_text__
+    </div>
+    <bx_if:show_image>
+        <div class="bx-base-text-entity-image bx-def-margin-top bx-def-font-align-center">
+            <img class="bx-def-border-radius-block" src="__entry_image__" />
+        </div>
+    </bx_if:show_image>
+    <bx_if:show_subentries>
+        <div class="bx-poll-entity-subentries bx-def-margin-top">__entry_subentries__</div>
+    </bx_if:show_subentries>
+</div>
+<div class="bx-content-description-after">__content_description_after__</div>

+ 51 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Posts',
+    'version_from' => '14.0.1',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/posts/updates/update_14.0.1_15.0.0/',
+    'home_uri' => 'posts_update_1401_1500',
+
+    'module_dir' => 'boonex/posts/',
+    'module_uri' => 'posts',
+
+    'db_prefix' => 'bx_posts_',
+    'class_prefix' => 'BxPosts',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Posts',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxPostsUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/install/langs/en.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_posts_menu_title_public_submenu"><![CDATA[Posts]]></string_add>
+</resources>

+ 7 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/install/sql/enable.sql

@@ -0,0 +1,7 @@
+-- MENUS
+DELETE FROM `sys_menu_items` WHERE `set_name`='sys_create_post' AND `name`='create-post';
+SET @iCreatePostOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_create_post' 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_create_post', 'bx_posts', 'create-post', '_bx_posts_menu_item_title_system_create_entry', '_bx_posts_menu_item_title_create_entry', 'page.php?i=create-post', '', '', 'file-alt col-red3', '', 2147483647, 1, 0, IFNULL(@iCreatePostOrder, 0) + 1);
+
+UPDATE `sys_objects_menu` SET `title_public`='_bx_posts_menu_title_public_submenu' WHERE `object`='bx_posts_submenu';

+ 12 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/install/sql/install.sql

@@ -0,0 +1,12 @@
+-- FORMS
+DELETE FROM `sys_form_inputs` WHERE `object`='bx_posts' AND `name` IN ('do_cancel', 'controls');
+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_posts', 'bx_posts', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_posts', 'bx_posts', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name`='bx_posts_entry_edit' AND `input_name` IN ('controls', 'do_submit', 'do_cancel');
+SET @iOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_form_display_inputs` WHERE `display_name`='bx_posts_entry_edit');
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_posts_entry_edit', 'controls', 2147483647, 1, @iOrder+1),
+('bx_posts_entry_edit', 'do_submit', 2147483647, 1, @iOrder+2),
+('bx_posts_entry_edit', 'do_cancel', 2147483647, 1, @iOrder+3);

+ 249 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/source/classes/BxPostsConfig.php

@@ -0,0 +1,249 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPostsConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'approve' => 'checkAllowedApprove',
+            'edit-post' => 'checkAllowedEdit',
+            'delete-post' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array_merge($this->CNF, array (
+
+            // module icon
+            'ICON' => 'file-alt col-red3',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'posts',
+            'TABLE_ENTRIES_FULLTEXT' => 'title_text',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_PUBLISHED' => 'published',
+            'FIELD_TITLE' => 'title',
+            'FIELD_ABSTRACT' => 'abstract',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'post-text',
+            'FIELD_CATEGORY' => 'cat',
+            'FIELD_MULTICAT' => 'multicat',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_CF' => 'cf',
+            'FIELD_COVER' => 'covers',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_VIDEO' => 'videos',
+            'FIELD_SOUND' => 'sounds',
+            'FIELD_FILE' => 'files',
+            'FIELD_POLL' => 'polls',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_THUMB_POSITION' => 'thumb_data',
+            'FIELD_LINK' => 'link',
+            'FIELD_ATTACHMENTS' => 'attachments',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => 'status_admin',
+            'FIELD_LOCATION' => 'location',
+            'FIELD_LOCATION_PREFIX' => 'location',
+            'FIELD_LABELS' => 'labels',
+            'FIELD_ANONYMOUS' => 'anonymous',
+            'FIELD_ALLOW_COMMENTS' => 'allow_comments',
+            'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
+            'FIELDS_DELAYED_PROCESSING' => 'videos', // can be array of fields or comma separated string of field names
+            
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-post',
+            'URI_AUTHOR_ENTRIES' => 'posts-author',
+            'URI_ENTRIES_BY_CONTEXT' => 'posts-context',
+            'URI_ADD_ENTRY' => 'create-post',
+            'URI_EDIT_ENTRY' => 'edit-post',
+            'URI_MANAGE_COMMON' => 'posts-manage',
+            'URI_FAVORITES_LIST' => 'posts-favorites',
+
+            'URL_HOME' => 'page.php?i=posts-home',
+            'URL_POPULAR' => 'page.php?i=posts-popular',
+            'URL_TOP' => 'page.php?i=posts-top',
+            'URL_UPDATED' => 'page.php?i=posts-updated',
+            'URL_MANAGE_COMMON' => 'page.php?i=posts-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=posts-administration',
+
+            // some params
+            'PARAM_AUTO_APPROVE' => 'bx_posts_enable_auto_approve',
+            'PARAM_CHARS_SUMMARY' => 'bx_posts_summary_chars',
+            'PARAM_CHARS_SUMMARY_PLAIN' => 'bx_posts_plain_summary_chars',
+            'PARAM_NUM_RSS' => 'bx_posts_rss_num',
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_posts_searchable_fields',
+            'PARAM_PER_PAGE_BROWSE_SHOWCASE' => 'bx_posts_per_page_browse_showcase',
+            'PARAM_PER_PAGE_FOR_FAVORITES_LISTS' => 'bx_posts_per_page_for_favorites_lists',
+
+            'PARAM_MULTICAT_ENABLED' => true,
+            'PARAM_LINKS_ENABLED' => true,
+            'PARAM_MULTICAT_AUTO_ACTIVATION_FOR_CATEGORIES' => 'bx_posts_auto_activation_for_categories',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_posts_covers',
+            'OBJECT_STORAGE_FILES' => 'bx_posts_files',
+            'OBJECT_STORAGE_PHOTOS' => 'bx_posts_photos',
+            'OBJECT_STORAGE_VIDEOS' => 'bx_posts_videos',
+            'OBJECT_STORAGE_SOUNDS' => 'bx_posts_sounds',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_posts_preview',
+            'OBJECT_IMAGES_TRANSCODER_MINIATURE' => 'bx_posts_miniature',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_posts_gallery',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_posts_cover',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW_FILES' => 'bx_posts_preview_files',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY_FILES' => 'bx_posts_gallery_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW_PHOTOS' => 'bx_posts_preview_photos',
+            'OBJECT_IMAGES_TRANSCODER_MINIATURE_PHOTOS' => 'bx_posts_miniature_photos',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY_PHOTOS' => 'bx_posts_gallery_photos',
+            'OBJECT_IMAGES_TRANSCODER_VIEW_PHOTOS' => 'bx_posts_view_photos',
+            'OBJECT_SOUNDS_TRANSCODER' => 'bx_posts_sounds_mp3',
+            'OBJECT_VIDEOS_TRANSCODERS' => array(
+                'poster' => 'bx_posts_videos_poster', 
+            	'poster_preview' => 'bx_posts_videos_poster_preview',
+            	'mp4' => 'bx_posts_videos_mp4', 
+            	'mp4_hd' => 'bx_posts_videos_mp4_hd'
+            ),
+            'OBJECT_VIDEO_TRANSCODER_HEIGHT' => '480px',
+            'OBJECT_REPORTS' => 'bx_posts',
+            'OBJECT_VIEWS' => 'bx_posts',
+            'OBJECT_VOTES' => 'bx_posts',
+            'OBJECT_REACTIONS' => 'bx_posts_reactions',
+            'OBJECT_SCORES' => 'bx_posts',
+            'OBJECT_FAVORITES' => 'bx_posts',
+            'OBJECT_FEATURED' => 'bx_posts',
+            'OBJECT_METATAGS' => 'bx_posts',
+            'OBJECT_COMMENTS' => 'bx_posts',
+            'OBJECT_NOTES' => 'bx_posts_notes',
+            'OBJECT_CATEGORY' => 'bx_posts_cats',
+            'OBJECT_PRIVACY_VIEW' => 'bx_posts_allow_view_to',
+            'OBJECT_PRIVACY_LIST_VIEW' => 'bx_posts_allow_view_favorite_list',
+            'OBJECT_FORM_ENTRY' => 'bx_posts',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_posts_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_posts_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_posts_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_posts_entry_delete',
+            'OBJECT_FORM_POLL' => 'bx_posts_poll',
+            'OBJECT_FORM_POLL_DISPLAY_ADD' => 'bx_posts_poll_add',
+            'OBJECT_MENU_ENTRY_ATTACHMENTS' => 'bx_posts_entry_attachments', // attachments menu in create/edit forms
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_posts_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_posts_view_actions', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_posts_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_posts_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_posts_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'posts-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_SNIPPET_META' => 'bx_posts_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_posts_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_posts_administration',
+            'OBJECT_GRID_COMMON' => 'bx_posts_common',
+            'OBJECT_GRID_CATEGORIES' => 'bx_posts_categories',
+            'OBJECT_UPLOADERS' => array('bx_posts_html5'),
+            'OBJECT_CONTENT_INFO' => 'bx_posts',
+            'OBJECT_CMTS_CONTENT_INFO' => 'bx_posts_cmts',
+            
+            'BADGES_AVALIABLE' => true,
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_posts_my' => array (
+                    'create-post' => 'checkAllowedAdd',
+                ),
+                'bx_posts_view' => $aMenuItems2Methods,
+            ),
+
+            // informer messages
+            'INFORMERS' => array (
+                'approving' => array (
+                    'name' => 'bx-posts-approving',
+                    'map' => array (
+                        'pending' => array('msg' => '_bx_posts_txt_msg_status_pending', 'type' => BX_INFORMER_ALERT),
+                        'hidden' => array('msg' => '_bx_posts_txt_msg_status_hidden', 'type' => BX_INFORMER_ERROR),
+                    ),
+                ),
+                'processing' => array (
+                    'name' => 'bx-posts-processing',
+                    'map' => array (
+                        'awaiting' => array('msg' => '_bx_posts_txt_processing_awaiting', 'type' => BX_INFORMER_ALERT),
+                        'failed' => array('msg' => '_bx_posts_txt_processing_failed', 'type' => BX_INFORMER_ERROR)
+                    ),
+                ),
+                'scheduled' => array (
+                    'name' => 'bx-posts-scheduled',
+                    'map' => array (
+                        'awaiting' => array('msg' => '_bx_posts_txt_scheduled_awaiting', 'type' => BX_INFORMER_ALERT),
+                    ),
+                ),
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_posts_txt_sample_single',
+            	'txt_sample_single_with_article' => '_bx_posts_txt_sample_single_with_article',
+            	'txt_sample_comment_single' => '_bx_posts_txt_sample_comment_single',
+            	'txt_sample_vote_single' => '_bx_posts_txt_sample_vote_single',
+                'txt_sample_reaction_single' => '_bx_posts_txt_sample_reaction_single',
+                'txt_sample_score_up_single' => '_bx_posts_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_posts_txt_sample_score_down_single',
+                'form_field_author' => '_bx_posts_form_entry_input_author',
+            	'grid_action_err_delete' => '_bx_posts_grid_action_err_delete',
+            	'grid_txt_account_manager' => '_bx_posts_grid_txt_account_manager',
+                'filter_item_active' => '_bx_posts_grid_filter_item_title_adm_active',
+            	'filter_item_hidden' => '_bx_posts_grid_filter_item_title_adm_hidden',
+                'filter_item_pending' => '_bx_posts_grid_filter_item_title_adm_pending',
+            	'filter_item_select_one_filter1' => '_bx_posts_grid_filter_item_title_adm_select_one_filter1',
+                'filter_item_select_one_filter2' => '_bx_posts_grid_filter_item_title_adm_select_one_filter2',
+            	'menu_item_manage_my' => '_bx_posts_menu_item_title_manage_my',
+            	'menu_item_manage_all' => '_bx_posts_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_posts_txt_all_entries_by',
+                'txt_all_entries_in' => '_bx_posts_txt_all_entries_in',
+                'txt_all_entries_by_author' => '_bx_posts_page_title_browse_by_author',
+                'txt_all_entries_by_context' => '_bx_posts_page_title_browse_by_context',
+                'txt_err_cannot_perform_action' => '_bx_posts_txt_err_cannot_perform_action',
+                'txt_poll_form_answers_add' => '_bx_posts_form_poll_input_answers_add',
+                'txt_poll_menu_view_answers' => '_bx_posts_txt_poll_view_answers',
+                'txt_poll_menu_view_results' => '_bx_posts_txt_poll_view_results',
+                'txt_poll_menu_view_' => '_bx_posts_txt_poll_view_',
+                'txt_poll_answer_vote_do_by' => '_bx_posts_txt_poll_answer_vote_do_by',
+                'txt_poll_answer_vote_counter' => '_bx_posts_txt_poll_answer_vote_counter',
+                'txt_poll_answer_vote_percent' => '_bx_posts_txt_poll_answer_vote_percent'
+            ),
+        ));
+        
+        $this->_aPrefixes = array(
+            'style' => 'bx-posts',
+        );
+        
+        $this->_aJsClasses = array_merge($this->_aJsClasses, [
+            'manage_tools' => 'BxPostsManageTools',
+            'categories' => 'BxDolCategories'
+        ]);
+
+        $this->_aJsObjects = array_merge($this->_aJsObjects, [
+            'manage_tools' => 'oBxPostsManageTools',
+            'categories' => 'oBxDolCategories'
+        ]);
+
+        $this->_aGridObjects = array(
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        );
+
+        $this->_bAttachmentsInTimeline = true;
+    }
+}
+
+/** @} */

+ 137 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/source/classes/BxPostsSearchResult.php

@@ -0,0 +1,137 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPostsSearchResult extends BxBaseModTextSearchResult
+{
+    function __construct($sMode = '', $aParams = array())
+    {
+        parent::__construct($sMode, $aParams);
+
+        $this->aCurrent = array(
+            'name' => 'bx_posts',
+            'module_name' => 'bx_posts',
+            'object_metatags' => 'bx_posts',
+            'title' => _t('_bx_posts_page_title_browse'),
+            'table' => 'bx_posts_posts',
+            'ownFields' => array('id', 'title', 'abstract', 'text', 'thumb', 'thumb_data', 'author', 'added'),
+            'searchFields' => array(),
+            'restriction' => array(
+                'author' => array('value' => '', 'field' => 'author', 'operator' => '='),
+                'featured' => array('value' => '', 'field' => 'featured', 'operator' => '<>'),
+                'status' => array('value' => 'active', 'field' => 'status', 'operator' => '='),
+                'statusAdmin' => array('value' => 'active', 'field' => 'status_admin', 'operator' => '='),
+            ),
+            'paginate' => array('perPage' => getParam('bx_posts_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',
+                    'Image' => 'thumb'
+                ),
+            ),
+            'ident' => 'id',
+        );
+
+        $this->sFilterName = 'bx_posts_filter';
+        $this->oModule = $this->getMain();
+
+        $CNF = &$this->oModule->_oConfig->CNF;
+
+        $sSearchFields = getParam($CNF['PARAM_SEARCHABLE_FIELDS']);
+        $this->aCurrent['searchFields'] = !empty($sSearchFields) ? explode(',', $sSearchFields) : '';
+
+        $oProfileAuthor = null;
+
+        switch ($sMode) {
+            case 'author':
+                if(!$this->_updateCurrentForAuthor($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'context':
+                if(!$this->_updateCurrentForContext($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'followed_contexts':
+                if(!$this->_updateCurrentForFollowedContexts($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+
+            case 'favorite':
+                if(!$this->_updateCurrentForFavorite($sMode, $aParams, $oProfileAuthor))
+                    $this->isError = true;
+                break;
+			
+            case 'recent':
+            case 'public':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_recent');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                break;
+
+            case 'featured':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_HOME']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_featured');
+                $this->aCurrent['restriction']['featured']['value'] = '0';
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'featured';
+                break;
+
+            case 'popular':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_TOP']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_popular');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'popular';
+                break;
+
+            case 'top':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_POPULAR']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_top');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'top';
+                break;
+
+            case 'updated':
+                $this->sBrowseUrl = BxDolPermalinks::getInstance()->permalink($CNF['URL_UPDATED']);
+                $this->aCurrent['title'] = _t('_bx_posts_page_title_browse_updated');
+                $this->aCurrent['rss']['link'] = 'modules/?r=posts/rss/' . $sMode;
+                $this->aCurrent['sorting'] = 'updated';
+                break;
+
+            case '': // search results
+                $this->checkRestrictionsForContext($sMode, $aParams, $oProfileAuthor);
+                $this->sBrowseUrl = BX_DOL_SEARCH_KEYWORD_PAGE;
+                $this->aCurrent['title'] = _t('_bx_posts');
+                unset($this->aCurrent['paginate']['perPage'], $this->aCurrent['rss']);
+                break;
+
+            default:
+                $sMode = '';
+                $this->isError = true;
+        }
+
+        $this->processReplaceableMarkers($oProfileAuthor);
+
+        $this->addConditionsForPrivateContent($CNF, $oProfileAuthor);
+        $this->addCustomConditions($CNF, $oProfileAuthor, $sMode, $aParams);
+    }
+}
+
+/** @} */

+ 155 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/source/install/config.php

@@ -0,0 +1,155 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Posts Posts
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_posts',
+    'title' => 'Posts',
+    'note' => 'Basic blogging module.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/posts/',
+    'home_uri' => 'posts',
+
+    'db_prefix' => 'bx_posts_',
+    'class_prefix' => 'BxPosts',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Posts',
+
+    /**
+     * List of page triggers.
+     */
+    'page_triggers' => array (
+    	'trigger_page_profile_view_entry',
+    ),
+    
+    /**
+     * Menu triggers.
+     */
+    'menu_triggers' => array(
+        'trigger_profile_view_submenu',
+        'trigger_group_view_submenu',
+    ),
+
+    /**
+     * Storage objects to automatically delete files from upon module uninstallation.
+     * Note. Don't add storage objects used in transcoder objects.
+     */
+    'storages' => array(
+        'bx_posts_covers',
+        'bx_posts_photos',
+        'bx_posts_videos',
+        'bx_posts_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_posts_preview',
+        'bx_posts_miniature',
+        'bx_posts_gallery',
+        'bx_posts_cover',
+
+        'bx_posts_preview_photos',
+        'bx_posts_miniature_photos',
+        'bx_posts_gallery_photos',
+        'bx_posts_view_photos',
+
+        'bx_posts_videos_poster',
+        'bx_posts_videos_poster_preview',
+        'bx_posts_videos_mp4',
+        'bx_posts_videos_mp4_hd',
+        
+        'bx_posts_sounds_mp3',
+
+        'bx_posts_preview_files',
+        'bx_posts_gallery_files'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_posts',
+    	'bx_posts_cmts'
+    ),
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'uninstall' => array (
+    	'process_esearches' => 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,
+        'process_page_triggers' => 1,
+    	'process_esearches' => 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(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

+ 367 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/source/install/langs/en.xml

@@ -0,0 +1,367 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+    <string name="_bx_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_cmts"><![CDATA[Posts' Comments]]></string>
+    <string name="_bx_posts_reactions"><![CDATA[Posts' Reactions]]></string>
+
+    <string name="_bx_posts_option_enable_auto_approve"><![CDATA[Auto approve a post after creation]]></string>
+    <string name="_bx_posts_option_summary_chars"><![CDATA[Number of characters in auto-cropped post summary]]></string>
+    <string name="_bx_posts_option_plain_summary_chars"><![CDATA[Number of characters in plain post description when post hasn't thumb]]></string>
+    <string name="_bx_posts_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_posts_option_per_page_profile"><![CDATA[Number of items on profile/group page]]></string>
+    <string name="_bx_posts_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_posts_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_posts_option_auto_activation_for_categories"><![CDATA[Auto-Activation For Categories]]></string>
+    <string name="_bx_posts_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+
+    <string name="_bx_posts_form_entry"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_form_entry_display_add"><![CDATA[Add Post]]></string>
+    <string name="_bx_posts_form_entry_display_edit"><![CDATA[Edit Post]]></string>
+    <string name="_bx_posts_form_entry_display_delete"><![CDATA[Delete Post]]></string>
+    <string name="_bx_posts_form_entry_display_view"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_form_entry_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_posts_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_posts_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_posts_form_entry_input_sys_do_publish"><![CDATA[Publish]]></string>
+    <string name="_bx_posts_form_entry_input_do_publish"><![CDATA[Publish]]></string>
+    <string name="_bx_posts_form_entry_input_sys_title"><![CDATA[Title]]></string>
+    <string name="_bx_posts_form_entry_input_title"><![CDATA[Title]]></string>
+    <string name="_bx_posts_form_entry_input_title_err"><![CDATA[Title is essential. Please, fill in this field]]></string>
+    <string name="_bx_posts_form_entry_input_sys_cat"><![CDATA[Category]]></string>
+    <string name="_bx_posts_form_entry_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_posts_form_entry_input_cat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_posts_form_entry_input_sys_multicat"><![CDATA[Categories]]></string>
+    <string name="_bx_posts_form_entry_input_multicat"><![CDATA[Categories]]></string>
+    <string name="_bx_posts_form_entry_input_multicat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_posts_form_entry_input_sys_abstract"><![CDATA[Summary]]></string>
+    <string name="_bx_posts_form_entry_input_abstract"><![CDATA[Summary]]></string>
+    <string name="_bx_posts_form_entry_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_posts_form_entry_input_text"><![CDATA[Text]]></string>
+    <string name="_bx_posts_form_entry_input_text_err"><![CDATA[Text field can't be empty]]></string>
+    <string name="_bx_posts_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_posts_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this post]]></string>
+    <string name="_bx_posts_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+    <string name="_bx_posts_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the post]]></string>
+    <string name="_bx_posts_form_entry_input_sys_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_posts_form_entry_input_covers"><![CDATA[Header Image]]></string>
+    <string name="_bx_posts_form_entry_input_covers_uploader_simple_title"><![CDATA[Upload]]></string>
+    <string name="_bx_posts_form_entry_input_covers_uploader_html5_title"><![CDATA[Upload]]></string>
+    <string name="_bx_posts_form_entry_input_sys_pictures"><![CDATA[Images]]></string>
+    <string name="_bx_posts_form_entry_input_pictures"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_videos"><![CDATA[Videos]]></string>
+    <string name="_bx_posts_form_entry_input_videos"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_sounds"><![CDATA[Sounds]]></string>
+    <string name="_bx_posts_form_entry_input_sounds"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_files"><![CDATA[Files]]></string>
+    <string name="_bx_posts_form_entry_input_files"><![CDATA[]]></string>
+    <string name="_bx_posts_form_entry_input_sys_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_posts_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_posts_form_entry_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_posts_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_posts_form_entry_input_sys_date_published"><![CDATA[Publishing time]]></string>
+    <string name="_bx_posts_form_entry_input_date_published"><![CDATA[Publishing time]]></string>
+    <string name="_bx_posts_form_entry_input_date_published_info"><![CDATA[Leave empty to publish immediately.]]></string>
+    <string name="_bx_posts_form_entry_input_sys_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_posts_form_entry_input_sys_allow_comments"><![CDATA[Allow comments]]></string>
+    <string name="_bx_posts_form_entry_input_allow_comments"><![CDATA[Allow comments]]></string>
+
+    <string name="_bx_posts_form_poll"><![CDATA[Polls]]></string>
+    <string name="_bx_posts_form_poll_display_add"><![CDATA[Add Poll]]></string>
+    <string name="_bx_posts_form_poll_input_sys_text"><![CDATA[Question]]></string>
+    <string name="_bx_posts_form_poll_input_text"><![CDATA[Question]]></string>
+    <string name="_bx_posts_form_poll_input_text_err"><![CDATA[Question is essential. Please, fill in this field]]></string>
+    <string name="_bx_posts_form_poll_input_sys_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_posts_form_poll_input_answers"><![CDATA[Answers]]></string>
+    <string name="_bx_posts_form_poll_input_answers_err"><![CDATA[Poll should have at least 2 non-empty answers.]]></string>
+    <string name="_bx_posts_form_poll_input_answers_add"><![CDATA[Add More]]></string>
+    <string name="_bx_posts_form_poll_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_poll_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_poll_input_do_cancel"><![CDATA[Close]]></string>
+
+    <string name="_bx_posts_category_form_entry"><![CDATA[Categories Form]]></string>
+    <string name="_bx_posts_category_display_add"><![CDATA[Add category]]></string>
+    <string name="_bx_posts_category_display_edit"><![CDATA[Edit category]]></string>
+    <string name="_bx_posts_category_form_entry_input_sys_value"><![CDATA[Value]]></string>
+    <string name="_bx_posts_category_form_entry_input_value"><![CDATA[Value]]></string>>
+    <string name="_bx_posts_category_form_entry_input_value_err"><![CDATA[Value is essential. Please, fill in this field]]></string>
+    <string name="_bx_posts_lmi_cpt_categories"><![CDATA[Categories]]></string>
+
+    <string name="_bx_posts_acl_action_create_entry"><![CDATA[Create Post]]></string>
+    <string name="_bx_posts_acl_action_delete_entry"><![CDATA[Delete Post]]></string>
+    <string name="_bx_posts_acl_action_view_entry"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_acl_action_set_thumb"><![CDATA[Set Post Header Image]]></string>
+    <string name="_bx_posts_acl_action_edit_any_entry"><![CDATA[Edit Any Post]]></string>
+    <string name="_bx_posts_acl_action_delete_any_entry"><![CDATA[Delete Any Post]]></string>
+
+    <string name="_bx_posts_page_title_sys_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_page_title_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_page_block_title_create_entry"><![CDATA[New Post]]></string>
+    <string name="_bx_posts_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_page_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_page_title_sys_view_entry"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_page_title_view_entry"><![CDATA[{title}]]></string>
+    <string name="_bx_posts_page_block_title_entry_text"><![CDATA[Post Text]]></string>
+    <string name="_bx_posts_page_title_browse"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_page_title_search_results"><![CDATA[Posts matching "{0}"]]></string>
+    <string name="_bx_posts_page_title_browse_by_author"><![CDATA[Posts of {display_name}]]></string>
+    <string name="_bx_posts_page_title_browse_by_context"><![CDATA[Posts in {display_name}]]></string>
+    <string name="_bx_posts_page_title_browse_featured"><![CDATA[Featured Posts]]></string>
+    <string name="_bx_posts_page_title_browse_recent"><![CDATA[Latest Posts]]></string>
+    <string name="_bx_posts_page_title_browse_popular"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_title_browse_top"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_title_browse_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_sys_home"><![CDATA[Posts Home]]></string>
+    <string name="_bx_posts_page_title_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_page_block_title_featured_entries_view_extended"><![CDATA[Featured Posts]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries"><![CDATA[Latest Posts (Gallery View)]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_extended"><![CDATA[Latest Posts]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_full"><![CDATA[Latest Posts (Full View)]]></string>
+    <string name="_bx_posts_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_posts_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_posts_page_block_title_entry_breadcrumb"><![CDATA[Breadcrumb]]></string>
+    <string name="_bx_posts_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_posts_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_posts_page_block_title_entry_reports"><![CDATA[Reports]]></string>
+    <string name="_bx_posts_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_posts_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_posts_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_posts_page_block_title_entry_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_posts_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_posts_page_title_sys_entries_popular"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_title_entries_popular"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_title_sys_entries_top"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_title_entries_top"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_title_sys_entries_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_entries_updated"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_page_title_sys_entries_favorites"><![CDATA[Favorites Posts]]></string>
+    <string name="_bx_posts_page_title_entries_favorites"><![CDATA[Favorites Posts]]></string>
+    <string name="_bx_posts_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_posts_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_posts_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_posts_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_extended"><![CDATA[Popular Posts (Extended View)]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_full"><![CDATA[Popular Posts (Full View)]]></string>
+    <string name="_bx_posts_page_block_title_top_entries"><![CDATA[Top Posts]]></string>
+    <string name="_bx_posts_page_block_title_updated_entries"><![CDATA[Updated Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_favorites_entries"><![CDATA[Favorite List]]></string>
+    <string name="_bx_posts_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_posts_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_posts_page_block_title_favorites_entries_actions"><![CDATA[Favorites List Actions]]></string>
+    <string name="_bx_posts_page_title_sys_view_entry_comments"><![CDATA[Post Comments]]></string>
+    <string name="_bx_posts_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_posts_page_title_sys_entries_of_author"><![CDATA[Posts of author]]></string>
+    <string name="_bx_posts_page_title_entries_of_author"><![CDATA[Posts by {display_name}]]></string>
+    <string name="_bx_posts_page_title_sys_entries_in_context"><![CDATA[Posts in context]]></string>
+    <string name="_bx_posts_page_title_entries_in_context"><![CDATA[Posts in {display_name}]]></string>
+    <string name="_bx_posts_page_block_title_favorites_of_author"><![CDATA[Favorites by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_sys_favorites_of_author"><![CDATA[Favorites of author]]></string>
+    <string name="_bx_posts_page_block_title_entries_of_author"><![CDATA[Posts by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_sys_entries_of_author"><![CDATA[Posts of author]]></string>
+    <string name="_bx_posts_page_block_title_entries_in_context"><![CDATA[Posts in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_sys_entries_in_context"><![CDATA[Posts in context]]></string>
+    <string name="_bx_posts_page_block_title_sys_multi_categories_in_context"><![CDATA[Multi categories in context]]></string>
+    <string name="_bx_posts_page_block_title_multi_categories_in_context"><![CDATA[Categories in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_posts_page_block_title_entries_actions"><![CDATA[Posts actions]]></string>
+    <string name="_bx_posts_page_block_title_browse_cmts"><![CDATA[Posts' Comments]]></string>
+    <string name="_bx_posts_page_title_sys_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_posts_page_title_sys_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_posts_page_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_page_block_title_system_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_posts_page_block_title_system_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_posts_page_block_title_manage"><![CDATA[Manage]]></string>    
+    <string name="_bx_posts_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+    <string name="_bx_posts_page_block_title_cats"><![CDATA[Posts Categories]]></string>
+    <string name="_bx_posts_page_block_title_sys_multicats"><![CDATA[Posts Categories(Multi)]]></string>
+    <string name="_bx_posts_page_block_title_multicats"><![CDATA[Posts Categories]]></string>
+    <string name="_bx_posts_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_posts_page_block_title_sys_my_entries"><![CDATA[User Posts]]></string>
+    <string name="_bx_posts_page_block_title_my_entries"><![CDATA[{display_name} Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_recent_entries_view_showcase"><![CDATA[Latest Posts (Showcase View)]]></string>
+    <string name="_bx_posts_page_block_title_recent_entries_view_showcase"><![CDATA[Latest Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_popular_entries_view_showcase"><![CDATA[Popular Posts (Showcase View)]]></string>
+    <string name="_bx_posts_page_block_title_popular_entries_view_showcase"><![CDATA[Popular Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Posts (Showcase View)]]></string>
+    <string name="_bx_posts_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Posts]]></string>
+    <string name="_bx_posts_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_posts_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+
+    <string name="_bx_posts_menu_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_posts_menu_set_title_entry_attachments"><![CDATA[Form Attachments]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_photo_simple"><![CDATA[Add Photo (simple)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_photo_simple"><![CDATA[Add Photo]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_photo_html5"><![CDATA[Add Photo (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_photo_html5"><![CDATA[Add Photos]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_video_simple"><![CDATA[Add Video (simple)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_video_simple"><![CDATA[Add Video]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_video_record_video"><![CDATA[Record Video]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_video_record_video"><![CDATA[Record Video]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_video_html5"><![CDATA[Add Video (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_video_html5"><![CDATA[Add Videos]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_file_simple"><![CDATA[Add File (simple)]]></string>
+
+    <string name="_bx_posts_menu_item_title_system_cpa_sound_simple"><![CDATA[Add Sound (simple)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_sound_simple"><![CDATA[Add Sound]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_sound_html5"><![CDATA[Add Sound (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_sound_html5"><![CDATA[Add Sound]]></string>
+  
+    <string name="_bx_posts_menu_item_title_cpa_file_simple"><![CDATA[Add File]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_file_html5"><![CDATA[Add File (html5)]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_file_html5"><![CDATA[Add Files]]></string>
+    <string name="_bx_posts_menu_item_title_system_cpa_poll"><![CDATA[Add Poll]]></string>
+    <string name="_bx_posts_menu_item_title_cpa_poll"><![CDATA[Add Poll]]></string>
+    
+    <string name="_bx_posts_menu_item_title_system_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_menu_item_title_add_link"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_post_input_link_err_delete"><![CDATA[Cannot remove the link. Please report.]]></string>
+    <string name="_bx_posts_form_post_input_sys_link"><![CDATA[Link]]></string>
+    <string name="_bx_posts_form_post_input_link_alt"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_attach_link"><![CDATA[Attach Link]]></string>
+    <string name="_bx_posts_form_attach_link_display_add"><![CDATA[Attach Link]]></string>
+    <string name="_bx_posts_form_attach_link_input_sys_content_id"><![CDATA[Content Id]]></string>
+    <string name="_bx_posts_form_attach_link_input_sys_url"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_attach_link_input_url_err"><![CDATA[Correct Link is essential. Please, fill in this field.]]></string>
+    <string name="_bx_posts_form_attach_link_input_url"><![CDATA[Add Link]]></string>
+    <string name="_bx_posts_form_attach_link_input_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_attach_link_input_sys_do_submit"><![CDATA[Add]]></string>
+    <string name="_bx_posts_form_attach_link_input_do_cancel"><![CDATA[Close]]></string>
+
+    <string name="_bx_posts_menu_set_title_view_entry"><![CDATA[Post Actions]]></string>
+    <string name="_bx_posts_menu_title_view_entry"><![CDATA[Post Actions]]></string>
+    <string name="_bx_posts_menu_title_submenu"><![CDATA[Posts Submenu]]></string>
+    <string name="_bx_posts_menu_title_public_submenu"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_set_title_submenu"><![CDATA[Posts Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_system_create_entry"><![CDATA[Post]]></string>
+    <string name="_bx_posts_menu_item_title_create_entry"><![CDATA[Post]]></string>
+    <string name="_bx_posts_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entry"><![CDATA[View Post]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_entries_home"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_menu_item_title_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_posts_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_posts_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_posts_menu_title_view_entry_submenu"><![CDATA[View Post Submenu]]></string>
+    <string name="_bx_posts_menu_set_title_view_entry_submenu"><![CDATA[View Post Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_view_entry_submenu_entry"><![CDATA[Post]]></string>
+    <string name="_bx_posts_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entry_comments"><![CDATA[Post Comments]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entries_author"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_view_entries_author"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_system_view_entries_in_context"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_view_entries_in_context"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_title_entries_my"><![CDATA[My Posts Action Menu]]></string>
+    <string name="_bx_posts_menu_set_title_entries_my"><![CDATA[My Posts Menu]]></string>
+    <string name="_bx_posts_menu_item_title_system_manage_my_posts"><![CDATA[My posts]]></string>
+    <string name="_bx_posts_menu_item_title_manage_my_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_posts_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_posts_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_posts_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_posts_menu_item_title_system_admt_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_admt_posts"><![CDATA[Posts]]></string>
+    <string name="_bx_posts_menu_item_title_manage_my"><![CDATA[My Posts]]></string>
+    <string name="_bx_posts_menu_item_title_manage_all"><![CDATA[All Posts]]></string>
+
+    <string name="_bx_posts_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_select_one_filter2"><![CDATA[Any Audience]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+    <string name="_bx_posts_grid_filter_item_title_adm_pending"><![CDATA[Pending]]></string>
+    <string name="_bx_posts_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_posts_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_posts_grid_action_title_adm_audit_content"><![CDATA[Audit actions]]></string>
+    <string name="_bx_posts_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_posts_grid_column_title_adm_author"><![CDATA[Author]]></string>>
+    <string name="_bx_posts_grid_action_title_adm_add"><![CDATA[Add]]></string>
+    <string name="_bx_posts_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_posts_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_posts_grid_action_title_adm_clear_reports"><![CDATA[Сlear reports]]></string>
+    <string name="_bx_posts_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_posts_grid_column_title_adm_status_admin"><![CDATA[Moderation]]></string>
+    <string name="_bx_posts_grid_action_err_delete"><![CDATA[Cannot delete the selected post(s).]]></string>
+    <string name="_bx_posts_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_posts_chart_growth"><![CDATA[Posts: Growth]]></string>
+    <string name="_bx_posts_chart_growth_speed"><![CDATA[Posts: Growth Speed]]></string>
+
+    <string name="_bx_posts_search_extended"><![CDATA[Posts Search]]></string>
+    <string name="_bx_posts_search_extended_cmts"><![CDATA[Posts Comments Search]]></string>
+
+    <string name="_bx_posts_pre_lists_cats"><![CDATA[Post categories]]></string>
+    <string name="_bx_posts_cat_Animals_Pets"><![CDATA[Animals & Pets]]></string>
+    <string name="_bx_posts_cat_Architecture"><![CDATA[Architecture]]></string>
+    <string name="_bx_posts_cat_Art"><![CDATA[Art]]></string>
+    <string name="_bx_posts_cat_Cars_Motorcycles"><![CDATA[Cars & Motorcycles]]></string>
+    <string name="_bx_posts_cat_Celebrities"><![CDATA[Celebrities]]></string>
+    <string name="_bx_posts_cat_Design"><![CDATA[Design]]></string>
+    <string name="_bx_posts_cat_DIY_Crafts"><![CDATA[DIY & Crafts]]></string>
+    <string name="_bx_posts_cat_Education"><![CDATA[Education]]></string>
+    <string name="_bx_posts_cat_Film_Music_Books"><![CDATA[Film, Music & Books]]></string>
+    <string name="_bx_posts_cat_Food_Drink"><![CDATA[Food & Drink]]></string>
+    <string name="_bx_posts_cat_Gardening"><![CDATA[Gardening]]></string>
+    <string name="_bx_posts_cat_Geek"><![CDATA[Geek]]></string>
+    <string name="_bx_posts_cat_Hair_Beauty"><![CDATA[Hair & Beauty]]></string>
+    <string name="_bx_posts_cat_Health_Fitness"><![CDATA[Health & Fitness]]></string>
+    <string name="_bx_posts_cat_History"><![CDATA[History]]></string>
+    <string name="_bx_posts_cat_Holidays_Events"><![CDATA[Holidays & Events]]></string>
+    <string name="_bx_posts_cat_Home_Decor"><![CDATA[Home Decor]]></string>
+    <string name="_bx_posts_cat_Humor"><![CDATA[Humor]]></string>
+    <string name="_bx_posts_cat_Illustrations_Posters"><![CDATA[Illustrations & Posters]]></string>
+    <string name="_bx_posts_cat_Kids_Parenting"><![CDATA[Kids & Parenting]]></string>
+    <string name="_bx_posts_cat_Mens_Fashion"><![CDATA[Men's Fashion]]></string>
+    <string name="_bx_posts_cat_Outdoors"><![CDATA[Outdoors]]></string>
+    <string name="_bx_posts_cat_Photography"><![CDATA[Photography]]></string>
+    <string name="_bx_posts_cat_Products"><![CDATA[Products]]></string>
+    <string name="_bx_posts_cat_Quotes"><![CDATA[Quotes]]></string>
+    <string name="_bx_posts_cat_Science_Nature"><![CDATA[Science & Nature]]></string>
+    <string name="_bx_posts_cat_Sports"><![CDATA[Sports]]></string>
+    <string name="_bx_posts_cat_Tattoos"><![CDATA[Tattoos]]></string>
+    <string name="_bx_posts_cat_Technology"><![CDATA[Technology]]></string>
+    <string name="_bx_posts_cat_Travel"><![CDATA[Travel]]></string>
+    <string name="_bx_posts_cat_Weddings"><![CDATA[Weddings]]></string>
+    <string name="_bx_posts_cat_Womens_Fashion"><![CDATA[Women's Fashion]]></string>
+
+    <string name="_bx_posts_txt_all_entries_in"><![CDATA[<a href="{0}">All Posts in {1} ({2})</a>]]></string>
+    <string name="_bx_posts_txt_all_entries_by"><![CDATA[{0} posts]]></string>
+    <string name="_bx_posts_txt_sample_single"><![CDATA[post]]></string>
+    <string name="_bx_posts_txt_sample_single_with_article"><![CDATA[a post]]></string>
+    <string name="_bx_posts_txt_sample_comment_single"><![CDATA[comment to post]]></string>
+    <string name="_bx_posts_txt_sample_vote_single"><![CDATA[vote to post]]></string>
+    <string name="_bx_posts_txt_sample_reaction_single"><![CDATA['{0}' reaction to post]]></string>
+    <string name="_bx_posts_txt_sample_score_up_single"><![CDATA[score up vote to post]]></string>
+    <string name="_bx_posts_txt_sample_score_down_single"><![CDATA[score down vote to post]]></string>
+    <string name="_bx_posts_txt_processing_awaiting"><![CDATA[Scheduled for publishing as soon as video conversion is complete.]]></string>
+    <string name="_bx_posts_txt_processing_failed"><![CDATA[Post isn't published because video conversion failed, edit video to fix the issue.]]></string>
+    <string name="_bx_posts_txt_scheduled_awaiting"><![CDATA[Post publishing date is {date_publish_uf}]]></string>
+
+    <string name="_bx_posts_txt_msg_status_hidden"><![CDATA[This post was hidden.]]></string>
+    <string name="_bx_posts_txt_msg_status_pending"><![CDATA[This post is pending approval.]]></string>
+    <string name="_bx_posts_txt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
+
+    <string name="_bx_posts_txt_poll_view_answers"><![CDATA[poll]]></string>
+    <string name="_bx_posts_txt_poll_view_results"><![CDATA[results]]></string>
+    <string name="_bx_posts_txt_poll_answer_vote_do_by"><![CDATA[Voted for]]></string>
+    <string name="_bx_posts_txt_poll_answer_vote_counter"><![CDATA[{0} votes]]></string>
+    <string name="_bx_posts_txt_poll_answer_vote_percent"><![CDATA[({0}%)]]></string>
+</resources>

+ 104 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/source/install/sql/enable-app.sql

@@ -0,0 +1,104 @@
+-- PAGES: config_api
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'post\',\r\n    top: true,\r\n    blocks: {\r\n        author: {\r\n            name: \'bx_posts:entity_author\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n            forHeader: true,\r\n        },\r\n        text: {\r\n            name: \'bx_posts:entity_text_block\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        attachments: {\r\n            name: \'bx_posts:entity_attachments\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        actions: {\r\n            name: \'bx_posts:entity_all_actions\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        \'comments-empty\': {\r\n            name: \'static:comments_empty\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            forList: true,\r\n        },\r\n        comments: {\r\n            name: \'bx_posts:entity_comments\',\r\n            showTitle: false,\r\n            showBg: false,\r\n        },\r\n    },\r\n    headerSettings: {\r\n        header: false,\r\n        footer: false,\r\n        offset: false,\r\n        backButton: true,\r\n        title: false,\r\n    },\r\n}' WHERE `object`='bx_posts_view_entry';
+UPDATE `sys_objects_page` SET `config_api`='{\r\n    layout: \'navigator\',\r\n    blocks: {\r\n        browse: {\r\n            name: \'bx_posts:browse_public\',\r\n            showTitle: false,\r\n            showBg: false,\r\n            perLine: 1,\r\n            unitType: \'small\',\r\n        },\r\n        browse_sidebar: {\r\n            name: \'bx_posts:browse_featured\',\r\n            showTitle: true,\r\n            showBg: false,\r\n            sidebar: true,\r\n        },\r\n    },\r\n}' WHERE `object`='bx_posts_home';
+
+-- PAGES: active_api
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_create_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_create_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_edit_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_edit_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_delete_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_delete_entry';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_breadcrumb';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_text';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_sys_entry_context' AND `title`='_bx_posts_page_block_title_entry_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_all_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_attachments';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_comments';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_location';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entry_polls';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_featured_entries_view_extended';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_view_entry_comments' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_entry_comments' AND `title`='_bx_posts_page_block_title_entry_comments_link';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_popular' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_popular_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_top' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_top_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_updated' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_updated_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_author' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_entries_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_author' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_sys_favorites_of_author' AND `title`='_bx_posts_page_block_title_favorites_of_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_author' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_sys_entries_of_author' AND `title`='_bx_posts_page_block_title_entries_of_author';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_author' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_sys_entries_in_context' AND `title`='_bx_posts_page_block_title_entries_in_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_favorites' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_sys_favorites_entries' AND `title`='_bx_posts_page_block_title_favorites_entries';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_favorites' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_favorites_entries_info';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_favorites' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_favorites_entries_actions';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_context' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_sys_entries_in_context' AND `title`='_bx_posts_page_block_title_entries_in_context';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_home' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_featured_entries_view_extended';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_home' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_recent_entries_view_extended';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_search' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_search_form';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_search' AND `module`='bx_posts' AND `title_system`='' AND `title`='_bx_posts_page_block_title_search_results';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_manage' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_system_manage' AND `title`='_bx_posts_page_block_title_manage';
+UPDATE `sys_pages_blocks` SET `active_api`=1 WHERE `object`='bx_posts_administration' AND `module`='bx_posts' AND `title_system`='_bx_posts_page_block_title_system_manage_administration' AND `title`='_bx_posts_page_block_title_manage';
+
+-- PAGES: menus_api
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_homepage' AND `module`='bx_posts' AND `name`='posts-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_add_content_links' AND `module`='bx_posts' AND `name`='create-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='photo_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='video_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='video_record_video';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='sound_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='file_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='add-link';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view' AND `module`='bx_posts' AND `name`='edit-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view' AND `module`='bx_posts' AND `name`='delete-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view' AND `module`='bx_posts' AND `name`='approve';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='edit-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='delete-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='comment';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='reaction';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='score';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='favorite';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='feature';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='report';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_my' AND `module`='bx_posts' AND `name`='create-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_submenu' AND `module`='bx_posts' AND `name`='posts-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_submenu' AND `module`='bx_posts' AND `name`='posts-popular';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_submenu' AND `module`='bx_posts' AND `name`='posts-manage';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_snippet_meta' AND `module`='bx_posts' AND `name`='author';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_snippet_meta' AND `module`='bx_posts' AND `name`='date';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_posts' AND `name`='profile-stats-my-posts';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_account_dashboard_manage_tools' AND `module`='bx_posts' AND `name`='posts-administration';
+
+
+-- MENUS:
+
+-- MENUS: config_api
+
+-- MENUS: active_api
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_site' AND `module`='bx_posts' AND `name`='posts-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_homepage' AND `module`='bx_posts' AND `name`='posts-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_add_content_links' AND `module`='bx_posts' AND `name`='create-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_create_post' AND `module`='bx_posts' AND `name`='create-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_profile_stats' AND `module`='bx_posts' AND `name`='profile-stats-my-posts';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='sys_account_dashboard_manage_tools' AND `module`='bx_posts' AND `name`='posts-administration';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='photo_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='video_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='video_record_video';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='sound_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='file_html5';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='poll';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_entry_attachments' AND `module`='bx_posts' AND `name`='add-link';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view' AND `module`='bx_posts' AND `name`='edit-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view' AND `module`='bx_posts' AND `name`='delete-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view' AND `module`='bx_posts' AND `name`='approve';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='edit-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='delete-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='comment';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='reaction';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='score';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='favorite';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='feature';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_view_actions' AND `module`='bx_posts' AND `name`='report';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_my' AND `module`='bx_posts' AND `name`='create-post';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_submenu' AND `module`='bx_posts' AND `name`='posts-home';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_submenu' AND `module`='bx_posts' AND `name`='posts-popular';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_submenu' AND `module`='bx_posts' AND `name`='posts-manage';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_snippet_meta' AND `module`='bx_posts' AND `name`='author';
+UPDATE `sys_menu_items` SET `active_api`=1 WHERE `set_name`='bx_posts_snippet_meta' AND `module`='bx_posts' AND `name`='date';

+ 539 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/source/install/sql/enable.sql

@@ -0,0 +1,539 @@
+
+-- 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_posts', '_bx_posts', 'bx_posts@modules/boonex/posts/|std-icon.svg', IF(ISNULL(@iTypeOrder), 1, @iTypeOrder + 1));
+SET @iTypeId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
+VALUES (@iTypeId, 'bx_posts', '_bx_posts', 1);
+SET @iCategId = LAST_INSERT_ID();
+
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `extra`, `order`) VALUES
+('bx_posts_enable_auto_approve', 'on', @iCategId, '_bx_posts_option_enable_auto_approve', 'checkbox', '', '', '', 0),
+('bx_posts_summary_chars', '700', @iCategId, '_bx_posts_option_summary_chars', 'digit', '', '', '', 1),
+('bx_posts_plain_summary_chars', '240', @iCategId, '_bx_posts_option_plain_summary_chars', 'digit', '', '', '', 2),
+('bx_posts_per_page_browse', '12', @iCategId, '_bx_posts_option_per_page_browse', 'digit', '', '', '', 10),
+('bx_posts_per_page_profile', '6', @iCategId, '_bx_posts_option_per_page_profile', 'digit', '', '', '', 12),
+('bx_posts_per_page_browse_showcase', '32', @iCategId, '_sys_option_per_page_browse_showcase', 'digit', '', '', '', 15),
+('bx_posts_per_page_for_favorites_lists', '5', @iCategId, '_bx_posts_option_per_page_for_favorites_lists', 'digit', '', '', '', 17),
+('bx_posts_rss_num', '10', @iCategId, '_bx_posts_option_rss_num', 'digit', '', '', '', 20),
+('bx_posts_searchable_fields', 'title,text', @iCategId, '_bx_posts_option_searchable_fields', 'list', '', '', 'a:2:{s:6:"module";s:8:"bx_posts";s:6:"method";s:21:"get_searchable_fields";}', 30),
+('bx_posts_auto_activation_for_categories', 'on', @iCategId, '_bx_posts_option_auto_activation_for_categories', 'checkbox', '', '', '', 35);
+
+-- 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_posts_create_entry', '_bx_posts_page_title_sys_create_entry', '_bx_posts_page_title_create_entry', 'bx_posts', 5, 2147483647, 1, 'create-post', 'page.php?i=create-post', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_posts_create_entry', 1, 'bx_posts', '_bx_posts_page_block_title_create_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_posts";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_posts_edit_entry', '_bx_posts_page_title_sys_edit_entry', '_bx_posts_page_title_edit_entry', 'bx_posts', 5, 2147483647, 1, 'edit-post', '', '', '', '', 0, 1, 0, 'BxPostsPageEntry', 'modules/boonex/posts/classes/BxPostsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_posts_edit_entry', 1, 'bx_posts', '_bx_posts_page_block_title_edit_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_posts";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_posts_delete_entry', '_bx_posts_page_title_sys_delete_entry', '_bx_posts_page_title_delete_entry', 'bx_posts', 5, 2147483647, 1, 'delete-post', '', '', '', '', 0, 1, 0, 'BxPostsPageEntry', 'modules/boonex/posts/classes/BxPostsPageEntry.php');
+
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('bx_posts_delete_entry', 1, 'bx_posts', '_bx_posts_page_block_title_delete_entry', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_posts";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_posts_view_entry', '_bx_posts_page_title_sys_view_entry', '_bx_posts_page_title_view_entry', 'bx_posts', 12, 2147483647, 1, 'view-post', '', '', '', '', 0, 1, 0, 'BxPostsPageEntry', 'modules/boonex/posts/classes/BxPostsPageEntry.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_posts_view_entry', 1,'bx_posts','', '_bx_posts_page_block_title_entry_breadcrumb', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_posts";s:6:"method";s:17:"entity_breadcrumb";}', 0, 0, 1, 1),
+('bx_posts_view_entry', 2, 'bx_posts', '', '_bx_posts_page_block_title_entry_text', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:17:\"entity_text_block\";}', 0, 0, 1, 2),
+('bx_posts_view_entry', 2, 'bx_posts', '', '_bx_posts_page_block_title_entry_author', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:13:\"entity_author\";}', 0, 0, 1, 1),
+('bx_posts_view_entry', 3, 'bx_posts', '_bx_posts_page_block_title_sys_entry_context', '_bx_posts_page_block_title_entry_context', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:14:\"entity_context\";}', 0, 0, 1, 1),
+('bx_posts_view_entry', 3, 'bx_posts', '', '_bx_posts_page_block_title_entry_info', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:11:\"entity_info\";}', 0, 0, 1, 2),
+('bx_posts_view_entry', 3, 'bx_posts', '', '_bx_posts_page_block_title_entry_location', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:15:\"entity_location\";}', 0, 0, 0, 0),
+('bx_posts_view_entry', 2, 'bx_posts', '', '_bx_posts_page_block_title_entry_all_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:18:\"entity_all_actions\";}', 0, 0, 1, 3),
+('bx_posts_view_entry', 4, 'bx_posts', '', '_bx_posts_page_block_title_entry_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:14:\"entity_actions\";}', 0, 0, 0, 0),
+('bx_posts_view_entry', 4, 'bx_posts', '', '_bx_posts_page_block_title_entry_social_sharing', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:21:\"entity_social_sharing\";}', 0, 0, 0, 0),
+('bx_posts_view_entry', 2, 'bx_posts', '', '_bx_posts_page_block_title_entry_attachments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:18:\"entity_attachments\";}', 0, 0, 1, 4),
+('bx_posts_view_entry', 2, 'bx_posts', '', '_bx_posts_page_block_title_entry_comments', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 1, 6),
+('bx_posts_view_entry', 3, 'bx_posts', '', '_bx_posts_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:8:\"bx_posts\";i:1;s:4:\"{id}\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 0, 1, 3),
+('bx_posts_view_entry', 2, 'bx_posts', '', '_bx_posts_page_block_title_entry_polls', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:12:\"entity_polls\";}', 0, 0, 1, 5),
+('bx_posts_view_entry', 3, 'bx_posts', '', '_bx_posts_page_block_title_featured_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 0, 1, 5),
+('bx_posts_view_entry', 2, 'bx_posts', '', '_bx_posts_page_block_title_entry_reports', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:14:\"entity_reports\";}', 0, 0, 1, 6);
+
+
+-- 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_posts_view_entry_comments', '_bx_posts_page_title_sys_view_entry_comments', '_bx_posts_page_title_view_entry_comments', 'bx_posts', 5, 2147483647, 1, 'view-post-comments', '', '', '', '', 0, 1, 0, 'BxPostsPageEntry', 'modules/boonex/posts/classes/BxPostsPageEntry.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_posts_view_entry_comments', 1, 'bx_posts', '_bx_posts_page_block_title_entry_comments', '_bx_posts_page_block_title_entry_comments_link', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:15:\"entity_comments\";}', 0, 0, 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_posts_popular', '_bx_posts_page_title_sys_entries_popular', '_bx_posts_page_title_entries_popular', 'bx_posts', 5, 2147483647, 1, 'posts-popular', 'page.php?i=posts-popular', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_posts_popular', 1, 'bx_posts', '_bx_posts_page_block_title_popular_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";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: top 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_posts_top', '_bx_posts_page_title_sys_entries_top', '_bx_posts_page_title_entries_top', 'bx_posts', 5, 2147483647, 1, 'posts-top', 'page.php?i=posts-top', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_posts_top', 1, 'bx_posts', '_bx_posts_page_block_title_top_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:10:"browse_top";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_posts_updated', '_bx_posts_page_title_sys_entries_updated', '_bx_posts_page_title_entries_updated', 'bx_posts', 5, 2147483647, 1, 'posts-updated', 'page.php?i=posts-updated', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_posts_updated', 1, 'bx_posts', '_bx_posts_page_block_title_updated_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";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_posts_author', 'posts-author', '_bx_posts_page_title_sys_entries_of_author', '_bx_posts_page_title_entries_of_author', 'bx_posts', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxPostsPageAuthor', 'modules/boonex/posts/classes/BxPostsPageAuthor.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_posts_author', 1, 'bx_posts', '', '_bx_posts_page_block_title_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:18:\"my_entries_actions\";}', 0, 0, 1, 1),
+('bx_posts_author', 1, 'bx_posts', '_bx_posts_page_block_title_sys_favorites_of_author', '_bx_posts_page_block_title_favorites_of_author', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:21:"browse_favorite_lists";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:8:"showcase";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1, 2),
+('bx_posts_author', 1, 'bx_posts', '_bx_posts_page_block_title_sys_entries_of_author', '_bx_posts_page_block_title_entries_of_author', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:13:\"browse_author\";}', 0, 0, 1, 3),
+('bx_posts_author', 1, 'bx_posts', '_bx_posts_page_block_title_sys_entries_in_context', '_bx_posts_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:14:"browse_context";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";i:0;a:1:{s:13:"empty_message";b:0;}}}', 0, 0, 1, 4);
+
+
+-- PAGE: favorites by list
+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_posts_favorites', '_bx_posts_page_title_sys_entries_favorites', '_bx_posts_page_title_entries_favorites', 'bx_posts', 12, 2147483647, 1, 'posts-favorites', 'page.php?i=posts-favorites', '', '', '', 0, 1, 0, 'BxPostsPageListEntry', 'modules/boonex/posts/classes/BxPostsPageListEntry.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_posts_favorites', 2, 'bx_posts', '_bx_posts_page_block_title_sys_favorites_entries', '_bx_posts_page_block_title_favorites_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:15:"browse_favorite";s:6:"params";a:2:{s:10:"profile_id";s:12:"{profile_id}";s:6:"params";a:3:{s:9:"unit_view";s:7:"gallery";s:13:"empty_message";b:0;s:13:"ajax_paginate";b:0;}}}', 0, 1, 1),
+('bx_posts_favorites', 3, 'bx_posts', '', '_bx_posts_page_block_title_favorites_entries_info', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_posts";s:6:"method";s:19:"favorites_list_info";}', 0, 0, 0),
+('bx_posts_favorites', 3, 'bx_posts', '', '_bx_posts_page_block_title_favorites_entries_actions', 13, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_posts";s:6:"method";s:22:"favorites_list_actions";}', 0, 0, 1);
+
+-- PAGE: entries in context
+
+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_posts_context', 'posts-context', '_bx_posts_page_title_sys_entries_in_context', '_bx_posts_page_title_entries_in_context', 'bx_posts', 5, 2147483647, 1, '', '', '', '', 0, 1, 0, 'BxPostsPageAuthor', 'modules/boonex/posts/classes/BxPostsPageAuthor.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_posts_context', 1, 'bx_posts', '_bx_posts_page_block_title_sys_entries_in_context', '_bx_posts_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:14:\"browse_context\";}', 0, 0, 1, 1),
+('bx_posts_context', 1, 'bx_posts', '_bx_posts_page_block_title_sys_multi_categories_in_context', '_bx_posts_page_block_title_multi_categories_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:29:\"categories_multi_list_context\";}', 0, 0, 0, 2);
+
+-- 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_posts_home', 'posts-home', '_bx_posts_page_title_sys_home', '_bx_posts_page_title_home', 'bx_posts', 2, 2147483647, 1, 'page.php?i=posts-home', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.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_posts_home', 1, 'bx_posts', '', '_bx_posts_page_block_title_featured_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:15:"browse_featured";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1, 0),
+('bx_posts_home', 1, 'bx_posts', '', '_bx_posts_page_block_title_recent_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:13:"browse_public";s:6:"params";a:1:{i:0;s:8:"extended";}}', 0, 1, 1, 1),
+('bx_posts_home', 2, 'bx_posts', '', '_bx_posts_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:8:\"bx_posts\";i:1;s:8:\"bx_posts\";}s:5:\"class\";s:20:\"TemplServiceMetatags\";}', 0, 1, 1, 0),
+('bx_posts_home', 2, 'bx_posts', '', '_bx_posts_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:13:\"bx_posts_cats\";i:1;a:1:{s:10:\"show_empty\";b:1;}}s:5:\"class\";s:20:\"TemplServiceCategory\";}', 0, 1, 1, 1),
+('bx_posts_home', 2, 'bx_posts', '_bx_posts_page_block_title_sys_multicats', '_bx_posts_page_block_title_multicats', 11, 2147483647, 'service', 'a:2:{s:6:"module";s:8:"bx_posts";s:6:"method";s:21:"categories_multi_list";}', 0, 1, 0, 2);
+
+-- PAGE: search for 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_posts_search', '_bx_posts_page_title_sys_entries_search', '_bx_posts_page_title_entries_search', 'bx_posts', 5, 2147483647, 1, 'posts-search', 'page.php?i=posts-search', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `active`, `order`) VALUES 
+('bx_posts_search', 1, 'bx_posts', '_bx_posts_page_block_title_search_form', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:8:"bx_posts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 1),
+('bx_posts_search', 1, 'bx_posts', '_bx_posts_page_block_title_search_results', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:8:"bx_posts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 1, 2),
+('bx_posts_search', 1, 'bx_posts', '_bx_posts_page_block_title_search_form_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:8:"get_form";s:6:"params";a:1:{i:0;a:1:{s:6:"object";s:13:"bx_posts_cmts";}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 3),
+('bx_posts_search', 1, 'bx_posts', '_bx_posts_page_block_title_search_results_cmts', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:11:"get_results";s:6:"params";a:1:{i:0;a:2:{s:6:"object";s:13:"bx_posts_cmts";s:10:"show_empty";b:1;}}s:5:"class";s:27:"TemplSearchExtendedServices";}', 0, 1, 0, 4);
+
+
+-- 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_posts_manage', '_bx_posts_page_title_sys_manage', '_bx_posts_page_title_manage', 'bx_posts', 5, 2147483647, 1, 'posts-manage', 'page.php?i=posts-manage', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.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_posts_manage', 1, 'bx_posts', '_bx_posts_page_block_title_system_manage', '_bx_posts_page_block_title_manage', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_posts\";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_posts_administration', '_bx_posts_page_title_sys_manage_administration', '_bx_posts_page_title_manage', 'bx_posts', 5, 192, 1, 'posts-administration', 'page.php?i=posts-administration', '', '', '', 0, 1, 0, 'BxPostsPageBrowse', 'modules/boonex/posts/classes/BxPostsPageBrowse.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_posts_administration', 1, 'bx_posts', '_bx_posts_page_block_title_system_manage_administration', '_bx_posts_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_posts\";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_posts', '_bx_posts_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:13:"browse_public";s:6:"params";a:2:{i:0;b:0;i:1;b:0;}}', 1, 0, 0, IFNULL(@iBlockOrder, 0) + 1);
+
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellProfile = 3;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_posts', '_bx_posts_page_block_title_sys_my_entries', '_bx_posts_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:25:"bx_posts_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0);
+
+-- 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_system` , `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('', 0, 'bx_posts', '', '_bx_posts_page_block_title_recent_entries', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_posts\";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_posts', '', '_bx_posts_page_block_title_recent_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";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_posts', '', '_bx_posts_page_block_title_popular_entries_view_extended', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";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_posts', '', '_bx_posts_page_block_title_popular_entries_view_full', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:14:"browse_popular";s:6:"params";a:1:{i:0;s:4:"full";}}', 0, 1, IFNULL(@iBlockOrder, 0) + 4),
+('', 0, 'bx_posts', '_bx_posts_page_block_title_sys_recent_entries_view_showcase', '_bx_posts_page_block_title_recent_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:13:\"browse_public\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 5),
+('', 0, 'bx_posts', '_bx_posts_page_block_title_sys_popular_entries_view_showcase', '_bx_posts_page_block_title_popular_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:14:\"browse_popular\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 6),
+('', 0, 'bx_posts', '_bx_posts_page_block_title_sys_featured_entries_view_showcase', '_bx_posts_page_block_title_featured_entries_view_showcase', 11, 2147483647, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_posts\";s:6:\"method\";s:15:\"browse_featured\";s:6:\"params\";a:3:{s:9:\"unit_view\";s:8:\"showcase\";s:13:\"empty_message\";b:0;s:13:\"ajax_paginate\";b:0;}}', 0, 1, IFNULL(@iBlockOrder, 0) + 7);
+
+
+-- MENU: add to site menu
+
+SET @iSiteMenuOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_site' AND `active` = 1 AND `order` < 9999 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_posts', 'posts-home', '_bx_posts_menu_item_title_system_entries_home', '_bx_posts_menu_item_title_entries_home', 'page.php?i=posts-home', '', '', 'file-alt col-red3', 'bx_posts_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_posts', 'posts-home', '_bx_posts_menu_item_title_system_entries_home', '_bx_posts_menu_item_title_entries_home', 'page.php?i=posts-home', '', '', 'file-alt col-red3', 'bx_posts_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_posts', 'create-post', '_bx_posts_menu_item_title_system_create_entry', '_bx_posts_menu_item_title_create_entry', 'page.php?i=create-post', '', '', 'file-alt col-red3', '', 2147483647, 1, 1, IFNULL(@iAddMenuOrder, 0) + 1);
+
+-- MENU: add to "create post" menu
+SET @iCreatePostOrder = (SELECT `order` FROM `sys_menu_items` WHERE `set_name` = 'sys_create_post' 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_create_post', 'bx_posts', 'create-post', '_bx_posts_menu_item_title_system_create_entry', '_bx_posts_menu_item_title_create_entry', 'page.php?i=create-post', '', '', 'file-alt col-red3', '', 2147483647, 1, 0, IFNULL(@iCreatePostOrder, 0) + 1);
+
+-- MENU: create post form attachments (link, photo, video, etc)
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_posts_entry_attachments', '_bx_posts_menu_title_entry_attachments', 'bx_posts_entry_attachments', 'bx_posts', 23, 0, 1, 'BxPostsMenuAttachments', 'modules/boonex/posts/classes/BxPostsMenuAttachments.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_entry_attachments', 'bx_posts', '_bx_posts_menu_set_title_entry_attachments', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_posts_entry_attachments', 'bx_posts', 'photo_simple', '_bx_posts_menu_item_title_system_cpa_photo_simple', '_bx_posts_menu_item_title_cpa_photo_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_photos_simple}.showUploaderForm();', '_self', 'camera', '', '', 2147483647, '', 0, 0, 1, 1),
+('bx_posts_entry_attachments', 'bx_posts', 'photo_html5', '_bx_posts_menu_item_title_system_cpa_photo_html5', '_bx_posts_menu_item_title_cpa_photo_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_photos_html5}.showUploaderForm();', '_self', 'camera', '', '', 2147483647, '', 1, 0, 1, 2),
+('bx_posts_entry_attachments', 'bx_posts', 'video_simple', '_bx_posts_menu_item_title_system_cpa_video_simple', '_bx_posts_menu_item_title_cpa_video_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_simple}.showUploaderForm();', '_self', 'video', '', '', 2147483647, '', 0, 0, 1, 3),
+('bx_posts_entry_attachments', 'bx_posts', 'video_html5', '_bx_posts_menu_item_title_system_cpa_video_html5', '_bx_posts_menu_item_title_cpa_video_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_html5}.showUploaderForm();', '_self', 'video', '', '', 2147483647, '', 1, 0, 1, 4),
+('bx_posts_entry_attachments', 'bx_posts', 'video_record_video', '_bx_posts_menu_item_title_system_cpa_video_record_video', '_bx_posts_menu_item_title_cpa_video_record_video', 'javascript:void(0)', 'javascript:{js_object_uploader_videos_record_video}.showUploaderForm();', '_self', 'fas circle', '', '', 2147483647, '', 1, 0, 1, 5),
+('bx_posts_entry_attachments', 'bx_posts', 'sound_simple', '_bx_posts_menu_item_title_system_cpa_sound_simple', '_bx_posts_menu_item_title_cpa_sound_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_sounds_simple}.showUploaderForm();', '_self', 'music', '', '', 2147483647, '', 0, 0, 1, 6),
+('bx_posts_entry_attachments', 'bx_posts', 'sound_html5', '_bx_posts_menu_item_title_system_cpa_sound_html5', '_bx_posts_menu_item_title_cpa_sound_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_sounds_html5}.showUploaderForm();', '_self', 'music', '', '', 2147483647, '', 1, 0, 1, 7),
+('bx_posts_entry_attachments', 'bx_posts', 'file_simple', '_bx_posts_menu_item_title_system_cpa_file_simple', '_bx_posts_menu_item_title_cpa_file_simple', 'javascript:void(0)', 'javascript:{js_object_uploader_files_simple}.showUploaderForm();', '_self', 'file', '', '', 2147483647, '', 0, 0, 1, 8),
+('bx_posts_entry_attachments', 'bx_posts', 'file_html5', '_bx_posts_menu_item_title_system_cpa_file_html5', '_bx_posts_menu_item_title_cpa_file_html5', 'javascript:void(0)', 'javascript:{js_object_uploader_files_html5}.showUploaderForm();', '_self', 'file', '', '', 2147483647, '', 1, 0, 1, 9),
+('bx_posts_entry_attachments', 'bx_posts', 'poll', '_bx_posts_menu_item_title_system_cpa_poll', '_bx_posts_menu_item_title_cpa_poll', 'javascript:void(0)', 'javascript:{js_object}.showPollForm(this);', '_self', 'tasks', '', '', 2147483647, '', 1, 0, 1, 7),
+('bx_posts_entry_attachments', 'bx_posts', 'add-link', '_bx_posts_menu_item_title_system_add_link', '_bx_posts_menu_item_title_add_link', 'javascript:void(0)', 'javascript:{js_object_link}.showAttachLink(this);', '_self', 'link', '', '', 2147483647, '', 1, 0, 1, 10);
+
+-- 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_posts_view', '_bx_posts_menu_title_view_entry', 'bx_posts_view', 'bx_posts', 9, 0, 1, 'BxPostsMenuView', 'modules/boonex/posts/classes/BxPostsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_view', 'bx_posts', '_bx_posts_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_posts_view', 'bx_posts', 'edit-post', '_bx_posts_menu_item_title_system_edit_entry', '_bx_posts_menu_item_title_edit_entry', 'page.php?i=edit-post&id={content_id}', '', '', 'pencil-alt', '', 2147483647, 1, 0, 1),
+('bx_posts_view', 'bx_posts', 'delete-post', '_bx_posts_menu_item_title_system_delete_entry', '_bx_posts_menu_item_title_delete_entry', 'page.php?i=delete-post&id={content_id}', '', '', 'remove', '', 2147483647, 1, 0, 2),
+('bx_posts_view', 'bx_posts', 'approve', '_sys_menu_item_title_system_va_approve', '_sys_menu_item_title_va_approve', 'javascript:void(0)', 'javascript:bx_approve(this, ''{module_uri}'', {content_id});', '', 'check', '', 2147483647, 1, 0, 3);
+
+
+-- MENU: all 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_posts_view_actions', '_sys_menu_title_view_actions', 'bx_posts_view_actions', 'bx_posts', 15, 0, 1, 'BxPostsMenuViewActions', 'modules/boonex/posts/classes/BxPostsMenuViewActions.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_view_actions', 'bx_posts', '_sys_menu_set_title_view_actions', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_posts_view_actions', 'bx_posts', 'edit-post', '_bx_posts_menu_item_title_system_edit_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 10),
+('bx_posts_view_actions', 'bx_posts', 'delete-post', '_bx_posts_menu_item_title_system_delete_entry', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 20),
+('bx_posts_view_actions', 'bx_posts', 'approve', '_sys_menu_item_title_system_va_approve', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 30),
+('bx_posts_view_actions', 'bx_posts', 'set-badges', '_sys_menu_item_title_system_set_badges', '_sys_menu_item_title_set_badges', 'javascript:void(0)', 'bx_menu_popup(''sys_set_badges'', window, {}, {module: ''bx_posts'', content_id: {content_id}});', '', 'check-circle', '', '', 0, 2147483647, 'a:2:{s:6:"module";s:8:"bx_posts";s:6:"method";s:19:"is_badges_avaliable";}', 1, 0, 40),
+('bx_posts_view_actions', 'bx_posts', 'comment', '_sys_menu_item_title_system_va_comment', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 200),
+('bx_posts_view_actions', 'bx_posts', 'view', '_sys_menu_item_title_system_va_view', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 210),
+('bx_posts_view_actions', 'bx_posts', 'vote', '_sys_menu_item_title_system_va_vote', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 220),
+('bx_posts_view_actions', 'bx_posts', 'reaction', '_sys_menu_item_title_system_va_reaction', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 225),
+('bx_posts_view_actions', 'bx_posts', 'score', '_sys_menu_item_title_system_va_score', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 230),
+('bx_posts_view_actions', 'bx_posts', 'favorite', '_sys_menu_item_title_system_va_favorite', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 240),
+('bx_posts_view_actions', 'bx_posts', 'feature', '_sys_menu_item_title_system_va_feature', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 250),
+('bx_posts_view_actions', 'bx_posts', 'repost', '_sys_menu_item_title_system_va_repost', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 260),
+('bx_posts_view_actions', 'bx_posts', 'repost-with-text', '_sys_menu_item_title_system_va_repost_with_text', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 261),
+('bx_posts_view_actions', 'bx_posts', 'repost-to-context', '_sys_menu_item_title_system_va_repost_to_context', '', '', '', '', '', '', '', 0, 2147483647, '', 0, 0, 262),
+('bx_posts_view_actions', 'bx_posts', 'report', '_sys_menu_item_title_system_va_report', '', '', '', '', '', '', '', 0, 2147483647, '', 1, 0, 270),
+('bx_posts_view_actions', 'bx_posts', 'notes', '_sys_menu_item_title_system_va_notes', '_sys_menu_item_title_va_notes', 'javascript:void(0)', 'javascript:bx_get_notes(this,  ''{module_uri}'', {content_id});', '', 'exclamation-triangle', '', '', 0, 2147483647, '', 1, 0, 280),
+('bx_posts_view_actions', 'bx_posts', 'audit', '_sys_menu_item_title_system_va_audit', '_sys_menu_item_title_va_audit', 'page.php?i=dashboard-audit&module=bx_posts&content_id={content_id}', '', '', 'history', '', '', 0, 192, '', 1, 0, 290),
+('bx_posts_view_actions', 'bx_posts', 'social-sharing', '_sys_menu_item_title_system_social_sharing', '_sys_menu_item_title_social_sharing', 'javascript:void(0)', 'oBxDolPage.share(this, \'{url_encoded}\')', '', 'share', '', '', 0, 2147483647, '', 1, 0, 300),
+('bx_posts_view_actions', 'bx_posts', 'more-auto', '_sys_menu_item_title_system_va_more_auto', '_sys_menu_item_title_va_more_auto', 'javascript:void(0)', '', '', 'ellipsis-v', '', '', 0, 2147483647, '', 1, 0, 9999);
+
+
+-- 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_posts_my', '_bx_posts_menu_title_entries_my', 'bx_posts_my', 'bx_posts', 9, 0, 1, 'BxPostsMenu', 'modules/boonex/posts/classes/BxPostsMenu.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_my', 'bx_posts', '_bx_posts_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_posts_my', 'bx_posts', 'create-post', '_bx_posts_menu_item_title_system_create_entry', '_bx_posts_menu_item_title_create_entry', 'page.php?i=create-post', '', '', 'plus', '', 2147483647, 1, 0, 0);
+
+
+-- MENU: module sub-menu
+
+INSERT INTO `sys_objects_menu`(`object`, `title`, `title_public`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_posts_submenu', '_bx_posts_menu_title_submenu', '_bx_posts_menu_title_public_submenu', 'bx_posts_submenu', 'bx_posts', 8, 0, 1, '', '');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_submenu', 'bx_posts', '_bx_posts_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_posts_submenu', 'bx_posts', 'posts-home', '_bx_posts_menu_item_title_system_entries_public', '_bx_posts_menu_item_title_entries_public', 'page.php?i=posts-home', '', '', '', '', 2147483647, 1, 1, 1),
+('bx_posts_submenu', 'bx_posts', 'posts-popular', '_bx_posts_menu_item_title_system_entries_popular', '_bx_posts_menu_item_title_entries_popular', 'page.php?i=posts-popular', '', '', '', '', 2147483647, 1, 1, 2),
+('bx_posts_submenu', 'bx_posts', 'posts-top', '_bx_posts_menu_item_title_system_entries_top', '_bx_posts_menu_item_title_entries_top', 'page.php?i=posts-top', '', '', '', '', 2147483647, 1, 1, 3),
+('bx_posts_submenu', 'bx_posts', 'posts-search', '_bx_posts_menu_item_title_system_entries_search', '_bx_posts_menu_item_title_entries_search', 'page.php?i=posts-search', '', '', '', '', 2147483647, 1, 1, 4),
+('bx_posts_submenu', 'bx_posts', 'posts-manage', '_bx_posts_menu_item_title_system_entries_manage', '_bx_posts_menu_item_title_entries_manage', 'page.php?i=posts-manage', '', '', '', '', 2147483646, 1, 1, 5);
+
+-- 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_posts_view_submenu', '_bx_posts_menu_title_view_entry_submenu', 'bx_posts_view_submenu', 'bx_posts', 8, 0, 1, 'BxPostsMenuView', 'modules/boonex/posts/classes/BxPostsMenuView.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_view_submenu', 'bx_posts', '_bx_posts_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_posts_view_submenu', 'bx_posts', 'view-post', '_bx_posts_menu_item_title_system_view_entry', '_bx_posts_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-post&id={content_id}', '', '', '', '', 2147483647, 0, 0, 1),
+('bx_posts_view_submenu', 'bx_posts', 'view-post-comments', '_bx_posts_menu_item_title_system_view_entry_comments', '_bx_posts_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-post-comments&id={content_id}', '', '', '', '', 2147483647, 0, 0, 2);
+
+-- MENU: custom menu for snippet meta info
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_posts_snippet_meta', '_sys_menu_title_snippet_meta', 'bx_posts_snippet_meta', 'bx_posts', 15, 0, 1, 'BxPostsMenuSnippetMeta', 'modules/boonex/posts/classes/BxPostsMenuSnippetMeta.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_snippet_meta', 'bx_posts', '_sys_menu_set_title_snippet_meta', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
+('bx_posts_snippet_meta', 'bx_posts', 'author', '_sys_menu_item_title_system_sm_author', '_sys_menu_item_title_sm_author', '', '', '', '', '', 2147483647, 1, 0, 1, 1),
+('bx_posts_snippet_meta', 'bx_posts', 'date', '_sys_menu_item_title_system_sm_date', '_sys_menu_item_title_sm_date', '', '', '', '', '', 2147483647, 1, 0, 1, 2),
+('bx_posts_snippet_meta', 'bx_posts', 'category', '_sys_menu_item_title_system_sm_category', '_sys_menu_item_title_sm_category', '', '', '', '', '', 2147483647, 0, 0, 1, 3),
+('bx_posts_snippet_meta', 'bx_posts', 'tags', '_sys_menu_item_title_system_sm_tags', '_sys_menu_item_title_sm_tags', '', '', '', '', '', 2147483647, 0, 0, 1, 4),
+('bx_posts_snippet_meta', 'bx_posts', 'views', '_sys_menu_item_title_system_sm_views', '_sys_menu_item_title_sm_views', '', '', '', '', '', 2147483647, 0, 0, 1, 5),
+('bx_posts_snippet_meta', 'bx_posts', 'comments', '_sys_menu_item_title_system_sm_comments', '_sys_menu_item_title_sm_comments', '', '', '', '', '', 2147483647, 0, 0, 1, 6);
+
+-- 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_posts', 'profile-stats-my-posts', '_bx_posts_menu_item_title_system_manage_my_posts', '_bx_posts_menu_item_title_manage_my_posts', 'page.php?i=posts-author&profile_id={member_id}', '', '_self', 'file-alt col-red3', 'a:2:{s:6:"module";s:8:"bx_posts";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_posts_menu_manage_tools', '_bx_posts_menu_title_manage_tools', 'bx_posts_menu_manage_tools', 'bx_posts', 6, 0, 1, 'BxPostsMenuManageTools', 'modules/boonex/posts/classes/BxPostsMenuManageTools.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_posts_menu_manage_tools', 'bx_posts', '_bx_posts_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_posts_menu_manage_tools', 'bx_posts', 'delete-with-content', '_bx_posts_menu_item_title_system_delete_with_content', '_bx_posts_menu_item_title_delete_with_content', 'javascript:void(0)', 'javascript:{js_object}.onClickDeleteWithContent({content_id});', '_self', 'far trash-alt', '', 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_posts', 'posts-administration', '_bx_posts_menu_item_title_system_admt_posts', '_bx_posts_menu_item_title_admt_posts', 'page.php?i=posts-administration', '', '_self', 'file-alt', 'a:2:{s:6:"module";s:8:"bx_posts";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_posts', 'posts-author', '_bx_posts_menu_item_title_system_view_entries_author', '_bx_posts_menu_item_title_view_entries_author', 'page.php?i=posts-author&profile_id={profile_id}', '', '', 'file-alt col-red3', '', 2147483647, 1, 0, 0),
+('trigger_group_view_submenu', 'bx_posts', 'posts-context', '_bx_posts_menu_item_title_system_view_entries_in_context', '_bx_posts_menu_item_title_view_entries_in_context', 'page.php?i=posts-context&profile_id={profile_id}', '', '', 'file-alt col-red3', '', 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_posts_allow_view_to', 'bx_posts', 'view', '_bx_posts_form_entry_input_allow_view_to', '3', 'bx_posts_posts', 'id', 'author', '', ''),
+('bx_posts_allow_view_favorite_list', 'bx_posts', 'view_favorite_list', '_bx_posts_form_entry_input_allow_view_favorite_list', '3', 'bx_posts_favorites_lists', 'id', 'author_id', '', '');
+
+
+-- ACL
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_posts', 'create entry', NULL, '_bx_posts_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_posts', 'delete entry', NULL, '_bx_posts_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_posts', 'view entry', NULL, '_bx_posts_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_posts', 'set thumb', NULL, '_bx_posts_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_posts', 'edit any entry', NULL, '_bx_posts_acl_action_edit_any_entry', '', 1, 3);
+SET @iIdActionEntryEditAny = LAST_INSERT_ID();
+
+INSERT INTO `sys_acl_actions` (`Module`, `Name`, `AdditionalParamName`, `Title`, `Desc`, `Countable`, `DisabledForLevels`) VALUES
+('bx_posts', 'delete any entry', NULL, '_bx_posts_acl_action_delete_any_entry', '', 1, 3);
+SET @iIdActionEntryDeleteAny = 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),
+
+-- delete any entry
+(@iAdministrator, @iIdActionEntryDeleteAny);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_posts', '_bx_posts', @iSearchOrder + 1, 'BxPostsSearchResult', 'modules/boonex/posts/classes/BxPostsSearchResult.php'),
+('bx_posts_cmts', '_bx_posts_cmts', @iSearchOrder + 2, 'BxPostsCmtsSearchResult', 'modules/boonex/posts/classes/BxPostsCmtsSearchResult.php');
+
+-- METATAGS
+INSERT INTO `sys_objects_metatags` (`object`, `module`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts', 'bx_posts', 'bx_posts_meta_keywords', 'bx_posts_meta_locations', 'bx_posts_meta_mentions', '', '');
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `module`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_cats', 'bx_posts', 'bx_posts', 'bx_posts', 'bx_posts_cats', 'bx_posts_posts', 'cat', 'INNER JOIN `sys_profiles` ON (`sys_profiles`.`id` = ABS(`bx_posts_posts`.`author`))', 'AND `sys_profiles`.`status` = ''active''', '', '');
+
+-- STATS
+SET @iMaxOrderStats = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_statistics`);
+INSERT INTO `sys_statistics` (`module`, `name`, `title`, `link`, `icon`, `query`, `order`) VALUES 
+('bx_posts', 'bx_posts', '_bx_posts', 'page.php?i=posts-home', 'file-alt col-red3', 'SELECT COUNT(*) FROM `bx_posts_posts` WHERE 1 AND `status` = ''active'' AND `status_admin` = ''active''', @iMaxOrderStats + 1);
+
+-- CHARTS
+SET @iMaxOrderCharts = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_objects_chart`);
+INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `field_date_dt`, `field_status`, `query`, `active`, `order`, `class_name`, `class_file`) VALUES
+('bx_posts_growth', '_bx_posts_chart_growth', 'bx_posts_posts', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
+('bx_posts_growth_speed', '_bx_posts_chart_growth_speed', 'bx_posts_posts', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
+
+-- 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`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_administration', 'Sql', 'SELECT * FROM `bx_posts_posts` WHERE 1 ', 'bx_posts_posts', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'title,text', '', 'like', 'reports', '', 192, 'BxPostsGridAdministration', 'modules/boonex/posts/classes/BxPostsGridAdministration.php'),
+('bx_posts_common', 'Sql', 'SELECT * FROM `bx_posts_posts` WHERE 1 ', 'bx_posts_posts', 'id', 'added', 'status', '', 20, NULL, 'start', '', 'title,text', '', 'like', '', '', 2147483647, 'BxPostsGridCommon', 'modules/boonex/posts/classes/BxPostsGridCommon.php');
+
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_posts_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_posts_administration', 'switcher', '_bx_posts_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_posts_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
+('bx_posts_administration', 'title', '_bx_posts_grid_column_title_adm_title', '25%', 0, '25', '', 4),
+('bx_posts_administration', 'added', '_bx_posts_grid_column_title_adm_added', '20%', 1, '25', '', 5),
+('bx_posts_administration', 'author', '_bx_posts_grid_column_title_adm_author', '20%', 0, '25', '', 6),
+('bx_posts_administration', 'actions', '', '20%', 0, '', '', 7),
+
+('bx_posts_common', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
+('bx_posts_common', 'switcher', '_bx_posts_grid_column_title_adm_active', '8%', 0, '', '', 2),
+('bx_posts_common', 'title', '_bx_posts_grid_column_title_adm_title', '40%', 0, '35', '', 3),
+('bx_posts_common', 'added', '_bx_posts_grid_column_title_adm_added', '15%', 1, '25', '', 4),
+('bx_posts_common', 'status_admin', '_bx_posts_grid_column_title_adm_status_admin', '15%', 0, '16', '', 5),
+('bx_posts_common', 'actions', '', '20%', 0, '', '', 6);
+
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_posts_administration', 'bulk', 'delete', '_bx_posts_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_posts_administration', 'bulk', 'clear_reports', '_bx_posts_grid_action_title_adm_clear_reports', '', 0, 1, 1),
+('bx_posts_administration', 'single', 'edit', '_bx_posts_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_posts_administration', 'single', 'delete', '_bx_posts_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_posts_administration', 'single', 'settings', '_bx_posts_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
+('bx_posts_administration', 'single', 'audit_content', '_bx_posts_grid_action_title_adm_audit_content', 'search', 1, 0, 4),
+('bx_posts_administration', 'single', 'clear_reports', '_bx_posts_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5),
+
+('bx_posts_common', 'bulk', 'delete', '_bx_posts_grid_action_title_adm_delete', '', 0, 1, 1),
+('bx_posts_common', 'single', 'edit', '_bx_posts_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
+('bx_posts_common', 'single', 'delete', '_bx_posts_grid_action_title_adm_delete', 'remove', 1, 1, 2),
+('bx_posts_common', 'single', 'settings', '_bx_posts_grid_action_title_adm_more_actions', 'cog', 1, 0, 3);
+
+-- UPLOADERS
+
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_html5', 1, 'BxPostsUploaderHTML5', 'modules/boonex/posts/classes/BxPostsUploaderHTML5.php'),
+('bx_posts_record_video', 1, 'BxPostsUploaderRecordVideo', 'modules/boonex/posts/classes/BxPostsUploaderRecordVideo.php'),
+('bx_posts_photos_html5', 1, 'BxPostsUploaderHTML5Attach', 'modules/boonex/posts/classes/BxPostsUploaderHTML5Attach.php'),
+('bx_posts_videos_html5', 1, 'BxPostsUploaderHTML5Attach', 'modules/boonex/posts/classes/BxPostsUploaderHTML5Attach.php'),
+('bx_posts_videos_record_video', 1, 'BxPostsUploaderRecordVideoAttach', 'modules/boonex/posts/classes/BxPostsUploaderRecordVideoAttach.php'),
+('bx_posts_sounds_html5', 1, 'BxPostsUploaderHTML5Attach', 'modules/boonex/posts/classes/BxPostsUploaderHTML5Attach.php'),
+('bx_posts_files_html5', 1, 'BxPostsUploaderHTML5Attach', 'modules/boonex/posts/classes/BxPostsUploaderHTML5Attach.php');
+
+-- ALERTS
+
+INSERT INTO `sys_alerts_handlers` (`name`, `class`, `file`, `service_call`) VALUES 
+('bx_posts', 'BxPostsAlertsResponse', 'modules/boonex/posts/classes/BxPostsAlertsResponse.php', '');
+SET @iHandler := LAST_INSERT_ID();
+
+INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('system', 'save_setting', @iHandler),
+('profile', 'delete', @iHandler),
+
+('bx_posts_videos_mp4', 'transcoded', @iHandler);
+
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_posts_publishing', '* * * * *', 'BxPostsCronPublishing', 'modules/boonex/posts/classes/BxPostsCronPublishing.php', '');

+ 716 - 0
modules/boonex/posts/updates/14.0.1_15.0.0/source/install/sql/install.sql

@@ -0,0 +1,716 @@
+-- TABLE: entries
+CREATE TABLE IF NOT EXISTS `bx_posts_posts` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `published` int(11) NOT NULL,
+  `thumb` int(11) NOT NULL,
+  `thumb_data` varchar(50) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `cat` int(11) NOT NULL,
+  `multicat` text NOT NULL,
+  `abstract` text NOT NULL,
+  `text` mediumtext NOT NULL,
+  `labels` text NOT NULL,
+  `location` text NOT NULL,
+  `views` int(11) NOT NULL default '0',
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `rrate` float NOT NULL default '0',
+  `rvotes` int(11) NOT NULL default '0',
+  `score` int(11) NOT NULL default '0',
+  `sc_up` int(11) NOT NULL default '0',
+  `sc_down` int(11) NOT NULL default '0',
+  `favorites` int(11) NOT NULL default '0',
+  `comments` int(11) NOT NULL default '0',
+  `reports` int(11) NOT NULL default '0',
+  `featured` int(11) NOT NULL default '0',
+  `cf` int(11) NOT NULL default '1',
+  `allow_view_to` varchar(16) NOT NULL DEFAULT '3',
+  `allow_comments` tinyint(4) NOT NULL DEFAULT '1',
+  `status` enum('active','awaiting','failed','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden','pending') NOT NULL DEFAULT 'active',
+  PRIMARY KEY (`id`),
+  FULLTEXT KEY `title_text` (`title`,`text`)
+);
+
+-- TABLE: storages & transcoders
+CREATE TABLE IF NOT EXISTS `bx_posts_covers` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_files` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_posts_photos` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) NOT NULL,
+  `added` int(11) NOT NULL,
+  `modified` int(11) NOT NULL,
+  `private` int(11) NOT NULL,
+  `dimensions` varchar(12) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `remote_id` (`remote_id`)
+);
+
+-- TABLES: LINKS
+CREATE TABLE IF NOT EXISTS `bx_posts_links` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `media_id` int(11) NOT NULL DEFAULT '0',
+  `url` varchar(255) NOT NULL,
+  `title` varchar(255) NOT NULL,
+  `text` text NOT NULL,
+  `added` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_links2content` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `content_id` int(11) NOT NULL DEFAULT '0',
+  `link_id` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `link` (`link_id`, `content_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_photos_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_posts_videos` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) NOT NULL,
+  `dimensions` varchar(12) 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_posts_videos_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_posts_sounds` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_posts_sounds_resized` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `remote_id` varchar(128) 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` bigint(20) 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_posts_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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  `cmt_cf` int(11) NOT NULL default '1',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_cmts_notes` (
+  `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(11) 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',
+  `cmt_pinned` int(11) NOT NULL default '0',
+  PRIMARY KEY (`cmt_id`),
+  KEY `cmt_object_id` (`cmt_object_id`,`cmt_parent_id`),
+  FULLTEXT KEY `search_fields` (`cmt_text`)
+);
+
+-- TABLE: votes
+CREATE TABLE IF NOT EXISTS `bx_posts_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_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`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_reactions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `reaction` varchar(32) NOT NULL default '',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `reaction` (`object_id`, `reaction`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_reactions_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',
+  `reaction` varchar(32) NOT NULL default '',
+  `value` tinyint(4) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: views
+CREATE TABLE `bx_posts_views_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `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',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE `bx_posts_meta_keywords` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE `bx_posts_meta_mentions` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+CREATE TABLE `bx_posts_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,
+  `street` varchar(255) NOT NULL,
+  `street_number` varchar(255) NOT NULL,
+  PRIMARY KEY (`object_id`),
+  KEY `country_state_city` (`country`,`state`(8),`city`(8))
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_posts_reports` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_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',
+  `checked_by` int(11) NOT NULL default '0',
+  `status` tinyint(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: favorites
+CREATE TABLE `bx_posts_favorites_track` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `author_id` int(11) NOT NULL default '0',
+  `list_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `id` (`object_id`,`author_id`)
+);
+
+CREATE TABLE `bx_posts_favorites_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `title` varchar(255) NOT NULL,
+  `author_id` int(11) NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  `allow_view_favorite_list_to` varchar(16) NOT NULL DEFAULT '3',
+   PRIMARY KEY (`id`)
+);
+
+-- TABLE: scores
+CREATE TABLE IF NOT EXISTS `bx_posts_scores` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_scores_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(8) NOT NULL default '',
+  `date` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `vote` (`object_id`, `author_nip`)
+);
+
+-- TABLE: polls
+CREATE TABLE IF NOT EXISTS `bx_posts_polls` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `author_id` int(11) NOT NULL default '0',
+  `content_id` int(11) NOT NULL default '0',
+  `text` text NOT NULL,
+  PRIMARY KEY (`id`),
+  KEY `content_id` (`content_id`),
+  FULLTEXT KEY `search_fields` (`text`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_polls_answers` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `poll_id` int(11) unsigned NOT NULL default '0',
+  `title` varchar(255) NOT NULL,
+  `rate` float NOT NULL default '0',
+  `votes` int(11) NOT NULL default '0',
+  `order` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  KEY `poll_id` (`poll_id`),
+  FULLTEXT KEY `title` (`title`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_polls_answers_votes` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+CREATE TABLE IF NOT EXISTS `bx_posts_polls_answers_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`)
+);
+
+-- STORAGES & TRANSCODERS
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+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_posts_covers', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_covers', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_photos', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_photos', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_photos_resized', 'allow-deny', '{image}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_videos', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_videos', 'allow-deny', '{video}', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_videos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_videos_resized', 'allow-deny', '{imagevideo}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_sounds', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_sounds', 'allow-deny', '{audio}', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_sounds_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_sounds_resized', 'allow-deny', '{audio}', '', 0, 0, 0, 0, 0, 0),
+
+('bx_posts_files', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_files', 'deny-allow', '', '{dangerous}', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`, `override_class_name`, `override_class_file`) VALUES 
+('bx_posts_preview', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_miniature', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_gallery', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_cover', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_covers";}', 'no', '1', '2592000', '0', '', ''),
+
+('bx_posts_preview_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_miniature_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_gallery_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_view_photos', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_photos";}', 'no', '1', '2592000', '0', '', ''),
+
+('bx_posts_videos_poster', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_posts_videos_poster_preview', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_posts_videos_mp4', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+('bx_posts_videos_mp4_hd', 'bx_posts_videos_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_videos";}', 'no', '0', '0', '0', 'BxDolTranscoderVideo', ''),
+
+('bx_posts_sounds_mp3', 'bx_posts_sounds_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_sounds";}', 'no', '0', '0', '0', 'BxDolTranscoderAudio', ''),
+
+('bx_posts_preview_files', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:14:"bx_posts_files";}', 'no', '1', '2592000', '0', '', ''),
+('bx_posts_gallery_files', 'bx_posts_photos_resized', 'Storage', 'a:1:{s:6:"object";s:14:"bx_posts_files";}', 'no', '1', '2592000', '0', '', '');
+
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_posts_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_posts_miniature', 'Resize', 'a:1:{s:1:"w";s:3:"300";}', '0'),
+('bx_posts_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0'),
+('bx_posts_cover', 'Resize', 'a:1:{s:1:"w";s:4:"1200";}', '0'),
+
+('bx_posts_preview_photos', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_posts_miniature_photos', 'Resize', 'a:4:{s:1:"w";s:3:"300";s:1:"h";s:3:"300";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0'),
+('bx_posts_gallery_photos', 'Resize', 'a:4:{s:1:"w";s:3:"600";s:1:"h";s:3:"600";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0'),
+('bx_posts_view_photos', 'Resize',  'a:2:{s:1:"w";s:4:"1200";s:1:"h";s:4:"1200";}', '0'),
+
+('bx_posts_videos_poster_preview', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:13:"square_resize";s:1:"1";}', 10),
+('bx_posts_videos_poster_preview', 'Poster', 'a:2:{s:1:"h";s:3:"480";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_posts_videos_poster', 'Poster', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"jpg";}', 0),
+('bx_posts_videos_mp4', 'Mp4', 'a:2:{s:1:"h";s:3:"318";s:10:"force_type";s:3:"mp4";}', 0),
+('bx_posts_videos_mp4_hd', 'Mp4', 'a:3:{s:1:"h";s:3:"720";s:13:"video_bitrate";s:4:"1536";s:10:"force_type";s:3:"mp4";}', 0),
+
+('bx_posts_sounds_mp3', 'Mp3', 'a:0:{}', 0),
+
+('bx_posts_preview_files', 'Resize', 'a:3:{s:1:"w";s:3:"300";s:1:"h";s:3:"200";s:11:"crop_resize";s:1:"1";}', '0'),
+('bx_posts_gallery_files', 'Resize', 'a:4:{s:1:"w";s:3:"600";s:1:"h";s:3:"600";s:13:"square_resize";s:1:"1";s:10:"force_type";s:3:"jpg";}', '0');
+
+
+-- FORMS: entry (post)
+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_posts', 'bx_posts', '_bx_posts_form_entry', '', 'a:1:{s:7:"enctype";s:19:"multipart/form-data";}', 'bx_posts_posts', 'id', '', '', 'a:2:{i:0;s:9:"do_submit";i:1;s:10:"do_publish";}', '', 0, 1, 'BxPostsFormEntry', 'modules/boonex/posts/classes/BxPostsFormEntry.php');
+
+INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
+('bx_posts', 'bx_posts_entry_add', 'bx_posts', 0, '_bx_posts_form_entry_display_add'),
+('bx_posts', 'bx_posts_entry_delete', 'bx_posts', 0, '_bx_posts_form_entry_display_delete'),
+('bx_posts', 'bx_posts_entry_edit', 'bx_posts', 0, '_bx_posts_form_entry_display_edit'),
+('bx_posts', 'bx_posts_entry_view', 'bx_posts', 1, '_bx_posts_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_posts', 'bx_posts', 'cf', '1', '#!sys_content_filter', 0, 'select', '_sys_form_entry_input_sys_cf', '_sys_form_entry_input_cf', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_posts', 'bx_posts', 'allow_view_to', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_allow_view_to', '_bx_posts_form_entry_input_allow_view_to', '', 1, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_posts_form_entry_input_sys_delete_confirm', '_bx_posts_form_entry_input_delete_confirm', '_bx_posts_form_entry_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_posts_form_entry_input_delete_confirm_error', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'do_publish', '_bx_posts_form_entry_input_do_publish', '', 0, 'submit', '_bx_posts_form_entry_input_sys_do_publish', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'do_submit', '_bx_posts_form_entry_input_do_submit', '', 0, 'submit', '_bx_posts_form_entry_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'do_cancel', '_sys_form_input_cancel', '', 0, 'button', '_sys_form_input_sys_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:41:"window.open(''{edit_cancel_url}'', ''_self'')";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
+('bx_posts', 'bx_posts', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '_sys_form_input_sys_controls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts', 'bx_posts', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'covers', 'a:1:{i:0;s:14:"bx_posts_html5";}', 'a:1:{s:14:"bx_posts_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_covers', '_bx_posts_form_entry_input_covers', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'pictures', 'a:1:{i:0;s:21:"bx_posts_photos_html5";}', 'a:1:{s:21:"bx_posts_photos_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_pictures', '_bx_posts_form_entry_input_pictures', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'videos', 'a:2:{i:0;s:21:"bx_posts_videos_html5";i:1;s:28:"bx_posts_videos_record_video";}', 'a:2:{s:21:"bx_posts_videos_html5";s:25:"_sys_uploader_html5_title";s:28:"bx_posts_videos_record_video";s:32:"_sys_uploader_record_video_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_videos', '_bx_posts_form_entry_input_videos', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'link', '', '', 0, 'custom', '_bx_posts_form_post_input_sys_link', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'sounds', 'a:1:{i:0;s:21:"bx_posts_sounds_html5";}', 'a:1:{s:21:"bx_posts_sounds_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_sounds', '_bx_posts_form_entry_input_sounds', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'files', 'a:1:{i:0;s:20:"bx_posts_files_html5";}', 'a:1:{s:20:"bx_posts_files_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_posts_form_entry_input_sys_files', '_bx_posts_form_entry_input_files', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'polls', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_polls', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'abstract', '', '', 0, 'textarea', '_bx_posts_form_entry_input_sys_abstract', '_bx_posts_form_entry_input_abstract', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'text', '', '', 0, 'textarea', '_bx_posts_form_entry_input_sys_text', '_bx_posts_form_entry_input_text', '', 1, 0, 2, '', '', '', 'Avail', '', '_bx_posts_form_entry_input_text_err', 'XssHtml', '', 1, 0),
+('bx_posts', 'bx_posts', 'title', '', '', 0, 'text', '_bx_posts_form_entry_input_sys_title', '_bx_posts_form_entry_input_title', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_posts_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'cat', '', '#!bx_posts_cats', 0, 'select', '_bx_posts_form_entry_input_sys_cat', '_bx_posts_form_entry_input_cat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_posts_form_entry_input_cat_err', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'multicat', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_multicat', '_bx_posts_form_entry_input_multicat', '', 1, 0, 0, '', '', '', 'avail', '', '_bx_posts_form_entry_input_multicat_err', 'Xss', '', 1, 0),
+('bx_posts', 'bx_posts', 'added', '', '', 0, 'datetime', '_bx_posts_form_entry_input_sys_date_added', '_bx_posts_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'changed', '', '', 0, 'datetime', '_bx_posts_form_entry_input_sys_date_changed', '_bx_posts_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'published', '', '', 0, 'datetime', '_bx_posts_form_entry_input_sys_date_published', '_bx_posts_form_entry_input_date_published', '_bx_posts_form_entry_input_date_published_info', 0, 0, 0, '', '', '', '', '', '', 'DateTimeTs', '', 1, 0),
+('bx_posts', 'bx_posts', 'attachments', '', '', 0, 'custom', '_bx_posts_form_entry_input_sys_attachments', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'anonymous', '', '', 0, 'switcher', '_sys_form_input_sys_anonymous', '_sys_form_input_anonymous', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
+('bx_posts', 'bx_posts', 'allow_comments', '1', '', 1, 'switcher', '_bx_posts_form_entry_input_sys_allow_comments', '_bx_posts_form_entry_input_allow_comments', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0);
+
+
+
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_posts_entry_add', 'delete_confirm', 2147483647, 0, 1),
+('bx_posts_entry_add', 'title', 2147483647, 1, 2),
+('bx_posts_entry_add', 'cat', 2147483647, 1, 3),
+('bx_posts_entry_add', 'abstract', 2147483647, 1, 4),
+('bx_posts_entry_add', 'text', 2147483647, 1, 5),
+('bx_posts_entry_add', 'attachments', 2147483647, 1, 6),
+('bx_posts_entry_add', 'link', 2147483647, 1, 7),
+('bx_posts_entry_add', 'pictures', 2147483647, 1, 8),
+('bx_posts_entry_add', 'videos', 2147483647, 1, 9),
+('bx_posts_entry_add', 'sounds', 2147483647, 1, 10),
+('bx_posts_entry_add', 'files', 2147483647, 1, 11),
+('bx_posts_entry_add', 'polls', 2147483647, 1, 12),
+('bx_posts_entry_add', 'covers', 2147483647, 1, 13),
+('bx_posts_entry_add', 'allow_view_to', 2147483647, 1, 14),
+('bx_posts_entry_add', 'cf', 2147483647, 1, 15),
+('bx_posts_entry_add', 'location', 2147483647, 1, 16),
+('bx_posts_entry_add', 'published', 192, 0, 17),
+('bx_posts_entry_add', 'allow_comments', 192, 1, 18),
+('bx_posts_entry_add', 'do_publish', 2147483647, 1, 19),
+
+('bx_posts_entry_delete', 'delete_confirm', 2147483647, 1, 1),
+('bx_posts_entry_delete', 'do_submit', 2147483647, 1, 2),
+
+('bx_posts_entry_edit', 'do_publish', 2147483647, 0, 1),
+('bx_posts_entry_edit', 'delete_confirm', 2147483647, 0, 2),
+('bx_posts_entry_edit', 'title', 2147483647, 1, 3),
+('bx_posts_entry_edit', 'cat', 2147483647, 1, 4),
+('bx_posts_entry_edit', 'abstract', 2147483647, 1, 5),
+('bx_posts_entry_edit', 'text', 2147483647, 1, 6),
+('bx_posts_entry_edit', 'attachments', 2147483647, 1, 7),
+('bx_posts_entry_edit', 'link', 2147483647, 1, 8),
+('bx_posts_entry_edit', 'pictures', 2147483647, 1, 9),
+('bx_posts_entry_edit', 'videos', 2147483647, 1, 10),
+('bx_posts_entry_edit', 'sounds', 2147483647, 1, 11),
+('bx_posts_entry_edit', 'files', 2147483647, 1, 12),
+('bx_posts_entry_edit', 'polls', 2147483647, 1, 13),
+('bx_posts_entry_edit', 'covers', 2147483647, 1, 14),
+('bx_posts_entry_edit', 'allow_view_to', 2147483647, 1, 15),
+('bx_posts_entry_edit', 'cf', 2147483647, 1, 16),
+('bx_posts_entry_edit', 'location', 2147483647, 1, 17),
+('bx_posts_entry_edit', 'allow_comments', 192, 1, 18),
+('bx_posts_entry_edit', 'published', 192, 0, 19),
+('bx_posts_entry_edit', 'controls', 2147483647, 1, 20),
+('bx_posts_entry_edit', 'do_submit', 2147483647, 1, 21),
+('bx_posts_entry_edit', 'do_cancel', 2147483647, 1, 22),
+
+('bx_posts_entry_view', 'cat', 2147483647, 1, 1),
+('bx_posts_entry_view', 'added', 2147483647, 1, 2),
+('bx_posts_entry_view', 'changed', 2147483647, 1, 3),
+('bx_posts_entry_view', 'published', 192, 1, 4);
+
+-- FORMS: poll
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_poll', 'bx_posts', '_bx_posts_form_poll', '', '', 'do_submit', 'bx_posts_polls', 'id', '', '', 'a:1:{s:14:"checker_helper";s:28:"BxPostsFormPollCheckerHelper";}', 0, 1, 'BxPostsFormPoll', 'modules/boonex/posts/classes/BxPostsFormPoll.php');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_posts_poll_add', 'bx_posts', 'bx_posts_poll', '_bx_posts_form_poll_display_add', 0);
+
+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_posts_poll', 'bx_posts', 'text', '', '', 0, 'text', '_bx_posts_form_poll_input_sys_text', '_bx_posts_form_poll_input_text', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_posts_form_poll_input_text_err', 'Xss', '', 1, 0),
+('bx_posts_poll', 'bx_posts', 'answers', '', '', 0, 'custom', '_bx_posts_form_poll_input_sys_answers', '_bx_posts_form_poll_input_answers', '', 1, 0, 0, '', '', '', 'AvailAnswers', '', '_bx_posts_form_poll_input_answers_err', '', '', 1, 0),
+('bx_posts_poll', 'bx_posts', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_poll', 'bx_posts', 'do_submit', '_bx_posts_form_poll_input_do_submit', '', 0, 'submit', '_bx_posts_form_poll_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_poll', 'bx_posts', 'do_cancel', '_bx_posts_form_poll_input_do_cancel', '', 0, 'button', '_bx_posts_form_poll_input_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_posts_poll_add', 'text', 2147483647, 1, 1),
+('bx_posts_poll_add', 'answers', 2147483647, 1, 2),
+('bx_posts_poll_add', 'controls', 2147483647, 1, 3),
+('bx_posts_poll_add', 'do_submit', 2147483647, 1, 4),
+('bx_posts_poll_add', 'do_cancel', 2147483647, 1, 5);
+
+-- Forms -> Attach link
+INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_attach_link', 'bx_posts', '_bx_posts_form_attach_link', '', '', 'do_submit', 'bx_posts_links', 'id', '', '', '', 0, 1, '', '');
+
+INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
+('bx_posts_attach_link_add', 'bx_posts', 'bx_posts_attach_link', '_bx_posts_form_attach_link_display_add', 0);
+
+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_posts_attach_link', 'bx_posts', 'content_id', '0', '', 0, 'hidden', '_bx_posts_form_attach_link_input_sys_content_id', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'url', '', '', 0, 'text', '_bx_posts_form_attach_link_input_sys_url', '_bx_posts_form_attach_link_input_url', '', 0, 0, 0, '', '', '', 'Preg', 'a:1:{s:4:"preg";s:0:"";}', '_bx_posts_form_attach_link_input_url_err', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'controls', '', 'do_submit,do_cancel', 0, 'input_set', '', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'do_submit', '_bx_posts_form_attach_link_input_do_submit', '', 0, 'submit', '_bx_posts_form_attach_link_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
+('bx_posts_attach_link', 'bx_posts', 'do_cancel', '_bx_posts_form_attach_link_input_do_cancel', '', 0, 'button', '_bx_posts_form_attach_link_input_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0);
+
+INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
+('bx_posts_attach_link_add', 'content_id', 2147483647, 1, 1),
+('bx_posts_attach_link_add', 'url', 2147483647, 1, 2),
+('bx_posts_attach_link_add', 'controls', 2147483647, 1, 3),
+('bx_posts_attach_link_add', 'do_submit', 2147483647, 1, 4),
+('bx_posts_attach_link_add', 'do_cancel', 2147483647, 1, 5);
+
+-- PRE-VALUES
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_posts_cats', '_bx_posts_pre_lists_cats', 'bx_posts', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_posts_cats', '', 0, '_sys_please_select', ''),
+('bx_posts_cats', '1', 1, '_bx_posts_cat_Animals_Pets', ''),
+('bx_posts_cats', '2', 2, '_bx_posts_cat_Architecture', ''),
+('bx_posts_cats', '3', 3, '_bx_posts_cat_Art', ''),
+('bx_posts_cats', '4', 4, '_bx_posts_cat_Cars_Motorcycles', ''),
+('bx_posts_cats', '5', 5, '_bx_posts_cat_Celebrities', ''),
+('bx_posts_cats', '6', 6, '_bx_posts_cat_Design', ''),
+('bx_posts_cats', '7', 7, '_bx_posts_cat_DIY_Crafts', ''),
+('bx_posts_cats', '8', 8, '_bx_posts_cat_Education', ''),
+('bx_posts_cats', '9', 9, '_bx_posts_cat_Film_Music_Books', ''),
+('bx_posts_cats', '10', 10, '_bx_posts_cat_Food_Drink', ''),
+('bx_posts_cats', '11', 11, '_bx_posts_cat_Gardening', ''),
+('bx_posts_cats', '12', 12, '_bx_posts_cat_Geek', ''),
+('bx_posts_cats', '13', 13, '_bx_posts_cat_Hair_Beauty', ''),
+('bx_posts_cats', '14', 14, '_bx_posts_cat_Health_Fitness', ''),
+('bx_posts_cats', '15', 15, '_bx_posts_cat_History', ''),
+('bx_posts_cats', '16', 16, '_bx_posts_cat_Holidays_Events', ''),
+('bx_posts_cats', '17', 17, '_bx_posts_cat_Home_Decor', ''),
+('bx_posts_cats', '18', 18, '_bx_posts_cat_Humor', ''),
+('bx_posts_cats', '19', 19, '_bx_posts_cat_Illustrations_Posters', ''),
+('bx_posts_cats', '20', 20, '_bx_posts_cat_Kids_Parenting', ''),
+('bx_posts_cats', '21', 21, '_bx_posts_cat_Mens_Fashion', ''),
+('bx_posts_cats', '22', 22, '_bx_posts_cat_Outdoors', ''),
+('bx_posts_cats', '23', 23, '_bx_posts_cat_Photography', ''),
+('bx_posts_cats', '24', 24, '_bx_posts_cat_Products', ''),
+('bx_posts_cats', '25', 25, '_bx_posts_cat_Quotes', ''),
+('bx_posts_cats', '26', 26, '_bx_posts_cat_Science_Nature', ''),
+('bx_posts_cats', '27', 27, '_bx_posts_cat_Sports', ''),
+('bx_posts_cats', '28', 28, '_bx_posts_cat_Tattoos', ''),
+('bx_posts_cats', '29', 29, '_bx_posts_cat_Technology', ''),
+('bx_posts_cats', '30', 30, '_bx_posts_cat_Travel', ''),
+('bx_posts_cats', '31', 31, '_bx_posts_cat_Weddings', ''),
+('bx_posts_cats', '32', 32, '_bx_posts_cat_Womens_Fashion', '');
+
+-- COMMENTS
+INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('bx_posts', 'bx_posts', 'bx_posts_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_posts_posts', 'id', 'author', 'title', 'comments', '', ''),
+('bx_posts_notes', 'bx_posts', 'bx_posts_cmts_notes', 1, 5000, 1000, 0, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-post&id={object_id}', '', 'bx_posts_posts', 'id', 'author', 'title', '', 'BxTemplCmtsNotes', '');
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `Module`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_votes', 'bx_posts_votes_track', '604800', '1', '1', '0', '1', 'bx_posts_posts', 'id', 'author', 'rate', 'votes', '', ''),
+('bx_posts_reactions', 'bx_posts', 'bx_posts_reactions', 'bx_posts_reactions_track', '604800', '1', '1', '1', '1', 'bx_posts_posts', 'id', 'author', 'rrate', 'rvotes', 'BxTemplVoteReactions', ''),
+('bx_posts_poll_answers', 'bx_posts', 'bx_posts_polls_answers_votes', 'bx_posts_polls_answers_votes_track', '604800', '1', '1', '0', '1', 'bx_posts_polls_answers', 'id', 'author_id', 'rate', 'votes', 'BxPostsVotePollAnswers', 'modules/boonex/posts/classes/BxPostsVotePollAnswers.php');
+
+-- SCORES
+INSERT INTO `sys_objects_score` (`name`, `module`, `table_main`, `table_track`, `post_timeout`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_score`, `trigger_field_cup`, `trigger_field_cdown`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_scores', 'bx_posts_scores_track', '604800', '0', 'bx_posts_posts', 'id', 'author', 'score', 'sc_up', 'sc_down', '', '');
+
+-- REPORTS
+INSERT INTO `sys_objects_report` (`name`, `module`, `table_main`, `table_track`, `is_on`, `base_url`, `object_comment`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_reports', 'bx_posts_reports_track', '1', 'page.php?i=view-post&id={object_id}', 'bx_posts_notes', 'bx_posts_posts', 'id', 'author', 'reports', '', '');
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `module`, `table_track`, `period`, `is_on`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', 'bx_posts_views_track', '86400', '1', 'bx_posts_posts', 'id', 'author', 'views', '', '');
+
+-- FAVORITES
+INSERT INTO `sys_objects_favorite` (`name`, `table_track`, `table_lists`, `is_on`, `is_undo`, `is_public`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_count`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts_favorites_track', 'bx_posts_favorites_lists', '1', '1', '1', 'page.php?i=view-post&id={object_id}', 'bx_posts_posts', 'id', 'author', 'favorites', '', '');
+
+-- FEATURED
+INSERT INTO `sys_objects_feature` (`name`, `module`, `is_on`, `is_undo`, `base_url`, `trigger_table`, `trigger_field_id`, `trigger_field_author`, `trigger_field_flag`, `class_name`, `class_file`) VALUES 
+('bx_posts', 'bx_posts', '1', '1', 'page.php?i=view-post&id={object_id}', 'bx_posts_posts', 'id', 'author', 'featured', '', '');
+
+-- CONTENT INFO
+INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_action_add`, `alert_action_update`, `alert_action_delete`, `class_name`, `class_file`) VALUES
+('bx_posts', '_bx_posts', 'bx_posts', 'added', 'edited', 'deleted', '', ''),
+('bx_posts_cmts', '_bx_posts_cmts', 'bx_posts', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
+
+INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
+('bx_posts', 'bx_posts_administration', 'id', '', ''),
+('bx_posts', 'bx_posts_common', 'id', '', '');
+
+-- SEARCH EXTENDED
+INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
+('bx_posts', 'bx_posts', 'bx_posts', '_bx_posts_search_extended', 1, '', ''),
+('bx_posts_cmts', 'bx_posts_cmts', 'bx_posts', '_bx_posts_search_extended_cmts', 1, 'BxTemplSearchExtendedCmts', '');
+
+-- STUDIO: page & widget
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_posts', '_bx_posts', '_bx_posts', 'bx_posts@modules/boonex/posts/|std-icon.svg');
+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`, `type`, `url`, `click`, `icon`, `caption`, `cnt_notices`, `cnt_actions`) VALUES
+(@iPageId, 'bx_posts', 'content', '{url_studio}module.php?name=bx_posts', '', 'bx_posts@modules/boonex/posts/|std-icon.svg', '_bx_posts', '', '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));
+

+ 51 - 0
modules/boonex/profiler/updates/13.0.4_15.0.0/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Profiler',
+    'version_from' => '13.0.4',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/profiler/updates/update_13.0.4_15.0.0/',
+    'home_uri' => 'profiler_update_1304_1500',
+
+    'module_dir' => 'boonex/profiler/',
+    'module_uri' => 'profiler',
+
+    'db_prefix' => 'bx_profiler_',
+    'class_prefix' => 'BxProfiler',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Profiler',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/profiler/updates/13.0.4_15.0.0/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxProfilerUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 691 - 0
modules/boonex/profiler/updates/13.0.4_15.0.0/source/classes/BxProfiler.php

@@ -0,0 +1,691 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Profiler Profiler
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+define ('BX_PROFILER', true);
+define ('BX_PROFILER_DISPLAY', 1);
+
+require_once(BX_DIRECTORY_PATH_MODULES . 'boonex/profiler/install/config.php');
+$GLOBALS['bx_profiler_module'] = array (
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_profiler',
+    'title' => $aConfig['title'],
+    'vendor' => $aConfig['vendor'],
+    'path' => $aConfig['home_dir'],
+    'uri' => $aConfig['home_uri'],
+    'class_prefix' => $aConfig['class_prefix'],
+    'db_prefix' => $aConfig['db_prefix'],
+);
+
+bx_import('Template', $GLOBALS['bx_profiler_module']);
+bx_import('Config', $GLOBALS['bx_profiler_module']);
+
+class BxProfiler extends BxDol
+{
+    protected $oConfig, $oTemplate, $oTemplateAdmin;
+
+    protected $aConf = [];
+
+    protected $_iTimeStart = 0;
+
+    protected $_aQueries = [];
+    protected $_sQueryIndex = 0;
+
+    protected $_aModules = [];
+    protected $_aModulesNames = [];
+    protected $_aModulesLevel = 0;
+
+    protected $_aAlerts = [];
+    protected $_iAlertsLevel = 0;
+
+    protected $_aInjections = [];
+    protected $_sInjectionIndex = 0;
+
+    protected $_sLogDateFormat = "Y-m-d H:i:s";
+    protected $_sLogMaxArgLength = 64;
+    protected $_sLogFilename = 64;
+
+    protected $_aTemplates = [];
+    protected $_aTemplateIndexes = [];
+
+    protected $_aPages = [];
+    protected $_sPageIndex = '';
+    protected $_sPageBlockIndex = 0;
+    protected $_aPagesBlocks = [];
+    
+    protected $_aMenus = [];   
+
+    function __construct($iTimeStart)
+    {
+        parent::__construct();
+
+        $this->oConfig = new BxProfilerConfig ($GLOBALS['bx_profiler_module']);
+        $this->oTemplate = new BxProfilerTemplate ($this->oConfig);
+        $this->oTemplateAdmin = BxDolStudioTemplate::getInstance();
+
+        if (getParam ('bx_profiler_long_sql_queries_log'))
+            $this->aConf['long_query'] = getParam ('bx_profiler_long_sql_queries_time');
+        if (getParam ('bx_profiler_long_module_query_log'))
+            $this->aConf['long_module'] = getParam ('bx_profiler_long_module_query_time');
+        if (getParam ('bx_profiler_long_page_log'))
+            $this->aConf['long_page'] = getParam ('bx_profiler_long_page_time');
+
+        $this->_iTimeStart = $iTimeStart;
+    }
+
+    // output profiler debug panel
+    function output ()
+    {
+        $iPageTime = $this->_getCurrentDelay ();
+        if (isset($this->aConf['long_page']) && $iPageTime > $this->aConf['long_page'])
+            $this->logPageOpen ($iPageTime);
+
+        switch (getParam('bx_profiler_show_debug_panel')) {
+        case 'all':
+            break;
+        case 'admins':
+            if (!isset($GLOBALS['logged']) || !$GLOBALS['logged']['admin'])
+                return;
+            break;
+        case 'none':
+        default:
+            return;
+        }
+
+        $aCss = array (
+			'profiler.css',
+            BX_DIRECTORY_PATH_PLUGINS_PUBLIC . 'jush/|jush.css',
+        );
+        $aJs = array (
+            'jquery.tablesorter.min.js',
+            'profiler.js',
+            'jush/jush.js',
+        );
+
+        $sJsCss = '';
+        foreach ($aCss as $sCssPath)
+            $sJsCss .= $this->oTemplate->addCss($sCssPath, 1);
+        foreach ($aJs as $sJsPath)
+            $sJsCss .= $this->oTemplate->addJs($sJsPath, 1);
+
+        $sPlanks  = $this->_plankMain ();
+        $sPlanks .= $this->_plankMenus ();
+        $sPlanks .= $this->_plankTemplates ();
+        $sPlanks .= $this->_plankInjections ();
+        $sPlanks .= $this->_plankPagesBlocks ();
+        $sPlanks .= $this->_plankSql ();
+        $sPlanks .= $this->_plankModules ();
+        $sPlanks .= $this->_plankAlerts ();
+
+        echo ob_get_clean();
+
+        $sContentType = $this->oTemplate->getHeaderContentType();
+        if ('text/html' == $sContentType) {            
+            echo $sJsCss . $sPlanks;
+        } 
+        else if ('application/json' == $sContentType) {
+            echo $sPlanks;
+        }
+    }
+
+    function _logBegin ($s)
+    {
+        $sDate = date ($this->_sLogDateFormat);
+        return "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" . $sDate . " " . $s . "\n" .
+        (getLoggedId() ? "User ID: " . getLoggedId()  . "\n" : '') .
+        "User role: " . ($GLOBALS['logged']['admin'] ? 'admin' : ($GLOBALS['logged']['member'] ? 'member' : 'guest')) . "\n";
+    }
+
+    function _logEnd ()
+    {
+        return "\n";
+    }
+
+    function _appendToLog ($s)
+    {
+		bx_log('bx_profiler', $s, BX_LOG_INFO);
+    }
+
+    function logSqlQuery ($iTime, $aSqlQuery, &$oStmt)
+    {
+        $s  = $this->_logBegin ('LONG SQL QUERY: ' . $aSqlQuery['time']);
+        $s .= "Rows: " . $aSqlQuery['rows'] . "\n";
+        $s .= "Affected: " . $aSqlQuery['affected'] . "\n";
+        $s .= "Query: " . $aSqlQuery['sql'] . "\n";
+        if (getParam('bx_profiler_long_sql_queries_debug'))
+            $s .= "Backtrace: \n" . $this->_debugBackTrace (3);
+        $s .= $this->_logEnd();
+        $this->_appendToLog ($s);
+    }
+
+    function logModuleQuery ($iTime, $aModuleQuery)
+    {
+        $s  = $this->_logBegin ('LONG MODULE QUERY: ' . $aModuleQuery['time']);
+        $s .= "Module name: " . $aModuleQuery['name'] . "\n";
+        $s .= "Query type: " . $aModuleQuery['type'] . "\n";
+        $s .= "Class/file: " . $aModuleQuery['class/file'] . "\n";
+        $s .= "Method: " . $aModuleQuery['method'] . "\n";
+        if (getParam('bx_profiler_long_module_query_debug'))
+            $s .= "Backtrace: \n" . $this->_debugBackTrace (3);
+        $s .= $this->_logEnd();
+        $this->_appendToLog ($s);
+    }
+
+    function logPageOpen ($iTime)
+    {
+        $s  = $this->_logBegin ('LONG PAGE OPEN: ' . $this->_formatTime($iTime));
+        $s .= "Request method: " . $_SERVER['REQUEST_METHOD'] . "\n";
+        $s .= "Query string: " . $_SERVER['QUERY_STRING'] . "\n";
+        $s .= "Request URI: " . $_SERVER['REQUEST_URI'] . "\n";
+        $s .= "Script name: " . $_SERVER['SCRIPT_NAME'] . "\n";
+        $s .= "PHP self: " . $_SERVER['PHP_SELF'] . "\n";
+        if (getParam('bx_profiler_long_page_debug'))
+            $s .= "All server vars: \n" . print_r ($_SERVER, true);
+        $s .= $this->_logEnd();
+        $this->_appendToLog ($s);
+    }
+
+    function beginModule($sType, $sHash, &$aModule, $sClassFile, $sMethod = '' )
+    {
+        ++$this->_aModulesLevel;
+        $this->_aModulesNames[$aModule['title']] = isset($this->_aModulesNames[$aModule['title']]) ? $this->_aModulesNames[$aModule['title']] + 1 : 1;
+        $this->_aModules[$sHash] = array (
+            'name' => str_repeat("--", $this->_aModulesLevel-1) . $aModule['title'],
+            'type' => $sType,
+            'class/file' => $sClassFile,
+            'method' => $sMethod,
+            'begin' => microtime (),
+            'time' => -1,
+        );
+    }
+
+    function endModule($sType, $sHash)
+    {
+        --$this->_aModulesLevel;
+        $iTime = $this->_calcTime ($this->_aModules[$sHash]['begin']);
+        unset ($this->_aModules[$sHash]['begin']);
+        $this->_aModules[$sHash]['time'] = $this->_formatTime($iTime);
+        $this->_aModules[$sHash]['raw_time'] = $iTime;
+        if (isset($this->aConf['long_module']) && $iTime > $this->aConf['long_module'])
+            $this->logModuleQuery ($iTime, $this->_aModules[$sHash]);
+    }
+
+    function beginAlert($sUnit, $sAction, $sHandler)
+    {
+        $sHash = md5($sUnit . $sAction . $sHandler . $this->_iAlertsLevel);
+        ++$this->_iAlertsLevel;
+        $this->_aAlerts[$sHash] = array (
+            'name' => str_repeat("--", $this->_iAlertsLevel-1) . $sHandler,
+            'unit' => $sUnit,
+            'action' => $sAction,
+            'handler' => $sHandler,
+            'begin' => microtime (),
+            'time' => -1,
+        );
+    }
+
+    function endAlert($sUnit, $sAction, $sHandler)
+    {
+        --$this->_iAlertsLevel;
+        $sHash = md5($sUnit . $sAction . $sHandler . $this->_iAlertsLevel);
+        $iTime = $this->_calcTime ($this->_aAlerts[$sHash]['begin']);
+        unset ($this->_aAlerts[$sHash]['begin']);
+        $this->_aAlerts[$sHash]['time'] = $this->_formatTime($iTime);
+        $this->_aAlerts[$sHash]['raw_time'] = $iTime;
+    }
+
+    function beginInjection ($sId)
+    {
+        $this->_sInjectionIndex = $sId;
+        $this->_aInjections[$sId]['begin'] = microtime ();
+    }
+
+    function endInjection ($sId, $aInjection)
+    {
+        if (!isset($this->_aInjections[$sId]))
+            return;
+        $iTime = $this->_calcTime ($this->_aInjections[$sId]['begin']);
+        unset ($this->_aInjections[$sId]['begin']);
+        $this->_aInjections[$sId]['name'] = isset($aInjection['name']) ? $aInjection['name'] : 'no-name';
+        $this->_aInjections[$sId]['key'] = $aInjection['key'];
+        $this->_aInjections[$sId]['replace'] = $aInjection['replace'] ? 'yes' : 'no';
+        $this->_aInjections[$sId]['time'] = $this->_formatTime($iTime);
+        $this->_aInjections[$sId]['raw_time'] = $iTime;
+    }
+
+    function beginPageBlock ($sName, $iBlockId)
+    {
+        $this->_sPageBlockIndex = $iBlockId;
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['name'] = $sName;
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['begin'] = microtime ();
+    }
+
+    function endPageBlock ($iBlockId, $isEmpty, $isCached)
+    {
+        if (!$this->_sPageBlockIndex)
+            return;
+        $iTime = $this->_calcTime ($this->_aPagesBlocks[$this->_sPageBlockIndex]['begin']);
+        unset ($this->_aPagesBlocks[$this->_sPageBlockIndex]['begin']);
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['cached'] = $isCached ? 'yes' : 'no';
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['empty'] = $isEmpty ? 'yes' : 'no';
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['time'] = $this->_formatTime($iTime);
+        $this->_aPagesBlocks[$this->_sPageBlockIndex]['raw_time'] = $iTime;
+    }
+
+    function beginPage ($sName)
+    {
+        $this->_sPageIndex = md5 ($sName.time().rand());
+        $this->_aPages[$this->_sPageIndex]['name'] = $sName;
+        $this->_aPages[$this->_sPageIndex]['begin'] = microtime ();
+    }
+
+    function endPage (&$sContent)
+    {
+        if (!$this->_sPageIndex || !isset($this->_aPages[$this->_sPageIndex]['begin']))
+            return;
+        $iTime = $this->_calcTime ($this->_aPages[$this->_sPageIndex]['begin']);
+        unset ($this->_aPages[$this->_sPageIndex]['begin']);
+        $this->_aPages[$this->_sPageIndex]['time'] = $this->_formatTime($iTime);
+        $this->_aPages[$this->_sPageIndex]['raw_time'] = $iTime;
+    }
+
+    function beginTemplate ($sName, $sRand)
+    {
+        $this->_aTemplateIndexes[$sName.$sRand] = 1;
+        $this->_aTemplates[$sName.$sRand]['name'] = $sName;
+        $this->_aTemplates[$sName.$sRand]['begin'] = microtime ();
+    }
+
+    function endTemplate ($sName, $sRand, &$sContent, $isCached)
+    {
+        if (!isset($this->_aTemplateIndexes[$sName.$sRand]))
+            return;
+        $iTime = $this->_calcTime ($this->_aTemplates[$sName.$sRand]['begin']);
+        unset ($this->_aTemplates[$sName.$sRand]['begin']);
+        $this->_aTemplates[$sName.$sRand]['cached'] = $isCached ? 'yes' : 'no';
+        $this->_aTemplates[$sName.$sRand]['time'] = $this->_formatTime($iTime);
+        $this->_aTemplates[$sName.$sRand]['raw_time'] = $iTime;
+    }
+
+    function beginQuery ($sSql)
+    {
+        $this->_sQueryIndex = md5 ($sSql.time().rand());
+        $this->_aQueries[$this->_sQueryIndex]['sql'] = $sSql;
+        $this->_aQueries[$this->_sQueryIndex]['begin'] = microtime ();
+    }
+
+    function endQuery (&$oStmt)
+    {
+        if (!$this->_sQueryIndex)
+            return;
+        $iTime = $this->_calcTime ($this->_aQueries[$this->_sQueryIndex]['begin']);
+        unset ($this->_aQueries[$this->_sQueryIndex]['begin']);
+        $this->_aQueries[$this->_sQueryIndex]['time'] = $this->_formatTime($iTime);
+        $this->_aQueries[$this->_sQueryIndex]['raw_time'] = $iTime;
+        $this->_aQueries[$this->_sQueryIndex]['rows'] = $oStmt ? BxDolDb::getInstance()->getNumRows($oStmt) : '';
+        $this->_aQueries[$this->_sQueryIndex]['affected'] = $oStmt ? BxDolDb::getInstance()->getAffectedRows($oStmt) : '';
+        if (isset($this->aConf['long_query']) && $iTime > $this->aConf['long_query'])
+            $this->logSqlQuery ($iTime, $this->_aQueries[$this->_sQueryIndex], $oStmt);
+    }
+
+    function isMenu($sName)
+    {
+        return isset($this->_aMenus[$sName]);
+    }
+
+    function beginMenu ($sName)
+    {
+        $this->_aMenus[$sName]['name'] = $sName;
+        $this->_aMenus[$sName]['begin'] = microtime ();
+    }
+
+    function endMenu ($sName, $sCacheType = '', $bCacheUsed = false)
+    {
+        if (!isset($this->_aMenus[$sName]))
+            return;
+        $iTime = $this->_calcTime ($this->_aMenus[$sName]['begin']);
+        unset ($this->_aMenus[$sName]['begin']);
+        $this->_aMenus[$sName]['time'] = $this->_formatTime($iTime);
+        $this->_aMenus[$sName]['raw_time'] = $iTime;        
+        $this->_aMenus[$sName]['cache type'] = $sCacheType;
+        $this->_aMenus[$sName]['cache used'] = $bCacheUsed ? 'yes' : 'no';
+    }
+
+    function _getCurrentDelay ()
+    {
+        $i1 = explode(' ', microtime ());
+        $i2 = explode(' ', $this->_iTimeStart);
+        return ($i1[0]+$i1[1]) - ($i2[0]+$i2[1]);
+    }
+
+    function _plankMain ()
+    {
+        $sTime = $this->_formatTime($this->_getCurrentDelay (), 3);
+        if (function_exists('memory_get_usage'))
+            $sMemory = $this->_formatBytes(memory_get_usage(true)) . ' of ' . ini_get('memory_limit') . ' allowed';
+        $aLoad = sys_getloadavg();
+        $sLoad = implode(',', array_map(function ($f) {
+            return round ($f, 2);
+        }, $aLoad));
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Time:', $sTime) .
+            (function_exists('memory_get_usage') ? $this->oTemplate->nameValue('Memory:', $sMemory) : '') .
+            $this->oTemplate->nameValue('PHP:', phpversion()) .
+            $this->oTemplate->nameValue('SAPI:', php_sapi_name()) .
+            $this->oTemplate->nameValue('OS:', php_uname('s')) .
+            $this->oTemplate->nameValue('Avg load:', $sLoad)
+        );
+    }
+
+    function _plankTemplates ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aPages) && empty($GLOBALS['bx_profiler']->_aTemplates))
+            return;
+
+        $sPages = '';
+        if (!empty($GLOBALS['bx_profiler']->_aPages)) {
+            $iTimePages = 0;
+            foreach ($GLOBALS['bx_profiler']->_aPages as $k => $r) {
+                if (!isset($r['raw_time']))
+                    continue;
+                $iTimePages += $r['raw_time'];
+                unset ($GLOBALS['bx_profiler']->_aPages[$k]['raw_time']);
+            }
+            $sPages = count($GLOBALS['bx_profiler']->_aPages) . ' (' . $this->_formatTime($iTimePages, 3) . ')';
+        }
+
+        $sTemplatesCached = '';
+        $sTemplatesNotCached = '';
+        if ($GLOBALS['bx_profiler']->_aTemplates) {
+            $iTimeTemplatesCached = 0;
+            $iTimeTemplatesNotCached = 0;
+            $sTemplatesCached = 0;
+            $sTemplatesNotCached = 0;
+            foreach ($GLOBALS['bx_profiler']->_aTemplates as $k => $r) {
+                if (!isset($r['raw_time']))
+                    continue;
+                if ('yes' == $r['cached']) {
+                    $iTimeTemplatesCached += $r['raw_time'];
+                    ++$sTemplatesCached;
+                } else {
+                    $iTimeTemplatesNotCached += $r['raw_time'];
+                    ++$sTemplatesNotCached;
+                }
+                unset ($GLOBALS['bx_profiler']->_aTemplates[$k]['raw_time']);
+            }
+            if ($sTemplatesCached)
+                $sTemplatesCached .= ' (' . $this->_formatTime($iTimeTemplatesCached, 3) . ')';
+            if ($sTemplatesNotCached)
+                $sTemplatesNotCached .= ' (' . $this->_formatTime($iTimeTemplatesNotCached, 3) . ')';
+        }
+
+        return $this->oTemplate->plank(
+            ($sPages ? $this->oTemplate->nameValue('Pages:', $sPages) : '') .
+            ($sTemplatesCached ? $this->oTemplate->nameValue('Templates Cached:', $sTemplatesCached) : '') .
+            ($sTemplatesNotCached ? $this->oTemplate->nameValue('Templates Not Cached:', $sTemplatesNotCached) : ''),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aTemplates)
+        );
+    }
+
+    function _plankInjections ()
+    {
+        if (!$GLOBALS['bx_profiler']->_aInjections)
+            return;
+
+        $iTimeInjections = 0;
+        foreach ($GLOBALS['bx_profiler']->_aInjections as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeInjections += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aInjections[$k]['raw_time']);
+        }
+
+        $sInjections = count($GLOBALS['bx_profiler']->_aInjections) . ' injection (' . $this->_formatTime($iTimeInjections, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Injections:', $sInjections),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aInjections)
+        );
+    }
+
+    function _plankPagesBlocks ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aPagesBlocks))
+            return;
+
+        $iTimeBlocks = 0;
+        $iTimeBlocksCached = 0;
+        $iTimeBlocksNotCached = 0;
+        $iTimeBlocksEmpty = 0;
+        $iTimeBlocksNotEmpty = 0;
+
+        $iCountBlocksCached = 0;
+        $iCountBlocksNotCached = 0;
+        $iCountBlocksEmpty = 0;
+        $iCountBlocksNotEmpty = 0;
+
+        foreach ($GLOBALS['bx_profiler']->_aPagesBlocks as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeBlocks += $r['raw_time'];
+            if ($r['cached'] == 'yes') {
+                $iTimeBlocksCached += $r['raw_time'];
+                ++$iCountBlocksCached;
+            } else {
+                $iTimeBlocksNotCached += $r['raw_time'];
+                ++$iCountBlocksNotCached;
+            }
+            if ($r['empty'] == 'yes') {
+                $iTimeBlocksEmpty += $r['raw_time'];
+                ++$iCountBlocksEmpty;
+            } else {
+                $iTimeBlocksNotEmpty += $r['raw_time'];
+                ++$iCountBlocksNotEmpty;
+            }
+            unset ($GLOBALS['bx_profiler']->_aPagesBlocks[$k]['raw_time']);
+        }
+
+        $sBlocks = count($GLOBALS['bx_profiler']->_aPagesBlocks) . ' (' . $this->_formatTime($iTimeBlocks, 3) . ')';
+        if ($iCountBlocksCached)
+            $sBlocksCached = $iCountBlocksCached . ' (' . $this->_formatTime($iTimeBlocksCached, 3) . ')';
+        if ($iCountBlocksNotCached)
+            $sBlocksNotCached = $iCountBlocksNotCached . ' (' . $this->_formatTime($iTimeBlocksNotCached, 3) . ')';
+        if ($iCountBlocksEmpty)
+            $sBlocksEmpty = $iCountBlocksEmpty . ' (' . $this->_formatTime($iTimeBlocksEmpty, 3) . ')';
+        if ($iCountBlocksNotEmpty)
+            $sBlocksNotEmpty = $iCountBlocksNotEmpty . ' (' . $this->_formatTime($iTimeBlocksNotEmpty, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Pages Blocks:', $sBlocks) .
+            ($iCountBlocksCached ? $this->oTemplate->nameValue('Cached:', $sBlocksCached) : '') .
+            ($iCountBlocksNotCached ? $this->oTemplate->nameValue('Not Cached:', $sBlocksNotCached) : '') .
+            ($iCountBlocksEmpty ? $this->oTemplate->nameValue('Empty:', $sBlocksEmpty) : '') .
+            ($iCountBlocksNotEmpty ? $this->oTemplate->nameValue('Not Empty:', $sBlocksNotEmpty) : ''),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aPagesBlocks)
+        );
+    }
+
+    function _plankMenus ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aMenus))
+            return;
+
+        $iTimeMenus = 0;
+        foreach ($GLOBALS['bx_profiler']->_aMenus as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeMenus += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aMenus[$k]['raw_time']);
+        }
+
+        $sMenus = count($GLOBALS['bx_profiler']->_aMenus) . ' menus (' . $this->_formatTime($iTimeMenus, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Menus:', $sMenus),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aMenus)
+        );
+    }
+
+    function _plankSql ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aQueries))
+            return;
+
+        $iTimeQueries = 0;
+        foreach ($GLOBALS['bx_profiler']->_aQueries as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeQueries += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aQueries[$k]['raw_time']);
+        }
+
+        $sQueries = count($GLOBALS['bx_profiler']->_aQueries) . ' queries (' . $this->_formatTime($iTimeQueries, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('SQL:', $sQueries),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aQueries, 'sql')
+        );
+    }
+
+    function _plankModules ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aModules))
+            return;
+
+        $iTimeModules = 0;
+        foreach ($GLOBALS['bx_profiler']->_aModules as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeModules += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aModules[$k]['raw_time']);
+        }
+
+        $sModules = count($GLOBALS['bx_profiler']->_aModulesNames) . ' modules loaded';
+        $sModulesQueries = count($GLOBALS['bx_profiler']->_aModules) . ' modules queries (' . $this->_formatTime($iTimeModules, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Modules:', $sModules) .
+            $this->oTemplate->nameValue('Modules Queries:', $sModulesQueries),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aModules)
+        );
+    }
+
+    function _plankAlerts ()
+    {
+        if (empty($GLOBALS['bx_profiler']->_aAlerts))
+            return;
+
+        $iTimeAlerts = 0;
+        foreach ($GLOBALS['bx_profiler']->_aAlerts as $k => $r) {
+            if (!isset($r['raw_time']))
+                continue;
+            $iTimeAlerts += $r['raw_time'];
+            unset ($GLOBALS['bx_profiler']->_aAlerts[$k]['raw_time']);
+        }
+
+        $sAlerts = count($GLOBALS['bx_profiler']->_aAlerts) . ' alerts responses (' . $this->_formatTime($iTimeAlerts, 3) . ')';
+
+        return $this->oTemplate->plank(
+            $this->oTemplate->nameValue('Alerts:', $sAlerts),
+            $this->oTemplate->table($GLOBALS['bx_profiler']->_aAlerts)
+        );
+    }
+
+    function _formatTime ($i, $iPrecision = 4)
+    {
+        return round($i, $iPrecision) . ' sec';
+    }
+
+    function _formatBytes ($i)
+    {
+        if ($i > 1024*1024)
+            return round($i/1024/1024, 1) . 'M';
+        elseif ($i > 1024)
+            return round($i/1024, 1) . 'K';
+        else
+            return $i . 'B';
+    }
+
+    function _isProfilerDisabled()
+    {
+        if (isset($GLOBALS['bx_profiler_disable']) || isset($_GET['bx_profiler_disable']))
+            return true;
+
+        return false;
+    }
+
+    function _calcTime ($begin)
+    {
+        $i1 = explode(' ', microtime ());
+        $i2 = explode(' ', $begin);
+        return ($i1[0]+$i1[1]) - ($i2[0]+$i2[1]);
+    }
+
+    function _debugPrintArray ($mixed)
+    {
+        $sArgs .= 'Array(';
+        foreach ($mixed as $mixed2)
+            $sArgs .= (is_object($mixed2) ? $this->_debugPrintObject($mixed2) : $this->_debugPrintAny($mixed2)) . ',';
+        $sArgs = substr($sArgs, 0, -1);
+        $sArgs .= ')';
+        return $sArgs;
+    }
+
+    function _debugPrintObject ($mixed)
+    {
+        return get_class($mixed) . ' instance';
+    }
+
+    function _debugPrintAny ($mixed)
+    {
+        if (is_string($mixed))
+            return "'" . (strlen($mixed) > $this->_sLogMaxArgLength ? substr($mixed, 0, $this->_sLogMaxArgLength) . '...' : $mixed) . "'";
+        else
+            return $mixed;
+    }
+
+    function _debugBackTrace ($iShifts = 0)
+    {
+        $a = debug_backtrace();
+        while (--$iShifts > -1)
+            array_shift($a);
+
+        $s = '';
+        foreach ($a as $r) {
+
+            $sArgs = '';
+            foreach ($r['args'] as $mixed) {
+                switch (true) {
+                case is_array($mixed):
+                    $sArgs .= $this->_debugPrintArray($mixed);
+                    break;
+                case is_object($mixed):
+                    $sArgs .= $this->_debugPrintObject($mixed);
+                    break;
+                default:
+                    $sArgs .= $this->_debugPrintAny($mixed);
+                }
+                $sArgs .= ',';
+            }
+            $sArgs = substr($sArgs, 0, -1);
+
+            $s .= "--------------------------------------\n";
+            $s .= "{$r['line']} {$r['file']}\n";
+            $s .= "{$r['class']}{$r['type']}{$r['function']} ({$sArgs});\n";
+        }
+        return $s;
+    }
+}
+
+$GLOBALS['bx_profiler'] = new BxProfiler(BX_DOL_START);
+if (!$GLOBALS['bx_profiler']->_isProfilerDisabled())
+    register_shutdown_function (array ($GLOBALS['bx_profiler'], 'output'));
+
+/** @} */

+ 69 - 0
modules/boonex/profiler/updates/13.0.4_15.0.0/source/install/config.php

@@ -0,0 +1,69 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Profiler Profiler
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_profiler',
+    'title' => 'Profiler',
+    'note' => 'Measure different site timings.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/profiler/',
+    'home_uri' => 'profiler',
+
+    'db_prefix' => 'bx_profiler_',
+    'class_prefix' => 'BxProfiler',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Profiler',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'uninstall' => array (
+        'execute_sql' => 1,
+        'update_languages' => 1,
+    ),
+    'enable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array(
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

+ 13 - 0
modules/boonex/profiler/updates/13.0.4_15.0.0/source/template/images/icons/std-icon.svg

@@ -0,0 +1,13 @@
+<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="48" height="48" fill="url(#paint0_linear_337_1972)"/>
+<path d="M22.5 38.25C16.8754 38.25 14.0631 38.25 12.0916 36.738C11.4549 36.2498 10.895 35.6587 10.4324 34.9866C9 32.9056 9 29.9372 9 24C9 18.0629 9 15.0944 10.4324 13.0134C10.895 12.3413 11.4549 11.7503 12.0916 11.262C14.0631 9.75 16.8754 9.75 22.5 9.75H25.5C31.1246 9.75 33.9369 9.75 35.9083 11.262C36.5451 11.7503 37.105 12.3413 37.5676 13.0134C39 15.0944 39 18.0629 39 24C39 29.9372 39 32.9056 37.5676 34.9866C37.105 35.6587 36.5451 36.2498 35.9083 36.738C33.9369 38.25 31.1246 38.25 25.5 38.25H22.5Z" stroke="white" stroke-width="2.25"/>
+<path d="M9.75 28.5H38.25" stroke="white" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M16.5134 33H16.5M22.5 33H22.4865" stroke="white" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M31.5 21.3C30.817 21.3 30.0983 21.3423 29.4854 20.9656C29.2517 20.8221 29.0965 20.6236 28.7865 20.2267L25.875 16.5L22.125 22.5L19.4151 19.8985C19.0308 19.5296 18.6562 19.1556 18.1477 19.0076C17.7778 18.9 17.3519 18.9 16.5 18.9" stroke="white" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"/>
+<defs>
+<linearGradient id="paint0_linear_337_1972" x1="24" y1="0" x2="24" y2="48" gradientUnits="userSpaceOnUse">
+<stop stop-color="#71717A"/>
+<stop offset="1" stop-color="#52525B"/>
+</linearGradient>
+</defs>
+</svg>

+ 51 - 0
modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/config.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Quote of the Day',
+    'version_from' => '13.0.1',
+    'version_to' => '15.0.0',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/quoteofday/updates/update_13.0.1_15.0.0/',
+    'home_uri' => 'quoteofday_update_1301_1500',
+
+    'module_dir' => 'boonex/quoteofday/',
+    'module_uri' => 'quoteofday',
+
+    'db_prefix' => 'bx_quoteofday_',
+    'class_prefix' => 'BxQuoteOfDay',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Quote Of Day',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/installer.php

@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxQuoteOfDayUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+}

+ 4 - 0
modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/langs/en.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_del name="_bx_quoteofday_grid_action_title_adm_audit_content"><![CDATA[Audit actions]]></string_del>
+</resources>

+ 2 - 0
modules/boonex/quoteofday/updates/13.0.1_15.0.0/install/sql/enable.sql

@@ -0,0 +1,2 @@
+-- GRIDS
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_quoteofday_internal' AND `name`='audit_content';

+ 115 - 0
modules/boonex/quoteofday/updates/13.0.1_15.0.0/source/classes/BxQuoteOfDayGridInternal.php

@@ -0,0 +1,115 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    QuoteOfTheDay Quote of the Day
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxQuoteOfDayGridInternal extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+    
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_quoteofday';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct ($aOptions, $oTemplate);
+    }
+    
+    protected function _getCellText($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = $this->_limitMaxLength(strip_tags(htmlspecialchars_decode($aRow['text'])), $sKey, $aField, $aRow, $this->_isDisplayPopupOnTextOverflow);
+        return parent::_getCellDefault ($mixedValue, $sKey, $aField, $aRow);
+    }
+    
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $sDisplay = 'bx_quoteofday_entry_add';
+        $oForm = BxDolForm::getObjectInstance('bx_quoteofday', $sDisplay);
+        if(!$oForm)
+            return echoJson([]);
+
+        $oForm->setId($sDisplay);
+        $oForm->setAction(BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction);
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $mixedResult = $oForm->insert(array('added' => time()));
+            if(is_numeric($mixedResult))
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $mixedResult);
+            else
+                $aRes = array('msg' => $mixedResult);
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplFunctions::getInstance()->popupBox('bx_quoteofday_form_add', _t('_bx_quoteofday_form_add_title'), $this->_oModule->_oTemplate->parseHtmlByName('manage_item.html', array(
+                'form_id' => $oForm->id,
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+           echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => true))));
+        }
+    }
+    
+    public function performActionEdit()
+    {
+        $iId = $this->_getId();
+
+        $sAction = 'edit';
+        $sDisplay = 'bx_quoteofday_entry_edit';
+        $oForm = BxDolForm::getObjectInstance('bx_quoteofday', $sDisplay); // get form instance for specified form object and display
+        if(!$oForm)
+            return echoJson([]);
+        
+        $oForm->setId($sDisplay);
+        $oForm->setAction(BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction . '&id=' . $iId);
+
+        $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iId);
+
+        $oForm->initChecker($aContentInfo);
+        if($oForm->isSubmittedAndValid()) {
+            $mixedResult = $oForm->update($iId);
+            if(is_numeric($mixedResult))
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $mixedResult);
+            else
+                $aRes = array('msg' => $mixedResult);
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplFunctions::getInstance()->popupBox('bx_quoteofday_form_edit', _t('_bx_quoteofday_form_edit_title'), $this->_oModule->_oTemplate->parseHtmlByName('manage_item.html', array(
+                'form_id' => $oForm->id,
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+           echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+        }
+    }
+    
+    public function performActionPublish()
+    {
+        $iId = $this->_getId();
+        $aContentInfo = $this->_oModule->_oDb->getContentInfoById($iId);
+
+        $this->_oModule->removeQuoteFromCache();
+        $this->_oModule->putQuoteToCache($aContentInfo["text"]);
+        echoJson(['msg' => _t('_bx_quoteofday_grid_action_title_adm_publish_text')]);
+    }
+
+    protected function _getId()
+    {
+        if(($aIds = bx_get('ids')) && is_array($aIds))
+            return array_shift($aIds);
+        else
+            return ($iId = bx_get('id')) !== false ? (int)$iId : false;
+    }
+}
+
+/** @} */

+ 77 - 0
modules/boonex/quoteofday/updates/13.0.1_15.0.0/source/install/config.php

@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    QuoteOfTheDay Quote of the Day
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_quoteofday',
+    'title' => 'Quote of the Day',
+    'note' => 'Quote of the Day module.',
+    'version' => '15.0.0',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-A1'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/quoteofday/',
+    'home_uri' => 'quoteofday',
+
+    'db_prefix' => 'bx_quoteofday_',
+    'class_prefix' => 'BxQuoteOfDay',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Quote Of Day',
+
+    /**
+     * 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,
+    ),
+    'enable_success' => array(
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

Некоторые файлы не были показаны из-за большого количества измененных файлов