AntonLV 5 лет назад
Родитель
Сommit
5de5454e54
32 измененных файлов с 1853 добавлено и 117 удалено
  1. 32 15
      inc/classes/BxDolPayments.php
  2. 6 3
      install/sql/system.sql
  3. 24 0
      invoices.php
  4. 81 0
      modules/base/payment/classes/BxBaseModPaymentCommissions.php
  5. 31 6
      modules/base/payment/classes/BxBaseModPaymentConfig.php
  6. 54 0
      modules/base/payment/classes/BxBaseModPaymentGridCommissions.php
  7. 158 0
      modules/base/payment/classes/BxBaseModPaymentGridInvoices.php
  8. 2 0
      modules/boonex/english/data/langs/system/en.xml
  9. 49 0
      modules/boonex/payment/classes/BxPaymentCommissions.php
  10. 14 1
      modules/boonex/payment/classes/BxPaymentConfig.php
  11. 31 0
      modules/boonex/payment/classes/BxPaymentCronCommissions.php
  12. 212 3
      modules/boonex/payment/classes/BxPaymentDb.php
  13. 36 0
      modules/boonex/payment/classes/BxPaymentFormCommissions.php
  14. 34 0
      modules/boonex/payment/classes/BxPaymentFormInvoices.php
  15. 6 6
      modules/boonex/payment/classes/BxPaymentFormView.php
  16. 140 0
      modules/boonex/payment/classes/BxPaymentGridCommissions.php
  17. 81 0
      modules/boonex/payment/classes/BxPaymentGridInvoices.php
  18. 1 1
      modules/boonex/payment/classes/BxPaymentGridPending.php
  19. 1 1
      modules/boonex/payment/classes/BxPaymentGridProcessed.php
  20. 386 16
      modules/boonex/payment/classes/BxPaymentModule.php
  21. 26 0
      modules/boonex/payment/classes/BxPaymentPageInvoices.php
  22. 13 1
      modules/boonex/payment/classes/BxPaymentStudioPage.php
  23. 24 7
      modules/boonex/payment/classes/BxPaymentTemplate.php
  24. 129 43
      modules/boonex/payment/install/langs/en.xml
  25. 1 1
      modules/boonex/payment/install/sql/disable.sql
  26. 15 3
      modules/boonex/payment/install/sql/enable.sql
  27. 123 3
      modules/boonex/payment/install/sql/install.sql
  28. 4 7
      modules/boonex/payment/install/sql/uninstall.sql
  29. 9 0
      modules/boonex/payment/template/css/invoices.css
  30. 87 0
      modules/boonex/russian/data/langs/bx_payment/ru.xml
  31. 2 0
      modules/boonex/russian/data/langs/system/ru.xml
  32. 41 0
      template/scripts/BxBasePaymentsServices.php

+ 32 - 15
inc/classes/BxDolPayments.php

@@ -9,10 +9,10 @@
 
 class BxDolPayments extends BxDolFactory implements iBxDolSingleton
 {
-	protected $_oDb;
+    protected $_oDb;
 
-	protected $_aObjects;
-	protected $_sActive;
+    protected $_aObjects;
+    protected $_sActive;
 
     protected function __construct()
     {
@@ -24,17 +24,17 @@ class BxDolPayments extends BxDolFactory implements iBxDolSingleton
         $this->_sActive = getParam('sys_default_payment');
     }
 
-	static public function getInstance()
+    static public function getInstance()
     {
         if(!isset($GLOBALS['bxDolClasses']['BxDolPayments']))
-        	$GLOBALS['bxDolClasses']['BxDolPayments'] = new BxDolPayments();
+            $GLOBALS['bxDolClasses']['BxDolPayments'] = new BxDolPayments();
 
-		return $GLOBALS['bxDolClasses']['BxDolPayments'];
+        return $GLOBALS['bxDolClasses']['BxDolPayments'];
     }
 
-	public function setActive($sActive)
+    public function setActive($sActive)
     {
-		$this->_sActive = $sActive;
+        $this->_sActive = $sActive;
     }
 
     public function getActive()
@@ -153,14 +153,14 @@ class BxDolPayments extends BxDolFactory implements iBxDolSingleton
     public function getPayments()
     {
         $aPayments = array(
-			'' => _t('_Select_one')
+            '' => _t('_Select_one')
         );
-		foreach($this->_aObjects as $aObject) {
-			if(empty($aObject) || !is_array($aObject))
-				continue;
+        foreach($this->_aObjects as $aObject) {
+            if(empty($aObject) || !is_array($aObject))
+                continue;
 
-			$aPayments[$aObject['object']] = _t($aObject['title']);
-		}
+            $aPayments[$aObject['object']] = _t($aObject['title']);
+        }
 
         return $aPayments;
     }
@@ -197,7 +197,7 @@ class BxDolPayments extends BxDolFactory implements iBxDolSingleton
 
     	return bx_srv($this->_sActive, 'get_orders_url', array(), 'Orders');
     }
-
+    
     public function getOrdersCount($sType)
     {
         if(!BxDolRequest::serviceExists($this->_sActive, 'get_orders_count', 'Orders'))
@@ -243,6 +243,23 @@ class BxDolPayments extends BxDolFactory implements iBxDolSingleton
         return bx_srv($this->_sActive, 'get_subscriptions_info', $aSrvParams, 'Subscriptions');
     }
 
+    public function getInvoicesUrl()
+    {
+    	if(!BxDolRequest::serviceExists($this->_sActive, 'get_invoices_url', 'Commissions'))
+            return '';
+
+    	return bx_srv($this->_sActive, 'get_invoices_url', array(), 'Commissions');
+    }
+
+    public function getInvoicesCount($sType)
+    {
+        if(!BxDolRequest::serviceExists($this->_sActive, 'get_invoices_count', 'Commissions'))
+            return array();
+
+        $aSrvParams = array($sType);
+        return bx_srv($this->_sActive, 'get_invoices_count', $aSrvParams, 'Commissions');
+    }
+
     public function getCartUrl($iVendor = 0)
     {
     	if(!BxDolRequest::serviceExists($this->_sActive, 'get_cart_url', 'Cart'))

+ 6 - 3
install/sql/system.sql

@@ -4173,6 +4173,7 @@ INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `tit
 ('sys_account_notifications', 'system', 'studio', '_sys_menu_item_title_system_studio', '_sys_menu_item_title_studio', '{studio_url}', '', '', 'wrench', '', '', 2147483646, 1, 0, 5),
 ('sys_account_notifications', 'system', 'cart', '_sys_menu_item_title_system_cart', '_sys_menu_item_title_cart', 'cart.php', '', '', 'cart-plus col-red3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:20:"get_cart_items_count";s:6:"params";a:0:{}s:5:"class";s:21:"TemplPaymentsServices";}', '', 2147483646, 1, 1, 6),
 ('sys_account_notifications', 'system', 'orders', '_sys_menu_item_title_system_orders', '_sys_menu_item_title_orders', 'orders.php', '', '', 'cart-arrow-down col-green3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:16:"get_orders_count";s:6:"params";a:1:{i:0;s:3:"new";}s:5:"class";s:21:"TemplPaymentsServices";}', '', 2147483646, 0, 1, 7),
+('sys_account_notifications', 'system', 'invoices', '_sys_menu_item_title_system_invoices', '_sys_menu_item_title_invoices', 'invoices.php', '', '', 'file-invoice col-green3', 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:18:"get_invoices_count";s:6:"params";a:1:{i:0;s:6:"unpaid";}s:5:"class";s:21:"TemplPaymentsServices";}', '', 2147483646, 0, 1, 8),
 ('sys_account_notifications', 'system', 'logout', '_sys_menu_item_title_system_logout', '_sys_menu_item_title_logout', 'logout.php', '', '', 'sign-out-alt', '', '', 2147483646, 1, 1, 9999);
 
 -- account settings menu
@@ -4190,8 +4191,9 @@ INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `tit
 -- account dashboard
 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', 'system', 'dashboard', '_sys_menu_item_title_system_account_dashboard', '_sys_menu_item_title_account_dashboard', 'page.php?i=dashboard', '', '', 'tachometer-alt', '', '', 2147483646, 1, 1, 1),
-('sys_account_dashboard', 'system', 'dashboard-subscriptions', '_sys_menu_item_title_system_subscriptions', '_sys_menu_item_title_subscriptions', 'subscriptions.php', '', '', 'money col-blue3', '', '', 2147483646, 1, 1, 2),
-('sys_account_dashboard', 'system', 'dashboard-orders', '_sys_menu_item_title_system_orders', '_sys_menu_item_title_orders', 'orders.php', '', '', 'cart-arrow-down col-green3', '', '', 2147483646, 1, 1, 3);
+('sys_account_dashboard', 'system', 'dashboard-subscriptions', '_sys_menu_item_title_system_subscriptions', '_sys_menu_item_title_subscriptions', 'subscriptions.php', '', '', 'credit-card col-blue3', '', '', 2147483646, 1, 1, 2),
+('sys_account_dashboard', 'system', 'dashboard-orders', '_sys_menu_item_title_system_orders', '_sys_menu_item_title_orders', 'orders.php', '', '', 'cart-arrow-down col-green3', '', '', 2147483646, 1, 1, 3),
+('sys_account_dashboard', 'system', 'dashboard-invoices', '_sys_menu_item_title_system_invoices', '_sys_menu_item_title_invoices', 'invoices.php', '', '', 'file-invoice col-green3', '', '', 2147483646, 1, 1, 4);
 
 -- comment manage menu
 INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES
@@ -5202,7 +5204,8 @@ CREATE TABLE `sys_objects_live_updates` (
 
 INSERT INTO `sys_objects_live_updates`(`name`, `init`, `frequency`, `service_call`, `active`) VALUES
 ('sys_payments_cart', 0, 1, 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:21:"get_live_updates_cart";s:6:"params";a:3:{i:0;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:7:"account";}i:1;a:2:{s:11:"menu_object";s:25:"sys_account_notifications";s:9:"menu_item";s:4:"cart";}i:2;s:7:"{count}";}s:5:"class";s:21:"TemplPaymentsServices";}', 1),
-('sys_payments_orders', 0, 1, 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:23:"get_live_updates_orders";s:6:"params";a:3:{i:0;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:7:"account";}i:1;a:2:{s:11:"menu_object";s:25:"sys_account_notifications";s:9:"menu_item";s:6:"orders";}i:2;s:7:"{count}";}s:5:"class";s:21:"TemplPaymentsServices";}', 1);
+('sys_payments_orders', 0, 1, 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:23:"get_live_updates_orders";s:6:"params";a:3:{i:0;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:7:"account";}i:1;a:2:{s:11:"menu_object";s:25:"sys_account_notifications";s:9:"menu_item";s:6:"orders";}i:2;s:7:"{count}";}s:5:"class";s:21:"TemplPaymentsServices";}', 1),
+('sys_payments_invoices', 0, 1, 'a:4:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_live_updates_invoices";s:6:"params";a:3:{i:0;a:2:{s:11:"menu_object";s:18:"sys_toolbar_member";s:9:"menu_item";s:7:"account";}i:1;a:2:{s:11:"menu_object";s:25:"sys_account_notifications";s:9:"menu_item";s:8:"invoices";}i:2;s:7:"{count}";}s:5:"class";s:21:"TemplPaymentsServices";}', 1);
 
 -- --------------------------------------------------------
 

