1
0
AntonLV 5 жил өмнө
parent
commit
c3c3374479
100 өөрчлөгдсөн 15156 нэмэгдсэн , 0 устгасан
  1. 51 0
      modules/boonex/payment/updates/11.0.6_12.0.0/install/config.php
  2. 72 0
      modules/boonex/payment/updates/11.0.6_12.0.0/install/installer.php
  3. 49 0
      modules/boonex/payment/updates/11.0.6_12.0.0/install/langs/en.xml
  4. 20 0
      modules/boonex/payment/updates/11.0.6_12.0.0/install/sql/enable.sql
  5. 112 0
      modules/boonex/payment/updates/11.0.6_12.0.0/install/sql/install.sql
  6. 378 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentCart.php
  7. 312 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentConfig.php
  8. 31 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentCronTimeTracker.php
  9. 567 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentDb.php
  10. 215 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentDetails.php
  11. 187 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentGridCart.php
  12. 257 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentGridProcessed.php
  13. 110 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentGridSbsAdministration.php
  14. 1238 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentModule.php
  15. 188 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderAppleInApp.php
  16. 457 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderChargebee.php
  17. 299 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderChargebeeV3.php
  18. 221 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderCredits.php
  19. 327 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderRecurly.php
  20. 381 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderStripe.php
  21. 640 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderStripeBasic.php
  22. 406 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderStripeV3.php
  23. 37 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentStudioPage.php
  24. 540 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentSubscriptions.php
  25. 459 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentTemplate.php
  26. 70 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/install/config.php
  27. 604 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/install/langs/en.xml
  28. 43 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/disable.sql
  29. 171 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/enable.sql
  30. 538 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/install.sql
  31. 37 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/uninstall.sql
  32. 144 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/js/orders.js
  33. 100 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/js/stripe_v3.js
  34. 93 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/css/orders.css
  35. 43 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_history.html
  36. 19 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_pending_process.html
  37. 52 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_processed.html
  38. 19 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_processed_add.html
  39. 2 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/providers_select_button.html
  40. 52 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/rcrl_card_popup_add.html
  41. 9 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/redirect.html
  42. 16 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_billing_change_recuring.html
  43. 2 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_button_recurring.html
  44. 4 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_button_single.html
  45. 16 0
      modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_details_change_recuring.html
  46. 51 0
      modules/boonex/photos/updates/11.0.2_12.0.0/install/config.php
  47. 26 0
      modules/boonex/photos/updates/11.0.2_12.0.0/install/installer.php
  48. 13 0
      modules/boonex/photos/updates/11.0.2_12.0.0/install/langs/en.xml
  49. 39 0
      modules/boonex/photos/updates/11.0.2_12.0.0/install/sql/enable.sql
  50. 26 0
      modules/boonex/photos/updates/11.0.2_12.0.0/install/sql/install.sql
  51. 194 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/classes/BxPhotosConfig.php
  52. 24 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/classes/BxPhotosPageListEntry.php
  53. 136 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/install/config.php
  54. 256 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/install/langs/en.xml
  55. 63 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/install/sql/disable.sql
  56. 463 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/install/sql/enable.sql
  57. 400 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/install/sql/install.sql
  58. 69 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/install/sql/uninstall.sql
  59. 1 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/template/favorite-list-info.html
  60. 1 0
      modules/boonex/photos/updates/11.0.2_12.0.0/source/template/favorite-lists.html
  61. 51 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/install/config.php
  62. 13 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/install/installer.php
  63. 3 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/install/sql/install.sql
  64. 30 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/source/classes/BxPlyrStudioPage.php
  65. 74 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/source/install/config.php
  66. 15 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/source/install/sql/install.sql
  67. 5 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/source/install/sql/uninstall.sql
  68. 19 0
      modules/boonex/plyr/updates/11.0.1_12.0.0/source/template/css/main.css
  69. 51 0
      modules/boonex/polls/updates/11.0.1_12.0.0/install/config.php
  70. 26 0
      modules/boonex/polls/updates/11.0.1_12.0.0/install/installer.php
  71. 13 0
      modules/boonex/polls/updates/11.0.1_12.0.0/install/langs/en.xml
  72. 45 0
      modules/boonex/polls/updates/11.0.1_12.0.0/install/sql/enable.sql
  73. 51 0
      modules/boonex/polls/updates/11.0.1_12.0.0/install/sql/install.sql
  74. 208 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsConfig.php
  75. 252 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsModule.php
  76. 24 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsPageListEntry.php
  77. 296 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsTemplate.php
  78. 136 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/install/config.php
  79. 256 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/install/langs/en.xml
  80. 48 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/disable.sql
  81. 465 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/enable.sql
  82. 435 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/install.sql
  83. 68 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/uninstall.sql
  84. 130 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/js/entry.js
  85. 138 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/template/css/entry.css
  86. 1 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/template/favorite-list-info.html
  87. 1 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/template/favorite-lists.html
  88. 1 0
      modules/boonex/polls/updates/11.0.1_12.0.0/source/template/unit_embed.html
  89. 53 0
      modules/boonex/posts/updates/11.0.2_12.0.0/install/config.php
  90. 26 0
      modules/boonex/posts/updates/11.0.2_12.0.0/install/installer.php
  91. 21 0
      modules/boonex/posts/updates/11.0.2_12.0.0/install/langs/en.xml
  92. 58 0
      modules/boonex/posts/updates/11.0.2_12.0.0/install/sql/enable.sql
  93. 116 0
      modules/boonex/posts/updates/11.0.2_12.0.0/install/sql/install.sql
  94. 229 0
      modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsConfig.php
  95. 191 0
      modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsFormEntry.php
  96. 24 0
      modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsPageListEntry.php
  97. 26 0
      modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsStudioPage.php
  98. 27 0
      modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsUploaderRecordVideo.php
  99. 27 0
      modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsUploaderRecordVideoAttach.php
  100. 153 0
      modules/boonex/posts/updates/11.0.2_12.0.0/source/install/config.php

+ 51 - 0
modules/boonex/payment/updates/11.0.6_12.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' => '11.0.6',
+    'version_to' => '12.0.0',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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_11.0.6_12.0.0/',
+    'home_uri' => 'payment_update_1106_1200',
+
+    '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(),
+);

+ 72 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/install/installer.php

@@ -0,0 +1,72 @@
+<?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);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_payment_providers', 'for_owner_only'))
+                $this->oDb->query("ALTER TABLE `bx_payment_providers` ADD `for_owner_only` tinyint(4) NOT NULL default '0' AFTER `for_visitor`");
+            if(!$this->oDb->isFieldExists('bx_payment_providers', 'single_seller'))
+                $this->oDb->query("ALTER TABLE `bx_ads_reviews` ADD `single_seller` tinyint(4) NOT NULL default '0' AFTER `for_recurring`");
+            if(!$this->oDb->isFieldExists('bx_payment_providers', 'time_tracker'))
+                $this->oDb->query("ALTER TABLE `bx_ads_reviews` ADD `time_tracker` tinyint(4) NOT NULL default '0' AFTER `single_seller`");
+
+            if(!$this->oDb->isFieldExists('bx_payment_transactions', 'author_id'))
+                $this->oDb->query("ALTER TABLE `bx_payment_transactions` ADD `author_id` int(11) NOT NULL default '0' AFTER `seller_id`");
+
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions', 'period'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` ADD `period` int(11) unsigned NOT NULL default '1' AFTER `subscription_id`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions', 'period_unit'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` ADD `period_unit` varchar(32) NOT NULL default '' AFTER `period`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions', 'trial'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` ADD `trial` int(11) unsigned NOT NULL default '0' AFTER `period_unit`");
+            if($this->oDb->isFieldExists('bx_payment_subscriptions', 'date'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` CHANGE `date` `date_add` int(11) NOT NULL default '0'");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions', 'date_next'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` ADD `date_next` int(11) NOT NULL default '0' AFTER `date_add`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions', 'pay_attempts'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` ADD `pay_attempts` tinyint(4) NOT NULL default '0' AFTER `date_next`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions', 'status')) {
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` ADD `status` varchar(32) NOT NULL default 'unpaid' AFTER `pay_attempts`");
+                
+                $this->oDb->query("UPDATE `bx_payment_subscriptions` SET `status`='active' WHERE `paid` <> 0");
+
+                if($this->oDb->isFieldExists('bx_payment_subscriptions', 'paid'))
+                    $this->oDb->query("ALTER TABLE `bx_payment_subscriptions` DROP `paid`");
+            }
+
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'period'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` ADD `period` int(11) unsigned NOT NULL default '1' AFTER `subscription_id`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'period_unit'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` ADD `period_unit` varchar(32) NOT NULL default '' AFTER `period`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'trial'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` ADD `trial` int(11) unsigned NOT NULL default '0' AFTER `period_unit`");
+            if($this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'date'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` CHANGE `date` `date_add` int(11) NOT NULL default '0'");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'date_next'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` ADD `date_next` int(11) NOT NULL default '0' AFTER `date_add`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'pay_attempts'))
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` ADD `pay_attempts` tinyint(4) NOT NULL default '0' AFTER `date_next`");
+            if(!$this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'status')) {
+                $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` ADD `status` varchar(32) NOT NULL default 'unpaid' AFTER `pay_attempts`");
+                
+                $this->oDb->query("UPDATE `bx_payment_subscriptions_deleted` SET `status`='active' WHERE `paid` <> 0");
+
+                if($this->oDb->isFieldExists('bx_payment_subscriptions_deleted', 'paid'))
+                    $this->oDb->query("ALTER TABLE `bx_payment_subscriptions_deleted` DROP `paid`");
+            }
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 49 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/install/langs/en.xml

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_payment_option_credits_only"><![CDATA[Pay with Credits only mode ('Credits' app should be installed).]]></string_add>
+	<string_add name="_bx_payment_option_single_seller"><![CDATA[Single seller mode (To sell everything on behalf of the 'Main seller').]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_pdrs_single_seller"><![CDATA[Single Seller]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_pdrs_time_tracker"><![CDATA[Time Tracker]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_ods_author_id"><![CDATA[Author]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_sbs_status"><![CDATA[Status]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_sbs_date_add"><![CDATA[Created]]></string_add>
+	<string_add name="_bx_payment_grid_column_title_sbs_date_next"><![CDATA[Next Payment]]></string_add>
+	<string_add name="_bx_payment_grid_action_title_sbs_delete"><![CDATA[Remove]]></string_add>
+	<string_add name="_bx_payment_msg_single_seller"><![CDATA[Single seller mode is enabled. <a href="{0}">Got to</a> single shopping cart.]]></string_add>
+	<string_add name="_bx_payment_err_not_supported"><![CDATA[Operation isn't supported.]]></string_add>
+	<string_add name="_bx_payment_txt_author"><![CDATA[Author]]></string_add>
+	<string_add name="_bx_payment_txt_all_authors"><![CDATA[All Authors]]></string_add>
+	<string_add name="_bx_payment_txt_status_scheduled"><![CDATA[Scheduled]]></string_add>
+	<string_add name="_bx_payment_txt_status_trial"><![CDATA[Trial]]></string_add>
+	<string_add name="_bx_payment_txt_status_active"><![CDATA[Active]]></string_add>
+	<string_add name="_bx_payment_txt_status_unpaid"><![CDATA[Unpaid]]></string_add>
+	<string_add name="_bx_payment_txt_status_paused"><![CDATA[Paused]]></string_add>
+	<string_add name="_bx_payment_txt_status_canceled"><![CDATA[Canceled]]></string_add>
+	<string_add name="_bx_payment_txt_status_unknown"><![CDATA[Unknown]]></string_add>
+	<string_add name="_bx_payment_cdt_msg_charged"><![CDATA[Payment was successfully processed.]]></string_add>
+	<string_add name="_bx_payment_cdt_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string_add>
+	<string_add name="_bx_payment_strp_v3_cpt"><![CDATA[Stripe]]></string_add>
+	<string_add 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_add>
+	<string_add name="_bx_payment_txt_name_stripe_v3"><![CDATA[Stripe]]></string_add>
+	<string_add name="_bx_payment_txt_cart_stripe_v3"><![CDATA[Stripe]]></string_add>
+	<string_add name="_bx_payment_aina_cpt"><![CDATA[Apple In-App]]></string_add>
+	<string_add name="_bx_payment_aina_dsc"><![CDATA[Apple In-App payment provider]]></string_add>
+	<string_add name="_bx_payment_aina_active_cpt"><![CDATA[Active]]></string_add>
+	<string_add name="_bx_payment_aina_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string_add>
+	<string_add name="_bx_payment_aina_hidden_cpt"><![CDATA[Hidden]]></string_add>
+	<string_add 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_add>
+	<string_add name="_bx_payment_aina_secret_cpt"><![CDATA[Shared Secret]]></string_add>
+	<string_add name="_bx_payment_aina_secret_dsc"><![CDATA[It's the app-specific unique code to receive receipts for auto-renewable subscriptions.]]></string_add>
+	<string_add name="_bx_payment_aina_notify_url_cpt"><![CDATA[URL for App Store Server Notifications]]></string_add>
+	<string_add name="_bx_payment_aina_menu_item_title_cancel"><![CDATA[Cancel]]></string_add>
+	<string_add name="_bx_payment_aina_msg_charged"><![CDATA[Payment was successfully processed.]]></string_add>
+	<string_add name="_bx_payment_aina_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string_add>
+	<string_add name="_bx_payment_txt_name_apple_in_app"><![CDATA[Apple In-App]]></string_add>
+	<string_add name="_bx_payment_txt_cart_apple_in_app"><![CDATA[Apple In-App]]></string_add>
+
+	<string_upd name="_bx_payment_option_site_admin"><![CDATA[Main seller (To sell on behalf of the site)]]></string_upd>
+
+	<string_del name="_bx_payment_grid_column_title_sbs_paid"><![CDATA[Paid]]></string_del>
+	<string_del name="_bx_payment_grid_column_title_sbs_date_created"><![CDATA[Created]]></string_del>
+	<string_del name="_bx_payment_cdt_msg_processed"><![CDATA[Payment was successfully processed.]]></string_del>
+</resources>

+ 20 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/install/sql/enable.sql

@@ -0,0 +1,20 @@
+SET @sName = 'bx_payment';
+
+
+-- SETTINGS
+SET @iCategoryId = (SELECT `id` FROM `sys_options_categories` WHERE `name`=@sName LIMIT 1);
+
+DELETE FROM `sys_options` WHERE `name` IN ('bx_payment_credits_only', 'bx_payment_single_seller');
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_payment_credits_only', '', @iCategoryId, '_bx_payment_option_credits_only', 'checkbox', '', '', '', '', 10),
+('bx_payment_single_seller', '', @iCategoryId, '_bx_payment_option_single_seller', 'checkbox', '', '', '', '', 11);
+
+
+-- MENUS
+UPDATE `sys_menu_items` SET `icon`='credit-card col-gray-dark' WHERE `set_name`='sys_account_settings' AND `name`='payment-details';
+
+
+-- CRON
+DELETE FROM `sys_cron_jobs` WHERE `name`='bx_payment_time_tracker';
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('bx_payment_time_tracker', '* * * * *', 'BxPaymentCronTimeTracker', 'modules/boonex/payment/classes/BxPaymentCronTimeTracker.php', '');

+ 112 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/install/sql/install.sql

@@ -0,0 +1,112 @@
+SET @sName = 'bx_payment';
+
+-- TABLES
+UPDATE `bx_payment_providers` SET `for_recurring`='1', `single_seller`='1', `time_tracker`='1' WHERE `name`='credits';
+
+SET @iProviderId = (SELECT `id` FROM `bx_payment_providers` WHERE `name`='stripe_v3' 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_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', '', '_sys_form_account_input_email_error', 10),
+(@iProviderId, 'strp_v3_expiration_email', 'text', '_bx_payment_strp_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_sys_form_account_input_email_error', 11),
+(@iProviderId, 'strp_v3_notify_url', 'value', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 12);
+
+SET @iProviderId = (SELECT `id` FROM `bx_payment_providers` WHERE `name`='apple_in_app' 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_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
+UPDATE `sys_objects_grid` SET `source`='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'' ', `field_order`='date_add', `filter_fields`='ts`.`customer_id,ts`.`subscription_id,ts`.`date_add' WHERE `object`='bx_payment_grid_sbs_list_my';
+UPDATE `sys_objects_grid` SET `source`='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'' ', `field_order`='date_add' WHERE `object`='bx_payment_grid_sbs_list_all';
+UPDATE `sys_objects_grid` SET `source`='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`.`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 ' WHERE `object`='bx_payment_grid_orders_processed';
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_payment_grid_providers';
+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);
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_payment_grid_sbs_list_my';
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('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);
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_payment_grid_sbs_list_all';
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('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);
+
+UPDATE `sys_grid_fields` SET `chars_limit`='0' WHERE `object`='bx_payment_grid_sbs_history' AND `name`='seller_id';
+UPDATE `sys_grid_fields` SET `chars_limit`='0' WHERE `object`='bx_payment_grid_orders_history' AND `name`='seller_id';
+
+DELETE FROM `sys_grid_fields` WHERE `object`='bx_payment_grid_orders_processed';
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('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, 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);
+
+UPDATE `sys_grid_fields` SET `chars_limit`='0' WHERE `object`='bx_payment_grid_orders_pending' AND `name`='client_id';
+
+UPDATE `sys_grid_actions` SET `icon`='ban' WHERE `object`='bx_payment_grid_sbs_list_all' AND `name`='cancel';
+
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_payment_grid_sbs_list_all' AND `name`='delete';
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_payment_grid_sbs_list_all', 'single', 'delete', '_bx_payment_grid_action_title_sbs_delete', 'times', 1, 1, 3);
+
+
+-- STUDIO PAGE & WIDGET
+SET @iPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name`=@sName LIMIT 1);
+UPDATE `sys_std_widgets` SET `type`='extensions' WHERE `page_id`=@iPageId;

+ 378 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentCart.php

@@ -0,0 +1,378 @@
+<?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 '';
+
+        return array(
+            'content' => $this->_oModule->_oTemplate->displayBlockCarts($iUserId)
+        );
+    }
+
+    /**
+     * @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 '';
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return array(
+            	'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 array(
+                'content' => MsgBox(_t($CNF['T']['ERR_UNKNOWN_VENDOR']))
+            );
+
+        $aSeller = $this->_oModule->getProfileInfo($iSellerId);
+        return array(
+            'title' => _t($CNF['T']['BLOCK_TITLE_CART'], $aSeller['name']),
+            'content' => $this->_oModule->_oTemplate->displayBlockCart($iUserId, $iSellerId)
+        );
+    }
+
+    /**
+     * @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'] : '';
+
+        $sCiDsc = $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $iItemId));
+        if(strpos($sCartItems, $sCiDsc) !== false)
+            $sCartItems = preg_replace_callback(
+                "/" . $this->_oModule->_oConfig->descriptorA2S(array($iSellerId, $iModuleId, $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));
+            $sCartItems = empty($sCartItems) ? $sCartItem : $sCartItems . $this->_oModule->_oConfig->getDivider('DIVIDER_DESCRIPTORS') . $sCartItem;
+        }
+
+        $aCartCustom = array();
+        if(!empty($aCart['customs']))
+            $aCartCustom = unserialize($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, $sCartItems, $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 = array();
+        if(!empty($aCart['customs']))
+            $aCartCustom = unserialize($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($iSellerId, $iModuleId, $iItemId, '[0-9]+:?')) . "'", "", $aCart['items']), ":");
+        $this->_oModule->_oDb->setCartItems($iClientId, $aCart['items'], $aCartCustom);
+
+        bx_alert($this->_oModule->getName(), '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 isset($aContent[$iSellerId]) ? $this->_getInfo($sType, $iUserId, $iSellerId, $aContent[$iSellerId]) : array();
+
+        $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'] : array();
+
+            //--- Get item main info
+            $aItemInfo = $this->_oModule->callGetCartItem((int)$aItem['module_id'], array($aItem['item_id'], $aCustom));
+            if(empty($aItemInfo) || !is_array($aItemInfo)) {
+                if($bTypeSingle) {
+                    $sCartItems = $this->_oModule->_oDb->getCartItems($iClientId);
+                    $sCartItems = trim(preg_replace("'" . $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, $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);
+        return 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_unit' => $aSeller['unit'],
+            'vendor_currency_code' => $aSeller['currency_code'],
+            'vendor_currency_sign' => $aSeller['currency_sign'],
+            'items_count' => $iItemsCount,
+            'items_price' => $fItemsPrice,
+            'items' => $aItemsInfo
+        );
+    }
+}
+
+/** @} */

+ 312 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentConfig.php

@@ -0,0 +1,312 @@
+<?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, array(
+            // module icon
+            'ICON' => 'credit-card col-gray-dark',
+
+            // 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_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_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/',
+
+            'KEY_ARRAY_PRICE_SINGLE' => 'price_single',
+            'KEY_ARRAY_PRICE_RECURRING' => 'price_recurring',
+            'KEY_ARRAY_TRIAL_RECURRING' => 'trial_recurring',
+
+            'OBJECT_FORM_PRELISTS_CURRENCIES' => 'bx_payment_currencies',
+            'OBJECT_PP_CREDITS' => 'credits', //Credits payment provider
+
+            'MODULE_CREDITS' => 'bx_credits',
+
+            // some language keys
+            'T' => array(
+                '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',	
+            ),
+        );
+
+        $this->_aPerPage = array(
+            'orders' => 10,
+            'history' => 10
+        );
+        $this->_aHandlers = array();
+
+        $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)
+    {
+    	$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 (float)$fPrice;
+    }
+
+    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)
+    {
+        return base64_encode(serialize($a));
+    }
+
+    public function s2a($s)
+    {
+        return unserialize(base64_decode($s));
+    }
+            
+    public function descriptorA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTOR'), $a);
+    }
+
+    public function descriptorS2A($s) 
+    {
+    	return explode($this->getDivider('DIVIDER_DESCRIPTOR'), $s);
+    }
+
+    /**
+     * Conver items to array with necessary structure.
+     *
+     * @param  string/array $mixed - string with cart items divided with (:) or an array of cart items.
+     * @return array        with items.
+     */
+    public function descriptorsM2A($mixed)
+    {
+        $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;
+        });
+    }
+}
+
+/** @} */

+ 31 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentCronTimeTracker.php

@@ -0,0 +1,31 @@
+<?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 BxPaymentCronTimeTracker extends BxDolCron
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+    	$this->_sModule = 'bx_payment';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+    }
+
+    function processing()
+    {
+        $this->_oModule->processTimeTracker();
+    }
+}
+
+/** @} */

+ 567 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentDb.php

@@ -0,0 +1,567 @@
+<?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()
+    {
+        $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' 
+            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 = "";
+        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'";
+                        break;
+
+                    case 'for_recurring':
+                        $aMethod['name'] = 'getAllWithKey';
+                        $aMethod['params'][1] = 'name';
+
+                        $sWhereClause = " AND `tp`.`for_recurring`='1'";
+                        break;
+
+                    case 'all':
+                        $aMethod['name'] = 'getAllWithKey';
+                        $aMethod['params'][1] = 'name';
+
+                        if(!empty($aParams['active'])) 
+                            $sWhereClause = " AND `tp`.`active`='1'";
+                        break;
+	        }          
+
+        $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;
+
+        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 = array(
+    		'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";
+
+        return $this->getAllWithKey($sQuery, 'name', $aBinding);
+    }
+
+    public function updateOption($iUserId, $iOptionId, $sValue)
+    {
+        $sQuery = $this->prepare("REPLACE INTO `" . $this->_sPrefix . "user_values` SET `user_id`=?, `option_id`=?, `value`=?", $iUserId, $iOptionId, $sValue);
+        return $this->query($sQuery);
+    }
+
+
+    /**
+     * Shopping cart methods.
+     */
+    public function getCartItems($iId)
+    {
+    	$sQuery = $this->prepare("SELECT `items` FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=? LIMIT 1", $iId);
+        return $this->getOne($sQuery);
+    }
+
+    public function getCartContent($iId)
+    {
+        $aCart = $this->getRow("SELECT * FROM `" . $this->_sPrefix . "cart` WHERE `client_id`=:client_id LIMIT 1", array(
+            'client_id' => $iId
+        ));
+
+        if(empty($aCart) || !is_array($aCart))
+            $aCart = array('items' => '', '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) ? serialize($aCustoms) : ''
+        ));
+    }
+
+	public function getVendorInfoProvidersSingle($iVendorId)
+    {
+    	return $this->getVendorInfoProviders($iVendorId, array('type' => 'for_single'));
+    }
+
+	public function getVendorInfoProvidersRecurring($iVendorId)
+    {
+    	return $this->getVendorInfoProviders($iVendorId, array('type' => 'for_recurring'));
+    }
+
+    public function getVendorInfoProviders($iVendorId, $aParams = array())
+    {
+    	if(empty($aParams))
+    		$aParams = array('type' => 'all');
+
+		$aProviders = $this->getProviders($aParams);
+		$aOptions = $this->getOptions($iVendorId);
+
+		$aResult = array();
+		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 = array())
+    {
+        $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'])) . ':';
+        }
+
+        return (int)$this->query("INSERT INTO `" . $this->_sPrefix . "transactions_pending` SET `client_id`=:client_id, `seller_id`=:seller_id, `type`=:type, `provider`=:provider, `items`=:items, `customs`=:customs, `amount`=:amount, `date`=UNIX_TIMESTAMP()", array(
+            'client_id' => $iClientId,
+            'seller_id' => $aCartInfo['vendor_id'],
+            'type' => $sType, 
+            'provider' => $sProvider,
+            'items' => trim($sItems, ':'),
+            'customs' => !empty($aCustom) && is_array($aCustom) ? serialize($aCustom) : '',
+            'amount' => $aCartInfo['items_price']
+        )) > 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 = "";
+
+        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 'mixed':
+                $aMethod['name'] = 'getAll';
+
+                $sWhereClause = ' AND ' . $this->arrayToSQL($aParams['conditions'], ' AND ');
+                break;
+
+        }
+
+        $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;
+
+        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`<=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);
+    }
+}
+
+/** @} */

+ 215 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentDetails.php

@@ -0,0 +1,215 @@
+<?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
+ *
+ * @{
+ */
+
+bx_import('BxDolForm');
+
+class BxPaymentDetailsFormCheckerHelper extends BxDolFormCheckerHelper
+{
+    function checkHttps ($s)
+    {
+        return empty($s) || substr(BX_DOL_URL_ROOT, 0, 5) == 'https';
+    }
+}
+
+class BxPaymentDetails extends BxBaseModPaymentDetails
+{
+    protected $_sLangsPrefix;
+    protected $_bCollapseFirst;
+
+    function __construct()
+    {
+        $this->MODULE = 'bx_payment';
+
+        parent::__construct();
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+        $this->_bCollapseFirst = true;
+    }
+
+    /**
+     * @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)
+    {
+        if(!$this->_oModule->isLogged())
+            return array(
+                'content' => MsgBox(_t($this->_sLangsPrefix . 'err_required_login'))
+            );
+
+        $iUserId = $iUserId != BX_PAYMENT_EMPTY_ID ? $iUserId : $this->_oModule->getProfileId();
+
+        $sContent = $this->getForm($iUserId);
+        if(empty($sContent))
+            $sContent = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        return array(
+            'content' => $sContent
+        );
+    }
+
+    public function getForm($iUserId)
+    {
+        $aInputs = $this->_oModule->_oDb->getForm();
+        if(empty($aInputs))
+            return '';
+
+        $aForm = array(
+            'form_attrs' => array(
+                'id' => 'pmt_details',
+                'name' => 'pmt_details',
+                'action' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=payment-details'),
+                'method' => 'post',
+                'enctype' => 'multipart/form-data'
+            ),
+            'params' => array(
+                'db' => array(
+                    'table' => '',
+                    'key' => 'id',
+                    'uri' => '',
+                    'uri_title' => '',
+                    'submit_name' => 'submit'
+                ),
+                'checker_helper' => 'BxPaymentDetailsFormCheckerHelper'
+            ),
+            'inputs' => array (
+            )
+        );
+
+        $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']) {
+                $aForm['inputs']['provider_' . $aInput['provider_id'] . '_begin'] = array(
+                    'type' => 'block_header',
+                    'caption' => _t($aInput['provider_caption']),
+                	'info' => _t($aInput['provider_description']),
+                    'collapsable' => true,
+                    'collapsed' => $bCollapsed
+                );
+
+                $iProvider = $aInput['provider_id'];
+                $sProvider = $aInput['provider_name'];
+                $oProvider = $this->_oModule->getObjectProvider($sProvider, $iUserId);
+                $bCollapsed = true;
+            }
+
+            $aForm['inputs'][$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 = array('values' => array());
+
+                    $aPairs = explode(',', $aInput['extra']);
+                    foreach($aPairs as $sPair) {
+                        $aPair = explode('|', $sPair);
+                        $aAddon['values'][] = array('key' => $aPair[0], 'value' => _t($aPair[1]));
+                    }
+                    break;
+
+                case 'checkbox':
+                    $aForm['inputs'][$aInput['name']]['value'] = 'on';
+                    $aAddon = array('checked' => $oProvider->getOption($aInput['name']) == 'on');
+                    break;
+
+                case 'value':
+                       $sName = str_replace($aInput['provider_option_prefix'], '', $aInput['name']);
+                       if(!in_array($sName, array('return_data_url', 'notify_url')))
+                            break;
+
+                       $sMethod = 'get' . bx_gen_method_name($sName);
+                       if(method_exists($oProvider, $sMethod))
+                            $aForm['inputs'][$aInput['name']]['value'] = $oProvider->$sMethod($iUserId);
+                       break;
+            }
+
+            if(!empty($aAddon) && is_array($aAddon))
+                $aForm['inputs'][$aInput['name']] = array_merge($aForm['inputs'][$aInput['name']], $aAddon);
+        }
+
+        $aForm['inputs']['provider_' . $iProvider . '_end'] = array(
+            'type' => 'block_end'
+        );
+        $aForm['inputs']['submit'] = array(
+            'type' => 'submit',
+            'name' => 'submit',
+            'value' => _t($this->_sLangsPrefix . 'form_details_input_do_submit'),
+        );
+
+        bx_import('BxTemplFormView');
+        $oForm = new BxTemplFormView($aForm);
+        $oForm->initChecker();
+
+        if($oForm->isSubmittedAndValid()) {
+            $aOptions = $this->_oModule->_oDb->getOptions();
+            foreach($aOptions as $aOption) {
+            	$sValue = bx_get($aOption['name']) !== false ? bx_get($aOption['name']) : '';
+                $this->_oModule->_oDb->updateOption($iUserId, $aOption['id'], bx_process_input($sValue));
+            }
+
+            header('Location: ' . $oForm->aFormAttrs['action']);
+            return;
+        }
+
+        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 $oForm->getCode();
+    }
+}
+
+/** @} */

+ 187 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentGridCart.php

@@ -0,0 +1,187 @@
+<?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 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($this->_sCurrencySign . $mixedValue, $sKey, $aField, $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;
+            }
+    	}
+
+    	return $sActions . parent::_getActions ($sType, $sActionData, $isSmall, $isDisabled, $isPermanentState, $aRow);
+    }
+
+    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) {
+            $aCartItem['descriptor'] = $this->_oModule->_oConfig->descriptorA2S(array($aCartItem['author_id'], $aCartItem['module_id'], $aCartItem['id'], $aCartItem['quantity']));
+            $aCartItem['description'] = strip_tags($aCartItem['description']);
+
+            $this->_aOptions['source'][] = $aCartItem;
+        }
+
+        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);
+    }
+}
+
+/** @} */

+ 257 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentGridProcessed.php

@@ -0,0 +1,257 @@
+<?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 BxPaymentGridProcessed extends BxBaseModPaymentGridOrders
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sOrdersType = 'processed';
+
+        $this->_sJsObject = $this->_oModule->_oConfig->getJsObject('processed');
+    }
+
+    public function performActionAdd()
+    {
+        $sType = BX_PAYMENT_TYPE_SINGLE;
+        $sAction = 'add';
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('processed');
+
+        $sFormObject = $this->_oModule->_oConfig->getObject('form_processed');
+        $sFormDisplay = $this->_oModule->_oConfig->getObject('display_processed_add');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+
+        $oForm->aInputs['seller_id']['value'] = $this->_aQueryAppend['seller_id'];
+
+        $oForm->aInputs['client_id']['attrs'] = array(
+            'id' => $this->_oModule->_oConfig->getHtmlIds('processed', 'order_processed_client_id'),
+        );
+
+        $oForm->aInputs['client']['attrs'] = array(
+            'id' => $this->_oModule->_oConfig->getHtmlIds('processed', 'order_processed_client')			
+        );
+
+        $oForm->aInputs['client']['ajax_get_suggestions'] = BX_DOL_URL_ROOT . 'modules/?r=' . $this->_oModule->_oConfig->getUri() . '/get_clients';
+
+        $oForm->aInputs['client']['custom'] = array(
+            'only_once' => true,
+            'on_select' => "function(oObject){{$sJsObject}.showPopup(oObject);}"
+        );
+
+        $oForm->aInputs['module_id']['attrs'] = array(
+            'onchange' => 'javascript:' . $sJsObject . '.selectModule(this);'
+        );
+        $oForm->aInputs['module_id']['values'] = array(
+            array('key' => '0', 'value' => _t('_Select_one'))
+        );
+
+        $aModules = $this->_oModule->_oDb->getModules();
+        foreach($aModules as $aModule)
+           $oForm->aInputs['module_id']['values'][] = array('key' => $aModule['id'], 'value' => $aModule['title']);
+
+        $oForm->aInputs['items']['content'] = $this->_oModule->_oTemplate->displayItems($sType);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sFormMethod = $oForm->aFormAttrs['method'];
+
+            $aItemIds = $oForm->getSubmittedValue('items', $sFormMethod);
+            if(empty($aItemIds) || !is_array($aItemIds))
+                return echoJson(array('msg' => $this->_sLangsPrefix . 'err_empty_items'));
+
+            $aItems = array();
+            $sPriceKey = $this->_oModule->_oConfig->getKey('KEY_ARRAY_PRICE_SINGLE');
+            foreach($aItemIds as $iItemId) {
+                $iItemId = (int)$iItemId;
+                $fItemPrice = (float)$oForm->getSubmittedValue('item-price-' . $iItemId, $sFormMethod);
+                $iItemQuantity = (int)$oForm->getSubmittedValue('item-quantity-' . $iItemId, $sFormMethod);
+
+                if($iItemQuantity <= 0)
+                    return echoJson(array('msg' => $this->_sLangsPrefix . 'err_wrong_quantity'));
+
+                $aItems[] = array(
+                    'id' => $iItemId, 
+                     $sPriceKey => $fItemPrice, 
+                    'quantity' => $iItemQuantity
+                );
+            }
+
+            $mixedResult = $this->_oModule->getObjectOrders()->addOrder(array(
+                'client_id' => $oForm->getCleanValue('client_id'),
+                'seller_id' => $oForm->getCleanValue('seller_id'),
+                'provider' => 'manual',
+                'type' => $sType,
+                'order' => $oForm->getCleanValue('order'),
+                'error_code' => 0,
+                'error_msg' => 'Manually processed',        		
+                'module_id' => $oForm->getCleanValue('module_id'),
+                'items' => $aItems
+            ));
+            if(is_array($mixedResult))
+                return echoJson($mixedResult);
+
+            $iPendingId = (int)$mixedResult;
+            if(!$this->_oModule->registerPayment($iPendingId))
+                return echoJson(array('msg' => _t($this->_sLangsPrefix . 'err_cannot_perform')));
+
+            $aOrders = $this->_oModule->_oDb->getOrderProcessed(array('type' => 'pending_id', 'pending_id' => $iPendingId, 'with_key' => 'id'));
+            return echoJson(array('grid' => $this->getCode(false), 'blink' => array_keys($aOrders)));
+        }
+
+        $sKey = 'order_' . $this->_sOrdersType . '_add';
+        $sId = $this->_oModule->_oConfig->getHtmlIds('processed', $sKey);
+        $sTitle = _t($this->_sLangsPrefix . 'popup_title_ods_' . $sKey);
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('order_processed_add.html', array(
+            'js_object' => $sJsObject,
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    protected function _getActionCancel ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!empty($aRow['seller_id']) && $aRow['seller_id'] != bx_get_logged_profile_id())
+            return '';
+
+        return $this->_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+            
+            
+    protected function _getFilterClients()
+    {
+        $aIds = $this->_oModule->_oDb->getOrderProcessed(array('type' => 'clients', 'seller_id' => $this->_aQueryAppend['seller_id']));
+
+        $aValues = array();
+        foreach($aIds as $iId)
+            if(!empty($iId) && ($oClient = BxDolProfile::getInstanceMagic($iId)) !== false)
+                $aValues[] = array('key' => $iId, 'value' => $oClient->getDisplayName());
+
+        $this->_oModule->_oConfig->sortByColumn('value', $aValues);
+
+        return $this->_getFilterSelectAll('client', array(
+            'values' => array_merge(array(
+                array('key' => '', 'value' => _t('_bx_payment_txt_all_clients'))
+            ), $aValues)
+        ));
+    }
+
+    protected function _getFilterAuthors()
+    {
+        $aIds = $this->_oModule->_oDb->getOrderProcessed(array('type' => 'authors', 'seller_id' => $this->_aQueryAppend['seller_id']));
+
+        $aValues = array();
+        foreach($aIds as $iId)
+            if(!empty($iId) && ($oClient = BxDolProfile::getInstanceMagic($iId)) !== false)
+                $aValues[] = array('key' => $iId, 'value' => $oClient->getDisplayName());
+
+        $this->_oModule->_oConfig->sortByColumn('value', $aValues);
+
+        return $this->_getFilterSelectAll('author', array(
+            'values' => array_merge(array(
+                array('key' => '', 'value' => _t('_bx_payment_txt_all_authors'))
+            ), $aValues)
+        ));
+    }
+
+    protected function _getFilterModules()
+    {
+        $aModules = $this->_oModule->_oDb->getModules();
+        
+        $aValues = array();
+        foreach($aModules as $aModule) {
+            $sLangKey = '_' . $aModule['name'];
+            $sLangValue = _t($sLangKey);
+
+            $aValues[] = array('key' => $aModule['id'], 'value' => $sLangKey != $sLangValue ? $sLangValue : $aModule['title']);
+        }
+
+        $this->_oModule->_oConfig->sortByColumn('value', $aValues);
+
+        return $this->_getFilterSelectAll('module', array(
+            'js_onchange' => 'onChangeFilterModule(this, ' . $this->_aQueryAppend['seller_id'] . ')',
+            'values' => array_merge(array(
+                array('key' => '', 'value' => _t('_bx_payment_txt_all_modules'))
+            ), $aValues)
+        ));
+    }
+
+    protected function _getFilterItems()
+    {
+        return $this->_getFilterSelectAll('item', array(
+            'attrs' => array('disabled' => 'disabled'),
+            'values' => array(
+                array('key' => '', 'value' => _t('_bx_payment_txt_all_items'))
+            )
+        ));
+    }
+
+    protected function _getFilterControls ()
+    {
+        parent::_getFilterControls();
+
+        $sResult = $this->_getFilterClients();
+        if($this->_bSingleSeller && $this->_aQueryAppend['seller_id'] == $this->_iSingleSeller)
+            $sResult .= $this->_getFilterAuthors();
+        $sResult .= $this->_getFilterModules() . $this->_getFilterItems() . $this->_getSearchInput();
+
+        return $sResult;
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+    	if(empty($this->_aQueryAppend['seller_id']))
+            return array();
+
+        $sParamsDivider = $this->_oModule->_oConfig->getDivider('DIVIDER_GRID_FILTERS');
+
+        $iClient = $iAuthor = $iModule = $iItem = 0;
+        if(strpos($sFilter, $sParamsDivider) !== false) {
+            $aFilters = explode($sParamsDivider, $sFilter);
+            if($this->_bSingleSeller && $this->_aQueryAppend['seller_id'] = $this->_iSingleSeller)
+                list($iClient, $iAuthor, $iModule, $iItem, $sFilter) = $aFilters;
+            else
+                list($iClient, $iModule, $iItem, $sFilter) = $aFilters;
+        }
+
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND (`tt`.`seller_id`=? OR `tt`.`author_id`=?)", $this->_aQueryAppend['seller_id'], $this->_aQueryAppend['seller_id']);
+
+        $iClient = (int)$iClient;
+        if($iClient != 0)
+            $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `tt`.`client_id`=?", $iClient);
+
+        $iAuthor = (int)$iAuthor;
+        if($iAuthor != 0)
+            $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `tt`.`author_id`=?", $iAuthor);
+
+        $iModule = (int)$iModule;
+        if($iModule != 0)
+            $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `tt`.`module_id`=?", $iModule);
+
+        $iItem = (int)$iItem;
+        if($iItem != 0)
+            $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `tt`.`item_id`=?", $iItem);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 110 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentGridSbsAdministration.php

@@ -0,0 +1,110 @@
+<?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 BxPaymentGridSbsAdministration extends BxBaseModPaymentGridOrders
+{
+    protected $_sManageType;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sOrdersType = BX_PAYMENT_ORDERS_TYPE_SUBSCRIPTION;
+        $this->_sManageType = 'administration';
+    }
+
+    public function performActionCancel()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) 
+            return echoJson(array());
+
+        $oSubscriptions = $this->_oModule->getObjectSubscriptions();
+
+        $iAffected = 0;
+        $aAffected = array();
+        foreach($aIds as $iId)
+            if($oSubscriptions->cancel($iId)) {
+                $aAffected[] = $iId;
+            	$iAffected++;
+            }
+
+        echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aAffected) : array('msg' => _t($this->_sLangsPrefix . 'err_cannot_perform')));
+    }
+
+    protected function _getCellProvider($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_payment_txt_name_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellSubscriptionId($mixedValue, $sKey, $aField, $aRow)
+    {
+        $aItems = $this->_oModule->_oConfig->descriptorsM2A($aRow['items']);
+        if(!is_array($aItems) || count($aItems) != 1)
+            return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+
+        $aItem = array_shift($aItems);
+        $aInfo = BxDolService::call((int)$aItem['module_id'], 'get_payment_data');
+        if(!empty($aInfo['url_browse_order_' . $this->_sManageType]))
+            $mixedValue = $this->_oModule->_oTemplate->displayLink('link', array(
+                'href' => bx_replace_markers($aInfo['url_browse_order_' . $this->_sManageType], array(
+                    'order' => $mixedValue
+                )),
+                'title' => bx_html_attribute($mixedValue),
+                'content' => $mixedValue
+            ));
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellDateAdd($mixedValue, $sKey, $aField, $aRow)
+    {
+        return $this->_getCellDefaultDateTime($mixedValue, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellDateNext($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(empty($mixedValue))
+            return parent::_getCellDefault(_t('_uknown'), $sKey, $aField, $aRow);
+
+        return $this->_getCellDefaultDateTime($mixedValue, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellStatus($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_payment_txt_status_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+
+        $this->_oTemplate->addJsTranslation(array(
+            '_bx_payment_msg_confirm_cancelation',
+            '_bx_payment_txt_unsubscribe_yes',
+            '_bx_payment_txt_unsubscribe_no'
+        ));
+    }
+
+    protected function _delete ($mixedId)
+    {
+        $aSubscription = $this->_oModule->_oDb->getSubscription(array('type' => 'pending_id', 'pending_id' => $mixedId));
+        if(empty($aSubscription) || !is_array($aSubscription))
+            return false;
+
+        return $this->_oModule->_oDb->deleteSubscription($aSubscription['id'], 'delete');
+    }
+}
+
+/** @} */

+ 1238 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentModule.php

@@ -0,0 +1,1238 @@
+<?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');
+
+
+/**
+ * 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));
+
+        echoJson(array(
+            'code' => 0, 
+            'eval' => $this->_oConfig->getJsObject('processed') . '.onSelectModule(oData);', 
+            'data' => $this->_oTemplate->displayItems($sType, $aItems)
+        ));
+    }
+
+    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',
+        ));
+    }
+
+    /**
+     * @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;
+    }
+
+    /**
+     * @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;
+    }
+
+    /**
+     * Cart Processing Methods
+     */
+    public function actionAddToCart($iSellerId, $iModuleId, $iItemId, $iItemCount, $sCustom = '')
+    {
+        if(empty($sCustom) && bx_get('custom') !== false)
+            $sCustom = bx_process_input(bx_get('custom'));
+
+        $aCustom = array();
+        if(!empty($sCustom)) {
+            $aCustom = unserialize(base64_decode($sCustom));
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = array();
+        }
+
+        $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 = unserialize(base64_decode($sCustom));
+            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 = unserialize(base64_decode($sCustom));
+            if(empty($aCustom) || !is_array($aCustom))
+                $aCustom = array();
+        }
+
+        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(
+            'sibscription_id' => $aSubscription['subscription_id'],
+            'sibscription_customer' => $aSubscription['customer_id'],
+            'sibscription_date' => bx_time_js($aSubscription['date'], 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 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;
+    }
+
+    /**
+     * @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 = !empty($aCart['customs']) ? unserialize($aCart['customs']) : array();
+
+                $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 = !empty($aCart['customs']) ? unserialize($aCart['customs']) : array();
+
+            $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);
+            }
+        }
+
+        bx_alert($this->getName(), 'before_pending', 0, bx_get_logged_profile_id(), array(
+            'client_id' => $this->_iUserId,
+            '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 actionFinalizeCheckout($sProvider, $mixedVendorId = "")
+    {
+        $aData = &$_REQUEST;
+
+        $oProvider = $this->getObjectProvider($sProvider, $mixedVendorId);
+        if($oProvider === false || !$oProvider->isActive())
+            return $this->_oTemplate->displayPageCodeError($this->_sLangsPrefix . 'err_incorrect_provider');
+
+        $aResult = $oProvider->finalizeCheckout($aData);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) 
+            return $this->_oTemplate->displayPageCodeError($aResult['message']);
+
+        $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$aResult['pending_id']));
+        $bTypeRecurring = $aPending['type'] == BX_PAYMENT_TYPE_RECURRING;
+        if($bTypeRecurring) {
+            $sStatus = BX_PAYMENT_SBS_STATUS_UNPAID;
+            if(isset($aResult['paid']) && $aResult['paid'])
+                $sStatus = BX_PAYMENT_SBS_STATUS_ACTIVE;
+            else if(isset($aResult['trial']) && $aResult['trial'])
+                $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 $this->_oTemplate->displayPageCodeError($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'] : '');
+
+        //--- Register payment for purchased items in associated modules 
+        if(!empty($aResult['paid']) || ($bTypeRecurring && !empty($aResult['trial'])))
+            $this->registerPayment($aPending);
+
+        bx_alert($this->getName(), '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()) {
+            header('Location: ' . $oProvider->getReturnUrl());
+            exit;
+        }
+
+        if(!empty($aResult['redirect'])) {
+            header('Location: ' . base64_decode(urldecode($aResult['redirect'])));
+            exit;
+        }
+
+        $this->_oTemplate->displayPageCodeResponse($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)
+    {
+		$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'], 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']));
+        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 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 registerPayment($mixedPending)
+    {
+    	$aPending = is_array($mixedPending) ? $mixedPending : $this->_oDb->getOrderPending(array('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'];
+        $sLicense = $this->_oConfig->getLicense();
+        $aCustoms = !empty($aPending['customs']) ? unserialize($aPending['customs']) : array();
+
+        $aCart = array();
+        if($bTypeSingle) {
+            $aCart = $this->_oDb->getCartContent($iClientId);
+            $aCart['customs'] = !empty($aCart['customs']) ? unserialize($aCart['customs']) : array();
+        }
+
+        $bResult = false;
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        foreach($aItems as $aItem) {
+            $sItem = $this->_oConfig->descriptorA2S(array($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'], array($aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order'], $sLicense, $aItemCustom));
+            if(empty($aItemInfo) || !is_array($aItemInfo))
+                continue;
+
+            $this->_oDb->insertOrderProcessed(array(
+                'pending_id' => $aPending['id'],
+                'client_id' => $aPending['client_id'],
+                'seller_id' => $aPending['seller_id'],
+                'author_id' => $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),
+            	'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'], array('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 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.');
+                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.');
+                continue;
+            }
+
+            if(!$oProvider->makePayment($aPending)) {
+                $this->log($aSubscription, 'Time Tracker', 'Payment cannot be processed.');
+                continue;
+            }
+
+            if(!$this->getObjectSubscriptions()->prolong($aPending)) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot prolong subscription.');
+                continue;
+            }
+
+            if(!$this->registerPayment($aPending)) {
+                $this->log($aSubscription, 'Time Tracker', 'Cannot register payment.');
+                continue;
+            }
+        }
+    }
+
+    public function onPaymentRegisterBefore($aPending, $aResult = array())
+    {
+        bx_alert('system', 'before_register_payment', 0, $aPending['client_id'], array('pending' => $aPending));
+    }
+
+    public function onPaymentRegister($aPending, $aResult = array())
+    {
+        $bTypeSingle = $aPending['type'] == BX_PAYMENT_TYPE_SINGLE;
+
+        if($bTypeSingle) {
+            $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+            foreach($aItems as $aItem)
+                $this->isAllowedPurchase(array('module_id' => $aItem['module_id'], 'item_id' => $aItem['item_id']), true);
+        }
+
+        bx_alert('system', 'register_payment', 0, $aPending['client_id'], array('pending' => $aPending));
+    }
+
+    public function onPaymentRefund($aPending, $aResult = array())
+    {
+        bx_alert('system', 'refund_payment', 0, $aPending['client_id'], array('pending' => $aPending));
+    }
+
+    public function onSubscriptionCreate($aPending, $aSubscription, $aResult = array())
+    {
+        $aItems = $this->_oConfig->descriptorsM2A($aPending['items']);
+        $this->isAllowedPurchase(array('module_id' => $aItems[0]['module_id'], 'item_id' => $aItems[0]['item_id']), true);
+
+        bx_alert('system', 'create_subscription', 0, $aPending['client_id'], array(
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ));
+    }
+
+    public function onSubscriptionProlong($aPending, $aSubscription, $aResult = array())
+    {
+        bx_alert('system', 'prolong_subscription', 0, $aPending['client_id'], array(
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ));
+    }
+
+    public function onSubscriptionOverdue($aPending, $aSubscription, $aResult = array())
+    {
+        bx_alert('system', 'overdue_subscription', 0, $aPending['client_id'], array(
+            'pending' => $aPending,
+            'subscription' => $aSubscription
+        ));
+    }
+
+    public function onSubscriptionCancel($aPending, $aSubscription, $aResult = array())
+    {
+        bx_alert('system', 'cancel_subscription', 0, $aPending['client_id'], array(
+            '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(serialize($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;
+    }
+}
+
+/** @} */

+ 188 - 0
modules/boonex/payment/updates/11.0.6_12.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 : ''));
+
+        $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;
+    }
+}
+
+/** @} */

+ 457 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderChargebee.php

@@ -0,0 +1,457 @@
+<?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(BX_DIRECTORY_PATH_PLUGINS . 'chargebee/ChargeBee.php');
+
+define('CBEE_MODE_LIVE', 1);
+define('CBEE_MODE_TEST', 2);
+
+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->createHostedPage($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 createHostedPage($aItem, $aClient, $aVendor = array(), $iPendingId = 0)
+    {
+        $oPage = false;
+
+        try {
+            $aPage = array(
+                'embed' => false, //--- Note. 'embed' should be disabled to allow payments via PayPal
+                'subscription' => array(
+                    'planId' => $aItem['name']
+                ),
+                'customer' => array(
+                    '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
+                ));
+
+            ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = ChargeBee_HostedPage::checkoutNew($aPage);
+
+            $oPage = $oResult->hostedPage();
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Create Hosted Page Error: ' . $sError . '(' . $iError . ')');
+
+            return false;
+        }
+
+        return $oPage;
+    }
+
+    public function retreiveHostedPage($sPageId)
+    {
+        $oPage = null;
+
+        try {
+            ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = ChargeBee_HostedPage::retrieve($sPageId);
+
+            $oPage = $oResult->hostedPage();
+        }
+        catch (Exception $oException) {
+            $iError = $oException->getCode();
+            $sError = $oException->getMessage();
+
+            $this->log('Retrieve Hosted Page Error: ' . $sError . '(' . $iError . ')');
+
+            return false;
+        }
+
+        return $oPage;
+    }
+
+    public function retrieveSubscription($sSubscriptionId)
+    {
+        $oSubscription = null;
+
+        try {
+            ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = ChargeBee_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 . ')');
+
+            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 {
+            ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = ChargeBee_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']);
+            $this->log($aError);
+
+            return false;
+        }
+
+        $this->onDeleteSubscription($sSubscriptionId, $oSubscription->getValues());
+
+        return true;
+    }
+
+    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;
+            
+            ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResults = ChargeBee_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 . ')');
+
+            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 {
+            ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = ChargeBee_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 . ')');
+
+            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 {
+            ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+            $oResult = ChargeBee_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 . ')');
+
+            return false;
+        }
+
+        return $oCustomer;
+    }
+
+    public function onDeleteSubscription($sSubscriptionId, $aSubscription)
+    {
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_cancel_subscription', 0, false, array(
+            '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 : ''));
+        $this->log($aEvent);
+
+        $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;
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $aTransaction['subscription_id']));
+        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);
+    }
+}
+
+/** @} */

