AntonLV 1 mese fa
parent
commit
54d9480309
100 ha cambiato i file con 10784 aggiunte e 3761 eliminazioni
  1. 51 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/install/config.php
  2. 26 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/install/installer.php
  3. 4 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/install/sql/enable.sql
  4. 50 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/classes/BxArtificerStudioPage.php
  5. 400 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/bx_timeline/css/view.css
  6. 89 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/bx_timeline/item_outline.html
  7. 91 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/bx_timeline/item_timeline.html
  8. 45 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_groups/cover.html
  9. 58 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_groups/cover_block.html
  10. 45 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_profile/cover.html
  11. 58 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_profile/cover_block.html
  12. 61 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/_block_explore.html
  13. 93 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/_block_splash.html
  14. 175 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/_header_js_custom.html
  15. 14 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/block_join.html
  16. 34 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/block_login.html
  17. 30 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/cover.html
  18. 36 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/cover_home.html
  19. 463 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/css/forms.css
  20. 17 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/menu_main_submenu.html
  21. 8 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/menu_main_submenu_more_auto.html
  22. 4 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/menu_meta_item.html
  23. 27 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/profile_avatar.html
  24. 27 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/profile_stats.html
  25. 117 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/pt_application.html
  26. 30 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplFormView.php
  27. 300 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplFunctions.php
  28. 74 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplMenuSidebarSite.php
  29. 97 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplMenuToolbar.php
  30. 20 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/sidebar_account.html
  31. 21 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/sidebar_site.html
  32. 68 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/install/config.php
  33. 6 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/install/sql/enable.sql
  34. 23 0
      modules/boonex/artificer/updates/15.0.5_15.0.6/source/template/images/icons/std-icon.svg
  35. 51 0
      modules/boonex/oauth2/updates/15.0.0_15.0.1/install/config.php
  36. 13 0
      modules/boonex/oauth2/updates/15.0.0_15.0.1/install/installer.php
  37. 429 0
      modules/boonex/oauth2/updates/15.0.0_15.0.1/source/classes/BxOAuthAPI.php
  38. 140 0
      modules/boonex/oauth2/updates/15.0.0_15.0.1/source/classes/BxOAuthGrid.php
  39. 68 0
      modules/boonex/oauth2/updates/15.0.0_15.0.1/source/install/config.php
  40. 3 0
      modules/boonex/oauth2/updates/15.0.0_15.0.1/source/template/images/icons/std-icon.svg
  41. 51 0
      modules/boonex/payment/updates/15.0.2_15.0.3/install/config.php
  42. 13 0
      modules/boonex/payment/updates/15.0.2_15.0.3/install/installer.php
  43. 4 0
      modules/boonex/payment/updates/15.0.2_15.0.3/install/langs/en.xml
  44. 2 0
      modules/boonex/payment/updates/15.0.2_15.0.3/install/sql/enable.sql
  45. 17 0
      modules/boonex/payment/updates/15.0.2_15.0.3/install/sql/install.sql
  46. 388 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentConfig.php
  47. 217 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentFormDetails.php
  48. 351 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridCart.php
  49. 93 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridCarts.php
  50. 119 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridPending.php
  51. 300 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridProcessed.php
  52. 2170 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentModule.php
  53. 260 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentOrders.php
  54. 284 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentProviderCredits.php
  55. 652 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentTemplate.php
  56. 70 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/install/config.php
  57. 716 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/install/langs/en.xml
  58. 35 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/install/sql/enable-app.sql
  59. 213 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/install/sql/enable.sql
  60. 701 0
      modules/boonex/payment/updates/15.0.2_15.0.3/source/install/sql/install.sql
  61. 51 0
      modules/boonex/shopify/updates/15.0.1_15.0.2/install/config.php
  62. 13 0
      modules/boonex/shopify/updates/15.0.1_15.0.2/install/installer.php
  63. 32 0
      modules/boonex/shopify/updates/15.0.1_15.0.2/source/classes/BxShopifyFormSettings.php
  64. 116 0
      modules/boonex/shopify/updates/15.0.1_15.0.2/source/install/config.php
  65. 9 0
      modules/boonex/shopify/updates/15.0.1_15.0.2/source/template/images/icons/std-icon.svg
  66. 1 5
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/install/config.php
  67. 245 0
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/classes/BxSMTPModule.php
  68. 0 5
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/composer.json
  69. 0 85
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/composer.lock
  70. 3 3
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/install/sql/enable.sql
  71. 0 22
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/autoload.php
  72. 0 579
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/ClassLoader.php
  73. 0 396
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/InstalledVersions.php
  74. 0 21
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/LICENSE
  75. 0 10
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_classmap.php
  76. 0 9
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_namespaces.php
  77. 0 10
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_psr4.php
  78. 0 38
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_real.php
  79. 0 36
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_static.php
  80. 0 75
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/installed.json
  81. 0 32
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/installed.php
  82. 0 26
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/platform_check.php
  83. 0 265
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/CHANGELOG.md
  84. 0 30
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/LICENSE
  85. 0 457
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/README.md
  86. 0 45
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/composer.json
  87. 0 18
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/BeforeValidException.php
  88. 0 275
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/CachedKeySet.php
  89. 0 30
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/ExpiredException.php
  90. 0 375
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/JWK.php
  91. 0 833
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/JWT.php
  92. 0 20
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php
  93. 0 54
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/Key.php
  94. 0 7
      modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/SignatureInvalidException.php
  95. 51 0
      modules/boonex/snipcart/updates/15.0.1_15.0.2/install/config.php
  96. 13 0
      modules/boonex/snipcart/updates/15.0.1_15.0.2/install/installer.php
  97. 35 0
      modules/boonex/snipcart/updates/15.0.1_15.0.2/source/classes/BxSnipcartFormSettings.php
  98. 136 0
      modules/boonex/snipcart/updates/15.0.1_15.0.2/source/install/config.php
  99. 6 0
      modules/boonex/snipcart/updates/15.0.1_15.0.2/source/template/images/icons/std-icon.svg
  100. 51 0
      modules/boonex/stripe_connect/updates/15.0.2_15.0.3/install/config.php

+ 51 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/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' => 'Artificer',
+    'version_from' => '15.0.5',
+    'version_to' => '15.0.6',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/artificer/updates/update_15.0.5_15.0.6/',
+    'home_uri' => 'artificer_update_1505_1506',
+
+    'module_dir' => 'boonex/artificer/',
+    'module_uri' => 'artificer',
+
+    'db_prefix' => 'bx_artificer_',
+    'class_prefix' => 'BxArtificer',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Artificer Template',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 26 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/install/installer.php

@@ -0,0 +1,26 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ */
+
+class BxArtificerUpdater extends BxDolStudioUpdater
+{
+    function __construct($aConfig)
+    {
+        parent::__construct($aConfig);
+    }
+
+    public function update($aParams)
+    {
+        $aResult = parent::update($aParams);
+        if(!$aResult['result'])
+            return $aResult;
+
+        $oCacheUtilities = BxDolCacheUtilities::getInstance();
+        $oCacheUtilities->clear('css');
+        $oCacheUtilities->clear('template');
+
+        return $aResult;
+    }
+}

File diff suppressed because it is too large
+ 4 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/install/sql/enable.sql


+ 50 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/classes/BxArtificerStudioPage.php

@@ -0,0 +1,50 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Artificer Artificer template
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+require_once('BxArtificerStudioOptions.php');
+
+define('BX_ARTIFICER_STUDIO_TEMPL_TYPE_STYLES', 'styles');
+
+class BxArtificerStudioPage extends BxTemplStudioDesign
+{
+    function __construct($sModule, $mixedPageName, $sPage = "")
+    {
+        parent::__construct($sModule, $mixedPageName, $sPage);
+
+        $this->aMenuItems = bx_array_insert_after([
+            BX_ARTIFICER_STUDIO_TEMPL_TYPE_STYLES => ['title' => '_bx_artificer_lmi_cpt_styles', 'icon' => 'mi-tpl-styles.svg', 'icon_bg' => true]
+        ], $this->aMenuItems, BX_DOL_STUDIO_TEMPL_TYPE_SETTINGS);
+    }
+
+    protected function getSettings($mixedCategory = '', $sMix = '')
+    {
+    	return parent::getSettings('bx_artificer_system', $sMix);
+    }
+
+    protected function getStyles($mixedCategory = '', $sMix = '')
+    {
+    	$sPrefix = $this->sModule;
+
+        if(empty($mixedCategory))
+            $mixedCategory = [
+                $sPrefix . '_styles_custom',
+            ];
+
+    	$oOptions = new BxArtificerStudioOptions($this->sModule, $mixedCategory, $sMix);
+
+        return BxDolStudioTemplate::getInstance()->parseHtmlByName('design.html', [
+            'content' => $oOptions->getCode(),
+            'js_content' => $this->getPageJsCode()
+        ]);
+    }
+}
+
+/** @} */

+ 400 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/bx_timeline/css/view.css

@@ -0,0 +1,400 @@
+/*--
+import url(../../../../../timeline/template/css/view.css);
+--*/
+
+/*--- Dynamic Browsing: Menu ---*/
+.bx-tl-menu-feeds.bx-menu-ver li img, 
+.bx-tl-menu-feeds.bx-menu-ver li .sys-icon {
+    display: inline-block;
+    vertical-align: top;
+    width: 1.5rem;
+    height: 1.5rem;
+
+    background-size: 1.25rem 1.25rem;
+    background-position: center center;
+
+    line-height: 1.5rem;
+    font-size: 1.0rem;
+}
+.bx-tl-menu-feeds.bx-menu-ver li .bx-menu-show {
+    display: none;
+}
+.bx-tl-menu-feeds.bx-menu-ver li .bx-menu-hide {
+    display: inline;
+}
+.bx-tl-menu-feeds.bx-menu-ver li.bx-mi-collapsed .bx-menu-show {
+    display: inline;
+}
+.bx-tl-menu-feeds.bx-menu-ver li.bx-mi-collapsed .bx-menu-hide {
+    display: none;
+}
+.bx-tl-menu-feeds.bx-menu-ver li.bx-mi-collapsed .bx-menu-item-subitems {
+    display: none;
+}
+
+/*--- View Block Style ---*/
+.bx-tl-grid-sizer {
+    width: 100%;
+}
+.bx-tl-grid-item-sizer {
+    width: 100%;
+}
+.bx-tl-view-sizer {
+    width: 100%;
+}
+.bx-tl-view-sizer div.bx-tl-item-ind {
+    padding: 0px;
+}
+
+/*--- Filters Style ---*/
+div.bx-tl-view-filters {
+    min-width: 14rem;
+    max-width: 20rem;
+}
+div.bx-tl-view-filters div.bx-form-section-wrapper:first-child {
+    margin-top: 0;
+}
+div.bx-tl-view-filters div.bx-form-section-content {
+    padding-top: 0;
+    padding-bottom: 0;
+}
+
+/*--- Load More Style ---*/
+div.bx-tl-view-timeline div.bx-tl-load-more {
+    padding-top: 0px;
+}
+
+/*--- Item Style: Timeline ---*/
+div.bx-tl-view-timeline div.bx-tl-items,
+div.bx-tl-view-search div.bx-tl-items,
+div.bx-tl-view-item div.bx-tl-items {
+    margin-left: 0px;
+    margin-right: 0px;
+}
+
+/*--- Item Meta Info Style ---*/
+.bx-tl-item-meta ul.bx-menu-custom li:first-child .bx-tl-item-meta-div {
+    display: none;
+}
+
+/*--- Item Content Style ---*/
+div.bx-tl-item-content form {
+    padding: 1rem 1rem 0 1rem;
+}
+div.bx-tl-item-content div.bx-tl-title {
+    /* This box used to be `overflow: hidden`, which clipped the focus ring of the title link sitting
+       flush inside it. The clipping was really there to stop a long unbroken title from widening the
+       page, and wrapping does that without hiding anything; `text-overflow` never applied here anyway,
+       the box is a flex container. */
+    overflow-wrap: anywhere;
+}
+div.bx-tl-item-content div.bx-tl-title div.bx-tl-title-cnt {
+    min-width: 0;
+}
+div.bx-tl-item-text div.bx-tl-content {
+    position: relative;
+    max-height: 16rem;
+}
+div.bx-tl-item-text div.bx-tl-content.bx-tl-overflow {
+    margin-bottom: 0;
+}
+div.bx-tl-item-text div.bx-tl-content .bx-tl-content-overflow {
+    display: none;
+}
+div.bx-tl-item-text div.bx-tl-content.bx-tl-overflow .bx-tl-content-overflow {
+    display: block;
+}
+
+/*--- Item Activity (Actions and Manage are different menus) ---*/
+div.bx-tl-item div.bx-tl-item-activity .bx-menu-custom.bx-menu-custom-hor {
+    flex-wrap: wrap;
+}
+div.bx-tl-item div.bx-tl-item-activity.bx-tl-ia-counters .bx-menu-custom.bx-menu-custom-hor li > a,
+div.bx-tl-item div.bx-tl-item-activity.bx-tl-ia-counters .bx-menu-custom.bx-menu-custom-hor li > span {
+    display: block;
+}
+div.bx-tl-item div.bx-tl-item-activity.bx-tl-ia-counters .bx-menu-custom.bx-menu-custom-hor li > a,
+div.bx-tl-item div.bx-tl-item-activity.bx-tl-ia-counters .bx-menu-custom.bx-menu-custom-hor li > div,
+div.bx-tl-item div.bx-tl-item-activity.bx-tl-ia-counters .bx-menu-custom.bx-menu-custom-hor li > span {
+    margin-top: 0.5rem;
+}
+
+.bx-menu-object-bx_timeline_menu_item_manage .menu-custom-item-ver a,
+.bx-menu-object-bx_timeline_menu_item_manage .bx-report-element-holder a {
+    display: block;
+    width: 100%;
+    box-sizing: border-box;
+}
+.bx-menu-object-bx_timeline_menu_item_manage .bx-report-element-holder {
+    -webkit-flex: 1 0 auto;
+    flex: 1 0 auto;
+
+    padding: 0px !important;
+}
+.bx-menu-object-bx_timeline_menu_item_manage .bx-report-counter-holder {
+    -webkit-flex: 0 1 auto;
+    flex: 0 1 auto;
+
+    padding-right: 1rem;
+}
+.bx-tl-owner-avatar .bx-def-thumb-size{
+    width: 2.5rem;
+    height: 2.5rem;
+}
+
+/*--- Item Owner: Name ---*/
+/* The owner-info wrapper is `overflow-hidden` (Tailwind), which would clip the
+   extra hit area added below; the name itself still truncates via `.truncate`. */
+div.bx-tl-item div.bx-tl-owner-info {
+    overflow: visible;
+}
+
+/* WCAG 2.5.8 (AA): the author link must be at least 24x24 CSS px. The extra
+   height is added as padding-top cancelled by an equal negative margin-top, so
+   the link's box grows UPWARD into the gap that already sits above the header
+   row. The text position, the row height, the meta row below and the card
+   height are all unchanged, and the box never reaches the date link beneath. */
+div.bx-tl-item div.bx-tl-owner-name > a.bx-tl-owner-name {
+    min-height: 1.5rem;
+
+    padding-top: 0.375rem;
+    margin-top: -0.375rem;
+}
+
+/*--- Menu: Item Manage ---*/
+.bx-menu-object-bx_timeline_menu_item_manage .sys-action-do-text {
+    margin-left: 0rem;
+}
+
+/*--- Item Action Style ---*/
+div.bx-tl-item div.bx-tl-item-action .bx-tl-timeline-owner-name .bx-tl-ton-div:first-child {
+    display: none;
+}
+
+/*+++ Item Text +++*/
+div.bx-tl-view-outline div.bx-tl-item-text div.bx-tl-title {
+    font-weight: bold;
+}
+div.bx-tl-view-outline div.bx-tl-content-show-more a {
+    font-weight: bold;
+}
+
+/*+++ Item Image +++*/
+div.bx-tl-view-search div.bx-tl-item-images {
+    margin-left: 0px;
+    margin-right: 0px;
+}
+div.bx-tl-view-search div.bx-tl-item-image {
+    margin-right: 2px;
+    margin-right: 0.125rem;
+}
+div.bx-tl-view-timeline div.bx-tl-item-image,
+div.bx-tl-view-outline div.bx-tl-item-image,
+div.bx-tl-view-item div.bx-tl-item-image {
+    width: 100%;
+    text-align: center;
+    overflow: hidden;
+}
+div.bx-tl-view-search div.bx-tl-item-image img {
+    height: 12.5rem;
+}
+div.bx-tl-view-timeline div.bx-tl-item-images.bx-tl-ii-gallery div.bx-tl-item-image img,
+div.bx-tl-view-item div.bx-tl-item-images.bx-tl-ii-gallery div.bx-tl-item-image img,
+div.bx-tl-view-timeline div.bx-tl-item-images.bx-tl-ii-single div.bx-tl-item-image img,
+div.bx-tl-view-item  div.bx-tl-item-images.bx-tl-ii-single div.bx-tl-item-image img {
+    position: relative;
+    display: block;
+    max-width: 100%;
+    margin-left: auto;
+    margin-right: auto;
+}
+div.bx-tl-view-outline div.bx-tl-item-image img {
+    max-width: 100%;
+    object-fit: cover;
+    object-position: center center;
+}
+
+/*+++ Item Video +++*/
+div.bx-tl-view-timeline div.bx-tl-item-video,
+div.bx-tl-view-outline div.bx-tl-item-video,
+div.bx-tl-view-item div.bx-tl-item-video {
+    width: 100%;
+}
+.bx-tl-video-iframe {
+    width: 100%;
+    border: none;
+}
+div.bx-tl-view div.bx-tl-item-videos.bx-tl-iv-gallery div.bx-tl-item-video video,
+div.bx-tl-view div.bx-tl-item-videos.bx-tl-iv-single div.bx-tl-item-video video {
+    display: block;
+    max-width: 100%;
+    margin-left: auto;
+    margin-right: auto;
+}
+
+/*+++ Item Attachment +++*/
+div.bx-tl-view div.bx-tl-item-attachments {
+    position: relative;
+    white-space: nowrap;
+    overflow-x: auto;
+}
+
+div.bx-tl-view div.bx-tl-item-attachments div.bx-tl-item-attachment {
+    height:auto;
+}
+div.bx-tl-view div.bx-tl-item-attachments div.bx-tl-item-attachment img {
+    max-height:25.5rem;
+    max-width:100%;
+    margin-left:auto;
+    margin-right:auto;
+}
+.bx-tl-item-attachments.bx-tl-ia-gallery {
+    text-align:center;
+}
+
+div.bx-tl-view div.bx-tl-item-attachments .flickity-slider div.bx-tl-item-attachment {
+    width: 100%;
+    height: 25.5rem;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    vertical-align: middle;
+}
+.flickity-slider .bx-tl-item-attachment img {
+    display: block;
+    max-height: 100%;
+}
+
+div.bx-tl-view-outline div.bx-tl-item-attachment img {
+    max-width: 100%;
+    object-fit: cover;
+    object-position: center center;
+}
+
+/*+++ Video +++*/
+div.bx-tl-view-timeline div.bx-tl-item-attachment video,
+div.bx-tl-view-outline div.bx-tl-item-attachment video,
+div.bx-tl-view-item div.bx-tl-item-attachment video {
+    display: block;
+    max-width: 100%;
+    margin-left: auto;
+    margin-right: auto;
+}
+div.bx-tl-item-attachment .bx-tl-item-video {
+    position: relative;
+}
+div.bx-tl-item-attachment .bx-tl-iv-duration {
+    position: absolute;
+    right: 0.25rem;
+    bottom: 0.25rem;
+    background-color: rgba(255, 255, 255, 0.8);
+}
+
+
+/*+++ Showcase Layout +++*/
+div.bx-tl-view div.bx-tl-item-attachments.bx-tl-ia-showcase {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    flex-wrap: wrap;
+    -webkit-justify-content: space-between;
+    justify-content: space-between;
+}
+div.bx-tl-view div.bx-tl-item-attachments.bx-tl-ia-showcase div.bx-tl-item-attachment {
+    position: relative;
+    box-sizing: border-box;
+    width: 33.2%;
+    height: 8.5rem;
+    border: 1px solid transparent;
+}
+div.bx-tl-view div.bx-tl-item-attachments.bx-tl-ia-showcase div.bx-tl-item-attachment.bx-tl-ia-first,
+div.bx-tl-view div.bx-tl-item-attachments.bx-tl-ia-showcase.bx-tl-ia-i2 div.bx-tl-item-attachment {
+    width: 100%;
+    height: auto;
+}
+div.bx-tl-view div.bx-tl-item-attachments.bx-tl-ia-showcase.bx-tl-ia-i3 div.bx-tl-item-attachment:not(.bx-tl-ia-first) {
+    width: 50%;
+}
+div.bx-tl-item-attachments.bx-tl-ia-showcase a,
+div.bx-tl-item-attachments.bx-tl-ia-showcase img {
+    position: relative;
+    display: block;
+    width: 100%;
+    height: 100%;
+}
+div.bx-tl-item-attachments.bx-tl-ia-showcase img {
+    object-fit: cover;
+}
+div.bx-tl-item-attachments.bx-tl-ia-showcase .bx-tl-item-more {
+    position: absolute;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.7);
+
+    font-size: 2.5rem;
+}
+div.bx-tl-item-attachments.bx-tl-ia-showcase .bx-tl-item-more,
+div.bx-tl-item-attachments.bx-tl-ia-showcase .bx-tl-item-more a {
+    color: #ffffff;
+}
+
+/*+++ Item Link +++*/
+div.bx-tl-view-outline div.bx-tl-item-link {
+    text-align: center;
+}
+div.bx-tl-view-outline div.bx-tl-il-thumbnail img {
+    width: 100%;
+    max-width: 100px;
+    height: 100%;
+    max-height: 100px;
+}
+div.bx-tl-view-outline div.bx-tl-il-embed iframe,
+div.bx-tl-view-timeline div.bx-tl-il-embed iframe {
+    width: 100%;
+}
+
+/*--- Item Brief Style ---*/
+div.bx-tl-bview-images {
+    position: relative;
+}
+div.bx-tl-bview-image.bx-tl-bvi-single,
+div.bx-tl-bview-images div.bx-tl-bview-image {
+    width: 100%;
+    height: calc(100vh - 7rem);
+    text-align: center;
+}
+div.bx-tl-bview-image.bx-tl-bvi-single img,
+div.bx-tl-bview-images div.bx-tl-bview-image:not(.bx-tl-bvi-single) img {
+    position: relative;
+    max-width: 100% !important;
+    max-height: 100% !important;
+    margin-left: auto;
+    margin-right: auto;
+}
+div.bx-tl-bview-image.bx-tl-bvi-single {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+}
+
+/*--- Comments Styles ---*/
+.bx-tl-view-item-comments .bx-tl-item-comments {
+    border-width: 0;
+    padding: 0;
+}
+
+.bx-tl-view-item-comments .cmt-reply.cmt-reply-min {
+    margin-bottom: 0;
+}

+ 89 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/bx_timeline/item_outline.html

@@ -0,0 +1,89 @@
+<div id="__html_id__" class="__style_prefix__-item __class__">
+    <a name="timeline-event-__id__"></a>
+    <div class="__style_prefix__-item-ind p-2">
+        <div class="__style_prefix__-item-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box __class_content__ group/item hover:bg-gray-50 dark:hover:bg-gray-900 hover:shadow-lg">
+            <div class="__style_prefix__-blink-plate"></div>
+            <bx_if:show_note>
+                <div class="__style_prefix__-item-notes mt-3 md:mt-4">
+                    <bx_repeat:notes>
+                        <div class="__style_prefix__-item-note mt-2 first:mt-0 text-sm text-gray-500 dark:text-gray-400">
+                            <div class="__style_prefix__-in-text mx-3 md:mx-4 lg:mx-6<bx_if:show_note_color> col-__item_note_color__</bx_if:show_note_color>">__item_note__</div>
+                        </div>
+                    </bx_repeat:notes>
+                </div>
+                <div class="__style_prefix__-in-divider  bx-def-hr mt-3 md:mt-4"></div>
+            </bx_if:show_note>
+            <div class="__style_prefix__-item-owner flex items-center px-3 md:px-4 mt-3 md:mt-4 __class_owner__"> 
+                <div class="__style_prefix__-owner-avatar flex-shrink-0">__item_owner_unit__</div>
+                <div class="__style_prefix__-owner-info min-w-0 ltr:ml-3 rtl:mr-3 overflow-hidden">
+                    <div class="__style_prefix__-owner-name flex flex-wrap items-center">
+                        <a href="__item_owner_url__" class="__style_prefix__-owner-name bx-def-font-author flex items-center min-w-0 mr-1 hover:text-gray-900 dark:hover:text-white" title="__item_owner_title__"><div class="truncate">__item_owner_name__</div>__item_owner_badges__</a>
+                        <bx_if:show_owner_actions>
+                            <span class="__style_prefix__-owner-actions bx-def-font-meta">
+                                <bx_repeat:owner_actions>
+                                    <span class="__style_prefix__-oa-div mr-1">&#183;</span><a class="__style_prefix__-owner-action hover:underline" href="__href__" onclick="__onclick__" title="__title__"><i class="sys-icon __icon__"></i></a>
+                                </bx_repeat:owner_actions>
+                            </span>
+                        </bx_if:show_owner_actions>
+                    </div>
+                    <div class="__style_prefix__-item-meta bx-def-font-meta flex items-center flex-wrap">
+                        <bx_if:show_menu_item_meta>
+                            <span class="__style_prefix__-meta mr-1">__meta__</span>
+                        </bx_if:show_menu_item_meta>
+                        <bx_if:show_item_action>
+                            <span class="__style_prefix__-div mr-1">&#183;</span>
+                            <div class="__style_prefix__-item-action mr-1 flex items-center">
+                                <span class="flex items-center mr-1 lowercase">__item_owner_action__</span>
+                                <bx_if:show_timeline_owner>
+                                    <span class="mr-1"><bx_text:_bx_timeline_txt_to /></span> 
+                                    <span class="__style_prefix__-timeline-owner-name mr-1">
+                                        <bx_repeat:owners><span class="__style_prefix__-ton-div">, </span><a href="__owner_url__" class="__style_prefix__-ton-item text-blue-600 dark:text-blue-400 font-semibold hover:underline">__owner_username__</a></bx_repeat:owners>
+                                    </span> 
+                                </bx_if:show_timeline_owner>
+                            </div>
+                        </bx_if:show_item_action>
+                        <bx_if:show_pinned>
+                            <span class="__style_prefix__-pinned mr-1">
+                                <i class="sys-icon thumbtack" title="<bx_text_attribute:_bx_timeline_txt_pinned />"></i>
+                            </span>
+                        </bx_if:show_pinned>
+                        <bx_if:show_sticked>
+                            <span class="__style_prefix__-sticked mr-1">
+                                <i class="sys-icon thumbtack" title="<bx_text_attribute:_bx_timeline_txt_sticked />"></i>
+                            </span>
+                        </bx_if:show_sticked>
+                        <bx_if:show_hot>
+                            <span class="__style_prefix__-hot mr-1">
+                                <i class="sys-icon fire" title="<bx_text_attribute:_bx_timeline_txt_hot />"></i>
+                            </span>
+                        </bx_if:show_hot>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="__style_prefix__-item-content __style_prefix__-ic-__content_type__ bx-clearfix">__content__</div>
+            <bx_if:show_location>
+                <div class="__style_prefix__-item-location mx-3 md:mx-4 mt-3 md:mt-4 bx-def-font-grayed bx-clearfix">__location__</div>
+            </bx_if:show_location>
+            <bx_if:show_fields>
+                <div class="__style_prefix__-item-fields mx-3 md:mx-4 mt-3 md:mt-4 bx-def-font-grayed bx-clearfix">__fields__</div>
+            </bx_if:show_fields>
+            <bx_if:show_menu_item_counters>
+                <div class="__style_prefix__-item-activity __style_prefix__-ia-counters space-x-4 px-2 md:px-3">__menu_item_counters__</div>
+            </bx_if:show_menu_item_counters>
+            <div class="flex justify-between space-x-8 mt-2 md:mt-3 p-3 md:p-4 border-t border-gray-200 dark:border-gray-700">
+                <bx_if:show_menu_item_actions>
+                    <div class="__style_prefix__-item-activity">__menu_item_actions__</div>
+                </bx_if:show_menu_item_actions>
+               <bx_if:show_manage>
+                <div class="__style_prefix__-item-manage">
+                    <a class="group bx-stl-mil-sm" href="javascript:void(0)" onclick="__onclick__" title="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-label="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-haspopup="dialog" aria-expanded="false">
+                        <span class="bx-menu-item-icon bx-def-align-center leading-5"><i class="sys-icon ellipsis-h"></i></span>
+                    </a>
+                </div>
+            </bx_if:show_manage>
+            </div>
+            <div class="__style_prefix__-item-comments-holder">__comments__</div>
+        </div>
+    </div>
+</div>

+ 91 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/bx_timeline/item_timeline.html

@@ -0,0 +1,91 @@
+<div id="__html_id__" class="__style_prefix__-item __class__ bx-def-thumb-size-min-height relative pb-3 md:pb-4 lg:pb-6 bx-clearfix ">
+    <a name="timeline-event-__id__"></a>
+    <div class="__style_prefix__-item-cnt bx-lnk-cnt bx-def-box bx-def-box-round-corners bx-def-color-bg-box __class_content__ group/item hover:bg-gray-50 dark:hover:bg-gray-900 hover:shadow-lg">
+        <div class="__style_prefix__-blink-plate"></div>
+        <bx_if:show_note>
+            <div class="__style_prefix__-item-notes mt-3 md:mt-4">
+                <bx_repeat:notes>
+                    <div class="__style_prefix__-item-note mt-2 first:mt-0 text-sm text-gray-500 dark:text-gray-400">
+                        <div class="__style_prefix__-in-text mx-3 md:mx-4 lg:mx-6<bx_if:show_note_color> col-__item_note_color__</bx_if:show_note_color>">__item_note__</div>
+                    </div>
+                </bx_repeat:notes>
+            </div>
+            <div class="__style_prefix__-in-divider bx-def-hr mt-3 md:mt-4"></div>
+        </bx_if:show_note>
+        <div class="__style_prefix__-item-owner flex items-center px-3 md:px-4 mt-3 md:mt-4 __class_owner__"> 
+            <div class="__style_prefix__-owner-avatar flex-shrink-0">__item_owner_unit__</div>
+            <div class="__style_prefix__-owner-info min-w-0 ltr:ml-3 rtl:mr-3 overflow-hidden">
+                <div class="__style_prefix__-owner-name flex flex-wrap items-center">
+                    <a href="__item_owner_url__" class="__style_prefix__-owner-name bx-def-font-author flex items-center min-w-0 mr-1 hover:text-gray-900 dark:hover:text-white" title="__item_owner_title__"><div class="truncate">__item_owner_name__</div>__item_owner_badges__</a> 
+                    <bx_if:show_owner_actions>
+                        <span class="__style_prefix__-owner-actions bx-def-font-meta">
+                            <bx_repeat:owner_actions>
+                                <span class="__style_prefix__-oa-div mr-1">&#183;</span><a class="__style_prefix__-owner-action hover:underline" href="__href__" onclick="__onclick__">__content__</a>
+                            </bx_repeat:owner_actions>
+                        </span>
+                    </bx_if:show_owner_actions>
+                </div>
+                <div class="__style_prefix__-item-meta bx-def-font-meta flex items-center flex-wrap">
+                    <bx_if:show_menu_item_meta>
+                        <span class="__style_prefix__-meta mr-1">__meta__</span>
+                    </bx_if:show_menu_item_meta>
+                    <bx_if:show_item_action>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <div class="__style_prefix__-item-action flex items-center mr-1">
+                            <span class="flex items-center mr-1 lowercase"><i class="sys-icon __item_icon__ mr-1"></i>__item_owner_action__</span>
+                            <bx_if:show_timeline_owner>
+                                <span class="mr-1"><bx_text:_bx_timeline_txt_to /></span> 
+                                <span class="__style_prefix__-timeline-owner-name mr-1">
+                                    <bx_repeat:owners><span class="__style_prefix__-ton-div">, </span><a href="__owner_url__" class="__style_prefix__-ton-item text-blue-600 dark:text-blue-400 font-semibold hover:underline">__owner_username__</a></bx_repeat:owners>
+                                </span> 
+                            </bx_if:show_timeline_owner>
+                        </div>
+                    </bx_if:show_item_action>
+                    <bx_if:show_pinned>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <span class="__style_prefix__-pinned ml-1">
+                            <i class="sys-icon thumbtack" title="<bx_text_attribute:_bx_timeline_txt_pinned />"></i>
+                        </span>
+                    </bx_if:show_pinned>
+                    <bx_if:show_sticked>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <span class="__style_prefix__-sticked ml-1">
+                            <i class="sys-icon thumbtack" title="<bx_text_attribute:_bx_timeline_txt_sticked />"></i>
+                        </span>
+                    </bx_if:show_sticked>
+                    <bx_if:show_hot>
+                        <span class="__style_prefix__-div mr-1">&#183;</span>
+                        <span class="__style_prefix__-hot ml-1">
+                            <i class="sys-icon fire" title="<bx_text_attribute:_bx_timeline_txt_hot />"></i>
+                        </span>
+                    </bx_if:show_hot>
+                </div>
+                
+            </div>
+        </div>
+        
+        <div class="__style_prefix__-item-content __style_prefix__-ic-__content_type__ bx-clearfix">__content__</div>
+        <bx_if:show_location>
+            <div class="__style_prefix__-item-location mx-3 md:mx-4 mt-3 md:mt-4 bx-def-font-grayed bx-clearfix">__location__</div>
+        </bx_if:show_location>
+        <bx_if:show_fields>
+            <div class="__style_prefix__-item-fields mx-3 md:mx-4 mt-3 md:mt-4 bx-def-font-grayed bx-clearfix">__fields__</div>
+        </bx_if:show_fields>
+        <bx_if:show_menu_item_counters>
+            <div class="__style_prefix__-item-activity __style_prefix__-ia-counters space-x-4 px-2 md:px-3">__menu_item_counters__</div>
+        </bx_if:show_menu_item_counters>
+        <div class="flex justify-between space-x-8 mt-2 md:mt-3 p-3 md:p-4 border-t border-gray-200 dark:border-gray-700">
+            <bx_if:show_menu_item_actions>
+                <div class="__style_prefix__-item-activity">__menu_item_actions__</div>
+            </bx_if:show_menu_item_actions>
+            <bx_if:show_manage>
+                <div class="__style_prefix__-item-manage">
+                    <a class="group bx-lnk-cnt bx-stl-mil-sm" href="javascript:void(0)" onclick="__onclick__" title="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-label="<bx_text_attribute:_bx_timeline_menu_title_item_manage />" aria-haspopup="dialog" aria-expanded="false">
+                        <span class="bx-menu-item-icon bx-def-align-center leading-5"><i class="sys-icon ellipsis-h"></i></span>
+                    </a>
+                </div>
+            </bx_if:show_manage>
+        </div>
+        <div class="__style_prefix__-item-comments-holder">__comments__</div>
+    </div>
+</div>

+ 45 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_groups/cover.html

@@ -0,0 +1,45 @@
+<div class="bx-menu-toolbar-padding pt-16">
+    <div class="bx-base-pofile-cover-wrapper __class__ relative">
+        <div class="bx-base-pofile-cover relative">
+            <div class="bx-base-pofile-cover-image-wrp relative xl:px-4 overflow-hidden">
+                <div class="bx-base-pofile-cover-image bx-def-page-width relative mx-auto opacity-100 xl:rounded-b-lg <bx_if:show_cover_placeholder>bx-bpci-holder h-32 lg:h-32 bg-gradient-to-b from-green-400 to-green-500</bx_if:show_cover_placeholder><bx_if:show_cover>h-64 lg:h-80</bx_if:show_cover> __add_class__ ">
+                    <p class="bx-base-pofile-cover-image box-border absolute h-full w-full flex justify-center items-center">
+                        <img alt="" class="bx-base-pofile-cover-image w-full object-cover bg-cover xl:rounded-b-lg h-full relative __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                    </p>
+                    __cover_tweak__
+                </div>
+                
+            </div>
+            <div class="bx-base-pofile-cover-info bx-def-page-width relative mx-auto px-6 lg:px-8">
+                <div class="bx-base-pofile-ci-cnt relative flex flex-col -mt-24 lg:-mt-16 lg:flex-row lg:items-center">
+                    <bx_if:show_avatar>
+                        <div class="bx-base-pofile-cover-thumb relative lg:absolute flex justify-center lg:flex-none z-10 __add_class__">
+                            <a class="bx-base-pofile-cover-thumb hover:no-underline" href="__picture_href__" >
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
+                            </a>
+                            <bx_if:show_online>
+                                <div class="bx-base-pofile-unit-online"></div>
+                            </bx_if:show_online>
+                            __picture_tweak__
+                        </div>
+                    </bx_if:show_avatar>
+                    <bx_if:show_avatar_placeholder>
+                        <div class="bx-base-pofile-cover-thumb-placeholder lg:absolute h-24 lg:flex-none"></div>
+                    </bx_if:show_avatar_placeholder>
+                    <div class="bx-base-pofile-cover-user relative flex flex-col lg:flex-row lg:items-start lg:justify-end mt-6 sm:pb-1 lg:w-full box-border">
+                        <div class="bx-base-profile-cover-title-bages min-w-0 flex-1 lg:mt-14 lg:mr-12 mb-2">
+                            <h1 class="bx-def-unit-info pl-1 text-gray-900 dark:text-gray-50 text-center lg:text-left text-4xl leading-14 font-bold truncate">__title__ </h1>
+                            <div class="bx-base-profile-cover-meta-holder mt-2 lg:h-8">
+                                <div class="bx-base-profile-cover-meta lg:absolute flex flex-row flex-wrap justify-center lg:justify-start text-sm">__meta__</div>
+                            </div>
+                        </div>
+                        <div class="bx-base-pofile-cover-actions relative flex lg:flex-1 h-14 md:h-10 mt-6 lg:mt-16" onclick="event.stopPropagation();">__action_menu__</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="bx-def-page-width mx-auto pt-5 px-4 sm:px-6 lg:px-8 border-b border-gray-200 dark:border-gray-800 box-border"></div>
+    </div>
+</div>
+__additional_code__

+ 58 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_groups/cover_block.html

@@ -0,0 +1,58 @@
+<div class="bx-base-profile-cover-block-wrapper">
+    <div class="bx-base-pofile-cover-wrapper __class__ relative bg-gradient-to-b from-gray-100 to-white dark:from-black dark:to-gray-900 rounded-md">
+        <div class="bx-base-pofile-cover relative <bx_if:show_clickable>bx-lnk-cnt</bx_if:show_clickable>">
+            <a href="__content_url__" class="bx-lnk-src hidden"></a>
+            <bx_if:show_cover>
+                <div class="bx-base-pofile-cover-image-wrp relative overflow-hidden">
+                    <div class="bx-base-pofile-cover-image relative h-64 lg:h-40 max-w-7xl mx-auto opacity-100 bg-gradient-to-b from-blue-400 to-blue-500 rounded-t-md __add_class__">
+                        <p class="bx-base-pofile-cover-image box-border absolute h-full w-full">
+                            <img alt="" class="bx-base-pofile-cover-image relative h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t-md __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                        </p>
+                    </div>
+                </div>
+            </bx_if:show_cover>
+            <div class="bx-base-pofile-cover-info relative mx-auto px-6">
+                <div class="bx-base-pofile-ci-cnt relative flex flex-col items-center -mt-24">
+                    <bx_if:show_avatar>
+                        <div class="bx-base-pofile-cover-thumb relative inline-flex justify-center __add_class__">
+                            <a class="bx-base-pofile-cover-thumb" href="__picture_href__" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
+                            </a>
+                            <bx_if:show_online>
+                                <div class="bx-base-pofile-unit-online"></div>
+                            </bx_if:show_online>
+                            __picture_tweak__
+                        </div>
+                    </bx_if:show_avatar>
+                    <bx_if:show_avatar_placeholder>
+                        <div class="bx-base-pofile-cover-thumb-placeholder h-24 lg:h-36"></div>
+                    </bx_if:show_avatar_placeholder>
+                </div>
+                <div class="bx-base-pofile-cover-user relative flex flex-col flex-colmt-6 pt-6 sm:pb-1">
+                    <div class="bx-base-profile-cover-title-bages min-w-0 flex-1 mb-4">
+                        <bx_if:show_title_as_tag>
+                            <h1 class="bx-def-unit-info text-2xl font-bold text-gray-900 dark:text-gray-50 text-center sm:truncate">__title__</h1>
+                        </bx_if:show_title_as_tag>
+                        <bx_if:show_title_as_text>
+                            <div class="bx-def-unit-info text-2xl font-bold text-gray-900 dark:text-gray-50 text-center sm:truncate">__title__</div>
+                        </bx_if:show_title_as_text>
+                        <div class="bx-base-profile-cover-meta-holder">
+                            <div class="bx-base-profile-cover-meta flex flex-row flex-wrap justify-center mt-6 md:mt-2 -ml-1  text-base font-medium">__meta__</div>
+                        </div>
+                    </div>
+                    <div class="bx-base-pofile-cover-actions relative flex lg:flex-1 h-14 md:h-10 mb-4" onclick="event.stopPropagation();">__action_menu__</div>
+                    <bx_if:show_text>
+                        <div class="flex justify-between mb-4">
+                            <div class="font-normal text-sm lg:text-base text-gray-500 group-hover:text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-300">__text__</div>
+                        </div>
+                    </bx_if:show_text>
+                </div>
+                __show_data__
+            </div>
+            __cover_tweak__
+        </div>
+    </div>
+    __picture_popup__
+</div>
+__additional_code__

+ 45 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_profile/cover.html

@@ -0,0 +1,45 @@
+<div class="bx-menu-toolbar-padding pt-16">
+    <div class="bx-base-pofile-cover-wrapper __class__ relative">
+        <div class="bx-base-pofile-cover relative">
+            <div class="bx-base-pofile-cover-image-wrp relative xl:px-4 overflow-hidden">
+                <div class="bx-base-pofile-cover-image bx-def-page-width relative mx-auto opacity-100 xl:rounded-b-lg <bx_if:show_cover_placeholder>bx-bpci-holder h-32 lg:h-32 bg-gradient-to-b from-blue-400 to-blue-500</bx_if:show_cover_placeholder><bx_if:show_cover>h-64 lg:h-80</bx_if:show_cover> __add_class__">
+                    <p class="bx-base-pofile-cover-image box-border absolute h-full w-full">
+                        <img alt="" class="bx-base-pofile-cover-image w-full object-cover bg-cover xl:rounded-b-lg h-full relative __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__); __cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                    </p>
+                    __cover_tweak__
+                </div>
+            </div>
+            <div class="bx-base-pofile-cover-info bx-def-page-width relative mx-auto px-6 lg:px-8">
+                <div class="bx-base-pofile-ci-cnt relative flex flex-col -mt-24 lg:-mt-16 lg:flex-row lg:items-center">
+                    <bx_if:show_avatar>
+                        <div class="bx-base-pofile-cover-thumb bx-def-ava-big-size relative lg:absolute flex self-center lg:flex-none z-10 __add_class__">
+                            <a class="bx-base-pofile-cover-thumb hover:no-underline" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
+                            </a>
+                            <bx_if:show_online>
+                                <div class="bx-base-pofile-unit-online"></div>
+                            </bx_if:show_online>
+                            __picture_tweak__
+                        </div>
+                    </bx_if:show_avatar>
+                    <bx_if:show_avatar_placeholder>
+                        <div class="bx-base-pofile-cover-thumb-placeholder absolute h-48 lg:flex-none"></div>
+                    </bx_if:show_avatar_placeholder>
+                    <div class="bx-base-pofile-cover-user relative flex flex-col lg:flex-row lg:items-start lg:justify-end mt-6 sm:pb-1 lg:w-full box-border">
+                        <div class="bx-base-profile-cover-title-bages min-w-0 flex-1 lg:mt-14 lg:mr-12 mb-2">
+                            <h1 class="bx-def-unit-info pl-1 text-gray-900 dark:text-gray-50 text-center ltr:lg:text-left rtl:lg:text-right text-4xl leading-14 font-bold truncate">__title__</h1>
+                            <div class="bx-base-profile-cover-meta-holder mt-2 lg:h-8">
+                                <div class="bx-base-profile-cover-meta lg:absolute flex flex-row flex-wrap justify-center lg:justify-start text-sm">__meta__</div>
+                            </div>
+                        </div>
+                        <div class="bx-base-pofile-cover-actions relative flex lg:flex-1 h-14 md:h-10 mt-6 lg:mt-16" onclick="event.stopPropagation();">__action_menu__</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <div class="bx-def-page-width mx-auto pt-5 px-4 sm:px-6 lg:px-8 border-b border-gray-200 dark:border-gray-800 box-border"></div>
+    </div>
+    __picture_popup__
+</div>
+__additional_code__

+ 58 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/mod_profile/cover_block.html

@@ -0,0 +1,58 @@
+<div class="bx-base-profile-cover-block-wrapper">
+    <div class="bx-base-pofile-cover-wrapper __class__ relative bg-gradient-to-b from-gray-100 to-white dark:from-black dark:to-gray-900 rounded-md">
+        <div class="bx-base-pofile-cover relative <bx_if:show_clickable>bx-lnk-cnt</bx_if:show_clickable>">
+            <a href="__content_url__" class="bx-lnk-src hidden"></a>
+            <bx_if:show_cover>
+                <div class="bx-base-pofile-cover-image-wrp relative overflow-hidden">
+                    <div class="bx-base-pofile-cover-image relative h-64 lg:h-40 max-w-7xl mx-auto opacity-100 bg-gradient-to-b from-blue-400 to-blue-500 rounded-t-md __add_class__">
+                        <p class="bx-base-pofile-cover-image box-border absolute h-full w-full">
+                            <img alt="" class="bx-base-pofile-cover-image relative h-64 mx-auto w-full object-cover bg-cover lg:h-40 rounded-t-md __img_class__ bx-image-edit-source-__unique_id__" style="background-image:url(__cover_url__);__cover_settins__" src="<bx_icon_url:spacer.gif />" />
+                        </p>
+                    </div>
+                </div>
+            </bx_if:show_cover>
+            <div class="bx-base-pofile-cover-info relative mx-auto px-6">
+                <div class="bx-base-pofile-ci-cnt relative flex flex-col items-center -mt-24">
+                    <bx_if:show_avatar>
+                        <div class="bx-base-pofile-cover-thumb relative inline-flex justify-center __add_class__">
+                            <a class="bx-base-pofile-cover-thumb" href="__picture_href__" href="javascript:" <bx_if:is_avatar>onclick="$('#__picture_popup_id__').dolPopupImage('__picture_url__', $(this).parent()); event.stopPropagation();"</bx_if:is_avatar>>
+                                <img alt="__title_attr__" class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 __img_class__ bx-image-edit-source-__unique_id__" src="__ava_url__"  <bx_if:show_ava_letter> style="display:none" </bx_if:show_ava_letter> />
+                                <p class="bx-base-pofile-unit-thumb bx-def-ava-big bx-def-ava-big-size flex items-center justify-center box-border m-0 rounded-full ring-4 mx-auto ring-white dark:ring-gray-900 h-48 w-48 lg:h-32 lg:w-32 text-white font-bold text-5xl __img_class__-placeholder" style="background-color:rgba(__color__);<bx_if:show_ava_image>display:none</bx_if:show_ava_image>" >__letter__</p>
+                            </a>
+                            <bx_if:show_online>
+                                <div class="bx-base-pofile-unit-online"></div>
+                            </bx_if:show_online>
+                            __picture_tweak__
+                        </div>
+                    </bx_if:show_avatar>
+                    <bx_if:show_avatar_placeholder>
+                        <div class="bx-base-pofile-cover-thumb-placeholder h-24 lg:h-36"></div>
+                    </bx_if:show_avatar_placeholder>
+                </div>
+                <div class="bx-base-pofile-cover-user relative flex flex-col flex-colmt-6 pt-6 sm:pb-1">
+                    <div class="bx-base-profile-cover-title-bages min-w-0 flex-1 mb-4">
+                        <bx_if:show_title_as_tag>
+                            <h1 class="bx-def-unit-info text-2xl font-bold text-gray-900 dark:text-gray-50 text-center sm:truncate">__title__</h1>
+                        </bx_if:show_title_as_tag>
+                        <bx_if:show_title_as_text>
+                            <div class="bx-def-unit-info text-2xl font-bold text-gray-900 dark:text-gray-50 text-center sm:truncate">__title__</div>
+                        </bx_if:show_title_as_text>
+                        <div class="bx-base-profile-cover-meta-holder">
+                            <div class="bx-base-profile-cover-meta flex flex-row flex-wrap justify-center mt-6 md:mt-2 -ml-1  text-base font-medium">__meta__</div>
+                        </div>
+                    </div>
+                    <div class="bx-base-pofile-cover-actions relative flex lg:flex-1 h-14 md:h-10 mb-4" onclick="event.stopPropagation();">__action_menu__</div>
+                    <bx_if:show_text>
+                        <div class="flex justify-between mb-4">
+                            <div class="font-normal text-sm lg:text-base text-gray-500 group-hover:text-gray-600 dark:text-gray-400 dark:group-hover:text-gray-300">__text__</div>
+                        </div>
+                    </bx_if:show_text>
+                </div>
+                __show_data__
+            </div>
+            __cover_tweak__
+        </div>
+    </div>
+    __picture_popup__
+</div>
+__additional_code__

+ 61 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/_block_explore.html

@@ -0,0 +1,61 @@
+<!-- 
+    This file contains a copy of Explore block which is stored in the DB and available for future customizations via Studio -> Pages builder.  
+    It's needed here to let Tailwind compailer know about the classes which should be included in compilation.
+-->
+<style>
+.bx-artificer-splash .bx-form-element .bx-btn.bx-btn-primary {
+    width: 100%;
+}
+</style>
+<div class="bx-artificer-splash relative max-w-7xl ring-1 ring-gray-200 dark:ring-gray-800 bg-gray-50 dark:bg-gray-900 shadow-sm rounded divide-y divide-gray-200 dark:divide-gray-800 my-2 lg:my-3 mx-2 lg:mx-3 xl:mx-auto overflow-hidden">
+    <div class="absolute top-0 left-0 w-full h-full dark:hidden z-1">
+        <img src="<bx_image_url:cover.svg />" class="object-cover h-full w-full" />
+    </div>
+    <div class="absolute top-0 left-0 w-full h-full hidden dark:block z-1">
+        <img src="<bx_image_url:cover-dark.svg />" class="object-cover h-full w-full" />
+    </div>
+    <div class="relative pb-8 z-2">
+        <div class="mt-6">
+            <div class="mx-auto max-w-7xl">
+                <div class="lg:grid lg:grid-cols-12 lg:gap-8">
+                    <div class="px-6 lg:px-8 text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left lg:flex lg:items-center">
+                      <div>
+                        <h1 class="text-5xl tracking-tight font-bold text-gray-800 dark:text-white xl:text-6xl">
+                            <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l1 /></span>
+                            <span class="block pb-3 bg-clip-text text-transparent bg-gradient-to-r from-green-500 to-blue-500 sm:pb-5"><bx_text:_bx_artificer_txt_splash_welcome_l2 /></span>
+                        </h1>
+                        <p class="mt-3 text-base font-normal text-gray-700 dark:text-gray-300 sm:mt-5 sm:text-xl lg:text-lg xl:text-xl">
+                            <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l3 /></span>
+                        </p>
+                        <p class="mt-3 text-base font-light text-gray-700 dark:text-gray-300 sm:mt-5 sm:text-sm lg:text-xs xl:text-base">
+                            <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l4 /></span>
+                        </p>
+                      </div>
+                    </div>
+                    <div class="relative mt-16 px-6 lg:mt-0 lg:px-8 lg:col-span-6 lg:ml-4">
+                        <div class="opacity-80 relative max-w-lg ring-1 ring-white dark:ring-gray-700 sm:overflow-hidden bg-gray-50 dark:bg-gray-800 shadow-2xl rounded divide-y divide-gray-300 dark:divide-gray-700 m-2 lg:m-3  mx-auto bg-opacity-80">
+                            <div class="p-8">
+                                <div>
+                                    <h2 class="text-2xl font-semibold text-gray-800 dark:text-gray-200"><bx_text:_bx_artificer_txt_splash_login_title /></h2>
+                                    <div class="mt-6">{{~system:login_form:TemplServiceLogin["no_join_text no_auth_buttons"]~}}</div>
+                                    <div class="mt-6 relative">
+                                        <div class="absolute inset-0 flex items-center" aria-hidden="true">
+                                            <div class="w-full border-t border-gray-300 dark:border-gray-700"></div>
+                                        </div>
+                                    </div>
+                                    <div class="pt-6">
+                                        <a class="bx-btn w-full flex justify-center py-2 px-4 border border-transparent rounded shadow-sm text-sm font-medium text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" href="__join_link__"><bx_text:_bx_artificer_txt_splash_login_join /></a>
+                                    </div>
+                                    <div class="mt-4">{{~system:member_auth_code:TemplServiceLogin~}}</div>
+                                </div>
+                            </div>
+                            <div class="px-4 py-6 bg-white dark:bg-gray-900 bg-opacity-50 sm:px-10">
+                                <p class="text-xs leading-5 text-gray-500">{{~bx_artificer:get_splash_marker["login_agreement"]~}}</p>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 93 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/_block_splash.html

@@ -0,0 +1,93 @@
+<!-- 
+    This file contains a copy of Splash block which is stored in the DB and available for future customizations via Studio -> Pages builder.  
+    It's needed here to let Tailwind compailer know about the classes which should be included in compilation.
+-->
+<style>
+.bx-artificer-splash .bx-form-element .bx-btn.bx-btn-primary {
+    width: 100%;
+}
+</style>
+<div class="bx-artificer-splash relative bg-gradient-to-br from-gray-100 to-blue-100 dark:bg-gradient-to-r dark:from-gray-900 dark:to-black overflow-hidden">
+    {{~bx_artificer:get_splash_marker["header"]~}}
+    <div class="relative pt-6 pb-16 sm:pb-24">
+        <div class="absolute top-0 left-0 w-full h-full dark:hidden z-1">
+            <img src="<bx_image_url:cover.svg />" class="object-cover h-full w-full" />
+        </div>
+        <div class="absolute top-0 left-0 w-full h-full hidden dark:block z-1">
+            <img src="<bx_image_url:cover-dark.svg />" class="object-cover h-full w-full" />
+        </div>
+        <div class="relative mt-16 z-2">
+            <div class="mx-auto max-w-7xl">
+                <div class="lg:grid lg:grid-cols-12 lg:gap-8">
+                    <div class="px-6 lg:px-8 text-center md:max-w-2xl md:mx-auto lg:col-span-6 lg:text-left lg:flex lg:items-center">
+                        <div>
+                            <h1 class="text-5xl tracking-tight font-bold text-gray-800 dark:text-white xl:text-6xl">
+                                <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l1 /></span>                      
+                                <span class="block pb-3 bg-clip-text text-transparent bg-gradient-to-r from-green-500 to-blue-500 sm:pb-5"><bx_text:_bx_artificer_txt_splash_welcome_l2 /></span>
+                            </h1>
+                            <p class="mt-3 text-base font-normal text-gray-700 dark:text-gray-300 sm:mt-5 sm:text-xl lg:text-lg xl:text-xl">
+                                <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l3 /></span>
+                            </p>
+                            <p class="mt-3 text-base font-light text-gray-700 dark:text-gray-300 sm:mt-5 sm:text-sm lg:text-xs xl:text-base">
+                                <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l4 /></span>
+                            </p>
+                        </div>
+                    </div>
+                    <div class="relative mt-16 px-6 sm:mt-24 lg:mt-0 lg:px-8 lg:col-span-6">
+                        <div class="opacity-80 relative max-w-lg ring-1 ring-white dark:ring-gray-700 sm:overflow-hidden bg-gray-50 dark:bg-gray-800 shadow-2xl rounded divide-y divide-gray-300 dark:divide-gray-700 m-2 lg:m-3  mx-auto bg-opacity-80">
+                            <div class="p-8">
+                                <div>
+                                    <h2 class="text-2xl font-semibold text-gray-800 dark:text-gray-200"><bx_text:_bx_artificer_txt_splash_login_title /></h2>
+                                    <div class="mt-6">{{~system:login_form:TemplServiceLogin["no_join_text no_auth_buttons"]~}}</div>
+                                    <div class="mt-6 relative">
+                                        <div class="absolute inset-0 flex items-center" aria-hidden="true">
+                                            <div class="w-full border-t border-gray-300 dark:border-gray-700"></div>
+                                        </div>
+                                    </div>
+                                    <div class="pt-6">
+                                        <a class="bx-btn w-full flex justify-center py-2 px-4 border border-transparent rounded shadow-sm text-sm font-medium text-white bg-green-600 hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500" href="__join_link__"><bx_text:_bx_artificer_txt_splash_login_join /></a>
+                                    </div>
+                                    <div class="mt-4">{{~system:member_auth_code:TemplServiceLogin~}}</div>
+                                </div>
+                            </div>
+                            <div class="px-4 py-6 bg-white dark:bg-gray-900 bg-opacity-50 sm:px-10">
+                                <p class="text-xs leading-5 text-gray-500">{{~bx_artificer:get_splash_marker["login_agreement"]~}}</p>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<div class="bg-gray-100 dark:bg-gray-900 pt-12 sm:pt-16">
+    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
+        <div class="max-w-4xl mx-auto text-center">
+            <h2 class="text-3xl font-semibold text-gray-900 dark:text-gray-100 sm:text-4xl"><bx_text:_bx_artificer_txt_splash_stats_l1 /></h2>
+            <p class="mt-3 text-xl font-light text-gray-500 sm:mt-4"><bx_text:_bx_artificer_txt_splash_stats_l2 /></p>
+        </div>
+    </div>
+    <div class="mt-10 pb-12 bg-white dark:bg-black sm:pb-16">
+        <div class="relative">
+            <div class="absolute inset-0 h-1/2 bg-gray-100 dark:bg-gray-900 "></div>
+            <div class="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
+                <div class="max-w-7xl mx-auto">
+                    <dl class="rounded-lg bg-white dark:bg-gray-800 shadow-lg sm:grid sm:grid-cols-3">
+                        <div class="flex flex-col border-b border-gray-100 dark:border-gray-700 p-4 pt-5 text-center sm:border-0 sm:border-r">
+                            <dt class="order-2 mt-2 text-lg leading-6 font-light text-gray-500"><bx_text:_bx_artificer_txt_splash_stats_c1 /></dt>
+                            <dd class="order-1 text-3xl font-bold text-blue-600">{{~bx_artificer:get_splash_marker["members"]~}}</dd>
+                        </div>
+                        <div class="flex flex-col border-t border-b border-gray-100 dark:border-gray-900 p-4 pt-5  text-center sm:border-0 sm:border-l sm:border-r">
+                            <dt class="order-2 mt-2 text-lg leading-6 font-light text-gray-500"><bx_text:_bx_artificer_txt_splash_stats_c2 /></dt>
+                            <dd class="order-1 text-3xl font-bold text-blue-600">{{~bx_artificer:get_splash_marker["posts"]~}}</dd>
+                        </div>
+                        <div class="flex flex-col border-t border-gray-100  dark:border-gray-700 p-4 pt-5 text-center sm:border-0 sm:border-l">
+                            <dt class="order-2 mt-2 text-lg leading-6 font-light text-gray-500"><bx_text:_bx_artificer_txt_splash_stats_c3 /></dt>
+                            <dd class="order-1 text-3xl font-bold text-blue-600">{{~bx_artificer:get_splash_marker["comments"]~}}</dd>
+                        </div>
+                    </dl>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 175 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/_header_js_custom.html

@@ -0,0 +1,175 @@
+<script language="javascript">
+    $(document).ready(function () {
+        bx_activate_anim_icons('#283C50');
+
+        var aSidebars = ['site', 'account'];
+        for(var i in aSidebars) {
+            if(typeof(aSidebars[i]) != 'string')
+                continue;
+
+            var oSidebar = bx_sidebar_get(aSidebars[i]);
+
+            $('.bx-sidebar-' + aSidebars[i] + '-trigger').on('click', function(event) {
+                event.preventDefault();
+
+                var aMatches = $(this).attr('class').match(/bx-sidebar-(.*)-trigger/);
+                if(!aMatches || aMatches.length != 2)
+                    return;
+
+                bx_sidebar_toggle(aMatches[1]);
+            });
+
+            $('.bx-sidebar .bx-sidebar-' + aSidebars[i] + '-bg').on('click', function(event){
+                event.preventDefault();
+
+                var aMatches = $(this).attr('class').match(/bx-sidebar-(.*)-bg/);
+                if(!aMatches || aMatches.length != 2)
+                    return;
+                
+                bx_sidebar_toggle(aMatches[1]);
+            });
+
+            $('.bx-sidebar .bx-sidebar-' + aSidebars[i] + '-close').on('click', function(event){
+                event.preventDefault();
+
+                var aMatches = $(this).attr('class').match(/bx-sidebar-(.*)-close/);
+                if(!aMatches || aMatches.length != 2)
+                    return;
+
+                bx_sidebar_toggle(aMatches[1]);
+            });
+
+            $('.bx-sidebar.bx-sidebar-' + aSidebars[i] + ' .bx-focus-trap').bind('focus', function() {
+                var aFocusable = bx_get_focusable(oSidebar.get(0));
+                if(aFocusable && aFocusable.length > 0)
+                    $(aFocusable[0]).focus();
+            });
+        }
+
+        //--- Escape closes whichever sidebar is open; bx_sidebar_toggle returns focus to its trigger.
+        $(document).on('keydown.bx-sidebar', function(event) {
+            if(event.which != 27 && event.key != 'Escape')
+                return;
+
+            for(var j in aSidebars) {
+                if(typeof(aSidebars[j]) != 'string' || !bx_sidebar_active(aSidebars[j]))
+                    continue;
+
+                event.preventDefault();
+                bx_sidebar_toggle(aSidebars[j]);
+            }
+        });
+    });
+
+    function bx_sidebar_get(sType) {
+        return $('.bx-sidebar.bx-sidebar-' + sType);
+    }
+
+    function bx_sidebar_active(sType) {
+        var oSidebar = bx_sidebar_get(sType);
+        if(!oSidebar || oSidebar.length == 0)
+            return false;
+
+        return oSidebar.hasClass('bx-sidebar-active');
+    }
+
+    function bx_sidebar_toggle(sType) {
+        var oSidebar = bx_sidebar_get(sType);
+        var bSidebarActive = bx_sidebar_active(sType);
+
+        oSidebar.toggleClass('bx-sidebar-active', !bSidebarActive);
+
+        var oTrigger = $('.bx-sidebar-' + sType + '-trigger');
+        oTrigger.attr('aria-expanded', !bSidebarActive ? 'true' : 'false');
+
+        if(!bSidebarActive) {
+            var aFocusable = bx_get_focusable(oSidebar.get(0));
+            if(aFocusable && aFocusable.length > 0)
+                $(aFocusable[0]).focus();
+        }
+        else {
+            var oReturnTo = bx_clicked_stack_pop();
+            $(oReturnTo || oTrigger.filter(':visible').get(0)).focus();
+        }
+    }
+
+    function bx_sidebar_dropdown_toggle(oLink) {
+        var oItem = $(oLink).parents('.bx-sidebar-item:first');
+        oItem.toggleClass('bx-si-dropdown-open').find('.bx-si-dropdown-icon').toggleClass('rotate-0 rotate-90');
+        $(oLink).attr('aria-expanded', oItem.hasClass('bx-si-dropdown-open') ? 'true' : 'false');
+
+        return false;
+    }
+
+    function bx_site_search_show(oButtom) {
+        var oButton = $(oButtom).parents('.bx-ti-search-button');
+        oButton.addClass('bx-tis-button-hidden').find('button,a').attr('aria-expanded', 'true');
+
+        var oBox = oButton.parents('.bx-ti-search').find('.bx-ti-search-box');
+        oBox.addClass('bx-tis-box-shown');
+        
+        oBox.find('.bx-form-input-text').focus();
+
+        setTimeout(function () {
+            $(document).on('click.bx-site-search-phone touchend.bx-site-search-phone', function (event) {
+                if ($(event.target).parents('.sys-search-results-quick,.bx-ti-search-box,.bx-ti-search-button').length || $(event.target).filter('.sys-search-results-quick,.bx-ti-search-box,.bx-ti-search-button').length)
+                    event.stopPropagation();
+                else {
+                    bx_site_search_close_all_opened();
+                    oBox.removeClass('bx-tis-box-shown');
+                    oButton.removeClass('bx-tis-button-hidden').find('button,a').attr('aria-expanded', 'false').focus();
+                }
+            });
+        }, 10);
+    }
+
+    function bx_site_search_complete(oContainer, oData) {
+        if(!oData) {
+            if(oContainer.is(':visible'))
+                oContainer.hide();
+
+            return;
+        }
+
+        oContainer.show();
+
+        setTimeout(function () {
+            var iWidthPrev = $(window).width();
+            $(window).on('resize.bx-site-search', function () {
+                if($(this).width() == iWidthPrev)
+                    return;
+
+                iWidthPrev = $(this).width();
+                bx_site_search_close_all_opened();
+            });
+ 
+            $(document).on('click.bx-site-search touchend.bx-site-search', function (event) {
+                if ($(event.target).parents('.sys-search-results-quick').length || $(event.target).filter('.sys-search-results-quick').length || e === event.target)
+                    event.stopPropagation();
+                else
+                    bx_site_search_close_all_opened();
+            });
+
+        }, 10);
+    }
+
+    function bx_site_search_cancel(oForm)
+    {
+        const oBox = $(oForm).parents('.bx-ti-search').find('.bx-ti-search-box');
+        const oButton = $(oForm).parents('.bx-ti-search').find('.bx-ti-search-button');
+
+        const sClassBox = 'bx-tis-box-shown';
+        const sClassButton = 'bx-tis-button-hidden';
+        if(oBox.hasClass(sClassBox) && oButton.hasClass(sClassButton)) {
+            bx_site_search_close_all_opened();
+            oBox.removeClass(sClassBox);
+            oButton.removeClass(sClassButton).find('button,a').attr('aria-expanded', 'false').focus();
+        }
+    }
+
+    function bx_site_search_close_all_opened() {
+        $('.sys-search-results-quick:visible').each(function () {
+            $(this).hide();
+        });
+    }
+</script>

+ 14 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/block_join.html

@@ -0,0 +1,14 @@
+<div class="sys-jf">
+    <bx_if:show_auth>__content__</bx_if:show_auth>
+    <bx_if:show_form>__content__</bx_if:show_form>
+    <bx_if:show_login>
+        <hr class="bx-def-hr my-4" />
+        <div class="sys-jf-login">
+            <a class="bx-btn w-full justify-center text-center" href="__url__"><bx_text:_sys_txt_join_description_action /></a>
+        </div>
+    </bx_if:show_login>
+    <div class="sys-jf-agreement -mx-4">
+        <hr class="bx-def-hr mt-4" />
+        <div class="sys-jf-agreement-cnt pt-4 px-4 text-xs text-gray-600 dark:text-gray-400 [&_a]:underline [&_a]:underline-offset-2">__agreement__</div>
+    </div>
+</div>

+ 34 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/block_login.html

@@ -0,0 +1,34 @@
+<div class="sys-lf">
+    __custom_html_before__
+    <bx_if:show_auth>__content__</bx_if:show_auth>
+    <bx_if:show_form>__content__</bx_if:show_form>
+    __custom_html_after__
+    <bx_if:show_join>
+        <hr class="bx-def-hr my-4" />
+        <div class="sys-lf-join">
+            <a class="bx-btn w-full justify-center text-center" href="__url__"><bx_text:_sys_txt_login_description_action /></a>
+        </div>
+    </bx_if:show_join>
+    <div class="sys-lf-agreement -mx-4">
+        <hr class="bx-def-hr mt-4" />
+        <div class="sys-lf-agreement-cnt pt-4 px-4 text-xs text-gray-600 dark:text-gray-400 [&_a]:underline [&_a]:underline-offset-2">__agreement__</div>
+    </div>
+    <bx_if:show_js_code>
+        <script>
+            (bx_login_init_ajax_form = function () {
+                $('#sys-form-login').ajaxForm({
+                    dataType: 'json',
+                    success: function (oData) {
+                        if ('undefined' !== typeof(oData['res']) && 'OK' == oData['res']) {
+                            location.reload();
+                        }
+                        else if ('undefined' !== typeof(oData['form'])) {
+                            $('#sys-form-login').replaceWith(oData['form']);
+                            bx_login_init_ajax_form();
+                        }
+                    }
+                });
+            })();
+        </script>
+    </bx_if:show_js_code>
+</div>

+ 30 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/cover.html

@@ -0,0 +1,30 @@
+<bx_if:logged_in>
+<style>
+    .bx-hide-when-logged-in {
+        display:none !important;
+    }
+</style>
+</bx_if:logged_in>
+<div class="bx-menu-toolbar-padding pt-16">
+    <div class="bx-cover-gap overflow-hidden">
+        <div class="bx-cover-wrapper<bx_if:empty_cover_class> bx-cover-empty</bx_if:empty_cover_class> relative" <bx_if:bg>style="background-image:url(__image_url__)"</bx_if:bg>>
+            <div class="bx-cover-gradient bx-def-page-width relative mx-auto"></div>
+            <div class="relative mx-auto py-16 text-center">
+                <bx_if:image>
+                    <div class="bx-cover-image">
+                        <img class="border rounded-md" style="background-image:url(__icon_url__)" src="<bx_icon_url:spacer.gif />" />
+                    </div>
+                </bx_if:image>
+                <div class="bx-cover-title flex justify-center items-center">
+                    <bx_if:title>
+                    <h1 class="text-4xl font-bold tracking-tight text-gray-900 dark:text-gray-50">
+                        <span class="block pb-1 relative">__title__</span>
+                        <span class="block pb-1 bg-clip-text text-transparent bg-gradient-to-r from-green-500 to-blue-500"></span>
+                    </h1>
+                    </bx_if:title>
+                </div>
+                <div class="bx-cover-actions">__actions__</div>
+            </div>
+        </div>
+    </div>
+</div>

+ 36 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/cover_home.html

@@ -0,0 +1,36 @@
+<bx_if:logged_in>
+<style>
+    .bx-hide-when-logged-in {
+        display:none !important;
+    }
+</style>
+</bx_if:logged_in>
+<div class="bx-menu-toolbar-padding pt-16">
+    <div class="bx-cover-gap overflow-hidden">
+        <div class="bx-cover-wrapper<bx_if:empty_cover_class> bx-cover-empty</bx_if:empty_cover_class> relative" <bx_if:bg>style="background-image:url(__image_url__)"</bx_if:bg>>
+            <div class="bx-cover-gradient bx-def-page-width relative mx-auto"></div>
+            <div class="relative mx-auto py-16 text-center">
+                <div>
+                    <h1 class="text-4xl  sm:text-5xl xl:text-6xl tracking-tight  font-bold text-gray-800 dark:text-white ">
+                        <span class="block pb-1 relative"><bx_text:_bx_artificer_txt_splash_welcome_l1 /></span>
+                        <span class="block pb-1  bg-clip-text text-transparent bg-gradient-to-r from-green-500 to-blue-500"><bx_text:_bx_artificer_txt_splash_welcome_l2 /></span>
+                    </h1>
+                    <p class="p-8  font-light text-gray-700 dark:text-gray-300 text-base  sm:text-lg xl:text-xl">
+                        <span class="block"><bx_text:_bx_artificer_txt_splash_welcome_l3 /></span>
+                    </p>
+                    <div class=" w-full flex justify-center items-center">
+                        <button type="button" onclick="document.location='__link_join__'"  class="bx-btn bx-btn-primary">
+                            <bx_text:_bx_artificer_txt_splash_welcome_a1 />
+                        </button>
+                        <button type="button"  onclick="document.location='__link_login__'" class="bx-btn ml-3">
+                            <svg class="-ml-1 mr-2 h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
+                              <path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path>
+                            </svg>
+                            <bx_text:_bx_artificer_txt_splash_welcome_a2 />
+                        </button>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>

+ 463 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/css/forms.css

@@ -0,0 +1,463 @@
+/*--
+import url(../../../../../../../template/css/forms.css);
+--*/
+
+.bx-form-advanced-wrapper .bx-form-section-wrapper:first-child {
+    margin-top:0;
+}
+
+.bx-form-advanced-wrapper .bx-form-section-wrapper:last-child {
+    margin-bottom:0;
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:first-child {
+    border: none; 
+    padding: 0; 
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:first-child .bx-form-section-content {
+    padding-top:0; 
+}
+
+.bx-form-advanced-wrapper .bx-form-section-divider:last-child .bx-form-section-content {
+    padding-bottom:0;
+}
+
+.bx-form-input-wrapper-pgc {
+    position: relative;
+}
+
+.bx-form-option-info {
+    display: inline-flex;
+    flex-direction: column;
+}
+
+/*-- Section Toggler ---*/
+.bx-form-section-wrapper {
+    position: relative;
+}
+
+.bx-form-section {
+    margin: 0;
+}
+
+.bx-form-section-header .bx-form-section-title {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-flex-wrap: nowrap;
+    flex-wrap: nowrap;
+
+    line-height: 1.25rem;
+    text-transform: uppercase;
+}
+
+.bx-form-section-header .bx-form-section-title .sys-icon {
+    color: inherit !important;
+}
+
+.bx-form-section-header .bx-form-section-title u {
+    cursor: pointer;
+}
+
+.bx-form-section-header .bx-form-section-title span {
+    white-space: nowrap;
+    text-transform: none;
+    font-size: 0.75rem;
+}
+
+.bx-form-section-hidden .bx-form-section-content {
+    display:none;
+}
+
+.bx-form-collapsable .bx-form-section-toggler {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    width: 1.25rem;
+    height: 1.25rem;
+
+    text-decoration: none;
+
+    -moz-transform: rotate(180deg);
+    -webkit-transform: rotate(180deg);
+    -ms-transform: rotate(180deg);
+    -o-transform: rotate(180deg);
+
+    -webkit-transition: all 0.5s ease;
+    -moz-transition: all 0.5s ease;
+    -ms-transition: all 0.5s ease;
+    -o-transition: all 0.5s ease;
+
+    line-height: 1.25rem;
+}
+
+.bx-form-collapsed .bx-form-section-toggler {
+    -moz-transform: rotate(0deg);
+    -webkit-transform: rotate(0deg);
+    -ms-transform: rotate(0deg);
+    -o-transform: rotate(0deg);
+}
+
+.bx-form-section-toggler .sys-icon {
+    font-size:0.875rem;
+}
+
+/*--- One Line fields ---*/
+.bx-form-element-wrapper-oneline .bx-form-element {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-flow: row nowrap;
+    flex-flow: row nowrap;
+    -webkit-align-items: flex-start;
+    align-items: flex-start;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+.bx-form-input-wrapper-submit .bx-btn {
+    float: none;
+}
+.bx-form-input-wrapper-input_set .bx-btn {
+    float: left;
+}
+
+
+/*-- Form field: Password --*/
+.bx-artificer .bx-form-input-wrapper-password > .password-show,
+.bx-artificer .bx-form-input-wrapper-password > .password-hide {
+    position: absolute;
+    z-index: 1000;
+    
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+
+    top: 0;
+    right: 0;    
+    height: 100%;
+
+    /* WCAG 2.5.8 (AA): at least 24px wide. 1.75rem is the project's "mini"
+       button size. The side margin is reduced by exactly half the added
+       width, (28px - 18px) / 2 = 5px, so the eye glyph does not move. */
+    min-width: 1.75rem;
+
+    margin: 0 0.1875rem;
+}
+.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-password > .password-show,
+.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-password > .password-hide {
+    left: 0;
+    right: auto;
+}
+.bx-artificer .bx-form-input-password {
+    position: relative;
+
+    -moz-box-sizing: border-box;
+    -ms-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+    box-sizing: border-box;
+
+    width: 100%;
+    height: 100%;
+
+    margin: 0;
+    padding: 0.5rem 0;
+
+    border: 0;
+    background-color: transparent;
+}
+.bx-artificer .bx-form-input-password:focus {
+    border-color: transparent;
+    outline: none;
+    box-shadow: none;
+}
+
+
+/*-- Form field: Slider/Doublerange --*/
+.bx-form-input-wrapper-slider,
+.bx-form-input-wrapper-doublerange {
+    position: relative;
+}
+.bx-form-input-wrapper-slider .ui-slider,
+.bx-form-input-wrapper-doublerange .ui-slider {
+    position: absolute;
+    top: 0px;
+    right: 0px;
+}
+.bx-form-input-wrapper-slider .ui-slider .ui-slider-handle,
+.bx-form-input-wrapper-doublerange .ui-slider .ui-slider-handle { 
+    z-index: 1;
+}
+
+/*-- Form field: Price --*/
+.bx-form-element .bx-form-value .bx-form-input-wrapper-price {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: stretch;
+    align-items: stretch;
+}
+.bx-form-element .bx-form-value .bx-form-input-wrapper-price span {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+
+    width: auto;
+}
+.bx-dir-ltr .bx-form-element .bx-form-value .bx-form-input-wrapper-price span {
+    border-right-width: 0;
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+.bx-dir-rtl .bx-form-element .bx-form-value .bx-form-input-wrapper-price span {
+    border-left-width: 0;
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+}
+.bx-dir-ltr .bx-form-element .bx-form-value .bx-form-input-price:not(:first-child) {
+    border-top-left-radius: 0;
+    border-bottom-left-radius: 0;
+}
+.bx-dir-rtl .bx-form-element .bx-form-value .bx-form-input-price:not(:first-child) {
+    border-top-right-radius: 0;
+    border-bottom-right-radius: 0;
+}
+
+
+/*-- Form field: Date/Time Pickers --*/
+.bx-form-datepicker-modal {
+    z-index: 10001 !important;
+}
+
+
+/*-- Form field: Switcher --*/
+.bx-switcher-cont input {
+   display: none !important;
+}
+
+
+/*-- Form field: Checkbox/Radio Set --*/
+.bx-form-input-wrapper-checkbox_set label,
+.bx-artificer .bx-form-input-wrapper-radio_set label {
+    margin-left: 0.5rem;
+    vertical-align: text-bottom;
+}
+.bx-dir-rtl .bx-form-input-wrapper-checkbox_set label,
+.bx-dir-rtl.bx-artificer .bx-form-input-wrapper-radio_set label {
+    margin-left: 0;
+    margin-right: 0.5rem;
+}
+
+
+/*--- Form field: File ---*/
+.bx-form-input-wrapper-file .bx-btn {
+    display: inline-block;
+    float: none;
+}
+.bx-form-input-file {
+    position: fixed;
+    top: -1000px;
+
+    border: none;
+    background-color: transparent;
+    visibility: hidden;
+}
+
+
+/*--- Form field: Location ---*/
+.bx-form-element .bx-form-value .bx-form-input-location-cont input,
+.bx-form-element .bx-form-value .bx-form-input-location-cont select {
+    display: inline-block;
+}
+.bx-form-element .bx-form-value .bx-form-input-location-cont.minimized input,
+.bx-form-element .bx-form-value .bx-form-input-location-cont.minimized select {
+    display: block;
+}
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-zip,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-city {
+    width:49%;
+}
+.bx-form-element .bx-form-input-location-street {
+    width:83%;
+}
+.bx-form-element .bx-form-input-location-street_number {
+    width:15%;
+}
+.bx-form-element .bx-form-input-location-street_number,
+.bx-form-element .bx-form-input-location-street,
+.bx-form-element .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-city {
+    margin-bottom: 0.25rem;
+}
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-street,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country {
+    margin-left: 0.25rem;
+}
+.bx-dir-rtl .bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-street,
+.bx-dir-rtl .bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-state,
+.bx-dir-rtl .bx-form-element .bx-form-input-location-cont:not(.minimized) .bx-form-input-location-country {
+    margin-left: 0;
+    margin-right: 0.25rem;
+}
+.bx-form-element .bx-form-input-location-cont .bx-form-input-location-status-cont {
+    float:none;
+    width:98%;
+    line-height:normal;
+}
+.bx-form-element .bx-form-input-location-cont.minimized .bx-form-input-location-status-cont {
+    display: flex;
+    flex-direction: column;
+    width: auto;
+}
+.bx-form-element .bx-form-input-location-status {
+    float:left;
+}
+.bx-form-element .bx-form-input-location-copyright {
+    float:right;
+}
+.bx-form-element .bx-form-input-location-cont.minimized .bx-form-input-location-copyright {
+    float: none;
+    margin-top: 0.25rem;
+}
+
+.bx-form-element .bx-form-input-location-auto-cont {
+    display:table;
+}
+.bx-form-element .bx-form-input-location-auto-cont > div {
+    display: table-cell;
+    vertical-align: middle;
+}
+
+
+/*--- Form field: Auto-siggestion ---*/
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) {
+    float: left;
+    padding: 0.125rem 0;
+    height: auto;
+    box-shadow: none;
+    min-height: 2.375rem;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b {
+    display: flex;
+    align-items: center;
+    float: left;
+    margin: 0.125rem;
+    padding-right: 0.5rem;
+    border-radius: 1.25rem;
+
+    line-height: 2rem;
+    white-space: nowrap;
+    font-weight: normal;    
+    cursor: pointer;
+}
+.bx-dir-rtl .bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b {
+    padding-left: 1.5rem;
+    padding-right: 0;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b.val-wo-icon {
+    padding-left: 1.5rem;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b:hover {
+    opacity: 0.7;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) b .sys-icon {
+    display: inline-block;
+    width: 1.0rem;
+    height: 1.0rem;
+    line-height: 1.0rem;
+    text-align: center;
+    font-size: 0.7em;
+    font-weight: bold;
+    vertical-align: middle;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels).bx-form-input-disabled b {
+    cursor: default;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels).bx-form-input-disabled b .sys-icon {
+    display: none;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) input {
+    float: left;
+    width: auto;
+    margin: 0;
+    padding: 0 0 0 0.5rem;
+    border: 0;
+    box-shadow: none;
+}
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-account-unit-wo-info,
+.bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-base-pofile-unit-wo-info {
+    display: inline-block;
+    vertical-align: top;
+
+    margin-right: 0.5rem;
+}
+.bx-dir-rtl .bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-account-unit-wo-info,
+.bx-dir-rtl .bx-form-value .bx-form-input-autotoken:not(.bx-form-input-labels) .bx-base-pofile-unit-wo-info {
+    margin-left: 0.5rem;
+    margin-right: 0;
+}
+
+.sys-labels .bx-form-input-text.bx-form-input-autotoken.bx-form-input-disabled b {
+    height: 2rem;
+    line-height: 2rem;
+}
+
+.select2-container {
+    width:100% !important;
+}
+.bx-form-input-select {
+    -webkit-appearance:none;
+}
+
+/* MiniColors plug-in */
+.bx-form-input-wrapper.bx-form-input-wrapper-text .minicolors-theme-bootstrap .minicolors-swatch {
+    top: 0.5rem;
+    left: 0.5rem;
+
+    width: 1.5625rem;
+    height: 1.5625rem;
+}
+
+/* tiny mce */
+.bx-form-input-wrapper-html .gray-theme.fr-toolbar.fr-top{
+   border-radius: .375rem .375rem 0 0 !important; 
+}
+.bx-form-input-wrapper-html .fr-wrapper{
+    border-radius: 0 0 .375rem .375rem !important; 
+    border-bottom-color: #CCCCCC !important;
+}
+.bx-form-input-wrapper-html .second-toolbar{
+    border-bottom:none !important;
+}
+
+.bx-form-secret {
+    display: inline-flex;
+    align-items: center;
+    justify-content: flex-start;
+    gap: 0.5rem;
+    max-width: 100%;
+    min-width: 0;
+}
+.bx-form-secret-value {
+    min-width: 0;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    font-family: monospace;
+}
+.bx-form-secret-toggle {
+    flex-shrink: 0;
+    line-height: 1;
+    cursor: pointer;
+}
+

+ 17 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/menu_main_submenu.html

@@ -0,0 +1,17 @@
+<ul id="bx-menu-main-submenu" class="bx-menu-main-submenu bx-menu-object-__object__ inline-flex items-stretch w-max">
+    <bx_repeat:menu_items>
+        <li class="bx-menu-item bx-menu-item-__name__ __class_add__ flex" __attrs_wrp__>
+            <a class="group block relative py-4 px-4 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200 whitespace-nowrap text-sm font-medium text-center hover:bg-transparent focus:z-10 box-sizing" href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick> __attrs__>
+                <bx_if:title>
+                    <span class="bx-menu-item-title">__title__</span>
+                </bx_if:title>
+                <bx_if:addon>
+                    <span class="bx-menu-addon bx-stl-mia ml-1">
+                        <span class="bx-menu-addon-cnt">__addon__</span>
+                    </span>
+                </bx_if:addon>
+                <span class="bx-mi-underline absolute inset-x-0 bottom-0 h-0.5 group-hover:bg-gray-500 rounded-md"></span>
+            </a>
+        </li>
+    </bx_repeat:menu_items>
+</ul>

+ 8 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/menu_main_submenu_more_auto.html

@@ -0,0 +1,8 @@
+<ul id="__html_id__" class="bx-menu-main-submenu<bx_if:show_more_auto_class> bx-menu-more-auto</bx_if:show_more_auto_class> bx-menu-object-__object__ flex items-stretch">
+    <bx_repeat:menu_items>
+        <li class="bx-menu-item bx-menu-item-__name__ __class_add__ flex" __attrs_wrp__>
+            <a href="__link__" <bx_if:onclick>onclick="__onclick__"</bx_if:onclick> class="group block relative py-4 px-4 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 hover:text-gray-700 dark:hover:text-gray-200 whitespace-nowrap text-sm font-medium text-center hover:bg-transparent focus:z-10 box-sizing"__attrs__><bx_if:title>__title__</bx_if:title><span class="bx-mi-underline absolute inset-x-0 bottom-0 h-0.5 group-hover:bg-gray-500 rounded-md"></span></a>__popup__
+        </li>
+    </bx_repeat:menu_items>
+</ul>
+__js_code__

+ 4 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/menu_meta_item.html

@@ -0,0 +1,4 @@
+<span class="group flex items-center p-1 border-none rounded-full text-gray-600 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600">
+    <span class="sys-action-counter-icon relative flex items-center justify-center ring-1  h-6 w-6 rounded-full ring-white dark:ring-gray-700 bg-gray-200 dark:bg-gray-700">__icon__</span>
+    <span class="sys-action-counter-text ltr:ml-1 rtl:mr-1">__caption__</span>
+</span>

+ 27 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/profile_avatar.html

@@ -0,0 +1,27 @@
+<div class="bx-profile-avatar text-gray-600 dark:text-gray-300">
+    <div class="bx-profile-avatar-cnt relative flex items-center">
+        <div class="bx-pa-img absolute">__profile_unit__</div>
+        <div class="bx-pa-info w-full" sidebar-toggle-item>
+            <div class="bx-pa-info-cnt flex flex-col justify-center h-10 pl-10 pr-4 box-border">
+                <div class="bx-pai-line text-gray-600 dark:text-gray-300 hover:text-gray-800 dark:hover:text-white font-semibold truncate">
+                    <a href="__profile_url__" title="__profile_title_attr__">__profile_title__</a>
+                </div>
+                <div class="bx-pai-line text-green-700 dark:text-green-400 text-xs font-normal truncate uppercase tracking-wider">
+                    <!--<bx_include_auto:menu_icon.html />--><span>__profile_acl_title__</span>
+                </div>
+            </div>
+        </div>
+        <bx_if:show_switcher_icon>
+            <div class="bx-pa-actions absolute right-0" sidebar-toggle-item>
+                <a class="block" href="__switcher_url__" onclick="__switcher_onclick__">
+                    <div class="bx-pa-action flex items-center justify-center h-8 w-8 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 text-gray-400 hover:text-gray-500 rounded-full">
+                        <div class="bx-icon bx-icon-small">
+                            <bx_image_auto:arrows-alt-v />
+                        </div>
+                    </div>
+                </a>
+            </div>
+        </bx_if:show_switcher_icon>
+    </div>
+</div>
+__switcher__

+ 27 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/profile_stats.html

@@ -0,0 +1,27 @@
+<div class="bx-profile-stats bx-def-border-radius-block">
+    <div class="bx-profile-stats-cnt bx-def-padding">
+        <div class="bx-ps-user">
+            <div class="bx-profile-avatar-cnt bx-stl-mil-hover group flex items-center px-2 py-1.5 rounded-md cursor-pointer" onclick="window.location.href='__profile_url__'">
+                <div class="bx-pa-img absolute">__profile_unit__</div>
+                <div class="bx-pa-info w-full">
+                    <div class="bx-pa-info-cnt flex flex-col justify-center h-10 pl-10 box-border">
+                        <div class="bx-pai-line text-gray-600 dark:text-gray-300 group-hover:text-gray-800 dark:group-hover:text-white font-semibold truncate">__profile_title__</div>
+                        <div class="bx-pai-line text-green-700 dark:text-green-400 text-xs truncate uppercase tracking-wider font-normal">
+                            <div><!--<bx_include_auto:menu_icon.html />--><span>__profile_acl_title__</span></div>
+                        </div>
+                    </div>
+                </div>
+                <!--
+                <div class="bx-pa-actions">
+                    <div class="bx-pa-action flex items-center justify-center h-5 w-5 ml-2 text-gray-400 hover:text-gray-500">
+                        <div class="bx-icon bx-icon-small">
+                            <bx_image_auto:arrows-alt-v />
+                        </div>
+                    </div>
+                </div>
+                -->
+            </div>
+            <div class="bx-ps-menu mt-5 pt-3">__menu__</div>
+        </div>
+    </div>
+</div>

+ 117 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/pt_application.html

@@ -0,0 +1,117 @@
+<bx_include_auto:_header.html />
+<div class="bx-main bx-pt-application <bx_injection:injection_main_class />">
+    <bx_injection:top />
+    <!-- BEG: Navigation -->
+    <nav class="bx-def-z-index-nav fixed w-full bg-white border-b border-gray-200 dark:bg-gray-800 dark:border-gray-700">
+        <div class="px-3 py-3 lg:px-5 lg:pl-3">
+            <div class="flex items-center justify-between">
+                <div class="flex flex-1 items-center justify-start">
+                    <!-- Sidebar Toggler -->
+                    <button id="toggleSidebar" aria-expanded="true" aria-controls="sidebar" class="hidden mr-6 bg-gray-100 dark:bg-gray-700/50 text-gray-600 rounded-full cursor-pointer xl:inline hover:text-gray-900 hover:bg-gray-100 dark:text-gray-400 dark:hover:text-white dark:hover:bg-gray-700">
+                      <div class="bx-icon bx-icon-hamburger flex items-center justify-center h-10 w-10">
+                          <bx_image_auto:bars />
+                      </div>
+                    </button>
+                    <button id="toggleSidebarMobile" aria-expanded="true" aria-controls="sidebar" class="mr-2 bg-gray-100 dark:bg-gray-700/50 text-gray-600 rounded-full cursor-pointer xl:hidden hover:text-gray-900 hover:bg-gray-100 focus:bg-gray-100 dark:focus:bg-gray-700 focus:ring-2 focus:ring-gray-100 dark:focus:ring-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white">
+                      <div id="toggleSidebarMobileHamburger" class="bx-icon bx-icon-hamburger flex items-center justify-center h-10 w-10">
+                          <bx_image_auto:bars />
+                      </div>
+                      <div id="toggleSidebarMobileClose" class="bx-icon bx-icon-close hidden flex items-center justify-center h-10 w-10">
+                        <bx_image_auto:times />
+                      </div>
+                    </button>
+                    <div class="bx-toolbar-items-group relative flex flex-1 items-center justify-start">
+                        <!-- Logo -->
+                        <div id="bx-logo-container" class="bx-toolbar-item bx-ti-left bx-ti-logo flex-none items-center">
+                            <bx_injection:injection_logo_before />
+                            __main_logo__
+                            <bx_injection:injection_logo_after />
+                        </div>
+                        <!-- Menu -->
+                        <div class="bx-toolbar-item bx-ti-menu flex-2 hidden xl:block w-64 ml-4">
+                            <div id="bx-menu-toolbar-1-container" class="bx-toolbar-item bx-ti-menu w-full">
+                                <bx_menu:sys_application />
+                            </div>
+                        </div>
+                        <!-- Search -->
+                        <div class="bx-toolbar-item bx-ti-search flex flex-1 items-center justify-end">
+                            __sys_toolbar_search__
+                        </div>
+                    </div>
+                </div>
+                <bx_menu:sys_toolbar_member />
+            </div>
+        </div>
+    </nav>
+    <!-- END: Navigation -->
+
+    <div class="bx-main-content flex pt-16 overflow-hidden">
+        <!-- BEG: Sidebar -->
+        <aside id="sidebar" class="bx-main-column narrow fixed top-0 left-0 z-20 hidden xl:flex flex-col flex-shrink-0 w-64 h-full pt-16 duration-75 transition-width" aria-label="Sidebar">
+            <div class="bx-mc-border relative flex flex-col flex-1 min-h-0 max-h-full h-full pt-0 bg-white border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700">
+                <div class="flex flex-col flex-1 py-2 overflow-y-auto">
+                    <div class="bx-mc-cnt flex-1 px-4 space-y-1 bg-white divide-y divide-gray-200 dark:bg-gray-800 dark:divide-gray-700">
+                        <bx_menu:sys_site_panel />
+                    </div>
+                </div>
+                <div class="absolute bottom-0 left-0 justify-center hidden w-full p-4 space-x-4 xl:flex" sidebar-bottom-menu>
+                    <!-- Some button based menu may be here -->
+                </div>
+            </div>
+        </aside>
+        <div class="fixed inset-0 z-10 hidden bg-gray-900/50 dark:bg-gray-900/90" id="sidebarBackdrop"></div>
+        <!-- END: Sidebar -->    
+
+        <!-- BEG: Main Content -->
+        <div id="main-content" class="bx-main-column wide relative w-full h-full overflow-y-auto xl:ml-64">
+            <div>
+                <bx_injection:injection_between_cover_logo />
+                __cover__
+                <bx_injection:injection_between_cover_top_menu />
+                <div id="bx-menu-main-bar-wrapper" class="bx-menu-main-bar-wrapper bg-white dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 __site_submenu_hidden__">
+                    <div id="bx-menu-main-bar" class="bx-menu-main-bar __site_submenu_class__ mx-auto px-4 sm:px-6 lg:px-8 box-border">
+                        <div class="bx-menu-main-bar-cnt -mb-px">
+                            <bx_injection:injection_top_menu_before />
+                            <div class="flex items-center h-full text-center">
+                                <div class="relative flex-1 h-full">
+                                    <div class="absolute w-full h-full">
+                                        <bx_menu:sys_site_submenu />
+                                    </div>
+                                </div>
+                                <div class="flex-none">
+                                    <bx_menu:sys_site_manage />
+                                </div>
+                            </div>
+                            <bx_injection:injection_top_menu_after />
+                        </div>
+                    </div>
+                </div>
+                <bx_injection:injection_between_content_menu />
+                <div id="bx-content-wrapper" class="bx-def-page-width mx-auto">
+                    __informer__
+                    <div class="bx-page-wrapper mx-auto px-3 md:px-4 lg:px-6 box-border">
+                        <div id="bx-content-container" class="bx-content-container">
+                            <main role="main"  id="bx-content-main" class="bx-content-main my-2 lg:my-3" tabindex="-1">
+                                <bx_injection:injection_content_before />
+                                __page_main_code__
+                                <bx_injection:injection_content_after />
+                                <bx_injection:banner_bottom />
+                            </main> <!-- #bx-content-main -->
+                            <bx_injection:injection_between_content_footer />
+                        </div> <!-- #bx-content-container -->
+                    </div> <!-- .bx-page-wrapper -->
+                </div> <!-- #bx-content-wrapper -->
+            </div>
+            <footer class="p-4 m-4 bg-white rounded-lg shadow md:flex md:items-center md:justify-between md:p-6 xl:p-8 dark:bg-gray-800">
+                <bx_injection:injection_footer_before />
+                <div id="bx-menu-bottom">
+                    <bx_menu:sys_footer />
+                </div>
+                <bx_injection:injection_footer_after />
+            </footer>
+        </div>
+        <!-- END: Main Content -->
+    </div>
+    <bx_menu:sys_site_action />
+</div> <!-- .bx-main -->
+<bx_include_auto:_footer.html />

+ 30 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplFormView.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    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+class BxTemplFormView extends BxBaseFormView
+{
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+    }
+
+    public function genInputSwitcher(&$aInput)
+    {
+        $aCheckbox = array_merge($aInput, ['type' => 'checkbox']);
+        $bChecked = isset($aInput['checked']) && $aInput['checked'];
+        return $this->oTemplate->parseHtmlByName('form_field_switcher.html', [
+            'class' => $bChecked ? 'on' : 'off',
+            'checked' => $bChecked ? 'true' : 'false', // the button's initial aria-checked; jquery.webForms.js keeps it in step
+            'checkbox' => $this->genInputStandard($aCheckbox),
+            'bx_if:show_label' => $this->genInputSwitcherLabel($aInput)
+        ]);
+    }
+}
+
+/** @} */

+ 300 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplFunctions.php

@@ -0,0 +1,300 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+bx_import('BxDolDesigns');
+
+class BxTemplFunctions extends BxBaseFunctions
+{
+    protected $_sModule;
+
+    public function __construct($oTemplate = null)
+    {
+        parent::__construct($oTemplate);
+
+        $this->_sModule = 'bx_artificer';
+    }
+
+    public function getMainLogoDarkUrl()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoDarkUrl();
+    }
+
+    public function getMainLogoInline()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoParam('logo_inline');
+    }
+
+    public function getMainMarkDarkUrl()
+    {
+        return BxDolDesigns::getInstance()->getSiteMarkDarkUrl();
+    }
+
+    public function getMainMarkInline()
+    {
+        return BxDolDesigns::getInstance()->getSiteLogoParam('mark_inline');
+    }
+
+    public function getMainLogo($aParams = [])
+    {
+        $oModule = BxDolModule::getInstance($this->_sModule);
+        $oDesigns = BxDolDesigns::getInstance();
+
+        $sTitle = getParam('site_title');
+
+        $sAlt = $oDesigns->getSiteLogoAlt();
+        if(empty($sAlt) && !empty($sTitle))
+            $sAlt = $sTitle;
+        $sAltAttr = bx_html_attribute($sAlt, BX_ESCAPE_STR_QUOTE);
+
+        $aImages = [
+            'logo' => ['uc' => 'Logo', 'gi' => 'logo-generic.svg'], 
+            'logo_dark' => ['uc' => 'LogoDark', 'gi' => 'logo-dark-generic.svg'], 
+            'mark' => ['uc' => 'Mark', 'gi' => 'mark-generic.svg'], 
+            'mark_dark' => ['uc' => 'MarkDark', 'gi' => 'mark-dark-generic.svg'], 
+        ];
+
+        $aTmplVarsImages = [];
+        $bLogo = $bLogoDark = $bMark = $bMarkDark = false;
+        foreach($aImages as $sType => &$aParams)
+            if(($aParams['g'] = false) || ($sFileUrl = $this->{'getMain' . $aParams['uc'] . 'Url'}()) !== false || ($aParams['g'] = (($sType == 'logo' || $aImages['logo']['g']) && ($sFileUrl = $this->_oTemplate->getImageUrl($aParams['gi'])) != ''))) {
+                $iLogoHeight = (int)$oDesigns->{'getSite' . $aParams['uc'] . 'Height'}();
+                $sLogoHeight = $iLogoHeight > 0 ? 'height:' . round($iLogoHeight/16, 3) . 'rem;' : '';
+
+                /**
+                 * Generic (SVG) images get the height only, the browser derives the width from the image's own aspect ratio.
+                 * Uploaded images use the dimensions from Designs settings.
+                 */
+                $iLogoWidth = empty($aParams['g']) ? (int)$oDesigns->{'getSite' . $aParams['uc'] . 'Width'}() : 0;
+                $sLogoWidth = $iLogoWidth > 0 ? 'width:' . round($iLogoWidth/16, 3) . 'rem;' : '';
+
+                $aTmplVarsImages[$sType] = [
+                    'id' => 'bx-' . str_replace('_', '-', $sType),
+                    'src' => $sFileUrl,
+                    'alt' => $sAltAttr,
+                    'class' => '',
+                    'style' => $sLogoWidth . ' ' . $sLogoHeight,
+                ];
+
+                ${'b' . $aParams['uc']} = true;
+            }
+
+        $sLogoInline = $sLogoInlineClass = '';
+        if($aImages['logo']['g'] && ($sLogoInline = $this->getMainLogoInline()) != '') {
+            $bLogo = true;
+            $bLogoDark = false;
+            unset($aTmplVarsImages['logo'], $aTmplVarsImages['logo_dark']);
+        }
+
+        $sMarkInline = $sMarkInlineClass = '';
+        if($aImages['mark']['g'] && ($sMarkInline = $this->getMainMarkInline()) != '') {
+            $bMark = true;
+            $bMarkDark = false;
+            unset($aTmplVarsImages['mark'], $aTmplVarsImages['mark_dark']);
+        }
+
+        if($bLogo) {
+            if($bLogoDark && !$bMark)
+                $aTmplVarsImages['logo']['class'] = 'block dark:hidden';
+            if(!$bLogoDark && $bMark) {
+                $sLogoInlineClass = 'hidden lg:block';
+                if(isset($aTmplVarsImages['logo']))
+                    $aTmplVarsImages['logo']['class'] = $sLogoInlineClass;
+            }
+            if($bLogoDark && $bMark)
+                $aTmplVarsImages['logo']['class'] = 'hidden dark:hidden lg:block'; 
+        }
+
+        if($bLogoDark) {
+            $aTmplVarsImages['logo_dark']['class'] = 'hidden dark:block';
+
+            if($bMark || $bMarkDark)
+                $aTmplVarsImages['logo_dark']['class'] = 'hidden dark:lg:block';
+        }
+
+        if($bMark) {
+            $sMarkInlineClass = 'block lg:hidden';
+            if(isset($aTmplVarsImages['mark']))
+                $aTmplVarsImages['mark']['class'] = $sMarkInlineClass;
+
+            if($bMarkDark)
+                $aTmplVarsImages['mark']['class'] = 'block dark:hidden lg:hidden';
+        }
+
+        if($bMarkDark) {
+            $aTmplVarsImages['mark_dark']['class'] = 'hidden dark:block dark:lg:hidden';
+        }
+
+
+        $aAttrs = [
+            'href' => BX_DOL_URL_ROOT, 
+            'title' => $sAltAttr
+        ];
+        if(!empty($aParams['attrs']) && is_array($aParams['attrs']))
+            $aAttrs = array_merge($aAttrs, $aParams['attrs']);
+
+        $sTmplName = 'logo_main.html';
+        $aTmplVars = [
+            'attrs' => bx_convert_array2attrs($aAttrs),
+            'bx_if:show_title' => [
+                'condition' => !$bLogo && !$sLogoInline,
+                'content' => [
+                    'logo' => $sTitle,
+                ]
+            ],
+            'bx_if:show_logo_inline' => [
+                'condition' => !empty($sLogoInline),
+                'content' => [
+                    'class' => $sLogoInlineClass,
+                    'height' => $oModule->_oConfig->getLogoHeight() . 'px',
+                    'content' => $sLogoInline
+                ]
+            ],
+            'bx_if:show_mark_inline' => [
+                'condition' => !empty($sMarkInline),
+                'content' => [
+                    'class' => $sMarkInlineClass,
+                    'height' => $oModule->_oConfig->getMarkHeight() . 'px',
+                    'content' => $sMarkInline
+                ]
+            ]
+        ];
+
+        foreach($aImages as $sType => $aParams) {
+            if(($sTypeIf = 'bx_if:show_' . $sType) && isset($aTmplVarsImages[$sType]))
+                $aTmplVars[$sTypeIf] = [
+                    'condition' => true,
+                    'content' => $aTmplVarsImages[$sType]
+                ];
+            else 
+                $aTmplVars[$sTypeIf] = [
+                    'condition' => false,
+                    'content' => []
+                ];
+        }
+
+        bx_alert('system', 'get_logo', 0, 0, [
+            'tmpl_name' => &$sTmplName,
+            'tmpl_vars' => &$aTmplVars,
+            'tmpl_name_ref' => &$sTmplName,
+            'tmpl_vars_ref' => &$aTmplVars,
+        ]);
+
+        return $this->_oTemplate->parseHtmlByName($sTmplName, $aTmplVars);
+    }
+
+    public function TemplPageAddComponent($sKey)
+    {
+        $mixedResult = false;
+
+        switch($sKey) {
+            case 'sys_header_width':
+                $mixedResult = '';
+                if(getParam('bx_artificer_header_stretched') != 'on')
+                    $mixedResult = parent::TemplPageAddComponent($sKey);
+                break;
+
+            case 'sys_toolbar_search':
+                if(getParam('bx_artificer_header_search') == 'on')
+                    $mixedResult = parent::TemplPageAddComponent($sKey);
+                else
+                    $mixedResult = '';
+                break;
+
+            default:
+                $mixedResult = parent::TemplPageAddComponent($sKey);
+        }
+
+        return $mixedResult;
+    }
+
+    public function getColorSchemeSwitcher()
+    {
+        $oModule = BxDolModule::getInstance($this->_sModule);
+
+        if($oModule->_oConfig->getColorScheme() != 'auto')
+            return '';
+        
+        $aMenu = [
+            ['id' => $this->_sModule . '-css-sun', 'name' => $this->_sModule . '-css-sun', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(1)', 'target' => '_self', 'icon' => 'sun', 'title' => _t('_bx_artificer_txt_color_scheme_light')],
+            ['id' => $this->_sModule . '-css-moon', 'name' => $this->_sModule . '-css-moon', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(2)', 'target' => '_self', 'icon' => 'moon', 'title' => _t('_bx_artificer_txt_color_scheme_dark')],
+            ['id' => $this->_sModule . '-css-desktop', 'name' => $this->_sModule . '-css-desktop', 'class' => '', 'link' => 'javascript:void(0)', 'onclick' => 'javascript:oBxArtificerUtils.setColorScheme(0)', 'target' => '_self', 'icon' => 'desktop', 'title' => _t('_bx_artificer_txt_color_scheme_system')],
+        ];
+        $oMenu = new BxTemplMenu(['template' => 'menu_vertical.html', 'menu_id'=> $this->_sModule . '-css-menu', 'menu_items' => $aMenu]);
+
+        return $oModule->_oTemplate->parseHtmlByName('color_scheme_switcher.html', [
+            'popup' => $this->transBox('bx-sb-theme-switcher-menu', $oMenu->getCode(), true)
+        ]);
+    }
+
+    protected function getInjFooterPopupMenus() 
+    {
+        $sContent = '';
+
+        $oSearch = new BxTemplSearch();
+        $oSearch->setLiveSearch(true);
+        $sContent .= $this->_oTemplate->parsePageByName('search.html', array(
+            'search_form' => $oSearch->getForm(BX_DB_CONTENT_ONLY),
+            'results' => $oSearch->getResultsContainer(),
+        ));
+
+        if(isLogged())
+            $sContent .= $this->_oTemplate->getMenu('sys_add_content');
+
+        return $sContent;
+    }
+
+    protected function getInjFooterSidebarSite() 
+    {
+        $oSearch = new BxTemplSearch();
+        $oSearch->setLiveSearch(true);
+        $sSearch = $oSearch->getForm(BX_DB_CONTENT_ONLY);
+
+        $sLogoUrl = $this->getMainLogoUrl();
+        $bLogoUrl = !empty($sLogoUrl);
+
+        $sLogoText = BxDolDesigns::getInstance()->getSiteLogoAlt();
+        if(empty($sLogoText))
+            $sLogoText = getParam('site_title');
+
+        return $this->_oTemplate->parsePageByName('sidebar_site.html', array(
+            'bx_if:show_logo_image' => array(
+                'condition' => $bLogoUrl,
+                'content' => array(
+                    'logo_url' => $sLogoUrl,
+                    'logo_text' => $sLogoText
+                )
+            ),
+            'bx_if:show_logo_text' => array(
+                'condition' => !$bLogoUrl,
+                'content' => array(
+                    'logo_text' => $sLogoText
+                )
+            ),
+            'search_form' => $sSearch,
+        ));
+    }
+
+    protected function getInjFooterSidebarAccount() 
+    {
+        $oProfile = BxDolProfile::getInstance();
+        if(!$oProfile)
+            return '';
+
+        $sMenuAccountPopup = 'sys_account_popup';
+        $oMenuAccountPopup = BxTemplMenu::getObjectInstance($sMenuAccountPopup);
+
+        return $this->_oTemplate->parsePageByName('sidebar_account.html', [
+            'color_scheme_switcher' => $this->getColorSchemeSwitcher(),
+            'ap_menu_object' => $sMenuAccountPopup,
+            'bx_repeat:ap_menu_items' => $oMenuAccountPopup->getMenuItems(),
+        ]);
+    }
+}
+
+/** @} */

+ 74 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplMenuSidebarSite.php

@@ -0,0 +1,74 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuSidebarSite extends BxTemplMenu
+{
+    protected $_sPageUri;
+    protected $_aHideFromMenu;
+
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        list($sPageUrl, $aPageParams) = bx_get_base_url_inline();
+        $this->_sPageUri = !empty($aPageParams['i']) ? $aPageParams['i'] : '';
+
+        $this->_aHideFromMenu = ['search', 'more-auto'];
+    }
+
+    protected function _getMenuItem ($a)
+    {
+        if(in_array($a['name'], $this->_aHideFromMenu))
+            return false;
+
+        $aResult = parent::_getMenuItem($a);
+        if(empty($aResult) || !is_array($aResult))
+            return $aResult;
+                
+        $aTmplVarsSubmenu = [];
+        $bTmplVarsSubmenu = false;
+        if(($bTmplVarsSubmenu = (!empty($aResult['submenu_object']) && ($oSubmenu = BxDolMenu::getObjectInstance($aResult['submenu_object'])) !== false))) {
+            $aResult['bx_if:onclick'] = [
+                'condition' => true,
+                'content' => [
+                    'onclick' => "javascript:return bx_sidebar_dropdown_toggle(this)"
+            ]];
+            $aResult['class_add'] .= ' bx-si-dropdown-has';
+            $aResult['attrs'] .= ' aria-expanded="false"';
+
+            $aSubmenuItems = $oSubmenu->getMenuItemsRaw();
+            if($oSubmenu->isHtmx() && !$this->_isSelected($a) && !array_key_exists($this->_sPageUri, $aSubmenuItems))
+                $oSubmenu->setHtmx(false);
+
+            $aTmplVarsSubmenu['bx_repeat:submenu_items'] = $oSubmenu->getMenuItems();
+        }
+
+        $aResult['bx_if:show_arrow'] = [
+            'condition' => false && $bTmplVarsSubmenu,
+            'content' => [true],
+        ];
+
+        $aResult['bx_if:show_line'] = [
+            'condition' => true,
+            'content' => [true],
+        ];
+
+        $aResult['bx_if:show_submenu'] = [
+            'condition' => $bTmplVarsSubmenu,
+            'content' => $aTmplVarsSubmenu,
+        ];
+
+        return $aResult;
+    }
+}
+
+/** @} */

+ 97 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/scripts/BxTemplMenuToolbar.php

@@ -0,0 +1,97 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuToolbar extends BxBaseMenuToolbar
+{
+    protected $_aHideFromSiteToolbar;
+    protected $_aHideFromMemberToolbar;
+
+    protected $_bSiteToolbar;    
+
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        $this->_aHideFromSiteToolbar = ['search'];
+        $this->_aHideFromMemberToolbar = [];
+
+        $this->_bSiteToolbar = $this->_sObject == 'sys_toolbar_site';
+    }
+
+    protected function _getMenuItem ($a)
+    {
+        if(in_array($a['hidden_on'], [7, 15])) 
+            return false;
+
+        //--- Update '[Main Menu]' from Site Toolbar
+        if($this->_bSiteToolbar && $a['name'] == 'main-menu')
+            $a['onclick'] = '';
+
+    	//--- Hide '[Search]' from Site Toolbar
+        if($this->_bSiteToolbar && in_array($a['name'], $this->_aHideFromSiteToolbar))
+            return false;
+
+        //--- Hide '[+ Add]' from Member Toolbar
+        if(!$this->_bSiteToolbar && in_array($a['name'], $this->_aHideFromMemberToolbar))
+            return false;
+
+        $a = parent::_getMenuItem ($a);
+        if($a === false)
+            return $a;
+
+        $a['class_add_a'] = '';
+
+        //--- Each of these items is a disclosure: it opens a sidebar or a popup instead of following a link.
+        $sAttrsAdd = '';
+        switch ($a['name']) {
+            case 'main-menu':
+                $a['class_add_a'] = ' bx-sidebar-site-trigger';
+                $a['link'] = 'javascript:void(0)';
+                $a['onclick'] = '';
+                $sAttrsAdd = 'aria-haspopup="dialog" aria-expanded="false" aria-controls="bx-sidebar-site"';
+                break;
+
+            case 'account':
+                $a['class_add_a'] = ' bx-sidebar-account-trigger';
+                $a['link'] = 'javascript:void(0)';
+                $a['onclick'] = '';
+                $sAttrsAdd = 'aria-haspopup="dialog" aria-expanded="false" aria-controls="bx-sidebar-account"';
+                break;
+
+            case 'add-content':
+                $a['class_add'] = str_replace('bx-def-media-phone-hide', '',  $a['class_add']);
+
+                if(isset($a['bx_if:onclick']['content']['onclick']))
+                    $a['bx_if:onclick']['content']['onclick'] = str_replace('bx_menu_slide_inline', 'bx_menu_popup_inline', $a['bx_if:onclick']['content']['onclick']);
+
+                $sAttrsAdd = 'aria-haspopup="true" aria-expanded="false" aria-controls="bx-sliding-menu-sys_add_content"';
+                break;
+
+            case 'notifications-preview':
+                if(isset($a['bx_if:onclick']['content']['onclick']))
+                    $a['bx_if:onclick']['content']['onclick'] = str_replace(["bx_menu_slide", "'site', "], ['bx_menu_popup'], $a['bx_if:onclick']['content']['onclick']);
+
+                //--- No aria-controls, because bx_menu_popup() creates the popup lazily and the id does not
+                //--- exist yet, and no aria-expanded, because the popup is anchored on the ancestor <ul>
+                //--- rather than on this link, so nothing is in a position to keep the state honest.
+                $sAttrsAdd = 'aria-haspopup="dialog"';
+                break;
+        }
+
+        if($sAttrsAdd && isset($a['attrs']))
+            $a['attrs'] .= ' ' . $sAttrsAdd;
+
+        return $a;
+    }
+}
+
+/** @} */

+ 20 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/sidebar_account.html

@@ -0,0 +1,20 @@
+<div id="bx-sidebar-account" class="bx-sidebar bx-sidebar-account bx-def-z-index-modal fixed flex flex-row justify-end inset-0" role="dialog" aria-modal="true" aria-label="<bx_text:_sys_menu_item_title_system_account_menu />">
+    <div class="bx-sidebar-account-bg fixed inset-0 bg-gray-600 opacity-75" aria-hidden="true"></div>
+    <div class="flex-shrink-0 w-12" aria-hidden="true"></div>
+    <div class="bx-sidebar-cnt relative flex max-w-xs w-full py-4 bg-white dark:bg-gray-900">
+        <div class="absolute top-0 ltr:left-0 rtl:right-0 ltr:-ml-12 rtl:-mr-12 pt-2">
+            <button type="button" class="bx-sidebar-account-close ltr:ml-1 rtl:mr-1 flex items-center justify-center h-10 w-10 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white">
+                <span class="sr-only"><bx_text:_bx_artificer_txt_close_sidebar /></span>
+                <div class="bx-icon bx-icon-close text-white">
+                    <bx_image_auto:times />
+                </div>
+            </button>
+        </div>
+        <div class="bx-menu-account-popup bx-menu-object-__ap_menu_object__ flex flex-col w-full">
+            <bx_repeat:ap_menu_items>
+                <div class="bx-menu-account-popup-__name__">__item__</div>
+            </bx_repeat:ap_menu_items>
+        </div>
+        <div class="bx-focus-trap w-0 h-0 outline-none" tabindex="0"></div>
+    </div>
+</div>

+ 21 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/data/template/system/sidebar_site.html

@@ -0,0 +1,21 @@
+<div id="bx-sidebar-site" class="bx-sidebar bx-sidebar-site bx-def-z-index-modal fixed flex lg:hidden inset-0" role="dialog" aria-modal="true" aria-label="<bx_text:_sys_menu_item_title_system_main_menu />">
+    <div class="bx-sidebar-site-bg fixed inset-0 bg-gray-600 opacity-75" aria-hidden="true"></div>
+    <div class="bx-sidebar-cnt relative flex-1 flex flex-col max-w-xs w-full pt-5 pb-4 bg-white dark:bg-gray-900">
+        <div class="absolute top-0 ltr:right-0 rtl:left-0 ltr:-mr-12 rtl:-ml-12 pt-2">
+            <button type="button" class="bx-sidebar-site-close ml-1 flex items-center justify-center h-10 w-10 rounded-full focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white">
+                <span class="sr-only"><bx_text:_bx_artificer_txt_close_sidebar /></span>
+                <div class="bx-icon bx-icon-close text-white">
+                    <bx_image_auto:times />
+                </div>
+            </button>
+        </div>
+        <div class="bx-sidebar-site-logo flex-shrink-0 flex items-center px-4">__main_logo__</div>
+        <div class="mt-5 flex-1 h-0 overflow-y-auto">
+            <nav class="px-2 space-y-1">
+                <bx_menu:bx_artificer_sidebar_site />
+            </nav>
+        </div>
+        <div class="bx-focus-trap w-0 h-0 outline-none" tabindex="0"></div>
+    </div>
+    <div class="flex-shrink-0 w-14" aria-hidden="true"></div>
+</div>

+ 68 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Artificer Artificer template
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_TEMPLATE,
+    'name' => 'bx_artificer',
+    'title' => 'Artificer',
+    'note' => 'Design template',
+    'version' => '15.0.6',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/artificer/',
+    'home_uri' => 'artificer',
+
+    'db_prefix' => 'bx_artificer_',
+    'class_prefix' => 'BxArtificer',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Boonex Artificer Template',
+
+    /**
+     * 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
+    ),
+    'disable' => array(
+        'execute_sql' => 1
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+);
+
+/** @} */

File diff suppressed because it is too large
+ 6 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/install/sql/enable.sql


+ 23 - 0
modules/boonex/artificer/updates/15.0.5_15.0.6/source/template/images/icons/std-icon.svg

@@ -0,0 +1,23 @@
+<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="80" height="80" fill="url(#paint0_linear_artificer)"/>
+<g transform="translate(13.6 13.6) scale(2.2)" fill="none" stroke="url(#paint1_linear_artificer)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+<path d="M3 2h18"/>
+<rect width="18" height="12" x="3" y="6" rx="2"/>
+<path d="M3 22h18"/>
+</g>
+<g transform="translate(13.6 14.6) scale(2.2)" fill="none" stroke="black" stroke-opacity="0.1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
+<path d="M3 2h18"/>
+<rect width="18" height="12" x="3" y="6" rx="2"/>
+<path d="M3 22h18"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_artificer" x1="40" y1="0" x2="40" y2="80" gradientUnits="userSpaceOnUse">
+<stop stop-color="#7C3AED"/>
+<stop offset="1" stop-color="#5B21B6"/>
+</linearGradient>
+<linearGradient id="paint1_linear_artificer" x1="12" y1="2" x2="12" y2="22" gradientUnits="userSpaceOnUse">
+<stop stop-color="white"/>
+<stop offset="1" stop-color="white" stop-opacity="0.6"/>
+</linearGradient>
+</defs>
+</svg>

+ 51 - 0
modules/boonex/oauth2/updates/15.0.0_15.0.1/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' => 'OAuth2 Server',
+    'version_from' => '15.0.0',
+    'version_to' => '15.0.1',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/oauth2/updates/update_15.0.0_15.0.1/',
+    'home_uri' => 'oauth2_update_1500_1501',
+
+    'module_dir' => 'boonex/oauth2/',
+    'module_uri' => 'oauth2',
+
+    'db_prefix' => 'bx_oauth_',
+    'class_prefix' => 'BxOAuth',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'OAuth2 Server',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/oauth2/updates/15.0.0_15.0.1/install/installer.php

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

+ 429 - 0
modules/boonex/oauth2/updates/15.0.0_15.0.1/source/classes/BxOAuthAPI.php

@@ -0,0 +1,429 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+use OAuth2\Response;
+
+class BxOAuthAPI extends BxDol
+{
+    protected $_oModule;
+    protected $_oDb;
+    public $aAction2Scope = array (
+        'me' => 'basic,market,service,api',
+        'user' => 'basic,market,service,api',
+        'friends' => 'basic,market,service,api',
+        'service' => 'service',
+        'market' => 'market',
+        'api' => 'api',
+    );
+    public $aExceptionsAPI = array ('output', 'errorOutput', 'isPublicAPI');
+
+    function __construct($oModule)
+    {
+        $this->_oModule = $oModule;
+        $this->_oDb = $oModule->_oDb;
+    }
+
+    /**
+     * @page private_api API Private
+     * @section private_api_me /m/oauth2/api/me
+     * 
+     * Provides information about current profile.  
+     *
+     * **Scopes:** 
+     * `basic`, `service`, `market`
+     * 
+     * **HTTP Method:** 
+     * `GET`
+     *
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "id":"123",
+     *     "type":"bx_organizations",
+     *     "email":"test@example.com",
+     *     "role":"1",
+     *     "name":"Test",
+     *     "profile_display_name":"Test",
+     *     "profile_link":"http:\/\/example.com\/path-to-una\/page\/view-organization-profile?id=12",
+     *     "picture":"http:\/\/example.com\/path-to-una\/image_transcoder.php?o=bx_organizations_picture&h=36&dpx=1&t=1496247306"
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     * 
+     */
+    function me($aToken)
+    {        
+        if (!($oProfile = BxDolProfile::getInstance($aToken['user_id']))) {
+            $this->errorOutput('404', 'not_found', 'Profile was not found');
+            return;
+        }
+
+        // get current account's profile (it maybe different if user switched to another profile)
+        $oAccount = $oProfile->getAccountObject();
+        if (!($oProfile = BxDolProfile::getInstanceByAccount($oAccount->id()))) {
+            $this->errorOutput('404', 'not_found', 'Profile was not found');
+            return;
+        }
+
+        $aClient = $this->_oDb->getClientsBy(array('type' => 'client_id', 'client_id' => $aToken['client_id']));
+
+        $aProfile = $this->_prepareProfileArray($oProfile, false);
+        $aProfile['owner'] = (int)$aProfile['id'] == (int)$aClient['user_id'];
+
+        $this->output($aProfile);
+    }
+
+    /**
+     * @page private_api API Private
+     * @section private_api_user /m/oauth2/api/user
+     * 
+     * Provides information about particular profile profile.
+     *
+     * **Parameters:**
+     * - `id` - profile ID
+     *
+     * Everything else is equivalent to @ref private_api_me
+     */
+    function user($aToken)
+    {
+        $iProfileId = (int)bx_get('id');
+
+        if ($iProfileId == $aToken['user_id']) {
+            $this->me($aToken);
+            return;
+        }
+
+        if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
+            return;
+
+        if (!(BxDolProfile::getInstance($aToken['user_id'])))
+            return;
+
+        $this->output($this->_prepareProfileArray($oProfile, !isAdmin()));
+    }
+
+    /**
+     * @page private_api API Private
+     * @section private_api_friends /m/oauth2/api/friends
+     * 
+     * Get list of friends.
+     *
+     * **Scopes:** 
+     * `basic`, `service`, `market`
+     * 
+     * **HTTP Method:** 
+     * `GET`
+     *
+     * **Parameters:**
+     * - `id` - profile ID
+     * 
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * @code
+     * {  
+     *     "user_id":30,
+     *     "friends":[  
+     *         "24",
+     *         "29",
+     *         "51"
+     *     ]
+     * }
+     * @endcode
+     *
+     * **Response (error):**
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     * 
+     */
+    function friends($aToken)
+    {
+        $iProfileId = (int)bx_get('id');
+
+        if (!($oProfile = $this->_getProfileWithAccessChecking($iProfileId)))
+            return;
+
+        if (!($oConn = BxDolConnection::getObjectInstance('sys_profiles_friends'))) {
+            $this->errorOutput(405, 'not_supported', 'Friends lists aren\'t supported');
+            return false;
+        }
+        
+        $this->output(array(
+            'user_id' => $iProfileId,
+            'friends' => $oConn->getConnectedContent($iProfileId, true),
+        ));
+    }
+
+    /**
+     * @page private_api API Private
+     * @section private_api_market /m/oauth2/api/market
+     * 
+     * Market service call.
+     * 
+     * **Scopes:** 
+     * `market`, `service`
+     *
+     * Everything is equivalent to @ref private_api_service, only module name parameter can be ommited
+     */
+    function market($aToken) 
+    {
+    	$_GET['key'] = $_POST['key'] = $aToken['client_id'];
+        $_GET['module'] = $_POST['module'] = 'bx_market_api';
+        $this->service($aToken);
+    }
+
+    /**
+     * @page public_api API Public
+     * @section public_api_com /m/oauth2/api/com
+     * 
+     * API service call (com is for command). 
+     * The call should be look this:
+     * `/m/oauth2/api/com/[metod-name-here]`
+     * 
+     * **Scopes:** 
+     * `api`
+     *
+     * Everything is equivalent to @ref private_api_service, 
+     * only module name parameter can be ommited and 
+     * method is passed as method parameter instead of GET/POST variable
+     */
+    function com($sMethod, $aToken, $bPublic)
+    {
+    	$_GET['key'] = $_POST['key'] = (isset($aToken['client_id']) ? $aToken['client_id'] : '');
+        if (!isset($_GET['module']) && !isset($_POST['module']))
+            $_GET['module'] = $_POST['module'] = 'bx_api';
+        $_GET['method'] = $_POST['method'] = $sMethod;
+        $this->service($aToken, $bPublic, true);
+    }
+
+    function isPublicAPI($sModule, $sMethod, $sClass = false)
+    {
+        return $this->_isAPI($sModule, $sMethod, $sClass, 'is_public_service');
+    }
+
+    function isSafeAPI($sModule, $sMethod, $sClass = false)
+    {
+        return $this->_isAPI($sModule, $sMethod, $sClass, 'is_safe_service');
+    }
+
+    protected function _isAPI($sModule, $sMethod, $sClass = false, $sCheckMethod = 'is_safe_service') 
+    {
+        if (!$sClass)
+            $sClass = 'Module';
+
+        if (!BxDolRequest::serviceExists($sModule, $sMethod, $sClass))
+            return false;
+
+        if (!BxDolRequest::serviceExists($sModule, $sCheckMethod, 'system' == $sModule ? 'TemplServices' : $sClass))
+            return false;
+
+        return BxDolService::call($sModule, $sCheckMethod, array($sMethod), 'system' == $sModule ? 'TemplServices' : $sClass);
+    }
+    
+
+    /**
+     * @page private_api API Private
+     * @section private_api_service /m/oauth2/api/service
+     * 
+     * Perform system call. 
+     * For a list of avalibale service calls and their parameters refer to @ref service page.
+     * 
+     * URL should look like this in case of service API call:
+     * @code
+     * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params[]=1&params[]=abc&class=custom_class_name_or_remove_it_if_main_module_class
+     * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params=serialized_string_of_params
+     * http://example.com/m/oauth2/api/service?module=bx_market&method=test&params=json_string_of_params
+     * @endcode
+     *
+     * **Scopes:** 
+     * `service`
+     * 
+     * **HTTP Method:** 
+     * `GET`, `POST`
+     *
+     * **Parameters:**
+     * - `module` - module name to perform service call in
+     * - `method` - service call method
+     * - `params` - parameters array
+     * - `class` - custom module name if different from main module class
+     * 
+     * **Request header:**
+     * @code
+     * Authorization: Bearer 9802c4a34e1535d8c3b721604ee0e7fb04116c49
+     * @endcode
+     *
+     * **Response (success):**
+     * Depends on particular service call
+     *
+     * **Response (error):**
+     * Error responce is described in particular service method.
+     * In case of general error (for example when service call isn't found, or error with token), the format is following:
+     * @code
+     * {  
+     *    "error":"short error description here",
+     *    "error_description":"long error description here"
+     * }
+     * @endcode
+     * 
+     */
+    function service($aToken, $bPublic = false, $bOutputResultOnly = false) 
+    {
+        if (!$bPublic && !($oProfile = BxDolProfile::getInstance($aToken['user_id']))) {
+            $this->errorOutput('404', 'not_found', 'Profile was not found');
+            return;
+        }
+        
+        if (!$bPublic) {
+            bx_login($oProfile->getAccountId(), false);
+            check_logged();
+        }
+
+        $sModule = bx_get('module');
+        $sMethod = bx_get('method');
+
+        if (!($aParams = bx_get('params')))
+            $aParams = array();
+        elseif (is_string($aParams) && preg_match('/^\[.*\]$/', $aParams))
+            $aParams = @json_decode($aParams);
+        if (!is_array($aParams))
+            $aParams = array($aParams);
+
+        if (!($sClass = bx_get('class')))
+            $sClass = 'Module';
+
+        if (!preg_match('/^[A-Za-z0-9_]+$/', $sModule) || !preg_match('/^[A-Za-z0-9_]+$/', $sMethod) || !preg_match('/^[A-Za-z0-9_]+$/', $sClass)) {
+            $this->errorOutput(500, 'error', 'Malformed request');
+            return false;
+        }
+
+        if (!BxDolRequest::serviceExists($sModule, $sMethod, $sClass)) {
+            $this->errorOutput(404, 'not_found', 'Service was not found');
+            return false;
+        }
+
+        $mixedRet = BxDolService::call($sModule, $sMethod, $aParams, $sClass);
+
+        if (is_array($mixedRet) && isset($mixedRet['error']) && isset($mixedRet['code'])) {
+            $this->errorOutput($mixedRet['code'], $mixedRet['error'], isset($mixedRet['desc']) ? $mixedRet['desc'] : $mixedRet['error']);
+            return false;
+        }
+
+        $this->output($bOutputResultOnly ? $mixedRet : array(
+            'module' => $sModule,
+            'method' => $sMethod,
+            'data' => $mixedRet,
+        ));
+    }
+
+    function errorOutput($iHttpCode, $sError, $sErrorDesc)
+    {
+        $oReponse = new Response();
+        $oReponse->setError($iHttpCode, $sError, $sErrorDesc);
+        $oReponse->send();
+    }
+
+    function output($a)
+    {
+        $oReponse = new Response();
+        $oReponse->setParameters($a);
+        $oReponse->send();
+    }
+
+    protected function _getProfileWithAccessChecking ($iProfileId) 
+    {
+        if (!$oProfile = BxDolProfile::getInstance($iProfileId)) {
+            $this->errorOutput('404', 'not_found', 'Profile was not found');
+            return false;
+        }
+/*        
+        // TODO: check visibility
+        if (!bx_check_profile_visibility($iProfileId, $aToken['user_id'], true)) {
+            $this->errorOutput(403, 'access_denied', 'You have no rights to view this user info');
+            return false;
+        }
+*/
+        return $oProfile;
+    }
+
+    protected function _prepareProfileArray ($oProfile, $bPublicFieldsOnly = true) 
+    {
+        $oAccount = $oProfile->getAccountObject();
+        $aProfileInfo = $oProfile->getInfo();
+        $aAccountInfo = $oAccount->getInfo();
+
+        if ($bPublicFieldsOnly) {
+            $aProfileInfo = array(
+                'id' => $aProfileInfo['id'],
+            );
+        } 
+        else {
+            unset($aProfileInfo['account_id']);
+            unset($aProfileInfo['content_id']);
+            unset($aProfileInfo['status']);
+
+            // --- account's profiles info
+            $aProfileInfo['email'] = $oAccount->getEmail();
+
+            // ---- returns all accounts profiles React Jot
+            $aProfiles = $oAccount->getProfiles();
+            foreach($aProfiles as &$aProfile) {
+               $oSubProfile = BxDolProfile::getInstance($aProfile['id']);
+               $aProfileInfo['profiles'][$aProfile['id']] = array(
+                    'name' => $oSubProfile->getDisplayName(),
+                    'profile_link' => $oSubProfile->getUrl(),
+                    'picture' => $oSubProfile->getThumb(),
+                    'id' => $aProfile['id']
+               );
+            }
+
+            // TODO: fetch extended info from profile module
+            bx_alert('bx_oauth2', 'profile_info', $aProfileInfo['id'], 0, ['info' => &$aProfileInfo]);
+        }
+
+
+        $aProfileInfo['role'] = $aAccountInfo['role'];
+        $aProfileInfo['name'] = $oAccount->getDisplayName();
+        $aProfileInfo['profile_display_name'] = $oProfile->getDisplayName();
+        $aProfileInfo['profile_link'] = $oProfile->getUrl();
+        $aProfileInfo['picture'] = $oProfile->getPicture();
+        $aProfileInfo['avatar'] = $oProfile->getAvatar();
+
+		// ---- additional profile's fields for React Jot
+        $aProfileInfo['cover'] = $oProfile->getCover();
+        $aProfileInfo['followers'] = (int)BxDolConnection::getObjectInstance('sys_profiles_subscriptions')->getConnectedInitiatorsCount($aProfileInfo['id']);
+        $aProfileInfo['following'] = (int)BxDolConnection::getObjectInstance('sys_profiles_subscriptions')->getConnectedContentCount($aProfileInfo['id']);
+        $aProfileInfo['friends'] = (int)BxDolConnection::getObjectInstance('sys_profiles_friends')->getConnectedContentCount($aProfileInfo['id'], true);
+
+        return $aProfileInfo;
+    }
+
+}
+
+/** @} */

+ 140 - 0
modules/boonex/oauth2/updates/15.0.0_15.0.1/source/classes/BxOAuthGrid.php

@@ -0,0 +1,140 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxOAuthGrid extends BxTemplGrid
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+    }
+
+    /**
+     * add js file for AJAX form submission
+     */
+    protected function _addJsCss()
+    {
+        parent::_addJsCss();
+        $this->_oTemplate->addJs('jquery.form.min.js');
+
+        $oForm = new BxTemplFormView(array());
+        $oForm->addCssJs();
+    }
+
+	protected function _isVisibleGrid ($a)
+    {
+        return isAdmin();
+    }
+
+    protected function _getCellClientSecret($mixedValue, $sKey, $aField, $aRow)
+    {
+        return $this->_getCellSecret($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    /**
+     * 'add' action handler
+     */
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $oModule = BxDolModule::getInstance('bx_oauth');
+
+        bx_import('FormAdd', $oModule->_aModule);
+        $oForm = new BxOAuthFormAdd();
+        $oForm->initChecker();
+
+        if ($oForm->isSubmittedAndValid()) {
+            $iNewId = $oForm->insert (array(), true);
+            if ($iNewId)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iNewId);
+            else
+                $aRes = array('msg' => _t('_error occured'));
+
+           return echoJson($aRes);
+
+        }
+
+        $s = BxTemplFunctions::getInstance()->transBox('', '
+            <div class="bx-def-padding bx-def-color-bg-block">' . $oForm->getCode() . '</div>
+            <script>
+                $(document).ready(function () {
+                    $("#bx-oauth-' . $sAction . '").ajaxForm({
+                        dataType: "json",
+                        beforeSubmit: function (formData, jqForm, options) {
+                            bx_loading($("#' . $oForm->aFormAttrs['id'] . '"), true);
+                        },
+                        success: function (data) {
+                            $(".bx-popup-active").dolPopupHide();
+                            glGrids.' . $this->_sObject . '.processJson(data, "' . $sAction . '");
+                        }
+                    });
+                });
+            </script>');
+
+        echoJson(array('popup' => array('html' => $s, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+	/**
+     * 'edit' action handler
+     */
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+        $oModule = BxDolModule::getInstance('bx_oauth');
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId) {
+                echoJson(array());
+                exit;
+            }
+
+            $aIds = array($iId);
+        }
+
+        $iId = $aIds[0];
+        $aClient = $oModule->_oDb->getClientsBy(array('type' => 'id', 'id' => $iId));
+
+        bx_import('FormEdit', $oModule->_aModule);
+        $oForm = new BxOAuthFormEdit();
+
+        $oForm->initChecker($aClient);
+        if ($oForm->isSubmittedAndValid()) {
+            if ($oForm->update($iId))
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_error occured'));
+
+            return echoJson($aRes);
+        } 
+
+        $s = BxTemplFunctions::getInstance()->transBox('', '
+            <div class="bx-def-padding bx-def-color-bg-block">' . $oForm->getCode() . '</div>
+            <script>
+                $(document).ready(function () {
+                    $("#bx-oauth-' . $sAction . '").ajaxForm({
+                        dataType: "json",
+                        beforeSubmit: function (formData, jqForm, options) {
+                            bx_loading($("#' . $oForm->aFormAttrs['id'] . '"), true);
+                        },
+                        success: function (data) {
+                            $(".bx-popup-active").dolPopupHide();
+                            glGrids.' . $this->_sObject . '.processJson(data, "' . $sAction . '");
+                        }
+                    });
+                });
+            </script>');
+
+        echoJson(array('popup' => array('html' => $s, 'options' => array('closeOnOuterClick' => false))));
+    }
+}
+
+/** @} */

+ 68 - 0
modules/boonex/oauth2/updates/15.0.0_15.0.1/source/install/config.php

@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    OAuth2 OAuth2 server
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_oauth',
+    'title' => 'OAuth2 Server',
+    'note' => 'Allow to use site user credentials and basic API',
+    'version' => '15.0.1',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/oauth2/',
+    'home_uri' => 'oauth2',
+
+    'db_prefix' => 'bx_oauth_',
+    'class_prefix' => 'BxOAuth',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'OAuth2 Server',
+
+    /**
+     * 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(),
+);
+
+/** @} */

File diff suppressed because it is too large
+ 3 - 0
modules/boonex/oauth2/updates/15.0.0_15.0.1/source/template/images/icons/std-icon.svg


+ 51 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/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' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * '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_15.0.2_15.0.3/',
+    'home_uri' => 'payment_update_1502_1503',
+
+    'module_dir' => 'boonex/payment/',
+    'module_uri' => 'payment',
+
+    'db_prefix' => 'bx_payment_',
+    'class_prefix' => 'BxPayment',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 1,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Payment',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/install/installer.php

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

+ 4 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/install/langs/en.xml

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

+ 2 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/install/sql/enable.sql

@@ -0,0 +1,2 @@
+-- OPTIONS
+UPDATE `sys_options` SET `type`='secret' WHERE `name`='bx_payment_currency_exchange_api';

+ 17 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/install/sql/install.sql

@@ -0,0 +1,17 @@
+-- OPTIONS
+UPDATE `bx_payment_providers_options` SET `type`='secret' WHERE `name` IN (
+    'pp_token',
+    'pp_api_live_secret', 'pp_api_test_secret',
+    'cbee_live_api_key', 'cbee_test_api_key',
+    'cbee_v3_live_api_key', 'cbee_v3_test_api_key',
+    'strp_live_sec_key', 'strp_test_sec_key',
+    'strp_v3_live_sec_key', 'strp_v3_test_sec_key',
+    'aina_secret'
+);
+
+
+-- GRIDS
+UPDATE `sys_grid_fields` SET `width`='5%' WHERE `object`='bx_payment_grid_cart' AND `name`='checkbox';
+UPDATE `sys_grid_fields` SET `width`='45%' WHERE `object`='bx_payment_grid_cart' AND `name`='description';
+UPDATE `sys_grid_fields` SET `width`='5%' WHERE `object`='bx_payment_grid_cart' AND `name`='price_single';
+UPDATE `sys_grid_fields` SET `width`='10%' WHERE `object`='bx_payment_grid_cart' AND `name`='actions';

+ 388 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentConfig.php

@@ -0,0 +1,388 @@
+<?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 $_bExtendedMode;
+    protected $_bCreditsOnly;
+
+    protected $_iPayAttemptsMax;
+    protected $_iPayAttemptsInterval;
+
+    function __construct($aModule)
+    {
+        parent::__construct($aModule);
+
+        $sBaseUrl = BX_DOL_URL_ROOT . $this->getBaseUri();
+
+        $this->CNF = array_merge($this->CNF, [
+            // module icon
+            'ICON' => 'credit-card',
+
+            // database tables
+            'TABLE_COMMISSIONS' => $aModule['db_prefix'] . 'commissions',
+            'TABLE_INVOICES' => $aModule['db_prefix'] . 'invoices',
+
+            // page URIs
+            'URL_JOIN' => 'page.php?i=payment-join',
+            'URL_CARTS' => 'page.php?i=payment-carts',
+            'URL_CART' => 'page.php?i=payment-cart',
+            'URL_CART_CHECKOUT' => $sBaseUrl . 'initialize_checkout/' . BX_PAYMENT_TYPE_SINGLE . '/',
+            'URL_AUTHORIZE' => $sBaseUrl . 'authorize_checkout/',
+            'URL_SUBSCRIBE' => $sBaseUrl . 'subscribe/',
+            'URL_SUBSCRIBE_JSON' => $sBaseUrl . 'subscribe_json/',
+            'URL_SUBSCRIPTIONS' => 'page.php?i=payment-sbs-list-my',
+            'URL_HISTORY' => 'page.php?i=payment-history',
+            'URL_ORDERS' => 'page.php?i=payment-orders',
+            'URL_INVOICES' => 'page.php?i=payment-invoices',
+            'URL_DETAILS' => 'page.php?i=payment-details',
+            'URL_RETURN' => 'page.php?i=payment-cart-thank-you',
+            'URL_RETURN_DATA' => $sBaseUrl . 'finalize_checkout/',
+            'URL_RETURN_DATA_API' => 'api.php?r=' . $aModule['name'] . '/finalize_checkout&params[]=',
+            'URL_NOTIFY' => $sBaseUrl . 'notify/',
+            'URL_CHECKOUT_OFFLINE' => 'page.php?i=payment-checkout-offline',
+
+            'KEY_ARRAY_PRICE_SINGLE' => 'price_single',
+            'KEY_ARRAY_PRICE_RECURRING' => 'price_recurring',
+            'KEY_ARRAY_PERIOD_RECURRING' => 'period_recurring',
+            'KEY_ARRAY_PERIOD_UNIT_RECURRING' => 'period_unit_recurring',
+            'KEY_ARRAY_TRIAL_RECURRING' => 'trial_recurring',
+
+            // some params
+            'PARAM_SBS_CANCEL_SURVEY' => 'bx_payment_sbs_cancel_survey',
+            'PARAM_CURRENCY_EXCHANGE_API' => 'bx_payment_currency_exchange_api',
+            'PARAM_CMSN_ENABLE' => 'bx_payment_commissions',
+            'PARAM_CMSN_INVOICE_ISSUE_DAY' => 'bx_payment_inv_issue_day', //some day of month
+            'PARAM_CMSN_INVOICE_LIFETIME' => 'bx_payment_inv_lifetime', //in days
+            'PARAM_CMSN_INVOICE_EXPIRATION_NOTIFY' => 'bx_payment_inv_expiraction_notify', //in days, before expiration date
+
+            // objects
+            'OBJECT_FORM_PRELISTS_CURRENCIES' => 'bx_payment_currencies',
+            'OBJECT_FORM_PRELISTS_REASONS_CANCEL' => 'bx_payment_reasons_cancel',
+            'OBJECT_PP_OFFLINE' => 'offline', //Offline payment provider
+            'OBJECT_PP_CREDITS' => 'credits', //Credits payment provider
+
+            'MODULE_CREDITS' => 'bx_credits',
+
+            // some language keys
+            'T' => [
+                'MSG_ITEM_ADDED' => '_bx_payment_msg_item_added',
+                'MSG_ITEM_DELETED' => '_bx_payment_msg_item_deleted',
+                'MSG_SINGLE_SELLER_MODE' => '_bx_payment_msg_single_seller',
+                'ERR_WRONG_DATA' => '_bx_payment_err_wrong_data',
+                'ERR_REQUIRED_LOGIN' => '_bx_payment_err_required_login',
+                'ERR_NOT_ACCEPT_PAYMENTS' => '_bx_payment_err_not_accept_payments',
+                'ERR_SELF_PURCHASE' => '_bx_payment_err_self_purchase',
+                'ERR_INACTIVE_VENDOR' => '_bx_payment_err_inactive_vendor',
+                'ERR_UNKNOWN_VENDOR' => '_bx_payment_err_unknown_vendor',
+
+                'BLOCK_TITLE_CART' => '_bx_payment_page_block_title_cart',
+
+                'POPUP_PROVIDERS_SELECT' => '_bx_payment_popup_title_crd_providers_select', 
+
+                'TXT_CART_PROVIDER' => '_bx_payment_txt_cart_'
+            ]
+        ]);
+
+        $this->_aHtmlIds = array(
+            'cart' => array(
+                'providers_select' => $this->_sName . '-cart-providers-select-',
+            ),
+            'history' => array(
+                'order_history_view' => $this->_sName . '-order-view-history',
+            ),
+            'subscription' => array(
+                'order_subscription_view' => $this->_sName . '-order-view-subscription',
+                'order_subscription_get_details' => $this->_sName . '-order-get-details-subscription',
+                'order_subscription_change_details' => $this->_sName . '-order-change-details-subscription',
+                'order_subscription_get_billing' => $this->_sName . '-order-get-billing-subscription',
+                'order_subscription_change_billing' => $this->_sName . '-order-change-billing-subscription',
+                'form_subscription_change_billing' => $this->_sName . '-form-change-billing-subscription',
+                'form_subscription_change_details' => $this->_sName . '-form-change-details-subscription',
+                'form_subscription_cancel_survay' => $this->_sName . '-form-cancel-subscription-survay-',
+                'popup_subscription_cancel_survay' => $this->_sName . '-popup-cancel-subscription-survay-',
+            ),
+            'pending' => array(
+                'order_pending_view' => $this->_sName . '-order-view-pending',
+                'order_pending_process' => $this->_sName . '-order-process',
+            ),
+            'processed' => array(
+                'order_processed_view' => $this->_sName . '-order-view-processed',
+                'order_processed_add' => $this->_sName . '-order-add',
+                'order_processed_client_id' => $this->_sName . '-oa-client-id',
+                'order_processed_client' => $this->_sName . '-oa-client',
+                'order_processed_items' => $this->_sName . '-oa-items',	
+            ),
+            'commission' => array(
+                'popup_add' => $this->_sName . '-commission-popup-add',
+                'popup_edit' => $this->_sName . '-commission-popup-edit',
+            ),
+            'invoice' => array(
+                'popup_edit' => $this->_sName . '-invoice-popup-edit',
+            )
+        );
+
+        $this->_aPerPage = array(
+            'orders' => 10,
+            'history' => 10
+        );
+
+        $this->_aJsClasses = array(
+            'cart' => 'BxPaymentCart',
+            'history' => 'BxPaymentOrders',
+            'subscription' => 'BxPaymentSubscriptions',
+            'pending' => 'BxPaymentOrders',
+            'processed' => 'BxPaymentOrders',
+            'chargebee_v3' => 'BxPaymentProviderChargebeeV3',
+            'stripe' => 'BxPaymentProviderStripe',
+            'stripe_v3' => 'BxPaymentProviderStripeV3'
+        );
+
+        $this->_aJsObjects = array(
+            'cart' => 'oPaymentCart',
+            'history' => 'oPaymentOrders',
+            'subscription' => 'oBxPaymentSubscriptions',
+            'pending' => 'oPaymentOrders',
+            'processed' => 'oPaymentOrders',
+            'chargebee_v3' => 'oPaymentProviderChargebeeV3',
+            'stripe' => 'oPaymentProviderStripe',
+            'stripe_v3' => 'oPaymentProviderStripeV3'
+        );
+
+        $this->_bExtendedMode = false;
+        $this->_bCreditsOnly = false;
+
+        $this->_iPayAttemptsMax = 3;
+        $this->_iPayAttemptsInterval = 86400; //--- in sec
+    }
+
+    public function init(&$oDb)
+    {
+        parent::init($oDb);
+
+        $sPrefix = $this->getPrefix('options');
+
+        $this->_bExtendedMode = $this->_oDb->getParam($sPrefix . 'extended_mode') == 'on';
+        $this->_bCreditsOnly = $this->_oDb->getParam($sPrefix . 'credits_only') == 'on';
+    }
+
+    public function isExtendedMode()
+    {
+        return $this->_bExtendedMode;
+    }
+
+    public function isCreditsOnly()
+    {
+        return $this->_bCreditsOnly;
+    }
+
+    public function getPayAttemptsMax()
+    {
+        return $this->_iPayAttemptsMax;
+    }
+
+    public function getPayAttemptsInterval()
+    {
+        return $this->_iPayAttemptsInterval;
+    }
+
+    public function getPrice($sType, $aItem, $iPrecision = 2)
+    {
+    	$fPrice = 0;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                $fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_SINGLE')];
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $fPrice = $aItem[$this->getKey('KEY_ARRAY_PRICE_RECURRING')];
+                break;
+        }
+
+        return round((float)$fPrice, $iPrecision);
+    }
+
+    public function getPeriod($sType, $aItem)
+    {
+        $mixedResult = false;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $mixedResult = [$aItem[$this->getKey('KEY_ARRAY_PERIOD_RECURRING')], $aItem[$this->getKey('KEY_ARRAY_PERIOD_UNIT_RECURRING')]];
+                break;
+        }
+
+        return $mixedResult;
+    }
+
+    public function getTrial($sType, $aItem)
+    {
+        $iTrial = 0;
+
+        switch($sType) {
+            case BX_PAYMENT_TYPE_RECURRING:
+                $iTrial = $aItem[$this->getKey('KEY_ARRAY_TRIAL_RECURRING')];
+                break;
+        }
+
+        return (int)$iTrial;
+    }
+
+    public function getModuleId($mixedId)
+    {
+        if(is_numeric($mixedId))
+            return (int)$mixedId;
+
+        if(is_string($mixedId)) {
+            $aInfo = $this->_oDb->getModuleByName($mixedId);
+            if(!is_array($aInfo) || empty($aInfo['id']))
+                $aInfo = $this->_oDb->getModuleByUri($mixedId);
+
+            if(is_array($aInfo) && !empty($aInfo['id']))
+                return (int)$aInfo['id'];
+        } 
+
+        return 0;
+    }
+
+    public function a2s($a, $bEncodeString = true)
+    {
+        $s = json_encode($a);
+
+        return $bEncodeString ? base64_encode($s) : $s;
+    }
+
+    public function s2a($s, $bDecodeString = true)
+    {
+        if($bDecodeString)
+            $s = base64_decode($s);
+
+        return json_decode($s, true);
+    }
+
+    public function urlEncode($s)
+    {
+        return urlencode(base64_encode($s));
+    }
+
+    public function urlDecode($s)
+    {
+        return base64_decode(urldecode($s));
+    }
+
+    public function descriptorA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTOR'), $a);
+    }
+
+    public function descriptorS2A($s) 
+    {
+    	return explode($this->getDivider('DIVIDER_DESCRIPTOR'), $s);
+    }
+
+    public function descriptorsA2S($a) 
+    {
+    	return implode($this->getDivider('DIVIDER_DESCRIPTORS'), $a);
+    }
+
+    /**
+     * Conver items to array with necessary structure.
+     *
+     * @param string/array $mixed - string with cart items divided with (:) or an array of cart items.
+     * @param boolean $bDescriptorsOnly - converts a string with cart items to an array of descriptors represented as strings.
+     * @return array with items.
+     */
+    public function descriptorsM2A($mixed, $bDescriptorsOnly = false)
+    {
+        $aResults = [];
+
+        $aItems = [];
+        if(is_string($mixed))
+           $aItems = explode($this->getDivider('DIVIDER_DESCRIPTORS'), $mixed);
+        else if(is_array($mixed))
+           $aItems = $mixed;
+
+        if($bDescriptorsOnly)
+            return $aItems;
+
+        foreach($aItems as $mixedItem) {
+            $aItem = is_array($mixedItem) ? $mixedItem : $this->descriptorS2A($mixedItem);
+
+            $aResult = ['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;
+        });
+    }
+}
+
+/** @} */

+ 217 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentFormDetails.php

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

+ 351 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridCart.php

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

+ 93 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridCarts.php

@@ -0,0 +1,93 @@
+<?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 BxPaymentGridCarts extends BxBaseModPaymentGridCarts
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+    }
+    
+    public function getCodeAPI($bForceReturn = false)
+    {
+        $aData = parent::getCodeAPI($bForceReturn);
+        $aData['settings']['field_id'] = 'id';
+        foreach ($aData['data'] as &$aRow){
+            $aRow['id'] = $aRow['checkbox']['data'];
+            $aRow['vendor_id']['value'] = strip_tags($aRow['vendor_id']['value']);
+            $aRow['items_price']['value'] = str_replace('&#36; ','$', $aRow['items_price']['value']);
+        }
+        return $aData;
+    }
+
+    protected function _getCellVendorId($mixedValue, $sKey, $aField, $aRow)
+    {
+    	return parent::_getCellDefault($this->_oModule->_oTemplate->displayProfileLink(array(
+            'id' => $mixedValue,
+            'name' => $aRow['vendor_name'],
+            'title' => _t('_bx_payment_txt_checkout_to', $aRow['vendor_name']),
+            'link' => bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART'), array('seller_id' => (int)$mixedValue))
+    	)), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellItemsPrice($mixedValue, $sKey, $aField, $aRow)
+    {
+        $sSign = $this->_sCurrencySign;
+        if(!$this->_bSingleSeller && !empty($aRow['vendor_currency_sign']))
+            $sSign = $aRow['vendor_currency_sign'];
+
+        return parent::_getCellDefault(_t_format_currency_ext($mixedValue, ['sign' => $sSign]), $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionContinue ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        $sUrl = bx_append_url_params($this->_oModule->_oConfig->getUrl('URL_CART'), array('seller_id' => $aRow['vendor_id']));
+
+        if($this->_bIsApi)
+            return array_merge($a, [
+                'type' => 'link',
+                'name' => $sKey,
+                'url' => $sUrl
+            ]);
+
+        unset($a['attr']['bx_grid_action_single']);
+        $a['attr'] = array_merge($a['attr'], array(
+            "onclick" => "window.open('" . $sUrl . "','_self');"
+        ));
+
+        return parent::_getActionDefault($sType, $sKey, $a, false, $isDisabled, $aRow);
+    }
+
+    protected function _getFilterControls ()
+    {
+    	return '';
+    }
+    
+    protected function _getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(empty($this->_aQueryAppend['client_id']))
+            return array();
+
+        $this->_aOptions['source'] = array_values($this->_oModule->getObjectCart()->getInfo(BX_PAYMENT_TYPE_SINGLE, $this->_aQueryAppend['client_id']));
+
+        return parent::_getDataArray($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    protected function _delete($mixedId)
+    {
+        return $this->_oCart->serviceDeleteFromCart($mixedId);
+    }
+}
+
+/** @} */

+ 119 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridPending.php

@@ -0,0 +1,119 @@
+<?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 BxPaymentGridPending extends BxBaseModPaymentGridOrders
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+    	$this->MODULE = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sOrdersType = 'pending';
+    }
+
+    public function getFormBlockTitleAPI($sAction, $iId = 0)
+    {
+        $sResult = '';
+
+        switch($sAction) {
+            case 'process':
+                $sResult = _t($this->_sLangsPrefix . 'popup_title_ods_order_' . $this->_sOrdersType . '_process');
+                break;
+        }
+
+        return $sResult;
+    }
+
+    public function getFormCallBackUrlAPI($sAction, $iId = 0)
+    {
+         return '/api.php?r=system/perfom_action_api/TemplServiceGrid/&params[]=&o=' . $this->_sObject . '&a=' . $sAction . '&id=' . $iId;
+    }
+
+    public function performActionProcess()
+    {
+    	$aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId)
+                return $this->_bIsApi ? [] : echoJson([]);
+
+            $aIds = array($iId);
+        }
+
+        $iId = (int)$aIds[0];
+
+    	$sAction = 'process';
+        $sFormObject = $this->_oModule->_oConfig->getObject('form_pendings');
+        $sFormDisplay = $this->_oModule->_oConfig->getObject('form_display_pendings_process');
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay, $this->_oModule->_oTemplate);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?o=' . $this->_sObject . '&a=' . $sAction;
+
+        $oForm->aInputs['id']['value'] = $iId;
+        $oForm->aInputs['seller_id']['value'] = $this->_aQueryAppend['seller_id'];
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $iId = $oForm->getCleanValue('id');
+
+            $this->_oModule->_oDb->updateOrderPending($iId, [
+                'order' => $oForm->getCleanValue('order'),
+                'error_code' => 0,
+                'error_msg' => 'Manually processed'
+            ]);
+
+            if($this->_oModule->registerPayment($iId))
+                $aRes = $this->_bIsApi ? [] : ['grid' => $this->getCode(false), 'blink' => $iId];
+            else
+                $aRes = ($sMsg = _t($this->_sLangsPrefix . 'err_cannot_perform')) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : ['msg' => $sMsg];
+
+            return $this->_bIsApi ? $aRes : echoJson($aRes);
+        }
+
+        if($this->_bIsApi)
+            return $this->getFormBlockAPI($oForm, $sAction, $iId);
+
+        $sKey = 'order_' . $this->_sOrdersType . '_process';
+        $sId = $this->_oModule->_oConfig->getHtmlIds('pending', $sKey);
+    	$sTitle = _t($this->_sLangsPrefix . 'popup_title_ods_' . $sKey);
+
+        $sContent = BxTemplFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('order_pending_process.html', [
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        ]));
+
+        echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
+    }
+
+    protected function _getActionCancel ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = [])
+    {
+        if($this->_bIsApi)
+            return array_merge($a, ['name' => $sKey, 'type' => 'callback', 'on_callback' => 'hide_row']);
+
+        return $this->_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+    	if(empty($this->_aQueryAppend['seller_id']))
+            return array();
+
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `tt`.`seller_id`=?", $this->_aQueryAppend['seller_id']);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

+ 300 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentGridProcessed.php

@@ -0,0 +1,300 @@
+<?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 getFormBlockTitleAPI($sAction, $iId = 0)
+    {
+        $sResult = '';
+
+        switch($sAction) {
+            case 'add':
+                $sResult = _t($this->_sLangsPrefix . 'popup_title_ods_order_' . $this->_sOrdersType . '_add');
+                break;
+        }
+
+        return $sResult;
+    }
+
+    public function getFormCallBackUrlAPI($sAction, $iId = 0)
+    {
+         return '/api.php?r=system/perfom_action_api/TemplServiceGrid/&params[]=&o=' . $this->_sObject . '&a=' . $sAction . '&id=' . $iId;
+    }
+
+    public function performActionAdd()
+    {
+        $sType = BX_PAYMENT_TYPE_SINGLE;
+        $sAction = 'add';
+        $sModule = $this->_oModule->_oConfig->getName();
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('processed');
+
+        $sFormObject = $this->_oModule->_oConfig->getObject('form_processed');
+        $sFormDisplay = $this->_oModule->_oConfig->getObject('form_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';
+        if($this->_bIsApi)
+            $oForm->aInputs['client']['ajax_get_suggestions'] = $sModule . "/get_clients&params[]=";
+
+        $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'][] = ['key' => $aModule['id'], 'value' => $aModule['title']];
+
+        if($this->_bIsApi)
+            $oForm->aInputs['module_id']['request_url'] = '/api.php?r=' . $sModule . "/get_items&params[]=" . $sType . "&params[]=";
+
+        $oForm->aInputs['items']['content'] = $this->_oModule->_oTemplate->displayItems($this->_aQueryAppend['seller_id'], $sType);
+
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sFormMethod = $oForm->aFormAttrs['method'];
+
+            $aItemIds = $oForm->getSubmittedValue('items', $sFormMethod);
+            if($this->_bIsApi && is_string($aItemIds))
+                $aItemIds = explode(',', $aItemIds);
+            if(empty($aItemIds) || !is_array($aItemIds))
+                return ($sMsg = $this->_sLangsPrefix . 'err_empty_items') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : echoJson(['msg' => $sMsg]);
+
+            $aItems = [];
+            $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 ($sMsg = $this->_sLangsPrefix . 'err_wrong_quantity') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : echoJson(['msg' => $sMsg]);
+
+                $aItems[$iItemId] = [
+                    'id' => $iItemId, 
+                     $sPriceKey => $fItemPrice, 
+                    'quantity' => $iItemQuantity
+                ];
+            }
+
+            $mixedResult = $this->_oModule->getObjectOrders()->addOrder([
+                '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' => array_values($aItems)
+            ]);
+            if(is_array($mixedResult))
+                return $this->_bIsApi ? [bx_api_get_msg($mixedResult['msg'])] : echoJson($mixedResult);
+
+            $iPendingId = (int)$mixedResult;
+            if(!$this->_oModule->registerPayment($iPendingId))
+                return ($sMsg = _t($this->_sLangsPrefix . 'err_cannot_perform')) && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : echoJson(['msg' => $sMsg]);
+
+            $aOrders = $this->_oModule->_oDb->getOrderProcessed(['type' => 'pending_id', 'pending_id' => $iPendingId, 'with_key' => 'id']);
+            foreach($aOrders as $iOrder => $aOrder)
+                if((float)$aOrder['amount'] != ($fAmount = $aItems[$aOrder['item_id']][$sPriceKey]))
+                    $this->_oModule->_oDb->updateOrderProcessed($iOrder, ['amount' => $fAmount]);
+
+            return $this->_bIsApi ? [] : echoJson(['grid' => $this->getCode(false), 'blink' => array_keys($aOrders)]);
+        }
+
+        if($this->_bIsApi)
+            return [
+                bx_api_get_block('payment_order_add', $oForm->getCodeAPI(), [
+                    'ext' => [
+                        'name' => $this->_oModule->getName(), 
+                        'title' => $this->getFormBlockTitleAPI($sAction),
+                        'request' => ['url' => $this->getFormCallBackUrlAPI($sAction), 'immutable' => true]]
+                    ]
+                )
+            ];
+
+        $sKey = 'order_' . $this->_sOrdersType . '_add';
+        $sId = $this->_oModule->_oConfig->getHtmlIds('processed', $sKey);
+        $sTitle = _t($this->_sLangsPrefix . 'popup_title_ods_' . $sKey);
+
+        $sContent = BxTemplFunctions::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(['popup' => ['html' => $sContent, 'options' => ['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 '';
+
+        if($this->_bIsApi)
+            return array_merge($a, ['name' => $sKey, 'type' => 'callback', 'on_callback' => 'hide_row']);
+
+        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);
+    }
+}
+
+/** @} */

+ 2170 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentModule.php

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

+ 260 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentOrders.php

@@ -0,0 +1,260 @@
+<?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 BxPaymentOrders extends BxBaseModPaymentOrders
+{
+    protected $_sLangsPrefix;
+
+    function __construct()
+    {
+    	$this->MODULE = 'bx_payment';
+
+    	parent::__construct();
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+    }
+
+	/*
+     * Service methods
+     */
+    
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_orders get_block_orders
+     * 
+     * @code bx_srv('bx_payment', 'get_block_orders', [...], 'Orders'); @endcode
+     * 
+     * Get page block with a list of orders represented as table.
+     *
+     * @param $sType string value with order type (processed or pending).
+     * @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 BxPaymentOrders::serviceGetBlockOrders
+     */
+    /** 
+     * @ref bx_payment-get_block_orders "get_block_orders"
+     */
+    public function serviceGetBlockOrders($sType = '', $iUserId = BX_PAYMENT_EMPTY_ID)
+    {
+        if(empty($sType) && bx_get('type') !== false)
+            $sType = bx_process_input(bx_get('type'));
+
+        if(empty($sType) || !in_array($sType, array(BX_PAYMENT_ORDERS_TYPE_PENDING, BX_PAYMENT_ORDERS_TYPE_PROCESSED)))
+            $sType = BX_PAYMENT_ORDERS_TYPE_PROCESSED;
+
+        if(!$this->_oModule->isLogged())
+            return ($sMsg = _t($this->_sLangsPrefix . 'err_required_login')) && $this->_bIsApi ? [bx_api_get_msg ($sMsg)] : [
+                'content' => MsgBox($sMsg)
+            ];
+
+        $iUserId = $iUserId != BX_PAYMENT_EMPTY_ID ? $iUserId : $this->_oModule->getProfileId();
+        if($sType == BX_PAYMENT_ORDERS_TYPE_PROCESSED)
+            $this->_oModule->_oDb->updateOrdersProcessed(array('new' => 0), array('seller_id' => $iUserId, 'new' => 1));
+
+        $this->_oModule->setSiteSubmenu('menu_dashboard', 'system', 'dashboard-orders');
+
+        $sBlockTitle = _t($this->_sLangsPrefix . 'page_block_title_orders_' . $sType);
+        $sBlockContent = $this->_oModule->_oTemplate->displayBlockOrders($sType, $iUserId);
+
+        $sBlockSubmenu = $this->_oModule->_oConfig->getObject('menu_orders_submenu');
+        $oBlockSubmenu = BxDolMenu::getObjectInstance($sBlockSubmenu);
+        if($oBlockSubmenu)
+            $oBlockSubmenu->setSelected($this->MODULE, 'orders-' . $sType);
+
+        return $this->_bIsApi ? [
+            'title' => $sBlockTitle,
+            'content' => !$sBlockContent ? [bx_api_get_msg(_t($this->_sLangsPrefix . 'msg_no_results'))] : [bx_api_get_block('grid', $sBlockContent)],
+            'menu' => $oBlockSubmenu->getCodeAPI()
+        ] : [
+            'title' => $sBlockTitle,
+            'content' => !$sBlockContent ? MsgBox(_t($this->_sLangsPrefix . 'msg_no_results')) : $sBlockContent,
+            'menu' => $oBlockSubmenu
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_orders_info get_orders_info
+     * 
+     * @code bx_srv('bx_payment', 'get_orders_info', [...], 'Orders'); @endcode
+     * 
+     * Get transaction(s) which meets all requirements.
+     *
+     * @param $aConditions an array of pears('key' => 'value'). Available keys are the following:
+     * a. license - internal license (string)
+     * b. client_id - client's ID (integer)
+     * c. seller_id - seller's ID (integer)
+     * d. module_id - modules's where the purchased product is located. (integer)
+     * e. item_id - item id in the database. (integer)
+     * f. date - the date when the payment was processed(UNIXTIME STAMP)
+     * @return an array of transactions. Each transaction has full info(client ID, seller ID, external transaction ID, date and so on)
+     * 
+     * @see BxPaymentOrders::serviceGetOrdersInfo
+     */
+    /** 
+     * @ref bx_payment-get_orders_info "get_orders_info"
+     */
+    public function serviceGetOrdersInfo($aConditions)
+    {
+        if(empty($aConditions) || !is_array($aConditions))
+            return array();
+
+        return $this->_oModule->_oDb->getOrderProcessed(array('type' => 'mixed', 'conditions' => $aConditions));
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-other Other
+     * @subsubsection bx_payment-get_pending_orders_info get_pending_orders_info
+     * 
+     * @code bx_srv('bx_payment', 'get_pending_orders_info', [...], 'Orders'); @endcode
+     * 
+     * Get pending 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 pending transactions. Each transaction has full info(client ID, seller ID, type, date and so on)
+     * 
+     * @see BxPaymentOrders::serviceGetPendingOrdersInfo
+     */
+    /** 
+     * @ref bx_payment-get_pending_orders_info "get_pending_orders_info"
+     */
+    public function serviceGetPendingOrdersInfo($aConditions)
+    {
+        if(empty($aConditions) || !is_array($aConditions))
+            return array();
+
+        return $this->_oModule->_oDb->getOrderPending(array('type' => 'mixed', 'conditions' => $aConditions));
+    }
+
+    public function serviceProcessOrder($iSellerId, $iClientId, $iModuleId, $aItems, $sType, $sOrder)
+    {
+        $mixedResult = $this->addOrder(array(
+            'client_id' => $iClientId,
+            'seller_id' => $iSellerId,
+            'provider' => 'manual',
+            'type' => $sType,
+            'order' => $sOrder,
+            'error_code' => 0,
+            'error_msg' => 'Manually processed',        		
+            'module_id' => $iModuleId,
+            'items' => $aItems
+        ), true);
+
+        if(is_array($mixedResult))
+            return false;
+
+        return $this->_oModule->registerPayment((int)$mixedResult);
+    }
+
+    public function serviceProcessOrderByPending($iPendingId, $sOrder)
+    {
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, array(
+            'order' => $sOrder,
+            'error_code' => 0,
+            'error_msg' => 'Manually processed'
+        ));
+
+        return $this->_oModule->registerPayment($iPendingId);
+    }
+
+    public function serviceRefundOrder($sOrder)
+    {
+        $aPending = $this->_oModule->_oDb->getOrderPending(['type' => 'order', 'order' => $sOrder]);
+        if(empty($aPending) || !is_array($aPending))
+            return false;
+
+        return $this->_oModule->refundPayment($aPending);
+    }
+
+    public function addOrder($aData, $bForce = false)
+    {
+        $iSellerId = isset($aData['seller_id']) ? (int)$aData['seller_id'] : $this->_oModule->getProfileId();
+        if($iSellerId == $aData['client_id'])
+            return ['msg' => $this->_sLangsPrefix . 'err_self_purchase'];
+
+        $sOrder = trim($aData['order']);
+        if(empty($sOrder))
+            return ['msg' => $this->_sLangsPrefix . 'form_processed_input_order_err'];
+
+        $aItems = [];
+        $fItemsPrice = 0;
+        foreach($aData['items'] as $aItem) {
+            if(!$bForce && !$this->_oModule->isAllowedSell(['module_id' => $aData['module_id'], 'item_id' => $aItem['id']], true))
+                continue;
+
+            $aItems[] = [
+                'author_id' => $iSellerId,
+                'module_id' => $aData['module_id'],
+                'id' => $aItem['id'],
+                'quantity' => $aItem['quantity']
+            ];
+            $fItemsPrice += $this->_oModule->_oConfig->getPrice($aData['type'], $aItem) * $aItem['quantity'];
+        }
+
+        $iPendingId = $this->_oModule->_oDb->insertOrderPending($aData['client_id'], $aData['type'], $aData['provider'], [
+            'vendor_id' => $iSellerId, 
+            'vendor_currency_code' => $this->_oModule->getVendorCurrencyCode($iSellerId),
+            'items_price' => $fItemsPrice, 
+            'items' => $aItems
+        ]);
+
+        $this->_oModule->_oDb->updateOrderPending($iPendingId, [
+            'order' => $sOrder,
+            'error_code' => $aData['error_code'],
+            'error_msg' => $aData['error_msg']
+        ]);
+
+        return (int)$iPendingId;
+    }
+
+    public function getOrder($sType, $iId)
+    {
+        return $this->_oModule->_oTemplate->displayOrder($sType, $iId);
+    }
+
+    public function cancel($sType, $iOrderId)
+    {
+    	$sMethodName = 'getOrder' . bx_gen_method_name($sType);
+    	$aOrder = $this->_oModule->_oDb->$sMethodName(array('type' => 'id', 'id' => $iOrderId));
+        if(empty($aOrder) || !is_array($aOrder))
+            return true;
+
+        if($sType == BX_PAYMENT_ORDERS_TYPE_PROCESSED && !$this->_oModule->callUnregisterCartItem((int)$aOrder['module_id'], array($aOrder['client_id'], $aOrder['seller_id'], $aOrder['item_id'], $aOrder['item_count'], $aOrder['order'], $aOrder['license'])))
+            return false;
+
+        $sMethodName = 'deleteOrder' . bx_gen_method_name($sType);
+        if(!$this->_oModule->_oDb->$sMethodName($iOrderId))
+            return false;
+
+        $this->_oModule->alert('cancel_order', $aOrder['id'], $aOrder['seller_id'], array(
+            'type' => $sType,
+            'order' => $aOrder
+        ));
+
+        return true;
+    }
+}
+
+/** @} */

+ 284 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentProviderCredits.php

@@ -0,0 +1,284 @@
+<?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 ($sMsg = $this->_sLangsPrefix . 'cdt_err_not_available') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : $sMsg;
+
+        $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 ($sMsg = $this->_sLangsPrefix . 'err_already_processed') && $this->_bIsApi ? [bx_api_get_msg($sMsg)] : $sMsg;
+
+        $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');
+                if($this->_bIsApi)
+                    return ['redirect' => bx_api_get_relative_url(bx_append_url_params($sCheckoutUrl, $aFormData))];
+
+                $this->_oModule->_oTemplate->displayPageCodeRedirect($sCheckoutUrl, $aFormData);
+                exit;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $aItem = array_shift($aCartInfo['items']);
+
+                return array(
+                    'code' => 0,
+                    'popup' => array(
+                        'html' => bx_srv($this->_sModuleCredits, 'get_popup_subscribe', array(array(
+                            'currency_code' => $aCartInfo['vendor_currency_code'],
+                            'currency_sign' => $aCartInfo['vendor_currency_sign'],
+                            'seller' => $iSellerId,
+                            'title' => bx_process_output($aItem['title']),
+                            'amount' => $aItem['price_recurring'],
+                            'period' => $aItem['period_recurring'],
+                            'period_unit' => $aItem['period_unit_recurring'],
+                            'trial' => isset($aItem['trial_recurring']) ? $aItem['trial_recurring'] : 0,
+                            'custom' => $sCustomData,
+                            'return_data_url' => $sReturnDataUrl,
+                        ))),
+                        'options' => array(
+                            'closeOnOuterClick' => true,
+                            'removeOnClose' => true
+                        )
+                    )
+                );
+        }
+    }
+
+    public function finalizeCheckout(&$aData)
+    {
+        $aResult = $this->_finalizeCheckout($aData);
+        if((int)$aResult['code'] != BX_PAYMENT_RESULT_SUCCESS) {
+            $this->log('Finalize Checkout: Failed', '', BX_LOG_ERR);
+            $this->log($aData, '', BX_LOG_ERR);
+            $this->log($aResult, '', BX_LOG_ERR);
+        }
+
+        if(!empty($aResult['pending_id']))
+            $this->_oModule->_oDb->updateOrderPending($aResult['pending_id'], array(
+                'order' => $aResult['order'],
+                'error_code' => $aResult['code'],
+                'error_msg' => _t($aResult['message'])
+            ));
+
+        return $aResult;
+    }
+
+    public function makePayment($mixedPending)
+    {
+        if(!BxDolModuleQuery::getInstance()->isEnabledByName($this->_sModuleCredits))
+            return ['code' => 1, 'message' => $this->_sLangsPrefix . 'cdt_err_not_available'];
+
+        if(!is_array($mixedPending))
+            $mixedPending = $this->_oModule->_oDb->getOrderPending(['type' => 'id', 'id' => (int)$mixedPending]);
+
+        if(empty($mixedPending) || !is_array($mixedPending))
+            return ['code' => 2, 'message' => $this->_sLangsPrefix . 'err_not_found_pending'];
+
+        $iClient = (int)$mixedPending['client_id'];
+        $oClient = BxDolProfile::getInstance($iClient);
+
+        $iSeller = (int)$mixedPending['seller_id'];
+        $oSeller = BxDolProfile::getInstance($iSeller);
+
+        if(!$oClient || !$oSeller)
+            return ['code' => 3, 'message' => $this->_sLangsPrefix . 'err_wrong_data'];
+
+        $fAmountM = $this->_getAmountByPending($mixedPending);
+        $fAmountC = bx_srv($this->_sModuleCredits, 'convert_money_to_credits', [$fAmountM]);
+
+        $fClientBalance = bx_srv($this->_sModuleCredits, 'get_profile_balance', [$iClient]);
+        if($fAmountC > $fClientBalance) {
+            $aSubscription = $this->_oModule->_oDb->getSubscription([
+                'type' => 'pending_id', 
+                'pending_id' => $mixedPending['id']
+            ]);
+
+            if(!empty($aSubscription) && is_array($aSubscription)) {
+                $aTemplate = BxDolEmailTemplates::getInstance()->parseTemplate($this->_oModule->_oConfig->getPrefix('general') . 'wrong_balance', [
+                    'profile_name' => $oClient->getDisplayName(),
+                    'profile_link' => $oClient->getUrl(),
+                    'subscription_id' => $aSubscription['subscription_id'],
+                    'subscription_customer' => $aSubscription['customer_id'],
+                    'subscription_provider' => _t('_bx_payment_txt_name_' . $mixedPending['provider']),
+                    'subscription_date' => date(getParam('sys_format_date'), $aSubscription['date_add']),
+                ], 0, $iClient);
+
+                if($aTemplate !== false)
+                    sendMail($oClient->getAccountObject()->getEmail(), $aTemplate['Subject'], $aTemplate['Body'], 0, [], BX_EMAIL_SYSTEM);
+            }
+
+            return ['code' => 4, 'message' => $this->_sLangsPrefix . 'cdt_err_wrong_balance'];
+        }
+
+        if(!bx_srv($this->_sModuleCredits, 'make_payment', [$iClient, $fAmountC, $iSeller, $mixedPending['order']]))
+            return ['code' => 5, 'message' => $this->_sLangsPrefix . 'err_cannot_perform'];
+
+        return true;        
+    }
+
+    public function cancelRecurring($iPendingId, $sCustomerId, $sSubscriptionId)
+    {
+        /**
+         * @hooks
+         * @hookdef hook-bx_payment-credits_cancel_subscription 'bx_payment', 'credits_cancel_subscription' - hook after a subscription was canceled
+         * - $unit_name - equals `bx_payment`
+         * - $action - equals `credits_cancel_subscription`
+         * - $object_id - not used
+         * - $sender_id - not used
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `pending_id` - [string] pending transaction id
+         *      - `subscription_id` - [string] unique subscription id
+         * @hook @ref hook-bx_payment-credits_cancel_subscription
+         */
+        bx_alert($this->MODULE, $this->_sName . '_cancel_subscription', 0, false, [
+            'pending_id' => $iPendingId,
+            'subscription_id' => $sSubscriptionId,
+        ]);
+
+        return true;
+    }
+
+    public function getMenuItemsActionsRecurring($iClientId, $iVendorId, $aParams = array())
+    {
+        return array();
+    }
+
+    protected function _finalizeCheckout(&$aData)
+    {
+        list($iSellerId, $iPendingId) = $this->_deconstructCustomData($aData['c']);
+
+        if(empty($this->_aOptions) && !empty($iPendingId))
+            $this->_aOptions = $this->getOptionsByPending((int)$iPendingId);
+
+        $aPending = $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => $iPendingId));
+        if(empty($aPending) || !is_array($aPending))
+            return array('code' => 1, 'message' => $this->_sLangsPrefix . 'err_not_found_pending');
+
+        if(empty($this->_aOptions) || !BxDolModuleQuery::getInstance()->isEnabledByName($this->_sModuleCredits))
+            return array('code' => 2, 'message' => $this->_sLangsPrefix . 'err_incorrect_provider', 'pending_id' => $iPendingId);
+
+        switch($aPending['type']) {
+            case BX_PAYMENT_TYPE_SINGLE:
+                if(!empty($aPending['order']) || !empty($aPending['error_code']) || !empty($aPending['error_msg']) || (int)$aPending['processed'] != 0)
+                    return array('code' => 3, 'message' => $this->_sLangsPrefix . 'err_already_processed');
+
+                $sOrder = $aData['o'];
+                $fAmount = $this->_getAmountByPending($aPending);
+                if(!bx_srv($this->_sModuleCredits, 'validate_checkout', array((int)$aPending['seller_id'], (int)$aPending['client_id'], $fAmount, $sOrder)))
+                    return array('code' => 4, 'message' => $this->_sLangsPrefix . 'cdt_err_wrong_transaction', 'pending_id' => $iPendingId);
+
+                $aResult = array(
+                    'message' => $this->_sLangsPrefix . 'cdt_msg_charged',
+                    'order' => $sOrder,
+                    'paid' => true
+                );
+                break;
+
+            case BX_PAYMENT_TYPE_RECURRING:
+                $sSubscriptionId = bx_process_input($aData['sb']);
+
+                $aResult = array(
+                    'message' => $this->_sLangsPrefix . 'cdt_msg_subscribed',
+                    'customer_id' => bx_process_input($aData['cs']),
+                    'subscription_id' => $sSubscriptionId,
+                    'trial' => (bool)$aData['tr'],
+                    'order' => $sSubscriptionId,
+                );
+                break;
+        }
+
+        $oClient = BxDolProfile::getInstance($aPending['client_id']);
+        return array_merge(array(
+            'code' => BX_PAYMENT_RESULT_SUCCESS, 
+            'message' => '',
+            'pending_id' => $iPendingId,
+            'client_name' => $oClient->getDisplayName(),
+            'client_email' => $oClient->getAccountObject()->getEmail(),
+            'order' => ''
+        ), $aResult);
+    }
+
+    protected function _constructCustomData()
+    {
+        $aParams = func_get_args();
+        return urlencode(base64_encode(implode('|', $aParams)));
+    }
+
+    protected function _deconstructCustomData($data)
+    {
+        return explode('|', base64_decode(urldecode($data)));
+    }
+
+    protected function _getAmountByPending($aPending)
+    {
+        $fCurrencyRate = false;
+        $sCurrencyDefault = $this->_oModule->_oConfig->getDefaultCurrencyCode();
+        if(!empty($aPending['data'])) {
+            $aPendingData = unserialize($aPending['data']);
+
+            if(!empty($aPendingData['cur_rate']))
+                $fCurrencyRate = (float)$aPendingData['cur_rate'];
+
+            if(!empty($aPendingData['cur_def']))
+                $sCurrencyDefault = $aPendingData['cur_def'];
+        }
+
+        $fAmount = (float)$aPending['amount'];
+        if(strcmp($aPending['currency'], $sCurrencyDefault) != 0)
+            $fAmount = $this->_oModule->serviceConvert($fAmount, $aPending['currency'], $sCurrencyDefault, $fCurrencyRate);
+
+        return $fAmount;
+    }
+}
+
+/** @} */

+ 652 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/classes/BxPaymentTemplate.php

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

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

+ 716 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/install/langs/en.xml

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

+ 35 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/install/sql/enable-app.sql

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

+ 213 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/install/sql/enable.sql

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

+ 701 - 0
modules/boonex/payment/updates/15.0.2_15.0.3/source/install/sql/install.sql

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

+ 51 - 0
modules/boonex/shopify/updates/15.0.1_15.0.2/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' => 'Shopify',
+    'version_from' => '15.0.1',
+    'version_to' => '15.0.2',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/shopify/updates/update_15.0.1_15.0.2/',
+    'home_uri' => 'shopify_update_1501_1502',
+
+    'module_dir' => 'boonex/shopify/',
+    'module_uri' => 'shopify',
+
+    'db_prefix' => 'bx_shopify_',
+    'class_prefix' => 'BxShopify',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Shopify',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/shopify/updates/15.0.1_15.0.2/install/installer.php

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

+ 32 - 0
modules/boonex/shopify/updates/15.0.1_15.0.2/source/classes/BxShopifyFormSettings.php

@@ -0,0 +1,32 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Shopify Shopify
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Edit settings form
+ */
+class BxShopifyFormSettings extends BxTemplFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_shopify';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aInfo, $oTemplate);
+
+        if(($sF = 'access_token') && isset($this->aInputs[$sF]))
+            $this->aInputs[$sF]['secret'] = 1;
+    }
+}
+
+/** @} */

+ 116 - 0
modules/boonex/shopify/updates/15.0.1_15.0.2/source/install/config.php

@@ -0,0 +1,116 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Shopify Shopify
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_shopify',
+    'title' => 'Shopify',
+    'note' => 'Shopify shopping module.',
+    'version' => '15.0.2',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/shopify/',
+    'home_uri' => 'shopify',
+
+    'db_prefix' => 'bx_shopify_',
+    'class_prefix' => 'BxShopify',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Shopify',
+
+    /**
+     * 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'
+    ),
+
+	/**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_shopify',
+    	'bx_shopify_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,
+        'clear_db_cache' => 1,
+    ),
+    'disable' => array (
+        'execute_sql' => 1,
+    	'update_relations' => 1,
+        'clear_db_cache' => 1,
+    ),
+    'disable_failed' => array (
+    	'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Dependencies Section
+     */
+    'dependencies' => array(),
+
+    /**
+     * Relations Section
+     */
+    'relations' => array(
+    	'bx_timeline',
+    	'bx_notifications'
+    ),
+
+);
+
+/** @} */

File diff suppressed because it is too large
+ 9 - 0
modules/boonex/shopify/updates/15.0.1_15.0.2/source/template/images/icons/std-icon.svg


+ 1 - 5
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/install/config.php

@@ -47,9 +47,5 @@ $aConfig = array(
     /**
      * Files Section
      */
-    'delete_files' => array(
-        'composer.json',
-        'composer.lock',
-        'vendor',
-    ),
+    'delete_files' => array(),
 );

+ 245 - 0
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/classes/BxSMTPModule.php

@@ -0,0 +1,245 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    SMTPMailer SMTP Mailer
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxSMTPModule extends BxDolModule
+{
+    function __construct(&$aModule)
+    {
+        parent::__construct($aModule);
+    }
+
+    function serviceSend ($sRecipientEmail, $sMailSubject, $sMailBody, $sMailHeader, $sMailParameters, $isHtml, $aRecipientInfo = array(), $aCustomHeaders = array())
+    {
+        $iRet = true;
+        $sErrorMessage = '';
+
+        if ($sRecipientEmail) {
+
+            try {
+
+                $mail = new PHPMailer\PHPMailer\PHPMailer(true);
+
+                if ('on' == getParam('bx_smtp_on'))
+                    $mail->IsSMTP();
+                // $mail->SMTPDebug = 2;
+
+                $mail->CharSet = 'UTF-8';
+
+                // smtp server auth or not
+                $mail->SMTPAuth = 'on' == getParam('bx_smtp_auth') ? true : false;
+
+                // from settings, smtp server secure ssl/tls
+                $sParamSecure = getParam('bx_smtp_secure');
+                if ('SSL' == $sParamSecure || 'TLS' == $sParamSecure) {
+
+                    $mail->SMTPSecure = strtolower($sParamSecure);
+
+                    if ('on' == getParam('bx_smtp_allow_selfsigned')) {
+                        $mail->SMTPOptions = array(
+                            'ssl' => array(
+                                'verify_peer' => false,
+                                'verify_peer_name' => false,
+                                'allow_self_signed' => true
+                            )
+                        );
+                    }
+                }
+
+                // from settings, smtp server
+                $sParamHost = getParam('bx_smtp_host');
+                if ($sParamHost)
+                    $mail->Host = $sParamHost;
+
+                // smtp port 25, 465
+                $sParamPort = getParam('bx_smtp_port');
+                if ((int)$sParamPort > 0)
+                    $mail->Port = $sParamPort;
+
+                // from settings, username and passord of smtp server
+                if (getParam('bx_smtp_oauth_on')) {
+                    $mail->AuthType = 'XOAUTH2';
+                    bx_import('MailAuthorization', $this->_aModule);
+                    bx_import('MailAuthorizationPHPMailer', $this->_aModule);
+                    $mail->setOAuth(BxSMTPMailAuthorizationPHPMailer::getInstance([
+                        'mailAddress' => getParam('bx_smtp_from_email'),
+                        'clientId' => getParam('bx_smtp_oauth_client_id'),
+                        'tenantId' => getParam('bx_smtp_oauth_tenant_id'),
+                        'tenantName' => getParam('bx_smtp_oauth_tenant_name'),
+                        'x509Cert' => getParam('bx_smtp_oauth_cert_public'),
+                        'x509Key' => getParam('bx_smtp_oauth_cert_private'),
+                    ]));
+                }
+                else {
+                    $mail->Username = getParam ('bx_smtp_username');
+                    $mail->Password = getParam ('bx_smtp_password');
+                }
+
+                if (!isset($aCustomHeaders['From'])) {
+                    $sParamSender = trim(getParam('bx_smtp_from_email'));
+                    if ($sParamSender)
+                        $mail->From = $sParamSender;
+                    else
+                        $mail->From = getParam('site_email_notify');
+
+                    // get site name or some other name as sender's name
+                    $mail->FromName = getParam ('bx_smtp_from_name');
+                } 
+
+                if (!isset($aCustomHeaders['Subject']))
+                    $mail->Subject = $sMailSubject;
+
+                if ($isHtml) {
+                    $mail->Body = $sMailBody;
+                    $mail->AltBody = $isHtml ? strip_tags($sMailBody) : $sMailBody;
+                } else {
+                    $mail->Body = $sMailBody;
+                }
+
+                $mail->WordWrap = 50; // set word wrap
+
+                if (getParam('bx_smtp_test_mode')) {
+                    $aCustomHeaders['X-Original-To'] = $sRecipientEmail;
+                    if (isset($aCustomHeaders['Subject']))
+                        $aCustomHeaders['Subject'] = getParam('bx_smtp_test_subj') . $aCustomHeaders['Subject'];
+                    else
+                        $mail->Subject = getParam('bx_smtp_test_subj') . $mail->Subject;
+                }
+
+                $mail->AddAddress(getParam('bx_smtp_test_mode') ? getParam('bx_smtp_test_email') : $sRecipientEmail);
+
+                $mail->IsHTML($isHtml ? true : false);
+
+                foreach ($aCustomHeaders as $sHeaderName => $sHeaderValue) {
+                    if ('From' == $sHeaderName) {
+                        if (preg_match('/(.+)<(.+)>/', $sHeaderValue, $m)) {
+                            $mail->setFrom($m[2], trim($m[1]), false);
+                        }
+                        else {
+                            $mail->setFrom($sHeaderValue, '', false);
+                        }
+                    } 
+                    else {
+                        $mail->addCustomHeader($sHeaderName, $sHeaderValue);
+                    }
+                }
+
+                $mail->Send();
+                
+            } catch (PHPMailer\PHPMailer\Exception $e) {
+                $iRet = false;
+                $sErrorMessage = $e->getMessage();
+                $this->log("Mailer Error ($sRecipientEmail): " . $sErrorMessage);
+            }
+        }
+
+        //--- create system event [begin]
+        $aAlertData = array(
+            'test_mode' => (bool)getParam('bx_smtp_test_mode'),
+            'email'     => $sRecipientEmail,
+            'subject'   => $sMailSubject,
+            'body'      => $sMailBody,
+            'header'    => $sMailHeader,
+            'params'    => $sMailParameters,
+            'recipient' => $aRecipientInfo,
+            'html'      => $isHtml,
+            'ret'       => $iRet,
+            'error_message' => $sErrorMessage,            
+        );
+        /**
+         * @hooks
+         * @hookdef hook-profile-send_mail 'profile', 'send_mail' - hook in  $oAccount->isConfirmed check
+         * - $unit_name - equals `profile`
+         * - $action - equals `send_mail` 
+         * - $object_id - not used 
+         * - $sender_id - recipient profile_id 
+         * - $extra_params - array of additional params with the following array keys:
+         *      - `test_mode` - [bool] test mode or not
+         *      - `email` - [string] email
+         *      - `subject` - [string] letter subject
+         *      - `body` - [string] letter body
+         *      - `header` - [string] letter header
+         *      - `params` - [string] letter params
+         *      - `recipient` - [array] recipient info
+         *      - `html` - [bool] is html letter or not
+         *      - `ret` - [bool] sent successfuly  or not
+         *      - `error_message` - [string] error message
+         * @hook @ref hook-profile-send_mail
+         */
+        bx_alert('profile', 'send_mail', $aRecipientInfo && isset($aRecipientInfo['ID']) ? $aRecipientInfo['ID'] : 0, '', $aAlertData);
+        //--- create system event [ end ]
+
+        return $iRet;
+    }
+
+    function formTester()
+    {
+        $sMsg  = '';
+        if (isset($_POST['tester_submit']) && $_POST['tester_submit']) {
+
+            $isHTML = bx_get('html') == 'on' ? true : false;
+            $sRecipient = bx_process_pass(bx_get('recipient'));
+            $sSubj = bx_get('subject');
+            $sBody = bx_process_pass(bx_get('body'), $isHTML ? BX_DATA_HTML : BX_DATA_TEXT);
+
+            if (sendMail($sRecipient, $sSubj, $sBody, 0, array(), BX_EMAIL_SYSTEM, $isHTML ? 'html' : ''))
+                $sMsg = MsgBox(_t('_bx_smtp_send_ok'));
+            else
+                $sMsg = MsgBox(_t('_bx_smtp_send_fail'));
+        }
+
+        $aForm = array(
+            'form_attrs' => array(
+                'method'   => 'post',
+            ),
+            'inputs' => array (
+                'recipient' => array(
+                    'type' => 'text',
+                    'name' => 'recipient',
+                    'caption' => _t('_bx_smtp_recipient'),
+                    'value' => '',
+                ),
+                'subject' => array(
+                    'type' => 'text',
+                    'name' => 'subject',
+                    'caption' => _t('_bx_smtp_subject'),
+                    'value' => '',
+                ),
+                'body' => array(
+                    'type' => 'textarea',
+                    'name' => 'body',
+                    'caption' => _t('_bx_smtp_body'),
+                    'value' => '',
+                ),
+                'html' => array(
+                    'type' => 'checkbox',
+                    'name' => 'html',
+                    'caption' => _t('_bx_smtp_is_html'),
+                    'checked' => false,
+                ),
+                'Submit' => array(
+                    'type' => 'submit',
+                    'name' => 'tester_submit',
+                    'value' => _t("_Submit"),
+                ),
+            )
+        );
+
+        $oForm = new BxTemplFormView($aForm);
+        return $sMsg . $oForm->getCode();
+    }
+
+    function log ($s)
+    {
+        bx_log('bx_smtp_mailer', $s, BX_LOG_ERR);
+    }
+}
+
+/** @} */

+ 0 - 5
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/composer.json

@@ -1,5 +0,0 @@
-{
-    "require": {
-        "firebase/php-jwt": "^7.1"
-    }
-}

+ 0 - 85
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/composer.lock

@@ -1,85 +0,0 @@
-{
-    "_readme": [
-        "This file locks the dependencies of your project to a known state",
-        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
-        "This file is @generated automatically"
-    ],
-    "content-hash": "57ead8f94a88c5546e5c032135793e3c",
-    "packages": [
-        {
-            "name": "firebase/php-jwt",
-            "version": "v7.1.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/googleapis/php-jwt.git",
-                "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/b374a5d1a4f1f67fadc2165cdb284645945e2fc0",
-                "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^8.0"
-            },
-            "require-dev": {
-                "guzzlehttp/guzzle": "^7.4",
-                "phpfastcache/phpfastcache": "^9.2",
-                "phpseclib/phpseclib": "~3.0",
-                "phpspec/prophecy-phpunit": "^2.0",
-                "phpunit/phpunit": "^9.5",
-                "psr/cache": "^2.0||^3.0",
-                "psr/http-client": "^1.0",
-                "psr/http-factory": "^1.0"
-            },
-            "suggest": {
-                "ext-sodium": "Support EdDSA (Ed25519) signatures",
-                "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present",
-                "phpseclib/phpseclib": "Support PS256 (RSASSA-PSS) signatures"
-            },
-            "type": "library",
-            "autoload": {
-                "psr-4": {
-                    "Firebase\\JWT\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Neuman Vong",
-                    "email": "neuman+pear@twilio.com",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Anant Narayanan",
-                    "email": "anant@php.net",
-                    "role": "Developer"
-                }
-            ],
-            "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
-            "homepage": "https://github.com/googleapis/php-jwt",
-            "keywords": [
-                "jwt",
-                "php"
-            ],
-            "support": {
-                "issues": "https://github.com/googleapis/php-jwt/issues",
-                "source": "https://github.com/googleapis/php-jwt/tree/v7.1.0"
-            },
-            "time": "2026-06-11T17:54:14+00:00"
-        }
-    ],
-    "packages-dev": [],
-    "aliases": [],
-    "minimum-stability": "stable",
-    "stability-flags": {},
-    "prefer-stable": false,
-    "prefer-lowest": false,
-    "platform": {},
-    "platform-dev": {},
-    "plugin-api-version": "2.6.0"
-}

+ 3 - 3
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/install/sql/enable.sql

@@ -14,7 +14,7 @@ INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `c
 ('bx_smtp_on', '', @iCategId, '_bx_smtp_option_on', 'checkbox', '', '', 10, ''),
 ('bx_smtp_auth', '', @iCategId, '_bx_smtp_option_auth', 'checkbox', '', '', 20, ''),
 ('bx_smtp_username', '', @iCategId, '_bx_smtp_option_username', 'digit', '', '', 30, ''),
-('bx_smtp_password', '', @iCategId, '_bx_smtp_option_password', 'digit', '', '', 40, ''),
+('bx_smtp_password', '', @iCategId, '_bx_smtp_option_password', 'secret', '', '', 40, ''),
 ('bx_smtp_host', '', @iCategId, '_bx_smtp_option_host', 'digit', '', '', 50, ''),
 ('bx_smtp_port', '25', @iCategId, '_bx_smtp_option_port', 'digit', '', '', 60, ''),
 ('bx_smtp_secure', 'Not Secure', @iCategId, '_bx_smtp_option_secure', 'select', '', '', 70, 'Not Secure,SSL,TLS'), 
@@ -26,7 +26,7 @@ INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `c
 ('bx_smtp_test_subj', '[TEST] ', @iCategId, '_bx_smtp_option_test_subj', 'digit', '', '', 104, '');
 
 INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order` )  
-VALUES (@iTypeId, 'bx_smtp_oauth', '_bx_smtp_adm_stg_cpt_category_oauth', 1);
+VALUES (@iTypeId, 'bx_smtp_oauth', '_bx_smtp_adm_stg_cpt_category_oauth', 2);
 SET @iCategId = LAST_INSERT_ID();
 
 INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `check`, `check_error`, `order`, `extra`) VALUES
@@ -35,7 +35,7 @@ INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `c
 ('bx_smtp_oauth_tenant_id', '', @iCategId, '_bx_smtp_oauth_tenant_id', 'digit', '', '', 30, ''),
 ('bx_smtp_oauth_tenant_name', '', @iCategId, '_bx_smtp_oauth_tenant_name', 'digit', '', '', 40, ''),
 ('bx_smtp_oauth_cert_public', '', @iCategId, '_bx_smtp_oauth_cert_public', 'text', '', '', 50, ''),
-('bx_smtp_oauth_cert_private', '', @iCategId, '_bx_smtp_oauth_cert_private', 'text', '', '', 60, '');
+('bx_smtp_oauth_cert_private', '', @iCategId, '_bx_smtp_oauth_cert_private', 'secret_text', '', '', 60, '');
 
 
 -- logs

+ 0 - 22
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/autoload.php

@@ -1,22 +0,0 @@
-<?php
-
-// autoload.php @generated by Composer
-
-if (PHP_VERSION_ID < 50600) {
-    if (!headers_sent()) {
-        header('HTTP/1.1 500 Internal Server Error');
-    }
-    $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
-    if (!ini_get('display_errors')) {
-        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
-            fwrite(STDERR, $err);
-        } elseif (!headers_sent()) {
-            echo $err;
-        }
-    }
-    throw new RuntimeException($err);
-}
-
-require_once __DIR__ . '/composer/autoload_real.php';
-
-return ComposerAutoloaderInit20fad51902f91e7fd3039e016a6556b5::getLoader();

+ 0 - 579
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/ClassLoader.php

@@ -1,579 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer\Autoload;
-
-/**
- * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
- *
- *     $loader = new \Composer\Autoload\ClassLoader();
- *
- *     // register classes with namespaces
- *     $loader->add('Symfony\Component', __DIR__.'/component');
- *     $loader->add('Symfony',           __DIR__.'/framework');
- *
- *     // activate the autoloader
- *     $loader->register();
- *
- *     // to enable searching the include path (eg. for PEAR packages)
- *     $loader->setUseIncludePath(true);
- *
- * In this example, if you try to use a class in the Symfony\Component
- * namespace or one of its children (Symfony\Component\Console for instance),
- * the autoloader will first look for the class under the component/
- * directory, and it will then fallback to the framework/ directory if not
- * found before giving up.
- *
- * This class is loosely based on the Symfony UniversalClassLoader.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- * @author Jordi Boggiano <j.boggiano@seld.be>
- * @see    https://www.php-fig.org/psr/psr-0/
- * @see    https://www.php-fig.org/psr/psr-4/
- */
-class ClassLoader
-{
-    /** @var \Closure(string):void */
-    private static $includeFile;
-
-    /** @var string|null */
-    private $vendorDir;
-
-    // PSR-4
-    /**
-     * @var array<string, array<string, int>>
-     */
-    private $prefixLengthsPsr4 = array();
-    /**
-     * @var array<string, list<string>>
-     */
-    private $prefixDirsPsr4 = array();
-    /**
-     * @var list<string>
-     */
-    private $fallbackDirsPsr4 = array();
-
-    // PSR-0
-    /**
-     * List of PSR-0 prefixes
-     *
-     * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
-     *
-     * @var array<string, array<string, list<string>>>
-     */
-    private $prefixesPsr0 = array();
-    /**
-     * @var list<string>
-     */
-    private $fallbackDirsPsr0 = array();
-
-    /** @var bool */
-    private $useIncludePath = false;
-
-    /**
-     * @var array<string, string>
-     */
-    private $classMap = array();
-
-    /** @var bool */
-    private $classMapAuthoritative = false;
-
-    /**
-     * @var array<string, bool>
-     */
-    private $missingClasses = array();
-
-    /** @var string|null */
-    private $apcuPrefix;
-
-    /**
-     * @var array<string, self>
-     */
-    private static $registeredLoaders = array();
-
-    /**
-     * @param string|null $vendorDir
-     */
-    public function __construct($vendorDir = null)
-    {
-        $this->vendorDir = $vendorDir;
-        self::initializeIncludeClosure();
-    }
-
-    /**
-     * @return array<string, list<string>>
-     */
-    public function getPrefixes()
-    {
-        if (!empty($this->prefixesPsr0)) {
-            return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
-        }
-
-        return array();
-    }
-
-    /**
-     * @return array<string, list<string>>
-     */
-    public function getPrefixesPsr4()
-    {
-        return $this->prefixDirsPsr4;
-    }
-
-    /**
-     * @return list<string>
-     */
-    public function getFallbackDirs()
-    {
-        return $this->fallbackDirsPsr0;
-    }
-
-    /**
-     * @return list<string>
-     */
-    public function getFallbackDirsPsr4()
-    {
-        return $this->fallbackDirsPsr4;
-    }
-
-    /**
-     * @return array<string, string> Array of classname => path
-     */
-    public function getClassMap()
-    {
-        return $this->classMap;
-    }
-
-    /**
-     * @param array<string, string> $classMap Class to filename map
-     *
-     * @return void
-     */
-    public function addClassMap(array $classMap)
-    {
-        if ($this->classMap) {
-            $this->classMap = array_merge($this->classMap, $classMap);
-        } else {
-            $this->classMap = $classMap;
-        }
-    }
-
-    /**
-     * Registers a set of PSR-0 directories for a given prefix, either
-     * appending or prepending to the ones previously set for this prefix.
-     *
-     * @param string              $prefix  The prefix
-     * @param list<string>|string $paths   The PSR-0 root directories
-     * @param bool                $prepend Whether to prepend the directories
-     *
-     * @return void
-     */
-    public function add($prefix, $paths, $prepend = false)
-    {
-        $paths = (array) $paths;
-        if (!$prefix) {
-            if ($prepend) {
-                $this->fallbackDirsPsr0 = array_merge(
-                    $paths,
-                    $this->fallbackDirsPsr0
-                );
-            } else {
-                $this->fallbackDirsPsr0 = array_merge(
-                    $this->fallbackDirsPsr0,
-                    $paths
-                );
-            }
-
-            return;
-        }
-
-        $first = $prefix[0];
-        if (!isset($this->prefixesPsr0[$first][$prefix])) {
-            $this->prefixesPsr0[$first][$prefix] = $paths;
-
-            return;
-        }
-        if ($prepend) {
-            $this->prefixesPsr0[$first][$prefix] = array_merge(
-                $paths,
-                $this->prefixesPsr0[$first][$prefix]
-            );
-        } else {
-            $this->prefixesPsr0[$first][$prefix] = array_merge(
-                $this->prefixesPsr0[$first][$prefix],
-                $paths
-            );
-        }
-    }
-
-    /**
-     * Registers a set of PSR-4 directories for a given namespace, either
-     * appending or prepending to the ones previously set for this namespace.
-     *
-     * @param string              $prefix  The prefix/namespace, with trailing '\\'
-     * @param list<string>|string $paths   The PSR-4 base directories
-     * @param bool                $prepend Whether to prepend the directories
-     *
-     * @throws \InvalidArgumentException
-     *
-     * @return void
-     */
-    public function addPsr4($prefix, $paths, $prepend = false)
-    {
-        $paths = (array) $paths;
-        if (!$prefix) {
-            // Register directories for the root namespace.
-            if ($prepend) {
-                $this->fallbackDirsPsr4 = array_merge(
-                    $paths,
-                    $this->fallbackDirsPsr4
-                );
-            } else {
-                $this->fallbackDirsPsr4 = array_merge(
-                    $this->fallbackDirsPsr4,
-                    $paths
-                );
-            }
-        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
-            // Register directories for a new namespace.
-            $length = strlen($prefix);
-            if ('\\' !== $prefix[$length - 1]) {
-                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
-            }
-            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
-            $this->prefixDirsPsr4[$prefix] = $paths;
-        } elseif ($prepend) {
-            // Prepend directories for an already registered namespace.
-            $this->prefixDirsPsr4[$prefix] = array_merge(
-                $paths,
-                $this->prefixDirsPsr4[$prefix]
-            );
-        } else {
-            // Append directories for an already registered namespace.
-            $this->prefixDirsPsr4[$prefix] = array_merge(
-                $this->prefixDirsPsr4[$prefix],
-                $paths
-            );
-        }
-    }
-
-    /**
-     * Registers a set of PSR-0 directories for a given prefix,
-     * replacing any others previously set for this prefix.
-     *
-     * @param string              $prefix The prefix
-     * @param list<string>|string $paths  The PSR-0 base directories
-     *
-     * @return void
-     */
-    public function set($prefix, $paths)
-    {
-        if (!$prefix) {
-            $this->fallbackDirsPsr0 = (array) $paths;
-        } else {
-            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
-        }
-    }
-
-    /**
-     * Registers a set of PSR-4 directories for a given namespace,
-     * replacing any others previously set for this namespace.
-     *
-     * @param string              $prefix The prefix/namespace, with trailing '\\'
-     * @param list<string>|string $paths  The PSR-4 base directories
-     *
-     * @throws \InvalidArgumentException
-     *
-     * @return void
-     */
-    public function setPsr4($prefix, $paths)
-    {
-        if (!$prefix) {
-            $this->fallbackDirsPsr4 = (array) $paths;
-        } else {
-            $length = strlen($prefix);
-            if ('\\' !== $prefix[$length - 1]) {
-                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
-            }
-            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
-            $this->prefixDirsPsr4[$prefix] = (array) $paths;
-        }
-    }
-
-    /**
-     * Turns on searching the include path for class files.
-     *
-     * @param bool $useIncludePath
-     *
-     * @return void
-     */
-    public function setUseIncludePath($useIncludePath)
-    {
-        $this->useIncludePath = $useIncludePath;
-    }
-
-    /**
-     * Can be used to check if the autoloader uses the include path to check
-     * for classes.
-     *
-     * @return bool
-     */
-    public function getUseIncludePath()
-    {
-        return $this->useIncludePath;
-    }
-
-    /**
-     * Turns off searching the prefix and fallback directories for classes
-     * that have not been registered with the class map.
-     *
-     * @param bool $classMapAuthoritative
-     *
-     * @return void
-     */
-    public function setClassMapAuthoritative($classMapAuthoritative)
-    {
-        $this->classMapAuthoritative = $classMapAuthoritative;
-    }
-
-    /**
-     * Should class lookup fail if not found in the current class map?
-     *
-     * @return bool
-     */
-    public function isClassMapAuthoritative()
-    {
-        return $this->classMapAuthoritative;
-    }
-
-    /**
-     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
-     *
-     * @param string|null $apcuPrefix
-     *
-     * @return void
-     */
-    public function setApcuPrefix($apcuPrefix)
-    {
-        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
-    }
-
-    /**
-     * The APCu prefix in use, or null if APCu caching is not enabled.
-     *
-     * @return string|null
-     */
-    public function getApcuPrefix()
-    {
-        return $this->apcuPrefix;
-    }
-
-    /**
-     * Registers this instance as an autoloader.
-     *
-     * @param bool $prepend Whether to prepend the autoloader or not
-     *
-     * @return void
-     */
-    public function register($prepend = false)
-    {
-        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
-
-        if (null === $this->vendorDir) {
-            return;
-        }
-
-        if ($prepend) {
-            self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders;
-        } else {
-            unset(self::$registeredLoaders[$this->vendorDir]);
-            self::$registeredLoaders[$this->vendorDir] = $this;
-        }
-    }
-
-    /**
-     * Unregisters this instance as an autoloader.
-     *
-     * @return void
-     */
-    public function unregister()
-    {
-        spl_autoload_unregister(array($this, 'loadClass'));
-
-        if (null !== $this->vendorDir) {
-            unset(self::$registeredLoaders[$this->vendorDir]);
-        }
-    }
-
-    /**
-     * Loads the given class or interface.
-     *
-     * @param  string    $class The name of the class
-     * @return true|null True if loaded, null otherwise
-     */
-    public function loadClass($class)
-    {
-        if ($file = $this->findFile($class)) {
-            $includeFile = self::$includeFile;
-            $includeFile($file);
-
-            return true;
-        }
-
-        return null;
-    }
-
-    /**
-     * Finds the path to the file where the class is defined.
-     *
-     * @param string $class The name of the class
-     *
-     * @return string|false The path if found, false otherwise
-     */
-    public function findFile($class)
-    {
-        // class map lookup
-        if (isset($this->classMap[$class])) {
-            return $this->classMap[$class];
-        }
-        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
-            return false;
-        }
-        if (null !== $this->apcuPrefix) {
-            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
-            if ($hit) {
-                return $file;
-            }
-        }
-
-        $file = $this->findFileWithExtension($class, '.php');
-
-        // Search for Hack files if we are running on HHVM
-        if (false === $file && defined('HHVM_VERSION')) {
-            $file = $this->findFileWithExtension($class, '.hh');
-        }
-
-        if (null !== $this->apcuPrefix) {
-            apcu_add($this->apcuPrefix.$class, $file);
-        }
-
-        if (false === $file) {
-            // Remember that this class does not exist.
-            $this->missingClasses[$class] = true;
-        }
-
-        return $file;
-    }
-
-    /**
-     * Returns the currently registered loaders keyed by their corresponding vendor directories.
-     *
-     * @return array<string, self>
-     */
-    public static function getRegisteredLoaders()
-    {
-        return self::$registeredLoaders;
-    }
-
-    /**
-     * @param  string       $class
-     * @param  string       $ext
-     * @return string|false
-     */
-    private function findFileWithExtension($class, $ext)
-    {
-        // PSR-4 lookup
-        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
-
-        $first = $class[0];
-        if (isset($this->prefixLengthsPsr4[$first])) {
-            $subPath = $class;
-            while (false !== $lastPos = strrpos($subPath, '\\')) {
-                $subPath = substr($subPath, 0, $lastPos);
-                $search = $subPath . '\\';
-                if (isset($this->prefixDirsPsr4[$search])) {
-                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
-                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
-                        if (file_exists($file = $dir . $pathEnd)) {
-                            return $file;
-                        }
-                    }
-                }
-            }
-        }
-
-        // PSR-4 fallback dirs
-        foreach ($this->fallbackDirsPsr4 as $dir) {
-            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
-                return $file;
-            }
-        }
-
-        // PSR-0 lookup
-        if (false !== $pos = strrpos($class, '\\')) {
-            // namespaced class name
-            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
-                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
-        } else {
-            // PEAR-like class name
-            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
-        }
-
-        if (isset($this->prefixesPsr0[$first])) {
-            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
-                if (0 === strpos($class, $prefix)) {
-                    foreach ($dirs as $dir) {
-                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
-                            return $file;
-                        }
-                    }
-                }
-            }
-        }
-
-        // PSR-0 fallback dirs
-        foreach ($this->fallbackDirsPsr0 as $dir) {
-            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
-                return $file;
-            }
-        }
-
-        // PSR-0 include paths.
-        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
-            return $file;
-        }
-
-        return false;
-    }
-
-    /**
-     * @return void
-     */
-    private static function initializeIncludeClosure()
-    {
-        if (self::$includeFile !== null) {
-            return;
-        }
-
-        /**
-         * Scope isolated include.
-         *
-         * Prevents access to $this/self from included files.
-         *
-         * @param  string $file
-         * @return void
-         */
-        self::$includeFile = \Closure::bind(static function($file) {
-            include $file;
-        }, null, null);
-    }
-}

+ 0 - 396
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/InstalledVersions.php

@@ -1,396 +0,0 @@
-<?php
-
-/*
- * This file is part of Composer.
- *
- * (c) Nils Adermann <naderman@naderman.de>
- *     Jordi Boggiano <j.boggiano@seld.be>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Composer;
-
-use Composer\Autoload\ClassLoader;
-use Composer\Semver\VersionParser;
-
-/**
- * This class is copied in every Composer installed project and available to all
- *
- * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
- *
- * To require its presence, you can require `composer-runtime-api ^2.0`
- *
- * @final
- */
-class InstalledVersions
-{
-    /**
-     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
-     * @internal
-     */
-    private static $selfDir = null;
-
-    /**
-     * @var mixed[]|null
-     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
-     */
-    private static $installed;
-
-    /**
-     * @var bool
-     */
-    private static $installedIsLocalDir;
-
-    /**
-     * @var bool|null
-     */
-    private static $canGetVendors;
-
-    /**
-     * @var array[]
-     * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
-     */
-    private static $installedByVendor = array();
-
-    /**
-     * Returns a list of all package names which are present, either by being installed, replaced or provided
-     *
-     * @return string[]
-     * @psalm-return list<string>
-     */
-    public static function getInstalledPackages()
-    {
-        $packages = array();
-        foreach (self::getInstalled() as $installed) {
-            $packages[] = array_keys($installed['versions']);
-        }
-
-        if (1 === \count($packages)) {
-            return $packages[0];
-        }
-
-        return array_keys(array_flip(\call_user_func_array('array_merge', $packages)));
-    }
-
-    /**
-     * Returns a list of all package names with a specific type e.g. 'library'
-     *
-     * @param  string   $type
-     * @return string[]
-     * @psalm-return list<string>
-     */
-    public static function getInstalledPackagesByType($type)
-    {
-        $packagesByType = array();
-
-        foreach (self::getInstalled() as $installed) {
-            foreach ($installed['versions'] as $name => $package) {
-                if (isset($package['type']) && $package['type'] === $type) {
-                    $packagesByType[] = $name;
-                }
-            }
-        }
-
-        return $packagesByType;
-    }
-
-    /**
-     * Checks whether the given package is installed
-     *
-     * This also returns true if the package name is provided or replaced by another package
-     *
-     * @param  string $packageName
-     * @param  bool   $includeDevRequirements
-     * @return bool
-     */
-    public static function isInstalled($packageName, $includeDevRequirements = true)
-    {
-        foreach (self::getInstalled() as $installed) {
-            if (isset($installed['versions'][$packageName])) {
-                return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Checks whether the given package satisfies a version constraint
-     *
-     * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call:
-     *
-     *   Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3')
-     *
-     * @param  VersionParser $parser      Install composer/semver to have access to this class and functionality
-     * @param  string        $packageName
-     * @param  string|null   $constraint  A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package
-     * @return bool
-     */
-    public static function satisfies(VersionParser $parser, $packageName, $constraint)
-    {
-        $constraint = $parser->parseConstraints((string) $constraint);
-        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
-
-        return $provided->matches($constraint);
-    }
-
-    /**
-     * Returns a version constraint representing all the range(s) which are installed for a given package
-     *
-     * It is easier to use this via isInstalled() with the $constraint argument if you need to check
-     * whether a given version of a package is installed, and not just whether it exists
-     *
-     * @param  string $packageName
-     * @return string Version constraint usable with composer/semver
-     */
-    public static function getVersionRanges($packageName)
-    {
-        foreach (self::getInstalled() as $installed) {
-            if (!isset($installed['versions'][$packageName])) {
-                continue;
-            }
-
-            $ranges = array();
-            if (isset($installed['versions'][$packageName]['pretty_version'])) {
-                $ranges[] = $installed['versions'][$packageName]['pretty_version'];
-            }
-            if (array_key_exists('aliases', $installed['versions'][$packageName])) {
-                $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']);
-            }
-            if (array_key_exists('replaced', $installed['versions'][$packageName])) {
-                $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']);
-            }
-            if (array_key_exists('provided', $installed['versions'][$packageName])) {
-                $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']);
-            }
-
-            return implode(' || ', $ranges);
-        }
-
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
-    }
-
-    /**
-     * @param  string      $packageName
-     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
-     */
-    public static function getVersion($packageName)
-    {
-        foreach (self::getInstalled() as $installed) {
-            if (!isset($installed['versions'][$packageName])) {
-                continue;
-            }
-
-            if (!isset($installed['versions'][$packageName]['version'])) {
-                return null;
-            }
-
-            return $installed['versions'][$packageName]['version'];
-        }
-
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
-    }
-
-    /**
-     * @param  string      $packageName
-     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present
-     */
-    public static function getPrettyVersion($packageName)
-    {
-        foreach (self::getInstalled() as $installed) {
-            if (!isset($installed['versions'][$packageName])) {
-                continue;
-            }
-
-            if (!isset($installed['versions'][$packageName]['pretty_version'])) {
-                return null;
-            }
-
-            return $installed['versions'][$packageName]['pretty_version'];
-        }
-
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
-    }
-
-    /**
-     * @param  string      $packageName
-     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference
-     */
-    public static function getReference($packageName)
-    {
-        foreach (self::getInstalled() as $installed) {
-            if (!isset($installed['versions'][$packageName])) {
-                continue;
-            }
-
-            if (!isset($installed['versions'][$packageName]['reference'])) {
-                return null;
-            }
-
-            return $installed['versions'][$packageName]['reference'];
-        }
-
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
-    }
-
-    /**
-     * @param  string      $packageName
-     * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path.
-     */
-    public static function getInstallPath($packageName)
-    {
-        foreach (self::getInstalled() as $installed) {
-            if (!isset($installed['versions'][$packageName])) {
-                continue;
-            }
-
-            return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null;
-        }
-
-        throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed');
-    }
-
-    /**
-     * @return array
-     * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
-     */
-    public static function getRootPackage()
-    {
-        $installed = self::getInstalled();
-
-        return $installed[0]['root'];
-    }
-
-    /**
-     * Returns the raw installed.php data for custom implementations
-     *
-     * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
-     * @return array[]
-     * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
-     */
-    public static function getRawData()
-    {
-        @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED);
-
-        if (null === self::$installed) {
-            // only require the installed.php file if this file is loaded from its dumped location,
-            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
-            if (substr(__DIR__, -8, 1) !== 'C') {
-                self::$installed = include __DIR__ . '/installed.php';
-            } else {
-                self::$installed = array();
-            }
-        }
-
-        return self::$installed;
-    }
-
-    /**
-     * Returns the raw data of all installed.php which are currently loaded for custom implementations
-     *
-     * @return array[]
-     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
-     */
-    public static function getAllRawData()
-    {
-        return self::getInstalled();
-    }
-
-    /**
-     * Lets you reload the static array from another file
-     *
-     * This is only useful for complex integrations in which a project needs to use
-     * this class but then also needs to execute another project's autoloader in process,
-     * and wants to ensure both projects have access to their version of installed.php.
-     *
-     * A typical case would be PHPUnit, where it would need to make sure it reads all
-     * the data it needs from this class, then call reload() with
-     * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure
-     * the project in which it runs can then also use this class safely, without
-     * interference between PHPUnit's dependencies and the project's dependencies.
-     *
-     * @param  array[] $data A vendor/composer/installed.php data set
-     * @return void
-     *
-     * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
-     */
-    public static function reload($data)
-    {
-        self::$installed = $data;
-        self::$installedByVendor = array();
-
-        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
-        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
-        // so we have to assume it does not, and that may result in duplicate data being returned when listing
-        // all installed packages for example
-        self::$installedIsLocalDir = false;
-    }
-
-    /**
-     * @return string
-     */
-    private static function getSelfDir()
-    {
-        if (self::$selfDir === null) {
-            self::$selfDir = strtr(__DIR__, '\\', '/');
-        }
-
-        return self::$selfDir;
-    }
-
-    /**
-     * @return array[]
-     * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
-     */
-    private static function getInstalled()
-    {
-        if (null === self::$canGetVendors) {
-            self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders');
-        }
-
-        $installed = array();
-        $copiedLocalDir = false;
-
-        if (self::$canGetVendors) {
-            $selfDir = self::getSelfDir();
-            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
-                $vendorDir = strtr($vendorDir, '\\', '/');
-                if (isset(self::$installedByVendor[$vendorDir])) {
-                    $installed[] = self::$installedByVendor[$vendorDir];
-                } elseif (is_file($vendorDir.'/composer/installed.php')) {
-                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
-                    $required = require $vendorDir.'/composer/installed.php';
-                    self::$installedByVendor[$vendorDir] = $required;
-                    $installed[] = $required;
-                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
-                        self::$installed = $required;
-                        self::$installedIsLocalDir = true;
-                    }
-                }
-                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
-                    $copiedLocalDir = true;
-                }
-            }
-        }
-
-        if (null === self::$installed) {
-            // only require the installed.php file if this file is loaded from its dumped location,
-            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
-            if (substr(__DIR__, -8, 1) !== 'C') {
-                /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
-                $required = require __DIR__ . '/installed.php';
-                self::$installed = $required;
-            } else {
-                self::$installed = array();
-            }
-        }
-
-        if (self::$installed !== array() && !$copiedLocalDir) {
-            $installed[] = self::$installed;
-        }
-
-        return $installed;
-    }
-}

+ 0 - 21
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/LICENSE

@@ -1,21 +0,0 @@
-
-Copyright (c) Nils Adermann, Jordi Boggiano
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is furnished
-to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-

+ 0 - 10
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_classmap.php

@@ -1,10 +0,0 @@
-<?php
-
-// autoload_classmap.php @generated by Composer
-
-$vendorDir = dirname(__DIR__);
-$baseDir = dirname($vendorDir);
-
-return array(
-    'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
-);

+ 0 - 9
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_namespaces.php

@@ -1,9 +0,0 @@
-<?php
-
-// autoload_namespaces.php @generated by Composer
-
-$vendorDir = dirname(__DIR__);
-$baseDir = dirname($vendorDir);
-
-return array(
-);

+ 0 - 10
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_psr4.php

@@ -1,10 +0,0 @@
-<?php
-
-// autoload_psr4.php @generated by Composer
-
-$vendorDir = dirname(__DIR__);
-$baseDir = dirname($vendorDir);
-
-return array(
-    'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
-);

+ 0 - 38
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_real.php

@@ -1,38 +0,0 @@
-<?php
-
-// autoload_real.php @generated by Composer
-
-class ComposerAutoloaderInit20fad51902f91e7fd3039e016a6556b5
-{
-    private static $loader;
-
-    public static function loadClassLoader($class)
-    {
-        if ('Composer\Autoload\ClassLoader' === $class) {
-            require __DIR__ . '/ClassLoader.php';
-        }
-    }
-
-    /**
-     * @return \Composer\Autoload\ClassLoader
-     */
-    public static function getLoader()
-    {
-        if (null !== self::$loader) {
-            return self::$loader;
-        }
-
-        require __DIR__ . '/platform_check.php';
-
-        spl_autoload_register(array('ComposerAutoloaderInit20fad51902f91e7fd3039e016a6556b5', 'loadClassLoader'), true, true);
-        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
-        spl_autoload_unregister(array('ComposerAutoloaderInit20fad51902f91e7fd3039e016a6556b5', 'loadClassLoader'));
-
-        require __DIR__ . '/autoload_static.php';
-        call_user_func(\Composer\Autoload\ComposerStaticInit20fad51902f91e7fd3039e016a6556b5::getInitializer($loader));
-
-        $loader->register(true);
-
-        return $loader;
-    }
-}

+ 0 - 36
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/autoload_static.php

@@ -1,36 +0,0 @@
-<?php
-
-// autoload_static.php @generated by Composer
-
-namespace Composer\Autoload;
-
-class ComposerStaticInit20fad51902f91e7fd3039e016a6556b5
-{
-    public static $prefixLengthsPsr4 = array (
-        'F' => 
-        array (
-            'Firebase\\JWT\\' => 13,
-        ),
-    );
-
-    public static $prefixDirsPsr4 = array (
-        'Firebase\\JWT\\' => 
-        array (
-            0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
-        ),
-    );
-
-    public static $classMap = array (
-        'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
-    );
-
-    public static function getInitializer(ClassLoader $loader)
-    {
-        return \Closure::bind(function () use ($loader) {
-            $loader->prefixLengthsPsr4 = ComposerStaticInit20fad51902f91e7fd3039e016a6556b5::$prefixLengthsPsr4;
-            $loader->prefixDirsPsr4 = ComposerStaticInit20fad51902f91e7fd3039e016a6556b5::$prefixDirsPsr4;
-            $loader->classMap = ComposerStaticInit20fad51902f91e7fd3039e016a6556b5::$classMap;
-
-        }, null, ClassLoader::class);
-    }
-}

+ 0 - 75
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/installed.json

@@ -1,75 +0,0 @@
-{
-    "packages": [
-        {
-            "name": "firebase/php-jwt",
-            "version": "v7.1.0",
-            "version_normalized": "7.1.0.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/googleapis/php-jwt.git",
-                "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/googleapis/php-jwt/zipball/b374a5d1a4f1f67fadc2165cdb284645945e2fc0",
-                "reference": "b374a5d1a4f1f67fadc2165cdb284645945e2fc0",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^8.0"
-            },
-            "require-dev": {
-                "guzzlehttp/guzzle": "^7.4",
-                "phpfastcache/phpfastcache": "^9.2",
-                "phpseclib/phpseclib": "~3.0",
-                "phpspec/prophecy-phpunit": "^2.0",
-                "phpunit/phpunit": "^9.5",
-                "psr/cache": "^2.0||^3.0",
-                "psr/http-client": "^1.0",
-                "psr/http-factory": "^1.0"
-            },
-            "suggest": {
-                "ext-sodium": "Support EdDSA (Ed25519) signatures",
-                "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present",
-                "phpseclib/phpseclib": "Support PS256 (RSASSA-PSS) signatures"
-            },
-            "time": "2026-06-11T17:54:14+00:00",
-            "type": "library",
-            "installation-source": "dist",
-            "autoload": {
-                "psr-4": {
-                    "Firebase\\JWT\\": "src"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Neuman Vong",
-                    "email": "neuman+pear@twilio.com",
-                    "role": "Developer"
-                },
-                {
-                    "name": "Anant Narayanan",
-                    "email": "anant@php.net",
-                    "role": "Developer"
-                }
-            ],
-            "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
-            "homepage": "https://github.com/googleapis/php-jwt",
-            "keywords": [
-                "jwt",
-                "php"
-            ],
-            "support": {
-                "issues": "https://github.com/googleapis/php-jwt/issues",
-                "source": "https://github.com/googleapis/php-jwt/tree/v7.1.0"
-            },
-            "install-path": "../firebase/php-jwt"
-        }
-    ],
-    "dev": true,
-    "dev-package-names": []
-}

+ 0 - 32
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/installed.php

@@ -1,32 +0,0 @@
-<?php return array(
-    'root' => array(
-        'name' => '__root__',
-        'pretty_version' => 'dev-master',
-        'version' => 'dev-master',
-        'reference' => '8c8b9e395565a5064aa73019b8e46c1670911a5b',
-        'type' => 'library',
-        'install_path' => __DIR__ . '/../../',
-        'aliases' => array(),
-        'dev' => true,
-    ),
-    'versions' => array(
-        '__root__' => array(
-            'pretty_version' => 'dev-master',
-            'version' => 'dev-master',
-            'reference' => '8c8b9e395565a5064aa73019b8e46c1670911a5b',
-            'type' => 'library',
-            'install_path' => __DIR__ . '/../../',
-            'aliases' => array(),
-            'dev_requirement' => false,
-        ),
-        'firebase/php-jwt' => array(
-            'pretty_version' => 'v7.1.0',
-            'version' => '7.1.0.0',
-            'reference' => 'b374a5d1a4f1f67fadc2165cdb284645945e2fc0',
-            'type' => 'library',
-            'install_path' => __DIR__ . '/../firebase/php-jwt',
-            'aliases' => array(),
-            'dev_requirement' => false,
-        ),
-    ),
-);

+ 0 - 26
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/composer/platform_check.php

@@ -1,26 +0,0 @@
-<?php
-
-// platform_check.php @generated by Composer
-
-$issues = array();
-
-if (!(PHP_VERSION_ID >= 80000)) {
-    $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.';
-}
-
-if ($issues) {
-    if (!headers_sent()) {
-        header('HTTP/1.1 500 Internal Server Error');
-    }
-    if (!ini_get('display_errors')) {
-        if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
-            fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
-        } elseif (!headers_sent()) {
-            echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
-        }
-    }
-    trigger_error(
-        'Composer detected issues in your platform: ' . implode(' ', $issues),
-        E_USER_ERROR
-    );
-}

+ 0 - 265
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/CHANGELOG.md

@@ -1,265 +0,0 @@
-# Changelog
-
-## [7.1.0](https://github.com/googleapis/php-jwt/compare/v7.0.5...v7.1.0) (2026-06-11)
-
-
-### Features
-
-* Add support for PS256 ([#637](https://github.com/googleapis/php-jwt/issues/637)) ([aa0b447](https://github.com/googleapis/php-jwt/commit/aa0b4472c137255545b177a1840891304eac55f1))
-
-
-### Bug Fixes
-
-* Skip parsing valid unsupported curves ([#638](https://github.com/googleapis/php-jwt/issues/638)) ([8a6c2a7](https://github.com/googleapis/php-jwt/commit/8a6c2a75d7f45e781c93d618939f8a045fe69f53))
-* Update homepage URL in composer.json ([#635](https://github.com/googleapis/php-jwt/issues/635)) ([f7ae571](https://github.com/googleapis/php-jwt/commit/f7ae571efe255aed89c8f8d0f2cb7f71c5835664))
-* Validate numeric type of iat, nbf and exp claims in encode ([#634](https://github.com/googleapis/php-jwt/issues/634)) ([958e422](https://github.com/googleapis/php-jwt/commit/958e422961e874843a7fcc339e55a0101a66201d))
-
-## [7.0.5](https://github.com/firebase/php-jwt/compare/v7.0.4...v7.0.5) (2026-03-31)
-
-
-### Bug Fixes
-
-* RSA from JWK sometimes returns empty Instance ([#628](https://github.com/firebase/php-jwt/issues/628)) ([b4c78aa](https://github.com/firebase/php-jwt/commit/b4c78aa731664122198ad36c0033aa29e807397a))
-
-## [7.0.4](https://github.com/firebase/php-jwt/compare/v7.0.3...v7.0.4) (2026-03-27)
-
-
-### Bug Fixes
-
-* readme examples, add tests for all examples ([#626](https://github.com/firebase/php-jwt/issues/626)) ([510a00c](https://github.com/firebase/php-jwt/commit/510a00c0e6353bc7d68412fab67e57a13954cb46))
-* use urlsafeB64Decode everywhere ([#627](https://github.com/firebase/php-jwt/issues/627)) ([b889495](https://github.com/firebase/php-jwt/commit/b889495c83ddc3f3885ca3f0b65b41b1cb37a3b1))
-
-## [7.0.3](https://github.com/firebase/php-jwt/compare/v7.0.2...v7.0.3) (2026-02-18)
-
-
-### Miscellaneous Chores
-
-* add environment for Release Please job ([#619](https://github.com/firebase/php-jwt/issues/619)) ([300fd02](https://github.com/firebase/php-jwt/commit/300fd02c883f096c9067df652dbd23f62cb5e2a7))
-
-## [7.0.2](https://github.com/firebase/php-jwt/compare/v7.0.1...v7.0.2) (2025-12-16)
-
-
-### Bug Fixes
-
-* add key length validation for ec keys ([#615](https://github.com/firebase/php-jwt/issues/615)) ([7044f9a](https://github.com/firebase/php-jwt/commit/7044f9ae7e7d175d28cca71714feb236f1c0e252))
-
-## [7.0.0](https://github.com/firebase/php-jwt/compare/v6.11.1...v7.0.0) (2025-12-15)
-
-
-### ⚠️ ⚠️ ⚠️  Security Fixes ⚠️ ⚠️ ⚠️ 
- * add key size validation ([#613](https://github.com/firebase/php-jwt/issues/613)) ([6b80341](https://github.com/firebase/php-jwt/commit/6b80341bf57838ea2d011487917337901cd71576))
- **NOTE**: This fix will cause keys with a size below the minimally allowed size to break. 
-
-### Features
-
-* add SensitiveParameter attribute to security-critical parameters ([#603](https://github.com/firebase/php-jwt/issues/603)) ([4dbfac0](https://github.com/firebase/php-jwt/commit/4dbfac0260eeb0e9e643063c99998e3219cc539b))
-* store timestamp in `ExpiredException` ([#604](https://github.com/firebase/php-jwt/issues/604)) ([f174826](https://github.com/firebase/php-jwt/commit/f1748260d218a856b6a0c23715ac7fae1d7ca95b))
-
-
-### Bug Fixes
-
-* validate iat and nbf on payload ([#568](https://github.com/firebase/php-jwt/issues/568)) ([953b2c8](https://github.com/firebase/php-jwt/commit/953b2c88bb445b7e3bb82a5141928f13d7343afd))
-
-## [6.11.1](https://github.com/firebase/php-jwt/compare/v6.11.0...v6.11.1) (2025-04-09)
-
-
-### Bug Fixes
-
-* update error text for consistency ([#528](https://github.com/firebase/php-jwt/issues/528)) ([c11113a](https://github.com/firebase/php-jwt/commit/c11113afa13265e016a669e75494b9203b8a7775))
-
-## [6.11.0](https://github.com/firebase/php-jwt/compare/v6.10.2...v6.11.0) (2025-01-23)
-
-
-### Features
-
-* support octet typed JWK ([#587](https://github.com/firebase/php-jwt/issues/587)) ([7cb8a26](https://github.com/firebase/php-jwt/commit/7cb8a265fa81edf2fa6ef8098f5bc5ae573c33ad))
-
-
-### Bug Fixes
-
-* refactor constructor Key to use PHP 8.0 syntax ([#577](https://github.com/firebase/php-jwt/issues/577)) ([29fa2ce](https://github.com/firebase/php-jwt/commit/29fa2ce9e0582cd397711eec1e80c05ce20fabca))
-
-## [6.10.2](https://github.com/firebase/php-jwt/compare/v6.10.1...v6.10.2) (2024-11-24)
-
-
-### Bug Fixes
-
-* Mitigate PHP8.4 deprecation warnings ([#570](https://github.com/firebase/php-jwt/issues/570)) ([76808fa](https://github.com/firebase/php-jwt/commit/76808fa227f3811aa5cdb3bf81233714b799a5b5))
-* support php 8.4 ([#583](https://github.com/firebase/php-jwt/issues/583)) ([e3d68b0](https://github.com/firebase/php-jwt/commit/e3d68b044421339443c74199edd020e03fb1887e))
-
-## [6.10.1](https://github.com/firebase/php-jwt/compare/v6.10.0...v6.10.1) (2024-05-18)
-
-
-### Bug Fixes
-
-* ensure ratelimit expiry is set every time ([#556](https://github.com/firebase/php-jwt/issues/556)) ([09cb208](https://github.com/firebase/php-jwt/commit/09cb2081c2c3bc0f61e2f2a5fbea5741f7498648))
-* ratelimit cache expiration ([#550](https://github.com/firebase/php-jwt/issues/550)) ([dda7250](https://github.com/firebase/php-jwt/commit/dda725033585ece30ff8cae8937320d7e9f18bae))
-
-## [6.10.0](https://github.com/firebase/php-jwt/compare/v6.9.0...v6.10.0) (2023-11-28)
-
-
-### Features
-
-* allow typ header override ([#546](https://github.com/firebase/php-jwt/issues/546)) ([79cb30b](https://github.com/firebase/php-jwt/commit/79cb30b729a22931b2fbd6b53f20629a83031ba9))
-
-## [6.9.0](https://github.com/firebase/php-jwt/compare/v6.8.1...v6.9.0) (2023-10-04)
-
-
-### Features
-
-* add payload to jwt exception ([#521](https://github.com/firebase/php-jwt/issues/521)) ([175edf9](https://github.com/firebase/php-jwt/commit/175edf958bb61922ec135b2333acf5622f2238a2))
-
-## [6.8.1](https://github.com/firebase/php-jwt/compare/v6.8.0...v6.8.1) (2023-07-14)
-
-
-### Bug Fixes
-
-* accept float claims but round down to ignore them ([#492](https://github.com/firebase/php-jwt/issues/492)) ([3936842](https://github.com/firebase/php-jwt/commit/39368423beeaacb3002afa7dcb75baebf204fe7e))
-* different BeforeValidException messages for nbf and iat ([#526](https://github.com/firebase/php-jwt/issues/526)) ([0a53cf2](https://github.com/firebase/php-jwt/commit/0a53cf2986e45c2bcbf1a269f313ebf56a154ee4))
-
-## [6.8.0](https://github.com/firebase/php-jwt/compare/v6.7.0...v6.8.0) (2023-06-14)
-
-
-### Features
-
-* add support for P-384 curve ([#515](https://github.com/firebase/php-jwt/issues/515)) ([5de4323](https://github.com/firebase/php-jwt/commit/5de4323f4baf4d70bca8663bd87682a69c656c3d))
-
-
-### Bug Fixes
-
-* handle invalid http responses ([#508](https://github.com/firebase/php-jwt/issues/508)) ([91c39c7](https://github.com/firebase/php-jwt/commit/91c39c72b22fc3e1191e574089552c1f2041c718))
-
-## [6.7.0](https://github.com/firebase/php-jwt/compare/v6.6.0...v6.7.0) (2023-06-14)
-
-
-### Features
-
-* add ed25519 support to JWK (public keys) ([#452](https://github.com/firebase/php-jwt/issues/452)) ([e53979a](https://github.com/firebase/php-jwt/commit/e53979abae927de916a75b9d239cfda8ce32be2a))
-
-## [6.6.0](https://github.com/firebase/php-jwt/compare/v6.5.0...v6.6.0) (2023-06-13)
-
-
-### Features
-
-* allow get headers when decoding token ([#442](https://github.com/firebase/php-jwt/issues/442)) ([fb85f47](https://github.com/firebase/php-jwt/commit/fb85f47cfaeffdd94faf8defdf07164abcdad6c3))
-
-
-### Bug Fixes
-
-* only check iat if nbf is not used ([#493](https://github.com/firebase/php-jwt/issues/493)) ([398ccd2](https://github.com/firebase/php-jwt/commit/398ccd25ea12fa84b9e4f1085d5ff448c21ec797))
-
-## [6.5.0](https://github.com/firebase/php-jwt/compare/v6.4.0...v6.5.0) (2023-05-12)
-
-
-### Bug Fixes
-
-* allow KID of '0' ([#505](https://github.com/firebase/php-jwt/issues/505)) ([9dc46a9](https://github.com/firebase/php-jwt/commit/9dc46a9c3e5801294249cfd2554c5363c9f9326a))
-
-
-### Miscellaneous Chores
-
-* drop support for PHP 7.3 ([#495](https://github.com/firebase/php-jwt/issues/495))
-
-## [6.4.0](https://github.com/firebase/php-jwt/compare/v6.3.2...v6.4.0) (2023-02-08)
-
-
-### Features
-
-* add support for W3C ES256K ([#462](https://github.com/firebase/php-jwt/issues/462)) ([213924f](https://github.com/firebase/php-jwt/commit/213924f51936291fbbca99158b11bd4ae56c2c95))
-* improve caching by only decoding jwks when necessary ([#486](https://github.com/firebase/php-jwt/issues/486)) ([78d3ed1](https://github.com/firebase/php-jwt/commit/78d3ed1073553f7d0bbffa6c2010009a0d483d5c))
-
-## [6.3.2](https://github.com/firebase/php-jwt/compare/v6.3.1...v6.3.2) (2022-11-01)
-
-
-### Bug Fixes
-
-* check kid before using as array index ([bad1b04](https://github.com/firebase/php-jwt/commit/bad1b040d0c736bbf86814c6b5ae614f517cf7bd))
-
-## [6.3.1](https://github.com/firebase/php-jwt/compare/v6.3.0...v6.3.1) (2022-11-01)
-
-
-### Bug Fixes
-
-* casing of GET for PSR compat ([#451](https://github.com/firebase/php-jwt/issues/451)) ([60b52b7](https://github.com/firebase/php-jwt/commit/60b52b71978790eafcf3b95cfbd83db0439e8d22))
-* string interpolation format for php 8.2 ([#446](https://github.com/firebase/php-jwt/issues/446)) ([2e07d8a](https://github.com/firebase/php-jwt/commit/2e07d8a1524d12b69b110ad649f17461d068b8f2))
-
-## 6.3.0 / 2022-07-15
-
- - Added ES256 support to JWK parsing ([#399](https://github.com/firebase/php-jwt/pull/399))
- - Fixed potential caching error in `CachedKeySet` by caching jwks as strings ([#435](https://github.com/firebase/php-jwt/pull/435))
-
-## 6.2.0 / 2022-05-14
-
- - Added `CachedKeySet` ([#397](https://github.com/firebase/php-jwt/pull/397))
- - Added `$defaultAlg` parameter to `JWT::parseKey` and `JWT::parseKeySet` ([#426](https://github.com/firebase/php-jwt/pull/426)).
-
-## 6.1.0 / 2022-03-23
-
- - Drop support for PHP 5.3, 5.4, 5.5, 5.6, and 7.0
- - Add parameter typing and return types where possible
-
-## 6.0.0 / 2022-01-24
-
- - **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v6.0.0) for more information.
- - New Key object to prevent key/algorithm type confusion (#365)
- - Add JWK support (#273)
- - Add ES256 support (#256)
- - Add ES384 support (#324)
- - Add Ed25519 support (#343)
-
-## 5.0.0 / 2017-06-26
-- Support RS384 and RS512.
-  See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)!
-- Add an example for RS256 openssl.
-  See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)!
-- Detect invalid Base64 encoding in signature.
-  See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)!
-- Update `JWT::verify` to handle OpenSSL errors.
-  See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)!
-- Add `array` type hinting to `decode` method
-  See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)!
-- Add all JSON error types.
-  See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)!
-- Bugfix 'kid' not in given key list.
-  See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)!
-- Miscellaneous cleanup, documentation and test fixes.
-  See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115),
-  [#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and
-  [#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman),
-  [@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)!
-
-## 4.0.0 / 2016-07-17
-- Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)!
-- Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)!
-- Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)!
-- Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)!
-
-## 3.0.0 / 2015-07-22
-- Minimum PHP version updated from `5.2.0` to `5.3.0`.
-- Add `\Firebase\JWT` namespace. See
-[#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to
-[@Dashron](https://github.com/Dashron)!
-- Require a non-empty key to decode and verify a JWT. See
-[#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to
-[@sjones608](https://github.com/sjones608)!
-- Cleaner documentation blocks in the code. See
-[#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to
-[@johanderuijter](https://github.com/johanderuijter)!
-
-## 2.2.0 / 2015-06-22
-- Add support for adding custom, optional JWT headers to `JWT::encode()`. See
-[#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to
-[@mcocaro](https://github.com/mcocaro)!
-
-## 2.1.0 / 2015-05-20
-- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew
-between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)!
-- Add support for passing an object implementing the `ArrayAccess` interface for
-`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)!
-
-## 2.0.0 / 2015-04-01
-- **Note**: It is strongly recommended that you update to > v2.0.0 to address
-  known security vulnerabilities in prior versions when both symmetric and
-  asymmetric keys are used together.
-- Update signature for `JWT::decode(...)` to require an array of supported
-  algorithms to use when verifying token signatures.

+ 0 - 30
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/LICENSE

@@ -1,30 +0,0 @@
-Copyright (c) 2011, Neuman Vong
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
-
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials provided
-      with the distribution.
-
-    * Neither the name of the copyright holder nor the names of other
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 457
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/README.md

@@ -1,457 +0,0 @@
-![Build Status](https://github.com/firebase/php-jwt/actions/workflows/tests.yml/badge.svg)
-[![Latest Stable Version](https://poser.pugx.org/firebase/php-jwt/v/stable)](https://packagist.org/packages/firebase/php-jwt)
-[![Total Downloads](https://poser.pugx.org/firebase/php-jwt/downloads)](https://packagist.org/packages/firebase/php-jwt)
-[![License](https://poser.pugx.org/firebase/php-jwt/license)](https://packagist.org/packages/firebase/php-jwt)
-
-PHP-JWT
-=======
-A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to [RFC 7519](https://tools.ietf.org/html/rfc7519).
-
-Installation
-------------
-
-Use composer to manage your dependencies and download PHP-JWT:
-
-```bash
-composer require firebase/php-jwt
-```
-
-Optionally, install the `paragonie/sodium_compat` package from composer if your
-php env does not have libsodium installed:
-
-```bash
-composer require paragonie/sodium_compat
-```
-
-## Example
-
-```php
-use Firebase\JWT\JWT;
-use Firebase\JWT\Key;
-
-$key = 'example_key_of_sufficient_length';
-$payload = [
-    'iss' => 'example.org',
-    'aud' => 'example.com',
-    'iat' => 1356999524,
-    'nbf' => 1357000000
-];
-
-/**
- * IMPORTANT:
- * You must specify supported algorithms for your application. See
- * https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40
- * for a list of spec-compliant algorithms.
- */
-$jwt = JWT::encode($payload, $key, 'HS256');
-$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
-print_r($decoded);
-
-// Pass a stdClass in as the third parameter to get the decoded header values
-$headers = new stdClass();
-$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers);
-print_r($headers);
-
-/*
- NOTE: This will now be an object instead of an associative array. To get
- an associative array, you will need to cast it as such:
-*/
-
-$decoded_array = (array) $decoded;
-
-/**
- * You can add a leeway to account for when there is a clock skew times between
- * the signing and verifying servers. It is recommended that this leeway should
- * not be bigger than a few minutes.
- *
- * Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef
- */
-JWT::$leeway = 60; // $leeway in seconds
-$decoded = JWT::decode($jwt, new Key($key, 'HS256'));
-```
-
-## Example encode/decode headers
-
-Decoding the JWT headers without verifying the JWT first is NOT recommended, and is not supported by
-this library. This is because without verifying the JWT, the header values could have been tampered with.
-Any value pulled from an unverified header should be treated as if it could be any string sent in from an
-attacker.  If this is something you still want to do in your application for whatever reason, it's possible to
-decode the header values manually simply by calling `json_decode` and `base64_decode` on the JWT
-header part:
-```php
-use Firebase\JWT\JWT;
-
-$key = 'example_key_of_sufficient_length';
-$payload = [
-    'iss' => 'example.org',
-    'aud' => 'example.com',
-    'iat' => 1356999524,
-    'nbf' => 1357000000
-];
-
-$headers = [
-    'x-forwarded-for' => 'www.google.com'
-];
-
-// Encode headers in the JWT string
-$jwt = JWT::encode($payload, $key, 'HS256', null, $headers);
-
-// Decode headers from the JWT string WITHOUT validation
-// **IMPORTANT**: This operation is vulnerable to attacks, as the JWT has not yet been verified.
-// These headers could be any value sent by an attacker.
-list($headersB64, $payloadB64, $sig) = explode('.', $jwt);
-$decoded = json_decode(base64_decode($headersB64), true);
-
-print_r($decoded);
-```
-
-## Example with RS256 (openssl)
-
-```php
-use Firebase\JWT\JWT;
-use Firebase\JWT\Key;
-
-$privateKey = <<<EOD
------BEGIN RSA PRIVATE KEY-----
-MIIEowIBAAKCAQEAuzWHNM5f+amCjQztc5QTfJfzCC5J4nuW+L/aOxZ4f8J3Frew
-M2c/dufrnmedsApb0By7WhaHlcqCh/ScAPyJhzkPYLae7bTVro3hok0zDITR8F6S
-JGL42JAEUk+ILkPI+DONM0+3vzk6Kvfe548tu4czCuqU8BGVOlnp6IqBHhAswNMM
-78pos/2z0CjPM4tbeXqSTTbNkXRboxjU29vSopcT51koWOgiTf3C7nJUoMWZHZI5
-HqnIhPAG9yv8HAgNk6CMk2CadVHDo4IxjxTzTTqo1SCSH2pooJl9O8at6kkRYsrZ
-WwsKlOFE2LUce7ObnXsYihStBUDoeBQlGG/BwQIDAQABAoIBAFtGaOqNKGwggn9k
-6yzr6GhZ6Wt2rh1Xpq8XUz514UBhPxD7dFRLpbzCrLVpzY80LbmVGJ9+1pJozyWc
-VKeCeUdNwbqkr240Oe7GTFmGjDoxU+5/HX/SJYPpC8JZ9oqgEA87iz+WQX9hVoP2
-oF6EB4ckDvXmk8FMwVZW2l2/kd5mrEVbDaXKxhvUDf52iVD+sGIlTif7mBgR99/b
-c3qiCnxCMmfYUnT2eh7Vv2LhCR/G9S6C3R4lA71rEyiU3KgsGfg0d82/XWXbegJW
-h3QbWNtQLxTuIvLq5aAryV3PfaHlPgdgK0ft6ocU2de2FagFka3nfVEyC7IUsNTK
-bq6nhAECgYEA7d/0DPOIaItl/8BWKyCuAHMss47j0wlGbBSHdJIiS55akMvnAG0M
-39y22Qqfzh1at9kBFeYeFIIU82ZLF3xOcE3z6pJZ4Dyvx4BYdXH77odo9uVK9s1l
-3T3BlMcqd1hvZLMS7dviyH79jZo4CXSHiKzc7pQ2YfK5eKxKqONeXuECgYEAyXlG
-vonaus/YTb1IBei9HwaccnQ/1HRn6MvfDjb7JJDIBhNClGPt6xRlzBbSZ73c2QEC
-6Fu9h36K/HZ2qcLd2bXiNyhIV7b6tVKk+0Psoj0dL9EbhsD1OsmE1nTPyAc9XZbb
-OPYxy+dpBCUA8/1U9+uiFoCa7mIbWcSQ+39gHuECgYAz82pQfct30aH4JiBrkNqP
-nJfRq05UY70uk5k1u0ikLTRoVS/hJu/d4E1Kv4hBMqYCavFSwAwnvHUo51lVCr/y
-xQOVYlsgnwBg2MX4+GjmIkqpSVCC8D7j/73MaWb746OIYZervQ8dbKahi2HbpsiG
-8AHcVSA/agxZr38qvWV54QKBgCD5TlDE8x18AuTGQ9FjxAAd7uD0kbXNz2vUYg9L
-hFL5tyL3aAAtUrUUw4xhd9IuysRhW/53dU+FsG2dXdJu6CxHjlyEpUJl2iZu/j15
-YnMzGWHIEX8+eWRDsw/+Ujtko/B7TinGcWPz3cYl4EAOiCeDUyXnqnO1btCEUU44
-DJ1BAoGBAJuPD27ErTSVtId90+M4zFPNibFP50KprVdc8CR37BE7r8vuGgNYXmnI
-RLnGP9p3pVgFCktORuYS2J/6t84I3+A17nEoB4xvhTLeAinAW/uTQOUmNicOP4Ek
-2MsLL2kHgL8bLTmvXV4FX+PXphrDKg1XxzOYn0otuoqdAQrkK4og
------END RSA PRIVATE KEY-----
-EOD;
-
-$publicKey = <<<EOD
------BEGIN PUBLIC KEY-----
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzWHNM5f+amCjQztc5QT
-fJfzCC5J4nuW+L/aOxZ4f8J3FrewM2c/dufrnmedsApb0By7WhaHlcqCh/ScAPyJ
-hzkPYLae7bTVro3hok0zDITR8F6SJGL42JAEUk+ILkPI+DONM0+3vzk6Kvfe548t
-u4czCuqU8BGVOlnp6IqBHhAswNMM78pos/2z0CjPM4tbeXqSTTbNkXRboxjU29vS
-opcT51koWOgiTf3C7nJUoMWZHZI5HqnIhPAG9yv8HAgNk6CMk2CadVHDo4IxjxTz
-TTqo1SCSH2pooJl9O8at6kkRYsrZWwsKlOFE2LUce7ObnXsYihStBUDoeBQlGG/B
-wQIDAQAB
------END PUBLIC KEY-----
-EOD;
-
-$payload = [
-    'iss' => 'example.org',
-    'aud' => 'example.com',
-    'iat' => 1356999524,
-    'nbf' => 1357000000
-];
-
-$jwt = JWT::encode($payload, $privateKey, 'RS256');
-echo "Encode:\n" . print_r($jwt, true) . "\n";
-
-$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
-
-/*
- NOTE: This will now be an object instead of an associative array. To get
- an associative array, you will need to cast it as such:
-*/
-
-$decoded_array = (array) $decoded;
-echo "Decode:\n" . print_r($decoded_array, true) . "\n";
-```
-
-## Example with a passphrase
-
-```php
-use Firebase\JWT\JWT;
-use Firebase\JWT\Key;
-
-// Your passphrase
-$passphrase = '[YOUR_PASSPHRASE]';
-
-// Your private key file with passphrase
-// Can be generated with "ssh-keygen -t rsa -m pem"
-$privateKeyFile = '/path/to/key-with-passphrase.pem';
-
-/** @var OpenSSLAsymmetricKey $privateKey */
-$privateKey = openssl_pkey_get_private(
-    file_get_contents($privateKeyFile),
-    $passphrase
-);
-
-$payload = [
-    'iss' => 'example.org',
-    'aud' => 'example.com',
-    'iat' => 1356999524,
-    'nbf' => 1357000000
-];
-
-$jwt = JWT::encode($payload, $privateKey, 'RS256');
-echo "Encode:\n" . print_r($jwt, true) . "\n";
-
-// Get public key from the private key, or pull from from a file.
-$publicKey = openssl_pkey_get_details($privateKey)['key'];
-
-$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256'));
-echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
-```
-
-## Example with EdDSA (libsodium and Ed25519 signature)
-
-```php
-use Firebase\JWT\JWT;
-use Firebase\JWT\Key;
-
-// Public and private keys are expected to be Base64 encoded. The last
-// non-empty line is used so that keys can be generated with
-// sodium_crypto_sign_keypair(). The secret keys generated by other tools may
-// need to be adjusted to match the input expected by libsodium.
-
-$keyPair = sodium_crypto_sign_keypair();
-
-$privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair));
-
-$publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair));
-
-$payload = [
-    'iss' => 'example.org',
-    'aud' => 'example.com',
-    'iat' => 1356999524,
-    'nbf' => 1357000000
-];
-
-$jwt = JWT::encode($payload, $privateKey, 'EdDSA');
-echo "Encode:\n" . print_r($jwt, true) . "\n";
-
-$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA'));
-echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
-```
-
-## Example with multiple keys
-
-```php
-use Firebase\JWT\JWT;
-use Firebase\JWT\Key;
-
-// Example RSA keys from previous example
-// $privateRsKey = '...';
-// $publicRsKey = '...';
-
-// Example EdDSA keys from previous example
-// $privateEcKey = '...';
-// $publicEcKey = '...';
-
-$payload = [
-    'iss' => 'example.org',
-    'aud' => 'example.com',
-    'iat' => 1356999524,
-    'nbf' => 1357000000
-];
-
-$jwt1 = JWT::encode($payload, $privateRsKey, 'RS256', 'kid1');
-$jwt2 = JWT::encode($payload, $privateEcKey, 'EdDSA', 'kid2');
-echo "Encode 1:\n" . print_r($jwt1, true) . "\n";
-echo "Encode 2:\n" . print_r($jwt2, true) . "\n";
-
-$keys = [
-    'kid1' => new Key($publicRsKey, 'RS256'),
-    'kid2' => new Key($publicEcKey, 'EdDSA'),
-];
-
-$decoded1 = JWT::decode($jwt1, $keys);
-$decoded2 = JWT::decode($jwt2, $keys);
-
-echo "Decode 1:\n" . print_r((array) $decoded1, true) . "\n";
-echo "Decode 2:\n" . print_r((array) $decoded2, true) . "\n";
-```
-
-## Example with PS256
-
-### Note
-PHP's OpenSSL extension does not support RSASSA-PSS signatures (PS256) by default, so we provide support via a soft dependency on the [phpseclib/phpseclib](https://github.com/phpseclib/phpseclib) library. It is necessary to install this library in your project if you plan to use PS256.
-```bash
-composer install phpseclib/phpseclib:^3.0
-```
-
-```php
-use Firebase\JWT\JWT;
-use Firebase\JWT\Key;
-
-$privateRsKey = '-----BEGIN RSA PRIVATE KEY----- ...';
-$publicKey = '-----BEGIN PUBLIC KEY----- ...';
-
-$payload = [
-    'iss' => 'example.org',
-    'aud' => 'example.com',
-    'iat' => 1356999524,
-    'nbf' => 1357000000
-];
-
-/**
-* PS256 support requires phpseclib/phpseclib
-*/
-$jwt = JWT::encode($payload, $privateRsKey, 'PS256', 'keyid');
-echo "Encode:\n" . print_r($jwt, true) . "\n";
-
-$decoded = JWT::decode($jwt, new Key($publicKey, 'PS256'));
-echo "Decode:\n" . print_r((array) $decoded, true) . "\n";
-```
-
-## Using JWKs
-
-```php
-use Firebase\JWT\JWK;
-use Firebase\JWT\JWT;
-
-// Set of keys. The "keys" key is required. For example, the JSON response to
-// this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk
-$jwks = ['keys' => []];
-
-// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key
-// objects. Pass this as the second parameter to JWT::decode.
-$decoded = JWT::decode($jwt, JWK::parseKeySet($jwks));
-print_r($decoded);
-```
-
-## Using Cached Key Sets
-
-The `CachedKeySet` class can be used to fetch and cache JWKS (JSON Web Key Sets) from a public URI.
-This has the following advantages:
-
-1. The results are cached for performance.
-2. If an unrecognized key is requested, the cache is refreshed, to accomodate for key rotation.
-3. If rate limiting is enabled, the JWKS URI will not make more than 10 requests a second.
-
-```php
-use Firebase\JWT\CachedKeySet;
-use Firebase\JWT\JWT;
-
-// The URI for the JWKS you wish to cache the results from
-$jwksUri = 'https://www.gstatic.com/iap/verify/public_key-jwk';
-
-// Create an HTTP client (can be any PSR-7 compatible HTTP client)
-$httpClient = new GuzzleHttp\Client();
-
-// Create an HTTP request factory (can be any PSR-17 compatible HTTP request factory)
-$httpFactory = new GuzzleHttp\Psr7\HttpFactory();
-
-// Create a cache item pool (can be any PSR-6 compatible cache item pool)
-$cacheItemPool = Phpfastcache\CacheManager::getInstance('files');
-
-$keySet = new CachedKeySet(
-    $jwksUri,
-    $httpClient,
-    $httpFactory,
-    $cacheItemPool,
-    null, // $expiresAfter int seconds to set the JWKS to expire
-    true  // $rateLimit    true to enable rate limit of 10 RPS on lookup of invalid keys
-);
-
-$jwt = 'eyJhbGci...'; // Some JWT signed by a key from the $jwkUri above
-$decoded = JWT::decode($jwt, $keySet);
-```
-
-Miscellaneous
--------------
-
-#### Exception Handling
-
-When a call to `JWT::decode` is invalid, it will throw one of the following exceptions:
-
-```php
-use Firebase\JWT\JWT;
-use Firebase\JWT\SignatureInvalidException;
-use Firebase\JWT\BeforeValidException;
-use Firebase\JWT\ExpiredException;
-use DomainException;
-use InvalidArgumentException;
-use UnexpectedValueException;
-
-try {
-    $decoded = JWT::decode($jwt, $keys);
-} catch (InvalidArgumentException $e) {
-    // provided key/key-array is empty or malformed.
-} catch (DomainException $e) {
-    // provided algorithm is unsupported OR
-    // provided key is invalid OR
-    // unknown error thrown in openSSL or libsodium OR
-    // libsodium is required but not available.
-} catch (SignatureInvalidException $e) {
-    // provided JWT signature verification failed.
-} catch (BeforeValidException $e) {
-    // provided JWT is trying to be used before "nbf" claim OR
-    // provided JWT is trying to be used before "iat" claim.
-} catch (ExpiredException $e) {
-    // provided JWT is trying to be used after "exp" claim.
-} catch (UnexpectedValueException $e) {
-    // provided JWT is malformed OR
-    // provided JWT is missing an algorithm / using an unsupported algorithm OR
-    // provided JWT algorithm does not match provided key OR
-    // provided key ID in key/key-array is empty or invalid.
-}
-```
-
-All exceptions in the `Firebase\JWT` namespace extend `UnexpectedValueException`, and can be simplified
-like this:
-
-```php
-use Firebase\JWT\JWT;
-use UnexpectedValueException;
-try {
-    $decoded = JWT::decode($jwt, $keys);
-} catch (LogicException $e) {
-    // errors having to do with environmental setup or malformed JWT Keys
-} catch (UnexpectedValueException $e) {
-    // errors having to do with JWT signature and claims
-}
-```
-
-#### Casting to array
-
-The return value of `JWT::decode` is the generic PHP object `stdClass`. If you'd like to handle with arrays
-instead, you can do the following:
-
-```php
-// return type is stdClass
-$decoded = JWT::decode($jwt, $keys);
-
-// cast to array
-$decoded = json_decode(json_encode($decoded), true);
-```
-
-Tests
------
-Run the tests using phpunit:
-
-```bash
-$ composer update
-$ vendor/bin/phpunit -c phpunit.xml.dist
-PHPUnit 3.7.10 by Sebastian Bergmann.
-.....
-Time: 0 seconds, Memory: 2.50Mb
-OK (5 tests, 5 assertions)
-```
-
-New Lines in private keys
------
-
-If your private key contains `\n` characters, be sure to wrap it in double quotes `""`
-and not single quotes `''` in order to properly interpret the escaped characters.
-
-License
--------
-[3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause).

+ 0 - 45
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/composer.json

@@ -1,45 +0,0 @@
-{
-    "name": "firebase/php-jwt",
-    "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
-    "homepage": "https://github.com/googleapis/php-jwt",
-    "keywords": [
-        "php",
-        "jwt"
-    ],
-    "authors": [
-        {
-            "name": "Neuman Vong",
-            "email": "neuman+pear@twilio.com",
-            "role": "Developer"
-        },
-        {
-            "name": "Anant Narayanan",
-            "email": "anant@php.net",
-            "role": "Developer"
-        }
-    ],
-    "license": "BSD-3-Clause",
-    "require": {
-        "php": "^8.0"
-    },
-    "suggest": {
-        "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present",
-        "ext-sodium": "Support EdDSA (Ed25519) signatures",
-        "phpseclib/phpseclib": "Support PS256 (RSASSA-PSS) signatures"
-    },
-    "autoload": {
-        "psr-4": {
-            "Firebase\\JWT\\": "src"
-        }
-    },
-    "require-dev": {
-        "guzzlehttp/guzzle": "^7.4",
-        "phpspec/prophecy-phpunit": "^2.0",
-        "phpunit/phpunit": "^9.5",
-        "psr/cache": "^2.0||^3.0",
-        "psr/http-client": "^1.0",
-        "psr/http-factory": "^1.0",
-        "phpfastcache/phpfastcache": "^9.2",
-        "phpseclib/phpseclib": "~3.0"
-    }
-}

+ 0 - 18
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/BeforeValidException.php

@@ -1,18 +0,0 @@
-<?php
-
-namespace Firebase\JWT;
-
-class BeforeValidException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface
-{
-    private object $payload;
-
-    public function setPayload(object $payload): void
-    {
-        $this->payload = $payload;
-    }
-
-    public function getPayload(): object
-    {
-        return $this->payload;
-    }
-}

+ 0 - 275
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/CachedKeySet.php

@@ -1,275 +0,0 @@
-<?php
-
-namespace Firebase\JWT;
-
-use ArrayAccess;
-use InvalidArgumentException;
-use LogicException;
-use OutOfBoundsException;
-use Psr\Cache\CacheItemInterface;
-use Psr\Cache\CacheItemPoolInterface;
-use Psr\Http\Client\ClientInterface;
-use Psr\Http\Message\RequestFactoryInterface;
-use RuntimeException;
-use UnexpectedValueException;
-
-/**
- * @implements ArrayAccess<string, Key>
- */
-class CachedKeySet implements ArrayAccess
-{
-    /**
-     * @var string
-     */
-    private $jwksUri;
-    /**
-     * @var ClientInterface
-     */
-    private $httpClient;
-    /**
-     * @var RequestFactoryInterface
-     */
-    private $httpFactory;
-    /**
-     * @var CacheItemPoolInterface
-     */
-    private $cache;
-    /**
-     * @var ?int
-     */
-    private $expiresAfter;
-    /**
-     * @var ?CacheItemInterface
-     */
-    private $cacheItem;
-    /**
-     * @var array<string, array<mixed>>
-     */
-    private $keySet;
-    /**
-     * @var string
-     */
-    private $cacheKey;
-    /**
-     * @var string
-     */
-    private $cacheKeyPrefix = 'jwks';
-    /**
-     * @var int
-     */
-    private $maxKeyLength = 64;
-    /**
-     * @var bool
-     */
-    private $rateLimit;
-    /**
-     * @var string
-     */
-    private $rateLimitCacheKey;
-    /**
-     * @var int
-     */
-    private $maxCallsPerMinute = 10;
-    /**
-     * @var string|null
-     */
-    private $defaultAlg;
-
-    public function __construct(
-        string $jwksUri,
-        ClientInterface $httpClient,
-        RequestFactoryInterface $httpFactory,
-        CacheItemPoolInterface $cache,
-        ?int $expiresAfter = null,
-        bool $rateLimit = false,
-        ?string $defaultAlg = null
-    ) {
-        $this->jwksUri = $jwksUri;
-        $this->httpClient = $httpClient;
-        $this->httpFactory = $httpFactory;
-        $this->cache = $cache;
-        $this->expiresAfter = $expiresAfter;
-        $this->rateLimit = $rateLimit;
-        $this->defaultAlg = $defaultAlg;
-        $this->setCacheKeys();
-    }
-
-    /**
-     * @param string $keyId
-     * @return Key
-     */
-    public function offsetGet($keyId): Key
-    {
-        if (!$this->keyIdExists($keyId)) {
-            throw new OutOfBoundsException('Key ID not found');
-        }
-        return JWK::parseKey($this->keySet[$keyId], $this->defaultAlg);
-    }
-
-    /**
-     * @param string $keyId
-     * @return bool
-     */
-    public function offsetExists($keyId): bool
-    {
-        return $this->keyIdExists($keyId);
-    }
-
-    /**
-     * @param string $offset
-     * @param Key $value
-     */
-    public function offsetSet($offset, $value): void
-    {
-        throw new LogicException('Method not implemented');
-    }
-
-    /**
-     * @param string $offset
-     */
-    public function offsetUnset($offset): void
-    {
-        throw new LogicException('Method not implemented');
-    }
-
-    /**
-     * @return array<mixed>
-     */
-    private function formatJwksForCache(string $jwks): array
-    {
-        $jwks = json_decode($jwks, true);
-
-        if (!isset($jwks['keys'])) {
-            throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
-        }
-
-        if (empty($jwks['keys'])) {
-            throw new InvalidArgumentException('JWK Set did not contain any keys');
-        }
-
-        $keys = [];
-        foreach ($jwks['keys'] as $k => $v) {
-            $kid = isset($v['kid']) ? $v['kid'] : $k;
-            $keys[(string) $kid] = $v;
-        }
-
-        return $keys;
-    }
-
-    private function keyIdExists(string $keyId): bool
-    {
-        if (null === $this->keySet) {
-            $item = $this->getCacheItem();
-            // Try to load keys from cache
-            if ($item->isHit()) {
-                // item found! retrieve it
-                $this->keySet = $item->get();
-                // If the cached item is a string, the JWKS response was cached (previous behavior).
-                // Parse this into expected format array<kid, jwk> instead.
-                if (\is_string($this->keySet)) {
-                    $this->keySet = $this->formatJwksForCache($this->keySet);
-                }
-            }
-        }
-
-        if (!isset($this->keySet[$keyId])) {
-            if ($this->rateLimitExceeded()) {
-                return false;
-            }
-            $request = $this->httpFactory->createRequest('GET', $this->jwksUri);
-            $jwksResponse = $this->httpClient->sendRequest($request);
-            if ($jwksResponse->getStatusCode() !== 200) {
-                throw new UnexpectedValueException(
-                    \sprintf(
-                        'HTTP Error: %d %s for URI "%s"',
-                        $jwksResponse->getStatusCode(),
-                        $jwksResponse->getReasonPhrase(),
-                        $this->jwksUri,
-                    ),
-                    $jwksResponse->getStatusCode()
-                );
-            }
-            $this->keySet = $this->formatJwksForCache((string) $jwksResponse->getBody());
-
-            if (!isset($this->keySet[$keyId])) {
-                return false;
-            }
-
-            $item = $this->getCacheItem();
-            $item->set($this->keySet);
-            if ($this->expiresAfter) {
-                $item->expiresAfter($this->expiresAfter);
-            }
-            $this->cache->save($item);
-        }
-
-        return true;
-    }
-
-    private function rateLimitExceeded(): bool
-    {
-        if (!$this->rateLimit) {
-            return false;
-        }
-
-        $cacheItem = $this->cache->getItem($this->rateLimitCacheKey);
-
-        $cacheItemData = [];
-        if ($cacheItem->isHit() && \is_array($data = $cacheItem->get())) {
-            $cacheItemData = $data;
-        }
-
-        $callsPerMinute = $cacheItemData['callsPerMinute'] ?? 0;
-        $expiry = $cacheItemData['expiry'] ?? new \DateTime('+60 seconds', new \DateTimeZone('UTC'));
-
-        if (++$callsPerMinute > $this->maxCallsPerMinute) {
-            return true;
-        }
-
-        $cacheItem->set(['expiry' => $expiry, 'callsPerMinute' => $callsPerMinute]);
-        $cacheItem->expiresAt($expiry);
-        $this->cache->save($cacheItem);
-        return false;
-    }
-
-    private function getCacheItem(): CacheItemInterface
-    {
-        if (\is_null($this->cacheItem)) {
-            $this->cacheItem = $this->cache->getItem($this->cacheKey);
-        }
-
-        return $this->cacheItem;
-    }
-
-    private function setCacheKeys(): void
-    {
-        if (empty($this->jwksUri)) {
-            throw new RuntimeException('JWKS URI is empty');
-        }
-
-        // ensure we do not have illegal characters
-        $key = preg_replace('|[^a-zA-Z0-9_\.!]|', '', $this->jwksUri);
-
-        // add prefix
-        $key = $this->cacheKeyPrefix . $key;
-
-        // Hash keys if they exceed $maxKeyLength of 64
-        if (\strlen($key) > $this->maxKeyLength) {
-            $key = substr(hash('sha256', $key), 0, $this->maxKeyLength);
-        }
-
-        $this->cacheKey = $key;
-
-        if ($this->rateLimit) {
-            // add prefix
-            $rateLimitKey = $this->cacheKeyPrefix . 'ratelimit' . $key;
-
-            // Hash keys if they exceed $maxKeyLength of 64
-            if (\strlen($rateLimitKey) > $this->maxKeyLength) {
-                $rateLimitKey = substr(hash('sha256', $rateLimitKey), 0, $this->maxKeyLength);
-            }
-
-            $this->rateLimitCacheKey = $rateLimitKey;
-        }
-    }
-}

+ 0 - 30
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/ExpiredException.php

@@ -1,30 +0,0 @@
-<?php
-
-namespace Firebase\JWT;
-
-class ExpiredException extends \UnexpectedValueException implements JWTExceptionWithPayloadInterface
-{
-    private object $payload;
-
-    private ?int $timestamp = null;
-
-    public function setPayload(object $payload): void
-    {
-        $this->payload = $payload;
-    }
-
-    public function getPayload(): object
-    {
-        return $this->payload;
-    }
-
-    public function setTimestamp(int $timestamp): void
-    {
-        $this->timestamp = $timestamp;
-    }
-
-    public function getTimestamp(): ?int
-    {
-        return $this->timestamp;
-    }
-}

+ 0 - 375
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/JWK.php

@@ -1,375 +0,0 @@
-<?php
-
-namespace Firebase\JWT;
-
-use DomainException;
-use InvalidArgumentException;
-use UnexpectedValueException;
-
-/**
- * JSON Web Key implementation, based on this spec:
- * https://tools.ietf.org/html/draft-ietf-jose-json-web-key-41
- *
- * PHP version 5
- *
- * @category Authentication
- * @package  Authentication_JWT
- * @author   Bui Sy Nguyen <nguyenbs@gmail.com>
- * @license  http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
- * @link     https://github.com/firebase/php-jwt
- */
-class JWK
-{
-    private const OID = '1.2.840.10045.2.1';
-    private const ASN1_OBJECT_IDENTIFIER = 0x06;
-    private const ASN1_SEQUENCE = 0x10; // also defined in JWT
-    private const ASN1_BIT_STRING = 0x03;
-    private const EC_CURVES = [
-        'P-256' => '1.2.840.10045.3.1.7', // Len: 64
-        'secp256k1' => '1.3.132.0.10', // Len: 64
-        'P-384' => '1.3.132.0.34', // Len: 96
-        // 'P-521' => '1.3.132.0.35', // Len: 132 (not supported)
-    ];
-
-    // Known standard curves from the IANA JOSE registry which are not supported
-    private const KNOWN_UNSUPPORTED_EC_CURVES = [
-        'P-521',   // RFC 7518
-        'Ed25519', // RFC 8037
-        'Ed448',   // RFC 8037
-        'X25519',  // RFC 8037
-        'X448'     // RFC 8037
-    ];
-
-    // For keys with "kty" equal to "OKP" (Octet Key Pair), the "crv" parameter must contain the key subtype.
-    // This library supports the following subtypes:
-    private const OKP_SUBTYPES = [
-        'Ed25519' => true, // RFC 8037
-    ];
-
-    /**
-     * Parse a set of JWK keys
-     *
-     * @param array<mixed> $jwks The JSON Web Key Set as an associative array
-     * @param string       $defaultAlg The algorithm for the Key object if "alg" is not set in the
-     *                                 JSON Web Key Set
-     *
-     * @return array<string, Key> An associative array of key IDs (kid) to Key objects
-     *
-     * @throws InvalidArgumentException     Provided JWK Set is empty
-     * @throws UnexpectedValueException     Provided JWK Set was invalid
-     * @throws DomainException              OpenSSL failure
-     *
-     * @uses parseKey
-     */
-    public static function parseKeySet(#[\SensitiveParameter] array $jwks, ?string $defaultAlg = null): array
-    {
-        $keys = [];
-
-        if (!isset($jwks['keys'])) {
-            throw new UnexpectedValueException('"keys" member must exist in the JWK Set');
-        }
-
-        if (empty($jwks['keys'])) {
-            throw new InvalidArgumentException('JWK Set did not contain any keys');
-        }
-
-        foreach ($jwks['keys'] as $k => $v) {
-            $kid = isset($v['kid']) ? $v['kid'] : $k;
-            if ($key = self::parseKey($v, $defaultAlg)) {
-                $keys[(string) $kid] = $key;
-            }
-        }
-
-        if (0 === \count($keys)) {
-            throw new UnexpectedValueException('No supported algorithms found in JWK Set');
-        }
-
-        return $keys;
-    }
-
-    /**
-     * Parse a JWK key
-     *
-     * @param array<mixed> $jwk An individual JWK
-     * @param string       $defaultAlg The algorithm for the Key object if "alg" is not set in the
-     *                                 JSON Web Key Set
-     *
-     * @return Key The key object for the JWK
-     *
-     * @throws InvalidArgumentException     Provided JWK is empty
-     * @throws UnexpectedValueException     Provided JWK was invalid
-     * @throws DomainException              OpenSSL failure
-     *
-     * @uses createPemFromModulusAndExponent
-     */
-    public static function parseKey(#[\SensitiveParameter] array $jwk, ?string $defaultAlg = null): ?Key
-    {
-        if (empty($jwk)) {
-            throw new InvalidArgumentException('JWK must not be empty');
-        }
-
-        if (!isset($jwk['kty'])) {
-            throw new UnexpectedValueException('JWK must contain a "kty" parameter');
-        }
-
-        if (!isset($jwk['alg'])) {
-            if (\is_null($defaultAlg)) {
-                // The "alg" parameter is optional in a KTY, but an algorithm is required
-                // for parsing in this library. Use the $defaultAlg parameter when parsing the
-                // key set in order to prevent this error.
-                // @see https://datatracker.ietf.org/doc/html/rfc7517#section-4.4
-                throw new UnexpectedValueException('JWK must contain an "alg" parameter');
-            }
-            $jwk['alg'] = $defaultAlg;
-        }
-
-        switch ($jwk['kty']) {
-            case 'RSA':
-                if (!empty($jwk['d'])) {
-                    throw new UnexpectedValueException('RSA private keys are not supported');
-                }
-                if (!isset($jwk['n']) || !isset($jwk['e'])) {
-                    throw new UnexpectedValueException('RSA keys must contain values for both "n" and "e"');
-                }
-
-                $pem = self::createPemFromModulusAndExponent($jwk['n'], $jwk['e']);
-                $publicKey = \openssl_pkey_get_public($pem);
-                if (false === $publicKey) {
-                    throw new DomainException(
-                        'OpenSSL error: ' . \openssl_error_string()
-                    );
-                }
-                return new Key($publicKey, $jwk['alg']);
-            case 'EC':
-                if (isset($jwk['d'])) {
-                    // The key is actually a private key
-                    throw new UnexpectedValueException('Key data must be for a public key');
-                }
-
-                if (empty($jwk['crv'])) {
-                    throw new UnexpectedValueException('crv not set');
-                }
-
-                if (!isset(self::EC_CURVES[$jwk['crv']])) {
-                    if (!\in_array($jwk['crv'], self::KNOWN_UNSUPPORTED_EC_CURVES)) {
-                        throw new DomainException('Unrecognised EC curve');
-                    }
-                    return null;
-                }
-
-                if (empty($jwk['x']) || empty($jwk['y'])) {
-                    throw new UnexpectedValueException('x and y not set');
-                }
-
-                $publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
-                return new Key($publicKey, $jwk['alg']);
-            case 'OKP':
-                if (isset($jwk['d'])) {
-                    // The key is actually a private key
-                    throw new UnexpectedValueException('Key data must be for a public key');
-                }
-
-                if (!isset($jwk['crv'])) {
-                    throw new UnexpectedValueException('crv not set');
-                }
-
-                if (empty(self::OKP_SUBTYPES[$jwk['crv']])) {
-                    throw new DomainException('Unrecognised or unsupported OKP key subtype');
-                }
-
-                if (empty($jwk['x'])) {
-                    throw new UnexpectedValueException('x not set');
-                }
-
-                // This library works internally with EdDSA keys (Ed25519) encoded in standard base64.
-                $publicKey = JWT::convertBase64urlToBase64($jwk['x']);
-                return new Key($publicKey, $jwk['alg']);
-            case 'oct':
-                if (!isset($jwk['k'])) {
-                    throw new UnexpectedValueException('k not set');
-                }
-
-                return new Key(JWT::urlsafeB64Decode($jwk['k']), $jwk['alg']);
-            default:
-                break;
-        }
-
-        return null;
-    }
-
-    /**
-     * Converts the EC JWK values to pem format.
-     *
-     * @param   string  $crv The EC curve (only P-256 & P-384 is supported)
-     * @param   string  $x   The EC x-coordinate
-     * @param   string  $y   The EC y-coordinate
-     *
-     * @return  string
-     */
-    private static function createPemFromCrvAndXYCoordinates(string $crv, string $x, string $y): string
-    {
-        $pem =
-            self::encodeDER(
-                self::ASN1_SEQUENCE,
-                self::encodeDER(
-                    self::ASN1_SEQUENCE,
-                    self::encodeDER(
-                        self::ASN1_OBJECT_IDENTIFIER,
-                        self::encodeOID(self::OID)
-                    )
-                    . self::encodeDER(
-                        self::ASN1_OBJECT_IDENTIFIER,
-                        self::encodeOID(self::EC_CURVES[$crv])
-                    )
-                ) .
-                self::encodeDER(
-                    self::ASN1_BIT_STRING,
-                    \chr(0x00) . \chr(0x04)
-                    . JWT::urlsafeB64Decode($x)
-                    . JWT::urlsafeB64Decode($y)
-                )
-            );
-
-        return \sprintf(
-            "-----BEGIN PUBLIC KEY-----\n%s\n-----END PUBLIC KEY-----\n",
-            wordwrap(base64_encode($pem), 64, "\n", true)
-        );
-    }
-
-    /**
-     * Create a public key represented in PEM format from RSA modulus and exponent information
-     *
-     * @param string $n The RSA modulus encoded in Base64
-     * @param string $e The RSA exponent encoded in Base64
-     *
-     * @return string The RSA public key represented in PEM format
-     *
-     * @uses encodeLength
-     */
-    private static function createPemFromModulusAndExponent(
-        string $n,
-        string $e
-    ): string {
-        $mod = JWT::urlsafeB64Decode($n);
-        $exp = JWT::urlsafeB64Decode($e);
-        // Correct encoding for ASN1, as ints are represented as unsigned in jwk
-        // but signed in ASN1. Prepending null byte makes it unsigned.
-        if (\strlen($mod) > 0 && \ord($mod[0]) >= 128) {
-            $mod = \chr(0) . $mod;
-        }
-        if (\strlen($exp) > 0 && \ord($exp[0]) >= 128) {
-            $exp = \chr(0) . $exp;
-        }
-
-        $modulus = \pack('Ca*a*', 2, self::encodeLength(\strlen($mod)), $mod);
-        $publicExponent = \pack('Ca*a*', 2, self::encodeLength(\strlen($exp)), $exp);
-
-        $rsaPublicKey = \pack(
-            'Ca*a*a*',
-            48,
-            self::encodeLength(\strlen($modulus) + \strlen($publicExponent)),
-            $modulus,
-            $publicExponent
-        );
-
-        // sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
-        $rsaOID = \pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
-        $rsaPublicKey = \chr(0) . $rsaPublicKey;
-        $rsaPublicKey = \chr(3) . self::encodeLength(\strlen($rsaPublicKey)) . $rsaPublicKey;
-
-        $rsaPublicKey = \pack(
-            'Ca*a*',
-            48,
-            self::encodeLength(\strlen($rsaOID . $rsaPublicKey)),
-            $rsaOID . $rsaPublicKey
-        );
-
-        return "-----BEGIN PUBLIC KEY-----\r\n" .
-            \chunk_split(\base64_encode($rsaPublicKey), 64) .
-            '-----END PUBLIC KEY-----';
-    }
-
-    /**
-     * DER-encode the length
-     *
-     * DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4.  See
-     * {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
-     *
-     * @param int $length
-     * @return string
-     */
-    private static function encodeLength(int $length): string
-    {
-        if ($length <= 0x7F) {
-            return \chr($length);
-        }
-
-        $temp = \ltrim(\pack('N', $length), \chr(0));
-
-        return \pack('Ca*', 0x80 | \strlen($temp), $temp);
-    }
-
-    /**
-     * Encodes a value into a DER object.
-     * Also defined in Firebase\JWT\JWT
-     *
-     * @param   int     $type DER tag
-     * @param   string  $value the value to encode
-     * @return  string  the encoded object
-     */
-    private static function encodeDER(int $type, string $value): string
-    {
-        $tag_header = 0;
-        if ($type === self::ASN1_SEQUENCE) {
-            $tag_header |= 0x20;
-        }
-
-        // Type
-        $der = \chr($tag_header | $type);
-
-        // Length
-        $der .= \chr(\strlen($value));
-
-        return $der . $value;
-    }
-
-    /**
-     * Encodes a string into a DER-encoded OID.
-     *
-     * @param   string $oid the OID string
-     * @return  string the binary DER-encoded OID
-     */
-    private static function encodeOID(string $oid): string
-    {
-        $octets = explode('.', $oid);
-
-        // Get the first octet
-        $first = (int) array_shift($octets);
-        $second = (int) array_shift($octets);
-        $oid = \chr($first * 40 + $second);
-
-        // Iterate over subsequent octets
-        foreach ($octets as $octet) {
-            if ($octet == 0) {
-                $oid .= \chr(0x00);
-                continue;
-            }
-            $bin = '';
-
-            while ($octet) {
-                $bin .= \chr(0x80 | ($octet & 0x7f));
-                $octet >>= 7;
-            }
-            $bin[0] = $bin[0] & \chr(0x7f);
-
-            // Convert to big endian if necessary
-            if (pack('V', 65534) == pack('L', 65534)) {
-                $oid .= strrev($bin);
-            } else {
-                $oid .= $bin;
-            }
-        }
-
-        return $oid;
-    }
-}

+ 0 - 833
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/JWT.php

@@ -1,833 +0,0 @@
-<?php
-
-namespace Firebase\JWT;
-
-use ArrayAccess;
-use DateTime;
-use DomainException;
-use Exception;
-use InvalidArgumentException;
-use OpenSSLAsymmetricKey;
-use OpenSSLCertificate;
-use stdClass;
-use UnexpectedValueException;
-
-/**
- * JSON Web Token implementation, based on this spec:
- * https://tools.ietf.org/html/rfc7519
- *
- * PHP version 5
- *
- * @category Authentication
- * @package  Authentication_JWT
- * @author   Neuman Vong <neuman@twilio.com>
- * @author   Anant Narayanan <anant@php.net>
- * @license  http://opensource.org/licenses/BSD-3-Clause 3-clause BSD
- * @link     https://github.com/firebase/php-jwt
- */
-class JWT
-{
-    private const ASN1_INTEGER = 0x02;
-    private const ASN1_SEQUENCE = 0x10;
-    private const ASN1_BIT_STRING = 0x03;
-
-    private const RSA_KEY_MIN_LENGTH = 2048;
-
-    /**
-     * When checking nbf, iat or expiration times,
-     * we want to provide some extra leeway time to
-     * account for clock skew.
-     *
-     * @var int
-     */
-    public static $leeway = 0;
-
-    /**
-     * Allow the current timestamp to be specified.
-     * Useful for fixing a value within unit testing.
-     * Will default to PHP time() value if null.
-     *
-     * @var ?int
-     */
-    public static $timestamp = null;
-
-    /**
-     * @var array<string, string[]>
-     */
-    public static $supported_algs = [
-        'ES384' => ['openssl', 'SHA384'],
-        'ES256' => ['openssl', 'SHA256'],
-        'ES256K' => ['openssl', 'SHA256'],
-        'HS256' => ['hash_hmac', 'SHA256'],
-        'HS384' => ['hash_hmac', 'SHA384'],
-        'HS512' => ['hash_hmac', 'SHA512'],
-        'RS256' => ['openssl', 'SHA256'],
-        'RS384' => ['openssl', 'SHA384'],
-        'RS512' => ['openssl', 'SHA512'],
-        'PS256' => ['openssl', 'SHA256'],
-        'EdDSA' => ['sodium_crypto', 'EdDSA']
-    ];
-
-    /**
-     * Decodes a JWT string into a PHP object.
-     *
-     * @param string                 $jwt            The JWT
-     * @param Key|ArrayAccess<string,Key>|array<string,Key> $keyOrKeyArray  The Key or associative array of key IDs
-     *                                                                      (kid) to Key objects.
-     *                                                                      If the algorithm used is asymmetric, this is
-     *                                                                      the public key.
-     *                                                                      Each Key object contains an algorithm and
-     *                                                                      matching key.
-     *                                                                      Supported algorithms are 'ES384','ES256',
-     *                                                                      'HS256', 'HS384', 'HS512', 'RS256', 'RS384'
-     *                                                                      and 'RS512'.
-     * @param stdClass               $headers                               Optional. Populates stdClass with headers.
-     *
-     * @return stdClass The JWT's payload as a PHP object
-     *
-     * @throws InvalidArgumentException     Provided key/key-array was empty or malformed
-     * @throws DomainException              Provided JWT is malformed
-     * @throws UnexpectedValueException     Provided JWT was invalid
-     * @throws SignatureInvalidException    Provided JWT was invalid because the signature verification failed
-     * @throws BeforeValidException         Provided JWT is trying to be used before it's eligible as defined by 'nbf'
-     * @throws BeforeValidException         Provided JWT is trying to be used before it's been created as defined by 'iat'
-     * @throws ExpiredException             Provided JWT has since expired, as defined by the 'exp' claim
-     *
-     * @uses jsonDecode
-     * @uses urlsafeB64Decode
-     */
-    public static function decode(
-        string $jwt,
-        #[\SensitiveParameter] $keyOrKeyArray,
-        ?stdClass &$headers = null
-    ): stdClass {
-        // Validate JWT
-        $timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
-
-        if (empty($keyOrKeyArray)) {
-            throw new InvalidArgumentException('Key may not be empty');
-        }
-        $tks = \explode('.', $jwt);
-        if (\count($tks) !== 3) {
-            throw new UnexpectedValueException('Wrong number of segments');
-        }
-        list($headb64, $bodyb64, $cryptob64) = $tks;
-        $headerRaw = static::urlsafeB64Decode($headb64);
-        if (null === ($header = static::jsonDecode($headerRaw))) {
-            throw new UnexpectedValueException('Invalid header encoding');
-        }
-        if ($headers !== null) {
-            $headers = $header;
-        }
-        $payloadRaw = static::urlsafeB64Decode($bodyb64);
-        if (null === ($payload = static::jsonDecode($payloadRaw))) {
-            throw new UnexpectedValueException('Invalid claims encoding');
-        }
-        if (\is_array($payload)) {
-            // prevent PHP Fatal Error in edge-cases when payload is empty array
-            $payload = (object) $payload;
-        }
-        if (!$payload instanceof stdClass) {
-            throw new UnexpectedValueException('Payload must be a JSON object');
-        }
-        if (isset($payload->iat) && !\is_numeric($payload->iat)) {
-            throw new UnexpectedValueException('Payload iat must be a number');
-        }
-        if (isset($payload->nbf) && !\is_numeric($payload->nbf)) {
-            throw new UnexpectedValueException('Payload nbf must be a number');
-        }
-        if (isset($payload->exp) && !\is_numeric($payload->exp)) {
-            throw new UnexpectedValueException('Payload exp must be a number');
-        }
-
-        $sig = static::urlsafeB64Decode($cryptob64);
-        if (empty($header->alg)) {
-            throw new UnexpectedValueException('Empty algorithm');
-        }
-        if (empty(static::$supported_algs[$header->alg])) {
-            throw new UnexpectedValueException('Algorithm not supported');
-        }
-
-        $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null);
-
-        // Check the algorithm
-        if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) {
-            // See issue #351
-            throw new UnexpectedValueException('Incorrect key for this algorithm');
-        }
-        if (\in_array($header->alg, ['ES256', 'ES256K', 'ES384'], true)) {
-            // OpenSSL expects an ASN.1 DER sequence for ES256/ES256K/ES384 signatures
-            $sig = self::signatureToDER($sig);
-        }
-        if (!self::verify("{$headb64}.{$bodyb64}", $sig, $key->getKeyMaterial(), $header->alg)) {
-            throw new SignatureInvalidException('Signature verification failed');
-        }
-
-        // Check the nbf if it is defined. This is the time that the
-        // token can actually be used. If it's not yet that time, abort.
-        if (isset($payload->nbf) && floor($payload->nbf) > ($timestamp + static::$leeway)) {
-            $ex = new BeforeValidException(
-                'Cannot handle token with nbf prior to ' . \date(DateTime::ATOM, (int) floor($payload->nbf))
-            );
-            $ex->setPayload($payload);
-            throw $ex;
-        }
-
-        // Check that this token has been created before 'now'. This prevents
-        // using tokens that have been created for later use (and haven't
-        // correctly used the nbf claim).
-        if (!isset($payload->nbf) && isset($payload->iat) && floor($payload->iat) > ($timestamp + static::$leeway)) {
-            $ex = new BeforeValidException(
-                'Cannot handle token with iat prior to ' . \date(DateTime::ATOM, (int) floor($payload->iat))
-            );
-            $ex->setPayload($payload);
-            throw $ex;
-        }
-
-        // Check if this token has expired.
-        if (isset($payload->exp) && ($timestamp - static::$leeway) >= $payload->exp) {
-            $ex = new ExpiredException('Expired token');
-            $ex->setPayload($payload);
-            $ex->setTimestamp($timestamp);
-            throw $ex;
-        }
-
-        return $payload;
-    }
-
-    /**
-     * Converts and signs a PHP array into a JWT string.
-     *
-     * @param array<mixed>          $payload PHP array
-     * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
-     * @param string                $alg     Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
-     *                                       'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
-     * @param string                $keyId
-     * @param array<string, string|string[]> $head  An array with header elements to attach
-     *
-     * @return string A signed JWT
-     *
-     * @uses jsonEncode
-     * @uses urlsafeB64Encode
-     */
-    public static function encode(
-        array $payload,
-        #[\SensitiveParameter] $key,
-        string $alg,
-        ?string $keyId = null,
-        ?array $head = null
-    ): string {
-        $header = ['typ' => 'JWT'];
-        if (isset($head)) {
-            $header = \array_merge($header, $head);
-        }
-        $header['alg'] = $alg;
-        if ($keyId !== null) {
-            $header['kid'] = $keyId;
-        }
-        if (isset($payload['nbf']) && !\is_numeric($payload['nbf'])) {
-            throw new UnexpectedValueException('Payload nbf must be a number');
-        }
-        if (isset($payload['iat']) && !\is_numeric($payload['iat'])) {
-            throw new UnexpectedValueException('Payload iat must be a number');
-        }
-        if (isset($payload['exp']) && !\is_numeric($payload['exp'])) {
-            throw new UnexpectedValueException('Payload exp must be a number');
-        }
-        $segments = [];
-        $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($header));
-        $segments[] = static::urlsafeB64Encode((string) static::jsonEncode($payload));
-        $signing_input = \implode('.', $segments);
-
-        $signature = static::sign($signing_input, $key, $alg);
-        $segments[] = static::urlsafeB64Encode($signature);
-
-        return \implode('.', $segments);
-    }
-
-    /**
-     * Sign a string with a given key and algorithm.
-     *
-     * @param string $msg  The message to sign
-     * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate  $key  The secret key.
-     * @param string $alg  Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256',
-     *                    'HS384', 'HS512', 'RS256', 'RS384', 'PS256' and 'RS512'
-     *
-     * @return string An encrypted message
-     *
-     * @throws DomainException Unsupported algorithm or bad key was specified
-     */
-    public static function sign(
-        string $msg,
-        #[\SensitiveParameter] $key,
-        string $alg
-    ): string {
-        if (empty(static::$supported_algs[$alg])) {
-            throw new DomainException('Algorithm not supported');
-        }
-        list($function, $algorithm) = static::$supported_algs[$alg];
-        switch ($function) {
-            case 'hash_hmac':
-                if (!\is_string($key)) {
-                    throw new InvalidArgumentException('key must be a string when using hmac');
-                }
-                self::validateHmacKeyLength($key, $algorithm);
-                return \hash_hmac($algorithm, $msg, $key, true);
-            case 'openssl':
-                if ($alg === 'PS256') {
-                    return self::signPS256($key, $msg);
-                }
-                $signature = '';
-                if (!$key = openssl_pkey_get_private($key)) {
-                    throw new DomainException('OpenSSL unable to validate key');
-                }
-                if (str_starts_with($alg, 'RS')) {
-                    self::validateRsaKeyLength($key);
-                } elseif (str_starts_with($alg, 'ES')) {
-                    self::validateEcKeyLength($key, $alg);
-                }
-                $success = \openssl_sign($msg, $signature, $key, $algorithm);
-                if (!$success) {
-                    throw new DomainException('OpenSSL unable to sign data');
-                }
-                if ($alg === 'ES256' || $alg === 'ES256K') {
-                    $signature = self::signatureFromDER($signature, 256);
-                } elseif ($alg === 'ES384') {
-                    $signature = self::signatureFromDER($signature, 384);
-                }
-                return $signature;
-            case 'sodium_crypto':
-                try {
-                    return sodium_crypto_sign_detached($msg, self::validateEdDSAKey($key));
-                } catch (Exception $e) {
-                    throw new DomainException($e->getMessage(), 0, $e);
-                }
-        }
-
-        throw new DomainException('Algorithm not supported');
-    }
-
-    /**
-     * Verify a signature with the message, key and method. Not all methods
-     * are symmetric, so we must have a separate verify and sign method.
-     *
-     * @param string $msg         The original message (header and body)
-     * @param string $signature   The original signature
-     * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate  $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
-     * @param string $alg         The algorithm
-     *
-     * @return bool
-     *
-     * @throws DomainException Invalid Algorithm, bad key, or OpenSSL failure
-     */
-    private static function verify(
-        string $msg,
-        string $signature,
-        #[\SensitiveParameter] $keyMaterial,
-        string $alg
-    ): bool {
-        if (empty(static::$supported_algs[$alg])) {
-            throw new DomainException('Algorithm not supported');
-        }
-
-        list($function, $algorithm) = static::$supported_algs[$alg];
-        switch ($function) {
-            case 'openssl':
-                if ($alg === 'PS256') {
-                    return self::verifyPS256($keyMaterial, $msg, $signature);
-                }
-                if (!$key = openssl_pkey_get_public($keyMaterial)) {
-                    throw new DomainException('OpenSSL unable to validate key');
-                }
-                if (str_starts_with($alg, 'RS')) {
-                    self::validateRsaKeyLength($key);
-                } elseif (str_starts_with($alg, 'ES')) {
-                    self::validateEcKeyLength($key, $alg);
-                }
-                $success = \openssl_verify($msg, $signature, $keyMaterial, $algorithm);
-                if ($success === 1) {
-                    return true;
-                }
-                if ($success === 0) {
-                    return false;
-                }
-                // returns 1 on success, 0 on failure, -1 on error.
-                throw new DomainException(
-                    'OpenSSL error: ' . \openssl_error_string()
-                );
-            case 'sodium_crypto':
-                try {
-                    $key = self::validateEdDSAKey($keyMaterial);
-                    if (\strlen($signature) === 0) {
-                        throw new DomainException('Signature cannot be empty string');
-                    }
-                    return sodium_crypto_sign_verify_detached($signature, $msg, $key);
-                } catch (Exception $e) {
-                    throw new DomainException($e->getMessage(), 0, $e);
-                }
-            case 'hash_hmac':
-            default:
-                if (!\is_string($keyMaterial)) {
-                    throw new InvalidArgumentException('key must be a string when using hmac');
-                }
-                self::validateHmacKeyLength($keyMaterial, $algorithm);
-                $hash = \hash_hmac($algorithm, $msg, $keyMaterial, true);
-                return self::constantTimeEquals($hash, $signature);
-        }
-    }
-
-    /**
-     * Decode a JSON string into a PHP object.
-     *
-     * @param string $input JSON string
-     *
-     * @return mixed The decoded JSON string
-     *
-     * @throws DomainException Provided string was invalid JSON
-     */
-    public static function jsonDecode(string $input)
-    {
-        $obj = \json_decode($input, false, 512, JSON_BIGINT_AS_STRING);
-
-        if ($errno = \json_last_error()) {
-            self::handleJsonError($errno);
-        } elseif ($obj === null && $input !== 'null') {
-            throw new DomainException('Null result with non-null input');
-        }
-        return $obj;
-    }
-
-    /**
-     * Encode a PHP array into a JSON string.
-     *
-     * @param array<mixed> $input A PHP array
-     *
-     * @return string JSON representation of the PHP array
-     *
-     * @throws DomainException Provided object could not be encoded to valid JSON
-     */
-    public static function jsonEncode(array $input): string
-    {
-        $json = \json_encode($input, \JSON_UNESCAPED_SLASHES);
-        if ($errno = \json_last_error()) {
-            self::handleJsonError($errno);
-        } elseif ($json === 'null') {
-            throw new DomainException('Null result with non-null input');
-        }
-        if ($json === false) {
-            throw new DomainException('Provided object could not be encoded to valid JSON');
-        }
-        return $json;
-    }
-
-    /**
-     * Decode a string with URL-safe Base64.
-     *
-     * @param string $input A Base64 encoded string
-     *
-     * @return string A decoded string
-     *
-     * @throws InvalidArgumentException invalid base64 characters
-     */
-    public static function urlsafeB64Decode(string $input): string
-    {
-        return \base64_decode(self::convertBase64UrlToBase64($input));
-    }
-
-    /**
-     * Convert a string in the base64url (URL-safe Base64) encoding to standard base64.
-     *
-     * @param string $input A Base64 encoded string with URL-safe characters (-_ and no padding)
-     *
-     * @return string A Base64 encoded string with standard characters (+/) and padding (=), when
-     * needed.
-     *
-     * @see https://www.rfc-editor.org/rfc/rfc4648
-     */
-    public static function convertBase64UrlToBase64(string $input): string
-    {
-        $remainder = \strlen($input) % 4;
-        if ($remainder) {
-            $padlen = 4 - $remainder;
-            $input .= \str_repeat('=', $padlen);
-        }
-        return \strtr($input, '-_', '+/');
-    }
-
-    /**
-     * Encode a string with URL-safe Base64.
-     *
-     * @param string $input The string you want encoded
-     *
-     * @return string The base64 encode of what you passed in
-     */
-    public static function urlsafeB64Encode(string $input): string
-    {
-        return \str_replace('=', '', \strtr(\base64_encode($input), '+/', '-_'));
-    }
-
-    /**
-     * Determine if an algorithm has been provided for each Key
-     *
-     * @param Key|ArrayAccess<string,Key>|array<string,Key> $keyOrKeyArray
-     * @param string|null            $kid
-     *
-     * @throws UnexpectedValueException
-     *
-     * @return Key
-     */
-    private static function getKey(
-        #[\SensitiveParameter] $keyOrKeyArray,
-        ?string $kid
-    ): Key {
-        if ($keyOrKeyArray instanceof Key) {
-            return $keyOrKeyArray;
-        }
-
-        if (empty($kid) && $kid !== '0') {
-            throw new UnexpectedValueException('"kid" empty, unable to lookup correct key');
-        }
-
-        if ($keyOrKeyArray instanceof CachedKeySet) {
-            // Skip "isset" check, as this will automatically refresh if not set
-            return $keyOrKeyArray[$kid];
-        }
-
-        if (!isset($keyOrKeyArray[$kid])) {
-            throw new UnexpectedValueException('"kid" invalid, unable to lookup correct key');
-        }
-
-        return $keyOrKeyArray[$kid];
-    }
-
-    /**
-     * @param string $left  The string of known length to compare against
-     * @param string $right The user-supplied string
-     * @return bool
-     */
-    public static function constantTimeEquals(string $left, string $right): bool
-    {
-        if (\function_exists('hash_equals')) {
-            return \hash_equals($left, $right);
-        }
-        $len = \min(self::safeStrlen($left), self::safeStrlen($right));
-
-        $status = 0;
-        for ($i = 0; $i < $len; $i++) {
-            $status |= (\ord($left[$i]) ^ \ord($right[$i]));
-        }
-        $status |= (self::safeStrlen($left) ^ self::safeStrlen($right));
-
-        return ($status === 0);
-    }
-
-    /**
-     * Helper method to create a JSON error.
-     *
-     * @param int $errno An error number from json_last_error()
-     *
-     * @throws DomainException
-     *
-     * @return void
-     */
-    private static function handleJsonError(int $errno): void
-    {
-        $messages = [
-            JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
-            JSON_ERROR_STATE_MISMATCH => 'Invalid or malformed JSON',
-            JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
-            JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON',
-            JSON_ERROR_UTF8 => 'Malformed UTF-8 characters' //PHP >= 5.3.3
-        ];
-        throw new DomainException(
-            isset($messages[$errno])
-            ? $messages[$errno]
-            : 'Unknown JSON error: ' . $errno
-        );
-    }
-
-    /**
-     * Get the number of bytes in cryptographic strings.
-     *
-     * @param string $str
-     *
-     * @return int
-     */
-    private static function safeStrlen(string $str): int
-    {
-        if (\function_exists('mb_strlen')) {
-            return \mb_strlen($str, '8bit');
-        }
-        return \strlen($str);
-    }
-
-    /**
-     * Convert an ECDSA signature to an ASN.1 DER sequence
-     *
-     * @param   string $sig The ECDSA signature to convert
-     * @return  string The encoded DER object
-     */
-    private static function signatureToDER(string $sig): string
-    {
-        // Separate the signature into r-value and s-value
-        $length = max(1, (int) (\strlen($sig) / 2));
-        list($r, $s) = \str_split($sig, $length);
-
-        // Trim leading zeros
-        $r = \ltrim($r, "\x00");
-        $s = \ltrim($s, "\x00");
-
-        // Convert r-value and s-value from unsigned big-endian integers to
-        // signed two's complement
-        if (\ord($r[0]) > 0x7f) {
-            $r = "\x00" . $r;
-        }
-        if (\ord($s[0]) > 0x7f) {
-            $s = "\x00" . $s;
-        }
-
-        return self::encodeDER(
-            self::ASN1_SEQUENCE,
-            self::encodeDER(self::ASN1_INTEGER, $r) .
-            self::encodeDER(self::ASN1_INTEGER, $s)
-        );
-    }
-
-    /**
-     * Encodes a value into a DER object.
-     *
-     * @param   int     $type DER tag
-     * @param   string  $value the value to encode
-     *
-     * @return  string  the encoded object
-     */
-    private static function encodeDER(int $type, string $value): string
-    {
-        $tag_header = 0;
-        if ($type === self::ASN1_SEQUENCE) {
-            $tag_header |= 0x20;
-        }
-
-        // Type
-        $der = \chr($tag_header | $type);
-
-        // Length
-        $der .= \chr(\strlen($value));
-
-        return $der . $value;
-    }
-
-    /**
-     * Encodes signature from a DER object.
-     *
-     * @param   string  $der binary signature in DER format
-     * @param   int     $keySize the number of bits in the key
-     *
-     * @return  string  the signature
-     */
-    private static function signatureFromDER(string $der, int $keySize): string
-    {
-        // OpenSSL returns the ECDSA signatures as a binary ASN.1 DER SEQUENCE
-        list($offset, $_) = self::readDER($der);
-        list($offset, $r) = self::readDER($der, $offset);
-        list($offset, $s) = self::readDER($der, $offset);
-
-        // Convert r-value and s-value from signed two's compliment to unsigned
-        // big-endian integers
-        $r = \ltrim($r, "\x00");
-        $s = \ltrim($s, "\x00");
-
-        // Pad out r and s so that they are $keySize bits long
-        $r = \str_pad($r, $keySize / 8, "\x00", STR_PAD_LEFT);
-        $s = \str_pad($s, $keySize / 8, "\x00", STR_PAD_LEFT);
-
-        return $r . $s;
-    }
-
-    /**
-     * Reads binary DER-encoded data and decodes into a single object
-     *
-     * @param string $der the binary data in DER format
-     * @param int $offset the offset of the data stream containing the object
-     * to decode
-     *
-     * @return array{int, string|null} the new offset and the decoded object
-     */
-    private static function readDER(string $der, int $offset = 0): array
-    {
-        $pos = $offset;
-        $size = \strlen($der);
-        $constructed = (\ord($der[$pos]) >> 5) & 0x01;
-        $type = \ord($der[$pos++]) & 0x1f;
-
-        // Length
-        $len = \ord($der[$pos++]);
-        if ($len & 0x80) {
-            $n = $len & 0x1f;
-            $len = 0;
-            while ($n-- && $pos < $size) {
-                $len = ($len << 8) | \ord($der[$pos++]);
-            }
-        }
-
-        // Value
-        if ($type === self::ASN1_BIT_STRING) {
-            $pos++; // Skip the first contents octet (padding indicator)
-            $data = \substr($der, $pos, $len - 1);
-            $pos += $len - 1;
-        } elseif (!$constructed) {
-            $data = \substr($der, $pos, $len);
-            $pos += $len;
-        } else {
-            $data = null;
-        }
-
-        return [$pos, $data];
-    }
-
-    /**
-     * Validate HMAC key length
-     *
-     * @param string $key HMAC key material
-     * @param string $algorithm The algorithm
-     *
-     * @throws DomainException Provided key is too short
-     */
-    private static function validateHmacKeyLength(string $key, string $algorithm): void
-    {
-        $keyLength = \strlen($key) * 8;
-        $minKeyLength = (int) \str_replace('SHA', '', $algorithm);
-        if ($keyLength < $minKeyLength) {
-            throw new DomainException('Provided key is too short');
-        }
-    }
-
-    /**
-     * Validate RSA key length
-     *
-     * @param OpenSSLAsymmetricKey $key RSA key material
-     * @throws DomainException Provided key is too short
-     */
-    private static function validateRsaKeyLength(#[\SensitiveParameter] OpenSSLAsymmetricKey $key): void
-    {
-        if (!$keyDetails = openssl_pkey_get_details($key)) {
-            throw new DomainException('Unable to validate key');
-        }
-        if ($keyDetails['bits'] < self::RSA_KEY_MIN_LENGTH) {
-            throw new DomainException('Provided key is too short');
-        }
-    }
-
-    /**
-     * Validate RSA key length
-     *
-     * @param OpenSSLAsymmetricKey $key RSA key material
-     * @param string $algorithm The algorithm
-     * @throws DomainException Provided key is too short
-     */
-    private static function validateEcKeyLength(
-        #[\SensitiveParameter] OpenSSLAsymmetricKey $key,
-        string $algorithm
-    ): void {
-        if (!$keyDetails = openssl_pkey_get_details($key)) {
-            throw new DomainException('Unable to validate key');
-        }
-        $minKeyLength = (int) \str_replace('ES', '', $algorithm);
-        if ($keyDetails['bits'] < $minKeyLength) {
-            throw new DomainException('Provided key is too short');
-        }
-    }
-
-    /**
-     * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate  $keyMaterial
-     * @return non-empty-string
-     */
-    private static function validateEdDSAKey(#[\SensitiveParameter] $keyMaterial): string
-    {
-        if (!\function_exists('sodium_crypto_sign_verify_detached')) {
-            throw new DomainException('libsodium is not available');
-        }
-        if (!\is_string($keyMaterial)) {
-            throw new InvalidArgumentException('key must be a string when using EdDSA');
-        }
-        // The last non-empty line is used as the key.
-        $lines = array_filter(explode("\n", $keyMaterial));
-        $key = self::urlsafeB64Decode((string) end($lines));
-        if (\strlen($key) === 0) {
-            throw new DomainException('Key cannot be empty string');
-        }
-        return $key;
-    }
-
-    /**
-     * Signs a message with a PS256 algorithm
-     *
-     * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key
-     * @param string $message
-     * @throws DomainException Provided key is invalid
-     */
-    private static function signPS256(
-        #[\SensitiveParameter] string|OpenSSLAsymmetricKey|OpenSSLCertificate $key,
-        string $message
-    ): string {
-        if (!class_exists('\phpseclib3\Crypt\RSA')) {
-            throw new DomainException('phpseclib/phpseclib is required for PS256 support');
-        }
-
-        if ($key instanceof OpenSSLCertificate) {
-            throw new DomainException('Cannot sign with an X.509 certificate. A private key is required.');
-        }
-
-        if ($key instanceof OpenSSLAsymmetricKey) {
-            if (!openssl_pkey_export($key, $pem)) {
-                throw new DomainException('OpenSSL unable to export the AsymmetricKey');
-            }
-            $key = $pem;
-        }
-
-        /** @var \phpseclib3\Crypt\RSA\PrivateKey $rsa */
-        $rsa = \phpseclib3\Crypt\PublicKeyLoader::load($key);
-
-        return $rsa->withPadding(\phpseclib3\Crypt\RSA::SIGNATURE_PSS)
-            ->withHash('sha256')
-            ->sign($message);
-    }
-
-    /**
-     * Validates a PS256 algorithm signature.
-     *
-     * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $key
-     * @param string $message
-     * @param string $signature
-     * @throws DomainException Provided key is invalid
-     */
-    private static function verifyPS256(
-        #[\SensitiveParameter] string|OpenSSLAsymmetricKey|OpenSSLCertificate $key,
-        string $message,
-        string $signature
-    ): bool {
-        if (!class_exists('\phpseclib3\Crypt\RSA')) {
-            throw new DomainException('phpseclib/phpseclib is required for PS256 support');
-        }
-
-        if ($key instanceof OpenSSLAsymmetricKey) {
-            $details = openssl_pkey_get_details($key);
-            if (!$details || !isset($details['key'])) {
-                throw new DomainException('OpenSSL unable to extract public key');
-            }
-            $key = $details['key'];
-        } elseif ($key instanceof OpenSSLCertificate) {
-            if (!openssl_x509_export($key, $pem)) {
-                throw new DomainException('OpenSSL unable to export certificate');
-            }
-            $key = $pem;
-        }
-
-        /** @var \phpseclib3\Crypt\RSA\PublicKey $rsa */
-        $rsa = \phpseclib3\Crypt\PublicKeyLoader::load($key);
-
-        return $rsa->withPadding(\phpseclib3\Crypt\RSA::SIGNATURE_PSS)
-            ->withHash('sha256')
-            ->verify($message, $signature);
-    }
-}

+ 0 - 20
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/JWTExceptionWithPayloadInterface.php

@@ -1,20 +0,0 @@
-<?php
-namespace Firebase\JWT;
-
-interface JWTExceptionWithPayloadInterface
-{
-    /**
-     * Get the payload that caused this exception.
-     *
-     * @return object
-     */
-    public function getPayload(): object;
-
-    /**
-     * Get the payload that caused this exception.
-     *
-     * @param object $payload
-     * @return void
-     */
-    public function setPayload(object $payload): void;
-}

+ 0 - 54
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/Key.php

@@ -1,54 +0,0 @@
-<?php
-
-namespace Firebase\JWT;
-
-use InvalidArgumentException;
-use OpenSSLAsymmetricKey;
-use OpenSSLCertificate;
-use TypeError;
-
-class Key
-{
-    /**
-     * @param string|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial
-     * @param string $algorithm
-     */
-    public function __construct(
-        #[\SensitiveParameter] private $keyMaterial,
-        private string $algorithm
-    ) {
-        if (
-            !\is_string($keyMaterial)
-            && !$keyMaterial instanceof OpenSSLAsymmetricKey
-            && !$keyMaterial instanceof OpenSSLCertificate
-        ) {
-            throw new TypeError('Key material must be a string, OpenSSLCertificate, or OpenSSLAsymmetricKey');
-        }
-
-        if (empty($keyMaterial)) {
-            throw new InvalidArgumentException('Key material must not be empty');
-        }
-
-        if (empty($algorithm)) {
-            throw new InvalidArgumentException('Algorithm must not be empty');
-        }
-    }
-
-    /**
-     * Return the algorithm valid for this key
-     *
-     * @return string
-     */
-    public function getAlgorithm(): string
-    {
-        return $this->algorithm;
-    }
-
-    /**
-     * @return string|OpenSSLAsymmetricKey|OpenSSLCertificate
-     */
-    public function getKeyMaterial()
-    {
-        return $this->keyMaterial;
-    }
-}

+ 0 - 7
modules/boonex/smtpmailer/updates/15.0.0_15.0.1/source/vendor/firebase/php-jwt/src/SignatureInvalidException.php

@@ -1,7 +0,0 @@
-<?php
-
-namespace Firebase\JWT;
-
-class SignatureInvalidException extends \UnexpectedValueException
-{
-}

+ 51 - 0
modules/boonex/snipcart/updates/15.0.1_15.0.2/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' => 'Snipcart',
+    'version_from' => '15.0.1',
+    'version_to' => '15.0.2',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/snipcart/updates/update_15.0.1_15.0.2/',
+    'home_uri' => 'snipcart_update_1501_1502',
+
+    'module_dir' => 'boonex/snipcart/',
+    'module_uri' => 'snipcart',
+
+    'db_prefix' => 'bx_snipcart_',
+    'class_prefix' => 'BxSnipcart',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 0,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 0,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Snipcart',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

+ 13 - 0
modules/boonex/snipcart/updates/15.0.1_15.0.2/install/installer.php

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

+ 35 - 0
modules/boonex/snipcart/updates/15.0.1_15.0.2/source/classes/BxSnipcartFormSettings.php

@@ -0,0 +1,35 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Snipcart Snipcart
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+/**
+ * Edit settings form
+ */
+class BxSnipcartFormSettings extends BxTemplFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct($aInfo, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_snipcart';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aInfo, $oTemplate);
+
+        if(($sF = 'api_key_test') && isset($this->aInputs[$sF]))
+            $this->aInputs[$sF]['secret'] = 1;
+
+        if(($sF = 'api_key_live') && isset($this->aInputs[$sF]))
+            $this->aInputs[$sF]['secret'] = 1;
+    }
+}
+
+/** @} */

+ 136 - 0
modules/boonex/snipcart/updates/15.0.1_15.0.2/source/install/config.php

@@ -0,0 +1,136 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Snipcart Snipcart
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+$aConfig = array(
+
+    /**
+     * Main Section.
+     */
+    'type' => BX_DOL_MODULE_TYPE_MODULE,
+    'name' => 'bx_snipcart',
+    'title' => 'Snipcart',
+    'note' => 'Snipcart shopping module.',
+    'version' => '15.0.2',
+    'vendor' => 'UNA INC',
+    'help_url' => 'http://feed.una.io/?section={module_name}',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/snipcart/',
+    'home_uri' => 'snipcart',
+
+    'db_prefix' => 'bx_snipcart_',
+    'class_prefix' => 'BxSnipcart',
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Snipcart',
+
+    /**
+     * 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_snipcart_files'
+    ),
+
+    /**
+     * Transcoders.
+     */
+    'transcoders' => array(
+		'bx_snipcart_preview',
+        'bx_snipcart_gallery',
+        'bx_snipcart_cover'
+    ),
+
+    /**
+     * Extended Search Forms.
+     */
+    'esearches' => array(
+        'bx_snipcart',
+    	'bx_snipcart_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'
+    ),
+
+);
+
+/** @} */

File diff suppressed because it is too large
+ 6 - 0
modules/boonex/snipcart/updates/15.0.1_15.0.2/source/template/images/icons/std-icon.svg


+ 51 - 0
modules/boonex/stripe_connect/updates/15.0.2_15.0.3/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' => 'Stripe Connect',
+    'version_from' => '15.0.2',
+    'version_to' => '15.0.3',
+    'vendor' => 'UNA INC',
+
+    'compatible_with' => array(
+        '15.0.0-RC2'
+    ),
+
+    /**
+     * 'home_dir' and 'home_uri' - should be unique. Don't use spaces in 'home_uri' and the other special chars.
+     */
+    'home_dir' => 'boonex/stripe_connect/updates/update_15.0.2_15.0.3/',
+    'home_uri' => 'stripe_connect_update_1502_1503',
+
+    'module_dir' => 'boonex/stripe_connect/',
+    'module_uri' => 'stripe_connect',
+
+    'db_prefix' => 'bx_stripe_connect_',
+    'class_prefix' => 'BxStripeConnect',
+
+    /**
+     * Installation/Uninstallation Section.
+     */
+    'install' => array(
+        'execute_sql' => 1,
+        'update_files' => 1,
+        'update_languages' => 0,
+        'clear_db_cache' => 1,
+    ),
+
+    /**
+     * Category for language keys.
+     */
+    'language_category' => 'Stripe Connect',
+
+    /**
+     * Files Section
+     */
+    'delete_files' => array(),
+);

Some files were not shown because too many files changed in this diff