+ 24 - 0
invoices.php

@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+require_once('./inc/header.inc.php');
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+bx_import('BxDolLanguages');
+
+check_logged();
+
+$sUrl = BxDolPayments::getInstance()->getInvoicesUrl();
+if(empty($sUrl))
+    BxDolTemplate::getInstance()->displayPageNotFound();
+
+header('Location: ' . $sUrl);
+exit;
+
+/** @} */

+ 81 - 0
modules/base/payment/classes/BxBaseModPaymentCommissions.php

@@ -0,0 +1,81 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxBaseModPaymentCommissions extends BxDol
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    function __construct()
+    {
+        parent::__construct();
+
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_base_payment Base Payment
+     * @subsection bx_base_payment-integration Integration
+     * @subsubsection bx_base_payment-get_invoices_url get_invoices_url
+     * 
+     * @code bx_srv('bx_payment', 'get_invoices_url', [...], 'Commissions'); @endcode
+     * 
+     * Get invoices page URL.
+     *
+     * @return string with invoices page URL.
+     * 
+     * @see BxBaseModPaymentOrders::serviceGetOrdersUrl
+     */
+    /** 
+     * @ref bx_base_payment-get_invoices_url "get_invoices_url"
+     */
+    public function serviceGetInvoicesUrl()
+    {
+    	if(!$this->_oModule->isLogged())
+            return '';
+
+    	return $this->_oModule->_oConfig->getUrl('URL_INVOICES');
+    }
+    
+    /**
+     * @page service Service Calls
+     * @section bx_base_payment Base Payment
+     * @subsection bx_base_payment-integration Integration
+     * @subsubsection bx_base_payment-get_invoices_count get_invoices_count
+     * 
+     * @code bx_srv('bx_payment', 'get_invoices_count', [...], 'Commissions'); @endcode
+     * 
+     * Get invoices count by type.
+     *
+     * @param $sType string value with type.
+     * @param $iProfileId (optional) integer value with profile ID. If empty value is provided then currently logged in profile will be used.
+     * @return integer value with invoices count.
+     * 
+     * @see BxBaseModPaymentOrders::serviceGetOrdersCount
+     */
+    /** 
+     * @ref bx_base_payment-get_invoices_count "get_invoices_count"
+     */
+    public function serviceGetInvoicesCount($sType, $iProfileId = 0)
+    {
+        if(!in_array($sType, array('unpaid', 'overdue')))
+            return 0;
+
+    	$iProfileId = !empty($iProfileId) ? $iProfileId : $this->_oModule->getProfileId();
+        if(empty($iProfileId))
+            return 0;
+
+        return $this->_oModule->_oDb->getInvoices(array('type' => 'status', 'status' => $sType, 'committent_id' => $iProfileId, 'count' => true));
+    }
+}
+
+/** @} */

+ 31 - 6
modules/base/payment/classes/BxBaseModPaymentConfig.php

@@ -30,6 +30,14 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
         parent::__construct($aModule);
 
         $this->CNF = array_merge($this->CNF, array(
+            // some params
+            'PARAM_CMSN_INVOICE_ISSUE_DAY' => 12, //the first day of month
+            'PARAM_CMSN_INVOICE_LIFETIME' => 4, //in days
+            'PARAM_CMSN_INVOICE_EXPIRATION_NOTIFY' => 1, //in days, before expiration date
+            'PARAM_CMSN_DATE_FORMAT' => 'd.m.Y',
+            'PARAM_CMSN_DATE_TIME_FORMAT' => 'd.m.Y H:i',
+
+            // objects
             'OBJECT_FORM_PRELISTS_CURRENCIES' => '',
 
             'KEY_SESSION_PENDING' => $this->_sName . '_pending_id',
@@ -49,8 +57,13 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
         $this->_aObjects = array_merge($this->_aObjects, array(
             'form_pendings' => $this->_sName . '_form_pendings',
             'form_processed' => $this->_sName . '_form_processed',
-            'display_pendings_process' => $this->_sName . '_form_pendings_process',
-            'display_processed_add' => $this->_sName . '_form_processed_add',
+            'form_display_pendings_process' => $this->_sName . '_form_pendings_process',
+            'form_display_processed_add' => $this->_sName . '_form_processed_add',
+            'form_commissions' => $this->_sName . '_form_commissions',
+            'form_display_commissions_add' => $this->_sName . '_form_commissions_add',
+            'form_display_commissions_edit' => $this->_sName . '_form_commissions_edit',
+            'form_invoices' => $this->_sName . '_form_invoices',
+            'form_display_invoices_edit' => $this->_sName . '_form_invoices_edit',
 
             'menu_dashboard' => 'sys_account_dashboard',
             'menu_cart_submenu' => $this->_sName . '_menu_cart_submenu',
@@ -62,6 +75,8 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
             'grid_history' => $this->_sName . '_grid_orders_history',
             'grid_processed' => $this->_sName . '_grid_orders_processed',
             'grid_pending' => $this->_sName . '_grid_orders_pending',
+            'grid_commissions' => $this->_sName . '_grid_commissions',
+            'grid_invoices' => $this->_sName . '_grid_invoices',
             'grid_carts' => $this->_sName . '_grid_carts',
             'grid_cart' => $this->_sName . '_grid_cart',
             'grid_sbs_list_my' => $this->_sName . '_grid_sbs_list_my',
@@ -141,7 +156,7 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
     	return $bSsl ? $this->http2https($sResult) : $sResult;
     }
 
-	public function getDivider($sType)
+    public function getDivider($sType)
     {
     	$sResult = '';
     	if(empty($sType) || !isset($this->CNF[$sType]))
@@ -150,7 +165,7 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
         return $this->CNF[$sType];
     }
 
-	public function getPerPage($sType = 'default')
+    public function getPerPage($sType = 'default')
     {
     	if(empty($sType))
             return $this->_aPerPage;
@@ -158,7 +173,7 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
         return isset($this->_aPerPage[$sType]) ? $this->_aPerPage[$sType] : '';
     }
 
-	public function getHtmlIds($sType, $sKey = '')
+    public function getHtmlIds($sType, $sKey = '')
     {
         if(empty($sKey))
             return isset($this->_aHtmlIds[$sType]) ? $this->_aHtmlIds[$sType] : array();
@@ -171,7 +186,7 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
         return $this->_sAnimationEffect;
     }
 
-	public function getAnimationSpeed()
+    public function getAnimationSpeed()
     {
         return $this->_iAnimationSpeed;
     }
@@ -197,6 +212,16 @@ class BxBaseModPaymentConfig extends BxBaseModGeneralConfig
 
         return $sResult;
     }
+
+    public function formatDate($iTs)
+    {
+        return gmdate($this->CNF['PARAM_CMSN_DATE_FORMAT'], $iTs);
+    }
+
+    public function formatDateTime($iTs)
+    {
+        return gmdate($this->CNF['PARAM_CMSN_DATE_TIME_FORMAT'], $iTs);
+    }
 }
 
 /** @} */

+ 54 - 0
modules/base/payment/classes/BxBaseModPaymentGridCommissions.php

@@ -0,0 +1,54 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxBaseModPaymentGridCommissions extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_sLangsPrefix;
+
+    protected $_aAclLevels;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+
+        $this->_aAclLevels = BxDolAcl::getInstance()->getMemberships(false, true, true, true);
+    }
+
+    protected function _getCellAclId($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = isset($this->_aAclLevels[$mixedValue]) > 0 ? $this->_aAclLevels[$mixedValue] : _t('_all');
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellPercentage($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = (float)$mixedValue > 0 ? $mixedValue . '%' : '';
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellInstallment($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = (float)$mixedValue > 0 ? _t_format_currency($mixedValue) : '';
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+}
+
+/** @} */

+ 158 - 0
modules/base/payment/classes/BxBaseModPaymentGridInvoices.php

@@ -0,0 +1,158 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    BasePayment Base classes for Payment like modules
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxBaseModPaymentGridInvoices extends BxTemplGrid
+{
+    protected $_sModule;
+    protected $_oModule;
+    protected $_oPayment;
+
+    protected $_sLangsPrefix;
+    protected $_aJsCodes;
+
+    protected $_bAllowManage;
+    protected $_iMainSeller;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+        $this->_oPayment = BxDolPayments::getInstance();
+
+        $this->_sLangsPrefix = $this->_oModule->_oConfig->getPrefix('langs');
+        $this->_aJsCodes = array();
+
+        $this->_bAllowManage = $this->_oModule->isAllowedManageInvoices() === true;
+        if(!$this->_bAllowManage) {
+            $iProfileId = bx_get('profile_id');
+            $this->_aQueryAppend['profile_id'] = $iProfileId !== false ? (int)$iProfileId : bx_get_logged_profile_id();
+        }
+
+        $this->_iMainSeller = $this->_oModule->_oConfig->getSiteAdmin();
+    }
+
+    public function getCode($isDisplayHeader = true)
+    {
+    	return parent::getCode($isDisplayHeader) . $this->getJsCode();
+    }
+
+    public function getJsCode()
+    {
+        if(empty($this->_aJsCodes) || !is_array($this->_aJsCodes))
+            return '';
+
+        return implode('', $this->_aJsCodes);
+    }
+
+    protected function _getActionEdit ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!$this->_bAllowManage)
+            return '';
+    
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!$this->_bAllowManage)
+            return '';
+    
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionPay ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if($aRow['committent_id'] != bx_get_logged_profile_id() || (float)$aRow['amount'] == 0 || $aRow['status'] == BX_PAYMENT_INV_STATUS_PAID)
+            return '';
+
+    	$aJs = $this->_oPayment->getAddToCartJs($this->_iMainSeller, $this->_sModule, $aRow['id'], 1, true);
+    	if(!empty($aJs) && is_array($aJs)) {
+            list($sJsCode, $sJsMethod) = $aJs;
+
+            $sJsCodeCheckSum = md5($sJsCode);
+            if(!isset($this->_aJsCodes[$sJsCodeCheckSum]))
+                $this->_aJsCodes[$sJsCodeCheckSum] = $sJsCode;
+
+            $a['attr'] = array(
+                'title' => bx_html_attribute(_t('_bx_payment_grid_action_title_inv_pay')),
+                'onclick' => $sJsMethod
+            );
+    	}
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getCellHeaderCommissionaireId ($sKey, $aField)
+    {
+        if(!$this->_bAllowManage)
+            return '';
+
+        return parent::_getCellHeaderDefault($sKey, $aField);
+    }
+
+    protected function _getCellCommissionaireId($mixedValue, $sKey, $aField, $aRow)
+    {
+        if(!$this->_bAllowManage)
+            return '';
+
+        return parent::_getCellDefault($this->_oModule->_oTemplate->displayProfileLink($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellCommittentId($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->_oTemplate->displayProfileLink($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellPeriodStart($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->_oConfig->formatDate($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellPeriodEnd($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->_oModule->_oConfig->formatDate($mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellDateIssue($mixedValue, $sKey, $aField, $aRow)
+    {
+        return $this->_getCellDefaultDate($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellDateDue($mixedValue, $sKey, $aField, $aRow)
+    {
+        return $this->_getCellDefaultDate($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellStatus($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(_t('_bx_payment_txt_status_' . $mixedValue), $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellDefaultDate($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault(bx_time_js($mixedValue, BX_FORMAT_DATE, true), $sKey, $aField, $aRow);
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        if(!$this->_bAllowManage) {
+            if(empty($this->_aQueryAppend['profile_id']))
+                return array();
+
+            $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(" AND `committent_id`=?", $this->_aQueryAppend['profile_id']);
+        }
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+}
+
+/** @} */

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

@@ -2622,6 +2622,7 @@ If it is not enabled then please consider implement this optimization, since it
     <string name="_sys_menu_item_title_cmts_item_more"><![CDATA[]]></string>
     <string name="_sys_menu_item_title_dashboard"><![CDATA[Dash]]></string>
     <string name="_sys_menu_item_title_home"><![CDATA[Home]]></string>
+    <string name="_sys_menu_item_title_invoices"><![CDATA[Invoices]]></string>
     <string name="_sys_menu_item_title_logout"><![CDATA[Sign out]]></string>
     <string name="_sys_menu_item_title_more"><![CDATA[More]]></string>
     <string name="_sys_menu_item_title_more_auto"><![CDATA[More]]></string>
@@ -2695,6 +2696,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_menu_item_title_system_cmts_item_more"><![CDATA[More]]></string>
 	<string name="_sys_menu_item_title_system_dashboard"><![CDATA[Dashboard]]></string>
 	<string name="_sys_menu_item_title_system_home"><![CDATA[Home]]></string>
+        <string name="_sys_menu_item_title_system_invoices"><![CDATA[Invoices]]></string>
 	<string name="_sys_menu_item_title_system_login"><![CDATA[Log in]]></string>
 	<string name="_sys_menu_item_title_system_logout"><![CDATA[Log out]]></string>
 	<string name="_sys_menu_item_title_system_main_menu"><![CDATA[Main Menu]]></string>

+ 49 - 0
modules/boonex/payment/classes/BxPaymentCommissions.php

@@ -0,0 +1,49 @@
+<?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 BxPaymentCommissions extends BxBaseModPaymentCommissions
+{
+    public function __construct()
+    {   
+        $this->_sModule = 'bx_payment';
+
+        parent::__construct();
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_payment Payment
+     * @subsection bx_payment-page_blocks Page Blocks
+     * @subsubsection bx_payment-get_block_invoices get_block_invoices
+     * 
+     * @code bx_srv('bx_payment', 'get_block_invoices', [...], 'Details'); @endcode
+     * 
+     * Get page block with a list of invoices.
+     *
+     * @return an array describing a block to display on the site. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxPaymentDetails::serviceGetBlockDetails
+     */
+    /** 
+     * @ref bx_payment-get_block_invoices "get_block_invoices"
+     */
+    public function serviceGetBlockInvoices($iUserId = BX_PAYMENT_EMPTY_ID)
+    {
+        if(!$this->_oModule->isLogged())
+            return MsgBox(_t($this->_sLangsPrefix . 'err_required_login'));
+
+        $this->_oModule->setSiteSubmenu('menu_dashboard', 'system', 'dashboard-invoices');
+
+        return $this->_oModule->_oTemplate->displayBlockInvoices();
+    }
+}
+
+/** @} */

+ 14 - 1
modules/boonex/payment/classes/BxPaymentConfig.php

@@ -26,6 +26,10 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
             // module icon
             'ICON' => 'credit-card col-gray-dark',
 
+            // database tables
+            'TABLE_COMMISSIONS' => $aModule['db_prefix'] . 'commissions',
+            'TABLE_INVOICES' => $aModule['db_prefix'] . 'invoices',
+
             // page URIs
             'URL_JOIN' => 'page.php?i=payment-join',
             'URL_CARTS' => 'page.php?i=payment-carts',
@@ -36,15 +40,17 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
             'URL_SUBSCRIPTIONS' => 'page.php?i=payment-sbs-list-my',
             'URL_HISTORY' => 'page.php?i=payment-history',
             'URL_ORDERS' => 'page.php?i=payment-orders',
+            'URL_INVOICES' => 'page.php?i=payment-invoices',
             'URL_DETAILS' => 'page.php?i=payment-details',
             'URL_RETURN' => 'page.php?i=payment-cart-thank-you',
             'URL_RETURN_DATA' => $sBaseUrl . 'finalize_checkout/',
             'URL_NOTIFY' => $sBaseUrl . 'notify/',
-
+            
             'KEY_ARRAY_PRICE_SINGLE' => 'price_single',
             'KEY_ARRAY_PRICE_RECURRING' => 'price_recurring',
             'KEY_ARRAY_TRIAL_RECURRING' => 'trial_recurring',
 
+            // objects
             'OBJECT_FORM_PRELISTS_CURRENCIES' => 'bx_payment_currencies',
             'OBJECT_PP_CREDITS' => 'credits', //Credits payment provider
 
@@ -97,6 +103,13 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
                 '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(

+ 31 - 0
modules/boonex/payment/classes/BxPaymentCronCommissions.php

@@ -0,0 +1,31 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentCronCommissions extends BxDolCron
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct()
+    {
+        parent::__construct();
+
+    	$this->_sModule = 'bx_payment';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+    }
+
+    function processing()
+    {
+        $this->_oModule->processCommissions();
+    }
+}
+
+/** @} */

+ 212 - 3
modules/boonex/payment/classes/BxPaymentDb.php

@@ -340,7 +340,7 @@ class BxPaymentDb extends BxBaseModPaymentDb
     	$aMethod = array('name' => 'getRow', 'params' => array(0 => 'query'));
 
         $sSelectClause = "`tt`.`id`, `tt`.`license`, `ttp`.`type`, `tt`.`client_id`, `tt`.`seller_id`, `tt`.`author_id`, `tt`.`module_id`, `tt`.`item_id`, `tt`.`item_count`, `tt`.`amount`, `tt`.`date`, `ttp`.`order`, `ttp`.`error_msg`, `ttp`.`provider`";
-        $sWhereClause = "";
+        $sWhereClause = $sGroupClause = "";
 
         switch($aParams['type']) {
             case 'id':
@@ -401,11 +401,23 @@ class BxPaymentDb extends BxBaseModPaymentDb
             case 'license':
                 $aMethod['name'] = 'getAll';
                 $aMethod['params'][1] = array(
-                	'license' => $aParams['license']
+                    'license' => $aParams['license']
                 );
 
                 $sWhereClause = " AND `tt`.`license`=:license";
                 break;
+            
+            case 'income':
+                $aMethod['name'] = 'getAll';
+                $aMethod['params'][1] = array(
+                    'period_start' => $aParams['period_start'],
+                    'period_end' => $aParams['period_end']
+                );
+
+                $sSelectClause = '`tt`.`author_id` AS `id`, SUM(`tt`.`amount`) AS `amount`';
+                $sWhereClause = ' AND `tt`.`date`>=:period_start AND `tt`.`date`<=:period_end';
+                $sGroupClause = '`tt`.`author_id`';
+                break;
 
             case 'mixed':
                 $aMethod['name'] = 'getAll';
@@ -415,11 +427,14 @@ class BxPaymentDb extends BxBaseModPaymentDb
 
         }
 
+        if(!empty($sGroupClause))
+            $sGroupClause = ' GROUP BY ' . $sGroupClause;
+
         $aMethod['params'][0] = "SELECT
                 " . $sSelectClause . "
             FROM `" . $this->_sPrefix . "transactions` AS `tt`
             LEFT JOIN `" . $this->_sPrefix . "transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id`
-            WHERE 1" . $sWhereClause;
+            WHERE 1" . $sWhereClause . $sGroupClause;
 
         return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
     }
@@ -562,6 +577,200 @@ class BxPaymentDb extends BxBaseModPaymentDb
     	$sQuery = $this->prepare("DELETE FROM `" . $this->_sPrefix . "user_values` WHERE `user_id`=?", $iId);
     	$this->query($sQuery);
     }
+
+
+    /*
+     * Commissions methods
+     */
+    public function getCommissions($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`tc`.*";
+        $sWhereClause = $sOrderClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'max_order':
+                    $aMethod['name'] = 'getOne';
+                    $aMethod['params'][1] = array();
+
+                    $sSelectClause = "IFNULL(MAX(`tc`.`order`), 0)";
+                    break;
+
+                case 'id':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'id' => $aParams['id']
+                    );
+
+                    $sWhereClause = " AND `tc`.`id`=:id";
+                    break;
+
+                case 'acl_id':
+                    $aMethod['name'] = 'getAll';
+                    $aMethod['params'][1] = array(
+                        'acl_id' => $aParams['acl_id']
+                    );
+
+                    $sWhereClause = " AND (`tc`.`acl_id`=:acl_id OR `tc`.`acl_id`=0)";
+                    $sOrderClause = "`tc`.`order` ASC";
+                    break;
+
+                case 'all':
+                    if(!empty($aParams['active'])) 
+                        $sWhereClause = " AND `tc`.`active`='1'";
+                    break;
+            }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = " ORDER BY " . $sOrderClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_COMMISSIONS'] . "` AS `tc`
+            WHERE 1" . $sWhereClause . $sOrderClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function getInvoices($aParams = array())
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
+
+        $sSelectClause = "`ti`.*";
+        $sWhereClause = "";
+        if(!empty($aParams['type']))
+            switch($aParams['type']) {
+                case 'index':
+                    $aMethod['name'] = 'getOne';
+                    $aMethod['params'][1] = array(
+                        'commissionaire_id' => $aParams['commissionaire_id'],
+                        'committent_id' => $aParams['committent_id'],
+                    );
+
+                    $sSelectClause = "COUNT(`ti`.`id`) + 1";
+                    $sWhereClause = " AND `ti`.`commissionaire_id`=:commissionaire_id AND `ti`.`committent_id`=:committent_id";
+                    break;
+
+                case 'id':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = array(
+                        'id' => $aParams['id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`id`=:id";
+                    break;
+
+                case 'commissionaire_id':
+                    $aMethod['params'][1] = array(
+                        'commissionaire_id' => $aParams['commissionaire_id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`commissionaire_id`=:commissionaire_id";
+                    break;
+
+                case 'committent_id':
+                    $aMethod['params'][1] = array(
+                        'committent_id' => $aParams['committent_id']
+                    );
+
+                    $sWhereClause = " AND `ti`.`committent_id`=:committent_id";
+
+                    if(!empty($aParams['period_start'])) {
+                        $aMethod['params'][1]['period_start'] = (int)$aParams['period_start'];
+
+                        $sWhereClause .= " AND `ti`.`period_start`=:period_start";
+                    }
+
+                    if(!empty($aParams['period_end'])) {
+                        $aMethod['params'][1]['period_end'] = (int)$aParams['period_end'];
+
+                        $sWhereClause .= " AND `ti`.`period_end`=:period_end";
+                    }
+                    break;
+
+                case 'expiring':
+                    $aMethod['params'][1] = array(
+                        'notify_days' => $CNF['PARAM_CMSN_INVOICE_EXPIRATION_NOTIFY'],
+                        'status' => BX_PAYMENT_INV_STATUS_UNPAID
+                    );
+
+                    $sWhereClause = " AND DATE_SUB(FROM_UNIXTIME(`ti`.`date_due`), INTERVAL :notify_days DAY) < NOW() AND DATE_SUB(FROM_UNIXTIME(`ti`.`date_due`), INTERVAL (:notify_days - 1) DAY) > NOW() AND `ti`.`status`=:status";
+                    break;
+
+                case 'overdue':
+                    $aMethod['params'][1] = array(
+                        'status_unpaid' => BX_PAYMENT_INV_STATUS_UNPAID,
+                        'status_overdue' => BX_PAYMENT_INV_STATUS_OVERDUE
+                    );
+
+                    $sWhereClause = " AND `ti`.`date_due` < UNIX_TIMESTAMP() AND (`ti`.`status`=:status_unpaid OR (`ti`.`status`=:status_overdue AND `ti`.`ntf_due`='0'))";
+                    break;
+
+                case 'status':
+                    $aMethod['params'][1] = array(
+                        'status' => $aParams['status']
+                    );
+
+                    $sWhereClause = " AND `ti`.`status`=:status";
+                    
+                    if(isset($aParams['count']) && $aParams['count'] === true) {
+                        $sSelectClause = "COUNT(`ti`.`id`)";
+                        $aMethod['name'] = 'getOne';
+                    }
+
+                    if(isset($aParams['committent_id'])) {
+                        $aMethod['params'][1]['committent_id'] = $aParams['committent_id'];
+
+                        $sWhereClause .= " AND `ti`.`committent_id`=:committent_id";
+                    }
+                    break;
+
+                case 'all_count':
+                    $sSelectClause = "COUNT(`ti`.`id`)";
+                    $aMethod['name'] = 'getOne';
+                    break;
+                
+                case 'all':
+                    break;
+            }
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . "
+            FROM `" . $CNF['TABLE_INVOICES'] . "` AS `ti`
+            WHERE 1" . $sWhereClause;
+
+        return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+
+    public function insertInvoice($aValues)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        return $this->query("INSERT INTO `" . $CNF['TABLE_INVOICES'] . "` SET " . $this->arrayToSQL($aValues));
+    }
+
+    public function updateInvoice($mixedId, $aValues)
+    {
+        $CNF = &$this->_oConfig->CNF;
+        
+        if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("UPDATE `" . $CNF['TABLE_INVOICES'] . "` SET " . $this->arrayToSQL($aValues) . " WHERE `id` IN (" . $this->implode_escape($mixedId) . ')') > 0;
+    }
+
+    public function deleteInvoice($mixedId)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+    	if(!is_array($mixedId))
+            $mixedId = array($mixedId);
+
+        return (int)$this->query("DELETE FROM `" . $CNF['TABLE_INVOICES'] . "` WHERE `id` IN (" . $this->implode_escape($mixedId) . ")") > 0;
+    }
 }
 
 /** @} */

+ 36 - 0
modules/boonex/payment/classes/BxPaymentFormCommissions.php

@@ -0,0 +1,36 @@
+<?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 BxPaymentFormCommissions extends BxTemplStudioFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+        
+        $this->_sModule = 'bx_payment';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        if(isset($this->aInputs['acl_id'])) {
+            $this->aInputs['acl_id']['values'] = array(
+                array('key' => '0', 'value' => _t('_Select_one'))
+            );
+
+            $aLevels = BxDolAcl::getInstance()->getMemberships(false, true, false, true);
+            foreach($aLevels as $iLevelId => $sLevelTitle)
+               $this->aInputs['acl_id']['values'][] = array('key' => $iLevelId, 'value' => _t($sLevelTitle));
+        }
+    }
+}
+
+/** @} */

+ 34 - 0
modules/boonex/payment/classes/BxPaymentFormInvoices.php

@@ -0,0 +1,34 @@
+<?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 BxPaymentFormInvoices extends BxTemplFormView
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    function __construct($aInfo, $oTemplate = false)
+    {
+        parent::__construct($aInfo, $oTemplate);
+
+        $this->_sModule = 'bx_payment';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        if(isset($this->aInputs['status'])) {
+            $aStatuses = array(BX_PAYMENT_INV_STATUS_UNPAID, BX_PAYMENT_INV_STATUS_PAID, BX_PAYMENT_INV_STATUS_OVERDUE);
+
+            $this->aInputs['status']['values'] = array();
+            foreach($aStatuses as $sStatus)
+                $this->aInputs['status']['values'][] = array('key' => $sStatus, 'value' => _t('_bx_payment_txt_status_' . $sStatus));
+        }
+    }
+}
+
+/** @} */

+ 6 - 6
modules/boonex/payment/classes/BxPaymentFormView.php

@@ -11,15 +11,15 @@
 
 class BxPaymentFormView extends BxTemplStudioFormView
 {
-	function __construct($aInfo, $oTemplate = false)
+    function __construct($aInfo, $oTemplate = false)
     {
         parent::__construct($aInfo, $oTemplate);
     }
-	
-	protected function genCustomInputClient ($aInput)
-	{
-		return parent::genCustomInputUsernamesSuggestions ($aInput);
-	}
+
+    protected function genCustomInputClient ($aInput)
+    {
+        return parent::genCustomInputUsernamesSuggestions ($aInput);
+    }
 }
 
 /** @} */

+ 140 - 0
modules/boonex/payment/classes/BxPaymentGridCommissions.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    Payment Payment
+ * @ingroup     UnaModules
+ * 
+ * @{
+ */
+
+class BxPaymentGridCommissions extends BxBaseModPaymentGridCommissions
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+    }
+
+    public function performActionAdd()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $sAction = 'add';
+
+        $oForm = $this->_getFormObject($sAction);
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $sFormMethod = $oForm->aFormAttrs['method'];
+
+            $sLanguage = BxDolStudioLanguagesUtils::getInstance()->getCurrentLangName(false);
+
+            $sName = BxDolForm::getSubmittedValue('caption-' . $sLanguage, $sFormMethod);
+            $sName = uriGenerate(strtolower($sName), $CNF['TABLE_COMMISSIONS'], 'name', 'commission');
+
+            $aValsToAdd = array(
+                'name' => $sName,
+                'active' => 1,
+                'order' => $this->_oModule->_oDb->getCommissions(array('type' => 'max_order')) + 1
+            );
+
+            if(($iId = $oForm->insert($aValsToAdd)) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_payment_err_cannot_perform'));
+
+            return echoJson($aRes);
+        }
+
+        $sId = $this->_oModule->_oConfig->getHtmlIds('commission', 'popup_' . $sAction);
+        $sTitle = _t($this->_sLangsPrefix . 'popup_title_cms_' . $sAction);
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('commission_form.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    public function performActionEdit()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId)
+                return echoJson(array());
+
+            $aIds = array($iId);
+        }
+
+        $iId = (int)array_shift($aIds);
+        $aCommission = $this->_oModule->_oDb->getCommissions(array('type' => 'id', 'id' => $iId));
+        if(empty($aCommission) || !is_array($aCommission))
+            return echoJson(array());
+
+        $sAction = 'edit';
+
+        $oForm = $this->_getFormObject($sAction, $iId);
+        $oForm->initChecker($aCommission);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iId) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_payment_err_cannot_perform'));
+
+            return echoJson($aRes);
+        }
+
+        $sId = $this->_oModule->_oConfig->getHtmlIds('commission', 'popup_' . $sAction);
+        $sTitle = _t($this->_sLangsPrefix . 'popup_title_cms_' . $sAction);
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('commission_form.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    protected function _delete($mixedId)
+    {
+        $aCommission = $this->_oModule->_oDb->getCommissions(array('type' => 'id', 'id' => $mixedId));
+        if(empty($aCommission) || !is_array($aCommission))
+            return false;
+
+        $mixedResult = parent::_delete($mixedId);
+        if($mixedResult !== false) {
+            $oLanguage = BxDolStudioLanguagesUtils::getInstance();
+            $oLanguage->deleteLanguageString($aCommission['caption']);
+            $oLanguage->deleteLanguageString($aCommission['description']);
+        }
+
+        return $mixedResult;
+    }
+
+    protected function _getFormObject($sAction, $iId = 0)
+    {
+        $sFormObject = $this->_oModule->_oConfig->getObject('form_commissions');
+        $sFormDisplay = $this->_oModule->_oConfig->getObject('form_display_commissions_' . $sAction);
+
+        $aParams = array('o' => $this->_sObject, 'a' => $sAction);
+        if(!empty($iId))
+            $aParams['id'] = $iId;
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . bx_append_url_params('grid.php', $aParams);
+
+        return $oForm;
+    }
+}
+
+/** @} */

+ 81 - 0
modules/boonex/payment/classes/BxPaymentGridInvoices.php

@@ -0,0 +1,81 @@
+<?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 BxPaymentGridInvoices extends BxBaseModPaymentGridInvoices
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_payment';
+
+        parent::__construct ($aOptions, $oTemplate);
+    }
+
+    public function performActionEdit()
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aIds = bx_get('ids');
+        if(!$aIds || !is_array($aIds)) {
+            $iId = (int)bx_get('id');
+            if(!$iId)
+                return echoJson(array());
+
+            $aIds = array($iId);
+        }
+
+        $iId = (int)array_shift($aIds);
+        $aInvoice = $this->_oModule->_oDb->getInvoices(array('type' => 'id', 'id' => $iId));
+        if(empty($aInvoice) || !is_array($aInvoice))
+            return echoJson(array());
+
+        $sAction = 'edit';
+
+        $oForm = $this->_getFormObject($sAction, $iId);
+        $oForm->initChecker($aInvoice);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($iId) !== false)
+                $aRes = array('grid' => $this->getCode(false), 'blink' => $iId);
+            else
+                $aRes = array('msg' => _t('_bx_payment_err_cannot_perform'));
+
+            return echoJson($aRes);
+        }
+
+        $sId = $this->_oModule->_oConfig->getHtmlIds('invoice', 'popup_' . $sAction);
+        $sTitle = _t($this->_sLangsPrefix . 'popup_title_cms_' . $sAction);
+
+        $sContent = BxTemplStudioFunctions::getInstance()->popupBox($sId, $sTitle, $this->_oModule->_oTemplate->parseHtmlByName('commission_form.html', array(
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        )));
+
+        echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => false))));
+    }
+
+    protected function _getFormObject($sAction, $iId = 0)
+    {
+        $sFormObject = $this->_oModule->_oConfig->getObject('form_invoices');
+        $sFormDisplay = $this->_oModule->_oConfig->getObject('form_display_invoices_' . $sAction);
+
+        $aParams = array('o' => $this->_sObject, 'a' => $sAction);
+        if(!empty($iId))
+            $aParams['id'] = $iId;
+
+        $oForm = BxDolForm::getObjectInstance($sFormObject, $sFormDisplay);
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . bx_append_url_params('grid.php', $aParams);
+
+        return $oForm;
+    }
+}
+
+/** @} */

+ 1 - 1
modules/boonex/payment/classes/BxPaymentGridPending.php

@@ -36,7 +36,7 @@ class BxPaymentGridPending extends BxBaseModPaymentGridOrders
 
     	$sAction = 'process';
         $sFormObject = $this->_oModule->_oConfig->getObject('form_pendings');
-        $sFormDisplay = $this->_oModule->_oConfig->getObject('display_pendings_process');
+        $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;

+ 1 - 1
modules/boonex/payment/classes/BxPaymentGridProcessed.php

@@ -30,7 +30,7 @@ class BxPaymentGridProcessed extends BxBaseModPaymentGridOrders
         $sJsObject = $this->_oModule->_oConfig->getJsObject('processed');
 
         $sFormObject = $this->_oModule->_oConfig->getObject('form_processed');
-        $sFormDisplay = $this->_oModule->_oConfig->getObject('display_processed_add');
+        $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;

+ 386 - 16
modules/boonex/payment/classes/BxPaymentModule.php

@@ -37,6 +37,13 @@ define('BX_PAYMENT_SBS_PU_DAY', 'day');
 define('BX_PAYMENT_SBS_PU_HOUR', 'hour');
 define('BX_PAYMENT_SBS_PU_MINUTE', 'minute');
 
+/*
+ * Invoice: statuses.
+ */
+define('BX_PAYMENT_INV_STATUS_UNPAID', 'unpaid');
+define('BX_PAYMENT_INV_STATUS_PAID', 'paid');
+define('BX_PAYMENT_INV_STATUS_OVERDUE', 'overdue');
+
 
 /**
  * Payment module by BoonEx
@@ -238,22 +245,22 @@ class BxPaymentModule extends BxBaseModPaymentModule
     	$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);
+            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;
+        return $bResult;
     }
 
     /** 
@@ -410,6 +417,17 @@ class BxPaymentModule extends BxBaseModPaymentModule
         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'))
+        );
+    }
+
     /**
      * Cart Processing Methods
      */
@@ -868,7 +886,7 @@ class BxPaymentModule extends BxBaseModPaymentModule
 
     public function onProfileDelete($iProfileId)
     {
-		$this->_oDb->onProfileDelete($iProfileId);
+        $this->_oDb->onProfileDelete($iProfileId);
     }
 
     public function isAllowedPurchase($aItem, $bPerform = false)
@@ -918,11 +936,19 @@ class BxPaymentModule extends BxBaseModPaymentModule
 
         $aCheckResult = checkActionModule($iUserId, 'manage any purchase', $this->getName(), $bPerform);
         if($aCheckResult[CHECK_ACTION_RESULT] == CHECK_ACTION_RESULT_ALLOWED)
-			return true;
+            return true;
 
         return $aCheckResult[CHECK_ACTION_MESSAGE];
     }
 
+    public function isAllowedManageInvoices($bPerform = false)
+    {
+        if(BxDolAcl::getInstance()->isMemberLevelInSet(array(MEMBERSHIP_ID_MODERATOR, MEMBERSHIP_ID_ADMINISTRATOR)) || isAdmin())
+            return true;
+
+        return _t('_sys_txt_access_denied');
+    }
+
     public function checkData($iClientId, $iSellerId, $iModuleId, $iItemId, $iItemCount, $aCustom = array())
     {
     	$CNF = &$this->_oConfig->CNF;
@@ -1070,6 +1096,136 @@ class BxPaymentModule extends BxBaseModPaymentModule
         return $this->getObjectSubscriptions()->cancelLocal($mixedPending);
     }
 
+    public function processCommissions()
+    {
+        if(!defined('BX_DOL_CRON_EXECUTE'))
+            return;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        if((int)date('j') == $CNF['PARAM_CMSN_INVOICE_ISSUE_DAY'])
+            $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 * $CNF['PARAM_CMSN_INVOICE_LIFETIME'];
+
+        $aCommissionsInfo = array();
+        $aAclLevels = BxDolAcl::getInstance()->getMemberships(false, true, false, true);
+        foreach($aAclLevels as $iAclLevelId => $sAclLevelTitle)
+            $aCommissionsInfo[$iAclLevelId] = $this->_oDb->getCommissions(array('type' => 'acl_id', 'acl_id' => $iAclLevelId));
+
+        $iMainSellerId = $this->_oConfig->getSiteAdmin();
+
+        $aVendors = $this->_oDb->getOrderProcessed(array('type' => 'income', 'period_start' => $iPeriodStart, 'period_end' => $iPeriodEnd));
+        foreach($aVendors as $aVendor) {
+            $iVendorId = (int)$aVendor['id'];
+            if($iVendorId == $iMainSellerId)
+                continue;
+
+            $aInvoice = $this->_oDb->getInvoices(array('type' => 'committent_id', 'committent_id' => $iVendorId, 'period_start' => $iPeriodStart, 'period_end' => $iPeriodEnd));
+            if(!empty($aInvoice) && is_array($aInvoice))
+                continue;
+
+            $aVendorAcl = BxDolAcl::getInstance()->getMemberMembershipInfo($iVendorId);
+            $aCommissions = $aCommissionsInfo[$aVendorAcl['id']];
+
+            $fCommission = 0;
+            foreach($aCommissions as $aCommission) {
+                if((float)$aCommission['percentage'] > 0)
+                    $fCommission += (float)$aVendor['amount'] * (float)$aCommission['percentage'] / 100;
+
+                if((float)$aCommission['installment'] > 0)
+                    $fCommission += (float)$aCommission['installment'];
+            }
+
+            $this->_oDb->insertInvoice(array(
+                'name' => sprintf($sInvoiceNameMask, $iMainSellerId, $iVendorId, $this->_oDb->getInvoices(array(
+                    'type' => 'index', 
+                    'commissionaire_id' => $iMainSellerId, 
+                    'committent_id' => $iVendorId
+                ))),
+                'commissionaire_id' => $iMainSellerId, 
+                'committent_id' => $iVendorId,
+                'amount' => $fCommission,
+                'period_start' => $iPeriodStart,
+                'period_end' => $iPeriodEnd,
+                'date_issue' => $iDateIssue,
+                'date_due' => $iDateDue,
+                'status' => BX_PAYMENT_INV_STATUS_UNPAID
+            ));
+        }
+    }
+
+    protected function _invoicesCheck()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $sPrefix = $this->_oConfig->getPrefix('general');
+        $oEmailTemplates = BxDolEmailTemplates::getInstance();
+
+        //--- Process expiring invoices.
+        $aInvoices = $this->_oDb->getInvoices(array('type' => 'expiring'));
+        if(!empty($aInvoices) && is_array($aInvoices))
+            foreach($aInvoices as $aInvoice) {
+                if((int)$aInvoice['ntf_exp'] > 0)
+                    continue;
+
+                $oCommittent = BxDolProfile::getInstance($aInvoice['committent_id']);
+                if(!$oCommittent)
+                    continue;
+
+                $bResult = sendMailTemplate($sPrefix . 'expiring_notification_committent', 0, (int)$aInvoice['committent_id'], array(
+                    'invoice' => $aInvoice['name'],
+                    'days' => $CNF['PARAM_CMSN_INVOICE_EXPIRATION_NOTIFY'],
+                    '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'))
@@ -1233,6 +1389,220 @@ class BxPaymentModule extends BxBaseModPaymentModule
 
         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();
+
+        bx_alert($this->getName(), '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;
+
+        bx_alert($this->getName(), '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;
+    }
+    
 }
 
 /** @} */

+ 26 - 0
modules/boonex/payment/classes/BxPaymentPageInvoices.php

@@ -0,0 +1,26 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Payment Payment
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxPaymentPageInvoices extends BxTemplPage
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_sModule = 'bx_payment';
+        $this->_oModule = BxDolModule::getInstance($this->_sModule);
+    }
+}
+
+/** @} */

+ 13 - 1
modules/boonex/payment/classes/BxPaymentStudioPage.php

@@ -21,7 +21,10 @@ class BxPaymentStudioPage extends BxTemplStudioModule
 
         parent::__construct($sModule, $mixedPageName, $sPage);
 
-        $this->aMenuItems['providers'] = array('name' => 'providers', 'icon' => 'money-bill-alt', 'title' => '_bx_payment_lmi_cpt_providers');
+        $this->aMenuItems = array_merge($this->aMenuItems, array(
+            'providers' => array('name' => 'providers', 'icon' => 'money-bill-alt', 'title' => '_bx_payment_lmi_cpt_providers'),
+            'commissions' => array('name' => 'commissions', 'icon' => 'percent', 'title' => '_bx_payment_lmi_cpt_commissions')
+        ));
     }
 
     protected function getProviders()
@@ -32,6 +35,15 @@ class BxPaymentStudioPage extends BxTemplStudioModule
 
         return $oGrid->getCode();
     }
+
+    protected function getCommissions()
+    {
+        $oGrid = BxDolGrid::getObjectInstance($this->_oModule->_oConfig->getObject('grid_commissions'), BxDolStudioTemplate::getInstance());
+        if(!$oGrid)
+            return '';
+
+        return $oGrid->getCode();
+    }
 }
 
 /** @} */

+ 24 - 7
modules/boonex/payment/classes/BxPaymentTemplate.php

@@ -25,16 +25,17 @@ class BxPaymentTemplate extends BxBaseModPaymentTemplate
     public function addJsCssOrders()
     {
     	$this->addJs(array(
-    		'jquery-ui/jquery.ui.widget.min.js',
-    		'jquery-ui/jquery.ui.menu.min.js', 
-    		'jquery-ui/jquery.ui.autocomplete.min.js', 
-    		'jquery.form.min.js', 
-    		'jquery.anim.js', 
-    		'jquery.webForms.js',
-    		'orders.js'
+            'jquery-ui/jquery.ui.widget.min.js',
+            'jquery-ui/jquery.ui.menu.min.js', 
+            'jquery-ui/jquery.ui.autocomplete.min.js', 
+            'jquery.form.min.js', 
+            'jquery.anim.js', 
+            'jquery.webForms.js',
+            'orders.js'
     	));
     	$this->addCss(array('orders.css'));
     }
+
     public function addJsCssSubscriptions()
     {
         $this->addJs(array('jquery.form.min.js', 'jquery.anim.js', 'jquery.webForms.js', 'main.js', 'subscriptions.js'));
@@ -56,6 +57,11 @@ class BxPaymentTemplate extends BxBaseModPaymentTemplate
     	}
     }
 