+ 299 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderChargebeeV3.php

@@ -0,0 +1,299 @@
+<?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');
+
+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 actionGetHostedPage($iClientId, $iVendorId, $sItemName, $sItemAddons = '')
+    {
+        $this->initOptionsByVendor($iVendorId);
+
+        $aItem = array('name' => $sItemName);
+        if(!empty($sItemAddons)) {
+            $aItemAddons = $this->_oModule->_oConfig->s2a($sItemAddons);
+
+            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->createHostedPage($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 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';
+
+        if($aPending['type'] != BX_PAYMENT_TYPE_RECURRING) 
+            return $this->_sLangsPrefix . 'err_wrong_data';
+
+		$oCustomer = $oPage->content()->customer();
+		$oSubscription = $oPage->content()->subscription();
+
+		return array(
+			'code' => 0,
+			'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+			'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
+				'order_id' => $oSubscription->id,
+				'customer_id' => $oCustomer->id,
+				'pending_id' => $aPending['id'],
+				'redirect' => $sRedirect
+			))
+		);
+    }
+
+    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');
+
+        if($aPending['type'] != BX_PAYMENT_TYPE_RECURRING) 
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $oCustomer = $this->retrieveCustomer($sCustomerId);
+        $oSubscription = $this->retrieveSubscription($sOrderId);
+        if($oCustomer === false || $oSubscription === false)
+            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+        $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',
+            'redirect' => $sRedirect
+        );
+
+        //--- 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 getPortal($sCustomerId, $sSubscriptionId)
+    {
+    	$oPortal = false;
+
+    	try {
+    		ChargeBee_Environment::configure($this->_getSite(), $this->_getApiKey());
+    		$oResult = ChargeBee_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 . ')');
+
+    		return false;
+    	}
+
+    	return $oPortal;
+    }
+
+    public function getJsCode($aParams = array())
+    {
+    	$sSite = '';
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_js_code', 0, 0, array(
+	    	'site' => &$sSite,
+	    	'params' => &$aParams
+    	));
+
+    	return $this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+			'sProvider' => $this->_sName,
+			'sSite' => !empty($sSite) ? $sSite : $this->_getSite()
+    	), $aParams));
+    }
+
+    /**
+     * Single time payments aren't available with Chargebee
+     */
+    public function getButtonSingle($iClientId, $iVendorId, $aParams = array())
+    {
+        return '';
+    }
+
+    public function getButtonSingleJs($iClientId, $iVendorId, $aParams = array())
+    {
+        return array();
+    }
+
+    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())
+    {
+        $sJsObject = $this->_oModule->_oConfig->getJsObject($this->_sName);
+
+        $sSite = '';
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, array(
+            'type' => &$sType, 
+            'site' => &$sSite,
+            'params' => &$aParams
+        ));
+
+        $sJsMethod = '';
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                /**
+                 * Single time payments aren't available with Chargebee.
+                 */
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sJsMethod = $sJsObject . '.subscribe(this)';
+                break;
+        }
+
+        return array($this->_oModule->_oTemplate->getJsCode($this->_sName, array_merge(array(
+            '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'))
+        );
+    }
+}
+
+/** @} */

+ 221 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderCredits.php

@@ -0,0 +1,221 @@
+<?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');
+            $this->log($aData);
+            $this->log($aResult);
+        }
+
+        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 array('code' => 1, 'message' => $this->_sLangsPrefix . 'cdt_err_not_available');
+
+        if(!is_array($mixedPending))
+            $mixedPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
+
+        if(empty($mixedPending) || !is_array($mixedPending))
+            return array('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 array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_wrong_data');
+
+        $fAmount = (float)$mixedPending['amount'];
+        if(!bx_srv($this->_sModuleCredits, 'make_payment', array($iClient, $fAmount, $iSeller, $mixedPending['order'])))
+            return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+        return true;        
+    }
+
+    public function cancelRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        bx_alert($this->MODULE, $this->_sName . '_cancel_subscription', 0, false, array(
+            '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'];
+                if(!bx_srv($this->_sModuleCredits, 'validate_checkout', array((int)$aPending['seller_id'], (int)$aPending['client_id'], (float)$aPending['amount'], $sOrder)))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'cdt_err_wrong_transaction', 'pending_id' => $iPendingId);
+
+                $aResult = array(
+                    'message' => $this->_sLangsPrefix . 'cdt_msg_charged',
+                    'order' => !empty($aData['o']) ? $aData['o'] : '',
+                    '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)));
+    }
+}
+
+/** @} */

+ 327 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderRecurly.php

@@ -0,0 +1,327 @@
+<?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(BX_DIRECTORY_PATH_PLUGINS . 'recurly/recurly.php');
+
+define('RCRL_MODE_LIVE', 1);
+define('RCRL_MODE_TEST', 2);
+
+class BxPaymentProviderRecurly extends BxBaseModPaymentProvider implements iBxBaseModPaymentProvider
+{
+	protected $_aIncludeJs;
+	protected $_aIncludeCss;
+
+	protected $_sFormCard;
+	protected $_sFormDisplayCardAdd;
+
+	protected $_iMode;
+	protected $_bCheckAmount;
+
+    function __construct($aConfig)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+        	'https://js.recurly.com/v4/recurly.js'
+        );
+        $this->_aIncludeCss = array(
+        	'recurly.css'
+        );
+
+        $this->_sFormCard = 'bx_payment_form_rcrl_card';
+        $this->_sFormDisplayCardAdd = 'bx_payment_form_rcrl_card_add';
+
+        $this->_bUseSsl = true;
+        $this->_bCheckAmount = false; // Disabled for easier processing of discounted subscriptions.
+    }
+
+    public function initOptions($aOptions)
+    {
+    	parent::initOptions($aOptions);
+
+    	$this->_iMode = (int)$this->getOption('mode');
+    }
+
+	public function addJsCss()
+    {
+    	if(!$this->isActive())
+    		return;
+
+		$this->_oModule->_oTemplate->addJs($this->_aIncludeJs);
+		$this->_oModule->_oTemplate->addCss($this->_aIncludeCss);
+    }
+
+    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']);
+
+		$mixedResult = $this->createCardForm($iPendingId, $aItem, $aClient, $aVendor);
+		if($mixedResult === false)
+			return $this->_sLangsPrefix . 'err_cannot_perform';
+
+		return array_merge(array('code' => 0), $mixedResult);
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+    	$iPendingId = bx_process_input($aData['pending_id'], BX_DATA_INT);
+    	$sItem = bx_process_input($aData['item']);
+    	$sToken = bx_process_input($aData['token']);
+    	$aClient = array(
+    		'first_name' => bx_process_input($aData['first_name']),
+    		'last_name' => bx_process_input($aData['last_name']),
+    		'email' => bx_process_input($aData['email'])
+    	);
+
+        if(empty($sToken) || empty($iPendingId))
+        	return array('code' => 1, 'message' => $this->_sLangsPrefix . 'pp_err_no_data_given');
+		
+		$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');
+
+		$oSubscription = $this->createSubscription($sToken, $sItem, $aClient);
+		if($oSubscription === false)
+			return $this->_sLangsPrefix . 'err_cannot_perform';
+
+		/*
+		 * TODO: Need to get subscription ID to save it in DB as Order
+		 */
+		$sSubscription = '';
+
+		$aResult = array(
+			'code' => BX_PAYMENT_RESULT_SUCCESS,
+        	'message' => $this->_sLangsPrefix . 'rcrl_msg_subscribed',
+			'pending_id' => $iPendingId,
+			'client_name' => _t($this->_sLangsPrefix . 'txt_buyer_name_mask', $aClient['first_name'], $aClient['last_name']),
+			'client_email' => $aClient['email'],
+			'paid' => false
+		);
+
+        //--- Update pending transaction ---//
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sSubscription,
+            'error_code' => $aResult['code'],
+            'error_msg' => _t($aResult['message'])
+        ));
+
+        return $aResult;
+    }
+
+    public function notify()
+    {
+    	/*
+    	 * TODO: Integrate necessary Webhook events. 
+    	 */
+		//$iResult = $this->_processEvent();
+		//http_response_code($iResult);
+    }
+
+    public function createCardForm($iPendingId, $aItem, $aClient, $aVendor)
+    {
+		$oForm = BxDolForm::getObjectInstance($this->_sFormCard, $this->_sFormDisplayCardAdd, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = bx_append_url_params($this->getReturnDataUrl($aVendor['id']), array(
+			'pending_id' => $iPendingId
+		));
+
+        $oForm->aInputs['pending_id']['value'] = $iPendingId;
+        $oForm->aInputs['item']['value'] = $aItem['name'];
+
+		$aCardFields = array('card_number', 'card_cvv');
+		foreach($aCardFields as $sCardField) {
+			$oForm->aInputs[$sCardField]['content'] = $this->_oModule->_oTemplate->parseHtmlByName('rcrl_card_field.html', array(
+				'attrs' => bx_convert_array2attrs($oForm->aInputs[$sCardField]['attrs'])
+			));
+		}
+		$oForm->aInputs['card_expire']['content'] = $this->_oModule->_oTemplate->parseHtmlByName('rcrl_card_field_date.html', array(
+			'attrs_month' => bx_convert_array2attrs(array('data-recurly' => 'month')),
+			'attrs_year' => bx_convert_array2attrs(array('data-recurly' => 'year'))
+		));
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+        	$sFormMethod = $oForm->aFormAttrs['method'];
+
+        	/*
+        	 * TODO: Need to reload form on internal error or update the code to work via this check and then redirect to Finalize.
+        	 * Issue with "form reloading". Currently Recurly doesn't allow to "call payment form" multiple times (https://github.com/recurly/recurly-js/issues/239). 
+        	 */ 
+        }
+
+        $aTmplConfig = BxTemplConfig::getInstance()->__get('aLessConfig');
+        
+        $sId = 'bx-payment-rcrl-card-add';
+    	$sTitle = _t($this->_sLangsPrefix . 'popup_title_rcrl_card_add');
+		$sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('rcrl_card_popup_add.html', array(
+			'public_key' => $this->getOption('api_key_public'),
+			'font_family' => $aTmplConfig['bx-font-family'],
+			'font_size' => $aTmplConfig['bx-font-size-default'],
+			'font_color' => $aTmplConfig['bx-font-color-default'],
+			'form_id' => $oForm->aFormAttrs['id'],
+			'form' => $oForm->getCode(true),
+		)));
+
+		return array('popup' => array(
+			'html' => $sContent, 
+			'options' => array(
+				'closeOnOuterClick' => false, 
+				'onBeforeShow' => 'bxRecurlyFieldsInit();', 
+				'onHide' => 'bxRecurlyFieldsDestroy();'
+			)
+		));
+    }
+
+	public function createSubscription($sToken, $sItem, $aClient)
+	{
+		$oSubscription = false;
+
+		try {
+			$oSubscription = new Recurly_Subscription();
+			$oSubscription->plan_code = $sItem;
+
+			$oSubscription->account = new Recurly_Account();
+			$oSubscription->account->account_code = 'pat_smith';
+			$oSubscription->account->first_name = $aClient['first_name'];
+			$oSubscription->account->last_name = $aClient['last_name'];
+			$oSubscription->account->email = $aClient['email'];
+
+			$oSubscription->account->billing_info = new Recurly_BillingInfo();
+			$oSubscription->account->billing_info->token_id = $sToken;
+
+			$oSubscription->create();
+		}
+		catch (Exception $oException) {
+			$iError = $oException->getCode();
+			$sError = $oException->getMessage();
+
+			$this->log('Create Subscription Error: ' . $sError . '(' . $iError . ')');
+
+			return false;
+		}
+
+		return $oSubscription;
+	}
+
+	public function retrieveSubscription($sSubscriptionId)
+	{
+		$oSubscription = null;
+
+		try {
+			
+		}
+		catch (Exception $oException) {
+			$iError = $oException->getCode();
+			$sError = $oException->getMessage();
+
+			$this->log('Retrieve Subscription Error: ' . $sError . '(' . $iError . ')');
+
+			return false;
+		}
+
+		return $oSubscription;
+	}
+
+	public function deleteSubscription($sSubscriptionId)
+	{
+		try {
+
+		}
+		catch (Exception $oException) {
+			$aError = $oException->getJsonBody();
+
+			$this->log('Delete Subscription Error: ' . $aError['error']['message']);
+			$this->log($aError);
+
+			return false;
+		}
+
+		return true;
+	}
+
+	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 : ''));
+		$this->log($aEvent);
+
+		$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->_getData($aEvent, true);
+		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;
+
+		return $this->_oModule->registerPayment($aPending);
+	}
+
+	protected function _processEventPaymentRefunded(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->refundPayment($aPending);
+	}
+
+	protected function _processEventSubscriptionCancelled(&$aEvent)
+	{
+		$mixedResult = $this->_getData($aEvent);
+		if($mixedResult === false)
+			return false;
+
+		list($aPending) = $mixedResult;
+		return $this->_oModule->getObjectSubscriptions()->cancelLocal($aPending);
+	}
+
+	protected function _getData(&$aEvent, $bWithStatusCheck = false)
+	{
+		$aTransaction = $aEvent['content']['transaction'];
+		if(empty($aTransaction) || ($bWithStatusCheck && $aTransaction['status'] != 'success'))
+			return false;
+
+		$aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'order', 'order' => $aTransaction['subscription_id']));
+		if(empty($aPending) || !is_array($aPending))
+			return false;
+
+		return array($aPending, $aTransaction);
+	}
+}
+
+/** @} */

+ 381 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderStripe.php

@@ -0,0 +1,381 @@
+<?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 BxPaymentProviderStripe extends BxPaymentProviderStripeBasic implements iBxBaseModPaymentProvider
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'https://checkout.stripe.com/checkout.js',
+            'stripe.js'
+        );
+    }
+
+    public function initializeCheckout($iPendingId, $aCartInfo, $sRedirect = '')
+    {
+    	$sToken = bx_process_input(bx_get('token'));
+
+    	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:
+                $aCartInfo['items_title'] = '';
+                foreach($aCartInfo['items'] as $aItem)
+                    $aCartInfo['items_title'] .= ' ' . $aItem['title'] . ',';
+                $aCartInfo['items_title'] = trim($aCartInfo['items_title'], ', ');
+
+                $mixedResult = $this->_createCharge($sToken, $iPendingId, $aClient, $aCartInfo);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                header("Location: " . $this->getReturnDataUrl($aVendor['id'], array(
+                    'order_id' => $mixedResult['order'],
+                    'customer_id' => $mixedResult['customer'], 
+                    'pending_id' => $aPending['id'],
+                    'redirect' => $sRedirect
+                )));
+                exit;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = $this->_createSubscription($sToken, $iPendingId, $aClient, $aCartInfo);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                return array(
+                    'code' => 0,
+                    'eval' => $this->_oModule->_oConfig->getJsObject('cart') . '.onSubscribeSubmit(oData);',
+                    'redirect' => $this->getReturnDataUrl($aVendor['id'], array(
+                        'order_id' => $mixedResult['order'],
+                        'customer_id' => $mixedResult['customer'],
+                        'pending_id' => $aPending['id'],
+                        'redirect' => $sRedirect
+                    ))
+                );
+        }
+    }
+
+    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');
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'customer_id' => '',
+            'subscription_id' => '',
+            'client_name' => '',
+            'client_email' => '',
+            'paid' => false,
+            'trial' => false,
+            'redirect' => $sRedirect
+        );
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_SINGLE, $sCustomerId);
+                $oCharge = $this->_retrieveCharge($sOrderId);
+                if($oCustomer === false || $oCharge === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                $aCharge = $oCharge->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer) || empty($aCharge) || !is_array($aCharge))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aResult = array_merge($aResult, array(
+                    'message' => $this->_sLangsPrefix . 'strp_msg_charged',
+                    'client_email' => $aCustomer['email'],
+                    'paid' => (bool)$aCharge['paid']
+                ));
+                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, array(
+                    'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
+                    'customer_id' => $sCustomerId,
+                    'subscription_id' => $sOrderId,
+                    'client_email' => $aCustomer['email'],
+                    'trial' => $aSubscription['status'] == 'trialing'
+                ));
+                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 getCheckoutParamsSingle($aParams, &$oGrid)
+    {
+    	if(bx_get('token') !== false)
+            $aParams['token'] = bx_process_input(bx_get('token'));
+
+    	return $aParams;
+    }
+
+    protected function _createToken($aCard)
+    {
+        try {
+            $oToken = Stripe\Token::create(array('card' => $aCard));
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Token Error: ', $oException);
+        }
+
+        return $oToken->jsonSerialize();
+    }
+
+    protected function _createCustomer($sType, $sToken, $aClient)
+    {
+        $oCustomer = null;
+        $aCustomer = array(
+            'card' => $sToken,
+            'email' => !empty($aClient['email']) ? $aClient['email'] : ''
+        );
+
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_customer', 0, $aClient['id'], array(
+            'type' => $sType,
+            'customer_object' => &$oCustomer, 
+            'customer_params' => &$aCustomer
+        ));
+
+        try {
+            $this->_oCustomer = !empty($oCustomer) ? $oCustomer : \Stripe\Customer::create($aCustomer);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Customer Error: ', $oException);
+        }
+
+        return $this->_oCustomer->jsonSerialize();
+    }
+
+    protected function _createCharge($sToken, $iPendingId, &$aClient, &$aCartInfo)
+    {
+        if(empty($this->_oCustomer))
+            $this->_createCustomer(BX_PAYMENT_TYPE_SINGLE, $sToken, $aClient);
+
+        if(empty($this->_oCustomer))
+            return false;
+
+        $fAmount = 100 * (float)$aCartInfo['items_price'];
+
+        $oCharge = null;
+        $aCharge = array(
+            'customer' => $this->_oCustomer->id,
+            'amount' => $fAmount,
+            'currency' => $aCartInfo['vendor_currency_code'],
+            'description' => $aCartInfo['items_title'],
+            'metadata' => array(
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'product' => $iPendingId,
+                'verification' => $this->_getVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code'])
+            )
+        );
+
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_charge', $iPendingId, false, array(
+            'charge_object' => &$oCharge, 
+            'charge_params' => &$aCharge
+        ));
+
+        try {
+            if(empty($oCharge))
+                $oCharge = \Stripe\Charge::create($aCharge);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Charge Error: ', $oException);
+        }
+
+        $aResult = $oCharge->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult) || empty($aResult['paid']))
+            return false;
+
+        $aMetadata = $aResult['metadata'];
+        if(empty($aMetadata['verification']) || $aMetadata['verification'] != $this->_getVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], $aResult['amount'], $aResult['currency']))
+            return false;
+
+        return array(
+            'pending' => $iPendingId,
+            'amount' =>(float)$aResult['amount'] / 100,
+            'customer' => $this->_oCustomer->id,
+            'order' => $aResult['id']
+        );
+    }
+
+    protected function _createSubscription($sToken, $iPendingId, &$aClient, &$aCartInfo)
+    {
+        if(empty($this->_oCustomer))
+            $this->_createCustomer(BX_PAYMENT_TYPE_RECURRING, $sToken, $aClient);
+
+        if(empty($this->_oCustomer))
+            return false;
+
+        $aItem = array_shift($aCartInfo['items']);
+        if(empty($aItem) || !is_array($aItem))
+            return false;
+
+        $iTrial = $this->_oModule->_oConfig->getTrial(BX_PAYMENT_TYPE_RECURRING, $aItem);
+        $bTrial = !empty($iTrial);
+
+        $oSubscription = null;
+        $aSubscription = array(
+            'plan' => $aItem['name'],
+            'metadata' => array(
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'product' => $iPendingId,
+                'verification' => $this->_getVerificationCodeSubscription($aCartInfo['vendor_id'], $aClient['id'], $aItem['name'], $aCartInfo['vendor_currency_code'])
+            )
+        );
+
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_subscription', $iPendingId, false, array(
+            'customer' => &$this->_oCustomer,
+            'subscription_object' => &$oSubscription, 
+            'subscription_params' => &$aSubscription
+        ));
+
+        try {
+            if(empty($oSubscription))
+                $oSubscription = $this->_oCustomer->subscriptions->create($aSubscription);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Subscription Error: ', $oException);
+        }
+
+        $aResult = $oSubscription->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult) || (!$bTrial && $aResult['status'] != 'active') || ($bTrial && !in_array($aResult['status'], array('active', 'trialing'))))
+            return false;
+
+        $aMetadata = $aResult['metadata'];
+        if(empty($aMetadata['verification']) || $aMetadata['verification'] != $this->_getVerificationCodeSubscription($aCartInfo['vendor_id'], $aClient['id'], $aResult['plan']['id'], $aResult['plan']['currency']))
+            return false;
+
+        return array(
+            'pending' => $iPendingId,
+            'amount' =>(float)$aCartInfo['items_price'],
+            'customer' => $this->_oCustomer->id, 
+            'order' => $aResult['id'],
+            'trial' => $bTrial
+        );
+    }
+
+    protected function _createCard($sType, $sCustomerId, $sToken)
+    {
+        try {
+            $oCard = $this->_retrieveCustomer($sType, $sCustomerId)->sources->create(array(
+                'source' => $sToken
+            ));
+        }
+        catch (Stripe\Error\Base $oException) {
+            return $this->_processException('Create Card Error: ', $oException);
+        }
+
+        return $oCard->jsonSerialize();
+    }
+
+    protected function _retrieveCard($sCustomerId, $sCardId = '') {
+        try {
+            $oCustomer = \Stripe\Customer::retrieve($sCustomerId);
+            $oCard = $oCustomer->sources->retrieve(!empty($sCardId) ? $sCardId : $oCustomer->default_source);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Card Error: ', $oException);
+        }
+
+        return $oCard;
+    }
+
+    protected function _retrieveCoupon($sId) {
+        try {
+            $oCoupon = \Stripe\Coupon::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Coupon Error: ', $oException);
+        }
+
+        return $oCoupon;
+    }
+
+    protected function _getButtonJs($sType, $iClientId, $iVendorId, $aParams = array())
+    {
+        $sClientEmail = '';
+    	if(!empty($iClientId) && ($oClient = BxDolProfile::getInstance($iClientId)) !== false)
+            $sClientEmail = $oClient->getAccountObject()->getEmail();
+
+        $sPublicKey = '';
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, array(
+            'type' => &$sType, 
+            'public_key' => &$sPublicKey
+        ));
+
+        $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,
+            'sPublicKey' => !empty($sPublicKey) ? $sPublicKey : $this->_getPublicKey(),
+            'sVendorName' => '',
+            'sVendorCurrency' => '',
+            'sVendorIcon' => '',
+            'sClientEmail' => $sClientEmail,
+        ), $aParams)), $sJsMethod);
+    }
+}
+
+/** @} */

+ 640 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderStripeBasic.php

@@ -0,0 +1,640 @@
+<?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(BX_DIRECTORY_PATH_PLUGINS . 'stripe/init.php');
+
+define('STRP_MODE_LIVE', 1);
+define('STRP_MODE_TEST', 2);
+
+class BxPaymentProviderStripeBasic extends BxBaseModPaymentProvider
+{
+    protected $_aIncludeJs;
+    protected $_aIncludeCss;
+
+    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')));
+    		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 = $this->_retrieveCard($sCustomerId)->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(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;
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_customer', 0, false, array(
+            '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;
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_charge', 0, false, array(
+            '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 = $oCustomer->subscriptions->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);
+        }
+
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_cancel_subscription', 0, false, array(
+            'subscription_id' => $sSubscriptionId,
+            'subscription_object' => &$oSubscription
+        ));
+
+        return $oSubscription;
+    }
+
+    protected function _retrieveProduct($sId)
+    {
+        $oProduct = null;
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_product', 0, false, array(
+            '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 : ''));
+        $this->log($aEvent);
+
+        $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->_getData($aEvent);
+        if($mixedResult === false)
+            return false;
+
+        list($aPending, $oCharge) = $mixedResult;
+        if(empty($aPending) || !is_array($aPending) || empty($oCharge))
+            return false;
+
+        $fChargeAmount = (float)$oCharge->amount / 100;
+        $sChargeCurrency = strtoupper($oCharge->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 _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']);
+        $this->log($aError);
+
+        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 _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 _getVerificationCodeCharge($iVendorId, $iCustomerId, $fAmount, $sCurrency) {
+        return md5(implode('#-#', array(
+            (int)$iVendorId,
+            (int)$iCustomerId,
+            (float)$fAmount,
+            strtoupper($sCurrency)
+        )));
+    }
+
+    protected function _getVerificationCodeSubscription($iVendorId, $iCustomerId, $sSubscription, $sCurrency) {
+        return md5(implode('#-#', array(
+            (int)$iVendorId,
+            (int)$iCustomerId,
+            strtoupper($sSubscription),
+            strtoupper($sCurrency)
+        )));
+    }
+
+    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,
+    	));
+    }
+}
+
+/** @} */

+ 406 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentProviderStripeV3.php

@@ -0,0 +1,406 @@
+<?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
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+
+        $this->_aIncludeJs = array(
+            'stripe_v3.js'
+        );
+    }
+
+    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' => bx_get('item_addons'),
+            'redirect' => bx_process_input(bx_get('redirect')),
+            'custom' => bx_process_input(bx_get('custom')),
+        );
+
+        $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'],
+        )));
+
+        $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}'
+            )))
+        );
+
+        $sSessionId = $this->_createSession(BX_PAYMENT_TYPE_RECURRING, $aSessionParams, $aClient, $aCartInfo);
+        if($sSessionId === 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' => $sSessionId,
+            'eval' => $sJsObject . '.onSubscribe(oData);'
+        ));
+    }
+
+    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';
+
+                header("Location: " . $this->getReturnDataUrl($aVendor['id'], array(
+                    'order_id' => $mixedResult['order_id'],
+                    'customer_id' => $mixedResult['customer_id'], 
+                    'pending_id' => $aPending['id'],
+                    'redirect' => $sRedirect
+                )));
+                exit;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = $this->_getSession(BX_PAYMENT_TYPE_RECURRING, $sSessionId);
+                if($mixedResult === false)
+                    return $this->_sLangsPrefix . 'err_cannot_perform';
+
+                header("Location: " . $this->getReturnDataUrl($aVendor['id'], array(
+                    'order_id' => $mixedResult['order_id'],
+                    'customer_id' => $mixedResult['customer_id'],
+                    'pending_id' => $aPending['id'],
+                    'redirect' => $sRedirect
+                )));
+                exit;
+        }
+    }
+
+    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');
+
+        $aResult = array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS,
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'customer_id' => '',
+            'subscription_id' => '',
+            'client_name' => '',
+            'client_email' => '',
+            'paid' => false,
+            'trial' => false,
+            'redirect' => $sRedirect
+        );
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $oCustomer = $this->_retrieveCustomer(BX_PAYMENT_TYPE_SINGLE, $sCustomerId);
+                $oPaymentIntent = $this->_retrievePaymentIntent($sOrderId);
+                if($oCustomer === false || $oPaymentIntent === false)
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aCustomer = $oCustomer->jsonSerialize();
+                $aPaymentIntent = $oPaymentIntent->jsonSerialize();
+                if(empty($aCustomer) || !is_array($aCustomer) || empty($aPaymentIntent) || !is_array($aPaymentIntent))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'err_cannot_perform');
+
+                $aResult = array_merge($aResult, array(
+                    'message' => $this->_sLangsPrefix . 'strp_msg_charged',
+                    'client_email' => $aCustomer['email'],
+                    'paid' => $aPaymentIntent['status'] == 'succeeded'
+                ));
+                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, array(
+                    'message' => $this->_sLangsPrefix . 'strp_msg_subscribed',
+                    'customer_id' => $sCustomerId,
+                    'subscription_id' => $sOrderId,
+                    'client_email' => $aCustomer['email'],
+                    'paid' => $this->isSubscriptionStatus(BX_PAYMENT_SBS_STATUS_ACTIVE, $aSubscription),
+                    'trial' => $this->isSubscriptionStatus(BX_PAYMENT_SBS_STATUS_TRIAL, $aSubscription)
+                ));
+                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}'
+            )))
+        );
+
+        $sSessionId = $this->_createSession(BX_PAYMENT_TYPE_SINGLE, $aSessionParams, $aClient, $aCartInfo);
+        if($sSessionId === false)
+            return array('msg' => _t('_bx_payment_err_cannot_perform'));
+
+        return array(
+            'eval' => $this->_oModule->_oConfig->getJsObject($this->_sName) . '.onCartCheckout(oData);', 
+            'session_id' => $sSessionId
+        );
+    }
+
+    protected function _createSession($sType, $aParams, &$aClient, &$aCartInfo)
+    {
+        $fAmount = 100 * (float)$aCartInfo['items_price'];
+
+        $aLineItems = array();
+        foreach($aCartInfo['items'] as $aItem) {
+            $aLineItems[] = array(
+                'price' => $aItem['name'],
+                'quantity' => $aItem['quantity'],
+            );
+        }
+
+        $oSession = null;
+        $aSession = array(
+            'payment_method_types' => ['card'],
+            'customer_email' => !empty($aClient['email']) ? $aClient['email'] : '',
+            'line_items' => $aLineItems,
+            'mode' => '',
+            'success_url' => $aParams['success_url'],
+            'cancel_url' => $aParams['cancel_url'],
+            'metadata' => array(
+                'vendor' => $aCartInfo['vendor_id'],
+                'client' => $aClient['id'],
+                'verification' => $this->_getVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], $fAmount, $aCartInfo['vendor_currency_code'])
+            )
+        );
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aSession['mode'] = 'payment';
+                break;
+            
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aSession['mode'] = 'subscription';
+                break;
+        }
+
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_create_session', 0, false, array(
+            'session_object' => &$oSession, 
+            'session_params' => &$aSession
+        ));
+
+        try {
+            if(empty($oSession))
+                $oSession = \Stripe\Checkout\Session::create($aSession);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Create Session Error: ', $oException);
+        }
+
+        $aResult = $oSession->jsonSerialize();
+        if(empty($aResult) || !is_array($aResult))
+            return false;
+
+        $aMetadata = $aResult['metadata'];
+        if(empty($aMetadata['verification']) || $aMetadata['verification'] != $this->_getVerificationCodeCharge($aCartInfo['vendor_id'], $aClient['id'], (float)$aResult['amount_total'], $aResult['currency']))
+            return false;
+
+        return $aResult['id'];
+    }
+
+    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();
+
+        $aResult = array(
+            'id' => $aSession['id'],
+            'order_id' => $aSession['payment_intent'],
+            'customer_id' => $aSession['customer'],
+            'status' => $aSession['payment_status']
+        );
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $aResult['order_id'] = $aSession['payment_intent'];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aResult['order_id'] = $aSession['subscription'];
+                break;
+        }
+
+        return $aResult;
+    }
+
+    protected function _retrieveSession($sId) {
+        $oSession = null;
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_session', 0, false, array(
+            'session_id' => &$sId,
+            'session_object' => &$oSession
+        ));
+
+        try {
+            if(empty($oSession))
+                $oSession = \Stripe\Checkout\Session::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Session Error: ', $oException);
+        }
+
+        return $oSession;
+    }
+    
+    protected function _retrievePaymentIntent($sId) {
+        $oPaymentIntent = null;
+        bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_retrieve_payment_intent', 0, false, array(
+            'payment_intent_id' => &$sId,
+            'payment_intent_object' => &$oPaymentIntent
+        ));
+
+        try {
+            if(empty($oPaymentIntent))
+                $oPaymentIntent = \Stripe\PaymentIntent::retrieve($sId);
+        }
+        catch (Exception $oException) {
+            return $this->_processException('Retrieve Payment Intent Error: ', $oException);
+        }
+
+        return $oPaymentIntent;
+    }
+
+    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 = '';
+    	bx_alert($this->_oModule->_oConfig->getName(), $this->_sName . '_get_button', 0, $iClientId, array(
+            '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);
+    }
+}
+
+/** @} */

+ 37 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentStudioPage.php

@@ -0,0 +1,37 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Forum Forum
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentStudioPage extends BxTemplStudioModule
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    function __construct($sModule, $mixedPageName, $sPage = "")
+    {
+    	$this->_sModule = 'bx_payment';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($sModule, $mixedPageName, $sPage);
+
+        $this->aMenuItems['providers'] = array('name' => 'providers', 'icon' => 'money-bill-alt', 'title' => '_bx_payment_lmi_cpt_providers');
+    }
+
+    protected function getProviders()
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oModule->_oConfig->getObject('grid_providers'), BxDolStudioTemplate::getInstance());
+        if(!$oGrid)
+            return '';
+
+        return $oGrid->getCode();
+    }
+}
+
+/** @} */

+ 540 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentSubscriptions.php

@@ -0,0 +1,540 @@
+<?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, $iModuleId, $iItemId, $iItemCount, $sItemAddons = '', $sRedirect = '', $aCustom = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	$iClientId = $this->_oModule->getProfileId();
+
+    	$mixedResult = $this->_oModule->checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount);
+    	if($mixedResult !== true)
+            return $mixedResult;
+
+        $aSellerProviders = $this->_oModule->_oDb->getVendorInfoProvidersRecurring($iSellerId);
+        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' => BxTemplStudioFunctions::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;
+    }
+
+    /**
+     * @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(
+            'sibscription_id' => $aSubscription['subscription_id'],
+            'sibscription_customer' => $aSubscription['customer_id'],
+            'sibscription_date' => bx_time_js($aSubscription['date'], 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']);
+
+        $sInterval = $this->_getInterval((int)$aItem['period_recurring'], $aItem['period_unit_recurring']);
+
+        $oDate = date_create('@' . $aSubscription['date_next']);
+        date_add($oDate, new DateInterval($sInterval));
+
+        $this->_oModule->_oDb->updateSubscription(array_merge(array(
+            'date_next' => date_format($oDate, 'U'),
+            '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 array(
+                'content' => MsgBox(_t('_Empty'))
+            );
+
+    	$iUserId = $this->_oModule->getProfileId();
+        if(empty($iUserId))
+            return array(
+                'content' => MsgBox(_t($CNF['T']['ERR_REQUIRED_LOGIN']))
+            );
+
+        $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 array(
+            'content' => $this->_oModule->_oTemplate->$sMethod($iUserId),
+            '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;
+    }
+}
+
+/** @} */

+ 459 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/classes/BxPaymentTemplate.php