+    public function addJsCssInvoices()
+    {
+    	$this->addCss(array('invoices.css'));
+    }
+
     public function displayCartJs($sType = '', $iVendorId = 0)
     {
         $this->addJsCssCart($sType, $iVendorId);
@@ -345,6 +351,17 @@ class BxPaymentTemplate extends BxBaseModPaymentTemplate
         return $this->parseHtmlByName('order_' . $sType . '.html', $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($sType, $aItems = array())
     {
         $aTmplVarsItems = array();

+ 129 - 43
modules/boonex/payment/install/langs/en.xml

@@ -55,8 +55,13 @@
     <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>
+    
     <!-- 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>
@@ -66,6 +71,10 @@
     <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_set_title_cart_submenu"><![CDATA[Cart Submenu]]></string>
@@ -126,6 +135,20 @@
     <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[Installment]]></string>
+    <string name="_bx_payment_grid_column_title_inv_commissionaire_id"><![CDATA[Commissionaire]]></string>
+    <string name="_bx_payment_grid_column_title_inv_committent_id"><![CDATA[Committent]]></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>
@@ -139,55 +162,98 @@
     <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_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>
-
-	<!-- FORMS -->
-	<string name="_bx_payment_form_cart_input_do_delete"><![CDATA[Delete]]></string>
-	<string name="_bx_payment_form_cart_input_do_checkout"><![CDATA[Checkout]]></string>
-	<string name="_bx_payment_form_details_input_do_submit"><![CDATA[Save]]></string>
-
-	<string name="_bx_payment_form_pendings_form"><![CDATA[Pendings Form]]></string>
-	<string name="_bx_payment_form_processed_form"><![CDATA[Processed Form]]></string>
-	<string name="_bx_payment_form_pendings_display_process"><![CDATA[Process Pending Display]]></string>
-	<string name="_bx_payment_form_processed_display_add"><![CDATA[Add Processed Display]]></string>
-	<string name="_bx_payment_form_pendings_input_id_sys"><![CDATA[ID]]></string>
-	<string name="_bx_payment_form_pendings_input_seller_id_sys"><![CDATA[Seller ID]]></string>
-	<string name="_bx_payment_form_pendings_input_order_sys"><![CDATA[Order]]></string>
-	<string name="_bx_payment_form_pendings_input_order"><![CDATA[Order]]></string>
-	<string name="_bx_payment_form_pendings_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
-	<string name="_bx_payment_form_pendings_input_process_sys"><![CDATA[Process]]></string>
-	<string name="_bx_payment_form_pendings_input_process"><![CDATA[Process]]></string>
-	<string name="_bx_payment_form_pendings_input_cancel_sys"><![CDATA[Cancel]]></string>
-	<string name="_bx_payment_form_pendings_input_cancel"><![CDATA[Cancel]]></string>
-	<string name="_bx_payment_form_processed_input_seller_id_sys"><![CDATA[Seller ID]]></string>
-	<string name="_bx_payment_form_processed_input_client_id_sys"><![CDATA[Client ID]]></string>
-	<string name="_bx_payment_form_processed_input_client_sys"><![CDATA[Client]]></string>
-	<string name="_bx_payment_form_processed_input_client"><![CDATA[Client]]></string>
-	<string name="_bx_payment_form_processed_input_client_err"><![CDATA[You need to enter a name of an existed member here.]]></string>
-	<string name="_bx_payment_form_processed_input_order_sys"><![CDATA[Order]]></string>
-	<string name="_bx_payment_form_processed_input_order"><![CDATA[Order]]></string>
-	<string name="_bx_payment_form_processed_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
-	<string name="_bx_payment_form_processed_input_module_id_sys"><![CDATA[Module]]></string>
-	<string name="_bx_payment_form_processed_input_module_id"><![CDATA[Module]]></string>
-	<string name="_bx_payment_form_processed_input_module_id_err"><![CDATA[You need to select a module here.]]></string>
-	<string name="_bx_payment_form_processed_input_items_sys"><![CDATA[Items]]></string>
-	<string name="_bx_payment_form_processed_input_items"><![CDATA[Items]]></string>
-	<string name="_bx_payment_form_processed_input_items_err"><![CDATA[You need to select at least one item from the list here.]]></string>
-	<string name="_bx_payment_form_processed_input_add"><![CDATA[Add]]></string>
-	<string name="_bx_payment_form_processed_input_add_sys"><![CDATA[Add]]></string>
-	<string name="_bx_payment_form_processed_input_cancel"><![CDATA[Cancel]]></string>
-	<string name="_bx_payment_form_processed_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <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 Commission]]></string>
+    <string name="_bx_payment_popup_title_cms_edit"><![CDATA[Edit 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_pendings_form"><![CDATA[Pendings Form]]></string>
+    <string name="_bx_payment_form_processed_form"><![CDATA[Processed Form]]></string>
+    <string name="_bx_payment_form_pendings_display_process"><![CDATA[Process Pending Display]]></string>
+    <string name="_bx_payment_form_processed_display_add"><![CDATA[Add Processed Display]]></string>
+    <string name="_bx_payment_form_pendings_input_id_sys"><![CDATA[ID]]></string>
+    <string name="_bx_payment_form_pendings_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+    <string name="_bx_payment_form_pendings_input_order_sys"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_pendings_input_order"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_pendings_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+    <string name="_bx_payment_form_pendings_input_process_sys"><![CDATA[Process]]></string>
+    <string name="_bx_payment_form_pendings_input_process"><![CDATA[Process]]></string>
+    <string name="_bx_payment_form_pendings_input_cancel_sys"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_pendings_input_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_processed_input_seller_id_sys"><![CDATA[Seller ID]]></string>
+    <string name="_bx_payment_form_processed_input_client_id_sys"><![CDATA[Client ID]]></string>
+    <string name="_bx_payment_form_processed_input_client_sys"><![CDATA[Client]]></string>
+    <string name="_bx_payment_form_processed_input_client"><![CDATA[Client]]></string>
+    <string name="_bx_payment_form_processed_input_client_err"><![CDATA[You need to enter a name of an existed member here.]]></string>
+    <string name="_bx_payment_form_processed_input_order_sys"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_processed_input_order"><![CDATA[Order]]></string>
+    <string name="_bx_payment_form_processed_input_order_err"><![CDATA[You need to fill in order number here.]]></string>
+    <string name="_bx_payment_form_processed_input_module_id_sys"><![CDATA[Module]]></string>
+    <string name="_bx_payment_form_processed_input_module_id"><![CDATA[Module]]></string>
+    <string name="_bx_payment_form_processed_input_module_id_err"><![CDATA[You need to select a module here.]]></string>
+    <string name="_bx_payment_form_processed_input_items_sys"><![CDATA[Items]]></string>
+    <string name="_bx_payment_form_processed_input_items"><![CDATA[Items]]></string>
+    <string name="_bx_payment_form_processed_input_items_err"><![CDATA[You need to select at least one item from the list here.]]></string>
+    <string name="_bx_payment_form_processed_input_add"><![CDATA[Add]]></string>
+    <string name="_bx_payment_form_processed_input_add_sys"><![CDATA[Add]]></string>
+    <string name="_bx_payment_form_processed_input_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_payment_form_processed_input_cancel_sys"><![CDATA[Cancel]]></string>
+    
+    <string name="_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[Installment]]></string>
+    <string name="_bx_payment_form_commissions_input_installment"><![CDATA[Installment]]></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>
 
     <!-- Predefined Values -->
     <string name="_bx_payment_pre_lists_currencies"><![CDATA[Currencies]]></string>
@@ -230,6 +296,22 @@
 <p>Your subscription purchased from '{profile_name}' expired.</p>
 <p>Subscription info:<br />ID: {sibscription_id}<br />Customer: {sibscription_customer}<br />Date: {sibscription_date}</p>
 <p><b>Note</b>. An associated data will be removed shortly.</p>
+{email_footer}]]></string>
+
+    <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>
 
 	<!-- MESSAGES, WARNINGS and ERRORS -->
@@ -291,10 +373,14 @@
         <string name="_bx_payment_txt_status_scheduled"><![CDATA[Scheduled]]></string>
         <string name="_bx_payment_txt_status_trial"><![CDATA[Trial]]></string>
         <string name="_bx_payment_txt_status_active"><![CDATA[Active]]></string>
+        <string name="_bx_payment_txt_status_paid"><![CDATA[Paid]]></string>
         <string name="_bx_payment_txt_status_unpaid"><![CDATA[Unpaid]]></string>
+        <string name="_bx_payment_txt_status_overdue"><![CDATA[Overdue]]></string>
         <string name="_bx_payment_txt_status_paused"><![CDATA[Paused]]></string>
         <string name="_bx_payment_txt_status_canceled"><![CDATA[Canceled]]></string>
         <string name="_bx_payment_txt_status_unknown"><![CDATA[Unknown]]></string>
+        <string name="_bx_payment_txt_invoice_title"><![CDATA[Invoice {0} from {1}]]></string>
+        <string name="_bx_payment_txt_invoice_description"><![CDATA[For a period between {0} and {1}]]></string>
 
         <!-- Credits payment provider -->
 	<string name="_bx_payment_cdt_cpt"><![CDATA[Credits]]></string>

+ 1 - 1
modules/boonex/payment/install/sql/disable.sql

@@ -36,7 +36,7 @@ DELETE FROM `sys_email_templates` WHERE `Module` = @sName;
 
 
 -- CRON
-DELETE FROM `sys_cron_jobs` WHERE `name` IN ('bx_payment_time_tracker');
+DELETE FROM `sys_cron_jobs` WHERE `name` IN ('bx_payment_commissions', 'bx_payment_time_tracker');
 
 
 -- PAYMENTS

+ 15 - 3
modules/boonex/payment/install/sql/enable.sql

@@ -32,7 +32,9 @@ INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `lay
 ('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_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),
@@ -47,7 +49,9 @@ INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designb
 ('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_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);
 
 
 -- MENU: cart submenu
@@ -100,6 +104,11 @@ SET @iMoAccountSettings = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items`
 INSERT INTO `sys_menu_items` (`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES
 ('sys_account_settings', 'bx_payment', 'payment-details', '_bx_payment_menu_item_title_system_details', '_bx_payment_menu_item_title_details', 'page.php?i=payment-details', '', '_self', 'credit-card col-gray-dark', '', '', 2147483646, 1, 0, 1, @iMoAccountSettings + 1);
 
+-- MENU: dashboard manage tools
+SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
+('sys_account_dashboard_manage_tools', 'bx_payment', 'payment-invoices', '_bx_payment_menu_item_title_system_admt_invoices', '_bx_payment_menu_item_title_admt_invoices', 'page.php?i=payment-invoices', '', '_self', 'credit-card col-gray-dark', '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 
@@ -158,11 +167,14 @@ INSERT INTO `sys_email_templates` (`Module`, `NameSystem`, `Name`, `Subject`, `B
 (@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_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');
 
 
 -- 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_time_tracker', '* * * * *', 'BxPaymentCronTimeTracker', 'modules/boonex/payment/classes/BxPaymentCronTimeTracker.php', '');
 
 

+ 123 - 3
modules/boonex/payment/install/sql/install.sql

@@ -125,6 +125,39 @@ CREATE TABLE IF NOT EXISTS `bx_payment_modules` (
   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',
+  `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`)
+);
 
 -- 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
@@ -294,7 +327,10 @@ INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `fie
 
 ('bx_payment_grid_orders_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `ttp`.`order` AS `transaction`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''single'' ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 'BxPaymentGridHistory', 'modules/boonex/payment/classes/BxPaymentGridHistory.php'),
 ('bx_payment_grid_orders_processed', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`author_id` AS `author_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `tt`.`item_count` AS `item_count`, `ttp`.`order` AS `transaction`, `ttp`.`error_msg` AS `error_msg`, `ttp`.`provider` AS `provider`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 'BxPaymentGridProcessed', 'modules/boonex/payment/classes/BxPaymentGridProcessed.php'),
-('bx_payment_grid_orders_pending', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`items` AS `items`, `tt`.`amount` AS `amount`, `tt`.`order` AS `transaction`, `tt`.`error_msg` AS `error_msg`, `tt`.`provider` AS `provider`, `tt`.`date` AS `date` FROM `bx_payment_transactions_pending` AS `tt` WHERE 1 AND (ISNULL(`tt`.`order`) OR (NOT ISNULL(`tt`.`order`) AND `tt`.`error_code`<>''0'')) ', 'bx_payment_transactions_pending', 'id', 'date', '', '', 100, NULL, 'start', '', 'tt`.`order,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 'BxPaymentGridPending', 'modules/boonex/payment/classes/BxPaymentGridPending.php');
+('bx_payment_grid_orders_pending', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`items` AS `items`, `tt`.`amount` AS `amount`, `tt`.`order` AS `transaction`, `tt`.`error_msg` AS `error_msg`, `tt`.`provider` AS `provider`, `tt`.`date` AS `date` FROM `bx_payment_transactions_pending` AS `tt` WHERE 1 AND (ISNULL(`tt`.`order`) OR (NOT ISNULL(`tt`.`order`) AND `tt`.`error_code`<>''0'')) ', 'bx_payment_transactions_pending', 'id', 'date', '', '', 100, NULL, 'start', '', 'tt`.`order,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 'BxPaymentGridPending', 'modules/boonex/payment/classes/BxPaymentGridPending.php'),
+
+('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, '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, '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),
@@ -369,7 +405,28 @@ INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable
 ('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_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),
@@ -398,15 +455,30 @@ INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon
 ('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_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', 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', 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_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, '', '');
@@ -415,8 +487,15 @@ INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_att
 INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `view_mode`) VALUES
 ('bx_payment_form_pendings_process', @sName, 'bx_payment_form_pendings', '_bx_payment_form_pendings_display_process', 0),
 ('bx_payment_form_processed_add', @sName, 'bx_payment_form_processed', '_bx_payment_form_processed_display_add', 0),
+
+('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);
@@ -439,6 +518,22 @@ INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `c
 ('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),
@@ -485,6 +580,31 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 ('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),

+ 4 - 7
modules/boonex/payment/install/sql/uninstall.sql

@@ -2,15 +2,12 @@ SET @sName = 'bx_payment';
 
 
 -- TABLES
-DROP TABLE IF EXISTS `bx_payment_providers`;
-DROP TABLE IF EXISTS `bx_payment_providers_options`;
-DROP TABLE IF EXISTS `bx_payment_user_values`;
+DROP TABLE IF EXISTS `bx_payment_providers`, `bx_payment_providers_options`, `bx_payment_user_values`;
 DROP TABLE IF EXISTS `bx_payment_cart`;
-DROP TABLE IF EXISTS `bx_payment_transactions`;
-DROP TABLE IF EXISTS `bx_payment_subscriptions`;
-DROP TABLE IF EXISTS `bx_payment_subscriptions_deleted`;
-DROP TABLE IF EXISTS `bx_payment_transactions_pending`;
+DROP TABLE IF EXISTS `bx_payment_transactions`, `bx_payment_transactions_pending`;
+DROP TABLE IF EXISTS `bx_payment_subscriptions`, `bx_payment_subscriptions_deleted`;
 DROP TABLE IF EXISTS `bx_payment_modules`;
+DROP TABLE IF EXISTS `bx_payment_commissions`, `bx_payment_invoices`;
 
 
 -- GRIDS

+ 9 - 0
modules/boonex/payment/template/css/invoices.css

@@ -0,0 +1,9 @@
+/*--- Grid ---*/
+#bx-grid-cont-bx_payment_grid_invoices .bx-grid-cell-single-actions-wrapper {
+    white-space: nowrap;
+}
+
+#bx-grid-cont-bx_payment_grid_invoices .bx-grid-cell-single-actions-wrapper .bx-btn {
+    display: inline-block;
+    float: none;
+}

+ 87 - 0
modules/boonex/russian/data/langs/bx_payment/ru.xml

@@ -55,8 +55,13 @@
     <string name="_bx_payment_page_title_join"><![CDATA[Присоединиться]]></string>
     <string name="_bx_payment_page_block_title_join"><![CDATA[Присоединиться]]></string>
 
+    <string name="_bx_payment_page_title_sys_invoices"><![CDATA[Счета]]></string>
+    <string name="_bx_payment_page_title_invoices"><![CDATA[Счета]]></string>
+    <string name="_bx_payment_page_block_title_invoices"><![CDATA[Счета]]></string>
+
     <!-- MENUS -->
     <string name="_bx_payment_lmi_cpt_providers"><![CDATA[Провайдеры]]></string>
+    <string name="_bx_payment_lmi_cpt_commissions"><![CDATA[Комиссии]]></string>
 
     <string name="_bx_payment_menu_title_orders_submenu"><![CDATA[Подменю заказов]]></string>
     <string name="_bx_payment_menu_set_title_orders_submenu"><![CDATA[Подменю заказов]]></string>
@@ -66,6 +71,10 @@
     <string name="_bx_payment_menu_item_title_orders_pending"><![CDATA[Обрабатываемые]]></string>
     <string name="_bx_payment_menu_item_title_system_details"><![CDATA[Детали платежных систем]]></string>
     <string name="_bx_payment_menu_item_title_details"><![CDATA[Платежные системы]]></string>
+    <string name="_bx_payment_menu_item_title_system_admt_invoices"><![CDATA[Счета]]></string>
+    <string name="_bx_payment_menu_item_title_admt_invoices"><![CDATA[Счета]]></string>
+    <string name="_bx_payment_menu_item_title_admt_addon_counter1_caption"><![CDATA[опл.]]></string>
+    <string name="_bx_payment_menu_item_title_admt_addon_counter2_caption"><![CDATA[задерж.]]></string>
 
     <string name="_bx_payment_menu_title_cart_submenu"><![CDATA[Подменю корзины]]></string>
     <string name="_bx_payment_menu_set_title_cart_submenu"><![CDATA[Подменю корзины]]></string>
@@ -126,6 +135,20 @@
     <string name="_bx_payment_grid_column_title_crt_description"><![CDATA[Описание]]></string>
     <string name="_bx_payment_grid_column_title_crt_quantity"><![CDATA[Количество]]></string>
     <string name="_bx_payment_grid_column_title_crt_price"><![CDATA[Цена]]></string>
+    <string name="_bx_payment_grid_column_title_cms_caption"><![CDATA[Заголовок]]></string>
+    <string name="_bx_payment_grid_column_title_cms_description"><![CDATA[Описание]]></string>
+    <string name="_bx_payment_grid_column_title_cms_acl_id"><![CDATA[Членство]]></string>
+    <string name="_bx_payment_grid_column_title_cms_percentage"><![CDATA[Процент]]></string>
+    <string name="_bx_payment_grid_column_title_cms_installment"><![CDATA[Взнос]]></string>
+    <string name="_bx_payment_grid_column_title_inv_commissionaire_id"><![CDATA[Комиссионер]]></string>
+    <string name="_bx_payment_grid_column_title_inv_committent_id"><![CDATA[Комитент]]></string>
+    <string name="_bx_payment_grid_column_title_inv_name"><![CDATA[Имя]]></string>
+    <string name="_bx_payment_grid_column_title_inv_period_start"><![CDATA[Начало периода]]></string>
+    <string name="_bx_payment_grid_column_title_inv_period_end"><![CDATA[Конец периода]]></string>
+    <string name="_bx_payment_grid_column_title_inv_amount"><![CDATA[Сумма]]></string>
+    <string name="_bx_payment_grid_column_title_inv_date_issue"><![CDATA[Дата выпуска]]></string>
+    <string name="_bx_payment_grid_column_title_inv_date_due"><![CDATA[Срок оплаты]]></string>
+    <string name="_bx_payment_grid_column_title_inv_status"><![CDATA[Статус]]></string>
 
     <string name="_bx_payment_grid_action_title_ods_add"><![CDATA[Добавить вручную]]></string>
     <string name="_bx_payment_grid_action_title_ods_cancel"><![CDATA[Отменить]]></string>
@@ -139,6 +162,12 @@
     <string name="_bx_payment_grid_action_title_crts_continue"><![CDATA[Продолжить оплату]]></string>
     <string name="_bx_payment_grid_action_title_crt_checkout"><![CDATA[Оплатить через {0}]]></string>
     <string name="_bx_payment_grid_action_title_crt_delete"><![CDATA[Удалить]]></string>
+    <string name="_bx_payment_grid_action_title_cms_add"><![CDATA[Добавить]]></string>
+    <string name="_bx_payment_grid_action_title_cms_edit"><![CDATA[Изменить]]></string>
+    <string name="_bx_payment_grid_action_title_cms_delete"><![CDATA[Удалить]]></string>
+    <string name="_bx_payment_grid_action_title_inv_edit"><![CDATA[Изменить]]></string>
+    <string name="_bx_payment_grid_action_title_inv_delete"><![CDATA[Удалить]]></string>
+    <string name="_bx_payment_grid_action_title_inv_pay"><![CDATA[Оплатить]]></string>
 
     <string name="_bx_payment_popup_title_ods_order_subscription_view"><![CDATA[Подписка]]></string>
     <string name="_bx_payment_popup_title_ods_order_subscription_get_details"><![CDATA[Детали подписки]]></string>
@@ -151,6 +180,9 @@
     <string name="_bx_payment_popup_title_ods_order_processed_view"><![CDATA[Обработанный заказ]]></string>
     <string name="_bx_payment_popup_title_ods_order_processed_add"><![CDATA[Добавить вручную]]></string>
     <string name="_bx_payment_popup_title_crd_providers_select"><![CDATA[Выберите платежную систему]]></string>
+    <string name="_bx_payment_popup_title_cms_add"><![CDATA[Добавить комиссию]]></string>
+    <string name="_bx_payment_popup_title_cms_edit"><![CDATA[Изменить комиссию]]></string>
+    <string name="_bx_payment_popup_title_inv_edit"><![CDATA[Изменить счет]]></string>
 
     <!-- FORMS -->
     <string name="_bx_payment_form_cart_input_do_delete"><![CDATA[Удалить]]></string>
@@ -189,6 +221,40 @@
     <string name="_bx_payment_form_processed_input_cancel"><![CDATA[Отменить]]></string>
     <string name="_bx_payment_form_processed_input_cancel_sys"><![CDATA[Отменить]]></string>
 
+    <string name="_bx_payment_form_commissions_form"><![CDATA[Форма комиссий]]></string>
+    <string name="_bx_payment_form_commissions_display_add"><![CDATA[Добавить комиссию]]></string>
+    <string name="_bx_payment_form_commissions_display_edit"><![CDATA[Изменить комиссию]]></string>
+    <string name="_bx_payment_form_commissions_input_caption_sys"><![CDATA[Заголовок]]></string>
+    <string name="_bx_payment_form_commissions_input_caption"><![CDATA[Заголовок]]></string>
+    <string name="_bx_payment_form_commissions_input_caption_err"><![CDATA[Это поле необходимо. Пожалуйста, заполните его.]]></string>
+    <string name="_bx_payment_form_commissions_input_description_sys"><![CDATA[Описание]]></string>
+    <string name="_bx_payment_form_commissions_input_description"><![CDATA[Описание]]></string>
+    <string name="_bx_payment_form_commissions_input_acl_id_sys"><![CDATA[Уровень членства]]></string>
+    <string name="_bx_payment_form_commissions_input_acl_id"><![CDATA[Уровень членства]]></string>
+    <string name="_bx_payment_form_commissions_input_percentage_sys"><![CDATA[Процент]]></string>
+    <string name="_bx_payment_form_commissions_input_percentage"><![CDATA[Процент]]></string>
+    <string name="_bx_payment_form_commissions_input_installment_sys"><![CDATA[Взнос]]></string>
+    <string name="_bx_payment_form_commissions_input_installment"><![CDATA[Взнос]]></string>
+    <string name="_bx_payment_form_commissions_input_submit_sys"><![CDATA[Выполнить]]></string>
+    <string name="_bx_payment_form_commissions_input_submit"><![CDATA[Выполнить]]></string>
+    <string name="_bx_payment_form_commissions_input_cancel_sys"><![CDATA[Отменить]]></string>
+    <string name="_bx_payment_form_commissions_input_cancel"><![CDATA[Отменить]]></string>
+    
+    <string name="_bx_payment_form_invoices_form"><![CDATA[Форма счетов]]></string>
+    <string name="_bx_payment_form_invoices_display_edit"><![CDATA[Изменить счет]]></string>
+    <string name="_bx_payment_form_invoices_input_amount_sys"><![CDATA[Сумма]]></string>
+    <string name="_bx_payment_form_invoices_input_amount"><![CDATA[Сумма]]></string>
+    <string name="_bx_payment_form_invoices_input_amount_err"><![CDATA[Это поле необходимо. Пожалуйста, заполните его.]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due_sys"><![CDATA[Срок оплаты]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due"><![CDATA[Срок оплаты]]></string>
+    <string name="_bx_payment_form_invoices_input_date_due_err"><![CDATA[Это поле необходимо. Пожалуйста, заполните его.]]></string>
+    <string name="_bx_payment_form_invoices_input_status_sys"><![CDATA[Статус]]></string>
+    <string name="_bx_payment_form_invoices_input_status"><![CDATA[Статус]]></string>
+    <string name="_bx_payment_form_invoices_input_submit_sys"><![CDATA[Выполнить]]></string>
+    <string name="_bx_payment_form_invoices_input_submit"><![CDATA[Выполнить]]></string>
+    <string name="_bx_payment_form_invoices_input_cancel_sys"><![CDATA[Отменить]]></string>
+    <string name="_bx_payment_form_invoices_input_cancel"><![CDATA[Отменить]]></string>
+
     <!-- Predefined Values -->
     <string name="_bx_payment_pre_lists_currencies"><![CDATA[Валюты]]></string>
 
@@ -230,6 +296,22 @@
 <p>Ваша подписка, купленная у '{profile_name}', закончилась.</p>
 <p>Информация о подписке:<br />ID: {sibscription_id}<br />Клиент: {sibscription_customer}<br />Дата: {sibscription_date}</p>
 <p><b>Внимание</b>. Данные, связанные с подпиской, будут удалены в ближайшее время.</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_expiring_notification_committent"><![CDATA[Уведомление об истечении срока действия счета.]]></string>
+    <string name="_bx_payment_et_txt_subject_expiring_notification_committent"><![CDATA[Уведомление об истечении срока действия счета.]]></string>
+    <string name="_bx_payment_et_txt_body_expiring_notification_committent"><![CDATA[{email_header}
+<p>Привет,</p>
+<p>Срок оплаты вашего счета '{invoice}' закончится через '{days}' день(ей).</p>
+<p>Информация о счете:<br />Начало периода: {period_start}<br />Конец периода: {period_end}<br />Дата выпуска: {date_issue}<br />Срок оплаты: {date_due}</p>
+{email_footer}]]></string>
+
+    <string name="_bx_payment_et_txt_name_overdue_notification_committent"><![CDATA[Уведомление о просроченном счете.]]></string>
+    <string name="_bx_payment_et_txt_subject_overdue_notification_committent"><![CDATA[Уведомление о просроченном счете.]]></string>
+    <string name="_bx_payment_et_txt_body_overdue_notification_committent"><![CDATA[{email_header}
+<p>Привет,</p>
+<p>Оплата вашего счета '{invoice}' просрочена '{date_due}'.</p>
+<p>Информация о счете:<br />Начало периода: {period_start}<br />Конец периода: {period_end}<br />Дата выпуска: {date_issue}<br />Срок оплаты: {date_due}</p>
 {email_footer}]]></string>
 
     <!-- MESSAGES, WARNINGS and ERRORS -->
@@ -259,6 +341,7 @@
     <string name="_bx_payment_err_wrong_quantity"><![CDATA[Указано неправильное количество.]]></string>
     <string name="_bx_payment_err_already_processed"><![CDATA[Этот платеж уже обработан.]]></string>
     <string name="_bx_payment_err_already_registered"><![CDATA[Подписка с аналогичными данными уже была зарегистрирована.]]></string>
+    <string name="_bx_payment_err_not_supported"><![CDATA[Операция не поддерживается.]]></string>
 
     <!-- Other -->
     <string name="_bx_payment_txt_add_to_cart"><![CDATA[В корзину]]></string>
@@ -290,10 +373,14 @@
     <string name="_bx_payment_txt_status_scheduled"><![CDATA[Запланированно]]></string>
     <string name="_bx_payment_txt_status_trial"><![CDATA[Пробный]]></string>
     <string name="_bx_payment_txt_status_active"><![CDATA[Активно]]></string>
+    <string name="_bx_payment_txt_status_paid"><![CDATA[Оплачено]]></string>
     <string name="_bx_payment_txt_status_unpaid"><![CDATA[Не оплачено]]></string>
+    <string name="_bx_payment_txt_status_overdue"><![CDATA[Просрочено]]></string>
     <string name="_bx_payment_txt_status_paused"><![CDATA[Приостановлено]]></string>
     <string name="_bx_payment_txt_status_canceled"><![CDATA[Отменено]]></string>
     <string name="_bx_payment_txt_status_unknown"><![CDATA[Неизвестно]]></string>
+    <string name="_bx_payment_txt_invoice_title"><![CDATA[Счет {0} от {1}]]></string>
+    <string name="_bx_payment_txt_invoice_description"><![CDATA[За период между {0} и {1}]]></string>
 
 
         <!-- Credits payment provider -->

+ 2 - 0
modules/boonex/russian/data/langs/system/ru.xml

@@ -2579,6 +2579,7 @@
     <string name="_sys_menu_item_title_cmts_item_more"><![CDATA[]]></string>
     <string name="_sys_menu_item_title_dashboard"><![CDATA[Панель]]></string>
     <string name="_sys_menu_item_title_home"><![CDATA[Домой]]></string>
+    <string name="_sys_menu_item_title_invoices"><![CDATA[Счета]]></string>
     <string name="_sys_menu_item_title_logout"><![CDATA[Выйти]]></string>
     <string name="_sys_menu_item_title_more"><![CDATA[Ещё]]></string>
     <string name="_sys_menu_item_title_more_auto"><![CDATA[Ещё]]></string>
@@ -2651,6 +2652,7 @@
 	<string name="_sys_menu_item_title_system_cmts_item_more"><![CDATA[Ещё]]></string>
 	<string name="_sys_menu_item_title_system_dashboard"><![CDATA[Панель]]></string>
 	<string name="_sys_menu_item_title_system_home"><![CDATA[Домой]]></string>
+        <string name="_sys_menu_item_title_system_invoices"><![CDATA[Счета]]></string>
 	<string name="_sys_menu_item_title_system_login"><![CDATA[Вход]]></string>
 	<string name="_sys_menu_item_title_system_logout"><![CDATA[Выйти]]></string>
 	<string name="_sys_menu_item_title_system_main_menu"><![CDATA[Главное Меню]]></string>

+ 41 - 0
template/scripts/BxBasePaymentsServices.php

@@ -65,6 +65,28 @@ class BxBasePaymentsServices extends BxDol
     	return BxDolPayments::getInstance()->getOrdersCount($sType);
     }
 
+    /**
+     * @page service Service Calls
+     * @section bx_system_general System Services
+     * @subsection bx_system_general-payments Payments
+     * @subsubsection bx_system_general-get_invoices_count get_invoices_count
+     * 
+     * @code bx_srv('system', 'get_invoices_count', ["unpaid"], 'TemplPaymentsServices'); @endcode
+     * @code {{~system:get_invoices_count:TemplPaymentsServices["unpaid"]~}} @endcode
+     * 
+     * Get number of invoices by type for currently logged in profile.
+     * @param $sType type, for example: unpaid
+     * 
+     * @see BxBasePaymentsServices::serviceGetInvoicesCount
+     */
+    /** 
+     * @ref bx_system_general-get_invoices_count "get_invoices_count"
+     */
+    public function serviceGetInvoicesCount($sType)
+    {
+    	return BxDolPayments::getInstance()->getInvoicesCount($sType);
+    }
+
     public function serviceGetLiveUpdatesCart($aMenuItemParent, $aMenuItemChild, $iCount = 0)
     {
         $iCountNew = BxDolPayments::getInstance()->getCartItemsCount();
@@ -102,6 +124,25 @@ class BxBasePaymentsServices extends BxDol
     		),  // optional, may have some additional data to be passed in JS method provided using 'method' param above.
     	);
     }
+    
+    public function serviceGetLiveUpdatesInvoices($aMenuItemParent, $aMenuItemChild, $iCount = 0)
+    {
+        $iCountNew = BxDolPayments::getInstance()->getInvoicesCount('unpaid');
+        if($iCountNew == $iCount)
+            return false;
+
+        return array(
+            'count' => $iCountNew, // required
+            'method' => 'bx_menu_show_live_update(oData)', // required
+            'data' => array(
+                'code' => BxDolTemplate::getInstance()->parseHtmlByTemplateName('menu_item_addon', array(
+                    'content' => '{count}'
+                )),
+                'mi_parent' => $aMenuItemParent,
+                'mi_child' => $aMenuItemChild
+            ),  // optional, may have some additional data to be passed in JS method provided using 'method' param above.
+    	);
+    }
 }
 
 /** @} */