@@ -0,0 +1,459 @@
+<?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.widget.min.js',
+    		'jquery-ui/jquery.ui.menu.min.js', 
+    		'jquery-ui/jquery.ui.autocomplete.min.js', 
+    		'jquery.form.min.js', 
+    		'jquery.anim.js', 
+    		'jquery.webForms.js',
+    		'orders.js'
+    	));
+    	$this->addCss(array('orders.css'));
+    }
+    public function 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 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(serialize($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(serialize($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(serialize($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(serialize($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);
+
+		$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);
+
+        $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 MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$oGrid->addQueryParam('client_id', $iClientId);
+
+		$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 MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+		$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));
+
+        $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']));
+            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']
+	            );
+        }
+
+        return $this->parseHtmlByName('order_' . $sType . '.html', $aResult);
+    }
+
+    public function displayItems($sType, $aItems = array())
+    {
+        $aTmplVarsItems = array();
+
+        if(!empty($aItems) && is_array($aItems))
+            foreach($aItems as $aItem) {
+                $aTmplVarsItems[$aItem['title']] = array(
+                    'id' => $aItem['id'],
+                    'price' => $this->_oConfig->getPrice($sType, $aItem),
+                    'bx_if:link' => array(
+                        'condition' => !empty($aItem['url']),
+                        'content' => array(
+                            'url' => $aItem['url'],
+                            'title' => $aItem['title']
+                        )
+                    ),
+                    'bx_if:text' => array(
+                        'condition' => empty($aItem['url']),
+                        'content' => array(
+                            'title' => $aItem['title']
+                        )
+                    ),
+                );
+            }
+
+        if(!empty($aTmplVarsItems) && is_array($aTmplVarsItems)) {
+            ksort($aTmplVarsItems);
+            $aTmplVarsItems = array_values($aTmplVarsItems);
+        }
+        else 
+        	$aTmplVarsItems = MsgBox(_t($this->_sLangsPrefix . 'msg_no_results'));
+
+        return $this->parseHtmlByName('items.html', array(
+        	'html_id' => $this->_oConfig->getHtmlIds('processed', 'order_processed_items'),
+        	'bx_repeat:items' => $aTmplVarsItems
+        ));
+    }
+
+    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);
+
+            $aTmplVarsProviders[] = array(
+                'button' => $this->parseHtmlByName('providers_select_button.html', array(
+                    'onclick' => $sJsOnclick,
+                    'title' => _t('_bx_payment_txt_checkout_with', _t($aProvider['caption'])),
+                    '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();
+        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/11.0.6_12.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' => '12.0.0',
+    'vendor' => 'Boonex',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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(),
+);
+
+/** @} */

+ 604 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/install/langs/en.xml

@@ -0,0 +1,604 @@
+<?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_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_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>
+
+    <!-- PAGES and BLOCKS -->
+    <string name="_bx_payment_page_title_sys_carts"><![CDATA[Shopping Carts]]></string>
+    <string name="_bx_payment_page_title_carts"><![CDATA[Shopping Carts]]></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 Carts]]></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>
+
+    <!-- MENUS -->
+    <string name="_bx_payment_lmi_cpt_providers"><![CDATA[Providers]]></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_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_set_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart"><![CDATA[Cart]]></string>
+    <string name="_bx_payment_menu_item_title_cart"><![CDATA[Cart]]></string>
+    <string name="_bx_payment_menu_item_title_system_cart_history"><![CDATA[Cart History]]></string>
+    <string name="_bx_payment_menu_item_title_cart_history"><![CDATA[Cart History]]></string>
+
+    <string name="_bx_payment_menu_title_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_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_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>
+
+	<!-- 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_pendings_form"><![CDATA[Pendings Form]]></string>
+	<string name="_bx_payment_form_processed_form"><![CDATA[Processed Form]]></string>
+	<string name="_bx_payment_form_pendings_display_process"><![CDATA[Process Pending Display]]></string>
+	<string name="_bx_payment_form_processed_display_add"><![CDATA[Add Processed Display]]></string>
+	<string name="_bx_payment_form_pendings_input_id_sys"><![CDATA[ID]]></string>
+	<string name="_bx_payment_form_pendings_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+	<string name="_bx_payment_form_pendings_input_order_sys"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_pendings_input_order"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_pendings_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+	<string name="_bx_payment_form_pendings_input_process_sys"><![CDATA[Process]]></string>
+	<string name="_bx_payment_form_pendings_input_process"><![CDATA[Process]]></string>
+	<string name="_bx_payment_form_pendings_input_cancel_sys"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_pendings_input_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_processed_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+	<string name="_bx_payment_form_processed_input_client_id_sys"><![CDATA[Client ID]]></string>
+	<string name="_bx_payment_form_processed_input_client_sys"><![CDATA[Client]]></string>
+	<string name="_bx_payment_form_processed_input_client"><![CDATA[Client]]></string>
+	<string name="_bx_payment_form_processed_input_client_err"><![CDATA[You need to enter a name of an existed member here.]]></string>
+	<string name="_bx_payment_form_processed_input_order_sys"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_processed_input_order"><![CDATA[Order]]></string>
+	<string name="_bx_payment_form_processed_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+	<string name="_bx_payment_form_processed_input_module_id_sys"><![CDATA[Module]]></string>
+	<string name="_bx_payment_form_processed_input_module_id"><![CDATA[Module]]></string>
+	<string name="_bx_payment_form_processed_input_module_id_err"><![CDATA[You need to select a module here.]]></string>
+	<string name="_bx_payment_form_processed_input_items_sys"><![CDATA[Items]]></string>
+	<string name="_bx_payment_form_processed_input_items"><![CDATA[Items]]></string>
+	<string name="_bx_payment_form_processed_input_items_err"><![CDATA[You need to select at least one item from the list here.]]></string>
+	<string name="_bx_payment_form_processed_input_add"><![CDATA[Add]]></string>
+	<string name="_bx_payment_form_processed_input_add_sys"><![CDATA[Add]]></string>
+	<string name="_bx_payment_form_processed_input_cancel"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_processed_input_cancel_sys"><![CDATA[Cancel]]></string>
+
+    <!-- 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: {sibscription_id}<br />Customer: {sibscription_customer}<br />Date: {sibscription_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: {sibscription_id}<br />Customer: {sibscription_customer}<br />Date: {sibscription_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: {sibscription_id}<br />Customer: {sibscription_customer}<br />Date: {sibscription_date}</p>
+<p><b>Note</b>. An associated data will be removed shortly.</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_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_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_order"><![CDATA[Order ID]]></string>
+	<string name="_bx_payment_txt_processed_with"><![CDATA[Processed with]]></string>
+	<string name="_bx_payment_txt_message"><![CDATA[Result]]></string>
+	<string name="_bx_payment_txt_date"><![CDATA[Date]]></string>
+	<string name="_bx_payment_txt_products"><![CDATA[Products]]></string>
+	<string name="_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_unpaid"><![CDATA[Unpaid]]></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>
+
+        <!-- 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_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>
+
+	<!-- 2Checkout payment provider -->
+	<string name="_bx_payment_2co_cpt"><![CDATA[2Checkout]]></string>
+	<string name="_bx_payment_2co_dsc"><![CDATA[2Checkout payment provider]]></string>
+	<string name="_bx_payment_2co_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_2co_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_2co_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_2co_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_2co_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_2co_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_2co_account_id_cpt"><![CDATA[Account number]]></string>
+	<string name="_bx_payment_2co_account_id_dsc"><![CDATA[Your 2Checkout vendor account number]]></string>
+	<string name="_bx_payment_2co_payment_method_cpt"><![CDATA[Payment Method]]></string>
+	<string name="_bx_payment_2co_payment_method_dsc"><![CDATA[This will set the default selection on the payment method step during the checkout process]]></string>
+	<string name="_bx_payment_2co_payment_method_cc"><![CDATA[Credit Card(CC)]]></string>
+	<string name="_bx_payment_2co_payment_method_ppi"><![CDATA[PayPal(PPI)]]></string>
+	<string name="_bx_payment_2co_secret_word_cpt"><![CDATA[Secret Word]]></string>
+	<string name="_bx_payment_2co_secret_word_dsc"><![CDATA[Secret word is used to calculate a check hash]]></string>
+	<string name="_bx_payment_2co_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_2co_err_no_vendor_given"><![CDATA[Unknown vendor]]></string>
+	<string name="_bx_payment_2co_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_2co_err_wrong_key"><![CDATA[Check key is incorrect.]]></string>
+	<string name="_bx_payment_2co_err_wrong_payment"><![CDATA[Wrong payment.]]></string>
+	<string name="_bx_payment_2co_err_already_processed"><![CDATA[This payment has already processed]]></string>
+	<string name="_bx_payment_2co_msg_verified"><![CDATA[Successfully verified.]]></string>
+	<string name="_bx_payment_txt_name_2checkout"><![CDATA[2Checkout]]></string>
+	<string name="_bx_payment_txt_cart_2checkout"><![CDATA[2Checkout]]></string>
+
+	<!-- BitPay payment provider -->
+	<string name="_bx_payment_bp_cpt"><![CDATA[BitPay]]></string>
+	<string name="_bx_payment_bp_dsc"><![CDATA[BitPay payment provider]]></string>
+	<string name="_bx_payment_bp_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_bp_active_dsc"><![CDATA[Activate(Deactivate) provider]]></string>
+	<string name="_bx_payment_bp_active_err"><![CDATA[You should have SSL certificate (HTTPS connection) to activate and use BitPay on your site.]]></string>
+	<string name="_bx_payment_bp_api_key_cpt"><![CDATA[API Key]]></string>
+	<string name="_bx_payment_bp_api_key_dsc"><![CDATA[Your merchant BitPay API Access key]]></string>
+	<string name="_bx_payment_bp_transaction_speed_cpt"><![CDATA[Transaction speed]]></string>
+	<string name="_bx_payment_bp_transaction_speed_dsc"><![CDATA[Determines when an invoice is confirmed]]></string>
+	<string name="_bx_payment_bp_transaction_speed_high"><![CDATA[High]]></string>
+	<string name="_bx_payment_bp_transaction_speed_medium"><![CDATA[Medium]]></string>
+	<string name="_bx_payment_bp_transaction_speed_low"><![CDATA[Low]]></string>
+	<string name="_bx_payment_bp_full_notifications_cpt"><![CDATA[Enable full notifications]]></string>
+	<string name="_bx_payment_bp_full_notifications_dsc"><![CDATA[When enabled notifications will be sent on every status change, otherwise when an invoice is confirmed only.]]></string>
+	<string name="_bx_payment_bp_notification_email_cpt"><![CDATA[Notification Email]]></string>
+	<string name="_bx_payment_bp_notification_email_dsc"><![CDATA[Email where invoice update notifications will be sent. Leave empty to disable.]]></string>
+	<string name="_bx_payment_bp_err_posdata_exceed_limit"><![CDATA[The value of posData exceeds limit. Contact with administrator.]]></string>
+	<string name="_bx_payment_bp_err_no_data_given"><![CDATA[No data given.]]></string>
+	<string name="_bx_payment_bp_err_no_vendor_given"><![CDATA[Unknown vendor.]]></string>
+	<string name="_bx_payment_bp_err_incorrect_data"><![CDATA[Incorrect order data.]]></string>
+	<string name="_bx_payment_bp_err_wrong_amount"><![CDATA[Wrong payment amount.]]></string>
+	<string name="_bx_payment_bp_err_already_processed"><![CDATA[This payment has already processed.]]></string>
+	<string name="_bx_payment_bp_err_no_confirmation_given"><![CDATA[Payment is waiting for full confirmation from the Bitcoin network.]]></string>
+	<string name="_bx_payment_bp_msg_checkout_finished"><![CDATA[A payment has been confirmed. Once the transaction is fully confirmed on the Bitcoin network, the payment will be processed automatically here. Then the purchased product(s) will be displayed in shopping cart history.<br /><b>Note.</b> If it doesn't happen for some reason, you need to contact with product\'s vendor and provide him with your payment's details. He'll be able to process payment manually if the payment was received.]]></string>
+	<string name="_bx_payment_txt_name_bitpay"><![CDATA[BitPay]]></string>
+	<string name="_bx_payment_txt_cart_bitpay"><![CDATA[BitPay]]></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_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>
+
+	<!-- Recurly payment provider -->
+	<string name="_bx_payment_rcrl_cpt"><![CDATA[Recurly]]></string>
+	<string name="_bx_payment_rcrl_dsc"><![CDATA[Recurly payment provider]]></string>
+	<string name="_bx_payment_rcrl_active_cpt"><![CDATA[Active]]></string>
+	<string name="_bx_payment_rcrl_active_dsc"><![CDATA[Activate(Deactivate) provider.]]></string>
+	<string name="_bx_payment_rcrl_active_err"><![CDATA[You should have SSL certificate (HTTPS connection) to activate and use Recurly on your site.]]></string>
+        <string name="_bx_payment_rcrl_hidden_cpt"><![CDATA[Hidden]]></string>
+	<string name="_bx_payment_rcrl_hidden_dsc"><![CDATA[Hide provider if you don't want to accept new payments but already have active subscriptions.]]></string>
+	<string name="_bx_payment_rcrl_mode_cpt"><![CDATA[Mode]]></string>
+	<string name="_bx_payment_rcrl_mode_dsc"><![CDATA[Mode to process payments]]></string>
+	<string name="_bx_payment_rcrl_mode_live"><![CDATA[live]]></string>
+	<string name="_bx_payment_rcrl_mode_test"><![CDATA[test]]></string>
+	<string name="_bx_payment_rcrl_site_cpt"><![CDATA[Site]]></string>
+	<string name="_bx_payment_rcrl_site_dsc"><![CDATA[Your site name registered in Recurly]]></string>
+	<string name="_bx_payment_rcrl_api_key_private_cpt"><![CDATA[Private API Key]]></string>
+	<string name="_bx_payment_rcrl_api_key_private_dsc"><![CDATA[Your Recurly Private API Access key]]></string>
+	<string name="_bx_payment_rcrl_api_key_public_cpt"><![CDATA[Public API Key]]></string>
+	<string name="_bx_payment_rcrl_api_key_public_dsc"><![CDATA[Your Recurly Public API Access key]]></string>
+	<string name="_bx_payment_rcrl_return_data_url_cpt"><![CDATA[Data return URL]]></string>
+	<string name="_bx_payment_rcrl_notify_url_cpt"><![CDATA[Webhooks URL]]></string>
+	<string name="_bx_payment_rcrl_msg_subscribed"><![CDATA[Thank you! Subscription created. Please, check your email for further instructions.]]></string>
+	<string name="_bx_payment_txt_name_recurly"><![CDATA[Recurly]]></string>
+	<string name="_bx_payment_txt_cart_recurly"><![CDATA[Recurly]]></string>
+
+	<string name="_bx_payment_form_rcrl_card"><![CDATA[Recurly: Card Form]]></string>
+	<string name="_bx_payment_form_rcrl_card_display_add"><![CDATA[Recurly: Add Card Display]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_pending_id_sys"><![CDATA[Pending ID]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_item_sys"><![CDATA[Item]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_token_sys"><![CDATA[Token]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_first_name_sys"><![CDATA[First Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_first_name"><![CDATA[First Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_first_name_err"><![CDATA[You need to fill in your first name here.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_last_name_sys"><![CDATA[Last Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_last_name"><![CDATA[Last Name]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_last_name_err"><![CDATA[You need to fill in your last name here.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_email_sys"><![CDATA[Email]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_email"><![CDATA[Email]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_email_err"><![CDATA[You need to fill in your email here.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_number_sys"><![CDATA[Card Number]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_number"><![CDATA[Card Number]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_number_inf"><![CDATA[16 digits without spaces describing your card number]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_sys"><![CDATA[Expiry Date]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire"><![CDATA[Expiry Date]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_month"><![CDATA[Month]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_year"><![CDATA[Year]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_expire_inf"><![CDATA[Use 'mm yyyy' format]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_cvv_sys"><![CDATA[CVV]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_cvv"><![CDATA[CVV]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_card_cvv_inf"><![CDATA[Three digits from the back side of your card.]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_submit_sys"><![CDATA[Submit]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_cancel_sys"><![CDATA[Cancel]]></string>
+	<string name="_bx_payment_form_rcrl_card_input_cancel"><![CDATA[Cancel]]></string>
+	
+	<string name="_bx_payment_popup_title_rcrl_card_add"><![CDATA[Card details]]></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_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>
+
+    <!-- _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>

+ 43 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/disable.sql

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

+ 171 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/enable.sql

@@ -0,0 +1,171 @@
+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, @sName, '_bx_payment', 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_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";}', 0),
+('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);
+
+
+-- 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');
+
+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);
+
+
+-- MENU: cart 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_cart_submenu', '_bx_payment_menu_title_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);
+
+
+-- 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
+('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');
+
+
+-- CRON
+INSERT INTO `sys_cron_jobs` (`name`, `time`, `class`, `file`, `service_call`) VALUES
+('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');

+ 538 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/install.sql

@@ -0,0 +1,538 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+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` (
+  `user_id` int(11) NOT NULL default '0',
+  `option_id` int(11) NOT NULL default '0',  
+  `value` varchar(255) NOT NULL default '',
+  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',
+  `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',
+  `order` varchar(32) NOT NULL default '',
+  `error_code` varchar(16) NOT NULL default '',
+  `error_msg` varchar(255) NOT NULL default '',
+  `date` int(11) 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`)
+);
+
+
+-- 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, 0, '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', '', '', '', '', 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', '', '', '', '', 6),
+(@iProviderId, 'pp_return_data_url', 'value', '_bx_payment_pp_return_data_url_cpt', '', '', '', '', '', 7);
+
+
+-- 2Checkout payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('2checkout', '_bx_payment_2co_cpt', '_bx_payment_2co_dsc', '2co_', 1, 1, 0, 0, 20, 'BxPaymentProvider2Checkout');
+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, '2co_active', 'checkbox', '_bx_payment_2co_active_cpt', '_bx_payment_2co_active_dsc', '', '', '', '', 1),
+(@iProviderId, '2co_mode', 'select', '_bx_payment_2co_mode_cpt', '_bx_payment_2co_mode_dsc', '1|_bx_payment_2co_mode_live,2|_bx_payment_2co_mode_test', '', '', '', 2),
+(@iProviderId, '2co_account_id', 'text', '_bx_payment_2co_account_id_cpt', '_bx_payment_2co_account_id_dsc', '', '', '', '', 3),
+(@iProviderId, '2co_payment_method', 'select', '_bx_payment_2co_payment_method_cpt', '_bx_payment_2co_payment_method_dsc', 'CC|_bx_payment_2co_payment_method_cc,PPI|_bx_payment_2co_payment_method_ppi', '', '', '', 4),
+(@iProviderId, '2co_secret_word', 'text', '_bx_payment_2co_secret_word_cpt', '_bx_payment_2co_secret_word_dsc', '', '', '', '', 5),
+(@iProviderId, '2co_return_data_url', 'value', '_bx_payment_2co_return_data_url_cpt', '', '', '', '', '', 6);
+
+
+-- BitPay payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('bitpay', '_bx_payment_bp_cpt', '_bx_payment_bp_dsc', 'bp_', 0, 1, 0, 0, 30, 'BxPaymentProviderBitPay');
+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, 'bp_active', 'checkbox', '_bx_payment_bp_active_cpt', '_bx_payment_bp_active_dsc', '', 'https', '', '_bx_payment_bp_active_err', 1),
+(@iProviderId, 'bp_api_key', 'text', '_bx_payment_bp_api_key_cpt', '_bx_payment_bp_api_key_dsc', '', '', '', '', 2),
+(@iProviderId, 'bp_transaction_speed', 'select', '_bx_payment_bp_transaction_speed_cpt', '_bx_payment_bp_transaction_speed_dsc', 'high|_bx_payment_bp_transaction_speed_high,medium|_bx_payment_bp_transaction_speed_medium,low|_bx_payment_bp_transaction_speed_low', '', '', '', 3),
+(@iProviderId, 'bp_full_notifications', 'checkbox', '_bx_payment_bp_full_notifications_cpt', '_bx_payment_bp_full_notifications_dsc', '', '', '', '', 4),
+(@iProviderId, 'bp_notification_email', 'text', '_bx_payment_bp_notification_email_cpt', '_bx_payment_bp_notification_email_dsc', '', '', '', '', 5);
+
+
+-- 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', '', '_sys_form_account_input_email_error', 10),
+(@iProviderId, 'cbee_expiration_email', 'text', '_bx_payment_cbee_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_sys_form_account_input_email_error', 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, 0, 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', '', '_sys_form_account_input_email_error', 10),
+(@iProviderId, 'cbee_v3_expiration_email', 'text', '_bx_payment_cbee_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_sys_form_account_input_email_error', 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);
+
+-- Recurly payment provider
+INSERT INTO `bx_payment_providers`(`name`, `caption`, `description`, `option_prefix`, `for_visitor`, `for_single`, `for_recurring`, `active`, `order`, `class_name`) VALUES
+('recurly', '_bx_payment_rcrl_cpt', '_bx_payment_rcrl_dsc', 'rcrl_', 1, 0, 1, 0, 50, 'BxPaymentProviderRecurly');
+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, 'rcrl_active', 'checkbox', '_bx_payment_rcrl_active_cpt', '_bx_payment_rcrl_active_dsc', '', 'https', '', '_bx_payment_rcrl_active_err', 1),
+(@iProviderId, 'rcrl_hidden', 'checkbox', '_bx_payment_rcrl_hidden_cpt', '_bx_payment_rcrl_hidden_dsc', '', '', '', '', 2),
+(@iProviderId, 'rcrl_mode', 'select', '_bx_payment_rcrl_mode_cpt', '_bx_payment_rcrl_mode_dsc', '1|_bx_payment_rcrl_mode_live,2|_bx_payment_rcrl_mode_test', '', '', '', 3),
+(@iProviderId, 'rcrl_site', 'text', '_bx_payment_rcrl_site_cpt', '_bx_payment_rcrl_site_dsc', '', '', '', '', 4),
+(@iProviderId, 'rcrl_api_key_private', 'text', '_bx_payment_rcrl_api_key_private_cpt', '_bx_payment_rcrl_api_key_private_dsc', '', '', '', '', 5),
+(@iProviderId, 'rcrl_api_key_public', 'text', '_bx_payment_rcrl_api_key_public_cpt', '_bx_payment_rcrl_api_key_public_dsc', '', '', '', '', 6),
+(@iProviderId, 'rcrl_return_data_url', 'value', '_bx_payment_rcrl_return_data_url_cpt', '', '', '', '', '', 7),
+(@iProviderId, 'rcrl_notify_url', 'value', '_bx_payment_rcrl_notify_url_cpt', '', '', '', '', '', 8);
+
+-- 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', '', '_sys_form_account_input_email_error', 10),
+(@iProviderId, 'strp_expiration_email', 'text', '_bx_payment_strp_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_sys_form_account_input_email_error', 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', '', '_sys_form_account_input_email_error', 10),
+(@iProviderId, 'strp_v3_expiration_email', 'text', '_bx_payment_strp_expiration_email_cpt', '', '', 'EmailOrEmpty', '', '_sys_form_account_input_email_error', 11),
+(@iProviderId, 'strp_v3_notify_url', 'value', '_bx_payment_strp_notify_url_cpt', '', '', '', '', '', 12);
+
+-- 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`, `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, 'BxPaymentGridProviders', 'modules/boonex/payment/classes/BxPaymentGridProviders.php'),
+
+('bx_payment_grid_carts', 'Array', '', '', 'vendor_id', '', '', '', 20, NULL, 'start', '', '', '', 'like', '', '', 2147483647, 'BxPaymentGridCarts', 'modules/boonex/payment/classes/BxPaymentGridCarts.php'),
+('bx_payment_grid_cart', 'Array', '', '', 'descriptor', '', '', '', 20, NULL, 'start', '', 'title,description', '', 'like', '', '', 2147483647, '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, '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', '', 'auto', '', '', 192, '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`.`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, '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`.`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, '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`.`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 ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, '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`.`order` AS `transaction`, `tt`.`error_msg` AS `error_msg`, `tt`.`provider` AS `provider`, `tt`.`date` AS `date` FROM `bx_payment_transactions_pending` AS `tt` 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', '', 'auto', '', '', 2147483647, 'BxPaymentGridPending', 'modules/boonex/payment/classes/BxPaymentGridPending.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);
+
+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_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);
+
+
+-- 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_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'),
+-- 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_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),
+-- 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),
+
+-- 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),
+
+-- 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', '&#128;'),
+('bx_payment_currencies', 'GBP', 4, 'GBP', '&#163;'),
+('bx_payment_currencies', 'USD', 5, 'USD', '&#36;'),
+('bx_payment_currencies', 'YEN', 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));

+ 37 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/install/sql/uninstall.sql

@@ -0,0 +1,37 @@
+SET @sName = 'bx_payment';
+
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_payment_providers`;
+DROP TABLE IF EXISTS `bx_payment_providers_options`;
+DROP TABLE IF EXISTS `bx_payment_user_values`;
+DROP TABLE IF EXISTS `bx_payment_cart`;
+DROP TABLE IF EXISTS `bx_payment_transactions`;
+DROP TABLE IF EXISTS `bx_payment_subscriptions`;
+DROP TABLE IF EXISTS `bx_payment_subscriptions_deleted`;
+DROP TABLE IF EXISTS `bx_payment_transactions_pending`;
+DROP TABLE IF EXISTS `bx_payment_modules`;
+
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` LIKE 'bx_payment_grid%';
+DELETE FROM `sys_grid_fields` WHERE `object` LIKE 'bx_payment_grid%';
+DELETE FROM `sys_grid_actions` WHERE `object` LIKE 'bx_payment_grid%';
+
+
+-- FORMS
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN (SELECT `display_name` FROM `sys_form_displays` WHERE `module`=@sName);
+DELETE FROM `sys_form_inputs` WHERE `module`=@sName;
+DELETE FROM `sys_form_displays` WHERE `module`=@sName;
+DELETE FROM `sys_objects_form` WHERE `module`=@sName;
+
+
+-- PRE-VALUES
+DELETE FROM `sys_form_pre_lists` WHERE `module` = 'bx_payment';
+DELETE FROM `sys_form_pre_values` WHERE `Key` IN ('bx_payment_currencies');
+
+
+-- 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` = @sName;

+ 144 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/js/orders.js

@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxPaymentOrders(oOptions) {
+	this.init(oOptions);
+}
+
+BxPaymentOrders.prototype.init = function(oOptions) {
+    if($.isEmptyObject(oOptions))
+        return;
+
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjNameGrid = oOptions.sObjNameGrid == undefined ? '' : oOptions.sObjNameGrid;
+    this._sObjName = oOptions.sObjName == undefined ? 'oPaymentOrders' : oOptions.sObjName;
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._iTimeout = (oOptions.iTimeout == undefined ? 5 : oOptions.iTimeout) * 1000;
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._sParamsDivider = oOptions.sParamsDivider == undefined ? '#-#' : oOptions.sParamsDivider;
+    this._sTextSearchInput = oOptions.sTextSearchInput == undefined ? '' : oOptions.sTextSearchInput;
+
+    this._iSearchTimeoutId = false;
+
+    var $this = this;
+    $(document).ready(function() {
+        $('#bx-grid-search-' + $this._sObjNameGrid).unbind('focusout');
+    });
+};
+
+/*--- Grid Filter function ---*/
+BxPaymentOrders.prototype.onChangeFilter = function(oElement) {
+    if(!this._sObjNameGrid)
+        return;
+
+    var $this = this;
+
+    var oClient = $('#bx-grid-client-' + this._sObjNameGrid);
+    var bClient = oClient.length > 0;
+    var sClient = bClient ? oClient.val() : '';
+
+    var oAuthor = $('#bx-grid-author-' + this._sObjNameGrid);
+    var bAuthor = oAuthor.length > 0;
+    var sAuthor = bAuthor ? oAuthor.val() : '';
+    
+    var oModule = $('#bx-grid-module-' + this._sObjNameGrid);
+    var bModule = oModule.length > 0;
+    var sModule = bModule ? oModule.val() : '';
+
+    var oItem = $('#bx-grid-item-' + this._sObjNameGrid);
+    var bItem = oItem.length > 0;
+    var sItem = bItem ? oItem.val() : '';
+
+    var sSearch = $('#bx-grid-search-' + this._sObjNameGrid).val();
+    if(sSearch == this._sTextSearchInput)
+        sSearch = '';
+
+    clearTimeout($this._iSearchTimeoutId);
+    $this._iSearchTimeoutId = setTimeout(function () {
+        var sValue = '';
+        if(bClient)
+            sValue += sClient + $this._sParamsDivider;
+        if(bAuthor)
+            sValue += sAuthor + $this._sParamsDivider;
+        if(bModule)
+            sValue += sModule + $this._sParamsDivider;
+        if(bItem)
+            sValue += sItem + $this._sParamsDivider;
+        sValue += sSearch;
+
+    	glGrids[$this._sObjNameGrid].setFilter(sValue, true);
+    }, 500);
+};
+
+BxPaymentOrders.prototype.onChangeFilterModule = function(oElement, iSeller) {
+    var $this = this;
+    var oDate = new Date();
+
+    var iModule = parseInt($(oElement).val());
+    if(!iModule)
+        iModule = 0;
+
+    $.get(
+        this._sActionsUrl + 'get_filter_values_item/' + iSeller + '/' + iModule + '/',
+        {
+            _t:oDate.getTime()
+        },
+        function(oData) {
+            var oFilterItem = $('#bx-grid-item-' + $this._sObjNameGrid);
+
+            if(oData && oData.code != undefined)
+                switch(oData.code) {
+                    case 0:
+                        oFilterItem.html(oData.content).removeAttr('disabled');
+                        break;
+
+                    case 1:
+                        oFilterItem.html(oData.content).attr('disabled', 'disabled');
+                        break;
+                }
+
+            $this.onChangeFilter(oElement);
+        },
+        'json'
+    );
+};
+
+/*--- Manual Order function ---*/
+BxPaymentOrders.prototype.showPopup = function(oUi) {
+	$('#' + this._aHtmlIds['order_processed_client_id']).val(oUi.item.value);	
+};
+
+BxPaymentOrders.prototype.selectModule = function(oSelect) {
+    var oDate = new Date();
+
+    var oPopup = $('#' + this._aHtmlIds['order_processed_add']);
+    oPopup.bx_loading(true);
+
+    $.get(
+        this._sActionsUrl + 'get_items/single/' + parseInt($(oSelect).val()) + '/',
+        {
+            _t:oDate.getTime()
+        },
+        function(oData) {
+        	oPopup.bx_loading(false);
+
+        	processJsonData(oData);
+        },
+        'json'
+    );
+};
+
+BxPaymentOrders.prototype.onSelectModule = function(oData) {
+	if(oData.data != undefined)
+		$('#' + this._aHtmlIds['order_processed_items']).replaceWith(oData.data);
+};
+
+/** @} */

+ 100 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/js/stripe_v3.js

@@ -0,0 +1,100 @@
+/**
+ * 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 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._sRedirect  = oOptions.sRedirect;
+    this._sCustom  = oOptions.sCustom;
+
+    var $this = this;
+    if(window.Stripe === undefined) {
+        $.getScript('https://js.stripe.com/v3/', function() {
+            $this._rHandler = Stripe(oOptions.sPublicKey);
+        });
+    }
+    else
+        this._rHandler = Stripe(oOptions.sPublicKey);
+};
+
+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) {
+    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,
+        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);
+    });
+};
+
+/** @} */

+ 93 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/css/orders.css

@@ -0,0 +1,93 @@
+iframe.hidden {
+    width: 0px;
+    height: 0px;
+    display: none;
+}
+
+/*--- 'Manual Order' and 'More' windows ---*/
+.ui-autocomplete.ui-front {
+	z-index: 1001;
+}
+div.bx-payment-pa-items {
+	max-height: 300px;
+	overflow-x: hidden;
+	overflow-y: auto;
+}
+div.bx-payment-pa-item {
+	width: 100%;
+	white-space: nowrap;
+}
+div.bx-payment-pa-item-chb,
+div.bx-payment-pa-item-title,
+div.bx-payment-pa-item-quantity {
+    position: relative;
+    display: inline-block;
+	vertical-align: middle;
+}
+div.bx-payment-pa-item-chb {
+    width: 4%;
+}
+div.bx-payment-pa-item-chb input {
+    margin: 0px;
+    padding: 0px;
+}
+div.bx-payment-pa-item-title {
+    width: 80%;
+}
+div.bx-payment-pa-item-title-cnt {
+	TEXT-OVERFLOW: ellipsis;
+    -o-text-overflow: ellipsis;
+    white-space: nowrap;
+	overflow: hidden;
+}
+div.bx-payment-pa-item-quantity {
+    width: 16%;
+}
+
+/*--- View Order ---*/
+div.bx-payment-view-order {
+    border-top-width: 0px;
+}
+div.bx-payment-vo-row {
+	white-space: nowrap;
+}
+div.bx-payment-vo-caption,
+div.bx-payment-vo-content,
+div.bx-payment-vo-items {
+    position: relative;
+    display: inline-block;
+	vertical-align: top;
+
+    overflow: hidden;
+}
+div.bx-payment-vo-caption {
+    width: 30%;
+}
+div.bx-payment-vo-content,
+div.bx-payment-vo-items {
+    width: 70%;
+	
+	TEXT-OVERFLOW: ellipsis;
+    -o-text-overflow: ellipsis;
+    white-space: nowrap;
+}
+
+
+/*--- Filters ---*/
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div.bx-form-element-wrapper {
+    position: relative;
+    float: left;
+    width: 165px;
+}
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-client,
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-author,
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-module,
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-item {
+    margin-right: 20px;
+}
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-author,
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-module,
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-item,
+#bx-grid-wrap-bx_payment_grid_orders_processed div.bx-grid-header div#bx-form-element-keyword {
+    margin-top: 0px;
+}

+ 43 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_history.html

@@ -0,0 +1,43 @@
+<div class="bx-payment-view-order-popup">
+    <div class="bx-payment-view-order-popup-cnt">
+        <div class="bx-payment-view-order bx-def-border">
+            <div class="bx-payment-vo-row bx-def-padding-thd-topbottom bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption bx-def-padding-thd-left bx-def-box-sizing">__txt_seller__</div><div class="bx-payment-vo-content">
+                    <bx_if:show_link>
+                        <a href="__seller_url__" target="_blank">__seller_name__</a>
+                    </bx_if:show_link>
+                    <bx_if:show_text>__seller_name__</bx_if:show_text>
+                </div>
+            </div>
+            <bx_if:show_author>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_author__</div><div class="bx-payment-vo-content">
+                        <a href="__author_url__" target="_blank">__author_name__</a>            
+                    </div>
+                </div>
+            </bx_if:show_author>
+            <div class="bx-payment-vo-row bx-def-padding-thd-topbottom bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption bx-def-padding-thd-left bx-def-box-sizing">__txt_order__</div><div class="bx-payment-vo-content">__order__</div>
+            </div>
+            <bx_if:show_license>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_license__</div><div class="bx-payment-vo-content">__license__</div>
+                </div>
+            </bx_if:show_license>
+            <div class="bx-payment-vo-row bx-def-padding-thd-topbottom bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption bx-def-padding-thd-left bx-def-box-sizing">__txt_date__</div><div class="bx-payment-vo-content">__date__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd-topbottom bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption bx-def-padding-thd-left bx-def-box-sizing">__txt_products__</div><div class="bx-payment-vo-items">
+                    <bx_repeat:items>
+                        <bx_if:link>
+                            <a href="__url__" target="_blank">__title__</a>
+                        </bx_if:link>
+                        <bx_if:text>__title__</bx_if:text>
+                        (__quantity__) - __price__ __currency_code__<br />
+                    </bx_repeat:items>
+                </div>
+            </div> 
+        </div>
+    </div>
+</div>

+ 19 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_pending_process.html

@@ -0,0 +1,19 @@
+<div class="bx-payment-pending-process bx-def-color-bg-block">
+    <div class="bx-payment-pending-process-cnt">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+                        glGrids.__object__.processJson(data, '__action__');
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 52 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_processed.html

@@ -0,0 +1,52 @@
+<div class="bx-payment-view-order-popup">
+    <div class="bx-payment-view-order-popup-cnt">
+        <div class="bx-payment-view-order bx-def-border">
+            <bx_if:show_seller>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_seller__</div><div class="bx-payment-vo-content">
+                        <bx_if:show_link><a href="__seller_url__" target="_blank">__seller_name__</a></bx_if:show_link>
+                        <bx_if:show_text>__seller_name__</bx_if:show_text>
+                    </div>
+                </div>
+            </bx_if:show_seller>
+            <bx_if:show_author>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_author__</div><div class="bx-payment-vo-content">
+                        <a href="__author_url__" target="_blank">__author_name__</a>            
+                    </div>
+                </div>
+            </bx_if:show_author>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_client__</div><div class="bx-payment-vo-content">
+                    <a href="__client_url__" target="_blank">__client_name__</a>            
+                </div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_order__</div><div class="bx-payment-vo-content">__order__</div>
+            </div>
+            <bx_if:show_license>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_license__</div><div class="bx-payment-vo-content">__license__</div>
+                </div>
+            </bx_if:show_license>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_processed_with__</div><div class="bx-payment-vo-content">__provider__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_message__</div><div class="bx-payment-vo-content">__error__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_date__</div><div class="bx-payment-vo-content">__date__</div>
+            </div>
+            <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                <div class="bx-payment-vo-caption">__txt_products__</div><div class="bx-payment-vo-items">
+                    <bx_repeat:items>
+                        <bx_if:link><a href="__url__" target="_blank">__title__</a></bx_if:link>
+                        <bx_if:text>__title__</bx_if:text>
+                        (__quantity__) - __price__ __currency_code__<br />
+                    </bx_repeat:items>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 19 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/order_processed_add.html

@@ -0,0 +1,19 @@
+<div class="bx-payment-processed-add">
+    <div class="bx-payment-processed-add-cnt">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+                        glGrids.__object__.processJson(data, '__action__');
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 2 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/providers_select_button.html

@@ -0,0 +1,2 @@
+<a class="bx-btn bx-def-margin-top-auto" href="javascript:void(0)" onclick="javascript:__onclick__">__title__</a>
+__js_code__

+ 52 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/rcrl_card_popup_add.html

@@ -0,0 +1,52 @@
+<div class="bx-payment-rcrl-card-add">
+    <div class="bx-payment-rcrl-card-add-cnt">
+        __form__
+        <script language="javascript">
+	        function bxRecurlyFieldsInit() {
+	    		recurly.configure({
+					publicKey: '__public_key__',
+					style: {
+						all: {
+							fontFamily: '__font_family__',
+							fontSize: '__font_size__',
+							fontColor: '__font_color__',
+						},
+						month: {
+							placeholder: '<bx_text:_bx_payment_form_rcrl_card_input_card_expire_month />'
+						},
+						year: {
+							placeholder: '<bx_text:_bx_payment_form_rcrl_card_input_card_expire_year />'
+						},
+					}
+				});
+	    	}
+
+	        function bxRecurlyFieldsDestroy() {
+	        	/*
+	        	 * TODO: May be it'll be usefull when Recurly fix the issue with Multiple Times Configuration.
+	        	 * http://stackoverflow.com/questions/36430647/is-it-possible-to-build-configure-the-recurly-js-form-multiple-times
+				 */
+	        }
+
+            $(document).ready(function () {
+            	$("#__form_id__").on('submit', function (oEvent) {
+            		oEvent.preventDefault();
+
+            		var oForm = this;
+            		bx_loading(oForm, true);         		
+
+            		recurly.token(oForm, function(oError, oToken) {
+            			if(oError) {
+            				if(oError.message.length > 0)
+            					alert(oError.message);
+
+            				return;
+            			}
+
+            			oForm.submit();
+                    });
+            	});
+            });
+        </script>
+    </div>
+</div>

+ 9 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/redirect.html

@@ -0,0 +1,9 @@
+__content__
+<form name="bx-payment-redirect" action="__action__" method="__method__">
+    <bx_repeat:items>
+        <input type="hidden" name="__name__" value="__value__" />
+    </bx_repeat:items>
+</form>
+<script language="javascript">
+    document.forms['bx-payment-redirect'].submit();
+</script>

+ 16 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_billing_change_recuring.html

@@ -0,0 +1,16 @@
+__form__
+<script language="javascript">
+    $(document).ready(function () {
+        $("#__form_id__").ajaxForm({ 
+            dataType: "json",
+            beforeSubmit: function (formData, jqForm, options) {
+                bx_loading($("#__form_id__"), true);
+            },
+            success: function(oData) {
+                $(".bx-popup-applied:visible").dolPopupHide();
+
+                __object__.processResult(oData);
+            }
+        });
+    });
+</script>

+ 2 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_button_recurring.html

@@ -0,0 +1,2 @@
+<a class="bx-btn bx-def-margin-top-auto" href="javascript:void(0)" onclick="javascript:__onclick__">__caption__</a>
+__js_code__

+ 4 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_button_single.html

@@ -0,0 +1,4 @@
+<div class="bx-payment-strp-button-__type__">
+    <button class="bx-btn bx-def-margin-thd" type="button" onclick="javascript:__onclick__">__caption__</button>
+    __js_code__
+</div>

+ 16 - 0
modules/boonex/payment/updates/11.0.6_12.0.0/source/template/strp_details_change_recuring.html

@@ -0,0 +1,16 @@
+__form__
+<script language="javascript">
+    $(document).ready(function () {
+        $("#__form_id__").ajaxForm({ 
+            dataType: "json",
+            beforeSubmit: function (formData, jqForm, options) {
+                bx_loading($("#__form_id__"), true);
+            },
+            success: function(oData) {
+                $(".bx-popup-applied:visible").dolPopupHide();
+
+                __object__.processResult(oData);
+            }
+        });
+    });
+</script>

+ 51 - 0
modules/boonex/photos/updates/11.0.2_12.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' => '11.0.2',
+    'version_to' => '12.0.0',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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_11.0.2_12.0.0/',
+    'home_uri' => 'photos_update_1102_1200',
+
+    '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' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Photos',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 26 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/install/installer.php

@@ -0,0 +1,26 @@
+<?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);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_photos_cmts', 'cmt_pinned'))
+                $this->oDb->query("ALTER TABLE `bx_photos_cmts` ADD `cmt_pinned` int(11) NOT NULL default '0' AFTER `cmt_replies`");
+
+            if(!$this->oDb->isFieldExists('bx_photos_favorites_track', 'list_id'))
+                $this->oDb->query("ALTER TABLE `bx_photos_favorites_track` ADD `list_id` int(11) NOT NULL default '0' AFTER `author_id`");
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 13 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/install/langs/en.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_photos_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string_add>
+	<string_add name="_bx_photos_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string_add>
+	<string_add name="_bx_photos_page_title_sys_entries_favorites"><![CDATA[Favorives Photos]]></string_add>
+	<string_add name="_bx_photos_page_title_entries_favorites"><![CDATA[Favorives Photos]]></string_add>
+	<string_add name="_bx_photos_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string_add>
+	<string_add name="_bx_photos_page_block_title_favorites_entries_info"><![CDATA[Info]]></string_add>
+	<string_add name="_bx_photos_page_block_title_sys_my_entries"><![CDATA[User Photos]]></string_add>
+	<string_add name="_bx_photos_grid_action_title_adm_clear_reports"><![CDATA[Clear reports]]></string_add>
+
+	<string_upd name="_bx_photos_page_block_title_my_entries"><![CDATA[{display_name} Photos]]></string_upd>
+</resources>

+ 39 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/install/sql/enable.sql

@@ -0,0 +1,39 @@
+-- SETTINGS
+SET @iCategId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_photos' LIMIT 1);
+
+DELETE FROM `sys_options` WHERE `name`='bx_photos_per_page_for_favorites_lists';
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_photos_per_page_for_favorites_lists', '5', @iCategId, '_bx_photos_option_per_page_for_favorites_lists', 'digit', '', '', '', '', 17);
+
+
+-- PAGES
+UPDATE `sys_pages_blocks` SET `content`='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;}}}' WHERE `object`='bx_photos_author' AND `title`='_bx_photos_page_block_title_favorites_of_author';
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_photos_author' AND `title`='_bx_photos_page_block_title_entries_in_context';
+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_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);
+
+DELETE FROM `sys_objects_page` WHERE `object`='bx_photos_favorites';
+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');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_photos_favorites';
+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_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);
+
+UPDATE `sys_pages_blocks` SET `title_system`='_bx_photos_page_block_title_sys_my_entries' WHERE `module`='bx_photos' AND `title`='_bx_photos_page_block_title_my_entries';
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object`='bx_photos_allow_view_favorite_list';
+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_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');
+
+
+-- GRIDS
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_photos_administration' AND `type` IN ('bulk', 'single') AND `name`='clear_reports';
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_photos_administration', 'bulk', 'clear_reports', '_bx_photos_grid_action_title_adm_clear_reports', '', 0, 1, 2),
+('bx_photos_administration', 'single', 'clear_reports', '_bx_photos_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5);

+ 26 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/install/sql/install.sql

@@ -0,0 +1,26 @@
+-- TABLES
+CREATE TABLE IF NOT EXISTS `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`)
+);
+
+
+-- REPORTS
+UPDATE `sys_objects_report` SET `module`='bx_photos' WHERE `name`='bx_photos';
+
+
+-- FAVORITES
+UPDATE `sys_objects_favorite` SET `table_lists`='bx_photos_favorites_lists' WHERE `name`='bx_photos';
+
+
+-- FEATURED
+UPDATE `sys_objects_feature` SET `module`='bx_photos' WHERE `name`='bx_photos';
+
+
+-- STUDIO PAGE & WIDGET
+SET @iPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name`='bx_photos' LIMIT 1);
+UPDATE `sys_std_widgets` SET `type`='content' WHERE `page_id`=@iPageId;

+ 194 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/classes/BxPhotosConfig.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
+ *
+ * @{
+ */
+
+class BxPhotosConfig extends BxBaseModTextConfig
+{
+    protected $_aHtmlIds;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            '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_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_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_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_simple', 'sys_html5'),
+            
+            'FUNCTION_FOR_GET_ITEM_INFO' => 'getContentInfoById',
+
+            // 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,
+            ),
+
+            // 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_select_one_filter1' => '_bx_photos_grid_filter_item_title_adm_select_one_filter1',
+            	'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] : '';
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/classes/BxPhotosPageListEntry.php

@@ -0,0 +1,24 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * List entry page
+ */
+class BxPhotosPageListEntry extends BxBaseModTextPageListEntry
+{    
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_photos';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 136 - 0
modules/boonex/photos/updates/11.0.2_12.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' => '12.0.0',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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'
+    ),
+
+);
+
+/** @} */

+ 256 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/install/langs/en.xml

@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+    <string name="_bx_photos"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_cmts"><![CDATA[Photos' Comments]]></string>
+    <string name="_bx_photos_reactions"><![CDATA[Photos' Reactions]]></string>
+
+    <string name="_bx_photos_option_summary_chars"><![CDATA[Number of characters in auto-cropped photo summary]]></string>
+    <string name="_bx_photos_option_plain_summary_chars"><![CDATA[Number of characters in plain photo description when photo hasn't thumb]]></string>
+    <string name="_bx_photos_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+    <string name="_bx_photos_option_per_page_profile"><![CDATA[Number of items on profile/group page]]></string>
+    <string name="_bx_photos_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+    <string name="_bx_photos_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+    <string name="_bx_photos_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+
+    <string name="_bx_photos_form_entry"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_form_entry_display_add"><![CDATA[Add Photo]]></string>
+    <string name="_bx_photos_form_entry_display_edit"><![CDATA[Edit Photo]]></string>
+    <string name="_bx_photos_form_entry_display_delete"><![CDATA[Delete Photo]]></string>
+    <string name="_bx_photos_form_entry_display_view"><![CDATA[View Photo]]></string>
+    <string name="_bx_photos_form_entry_input_sys_profile_id"><![CDATA[Author]]></string>
+    <string name="_bx_photos_form_entry_input_author"><![CDATA[Author]]></string>
+    <string name="_bx_photos_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_photos_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_photos_form_entry_input_sys_do_publish"><![CDATA[Publish]]></string>
+    <string name="_bx_photos_form_entry_input_do_publish"><![CDATA[Publish]]></string>
+    <string name="_bx_photos_form_entry_input_sys_title"><![CDATA[Title]]></string>
+    <string name="_bx_photos_form_entry_input_title"><![CDATA[Title]]></string>
+    <string name="_bx_photos_form_entry_input_title_err"><![CDATA[Title is essential. Please, fill in this field]]></string>
+    <string name="_bx_photos_form_entry_input_sys_cat"><![CDATA[Category]]></string>
+    <string name="_bx_photos_form_entry_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_photos_form_entry_input_cat_err"><![CDATA[Please select category]]></string>
+    <string name="_bx_photos_form_entry_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_photos_form_entry_input_text"><![CDATA[Text]]></string>
+    <string name="_bx_photos_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+    <string name="_bx_photos_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this photo]]></string>
+    <string name="_bx_photos_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+    <string name="_bx_photos_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the photo]]></string>
+    <string name="_bx_photos_form_entry_input_sys_pictures"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_form_entry_input_pictures"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_form_entry_input_pictures_err"><![CDATA[Photo is essential. Please, upload some photo(s).]]></string>
+    <string name="_bx_photos_form_entry_input_pictures_upload"><![CDATA[Upload]]></string>
+    <string name="_bx_photos_form_entry_input_sys_picture"><![CDATA[Photo]]></string>
+    <string name="_bx_photos_form_entry_input_picture"><![CDATA[Photo]]></string>
+    <string name="_bx_photos_form_entry_input_picture_err"><![CDATA[Photo is essential. Please, upload a photo.]]></string>
+    <string name="_bx_photos_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_photos_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_photos_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_photos_form_entry_input_picture_use_as_thumb"><![CDATA[Cover Image]]></string>
+    <string name="_bx_photos_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_photos_form_entry_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_photos_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_photos_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+
+    <string name="_bx_photos_form_upload"><![CDATA[Photos Upload]]></string>
+    <string name="_bx_photos_form_upload_display_upload"><![CDATA[Add Photos]]></string>
+
+	<string name="_bx_photos_acl_action_create_entry"><![CDATA[Create Photo]]></string>
+	<string name="_bx_photos_acl_action_delete_entry"><![CDATA[Delete Photo]]></string>
+	<string name="_bx_photos_acl_action_view_entry"><![CDATA[View Photo]]></string>
+	<string name="_bx_photos_acl_action_set_thumb"><![CDATA[Set Photo Thumbnail]]></string>
+	<string name="_bx_photos_acl_action_edit_any_entry"><![CDATA[Edit Any Photo]]></string>
+
+	<string name="_bx_photos_page_title_sys_create_entry"><![CDATA[Upload Photos]]></string>
+	<string name="_bx_photos_page_title_create_entry"><![CDATA[Upload Photos]]></string>
+	<string name="_bx_photos_page_block_title_create_entry"><![CDATA[Upload Photos]]></string>
+	<string name="_bx_photos_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_photos_page_title_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_photos_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_photos_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_photos_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_photos_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+	<string name="_bx_photos_page_title_sys_view_entry"><![CDATA[View Photo]]></string>
+	<string name="_bx_photos_page_title_view_entry"><![CDATA[{title}]]></string>
+	<string name="_bx_photos_page_title_sys_view_entry_brief"><![CDATA[Brief View Photo]]></string>
+    <string name="_bx_photos_page_title_view_entry_brief"><![CDATA[{title}]]></string>
+	<string name="_bx_photos_page_block_title_entry_text"><![CDATA[Text]]></string>
+	<string name="_bx_photos_page_block_title_entry_photo"><![CDATA[Photo]]></string>
+	<string name="_bx_photos_page_title_browse"><![CDATA[Photos]]></string>
+	<string name="_bx_photos_page_title_search_results"><![CDATA[Photos matching "{0}"]]></string>
+	<string name="_bx_photos_page_title_browse_by_author"><![CDATA[Photos of {display_name}]]></string>
+	<string name="_bx_photos_page_title_browse_featured"><![CDATA[Featured Photos]]></string>
+    <string name="_bx_photos_page_title_browse_recent"><![CDATA[Latest Photos]]></string>
+    <string name="_bx_photos_page_title_browse_popular"><![CDATA[Popular Photos]]></string>
+    <string name="_bx_photos_page_title_browse_top"><![CDATA[Top Photos]]></string>
+    <string name="_bx_photos_page_title_browse_updated"><![CDATA[Updated Photos]]></string>
+    <string name="_bx_photos_page_title_sys_home"><![CDATA[Photos Home]]></string>
+    <string name="_bx_photos_page_title_home"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_page_block_title_featured_entries"><![CDATA[Featured Photos]]></string>
+    <string name="_bx_photos_page_block_title_featured_entries_view_extended"><![CDATA[Featured Photos (Extended View)]]></string>
+    <string name="_bx_photos_page_block_title_featured_entries_view_full"><![CDATA[Featured Photos (Full View)]]></string>
+    <string name="_bx_photos_page_block_title_recent_entries"><![CDATA[Latest Photos]]></string>
+    <string name="_bx_photos_page_block_title_recent_entries_view_extended"><![CDATA[Latest Photos (Extended View)]]></string>
+    <string name="_bx_photos_page_block_title_recent_entries_view_full"><![CDATA[Latest Photos (Full View)]]></string>
+    <string name="_bx_photos_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_photos_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_photos_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_photos_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_photos_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_photos_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_photos_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_photos_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_photos_page_block_title_entry_rating"><![CDATA[Rating]]></string>
+    <string name="_bx_photos_page_title_sys_entries_popular"><![CDATA[Popular Photos]]></string>
+    <string name="_bx_photos_page_title_entries_popular"><![CDATA[Popular Photos]]></string>
+    <string name="_bx_photos_page_title_sys_entries_top"><![CDATA[Top Photos]]></string>
+    <string name="_bx_photos_page_title_entries_top"><![CDATA[Top Photos]]></string>
+    <string name="_bx_photos_page_title_sys_entries_updated"><![CDATA[Updated Photos]]></string>
+    <string name="_bx_photos_page_title_entries_updated"><![CDATA[Updated Photos]]></string>
+    <string name="_bx_photos_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_photos_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_photos_page_title_sys_entries_favorites"><![CDATA[Favorives Photos]]></string>
+    <string name="_bx_photos_page_title_entries_favorites"><![CDATA[Favorives Photos]]></string>
+    <string name="_bx_photos_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_photos_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_photos_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_photos_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_photos_page_block_title_popular_entries"><![CDATA[Popular Photos]]></string>
+    <string name="_bx_photos_page_block_title_popular_entries_view_extended"><![CDATA[Popular Photos (Extended View)]]></string>
+    <string name="_bx_photos_page_block_title_popular_entries_view_full"><![CDATA[Popular Photos (Full View)]]></string>
+    <string name="_bx_photos_page_block_title_top_entries"><![CDATA[Top Photos]]></string>
+    <string name="_bx_photos_page_block_title_updated_entries"><![CDATA[Updated Photos]]></string>
+    <string name="_bx_photos_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_photos_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_photos_page_title_sys_view_entry_comments"><![CDATA[Photo Comments]]></string>
+    <string name="_bx_photos_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_photos_page_title_sys_entries_of_author"><![CDATA[Photos of author]]></string>
+    <string name="_bx_photos_page_title_entries_of_author"><![CDATA[Photos by {display_name}]]></string>
+    <string name="_bx_photos_page_title_sys_entries_in_context"><![CDATA[Photos in context]]></string>
+    <string name="_bx_photos_page_title_entries_in_context"><![CDATA[Photos in {display_name}]]></string>
+    <string name="_bx_photos_page_block_title_favorites_of_author"><![CDATA[Favorites by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_photos_page_block_title_sys_favorites_of_author"><![CDATA[Favorites of author]]></string>
+    <string name="_bx_photos_page_block_title_entries_of_author"><![CDATA[Photos by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_photos_page_block_title_sys_entries_of_author"><![CDATA[Photos of author]]></string>
+    <string name="_bx_photos_page_block_title_entries_in_context"><![CDATA[Photos in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_photos_page_block_title_sys_entries_in_context"><![CDATA[Photos in context]]></string>
+    <string name="_bx_photos_page_block_title_entries_actions"><![CDATA[Photos actions]]></string>
+    <string name="_bx_photos_page_block_title_browse_cmts"><![CDATA[Photos' Comments]]></string>
+    <string name="_bx_photos_page_title_sys_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_photos_page_title_sys_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_photos_page_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_photos_page_block_title_system_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_photos_page_block_title_system_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_photos_page_block_title_manage"><![CDATA[Manage]]></string>    
+    <string name="_bx_photos_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+    <string name="_bx_photos_page_block_title_cats"><![CDATA[Photos Categories]]></string>
+    <string name="_bx_photos_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_photos_page_block_title_entry_media_exif"><![CDATA[EXIF]]></string>
+    <string name="_bx_photos_page_block_title_sys_my_entries"><![CDATA[User Photos]]></string>
+    <string name="_bx_photos_page_block_title_my_entries"><![CDATA[{display_name} Photos]]></string>
+    <string name="_bx_photos_page_block_title_sys_recent_entries_view_showcase"><![CDATA[Latest Photos (Showcase View)]]></string>
+    <string name="_bx_photos_page_block_title_recent_entries_view_showcase"><![CDATA[Latest Photos]]></string>
+    <string name="_bx_photos_page_block_title_sys_popular_entries_view_showcase"><![CDATA[Popular Photos (Showcase View)]]></string>
+    <string name="_bx_photos_page_block_title_popular_entries_view_showcase"><![CDATA[Popular Photos]]></string>
+    <string name="_bx_photos_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Photos (Showcase View)]]></string>
+    <string name="_bx_photos_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Photos]]></string>
+    <string name="_bx_photos_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_photos_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+
+  <string name="_bx_photos_menu_set_title_view_entry"><![CDATA[Photo Actions]]></string>
+    <string name="_bx_photos_menu_title_view_entry"><![CDATA[Photo Actions]]></string>
+    <string name="_bx_photos_menu_title_submenu"><![CDATA[Photos Submenu]]></string>
+    <string name="_bx_photos_menu_set_title_submenu"><![CDATA[Photos Submenu]]></string>
+    <string name="_bx_photos_menu_item_title_system_create_entry"><![CDATA[Photo]]></string>
+    <string name="_bx_photos_menu_item_title_create_entry"><![CDATA[Photo]]></string>
+    <string name="_bx_photos_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_photos_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_photos_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_photos_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_photos_menu_item_title_system_view_entry"><![CDATA[View Photo]]></string>
+    <string name="_bx_photos_menu_item_title_system_entries_home"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_menu_item_title_entries_home"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_menu_item_title_system_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_photos_menu_item_title_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_photos_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_photos_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_photos_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_photos_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_photos_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_photos_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_photos_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_photos_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_photos_menu_title_view_entry_submenu"><![CDATA[View Photo Submenu]]></string>
+    <string name="_bx_photos_menu_set_title_view_entry_submenu"><![CDATA[View Photo Submenu]]></string>
+    <string name="_bx_photos_menu_item_title_view_entry_submenu_entry"><![CDATA[Photo]]></string>
+    <string name="_bx_photos_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_photos_menu_item_title_system_view_entry_comments"><![CDATA[Photo Comments]]></string>
+    <string name="_bx_photos_menu_item_title_system_view_entries_author"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_menu_item_title_view_entries_author"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_menu_item_title_system_view_entries_in_context"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_menu_item_title_view_entries_in_context"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_menu_title_entries_my"><![CDATA[My Photos Action Menu]]></string>
+    <string name="_bx_photos_menu_set_title_entries_my"><![CDATA[My Photos Menu]]></string>
+	<string name="_bx_photos_menu_item_title_system_manage_my_photos"><![CDATA[My photos]]></string>
+    <string name="_bx_photos_menu_item_title_manage_my_photos"><![CDATA[Photos]]></string>
+    <string name="_bx_photos_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_photos_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_photos_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_photos_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+	<string name="_bx_photos_menu_item_title_system_admt_photos"><![CDATA[Photos]]></string>
+	<string name="_bx_photos_menu_item_title_admt_photos"><![CDATA[Photos]]></string>
+	<string name="_bx_photos_menu_item_title_manage_my"><![CDATA[My Photos]]></string>
+	<string name="_bx_photos_menu_item_title_manage_all"><![CDATA[All Photos]]></string>
+
+	<string name="_bx_photos_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+	<string name="_bx_photos_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+	<string name="_bx_photos_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+	<string name="_bx_photos_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_photos_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_photos_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_photos_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_photos_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_photos_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_photos_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_photos_grid_action_title_adm_audit_content"><![CDATA[Audit actions]]></string>
+    <string name="_bx_photos_grid_action_title_adm_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_photos_grid_action_err_delete"><![CDATA[Cannot delete the selected photo(s).]]></string>
+    <string name="_bx_photos_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_photos_chart_growth"><![CDATA[Photos: Growth]]></string>
+    <string name="_bx_photos_chart_growth_speed"><![CDATA[Photos: Growth Speed]]></string>
+
+    <string name="_bx_photos_search_extended"><![CDATA[Photos Search]]></string>
+    <string name="_bx_photos_search_extended_cmts"><![CDATA[Photos Comments Search]]></string>
+
+    <string name="_bx_photos_pre_lists_cats"><![CDATA[Photo categories]]></string>
+    <string name="_bx_photos_cat_animals_and_pets"><![CDATA[Animals & Pets]]></string>
+    <string name="_bx_photos_cat_education"><![CDATA[Education]]></string>
+    <string name="_bx_photos_cat_entertainment"><![CDATA[Entertainment]]></string>
+    <string name="_bx_photos_cat_film_and_animation"><![CDATA[Film & Animation]]></string>
+    <string name="_bx_photos_cat_music"><![CDATA[Music]]></string>
+    <string name="_bx_photos_cat_news"><![CDATA[News]]></string>
+    <string name="_bx_photos_cat_people_and_blogs"><![CDATA[People & Blogs]]></string>
+    <string name="_bx_photos_cat_sports"><![CDATA[Sports]]></string>
+    <string name="_bx_photos_cat_travel"><![CDATA[Travel]]></string>
+
+    <string name="_bx_photos_txt_all_entries_by"><![CDATA[{0} photos]]></string>
+    <string name="_bx_photos_txt_all_entries_in"><![CDATA[<a href="{0}">All Photos in {1} ({2})</a>]]></string>
+    <string name="_bx_photos_txt_sample_single"><![CDATA[photo]]></string>
+    <string name="_bx_photos_txt_sample_single_with_article"><![CDATA[a photo]]></string>
+    <string name="_bx_photos_txt_sample_comment_single"><![CDATA[comment to photo]]></string>
+    <string name="_bx_photos_txt_sample_vote_single"><![CDATA[vote to photo]]></string>
+    <string name="_bx_photos_txt_sample_reaction_single"><![CDATA['{0}' reaction to photo]]></string>
+    <string name="_bx_photos_txt_sample_score_up_single"><![CDATA[score up vote to photo]]></string>
+    <string name="_bx_photos_txt_sample_score_down_single"><![CDATA[score down vote to photo]]></string>
+    <string name="_bx_photos_txt_n_views"><![CDATA[{0} views]]></string>
+    <string name="_bx_photos_txt_previous"><![CDATA[Previous]]></string>
+    <string name="_bx_photos_txt_next"><![CDATA[Next]]></string>
+    <string name="_bx_photos_txt_camera"><![CDATA[Camera]]></string>
+    <string name="_bx_photos_txt_focal_length"><![CDATA[Focal length]]></string>
+    <string name="_bx_photos_txt_focal_length_value"><![CDATA[{0}mm]]></string>
+    <string name="_bx_photos_txt_aperture"><![CDATA[Aperture]]></string>
+    <string name="_bx_photos_txt_shutter_speed"><![CDATA[Exposure time]]></string>
+    <string name="_bx_photos_txt_shutter_speed_value"><![CDATA[{0}s]]></string>
+    <string name="_bx_photos_txt_iso"><![CDATA[ISO]]></string>
+</resources>

+ 63 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/install/sql/disable.sql

@@ -0,0 +1,63 @@
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_photos' 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_photos';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_photos' OR `object` IN('bx_photos_create_entry', 'bx_photos_edit_entry', 'bx_photos_delete_entry', 'bx_photos_view_entry', 'bx_photos_view_entry_brief', 'bx_photos_view_entry_comments', 'bx_photos_home', 'bx_photos_popular', 'bx_photos_top', 'bx_photos_updated', 'bx_photos_author', 'bx_photos_context', 'bx_photos_search', 'bx_photos_manage');
+
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_photos';
+DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_photos';
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_photos' OR `set_name` IN('bx_photos_view', 'bx_photos_view_actions', 'bx_photos_submenu', 'bx_photos_view_submenu', 'bx_photos_snippet_meta', 'bx_photos_my', 'bx_photos_menu_manage_tools');
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object` IN ('bx_photos_allow_view_to', 'bx_photos_allow_view_favorite_list');
+
+
+-- 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_photos';
+DELETE FROM `sys_acl_actions` WHERE `Module` = 'bx_photos';
+
+
+-- SEARCH
+DELETE FROM `sys_objects_search` WHERE `ObjectName` IN ('bx_photos', 'bx_photos_cmts');
+
+
+-- METATAGS
+DELETE FROM `sys_objects_metatags` WHERE `object` IN ('bx_photos', 'bx_photos_camera');
+
+
+-- CATEGORY
+DELETE FROM `sys_objects_category` WHERE `object` = 'bx_photos_cats';
+
+
+-- STATS
+DELETE FROM `sys_statistics` WHERE `name` LIKE 'bx_photos%';
+
+
+-- CHARTS
+DELETE FROM `sys_objects_chart` WHERE `object` LIKE 'bx_photos%';
+
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_photos_administration', 'bx_photos_common');
+DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_photos_administration', 'bx_photos_common');
+DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_photos_administration', 'bx_photos_common');
+
+
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object` IN('bx_photos_simple', 'bx_photos_html5');
+
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_photos' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;

+ 463 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/install/sql/enable.sql

@@ -0,0 +1,463 @@
+
+-- 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_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);
+
+-- 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`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_photos_favorites', 2, 'bx_photos', '_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);
+
+-- 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`, `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', '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', 'social-sharing-facebook', '_sys_menu_item_title_system_social_sharing_facebook', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 300),
+('bx_photos_view_actions', 'bx_photos', 'social-sharing-twitter', '_sys_menu_item_title_system_social_sharing_twitter', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 320),
+('bx_photos_view_actions', 'bx_photos', 'social-sharing-pinterest', '_sys_menu_item_title_system_social_sharing_pinterest', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 330),
+('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-manage-photos', '_bx_photos_menu_item_title_system_manage_my_photos', '_bx_photos_menu_item_title_manage_my_photos', 'page.php?i=photos-manage', '', '_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();
+
+SET @iUnauthenticated = 1;
+SET @iAccount = 2;
+SET @iStandard = 3;
+SET @iUnconfirmed = 4;
+SET @iPending = 5;
+SET @iSuspended = 6;
+SET @iModerator = 7;
+SET @iAdministrator = 8;
+SET @iPremium = 9;
+
+INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`) VALUES
+
+-- entry create
+(@iStandard, @iIdActionEntryCreate),
+(@iModerator, @iIdActionEntryCreate),
+(@iAdministrator, @iIdActionEntryCreate),
+(@iPremium, @iIdActionEntryCreate),
+
+-- entry delete
+(@iStandard, @iIdActionEntryDelete),
+(@iModerator, @iIdActionEntryDelete),
+(@iAdministrator, @iIdActionEntryDelete),
+(@iPremium, @iIdActionEntryDelete),
+
+-- entry view
+(@iUnauthenticated, @iIdActionEntryView),
+(@iAccount, @iIdActionEntryView),
+(@iStandard, @iIdActionEntryView),
+(@iUnconfirmed, @iIdActionEntryView),
+(@iPending, @iIdActionEntryView),
+(@iModerator, @iIdActionEntryView),
+(@iAdministrator, @iIdActionEntryView),
+(@iPremium, @iIdActionEntryView),
+
+-- set entry thumb
+(@iStandard, @iIdActionSetThumb),
+(@iModerator, @iIdActionSetThumb),
+(@iAdministrator, @iIdActionSetThumb),
+(@iPremium, @iIdActionSetThumb),
+
+-- edit any entry
+(@iModerator, @iIdActionEntryEditAny),
+(@iAdministrator, @iIdActionEntryEditAny);
+
+
+-- SEARCH
+SET @iSearchOrder = (SELECT IFNULL(MAX(`Order`), 0) FROM `sys_objects_search`);
+INSERT INTO `sys_objects_search` (`ObjectName`, `Title`, `Order`, `ClassName`, `ClassPath`) VALUES
+('bx_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`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_photos', 'bx_photos_meta_keywords', 'bx_photos_meta_locations', 'bx_photos_meta_mentions', '', ''),
+('bx_photos_camera', 'bx_photos_meta_keywords_camera', '', '', '', '');
+
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_photos_cats', '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', '30%', 1, '25', '', 4),
+('bx_photos_common', 'actions', '', '20%', 0, '', '', 5);
+
+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_simple', 1, 'BxPhotosUploaderSimple', 'modules/boonex/photos/classes/BxPhotosUploaderSimple.php'),
+('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);

+ 400 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/install/sql/install.sql

@@ -0,0 +1,400 @@
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+
+-- 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',
+  `status` enum('active','hidden') NOT NULL DEFAULT 'active',
+  `status_admin` enum('active','hidden') 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',
+  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` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+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` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+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` (
+  `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',
+  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` (
+  `object_id` int(11) NOT NULL default '0',
+  `viewer_id` int(11) NOT NULL default '0',
+  `viewer_nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE `bx_photos_meta_keywords` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `keyword` (`keyword`)
+);
+
+CREATE TABLE `bx_photos_meta_keywords_camera` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  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` (
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_photos_reports` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  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',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: favorites
+CREATE TABLE `bx_photos_favorites_track` (
+  `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',
+  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` (
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  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
+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', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
+('bx_photos_media_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_photos_media_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png,avi,flv,mpg,mpeg,wmv,mp4,m4v,mov,qt,divx,xvid,3gp,3g2,webm,mkv,ogv,ogg,rm,rmvb,asf,drc', '', 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:"2000";}', '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', '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', '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:2:{s:16:"bx_photos_simple";s:26:"_sys_uploader_simple_title";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:2:{s:16:"bx_photos_simple";s:26:"_sys_uploader_simple_title";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', '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', 'do_submit', 2147483647, 1, 5),
+
+('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', 'location', 2147483647, 1, 6),
+('bx_photos_entry_edit', 'do_submit', 2147483647, 1, 7),
+
+('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', '', '');
+
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('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_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_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`, `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_entries', 'id', 'author', 'reports', '', '');
+
+
+-- VIEWS
+INSERT INTO `sys_objects_view` (`name`, `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_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/11.0.2_12.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_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` = 'bx_photos';
+
+
+-- 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';

+ 1 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/template/favorite-list-info.html

@@ -0,0 +1 @@
+<bx_include_base:../modules/base/general/template/favorite-list-info.html />

+ 1 - 0
modules/boonex/photos/updates/11.0.2_12.0.0/source/template/favorite-lists.html

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

+ 51 - 0
modules/boonex/plyr/updates/11.0.1_12.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' => '11.0.1',
+    'version_to' => '12.0.0',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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_11.0.1_12.0.0/',
+    'home_uri' => 'plyr_update_1101_1200',
+
+    'module_dir' => 'boonex/plyr/',
+    'module_uri' => 'plyr',
+
+    'db_prefix' => 'bx_plyr_',
+    'class_prefix' => 'BxPlyr',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Plyr',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/plyr/updates/11.0.1_12.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);
+    }
+}

+ 3 - 0
modules/boonex/plyr/updates/11.0.1_12.0.0/install/sql/install.sql

@@ -0,0 +1,3 @@
+-- STUDIO PAGE & WIDGET
+SET @iPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name`='bx_plyr' LIMIT 1);
+UPDATE `sys_std_widgets` SET `type`='integrations' WHERE `page_id`=@iPageId;

+ 30 - 0
modules/boonex/plyr/updates/11.0.1_12.0.0/source/classes/BxPlyrStudioPage.php

@@ -0,0 +1,30 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Plyr Plyr player integration
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPlyrStudioPage extends BxTemplStudioModule
+{
+    function __construct($sModule, $mixedPageName, $sPage = "")
+    {
+        parent::__construct($sModule, $mixedPageName, $sPage);
+
+        $this->aMenuItems = array(
+            'settings' => array('name' => 'settings', 'icon' => 'cogs', 'title' => '_adm_lmi_cpt_settings'),
+            'help' => array('name' => 'help', 'icon' => 'question', 'title' => '_bx_plyr_information'),
+        );
+    }
+    
+    function getHelp ()
+    {
+        return _t('_bx_plyr_information_block');
+    }
+}
+
+/** @} */

+ 74 - 0
modules/boonex/plyr/updates/11.0.1_12.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' => '12.0.0',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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(),
+);
+
+/** @} */

+ 15 - 0
modules/boonex/plyr/updates/11.0.1_12.0.0/source/install/sql/install.sql

@@ -0,0 +1,15 @@
+
+
+-- Studio page and widget
+
+INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
+(3, 'bx_plyr', '_bx_plyr', '_bx_plyr', 'bx_plyr@modules/boonex/plyr/|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_plyr', 'integrations', '{url_studio}module.php?name=bx_plyr', '', 'bx_plyr@modules/boonex/plyr/|std-icon.svg', '_bx_plyr', '', '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));
+

+ 5 - 0
modules/boonex/plyr/updates/11.0.1_12.0.0/source/install/sql/uninstall.sql

@@ -0,0 +1,5 @@
+
+-- Studio page and 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_plyr';

+ 19 - 0
modules/boonex/plyr/updates/11.0.1_12.0.0/source/template/css/main.css

@@ -0,0 +1,19 @@
+
+.bx-player-plyr {
+    width:100%;
+}
+
+.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%;
+}
+.bx-base-general-attachment .bx-player-plyr-wrapper {
+    width:100%;
+    height:100%;
+}

+ 51 - 0
modules/boonex/polls/updates/11.0.1_12.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' => '11.0.1',
+    'version_to' => '12.0.0',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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_11.0.1_12.0.0/',
+    'home_uri' => 'polls_update_1101_1200',
+
+    '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' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Polls',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 26 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/install/installer.php

@@ -0,0 +1,26 @@
+<?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);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_polls_cmts', 'cmt_pinned'))
+                $this->oDb->query("ALTER TABLE `bx_polls_cmts` ADD `cmt_pinned` int(11) NOT NULL default '0' AFTER `cmt_replies`");
+                
+            if(!$this->oDb->isFieldExists('bx_polls_favorites_track', 'list_id'))
+                $this->oDb->query("ALTER TABLE `bx_polls_favorites_track` ADD `list_id` int(11) NOT NULL default '0' AFTER `author_id`");
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 13 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/install/langs/en.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_polls_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string_add>
+	<string_add name="_bx_polls_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string_add>
+	<string_add name="_bx_polls_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string_add>
+	<string_add name="_bx_polls_page_block_title_favorites_entries_info"><![CDATA[Info]]></string_add>
+	<string_add name="_bx_polls_page_block_title_sys_my_entries"><![CDATA[User Polls]]></string_add>
+	<string_add name="_bx_polls_page_title_sys_entries_favorites"><![CDATA[Favorives Polls]]></string_add>
+	<string_add name="_bx_polls_page_title_entries_favorites"><![CDATA[Favorives Polls]]></string_add>
+	<string_add name="_bx_polls_grid_action_title_adm_clear_reports"><![CDATA[Clear reports]]></string_add>
+
+	<string_upd name="_bx_polls_page_block_title_my_entries"><![CDATA[{display_name} Polls]]></string_upd>
+</resources>

+ 45 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/install/sql/enable.sql

@@ -0,0 +1,45 @@
+-- SETTINGS
+SET @iTypeId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_polls' LIMIT 1);
+
+DELETE FROM `sys_options` WHERE `name`='bx_polls_per_page_for_favorites_lists';
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_polls_per_page_for_favorites_lists', '5', @iCategId, '_bx_polls_option_per_page_for_favorites_lists', 'digit', '',  '', '', '', 17);
+
+
+-- PAGES
+UPDATE `sys_pages_blocks` SET `content`='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;}}}' WHERE `object`='bx_polls_author' AND `title`='_bx_polls_page_block_title_favorites_of_author';
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_polls_author' AND `title`='_bx_polls_page_block_title_entries_in_context';
+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_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);
+
+DELETE FROM `sys_objects_page` WHERE `object`='bx_polls_favorites';
+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');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_polls_favorites';
+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_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);
+
+UPDATE `sys_pages_blocks` SET `title_system`='_bx_polls_page_block_title_sys_my_entries' WHERE `module`='bx_polls' AND `title`='_bx_polls_page_block_title_my_entries';
+
+
+-- MENUS
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_polls_view_actions' AND `name`='_sys_menu_item_title_va_notes';
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('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);
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object`='bx_polls_allow_view_favorite_list';
+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_favorite_list', 'bx_polls', 'view_favorite_list', '_bx_polls_form_entry_input_allow_view_favorite_list', '3', 'bx_polls_favorites_lists', 'id', 'author_id', '', '');
+
+
+-- GRIDS
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_polls_administration' AND `type` IN ('bulk', 'single') AND `name`='clear_reports';
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_polls_administration', 'bulk', 'clear_reports', '_bx_polls_grid_action_title_adm_clear_reports', '', 0, 1, 2),
+('bx_polls_administration', 'single', 'clear_reports', '_bx_polls_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5);

+ 51 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/install/sql/install.sql

@@ -0,0 +1,51 @@
+-- TABLES
+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`)
+);
+
+CREATE TABLE IF NOT EXISTS `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`)
+);
+
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name`='bx_polls_notes';
+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`, `ObjectScore`, `ObjectReport`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('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', 'comments', '', '');
+
+
+-- REPORTS
+UPDATE `sys_objects_report` SET `module`='bx_polls', `object_comment`='bx_polls_notes' WHERE `name`='bx_polls';
+
+
+-- FAVORITES
+UPDATE `sys_objects_favorite` SET `table_lists`='bx_polls_favorites_lists' WHERE `name`='bx_polls';
+
+
+-- FEATURED
+UPDATE `sys_objects_feature` SET `module`='bx_polls' WHERE `name`='bx_polls';
+
+
+-- STUDIO PAGE & WIDGET
+SET @iPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name`='bx_polls' LIMIT 1);
+UPDATE `sys_std_widgets` SET `type`='content' WHERE `page_id`=@iPageId;

+ 208 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsConfig.php

@@ -0,0 +1,208 @@
+<?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 BxPollsConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            'edit-poll' => 'checkAllowedEdit',
+            'delete-poll' => 'checkAllowedDelete',
+        );
+
+        $this->CNF = array (
+
+            // module icon
+            'ICON' => 'tasks col-green1',
+
+            // database tables
+            'TABLE_ENTRIES' => $aModule['db_prefix'] . 'entries',
+            'TABLE_SUBENTRIES' => $aModule['db_prefix'] . 'subentries',
+            'TABLE_VOTES_SUBENTRIES_TRACK' => $aModule['db_prefix'] . 'votes_subentries_track',
+            'TABLE_ENTRIES_FULLTEXT' => 'title_text',
+
+            // database fields
+            'FIELD_ID' => 'id',
+            'FIELD_AUTHOR' => 'author',
+            'FIELD_ADDED' => 'added',
+            'FIELD_CHANGED' => 'changed',
+            'FIELD_TITLE' => '',
+            'FIELD_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'poll-text',
+            'FIELD_CATEGORY' => 'cat',
+            'FIELD_SUBENTRIES' => 'subentries',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_ANONYMOUS_VOTING' => 'anonymous',
+            'FIELD_HIDDEN_RESULTS' => 'hidden_results',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_THUMB' => 'thumb',
+            'FIELD_VIEWS' => 'views',
+            'FIELD_COMMENTS' => 'comments',
+            'FIELD_STATUS' => 'status',
+            'FIELD_STATUS_ADMIN' => 'status_admin',
+            '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
+
+            // some params
+            'PARAM_PER_PAGE_FOR_FAVORITES_LISTS' => 'bx_polls_per_page_for_favorites_lists',
+            
+            // page URIs
+            'URI_VIEW_ENTRY' => 'view-poll',
+            'URI_AUTHOR_ENTRIES' => 'polls-author',
+            'URI_ENTRIES_BY_CONTEXT' => 'polls-context',
+            'URI_ADD_ENTRY' => 'create-poll',
+            'URI_EDIT_ENTRY' => 'edit-poll',
+            'URI_MANAGE_COMMON' => 'polls-manage',
+            'URI_FAVORITES_LIST' => 'polls-favorites',
+
+            'URL_HOME' => 'page.php?i=polls-home',
+            'URL_POPULAR' => 'page.php?i=polls-popular',
+            'URL_TOP' => 'page.php?i=polls-top',
+            'URL_UPDATED' => 'page.php?i=polls-updated',
+            'URL_MANAGE_COMMON' => 'page.php?i=polls-manage',
+            'URL_MANAGE_ADMINISTRATION' => 'page.php?i=polls-administration',
+
+            // some params
+            'PARAM_CHARS_TITLE' => 'bx_polls_title_chars',
+            'PARAM_CHARS_SUMMARY' => '',
+            'PARAM_CHARS_SUMMARY_PLAIN' => '',
+            'PARAM_NUM_RSS' => 'bx_polls_rss_num',
+            'PARAM_SEARCHABLE_FIELDS' => 'bx_polls_searchable_fields',
+
+            // objects
+            'OBJECT_STORAGE' => 'bx_polls_files',
+            'OBJECT_IMAGES_TRANSCODER_PREVIEW' => 'bx_polls_preview',
+            'OBJECT_IMAGES_TRANSCODER_GALLERY' => 'bx_polls_gallery',
+            'OBJECT_IMAGES_TRANSCODER_COVER' => 'bx_polls_cover',
+            'OBJECT_VIDEOS_TRANSCODERS' => array(),
+            'OBJECT_REPORTS' => 'bx_polls',
+            'OBJECT_VIEWS' => 'bx_polls',
+            'OBJECT_VOTES' => 'bx_polls',
+            'OBJECT_VOTES_SUBENTRIES' => 'bx_polls_subentries',
+            'OBJECT_REACTIONS' => 'bx_polls_reactions',
+            'OBJECT_SCORES' => 'bx_polls',
+            'OBJECT_FAVORITES' => 'bx_polls',
+            'OBJECT_FEATURED' => 'bx_polls',
+            'OBJECT_METATAGS' => 'bx_polls',
+            'OBJECT_COMMENTS' => 'bx_polls',
+            'OBJECT_NOTES' => 'bx_polls_notes',
+            'OBJECT_CATEGORY' => 'bx_polls_cats',
+            'OBJECT_PRIVACY_VIEW' => 'bx_polls_allow_view_to',
+            'OBJECT_PRIVACY_LIST_VIEW' => 'bx_polls_allow_view_favorite_list',
+            'OBJECT_FORM_ENTRY' => 'bx_polls',
+            'OBJECT_FORM_ENTRY_DISPLAY_VIEW' => 'bx_polls_entry_view',
+            'OBJECT_FORM_ENTRY_DISPLAY_ADD' => 'bx_polls_entry_add',
+            'OBJECT_FORM_ENTRY_DISPLAY_EDIT' => 'bx_polls_entry_edit',
+            'OBJECT_FORM_ENTRY_DISPLAY_DELETE' => 'bx_polls_entry_delete',
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_polls_view', // actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_polls_view_actions', // all actions menu on view entry page
+            'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_polls_my', // actions menu on my entries page
+            'OBJECT_MENU_SUBMENU' => 'bx_polls_submenu', // main module submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_polls_view_submenu', // view entry submenu
+            'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'polls-home', // first item in view entry submenu from main module submenu
+            'OBJECT_MENU_SNIPPET_META' => 'bx_polls_snippet_meta', // menu for snippet meta info
+            'OBJECT_MENU_MANAGE_TOOLS' => 'bx_polls_menu_manage_tools', //manage menu in content administration tools
+            'OBJECT_GRID_ADMINISTRATION' => 'bx_polls_administration',
+            'OBJECT_GRID_COMMON' => 'bx_polls_common',
+            'OBJECT_UPLOADERS' => array('sys_simple', 'sys_html5'),
+
+            // styles
+            'STYLES_POLLS_EMBED_CLASS' => 'body.bx-page-iframe.bx-def-color-bg-page',
+            'STYLES_POLLS_EMBED_CONTENT' => array(
+                'background-color' => 'transparent'
+            ),
+
+            // menu items which visibility depends on custom visibility checking
+            'MENU_ITEM_TO_METHOD' => array (
+                'bx_polls_my' => array (
+                    'create-poll' => 'checkAllowedAdd',
+                ),
+                'bx_polls_view' => $aMenuItems2Methods,
+            ),
+
+            // some language keys
+            'T' => array (
+                'txt_sample_single' => '_bx_polls_txt_sample_single',
+                'txt_sample_single_with_article' => '_bx_polls_txt_sample_single_with_article',
+                'txt_sample_comment_single' => '_bx_polls_txt_sample_comment_single',
+                'txt_sample_vote_single' => '_bx_polls_txt_sample_vote_single',
+                'txt_sample_reaction_single' => '_bx_polls_txt_sample_reaction_single',
+                'txt_sample_score_up_single' => '_bx_polls_txt_sample_score_up_single',
+                'txt_sample_score_down_single' => '_bx_polls_txt_sample_score_down_single',
+                'form_field_author' => '_bx_polls_form_entry_input_author',
+                'grid_action_err_delete' => '_bx_polls_grid_action_err_delete',
+                'grid_txt_account_manager' => '_bx_polls_grid_txt_account_manager',
+                'filter_item_active' => '_bx_polls_grid_filter_item_title_adm_active',
+                'filter_item_hidden' => '_bx_polls_grid_filter_item_title_adm_hidden',
+                'filter_item_select_one_filter1' => '_bx_polls_grid_filter_item_title_adm_select_one_filter1',
+                'menu_item_manage_my' => '_bx_polls_menu_item_title_manage_my',
+                'menu_item_manage_all' => '_bx_polls_menu_item_title_manage_all',
+                'txt_all_entries_by' => '_bx_polls_txt_all_entries_by',
+                'txt_all_entries_in' => '_bx_polls_txt_all_entries_in',
+                'txt_all_entries_by_author' => '_bx_polls_page_title_browse_by_author',
+                'txt_all_entries_by_context' => '_bx_polls_page_title_browse_by_context',
+                'txt_pict_use_as_thumb' => '_bx_polls_form_entry_input_picture_use_as_thumb'
+            ),
+        );
+
+        $this->_aJsClasses = array(
+            'form' => 'BxPollsForm',
+            'entry' => 'BxPollsEntry',
+            'manage_tools' => 'BxPollsManageTools'
+        );
+
+        $this->_aJsObjects = array(
+            'form' => 'oBxPollsForm',
+            'entry' => 'oBxPollsEntry',
+            'manage_tools' => 'oBxPollsManageTools'
+        );
+
+        $this->_aGridObjects = array(
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        );
+
+        $sHtmlPrefix = str_replace('_', '-', $this->_sName);
+        $this->_aHtmlIds = array(
+            'block_menu' => $sHtmlPrefix . '-block-menu',
+            'block_link_subentries' => $sHtmlPrefix . '-block-subentries-',
+            'block_link_results' => $sHtmlPrefix . '-block-results-',
+            'snippet_link_subentries' => $sHtmlPrefix . '-snippet-subentries-',
+            'snippet_link_results' => $sHtmlPrefix . '-snippet-results-',
+            'content' => $sHtmlPrefix . '-content-',
+            'embed' => $sHtmlPrefix . '-content-',
+        );
+    }
+
+    public function getHtmlIds($sKey = '')
+    {
+        if(empty($sKey))
+            return $this->_aHtmlIds;
+
+        return isset($this->_aHtmlIds[$sKey]) ? $this->_aHtmlIds[$sKey] : '';
+    }
+
+    public function getTitle($aData)
+    {
+        return BxTemplFunctions::getInstance()->getStringWithLimitedLength(strip_tags($aData[$this->CNF['FIELD_TEXT']]), (int)getParam($this->CNF['PARAM_CHARS_TITLE']));
+    }
+    
+    public function getSalt()
+    {
+        return time() . rand(0, PHP_INT_MAX);
+    }
+}
+
+/** @} */

+ 252 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsModule.php

@@ -0,0 +1,252 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * Polls module
+ */
+class BxPollsModule extends BxBaseModTextModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+
+        $CNF = &$this->_oConfig->CNF;
+        $this->_aSearchableNamesExcept = array_merge($this->_aSearchableNamesExcept, array(
+             $CNF['FIELD_ANONYMOUS_VOTING'],
+             $CNF['FIELD_HIDDEN_RESULTS']
+        ));
+    }
+
+    /**
+     * ACTION METHODS
+     */
+    public function actionGetBlock()
+    {
+        $iContentId = (int)bx_get('content_id');
+        $sBlock = bx_process_input(bx_get('block'));
+
+        $sMethod = 'serviceGetBlock' . bx_gen_method_name($sBlock);
+        if(!method_exists($this, $sMethod))
+            return echoJson(array());
+
+        $aBlock = $this->$sMethod($iContentId, true);
+        if(empty($aBlock) || !is_array($aBlock))
+            return echoJson(array());
+
+        return echoJson(array(
+        	'content' => $aBlock['content']
+        ));
+    }
+
+    public function actionEmbedEntry($iId = 0)
+    {
+        list($iContentId, $aContentInfo) = $this->_getContent($iId);
+        if($iContentId === false)
+            return;
+
+        $aParams = bx_get_with_prefix('param');
+        array_walk($aParams, function(&$sValue) {
+            $sValue = bx_process_input($sValue);
+        });
+
+        $this->_oTemplate->embedEntry($aContentInfo, $aParams);
+    }
+
+
+    /**
+     * SERVICE METHODS
+     */
+    
+    /**
+     * @page service Service Calls
+     * @section bx_polls Polls
+     * @subsection bx_polls-page_blocks Page Blocks
+     * @subsubsection bx_polls-get_results_search_extended get_results_search_extended
+     * 
+     * @code bx_srv('bx_polls', 'get_results_search_extended', [...]); @endcode
+     * 
+     * Get page block with the results of Extended Search.
+     *
+     * @param $aParams an array with search params.
+     * @return HTML string with block content to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPollsModule::serviceGetResultsSearchExtended
+     */
+    /** 
+     * @ref bx_polls-get_results_search_extended "get_results_search_extended"
+     */
+    public function serviceGetResultsSearchExtended($aParams)
+    {
+        $this->_oTemplate->addJs(array('entry.js'));
+        $this->_oTemplate->addCss(array('entry.css'));
+        return $this->_oTemplate->getJsCode('entry') . BxDolService::call('system', 'get_results', array($aParams), 'TemplSearchExtendedServices');
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_polls Polls
+     * @subsection bx_polls-page_blocks Page Blocks
+     * @subsubsection bx_polls-get_block_subentries get_block_subentries
+     * 
+     * @code bx_srv('bx_polls', 'get_block_subentries', [...]); @endcode
+     * 
+     * Get page block with poll questions.
+     *
+     * @param $iContentId (optional) poll's ID. If empty value is provided, an attempt to get it from GET/POST arrays will be performed.
+     * @param $bForceDisplay (optional) if true is passed then the block will be displayed as is (without checking whether user answered the poll or not).
+     * @return HTML string with block content to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPollsModule::serviceGetBlockSubentries
+     */
+    /** 
+     * @ref bx_polls-get_block_subentries "get_block_subentries"
+     */
+    public function serviceGetBlockSubentries($iContentId = 0, $bForceDisplay = false)
+    {
+        if (!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if (!$iContentId)
+            return false;
+
+        if(!$bForceDisplay && $this->isPerformed($iContentId))
+            return $this->serviceGetBlockResults($iContentId);
+
+        return $this->_serviceTemplateFunc('entrySubentries', $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_polls Polls
+     * @subsection bx_polls-page_blocks Page Blocks
+     * @subsubsection bx_polls-get_block_results get_block_results
+     * 
+     * @code bx_srv('bx_polls', 'get_block_results', [...]); @endcode
+     * 
+     * Get page block with poll results.
+     *
+     * @param $iContentId (optional) poll's ID. If empty value is provided, an attempt to get it from GET/POST arrays will be performed.
+     * @return HTML string with block content to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPollsModule::serviceGetBlockResults
+     */
+    /** 
+     * @ref bx_polls-get_block_results "get_block_results"
+     */
+    public function serviceGetBlockResults($iContentId = 0)
+    {
+        return $this->_serviceTemplateFunc('entryResults', $iContentId);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_polls Polls
+     * @subsection bx_polls-page_blocks Page Blocks
+     * @subsubsection bx_polls-get_block_text_and_subentries get_block_text_and_subentries
+     * 
+     * @code bx_srv('bx_polls', 'get_block_text_and_subentries', [...]); @endcode
+     * 
+     * Get page block with poll question and answers with possibility to switch to results.
+     *
+     * @param $iContentId (optional) poll's ID. If empty value is provided, an attempt to get it from GET/POST arrays will be performed.
+     * @param $bForceDisplay (optional) if true is passed then the block will be displayed as is (without checking whether user answered the poll or not).
+     * @return HTML string with block content to display on the site or false if there is no enough input data. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPollsModule::serviceGetBlockTextAndSubentries
+     */
+    /** 
+     * @ref bx_polls-get_block_text_and_subentries "get_block_text_and_subentries"
+     */
+    public function serviceGetBlockTextAndSubentries($iContentId = 0, $bForceDisplaySubentries = false)
+    {
+        if (!$iContentId)
+            $iContentId = bx_process_input(bx_get('id'), BX_DATA_INT);
+        if (!$iContentId)
+            return false;
+
+        $mixedContent = $this->_getContent($iContentId);
+        if($mixedContent === false)
+            return false;
+
+        list($iContentId, $aContentInfo) = $mixedContent;
+
+        return $this->_oTemplate->entryTextAndSubentries($aContentInfo, $bForceDisplaySubentries);
+    }
+    
+    /**
+     * PERMISSION METHODS
+     */
+    public function isAllowedVote($isPerformAction = false)
+    {
+        $aCheck = checkActionModule($this->_iProfileId, 'vote entry', $this->getName(), false);
+        if ($aCheck[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return $aCheck[CHECK_ACTION_MESSAGE];
+
+        return CHECK_ACTION_RESULT_ALLOWED;
+    }
+
+    public function isPerformed($iObjectId, $iAuthorId = 0, $iAuthorIp = 0)
+    {
+        if(empty($iAuthorId)) {
+            $iAuthorId = bx_get_logged_profile_id();
+            $iAuthorIp = ip2long(getVisitorIP());
+        }
+
+        return $this->_oDb->isPerformed($iObjectId, $iAuthorId, $iAuthorIp);
+    }
+
+
+    /**
+     * INTERNAL METHODS
+     */
+    protected function _getContent($iContentId = 0, $sFuncGetContent = 'getContentInfoById')
+    {
+        $mixedResult = parent::_getContent($iContentId, $sFuncGetContent);
+        if(empty($mixedResult) || !is_array($mixedResult)) 
+            return $mixedResult;
+
+        list($iContentId, $aContentInfo) = $mixedResult;
+
+        if(bx_get('salt') !== false)
+            $aContentInfo['salt'] = bx_process_input(bx_get('salt'));
+    
+        return array($iContentId, $aContentInfo);
+    }
+
+    protected function _getImagesForTimelinePost($aEvent, $aContentInfo, $sUrl, $aBrowseParams = array())
+    {
+        return array();
+    }
+
+    protected function _getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+        $bDynamic = isset($aBrowseParams['dynamic_mode']) && $aBrowseParams['dynamic_mode'] === true;
+
+        $sInclude = '';
+        $sInclude .= $this->_oTemplate->addCss(array('main.css'), $bDynamic);
+
+        $aBlock = $this->_oTemplate->{$this->isPerformed($aContentInfo[$CNF['FIELD_ID']]) ? 'entryResults' : 'entrySubentries'}($aContentInfo, $bDynamic);
+
+        $aResult = parent::_getContentForTimelinePost($aEvent, $aContentInfo, $aBrowseParams);
+        $aResult['title'] = $this->_oConfig->getTitle($aContentInfo);
+        $aResult['text'] = '';
+        $aResult['raw'] = ($bDynamic ? $sInclude : '') . $this->_oTemplate->parseHtmlByName('unit_embed.html', array(
+            'html_id' => $this->_oConfig->getHtmlIds('embed') . (int)$aContentInfo[$CNF['FIELD_ID']],
+            'embed_url' => BX_DOL_URL_ROOT . bx_append_url_params($this->_oConfig->getBaseUri() . 'embed_entry/', array(
+                'id' => (int)$aContentInfo[$CNF['FIELD_ID']]
+            ))
+        ));
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsPageListEntry.php

@@ -0,0 +1,24 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * List entry page
+ */
+class BxPollsPageListEntry extends BxBaseModTextPageListEntry
+{    
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_polls';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 296 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/classes/BxPollsTemplate.php

@@ -0,0 +1,296 @@
+<?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)
+    {
+        $sContent = $this->_getGetBlockContentSubentries($aData, $bDynamic);
+        if(empty($sContent))
+            return '';
+
+    	return array(
+            'content' => $sContent,
+            'menu' => $this->_getGetBlockMenu($aData, 'subentries')
+        );
+    }
+
+    public function entryResults($aData, $bDynamic = false)
+    {
+        $sContent = $this->_getGetBlockContentResults($aData, $bDynamic);
+        if(empty($sContent))
+            return '';
+
+        return array(
+            'content' => $sContent,
+            'menu' => $this->_getGetBlockMenu($aData, 'results')
+        );
+    }
+
+    public function entryTextAndSubentries($aData, $bForceDisplaySubentries = false)
+    {
+        $oModule = $this->getModule();
+        $CNF = &$oModule->_oConfig->CNF;
+
+        $sMethod = '_getGetBlockContent';
+        $sMenuItem = '';
+        if(!$bForceDisplaySubentries && $oModule->isPerformed($aData[$CNF['FIELD_ID']])) {
+            $sMethod .= 'Results';
+            $sMenuItem = 'results';
+        }
+        else {
+            $sMethod .= 'Subentries';
+            $sMenuItem = 'subentries';
+        };
+
+        $sSubentries = $this->$sMethod($aData);
+        $oMenu = $this->_getGetBlockMenu($aData, $sMenuItem);
+
+        $sMenu = str_replace('_', '-', $this->_oConfig->getName()) . '-menu-db';
+        $sMenuId = $sMenu . '-' . $aData['salt'];        
+
+        $aTmplVars = parent::getTmplVarsText($aData);
+        $aTmplVars = array_merge($aTmplVars, array(
+            'menu' => BxTemplFunctions::getInstance()->designBoxMenu($oMenu, array(
+                array(
+                    'menu' => array(
+                        'id' => $sMenuId, 
+                        'class' => $sMenu, 
+                        'onclick' => "bx_menu_slide_inline('#" . $sMenuId . "', this, $(this).parents('.bx-db-menu:first'))"
+                    )
+                )
+            )),
+            'bx_if:show_subentries' => array(
+                'condition' => !empty($sSubentries),
+                'content' => array(
+                    'entry_subentries' => $sSubentries
+                )
+            )
+        ));
+
+        return array(
+            'content' => $this->parseHtmlByName('entry-text-subentries.html', $aTmplVars),
+            'menu' => $oMenu
+        );
+    }
+
+    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 = array())
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $aResult = parent::getUnit($aData, $aParams);
+        
+        $oMenuMeta = BxDolMenu::getObjectInstance($CNF['OBJECT_MENU_SNIPPET_META'], $this);
+        if($oMenuMeta) {
+            $oMenuMeta->setContent($aData);
+
+            $aResult = array_merge($aResult, array(
+                'bx_if:meta' => array(
+                    'condition' => true,
+                    'content' => array(
+                        'meta' => $oMenuMeta->getCode()
+                    )
+                ),
+            ));
+        }
+
+        return $aResult;
+    }
+
+    protected function getUnitThumbAndGallery ($aData)
+    {
+        return array('', '');
+    }
+
+    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(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)
+    {
+        $CNF = &$this->getModule()->_oConfig->CNF;
+
+        $bAnonymous = (int)$aData[$CNF['FIELD_ANONYMOUS_VOTING']] == 1;
+
+        $aSubentries = $this->_oDb->getSubentries(array('type' => 'entry_id', 'entry_id' => $aData[$CNF['FIELD_ID']]));
+        if(empty($aSubentries) || !is_array($aSubentries))
+            return '';
+
+        $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(
+                'title' => bx_process_output($aSubentry['title']),
+                'width' => (int)round($fPercent) . '%',
+                'votes' => $oVotes->getCounter(array('show_counter_empty' => true, 'show_counter_in_brackets' => false)),
+                'percent' => _t('_bx_polls_txt_subentry_vote_percent', $iTotal > 0 ? round($fPercent, 2) : 0),
+                'js_code' => $oVotes->getJsScript(array('dynamic_mode' => $bDynamic))
+            );
+        }
+
+        return $this->parseHtmlByName('subentries_results.html', array(
+            'html_id' => $this->_oConfig->getHtmlIds('content') . $aData[$CNF['FIELD_ID']],
+            'bx_repeat:subentries' => $aTmplVarsSubentries,
+        ));
+    }
+}
+
+/** @} */

+ 136 - 0
modules/boonex/polls/updates/11.0.1_12.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' => '12.0.0',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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'
+    ),
+
+);
+
+/** @} */

+ 256 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/install/langs/en.xml

@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+
+	<string name="_bx_polls"><![CDATA[Polls]]></string>
+	<string name="_bx_polls_cmts"><![CDATA[Polls' Comments]]></string>
+        <string name="_bx_polls_reactions"><![CDATA[Polls' Reactions]]></string>
+
+	<string name="_bx_polls_option_title_chars"><![CDATA[Number of characters in auto-cropped poll title]]></string>
+	<string name="_bx_polls_option_per_page_browse"><![CDATA[Number of items per page]]></string>
+	<string name="_bx_polls_option_rss_num"><![CDATA[Number of items in RSS feed]]></string>
+	<string name="_bx_polls_option_searchable_fields"><![CDATA[Searchable fields for keyword search]]></string>
+  <string name="_bx_polls_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string>
+
+
+  <string name="_bx_polls_form_entry"><![CDATA[Polls]]></string>
+	<string name="_bx_polls_form_entry_display_add"><![CDATA[Add Poll]]></string>
+	<string name="_bx_polls_form_entry_display_edit"><![CDATA[Edit Poll]]></string>
+	<string name="_bx_polls_form_entry_display_delete"><![CDATA[Delete Poll]]></string>
+	<string name="_bx_polls_form_entry_display_view"><![CDATA[View Poll]]></string>
+	<string name="_bx_polls_form_entry_input_author"><![CDATA[Author]]></string>
+	<string name="_bx_polls_form_entry_input_sys_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_polls_form_entry_input_do_submit"><![CDATA[Submit]]></string>
+	<string name="_bx_polls_form_entry_input_sys_do_publish"><![CDATA[Publish]]></string>
+	<string name="_bx_polls_form_entry_input_do_publish"><![CDATA[Publish]]></string>
+	<string name="_bx_polls_form_entry_input_sys_cat"><![CDATA[Category]]></string>
+	<string name="_bx_polls_form_entry_input_cat"><![CDATA[Category]]></string>
+    <string name="_bx_polls_form_entry_input_cat_err"><![CDATA[Please select category]]></string>
+	<string name="_bx_polls_form_entry_input_sys_text"><![CDATA[Question]]></string>
+	<string name="_bx_polls_form_entry_input_text"><![CDATA[Question]]></string>
+	<string name="_bx_polls_form_entry_input_text_err"><![CDATA[Question is essential. Please, fill in this field]]></string>
+	<string name="_bx_polls_form_entry_input_sys_subentries"><![CDATA[Answers]]></string>
+    <string name="_bx_polls_form_entry_input_subentries"><![CDATA[Answers]]></string>
+    <string name="_bx_polls_form_entry_input_subentries_err"><![CDATA[Poll should have at least 2 non-empty answers.]]></string>
+    <string name="_bx_polls_form_entry_input_subentries_add"><![CDATA[Add More]]></string>
+	<string name="_bx_polls_form_entry_input_sys_delete_confirm"><![CDATA[Delete confirmation]]></string>
+	<string name="_bx_polls_form_entry_input_delete_confirm"><![CDATA[I am sure I want to delete this poll]]></string>
+	<string name="_bx_polls_form_entry_input_delete_confirm_info"><![CDATA[This action can not be undone]]></string>
+	<string name="_bx_polls_form_entry_input_delete_confirm_error"><![CDATA[Please check this checkbox if you really want to delete the poll]]></string>
+	<string name="_bx_polls_form_entry_input_sys_pictures"><![CDATA[Pictures]]></string>
+	<string name="_bx_polls_form_entry_input_pictures"><![CDATA[Pictures]]></string>
+	<string name="_bx_polls_form_profile_input_sys_anonymous"><![CDATA[Anonymous]]></string>
+    <string name="_bx_polls_form_profile_input_anonymous"><![CDATA[Anonymous vote]]></string>
+    <string name="_bx_polls_form_profile_input_anonymous_info"><![CDATA[When Anonymous mode is enabled, a list of voters won't be available to anybody.]]></string>
+    <string name="_bx_polls_form_profile_input_sys_hidden_results"><![CDATA[Hidden Results]]></string>
+    <string name="_bx_polls_form_profile_input_hidden_results"><![CDATA[Hide results until voted]]></string>
+    <string name="_bx_polls_form_entry_input_sys_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_polls_form_entry_input_allow_view_to"><![CDATA[Visibility]]></string>
+    <string name="_bx_polls_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string>
+    <string name="_bx_polls_form_entry_input_picture_use_as_thumb"><![CDATA[Header Image]]></string>
+    <string name="_bx_polls_form_entry_input_sys_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_polls_form_entry_input_date_added"><![CDATA[Created]]></string>
+    <string name="_bx_polls_form_entry_input_sys_date_changed"><![CDATA[Updated]]></string>
+    <string name="_bx_polls_form_entry_input_date_changed"><![CDATA[Updated]]></string>
+
+	<string name="_bx_polls_acl_action_create_entry"><![CDATA[Create Poll]]></string>
+	<string name="_bx_polls_acl_action_delete_entry"><![CDATA[Delete Poll]]></string>
+	<string name="_bx_polls_acl_action_view_entry"><![CDATA[View Poll]]></string>
+	<string name="_bx_polls_acl_action_vote_entry"><![CDATA[Vote Poll]]></string>
+	<string name="_bx_polls_acl_action_set_thumb"><![CDATA[Set Poll Thumbnail]]></string>
+	<string name="_bx_polls_acl_action_edit_any_entry"><![CDATA[Edit Any Poll]]></string>
+
+	<string name="_bx_polls_page_title_sys_create_entry"><![CDATA[New Poll]]></string>
+	<string name="_bx_polls_page_title_create_entry"><![CDATA[New Poll]]></string>
+	<string name="_bx_polls_page_block_title_create_entry"><![CDATA[New Poll]]></string>
+	<string name="_bx_polls_page_title_sys_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_polls_page_title_edit_entry"><![CDATA[Edit]]></string>
+	<string name="_bx_polls_page_block_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_polls_page_title_sys_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_polls_page_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_polls_page_block_title_delete_entry"><![CDATA[Delete]]></string>
+	<string name="_bx_polls_page_title_sys_view_entry"><![CDATA[View Poll]]></string>
+	<string name="_bx_polls_page_title_view_entry"><![CDATA[{title}]]></string>
+	<string name="_bx_polls_page_block_title_entry_subentries"><![CDATA[Answers]]></string>
+	<string name="_bx_polls_page_block_title_entry_text"><![CDATA[Description]]></string>
+        <string name="_bx_polls_page_block_title_entry_text_and_subentries"><![CDATA[Description and Answers]]></string>
+	<string name="_bx_polls_page_title_browse"><![CDATA[Polls]]></string>
+	<string name="_bx_polls_page_title_search_results"><![CDATA[Polls matching "{0}"]]></string>
+	<string name="_bx_polls_page_title_browse_by_author"><![CDATA[Polls of {display_name}]]></string>
+	<string name="_bx_polls_page_title_browse_by_context"><![CDATA[Polls in {display_name}]]></string>
+	<string name="_bx_polls_page_title_browse_featured"><![CDATA[Featured Polls]]></string>
+    <string name="_bx_polls_page_title_browse_recent"><![CDATA[Latest Polls]]></string>
+    <string name="_bx_polls_page_title_browse_popular"><![CDATA[Popular Polls]]></string>
+    <string name="_bx_polls_page_title_browse_top"><![CDATA[Top]]></string>
+    <string name="_bx_polls_page_title_browse_updated"><![CDATA[Updated Polls]]></string>
+    <string name="_bx_polls_page_title_sys_home"><![CDATA[Polls Home]]></string>
+    <string name="_bx_polls_page_title_home"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_page_block_title_featured_entries"><![CDATA[Featured Polls]]></string>
+    <string name="_bx_polls_page_block_title_recent_entries"><![CDATA[Latest Polls]]></string>
+    <string name="_bx_polls_page_block_title_recent_entries_view_full"><![CDATA[Latest Polls (Full View)]]></string>
+    <string name="_bx_polls_page_block_title_entry_social_sharing"><![CDATA[Share]]></string>
+    <string name="_bx_polls_page_block_title_entry_author"><![CDATA[Author]]></string>
+    <string name="_bx_polls_page_block_title_entry_actions"><![CDATA[Actions]]></string>
+    <string name="_bx_polls_page_block_title_entry_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_polls_page_block_title_entry_comments_link"><![CDATA[Comments to <a href="{entry_link}">{title}</a>]]></string>
+    <string name="_bx_polls_page_block_title_entry_location"><![CDATA[Location]]></string>
+    <string name="_bx_polls_page_block_title_entry_attachments"><![CDATA[Attachments]]></string>
+    <string name="_bx_polls_page_block_title_entry_all_actions"><![CDATA[All Actions]]></string>
+    <string name="_bx_polls_page_title_sys_entries_popular"><![CDATA[Popular Polls]]></string>
+    <string name="_bx_polls_page_title_entries_popular"><![CDATA[Popular Polls]]></string>
+    <string name="_bx_polls_page_title_sys_entries_top"><![CDATA[Top Polls]]></string>
+    <string name="_bx_polls_page_title_entries_top"><![CDATA[Top Polls]]></string>
+    <string name="_bx_polls_page_title_sys_entries_updated"><![CDATA[Updated Polls]]></string>
+    <string name="_bx_polls_page_title_entries_updated"><![CDATA[Updated Polls]]></string>
+    <string name="_bx_polls_page_block_title_popular_entries"><![CDATA[Popular Polls]]></string>
+    <string name="_bx_polls_page_block_title_popular_entries_view_full"><![CDATA[Popular Polls (Full View)]]></string>
+    <string name="_bx_polls_page_block_title_top_entries"><![CDATA[Top Polls]]></string>
+    <string name="_bx_polls_page_block_title_updated_entries"><![CDATA[Updated Polls]]></string>
+    <string name="_bx_polls_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string>
+    <string name="_bx_polls_page_block_title_favorites_entries_info"><![CDATA[Info]]></string>
+    <string name="_bx_polls_page_title_sys_view_entry_comments"><![CDATA[Poll Comments]]></string>
+    <string name="_bx_polls_page_title_view_entry_comments"><![CDATA[Comments to {title}]]></string>
+    <string name="_bx_polls_page_title_sys_entries_of_author"><![CDATA[Polls of author]]></string>
+    <string name="_bx_polls_page_title_entries_of_author"><![CDATA[Polls by {display_name}]]></string>
+    <string name="_bx_polls_page_title_sys_entries_in_context"><![CDATA[Polls in context]]></string>
+    <string name="_bx_polls_page_title_entries_in_context"><![CDATA[Polls in {display_name}]]></string>
+    <string name="_bx_polls_page_block_title_favorites_of_author"><![CDATA[Favorites by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_polls_page_block_title_sys_favorites_of_author"><![CDATA[Favorites of author]]></string>
+    <string name="_bx_polls_page_block_title_entries_of_author"><![CDATA[Polls by <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_polls_page_block_title_sys_entries_of_author"><![CDATA[Polls of author]]></string>
+    <string name="_bx_polls_page_block_title_entries_in_context"><![CDATA[Polls in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_polls_page_block_title_sys_entries_in_context"><![CDATA[Polls in context]]></string>
+    <string name="_bx_polls_page_block_title_entries_actions"><![CDATA[Polls actions]]></string>
+    <string name="_bx_polls_page_block_title_browse_cmts"><![CDATA[Polls' Comments]]></string>
+    <string name="_bx_polls_page_title_sys_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_polls_page_title_sys_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_polls_page_title_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_polls_page_block_title_system_manage"><![CDATA[Manage Own]]></string>
+    <string name="_bx_polls_page_block_title_system_manage_administration"><![CDATA[Manage All]]></string>
+    <string name="_bx_polls_page_block_title_manage"><![CDATA[Manage]]></string>    
+    <string name="_bx_polls_page_block_title_popular_keywords"><![CDATA[Popular Hashtags]]></string>
+    <string name="_bx_polls_page_block_title_cats"><![CDATA[Polls Categories]]></string>
+    <string name="_bx_polls_page_block_title_entry_info"><![CDATA[Info]]></string>
+    <string name="_bx_polls_page_block_title_sys_my_entries"><![CDATA[User Polls]]></string>
+    <string name="_bx_polls_page_block_title_my_entries"><![CDATA[{display_name} Polls]]></string>
+    <string name="_bx_polls_page_title_sys_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_polls_page_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_polls_page_title_sys_entries_favorites"><![CDATA[Favorives Polls]]></string>
+    <string name="_bx_polls_page_title_entries_favorites"><![CDATA[Favorives Polls]]></string>
+    <string name="_bx_polls_page_block_title_search_form"><![CDATA[Search Form]]></string>
+    <string name="_bx_polls_page_block_title_search_results"><![CDATA[Search Results]]></string>
+    <string name="_bx_polls_page_block_title_search_form_cmts"><![CDATA[Comments Search Form]]></string>
+    <string name="_bx_polls_page_block_title_search_results_cmts"><![CDATA[Comments Search Results]]></string>
+    <string name="_bx_polls_page_block_title_sys_recent_entries_view_showcase"><![CDATA[Latest Polls (Showcase View)]]></string>
+    <string name="_bx_polls_page_block_title_recent_entries_view_showcase"><![CDATA[Latest Polls]]></string>
+    <string name="_bx_polls_page_block_title_sys_popular_entries_view_showcase"><![CDATA[Popular Polls (Showcase View)]]></string>
+    <string name="_bx_polls_page_block_title_popular_entries_view_showcase"><![CDATA[Popular Polls]]></string>
+    <string name="_bx_polls_page_block_title_sys_featured_entries_view_showcase"><![CDATA[Featured Polls (Showcase View)]]></string>
+    <string name="_bx_polls_page_block_title_featured_entries_view_showcase"><![CDATA[Featured Polls]]></string>
+    <string name="_bx_polls_page_block_title_sys_entry_context"><![CDATA[Posted in]]></string>
+    <string name="_bx_polls_page_block_title_entry_context"><![CDATA[Posted in]]></string>
+
+    <string name="_bx_polls_menu_set_title_view_entry"><![CDATA[Poll Actions]]></string>
+    <string name="_bx_polls_menu_title_view_entry"><![CDATA[Poll Actions]]></string>
+    <string name="_bx_polls_menu_title_submenu"><![CDATA[Polls Submenu]]></string>
+    <string name="_bx_polls_menu_set_title_submenu"><![CDATA[Polls Submenu]]></string>
+    <string name="_bx_polls_menu_item_title_system_create_entry"><![CDATA[Poll]]></string>
+    <string name="_bx_polls_menu_item_title_create_entry"><![CDATA[Poll]]></string>
+    <string name="_bx_polls_menu_item_title_system_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_polls_menu_item_title_edit_entry"><![CDATA[Edit]]></string>
+    <string name="_bx_polls_menu_item_title_system_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_polls_menu_item_title_delete_entry"><![CDATA[Delete]]></string>
+    <string name="_bx_polls_menu_item_title_system_view_entry"><![CDATA[View Poll]]></string>
+    <string name="_bx_polls_menu_item_title_system_entries_home"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_menu_item_title_entries_home"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_menu_item_title_system_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_polls_menu_item_title_entries_public"><![CDATA[Latest]]></string>
+    <string name="_bx_polls_menu_item_title_system_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_polls_menu_item_title_entries_search"><![CDATA[Search]]></string>
+    <string name="_bx_polls_menu_item_title_system_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_polls_menu_item_title_entries_manage"><![CDATA[Manage]]></string>
+    <string name="_bx_polls_menu_item_title_system_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_polls_menu_item_title_entries_popular"><![CDATA[Popular]]></string>
+    <string name="_bx_polls_menu_item_title_system_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_polls_menu_item_title_entries_top"><![CDATA[Top]]></string>
+    <string name="_bx_polls_menu_title_view_entry_submenu"><![CDATA[View Poll Submenu]]></string>
+    <string name="_bx_polls_menu_set_title_view_entry_submenu"><![CDATA[View Poll Submenu]]></string>
+    <string name="_bx_polls_menu_item_title_view_entry_submenu_entry"><![CDATA[Poll]]></string>
+    <string name="_bx_polls_menu_item_title_view_entry_submenu_comments"><![CDATA[Comments]]></string>
+    <string name="_bx_polls_menu_item_title_system_view_entry_comments"><![CDATA[Poll Comments]]></string>
+    <string name="_bx_polls_menu_item_title_system_view_entries_author"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_menu_item_title_view_entries_author"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_menu_item_title_system_view_entries_in_context"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_menu_item_title_view_entries_in_context"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_menu_title_entries_my"><![CDATA[My Polls Action Menu]]></string>
+    <string name="_bx_polls_menu_set_title_entries_my"><![CDATA[My Polls Menu]]></string>
+	<string name="_bx_polls_menu_item_title_system_manage_my_polls"><![CDATA[My polls]]></string>
+    <string name="_bx_polls_menu_item_title_manage_my_polls"><![CDATA[Polls]]></string>
+    <string name="_bx_polls_menu_set_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_polls_menu_title_manage_tools"><![CDATA[Manage Tools Submenu]]></string>
+    <string name="_bx_polls_menu_item_title_system_manage_account"><![CDATA[Manage account]]></string>
+    <string name="_bx_polls_menu_item_title_manage_account"><![CDATA[Manage account]]></string>
+	<string name="_bx_polls_menu_item_title_system_admt_polls"><![CDATA[Polls]]></string>
+	<string name="_bx_polls_menu_item_title_admt_polls"><![CDATA[Polls]]></string>
+	<string name="_bx_polls_menu_item_title_manage_my"><![CDATA[My Polls]]></string>
+	<string name="_bx_polls_menu_item_title_manage_all"><![CDATA[All Polls]]></string>
+	<string name="_bx_polls_menu_item_view_subentries"><![CDATA[View Poll]]></string>
+	<string name="_bx_polls_menu_item_view_results"><![CDATA[View Results]]></string>
+	
+
+	<string name="_bx_polls_grid_filter_item_title_adm_select_one_filter1"><![CDATA[All Statuses]]></string>
+	<string name="_bx_polls_grid_filter_item_title_adm_active"><![CDATA[Active]]></string>
+	<string name="_bx_polls_grid_filter_item_title_adm_hidden"><![CDATA[Hidden]]></string>
+	<string name="_bx_polls_grid_column_title_adm_active"><![CDATA[Active]]></string>
+    <string name="_bx_polls_grid_column_title_adm_title"><![CDATA[Title]]></string>
+    <string name="_bx_polls_grid_column_title_adm_added"><![CDATA[Added]]></string>
+    <string name="_bx_polls_grid_column_title_adm_author"><![CDATA[Author]]></string>
+    <string name="_bx_polls_grid_action_title_adm_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_polls_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_polls_grid_action_title_adm_more_actions"><![CDATA[More Actions]]></string>
+    <string name="_bx_polls_grid_action_title_adm_audit_content"><![CDATA[Audit actions]]></string>
+    <string name="_bx_polls_grid_action_title_adm_clear_reports"><![CDATA[Clear reports]]></string>
+    <string name="_bx_polls_grid_action_err_delete"><![CDATA[Cannot delete the selected poll(s).]]></string>
+    <string name="_bx_polls_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+
+    <string name="_bx_polls_chart_growth"><![CDATA[Polls: Growth]]></string>
+    <string name="_bx_polls_chart_growth_speed"><![CDATA[Polls: Growth Speed]]></string>
+
+    <string name="_bx_polls_search_extended"><![CDATA[Polls Search]]></string>
+    <string name="_bx_polls_search_extended_cmts"><![CDATA[Polls Comments Search]]></string>
+
+    <string name="_bx_polls_pre_lists_cats"><![CDATA[Poll categories]]></string>
+    <string name="_bx_polls_cat_beauty_and_style"><![CDATA[Beauty & Style]]></string>
+    <string name="_bx_polls_cat_business_and_money"><![CDATA[Business & Money]]></string>
+    <string name="_bx_polls_cat_cars_and_transportation"><![CDATA[Cars & Transportation]]></string>
+    <string name="_bx_polls_cat_computers_and_internet"><![CDATA[Computers & Internet]]></string>
+    <string name="_bx_polls_cat_food_and_dining"><![CDATA[Food & Dining]]></string>
+    <string name="_bx_polls_cat_education"><![CDATA[Education]]></string>
+    <string name="_bx_polls_cat_electronics"><![CDATA[Electronics]]></string>
+    <string name="_bx_polls_cat_entertainment"><![CDATA[Entertainment]]></string>
+    <string name="_bx_polls_cat_family_and_relationships"><![CDATA[Family & Relationships]]></string>
+    <string name="_bx_polls_cat_games"><![CDATA[Games]]></string>
+    <string name="_bx_polls_cat_health_and_fitness"><![CDATA[Health & Fitness]]></string>
+    <string name="_bx_polls_cat_home_and_garden"><![CDATA[Home & Garden]]></string>
+    <string name="_bx_polls_cat_news_and_events"><![CDATA[News & Events]]></string>
+    <string name="_bx_polls_cat_pets"><![CDATA[Pets]]></string>
+    <string name="_bx_polls_cat_politics_and_government"><![CDATA[Politics & Government]]></string>
+    <string name="_bx_polls_cat_pregnancy_and_parenting"><![CDATA[Pregnancy & Parenting]]></string>
+    <string name="_bx_polls_cat_sports"><![CDATA[Sports]]></string>
+    <string name="_bx_polls_cat_misc"><![CDATA[Misc]]></string>
+    <string name="_bx_polls_cat_would_you_rather"><![CDATA[Would You Rather]]></string>
+    <string name="_bx_polls_cat_yes_or_no"><![CDATA[Yes or No]]></string>
+
+    <string name="_bx_polls_txt_all_entries_by"><![CDATA[{0} polls]]></string>
+    <string name="_bx_polls_txt_all_entries_in"><![CDATA[<a href="{0}">All Polls in {1} ({2})</a>]]></string>
+    <string name="_bx_polls_txt_sample_single"><![CDATA[poll]]></string>
+    <string name="_bx_polls_txt_sample_single_with_article"><![CDATA[a poll]]></string>
+    <string name="_bx_polls_txt_sample_comment_single"><![CDATA[comment to poll]]></string>
+    <string name="_bx_polls_txt_sample_vote_single"><![CDATA[vote to poll]]></string>
+    <string name="_bx_polls_txt_sample_reaction_single"><![CDATA['{0}' reaction to poll]]></string>
+    <string name="_bx_polls_txt_sample_score_up_single"><![CDATA[score up vote to poll]]></string>
+    <string name="_bx_polls_txt_sample_score_down_single"><![CDATA[score down vote to poll]]></string>
+    <string name="_bx_polls_txt_subentry_vote_do_by"><![CDATA[Voted for]]></string>
+    <string name="_bx_polls_txt_subentry_vote_counter"><![CDATA[{0} votes]]></string>
+    <string name="_bx_polls_txt_subentry_vote_percent"><![CDATA[({0}%)]]></string>
+    <string name="_bx_polls_msg_public_voting"><![CDATA[This voting is public, your choice will be displayed for others.]]></string>
+</resources>

+ 48 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/disable.sql

@@ -0,0 +1,48 @@
+
+-- SETTINGS
+SET @iTypeId = (SELECT `ID` FROM `sys_options_types` WHERE `name` = 'bx_polls' 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_polls';
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_polls' OR `object` IN('bx_polls_create_entry', 'bx_polls_edit_entry', 'bx_polls_delete_entry', 'bx_polls_view_entry', 'bx_polls_view_entry_comments', 'bx_polls_home', 'bx_polls_popular', 'bx_polls_top', 'bx_polls_updated', 'bx_polls_author', 'bx_polls_search', 'bx_polls_context', 'bx_polls_manage');
+
+-- MENU
+DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_polls';
+DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_polls';
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_polls' OR `set_name` IN('bx_polls_view', 'bx_polls_view_actions', 'bx_polls_submenu', 'bx_polls_view_submenu', 'bx_polls_snippet_meta', 'bx_polls_my', 'bx_polls_menu_manage_tools');
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object` IN ('bx_polls_allow_view_to', 'bx_polls_allow_view_favorite_list');
+
+-- 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_polls';
+DELETE FROM `sys_acl_actions` WHERE `Module` = 'bx_polls';
+
+-- SEARCH
+DELETE FROM `sys_objects_search` WHERE `ObjectName` IN ('bx_polls', 'bx_polls_cmts');
+
+-- METATAGS
+DELETE FROM `sys_objects_metatags` WHERE `object` = 'bx_polls';
+
+-- CATEGORY
+DELETE FROM `sys_objects_category` WHERE `object` = 'bx_polls_cats';
+
+-- STATS
+DELETE FROM `sys_statistics` WHERE `name` LIKE 'bx_polls%';
+
+-- CHARTS
+DELETE FROM `sys_objects_chart` WHERE `object` LIKE 'bx_polls%';
+
+-- GRIDS
+DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_polls_administration', 'bx_polls_common');
+DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_polls_administration', 'bx_polls_common');
+DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_polls_administration', 'bx_polls_common');
+
+-- ALERTS
+SET @iHandler := (SELECT `id` FROM `sys_alerts_handlers` WHERE `name` = 'bx_polls' LIMIT 1);
+DELETE FROM `sys_alerts` WHERE `handler_id` = @iHandler;
+DELETE FROM `sys_alerts_handlers` WHERE `id` = @iHandler;

+ 465 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/enable.sql

@@ -0,0 +1,465 @@
+
+-- 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_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', 3, 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);
+
+
+-- 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`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_polls_favorites', 2, 'bx_polls', '_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);
+
+-- 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', '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', 'social-sharing-facebook', '_sys_menu_item_title_system_social_sharing_facebook', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 300),
+('bx_polls_view_actions', 'bx_polls', 'social-sharing-twitter', '_sys_menu_item_title_system_social_sharing_twitter', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 320),
+('bx_polls_view_actions', 'bx_polls', 'social-sharing-pinterest', '_sys_menu_item_title_system_social_sharing_pinterest', '', '', '', '', '', '', '', 0, 2147483647, 1, 0, 330),
+('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-manage-polls', '_bx_polls_menu_item_title_system_manage_my_polls', '_bx_polls_menu_item_title_manage_my_polls', 'page.php?i=polls-manage', '', '_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();
+
+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);
+
+
+-- 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`, `table_keywords`, `table_locations`, `table_mentions`, `override_class_name`, `override_class_file`) VALUES
+('bx_polls', 'bx_polls_meta_keywords', 'bx_polls_meta_locations', 'bx_polls_meta_mentions', '', '');
+
+-- CATEGORY
+INSERT INTO `sys_objects_category` (`object`, `search_object`, `form_object`, `list_name`, `table`, `field`, `join`, `where`, `override_class_name`, `override_class_file`) VALUES
+('bx_polls_cats', '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', '30%', 1, '25', '', 4),
+('bx_polls_common', 'actions', '', '20%', 0, '', '', 5);
+
+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);
+

+ 435 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/install.sql

@@ -0,0 +1,435 @@
+
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+-- 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',
+  `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') 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',
+  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` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+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` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  `sum` int(11) NOT NULL default '0',
+  UNIQUE KEY `object_id` (`object_id`)
+);
+
+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` (
+  `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',
+  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` (
+  `object_id` int(11) NOT NULL default '0',
+  `viewer_id` int(11) NOT NULL default '0',
+  `viewer_nip` int(11) unsigned NOT NULL default '0',
+  `date` int(11) NOT NULL default '0',
+  KEY `id` (`object_id`,`viewer_id`,`viewer_nip`)
+);
+
+-- TABLE: metas
+CREATE TABLE `bx_polls_meta_keywords` (
+  `object_id` int(10) unsigned NOT NULL,
+  `keyword` varchar(255) NOT NULL,
+  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` (
+  `object_id` int(10) unsigned NOT NULL,
+  `profile_id` int(10) unsigned NOT NULL,
+  KEY `object_id` (`object_id`),
+  KEY `profile_id` (`profile_id`)
+);
+
+-- TABLE: reports
+CREATE TABLE IF NOT EXISTS `bx_polls_reports` (
+  `object_id` int(11) NOT NULL default '0',
+  `count` int(11) NOT NULL default '0',
+  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',
+  PRIMARY KEY (`id`),
+  KEY `report` (`object_id`, `author_nip`)
+);
+
+-- TABLE: favorites
+CREATE TABLE `bx_polls_favorites_track` (
+  `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',
+  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` (
+  `object_id` int(11) NOT NULL default '0',
+  `count_up` int(11) NOT NULL default '0',
+  `count_down` int(11) NOT NULL default '0',
+  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
+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', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0),
+('bx_polls_photos_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_polls_photos_resized', 'allow-deny', 'jpg,jpeg,jpe,gif,png', '', 0, 0, 0, 0, 0, 0);
+
+INSERT INTO `sys_objects_transcoder` (`object`, `storage_object`, `source_type`, `source_params`, `private`, `atime_tracking`, `atime_pruning`, `ts`) VALUES 
+('bx_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:"2000";}', '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', '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', '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:2:{s:10:"sys_simple";s:26:"_sys_uploader_simple_title";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', 'anonymous', 2147483647, 1, 6),
+('bx_polls_entry_add', 'hidden_results', 2147483647, 1, 7),
+('bx_polls_entry_add', 'location', 2147483647, 1, 8),
+('bx_polls_entry_add', 'do_publish', 2147483647, 1, 9),
+
+('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', 'hidden_results', 2147483647, 1, 6),
+('bx_polls_entry_edit', 'location', 2147483647, 1, 7),
+('bx_polls_entry_edit', 'do_submit', 2147483647, 1, 8),
+
+('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', 'comments', '', '');
+
+
+-- VOTES
+INSERT INTO `sys_objects_vote` (`Name`, `TableMain`, `TableTrack`, `PostTimeout`, `MinValue`, `MaxValue`, `IsUndo`, `IsOn`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldRate`, `TriggerFieldRateCount`, `ClassName`, `ClassFile`) VALUES 
+('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_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_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`, `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_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));

+ 68 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/install/sql/uninstall.sql

@@ -0,0 +1,68 @@
+
+-- TABLES
+DROP TABLE IF EXISTS `bx_polls_entries`, `bx_polls_subentries`, `bx_polls_files`, `bx_polls_photos_resized`, `bx_polls_cmts`, `bx_polls_cmts_notes`, `bx_polls_votes`, `bx_polls_votes_track`, `bx_polls_votes_subentries`, `bx_polls_votes_subentries_track`, `bx_polls_reactions`, `bx_polls_reactions_track`, `bx_polls_views_track`, `bx_polls_meta_keywords`, `bx_polls_meta_locations`, `bx_polls_meta_mentions`, `bx_polls_reports`, `bx_polls_reports_track`, `bx_polls_favorites_track`, `bx_polls_favorites_lists`, `bx_polls_scores`, `bx_polls_scores_track`;
+
+
+-- STORAGES & TRANSCODERS
+DELETE FROM `sys_objects_storage` WHERE `object` = 'bx_polls_files' OR `object` = 'bx_polls_photos_resized';
+DELETE FROM `sys_storage_tokens` WHERE `object` = 'bx_polls_files' OR `object` = 'bx_polls_photos_resized';
+
+DELETE FROM `sys_objects_transcoder` WHERE `object` IN('bx_polls_preview', 'bx_polls_gallery', 'bx_polls_cover');
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object` IN('bx_polls_preview', 'bx_polls_gallery', 'bx_polls_cover');
+DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` IN('bx_polls_preview', 'bx_polls_gallery', 'bx_polls_cover');
+
+
+-- FORMS
+DELETE FROM `sys_objects_form` WHERE `module` = 'bx_polls';
+DELETE FROM `sys_form_displays` WHERE `module` = 'bx_polls';
+DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_polls';
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN ('bx_polls_entry_add', 'bx_polls_entry_edit', 'bx_polls_entry_view', 'bx_polls_entry_delete');
+
+
+-- PRE-VALUES
+DELETE FROM `sys_form_pre_lists` WHERE `module` = 'bx_polls';
+DELETE FROM `sys_form_pre_values` WHERE `Key` IN('bx_polls_cats');
+
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name` LIKE 'bx_polls%';
+
+
+-- VOTES
+DELETE FROM `sys_objects_vote` WHERE `Name` LIKE 'bx_polls%';
+
+
+-- SCORES
+DELETE FROM `sys_objects_score` WHERE `name` = 'bx_polls';
+
+
+-- REPORTS
+DELETE FROM `sys_objects_report` WHERE `name` = 'bx_polls';
+
+
+-- VIEWS
+DELETE FROM `sys_objects_view` WHERE `name` = 'bx_polls';
+
+
+-- FAFORITES
+DELETE FROM `sys_objects_favorite` WHERE `name` = 'bx_polls';
+
+
+-- FEATURED
+DELETE FROM `sys_objects_feature` WHERE `name` = 'bx_polls';
+
+
+-- CONTENT INFO
+DELETE FROM `sys_objects_content_info` WHERE `name` IN ('bx_polls', 'bx_polls_cmts');
+
+DELETE FROM `sys_content_info_grids` WHERE `object` IN ('bx_polls');
+
+
+-- SEARCH EXTENDED
+DELETE FROM `sys_objects_search_extended` WHERE `module` = 'bx_polls';
+
+
+-- 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_polls';

+ 130 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/js/entry.js

@@ -0,0 +1,130 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Polls Polls
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxPollsEntry(oOptions) {
+    this._sActionsUrl = oOptions.sActionUrl;
+    this._sObjName = oOptions.sObjName == undefined ? 'oBxPollsEntry' : oOptions.sObjName;
+
+    this._bEmbed = oOptions.bEmbed == undefined ? false : oOptions.bEmbed;
+
+    this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
+    this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+
+    this._aHtmlIds = oOptions.aHtmlIds == undefined ? {} : oOptions.aHtmlIds;
+    this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
+    
+    var $this = this;
+    if(this._bEmbed)
+        $(document).ready(function() {
+            $this.resizeEmbed();
+        });
+}
+
+BxPollsEntry.prototype.resizeEmbed = function() {
+    var oEntry = $('.bx-polls-content:last');
+    if(!oEntry || oEntry.length == 0)
+        return;
+
+    var iEntryId = parseInt(oEntry.attr('id').replace(this._aHtmlIds['content'], ''));
+    var iEntryHeight = oEntry.height();
+    if(!iEntryId || !iEntryHeight)
+        return;
+
+    window.parent.$('iframe#' + this._aHtmlIds['embed'] + iEntryId).height(iEntryHeight);
+};
+
+BxPollsEntry.prototype.changeBlockSnippet = function(oLink, sBlock, mixedContent) {
+    var $this = this;
+
+    this.changeBlock(oLink, sBlock, mixedContent, function(iContentId, oData) {
+        $(oLink).hide().siblings('.bx-base-text-unit-switcher:hidden').show();
+
+        $(oLink).parents('.bx-base-text-unit:first').find('#' + $this._aHtmlIds['content'] + iContentId).bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+            $(this).replaceWith(oData.content);
+        });
+    });
+};
+
+BxPollsEntry.prototype.changeBlock = function(oLink, sBlock, mixedContent, onComplete) {
+    var $this = this;
+
+    this.loadingInBlock(oLink, true);
+
+    if(typeof onComplete !== 'function')
+        onComplete = function(iContentId, oData) {
+            var sContentId = $this._aHtmlIds['content'] + iContentId;
+
+            var oContent = $(oLink).parents('.bx-db-container:first').find('#' + sContentId);
+            if(!oContent.length)
+                oContent = $('#' + sContentId);
+            if(!oContent.length)
+                return;
+
+            oContent.bx_anim('hide', $this._sAnimationEffect, $this._iAnimationSpeed, function() {
+                $(this).replaceWith(oData.content);
+            });
+        };
+
+    var iContentId = 0;
+    var oParams = {
+        block: sBlock,
+    };
+
+    switch(typeof mixedContent) {
+        case 'number':
+            iContentId = parseInt(mixedContent);
+            oParams['content_id'] = iContentId;
+            break;
+
+        case 'object':
+            iContentId = parseInt(mixedContent.content_id);
+            oParams = $.extend({}, oParams, mixedContent); 
+            break;
+    }
+
+    jQuery.get (
+        this._sActionsUrl + 'get_block',
+        oParams,
+        function(oData) {
+            if(oLink)
+                $this.loadingInBlock(oLink, false);
+
+            if(!oData.content)
+                return;
+
+            if(typeof onComplete === 'function')
+                onComplete(iContentId, oData);
+        },
+        'json'
+    );
+};
+
+BxPollsEntry.prototype.onVote = function(oLink, oData, iContentId, sSalt) {
+    //--- Check for block submenu (tabs)
+    var oMenuLink = $('#' + this._aHtmlIds['block_link_results'] + sSalt);
+    if(oMenuLink.length > 0) {
+        oMenuLink.click();
+        return;
+    }
+
+    //--- Check for snippet meta submenu
+    var oMenuLink = $('#' + this._aHtmlIds['snippet_link_results'] + sSalt);
+    if(oMenuLink.length > 0) {
+        oMenuLink.click();
+        return;
+    }
+
+    this.changeBlock(oLink, 'results', {content_id: iContentId, salt: sSalt});
+};
+
+BxPollsEntry.prototype.loadingInBlock = function(e, bShow) {
+    var oParent = $(e).length ? $(e).parents('.bx-db-container:first') : $('body'); 
+    bx_loading(oParent, bShow);
+};

+ 138 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/template/css/entry.css

@@ -0,0 +1,138 @@
+/*--- Embed ---*/
+.bx-page-iframe .bx-polls-content {
+    width: 100vw;
+    overflow-x: hidden;
+    overflow-y: auto;
+}
+
+/*--- Text and Subentries ---*/
+.bx-polls-entity-actions {
+    position: relative;
+    width: 100%;
+}
+.bx-polls-entity-actions .bx-db-menu {
+    position: absolute;
+    top: 0;
+    right: 0;
+    line-height: normal;
+}
+.bx-polls-entity-actions .bx-db-menu-tab {
+    display: inline-block;
+    float: none;
+    margin: 0;
+}
+.bx-polls-entity-actions .bx-polls-menu-db {
+    position: relative;
+    display: block;
+    margin: 0;
+    padding: 1rem;
+}
+
+.bx-pull-combined-entity-content {
+    padding-right: 3.5rem;
+}
+
+
+/*--- Results ---*/
+div.bx-polls-result-graph {
+	display: table;
+	width: 100%;
+}
+div.bx-polls-result-graph .bx-polls-rg-bar,
+div.bx-polls-result-graph .bx-polls-rg-text {
+	display: table-cell;
+}
+div.bx-polls-result-graph .bx-polls-rg-bar {
+    -webkit-animation-fill-mode: both;
+    -moz-animation-fill-mode: both;
+    -o-animation-fill-mode: both;
+    animation-fill-mode: both;
+
+    -webkit-transform-origin: left;
+    -moz-transform-origin: left;
+    -ms-transform-origin: left;
+    -o-transform-origin: left;
+    transform-origin: left;
+
+    -webkit-animation: votes-bar 1000ms ease-out;
+    -o-animation: votes-bar 1000ms ease-out;
+    animation: votes-bar 1000ms ease-out;
+
+    background: #2196F3;
+    background: -moz-linear-gradient(left,#2196F3 0%,#1976D2 100%);
+    background: -webkit-gradient(linear,left top,right top,color-stop(0%,#2196F3),color-stop(100%,#1976D2));
+    background: -webkit-linear-gradient(left,#2196F3 0%,#1976D2 100%);
+    background: -o-linear-gradient(left,#2196F3 0%,#1976D2 100%);
+    background: -ms-linear-gradient(left,#2196F3 0%,#1976D2 100%);
+    background: linear-gradient(to right,#2196F3 0%,#1976D2 100%);
+    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#2196F3',endColorstr='#1976D2',GradientType=1);
+}
+div.bx-polls-result-graph .bx-polls-rg-text {
+	white-space: nowrap;
+}
+
+/*--- Animation ---*/
+@-webkit-keyframes votes-bar {
+    from {
+        -webkit-transform:scaleX(0);
+        -moz-transform:scaleX(0);
+        -ms-transform:scaleX(0);
+        -o-transform:scaleX(0);
+        transform:scaleX(0)
+    }
+    to {
+        -webkit-transform:scaleX(1);
+        -moz-transform:scaleX(1);
+        -ms-transform:scaleX(1);
+        -o-transform:scaleX(1);
+        transform:scaleX(1)
+    }
+}
+@-moz-keyframes votes-bar {
+    from {
+        -webkit-transform:scaleX(0);
+        -moz-transform:scaleX(0);
+        -ms-transform:scaleX(0);
+        -o-transform:scaleX(0);
+        transform:scaleX(0)
+    }
+    to {
+        -webkit-transform:scaleX(1);
+        -moz-transform:scaleX(1);
+        -ms-transform:scaleX(1);
+        -o-transform:scaleX(1);
+        transform:scaleX(1)
+    }
+}
+@-ms-keyframes votes-bar {
+    from {
+        -webkit-transform:scaleX(0);
+        -moz-transform:scaleX(0);
+        -ms-transform:scaleX(0);
+        -o-transform:scaleX(0);
+        transform:scaleX(0)
+    }
+    to {
+        -webkit-transform:scaleX(1);
+        -moz-transform:scaleX(1);
+        -ms-transform:scaleX(1);
+        -o-transform:scaleX(1);
+        transform:scaleX(1)
+    }
+}
+@keyframes votes-bar {
+    from {
+        -webkit-transform:scaleX(0);
+        -moz-transform:scaleX(0);
+        -ms-transform:scaleX(0);
+        -o-transform:scaleX(0);
+        transform:scaleX(0)
+    }
+    to {
+        -webkit-transform:scaleX(1);
+        -moz-transform:scaleX(1);
+        -ms-transform:scaleX(1);
+        -o-transform:scaleX(1);
+        transform:scaleX(1)
+    }
+}

+ 1 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/template/favorite-list-info.html

@@ -0,0 +1 @@
+<bx_include_base:../modules/base/general/template/favorite-list-info.html />

+ 1 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/template/favorite-lists.html

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

+ 1 - 0
modules/boonex/polls/updates/11.0.1_12.0.0/source/template/unit_embed.html

@@ -0,0 +1 @@
+<iframe id="__html_id__" class="bx-polls-embed" src="__embed_url__" frameborder="0"></iframe>

+ 53 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/install/config.php

@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'title' => 'Posts',
+    'version_from' => '11.0.2',
+    'version_to' => '12.0.0',
+    'vendor' => 'BoonEx',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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_11.0.2_12.0.0/',
+    'home_uri' => 'posts_update_1102_1200',
+
+    '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(
+        'js/categories.js',
+    ),
+);

+ 26 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/install/installer.php

@@ -0,0 +1,26 @@
+<?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);
+    }
+
+    public function actionExecuteSql($sOperation)
+    {
+        if($sOperation == 'install') {
+            if(!$this->oDb->isFieldExists('bx_posts_cmts', 'cmt_pinned'))
+                $this->oDb->query("ALTER TABLE `bx_posts_cmts` ADD `cmt_pinned` int(11) NOT NULL default '0' AFTER `cmt_replies`");
+
+            if(!$this->oDb->isFieldExists('bx_posts_favorites_track', 'list_id'))
+                $this->oDb->query("ALTER TABLE `bx_posts_favorites_track` ADD `list_id` int(11) NOT NULL default '0' AFTER `author_id`");
+        }
+
+        return parent::actionExecuteSql($sOperation);
+    }
+}

+ 21 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/install/langs/en.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources name="en" flag="gb" title="English">
+	<string_add name="_bx_posts_option_per_page_for_favorites_lists"><![CDATA[Number of favorite lists per page]]></string_add>
+	<string_add name="_bx_posts_form_entry_input_sys_sounds"><![CDATA[Sounds]]></string_add>
+	<string_add name="_bx_posts_form_entry_input_sounds"><![CDATA[]]></string_add>
+	<string_add name="_bx_posts_form_entry_input_allow_view_favorite_list"><![CDATA[Visibility]]></string_add>
+	<string_add name="_bx_posts_page_title_sys_entries_favorites"><![CDATA[Favorives Posts]]></string_add>
+	<string_add name="_bx_posts_page_title_entries_favorites"><![CDATA[Favorives Posts]]></string_add>
+	<string_add name="_bx_posts_page_block_title_favorites_entries"><![CDATA["{title}" List]]></string_add>
+	<string_add name="_bx_posts_page_block_title_favorites_entries_info"><![CDATA[Info]]></string_add>
+	<string_add name="_bx_posts_page_block_title_sys_my_entries"><![CDATA[User Posts]]></string_add>
+	<string_add name="_bx_posts_menu_item_title_system_cpa_video_record_video"><![CDATA[Record Video]]></string_add>
+	<string_add name="_bx_posts_menu_item_title_cpa_video_record_video"><![CDATA[Record Video]]></string_add>
+	<string_add name="_bx_posts_menu_item_title_system_cpa_sound_simple"><![CDATA[Add Sound (simple)]]></string_add>
+	<string_add name="_bx_posts_menu_item_title_cpa_sound_simple"><![CDATA[Add Sound]]></string_add>
+	<string_add name="_bx_posts_menu_item_title_system_cpa_sound_html5"><![CDATA[Add Sound (html5)]]></string_add>
+	<string_add name="_bx_posts_menu_item_title_cpa_sound_html5"><![CDATA[Add Sound]]></string_add>
+	<string_add name="_bx_posts_grid_action_title_adm_clear_reports"><![CDATA[Ñlear reports]]></string_add>
+
+	<string_upd name="_bx_posts_page_block_title_my_entries"><![CDATA[{display_name} Posts]]></string_upd>
+</resources>

+ 58 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/install/sql/enable.sql

@@ -0,0 +1,58 @@
+-- SETTINGS
+SET @iCategId = (SELECT `id` FROM `sys_options_categories` WHERE `name`='bx_posts' LIMIT 1);
+
+DELETE FROM `sys_options` WHERE `name`='bx_posts_per_page_for_favorites_lists';
+INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_params`, `check_error`, `extra`, `order`) VALUES
+('bx_posts_per_page_for_favorites_lists', '5', @iCategId, '_bx_posts_option_per_page_for_favorites_lists', 'digit', '', '', '', '', 17);
+
+
+-- PAGES
+UPDATE `sys_pages_blocks` SET `content`='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;}}}' WHERE `object`='bx_posts_author' AND `title`='_bx_posts_page_block_title_favorites_of_author';
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_posts_author' AND `title`='_bx_posts_page_block_title_entries_in_context';
+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_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);
+
+DELETE FROM `sys_objects_page` WHERE `object`='bx_posts_favorites';
+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');
+
+DELETE FROM `sys_pages_blocks` WHERE `object`='bx_posts_favorites';
+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_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);
+
+UPDATE `sys_pages_blocks` SET `title_system`='_bx_posts_page_block_title_sys_my_entries' WHERE `module`='bx_posts' AND `title`='_bx_posts_page_block_title_my_entries';
+
+-- MENUS
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_posts_entry_attachments' AND `name` IN ('video_record_video', 'sound_simple', 'sound_html5');
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `editable`, `order`) VALUES 
+('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);
+
+DELETE FROM `sys_menu_items` WHERE `set_name`='bx_posts_view_actions' AND `name`='notes';
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `markers`, `submenu_object`, `submenu_popup`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('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);
+
+
+-- PRIVACY 
+DELETE FROM `sys_objects_privacy` WHERE `object`='bx_posts_allow_view_favorite_list';
+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_favorite_list', 'bx_posts', 'view_favorite_list', '_bx_posts_form_entry_input_allow_view_favorite_list', '3', 'bx_posts_favorites_lists', 'id', 'author_id', '', '');
+
+
+-- GRIDS
+DELETE FROM `sys_grid_actions` WHERE `object`='bx_posts_administration' AND `type` IN ('bulk', 'single') AND `name`='clear_reports';
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_posts_administration', 'bulk', 'clear_reports', '_bx_posts_grid_action_title_adm_clear_reports', '', 0, 1, 1),
+('bx_posts_administration', 'single', 'clear_reports', '_bx_posts_grid_action_title_adm_clear_reports', 'eraser', 1, 0, 5);
+
+-- UPLOADERS
+DELETE FROM `sys_objects_uploader` WHERE `object` IN ('bx_posts_record_video', 'bx_posts_videos_record_video', 'bx_posts_sounds_simple', 'bx_posts_sounds_html5');
+INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
+('bx_posts_record_video', 1, 'BxPostsUploaderRecordVideo', 'modules/boonex/posts/classes/BxPostsUploaderRecordVideo.php'),
+('bx_posts_videos_record_video', 1, 'BxPostsUploaderRecordVideoAttach', 'modules/boonex/posts/classes/BxPostsUploaderRecordVideoAttach.php'),
+('bx_posts_sounds_simple', 1, 'BxPostsUploaderSimpleAttach', 'modules/boonex/posts/classes/BxPostsUploaderSimpleAttach.php'),
+('bx_posts_sounds_html5', 1, 'BxPostsUploaderHTML5Attach', 'modules/boonex/posts/classes/BxPostsUploaderHTML5Attach.php');

+ 116 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/install/sql/install.sql

@@ -0,0 +1,116 @@
+-- TABLES
+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`)
+);
+
+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`)
+);
+
+CREATE TABLE IF NOT EXISTS `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`)
+);
+
+
+-- STORAGES & TRANSCODERS
+SET @sStorageEngine = (SELECT `value` FROM `sys_options` WHERE `name` = 'sys_storage_default');
+
+DELETE FROM `sys_objects_storage` WHERE `object` IN ('bx_posts_sounds', 'bx_posts_sounds_resized');
+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_sounds', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_sounds', 'allow-deny', 'mp3,m4a,m4b,wma,wav,3gp', '', 0, 0, 0, 0, 0, 0),
+('bx_posts_sounds_resized', @sStorageEngine, '', 360, 2592000, 3, 'bx_posts_sounds_resized', 'allow-deny', 'mp3,m4a,m4b,wma,wav,3gp', '', 0, 0, 0, 0, 0, 0);
+
+DELETE FROM `sys_objects_transcoder` WHERE `object`='bx_posts_sounds_mp3';
+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_sounds_mp3', 'bx_posts_sounds_resized', 'Storage', 'a:1:{s:6:"object";s:15:"bx_posts_sounds";}', 'no', '0', '0', '0', 'BxDolTranscoderAudio', '');
+
+UPDATE `sys_transcoder_filters` SET `filter_params`='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";}' WHERE `transcoder_object`='bx_posts_gallery_photos' AND `filter`='Resize';
+UPDATE `sys_transcoder_filters` SET `filter_params`='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";}' WHERE `transcoder_object`='bx_posts_gallery_files' AND `filter`='Resize';
+
+DELETE FROM `sys_transcoder_filters` WHERE `transcoder_object`='bx_posts_sounds_mp3' AND `filter`='Mp3';
+INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_params`, `order`) VALUES 
+('bx_posts_sounds_mp3', 'Mp3', 'a:0:{}', 0);
+
+
+-- FORMS
+UPDATE `sys_form_inputs` SET `value`='a:2:{i:0;s:21:"bx_posts_videos_html5";i:1;s:28:"bx_posts_videos_record_video";}', `values`='a:3:{s:22:"bx_posts_videos_simple";s:26:"_sys_uploader_simple_title";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";}' WHERE `object`='bx_posts' AND `name`='videos';
+
+DELETE FROM `sys_form_inputs` WHERE `object`='bx_posts' AND `name`='sounds';
+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', 'sounds', 'a:1:{i:0;s:21:"bx_posts_sounds_html5";}', 'a:2:{s:22:"bx_posts_sounds_simple";s:26:"_sys_uploader_simple_title";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);
+
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN ('bx_posts_entry_add', 'bx_posts_entry_edit') AND `input_name`='sounds';
+INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
+('bx_posts_entry_add', 'sounds', 2147483647, 1, 8),
+('bx_posts_entry_edit', 'sounds', 2147483647, 1, 9);
+
+
+-- COMMENTS
+DELETE FROM `sys_objects_cmts` WHERE `Name`='bx_posts_notes';
+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`, `ObjectScore`, `ObjectReport`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES
+('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', 'comments', '', '');
+
+
+-- REPORTS
+UPDATE `sys_objects_report` SET `module`='bx_posts', `object_comment`='bx_posts_notes' WHERE `name`='bx_posts';
+
+
+-- FAVORITES
+UPDATE `sys_objects_favorite` SET `table_lists`='bx_posts_favorites_lists' WHERE `name`='bx_posts';
+
+
+-- FEATURED
+UPDATE `sys_objects_feature` SET `module`='bx_posts' WHERE `name`='bx_posts';
+
+
+-- STUDIO PAGE & WIDGET
+SET @iPageId = (SELECT `id` FROM `sys_std_pages` WHERE `name`='bx_posts' LIMIT 1);
+UPDATE `sys_std_widgets` SET `type`='content' WHERE `page_id`=@iPageId;

+ 229 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsConfig.php

@@ -0,0 +1,229 @@
+<?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
+ *
+ * @{
+ */
+
+bx_import('BxDolInformer');
+
+class BxPostsConfig extends BxBaseModTextConfig
+{
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $aMenuItems2Methods = array (
+            '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_TEXT' => 'text',
+            'FIELD_TEXT_ID' => 'post-text',
+            'FIELD_CATEGORY' => 'cat',
+            'FIELD_MULTICAT' => 'multicat',
+            'FIELD_ALLOW_VIEW_TO' => 'allow_view_to',
+            'FIELD_COVER' => 'covers',
+            'FIELD_PHOTO' => 'pictures',
+            'FIELD_VIDEO' => 'videos',
+            'FIELD_SOUND' => 'sounds',
+            'FIELD_FILE' => 'files',
+            'FIELD_POLL' => 'polls',
+            'FIELD_THUMB' => 'thumb',
+            '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_DISABLE_COMMENTS' => 'disable_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
+
+             // some params
+            'PARAM_MULTICAT_ENABLED' => true,
+            'PARAM_MULTICAT_AUTO_ACTIVATION_FOR_CATEGORIES' => 'bx_posts_auto_activation_for_categories',
+            'PARAM_PER_PAGE_FOR_FAVORITES_LISTS' => 'bx_posts_per_page_for_favorites_lists',
+            
+            // 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_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',
+
+            // 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_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_GALLERY_PHOTOS' => 'bx_posts_gallery_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_simple', '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 (
+                '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_select_one_filter1' => '_bx_posts_grid_filter_item_title_adm_select_one_filter1',
+            	'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->_aJsClasses = array_merge($this->_aJsClasses, array(
+            'manage_tools' => 'BxPostsManageTools',
+            'categories' => 'BxDolCategories'
+        ));
+
+        $this->_aJsObjects = array_merge($this->_aJsObjects, array(
+            'manage_tools' => 'oBxPostsManageTools',
+             'categories' => 'oBxDolCategories'
+        ));
+
+        $this->_aGridObjects = array(
+            'common' => $this->CNF['OBJECT_GRID_COMMON'],
+            'administration' => $this->CNF['OBJECT_GRID_ADMINISTRATION'],
+        );
+
+        $this->_bAttachmentsInTimeline = true;
+    }
+}
+
+/** @} */

+ 191 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsFormEntry.php

@@ -0,0 +1,191 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * Create/Edit entry form
+ */
+class BxPostsFormEntry extends BxBaseModTextFormEntry
+{
+    protected $_sGhostTemplateCover = 'form_ghost_template_cover.html';
+	
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_posts';
+        parent::__construct($aInfo, $oTemplate);
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+    	if(isset($CNF['FIELD_COVER']) && isset($this->aInputs[$CNF['FIELD_COVER']])) {
+            if($this->_oModule->checkAllowedSetThumb() === CHECK_ACTION_RESULT_ALLOWED) {
+                $this->aInputs[$CNF['FIELD_COVER']]['storage_object'] = $CNF['OBJECT_STORAGE'];
+                $this->aInputs[$CNF['FIELD_COVER']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_COVER']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_COVER']]['value']) : $CNF['OBJECT_UPLOADERS'];
+                $this->aInputs[$CNF['FIELD_COVER']]['upload_buttons_titles'] = array(
+                    'Simple' => _t('_bx_posts_form_entry_input_covers_uploader_simple_title'), 
+                    'HTML5' => _t('_bx_posts_form_entry_input_covers_uploader_html5_title')
+                );
+                $this->aInputs[$CNF['FIELD_COVER']]['images_transcoder'] = $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW'];
+                $this->aInputs[$CNF['FIELD_COVER']]['storage_private'] = 0;
+                $this->aInputs[$CNF['FIELD_COVER']]['multiple'] = false;
+                $this->aInputs[$CNF['FIELD_COVER']]['content_id'] = 0;
+                $this->aInputs[$CNF['FIELD_COVER']]['ghost_template'] = '';
+            }
+            else
+                unset($this->aInputs[$CNF['FIELD_COVER']]);
+        }
+
+        if(isset($CNF['FIELD_PHOTO']) && isset($this->aInputs[$CNF['FIELD_PHOTO']])) {
+            $this->aInputs[$CNF['FIELD_PHOTO']]['storage_object'] = $CNF['OBJECT_STORAGE_PHOTOS'];
+            $this->aInputs[$CNF['FIELD_PHOTO']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_PHOTO']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_PHOTO']]['value']) : $CNF['OBJECT_UPLOADERS'];
+            $this->aInputs[$CNF['FIELD_PHOTO']]['images_transcoder'] = $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW_PHOTOS'];
+            $this->aInputs[$CNF['FIELD_PHOTO']]['storage_private'] = 0;
+            $this->aInputs[$CNF['FIELD_PHOTO']]['multiple'] = true;
+            $this->aInputs[$CNF['FIELD_PHOTO']]['content_id'] = 0;
+            $this->aInputs[$CNF['FIELD_PHOTO']]['ghost_template'] = '';
+            $this->aInputs[$CNF['FIELD_PHOTO']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+
+        if(isset($this->aInputs[$CNF['FIELD_VIDEO']])) {
+            $this->aInputs[$CNF['FIELD_VIDEO']]['storage_object'] = $CNF['OBJECT_STORAGE_VIDEOS'];
+            $this->aInputs[$CNF['FIELD_VIDEO']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_VIDEO']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_VIDEO']]['value']) : $CNF['OBJECT_UPLOADERS'];
+            $this->aInputs[$CNF['FIELD_VIDEO']]['images_transcoder'] = $CNF['OBJECT_VIDEOS_TRANSCODERS']['poster_preview'];
+            $this->aInputs[$CNF['FIELD_VIDEO']]['storage_private'] = 0;
+            $this->aInputs[$CNF['FIELD_VIDEO']]['multiple'] = true;
+            $this->aInputs[$CNF['FIELD_VIDEO']]['content_id'] = 0;
+            $this->aInputs[$CNF['FIELD_VIDEO']]['ghost_template'] = '';
+            $this->aInputs[$CNF['FIELD_VIDEO']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+        
+        if(isset($this->aInputs[$CNF['FIELD_SOUND']])) {
+            $this->aInputs[$CNF['FIELD_SOUND']]['storage_object'] = $CNF['OBJECT_STORAGE_SOUNDS'];
+            $this->aInputs[$CNF['FIELD_SOUND']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_SOUND']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_SOUND']]['value']) : $CNF['OBJECT_UPLOADERS'];
+            $this->aInputs[$CNF['FIELD_SOUND']]['images_transcoder'] = $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW_FILES'];
+            $this->aInputs[$CNF['FIELD_SOUND']]['storage_private'] = 0;
+            $this->aInputs[$CNF['FIELD_SOUND']]['multiple'] = true;
+            $this->aInputs[$CNF['FIELD_SOUND']]['content_id'] = 0;
+            $this->aInputs[$CNF['FIELD_SOUND']]['ghost_template'] = '';
+            $this->aInputs[$CNF['FIELD_SOUND']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+
+        if (isset($CNF['FIELD_FILE']) && isset($this->aInputs[$CNF['FIELD_FILE']])) {
+            $this->aInputs[$CNF['FIELD_FILE']]['storage_object'] = $CNF['OBJECT_STORAGE_FILES'];
+            $this->aInputs[$CNF['FIELD_FILE']]['uploaders'] = !empty($this->aInputs[$CNF['FIELD_FILE']]['value']) ? unserialize($this->aInputs[$CNF['FIELD_FILE']]['value']) : $CNF['OBJECT_UPLOADERS'];
+            $this->aInputs[$CNF['FIELD_FILE']]['images_transcoder'] = $CNF['OBJECT_IMAGES_TRANSCODER_PREVIEW_FILES'];
+            $this->aInputs[$CNF['FIELD_FILE']]['storage_private'] = 0;
+            $this->aInputs[$CNF['FIELD_FILE']]['multiple'] = true;
+            $this->aInputs[$CNF['FIELD_FILE']]['content_id'] = 0;
+            $this->aInputs[$CNF['FIELD_FILE']]['ghost_template'] = '';
+            $this->aInputs[$CNF['FIELD_FILE']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+
+        if(isset($this->aInputs[$CNF['FIELD_POLL']])) {
+            $this->aInputs[$CNF['FIELD_POLL']]['tr_attrs'] = array('class'=> 'bx-base-text-attachment-item');
+        }
+    }
+
+    function initChecker ($aValues = array (), $aSpecificValues = array())
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $bValues = $aValues && !empty($aValues['id']);
+        $aContentInfo = $bValues ? $this->_oModule->_oDb->getContentInfoById($aValues['id']) : false;
+
+        if($this->aParams['display'] == $CNF['OBJECT_FORM_ENTRY_DISPLAY_EDIT'] && isset($CNF['FIELD_PUBLISHED']) && isset($this->aInputs[$CNF['FIELD_PUBLISHED']]))
+            if($bValues && in_array($aValues[$CNF['FIELD_STATUS']], array('active', 'hidden')))
+                unset($this->aInputs[$CNF['FIELD_PUBLISHED']]);
+
+        if (isset($CNF['FIELD_COVER']) && isset($this->aInputs[$CNF['FIELD_COVER']])) {
+            if($bValues)
+                $this->aInputs[$CNF['FIELD_COVER']]['content_id'] = $aValues['id'];
+
+            $this->aInputs[$CNF['FIELD_COVER']]['ghost_template'] = $this->_oModule->_oTemplate->parseHtmlByName($this->_sGhostTemplateCover, $this->_getCoverGhostTmplVars($aContentInfo));
+        }
+
+        parent::initChecker ($aValues, $aSpecificValues);
+    }
+
+    public function insert ($aValsToAdd = array(), $isIgnore = false)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(isset($CNF['FIELD_ADDED']) && empty($aValsToAdd[$CNF['FIELD_ADDED']])) {
+            $iAdded = 0;
+            if(isset($this->aInputs[$CNF['FIELD_ADDED']]))
+                $iAdded = $this->getCleanValue($CNF['FIELD_ADDED']);
+
+            if(empty($iAdded))
+                 $iAdded = time();
+
+            $aValsToAdd[$CNF['FIELD_ADDED']] = $iAdded;
+        }
+
+        if(empty($aValsToAdd[$CNF['FIELD_PUBLISHED']])) {
+            $iPublished = 0;
+            if(isset($this->aInputs[$CNF['FIELD_PUBLISHED']]))
+                $iPublished = $this->getCleanValue($CNF['FIELD_PUBLISHED']);
+                
+             if(empty($iPublished))
+                 $iPublished = time();
+
+             $aValsToAdd[$CNF['FIELD_PUBLISHED']] = $iPublished;
+        }
+
+        $aValsToAdd[$CNF['FIELD_STATUS']] = $aValsToAdd[$CNF['FIELD_PUBLISHED']] > $aValsToAdd[$CNF['FIELD_ADDED']] ? 'awaiting' : 'active';
+
+        $iContentId = parent::insert ($aValsToAdd, $isIgnore);
+        if(!empty($iContentId)){
+            $this->processFiles($CNF['FIELD_COVER'], $iContentId, true);
+        }
+        return $iContentId;
+    }
+
+    function update ($iContentId, $aValsToAdd = array(), &$aTrackTextFieldsChanges = null)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($aValsToAdd[$CNF['FIELD_PUBLISHED']]) && isset($this->aInputs[$CNF['FIELD_PUBLISHED']])) {
+            $iPublished = $this->getCleanValue($CNF['FIELD_PUBLISHED']);
+            if(empty($iPublished))
+                $iPublished = time();
+
+            $aValsToAdd[$CNF['FIELD_PUBLISHED']] = $iPublished;
+        }
+
+        $iResult = parent::update ($iContentId, $aValsToAdd, $aTrackTextFieldsChanges);
+        $this->processFiles($CNF['FIELD_COVER'], $iContentId, false);   
+        return $iResult;
+    }
+
+    protected function _getCoverGhostTmplVars($aContentInfo = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	return array (
+            'name' => $this->aInputs[$CNF['FIELD_COVER']]['name'],
+            'content_id' => $this->aInputs[$CNF['FIELD_COVER']]['content_id'],
+            'editor_id' => isset($CNF['FIELD_TEXT_ID']) ? $CNF['FIELD_TEXT_ID'] : '',
+            'thumb_id' => isset($CNF['FIELD_THUMB']) && isset($aContentInfo[$CNF['FIELD_THUMB']]) ? $aContentInfo[$CNF['FIELD_THUMB']] : 0,
+            'name_thumb' => isset($CNF['FIELD_THUMB']) ? $CNF['FIELD_THUMB'] : ''
+        );
+    }
+
+    protected function _getPhotoGhostTmplVars($aContentInfo = array())
+    {
+    	$CNF = &$this->_oModule->_oConfig->CNF;
+
+    	return array (
+            'name' => $this->aInputs[$CNF['FIELD_PHOTO']]['name'],
+            'content_id' => (int)$this->aInputs[$CNF['FIELD_PHOTO']]['content_id'],
+            'editor_id' => isset($CNF['FIELD_TEXT_ID']) ? $CNF['FIELD_TEXT_ID'] : ''
+    	);
+    }
+}
+
+/** @} */

+ 24 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsPageListEntry.php

@@ -0,0 +1,24 @@
+<?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
+ *
+ * @{
+ */
+
+/**
+ * List entry page
+ */
+class BxPostsPageListEntry extends BxBaseModTextPageListEntry
+{    
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->MODULE = 'bx_posts';
+        parent::__construct($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 26 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsStudioPage.php

@@ -0,0 +1,26 @@
+<?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 BxPostsStudioPage extends BxTemplStudioModule
+{
+    protected $_sModule;
+    protected $_oModule;
+    
+    function __construct($sModule, $mixedPageName, $sPage = "")
+    {
+    	$this->_sModule = 'bx_posts';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($sModule, $mixedPageName, $sPage);
+    }
+}
+
+/** @} */

+ 27 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsUploaderRecordVideo.php

@@ -0,0 +1,27 @@
+<?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 BxPostsUploaderSimple extends BxBaseModTextUploaderSimple
+{
+    public function __construct ($aObject, $sStorageObject, $sUniqId, $oTemplate)
+    {
+        $this->_sModule = 'bx_posts';
+        
+        parent::__construct($aObject, $sStorageObject, $sUniqId, $oTemplate);
+    }
+
+    protected function isAdmin ($iContentId = 0)
+    {
+        return $this->_oModule->_isModerator (false);
+    }
+}
+
+/** @} */

+ 27 - 0
modules/boonex/posts/updates/11.0.2_12.0.0/source/classes/BxPostsUploaderRecordVideoAttach.php

@@ -0,0 +1,27 @@
+<?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 BxPostsUploaderRecordVideoAttach extends BxBaseModTextUploaderRecordVideoAttach
+{
+    public function __construct ($aObject, $sStorageObject, $sUniqId, $oTemplate)
+    {
+        $this->_sModule = 'bx_posts';
+
+        parent::__construct($aObject, $sStorageObject, $sUniqId, $oTemplate);
+    }
+
+    protected function isAdmin ($iContentId = 0)
+    {
+        return $this->_oModule->_isModerator (false);
+    }
+}
+
+/** @} */

+ 153 - 0
modules/boonex/posts/updates/11.0.2_12.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    Posts Posts
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_posts',
+    'title' => 'Posts',
+    'note' => 'Basic blogging module.',
+    'version' => '12.0.0',
+    'vendor' => 'BoonEx',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '12.0.0-B1'
+    ),
+
+    /**
+     * '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_classes_sounds',
+        'bx_posts_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+        'bx_posts_preview',
+        'bx_posts_gallery',
+        'bx_posts_cover',
+
+        'bx_posts_preview_photos',
+        'bx_posts_gallery_photos', 
+
+        'bx_posts_videos_poster',
+        'bx_posts_videos_poster_preview',
+        'bx_posts_videos_mp4',
+        'bx_posts_videos_mp4_hd',
+        
+        'bx_classes_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'
+    ),
+
+);
+
+/** @} */

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно