Просмотр исходного кода

Ticket #5493 - Payments: Add 'Reason to cancel' survey in subscriptions.

AntonLV 5 месяцев назад
Родитель
Сommit
c8bb54dd1f

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

@@ -56,6 +56,7 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
             'KEY_ARRAY_TRIAL_RECURRING' => 'trial_recurring',
 
             // some params
+            'PARAM_SBS_CANCEL_SURVEY' => 'bx_payment_sbs_cancel_survey',
             'PARAM_CURRENCY_EXCHANGE_API' => 'bx_payment_currency_exchange_api',
             'PARAM_CMSN_ENABLE' => 'bx_payment_commissions',
             'PARAM_CMSN_INVOICE_ISSUE_DAY' => 'bx_payment_inv_issue_day', //some day of month
@@ -64,6 +65,7 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
 
             // objects
             'OBJECT_FORM_PRELISTS_CURRENCIES' => 'bx_payment_currencies',
+            'OBJECT_FORM_PRELISTS_REASONS_CANCEL' => 'bx_payment_reasons_cancel',
             'OBJECT_PP_OFFLINE' => 'offline', //Offline payment provider
             'OBJECT_PP_CREDITS' => 'credits', //Credits payment provider
 
@@ -104,6 +106,8 @@ class BxPaymentConfig extends BxBaseModPaymentConfig
                 'order_subscription_change_billing' => $this->_sName . '-order-change-billing-subscription',
                 'form_subscription_change_billing' => $this->_sName . '-form-change-billing-subscription',
                 'form_subscription_change_details' => $this->_sName . '-form-change-details-subscription',
+                'form_subscription_cancel_survay' => $this->_sName . '-form-cancel-subscription-survay-',
+                'popup_subscription_cancel_survay' => $this->_sName . '-popup-cancel-subscription-survay-',
             ),
             'pending' => array(
                 'order_pending_view' => $this->_sName . '-order-view-pending',

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

@@ -572,6 +572,7 @@ class BxPaymentDb extends BxBaseModPaymentDb
                 $aResult = array_merge($aResult, [
                     'customer_id' => $aSubscription['customer_id'],
                     'deleted' => $aSubscription['deleted'] ?? false,
+                    'deleted_reason' => $aSubscription['reason'] ?? '',
                 ]);
         }
 

+ 1 - 0
modules/boonex/payment/classes/BxPaymentGridSbsAdministration.php

@@ -95,6 +95,7 @@ class BxPaymentGridSbsAdministration extends BxBaseModPaymentGridTransactions
         parent::_addJsCss();
 
         $this->_oTemplate->addJsTranslation(array(
+            '_bx_payment_form_input_err',
             '_bx_payment_msg_confirm_cancelation',
             '_bx_payment_txt_unsubscribe_yes',
             '_bx_payment_txt_unsubscribe_no'

+ 18 - 6
modules/boonex/payment/classes/BxPaymentModule.php

@@ -687,17 +687,29 @@ class BxPaymentModule extends BxBaseModPaymentModule
 
     public function actionSubscriptionCancel($iId, $mixedGridObject = false)
     {
-        $aResult = array('code' => 1, 'message' => _t('_bx_payment_err_cannot_perform'));
+        $CNF = &$this->_oConfig->CNF;
+        $aResult = ['code' => 1, 'message' => _t('_bx_payment_err_cannot_perform')];
 
-        $aPending = $this->_oDb->getOrderPending(array('type' => 'id', 'id' => $iId));
+        $aPending = $this->_oDb->getOrderPending(['type' => 'id', 'id' => $iId]);
         if(empty($aPending) || !is_array($aPending))
             return echoJson($aResult);
 
         $mixedResult = $this->isAllowedManage($aPending);
         if($mixedResult !== true)
-            return echoJson(array('code' => 2, 'message' => $mixedResult));
+            return echoJson(['code' => 2, 'message' => $mixedResult]);
+
+        $oSubscriptions = $this->getObjectSubscriptions();
+        
+        $sReason = '';
+        if(getParam($CNF['PARAM_SBS_CANCEL_SURVEY']) == 'on') {
+            $aCsResult = $oSubscriptions->getPopupCancelSurvey($iId);
+            if($aCsResult['code'] != 0)
+                return echoJson($aCsResult);
+
+            $sReason = $aCsResult['msg'];
+        }
 
-        if(!$this->getObjectSubscriptions()->cancel($iId))
+        if(!$oSubscriptions->cancel($iId, $sReason))
             return echoJson($aResult);
 
         if(empty($mixedGridObject) && bx_get('grid') !== false)
@@ -707,10 +719,10 @@ class BxPaymentModule extends BxBaseModPaymentModule
             $oGrid = BxDolGrid::getObjectInstance($mixedGridObject, $this->_oTemplate);
             $oGrid->addQueryParam('client_id', $aPending['client_id']);
 
-            return echoJson(array('object' => $mixedGridObject, 'grid' => $oGrid->getCode(false), 'blink' => array($iId)));
+            return echoJson(['object' => $mixedGridObject, 'grid' => $oGrid->getCode(false), 'blink' => array($iId)]);
         }
         else
-            return echoJson(array('code' => 0, 'message' => _t('_bx_payment_msg_successfully_performed')));
+            return echoJson(['code' => 0, 'message' => _t('_bx_payment_msg_successfully_performed')]);
     }
 
     /**

+ 109 - 5
modules/boonex/payment/classes/BxPaymentSubscriptions.php

@@ -457,12 +457,13 @@ class BxPaymentSubscriptions extends BxBaseModPaymentSubscriptions
         return true;
     }
 
-    public function cancel($iPendingId)
+    public function cancel($iPendingId, $sReason = '')
     {
+        /*
         if(!$this->cancelRemote($iPendingId))
             return false;
-
-        if(!$this->cancelLocal($iPendingId))
+        */
+        if(!$this->cancelLocal($iPendingId, $sReason))
             return false;
 
         return true;
@@ -489,7 +490,7 @@ class BxPaymentSubscriptions extends BxBaseModPaymentSubscriptions
         return true;
     }
 
-    public function cancelLocal($mixedPending)
+    public function cancelLocal($mixedPending, $sReason = 'cancel')
     {
         $aPending = is_array($mixedPending) ? $mixedPending : $this->_oModule->_oDb->getOrderPending(array('type' => 'id', 'id' => (int)$mixedPending));
         if(empty($aPending) || !is_array($aPending) || $aPending['type'] != BX_PAYMENT_TYPE_RECURRING)
@@ -503,7 +504,7 @@ class BxPaymentSubscriptions extends BxBaseModPaymentSubscriptions
         foreach($aItems as $aItem)
             $this->_oModule->callCancelSubscriptionItem((int)$aItem['module_id'], array($aPending['client_id'], $aPending['seller_id'], $aItem['item_id'], $aItem['item_count'], $aPending['order']));
 
-        if(!$this->_oModule->_oDb->deleteSubscription($aSubscription['id'], 'cancel'))
+        if(!$this->_oModule->_oDb->deleteSubscription($aSubscription['id'], $sReason))
             return false;
 
         $this->_oModule->onSubscriptionCancel($aPending, $aSubscription);
@@ -511,6 +512,30 @@ class BxPaymentSubscriptions extends BxBaseModPaymentSubscriptions
         return true;
     }
 
+    public function getPopupCancelSurvey($iId)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $oForm = $this->_getFormCancelSurvey($iId);
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            $aReasons = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_REASONS_CANCEL']);
+
+            return [
+                'code' => 0,
+                'msg' => ($sOther = $oForm->getCleanValue('other')) ? $sOther : $aReasons[$oForm->getCleanValue('items')]
+            ];
+        }
+
+        $sPopupId = $this->_oModule->_oConfig->getHtmlIds('subscription', 'popup_subscription_cancel_survay') . $iId;
+        $sPopupContent = BxTemplFunctions::getInstance()->transBox($sPopupId, $this->_oModule->_oTemplate->parseHtmlByName('subscription_form.html', [
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true)
+        ]));
+
+        return ['code' => 1, 'popup' => ['html' => $sPopupContent, 'options' => ['closeOnOuterClick' => false]]];
+    }
+
     protected function _getBlock($sType)
     {
         $CNF = &$this->_oModule->_oConfig->CNF;
@@ -581,6 +606,85 @@ class BxPaymentSubscriptions extends BxBaseModPaymentSubscriptions
 
         return $sInterval;
     }
+
+    protected function _getFormCancelSurvey($iId)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('subscription');
+
+        $aReasons = BxDolForm::getDataItems($CNF['OBJECT_FORM_PRELISTS_REASONS_CANCEL']);
+        
+        $aForm = [
+            'form_attrs' => [
+                'id' => $this->_oModule->_oConfig->getHtmlIds('subscription', 'form_subscription_cancel_survay') . $iId,
+                'action' => BX_DOL_URL_ROOT . $this->_oModule->_oConfig->getBaseUri() . 'subscription_cancel/' . $iId,
+                'method' => BX_DOL_FORM_METHOD_DEFAULT,
+                'onsubmit' => 'return ' . $sJsObject . '.onSubmitCancelationReason(this)'
+            ],
+            'params' => [
+                'db' => [
+                    'table' => '',
+                    'key' => '',
+                    'uri' => '',
+                    'uri_title' => '',
+                    'submit_name' => 'do_submit'
+                ],
+            ],
+            'inputs' => [
+                'items' => [
+                    'type' => 'radio_set',
+                    'name' => 'items',
+                    'caption' => _t('_bx_payment_form_cs_input_items'),
+                    'values' => $aReasons,
+                    'value' => key($aReasons),
+                    'required' => '1',
+                    'attrs' => [
+                        'onchange' => $sJsObject . '.onChangeCancelationReason(this)'
+                    ],
+                    'db' => [
+                        'pass' => 'Xss',
+                    ],
+                    'checker' => [
+                        'func' => 'Avail',
+                        'params' => [],
+                        'error' => _t('_bx_payment_form_input_err'),
+                    ],
+                ],
+                'other' => [
+                    'type' => 'text',
+                    'name' => 'other',
+                    'caption' => _t('_bx_payment_form_cs_input_other'),
+                    'value' => '',
+                    'required' => '1',
+                    'tr_attrs' => [
+                        'class' => 'bx-payment-cs-other bx-payment-cs-hidden'
+                    ],
+                    'db' => [
+                        'pass' => 'Xss',
+                    ],
+                ],
+                'controls' => [
+                    'name' => 'controls',
+                    'type' => 'input_set',
+                    [
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_bx_payment_form_cs_input_submit'),
+                    ], [
+                        'type' => 'reset',
+                        'name' => 'do_cancel',
+                        'value' => _t('_bx_payment_form_cs_input_cancel'),
+                        'attrs' => [
+                            'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
+                            'class' => 'bx-def-margin-sec-left',
+                        ],
+                    ]
+                ]
+            ]
+        ];
+
+        return new BxTemplFormView($aForm);
+    }
 }
 
 /** @} */

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

@@ -357,14 +357,19 @@ class BxPaymentTemplate extends BxBaseModPaymentTemplate
                     'condition' => false,
                     'content' => [
                         'txt_deleted' => _t($this->_sLangsPrefix . 'txt_deleted'),
-                        'deleted' => 0
+                        'txt_deleted_reason' => _t($this->_sLangsPrefix . 'txt_deleted_reason'),
+                        'deleted' => 0,
+                        'deleted_reason' => ''
                     ]
                 ]
             ];
 
             if(($sK = 'deleted') && isset($aOrder[$sK]) && $aOrder[$sK]) {
                 $aTmplVarsCustom['bx_if:show_deleted']['condition'] = true;
-                $aTmplVarsCustom['bx_if:show_deleted']['content']['deleted'] = bx_time_js($aOrder[$sK], BX_FORMAT_DATE_TIME, true);
+                $aTmplVarsCustom['bx_if:show_deleted']['content'] = array_merge($aTmplVarsCustom['bx_if:show_deleted']['content'], [
+                    'deleted' => bx_time_js($aOrder[$sK], BX_FORMAT_DATE_TIME, true),
+                    'deleted_reason' => $aOrder['deleted_reason'] ?? ''
+                ]);
             }
         }
 

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

@@ -13,6 +13,7 @@
     <string name="_bx_payment_option_extended_mode"><![CDATA[Extended mode (Allows sellers to use Test mode, etc).]]></string>
     <string name="_bx_payment_option_credits_only"><![CDATA[Pay with Credits only mode ('Credits' app should be installed).]]></string>
     <string name="_bx_payment_option_single_seller"><![CDATA[Single seller mode (To sell everything on behalf of the 'Main seller').]]></string>
+    <string name="_bx_payment_option_sbs_cancel_survey"><![CDATA[Enable 'Your reason to cancel subscription' survey.]]></string>
     <string name="_bx_payment_option_commissions"><![CDATA[Enable commissions calculation]]></string>
     <string name="_bx_payment_option_inv_issue_day"><![CDATA[Day of month when invoices are automatically generated (1, 2, 3, etc)]]></string>
     <string name="_bx_payment_option_inv_lifetime"><![CDATA[Due date - days after invoice date]]></string>
@@ -271,11 +272,26 @@
     <string name="_bx_payment_form_invoices_input_submit"><![CDATA[Submit]]></string>
     <string name="_bx_payment_form_invoices_input_cancel_sys"><![CDATA[Cancel]]></string>
     <string name="_bx_payment_form_invoices_input_cancel"><![CDATA[Cancel]]></string>
+    
+    <string name="_bx_payment_form_cs_input_items"><![CDATA[Why do you want to cancel?]]></string>
+    <string name="_bx_payment_form_cs_input_other"><![CDATA[Your variant]]></string>
+    <string name="_bx_payment_form_cs_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_payment_form_cs_input_cancel"><![CDATA[Cancel]]></string>
 
+    <string name="_bx_payment_form_input_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
     <string name="_bx_payment_form_input_email_err_cor_or_emp"><![CDATA[Use correct email address or leave empty.]]></string>
 
     <!-- Predefined Values -->
     <string name="_bx_payment_pre_lists_currencies"><![CDATA[Currencies]]></string>
+    
+    <string name="_bx_payment_pre_lists_reasons_cancel"><![CDATA[Reasons to cancel subscription]]></string>
+    <string name="_bx_payment_pre_values_rc_0"><![CDATA[Other]]></string>
+    <string name="_bx_payment_pre_values_rc_1"><![CDATA[Cost & Budgeting]]></string>
+    <string name="_bx_payment_pre_values_rc_2"><![CDATA[Hidden Fees & Billing Issues]]></string>
+    <string name="_bx_payment_pre_values_rc_3"><![CDATA[Low Usage]]></string>
+    <string name="_bx_payment_pre_values_rc_4"><![CDATA[Loss of Interest]]></string>
+    <string name="_bx_payment_pre_values_rc_5"><![CDATA[Poor User Experience]]></string>
+    <string name="_bx_payment_pre_values_rc_6"><![CDATA[Better Alternatives]]></string>
 
     <!-- ACL -->
     <string name="_bx_payment_acl_action_purchase"><![CDATA[Purchase]]></string>
@@ -407,6 +423,7 @@
     <string name="_bx_payment_txt_message"><![CDATA[Result]]></string>
     <string name="_bx_payment_txt_date"><![CDATA[Date]]></string>
     <string name="_bx_payment_txt_deleted"><![CDATA[Date cancel]]></string>
+    <string name="_bx_payment_txt_deleted_reason"><![CDATA[Reason to cancel]]></string>
     <string name="_bx_payment_txt_products"><![CDATA[Products]]></string>
     <string name="_bx_payment_txt_buyer_name_mask"><![CDATA[{0} {1}]]></string>
     <string name="_bx_payment_txt_none"><![CDATA[none]]></string>

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

@@ -15,7 +15,8 @@ INSERT INTO `sys_options` (`name`, `value`, `category_id`, `caption`, `type`, `c
 ('bx_payment_site_admin', '', @iCategoryId, '_bx_payment_option_site_admin', 'select', '', '', '', 'a:2:{s:6:"module";s:10:"bx_payment";s:6:"method";s:22:"get_options_site_admin";}', 1),
 ('bx_payment_extended_mode', '', @iCategoryId, '_bx_payment_option_extended_mode', 'checkbox', '', '', '', '', 11),
 ('bx_payment_credits_only', '', @iCategoryId, '_bx_payment_option_credits_only', 'checkbox', '', '', '', '', 13),
-('bx_payment_single_seller', '', @iCategoryId, '_bx_payment_option_single_seller', 'checkbox', '', '', '', '', 15);
+('bx_payment_single_seller', '', @iCategoryId, '_bx_payment_option_single_seller', 'checkbox', '', '', '', '', 15),
+('bx_payment_sbs_cancel_survey', '', @iCategoryId, '_bx_payment_option_sbs_cancel_survey', 'checkbox', '', '', '', '', 20);
 
 INSERT INTO `sys_options_categories` (`type_id`, `name`, `caption`, `order`)
 VALUES (@iTypeId, 'bx_payment_currency', '_bx_payment_options_category_currency', 5);
@@ -111,7 +112,7 @@ INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES
 
 INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `editable`, `order`) VALUES 
 ('bx_payment_menu_sbs_actions', 'bx_payment', 'sbs-request-cancelation', '_bx_payment_menu_item_title_system_sbs_request_cancelation', '_bx_payment_menu_item_title_sbs_request_cancelation', 'javascript:void(0)', '{js_object}.requestCancelation(this, {id})', '_self', '', '', '', 2147483647, 1, 0, 1, 1),
-('bx_payment_menu_sbs_actions', 'bx_payment', 'sbs-cancel', '_bx_payment_menu_item_title_system_sbs_cancel', '_bx_payment_menu_item_title_sbs_cancel', 'javascript:void(0)', '{js_object}.cancel(this, {id}, \'{grid}\')', '_self', '', '', '', 2147483647, 0, 0, 1, 2);
+('bx_payment_menu_sbs_actions', 'bx_payment', 'sbs-cancel', '_bx_payment_menu_item_title_system_sbs_cancel', '_bx_payment_menu_item_title_sbs_cancel', 'javascript:void(0)', '{js_object}.cancel(this, {id}, \'{grid}\', 1)', '_self', '', '', '', 2147483647, 0, 0, 1, 2);
 
 -- MENU: orders submenu
 INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 

+ 14 - 2
modules/boonex/payment/install/sql/install.sql

@@ -351,8 +351,8 @@ INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `fie
 ('bx_payment_grid_carts', 'Array', '', '', 'vendor_id', '', '', '', 20, NULL, 'start', '', '', '', 'like', '', '', 2147483647, 1, 'BxPaymentGridCarts', 'modules/boonex/payment/classes/BxPaymentGridCarts.php'),
 ('bx_payment_grid_cart', 'Array', '', '', 'descriptor', '', '', '', 20, NULL, 'start', '', 'title,description', '', 'like', '', '', 2147483647, 1, 'BxPaymentGridCart', 'modules/boonex/payment/classes/BxPaymentGridCart.php'),
 
-('bx_payment_grid_sbs_list_my', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `reason` AS `status` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridSbsList', 'modules/boonex/payment/classes/BxPaymentGridSbsList.php'),
-('bx_payment_grid_sbs_list_all', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tac`.`email` AS `client_email`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `reason` AS `status` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` LEFT JOIN `sys_profiles` AS `tpc` ON `ttp`.`client_id`=`tpc`.`id` LEFT JOIN `sys_accounts` AS `tac` ON `tpc`.`account_id`=`tac`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'tac`.`email,ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 192, 0, 'BxPaymentGridSbsAdministration', 'modules/boonex/payment/classes/BxPaymentGridSbsAdministration.php'),
+('bx_payment_grid_sbs_list_my', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status`, `ts`.`reason` AS `reason` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status`, '''' AS `reason` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, ''canceled'' AS `status`, `reason` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridSbsList', 'modules/boonex/payment/classes/BxPaymentGridSbsList.php'),
+('bx_payment_grid_sbs_list_all', 'Sql', 'SELECT `ttp`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tac`.`email` AS `client_email`, `ttp`.`seller_id` AS `seller_id`, `ttp`.`items` AS `items`, `ts`.`date_add` AS `date_add`, `ts`.`date_next` AS `date_next`, `ts`.`status` AS `status`, `ts`.`reason` AS `reason` FROM (SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, `status`, '''' AS `reason` FROM `bx_payment_subscriptions` UNION SELECT `id`, `pending_id`, `customer_id`, `subscription_id`, `date_add`, `date_next`, ''canceled'' AS `status`, `reason` FROM `bx_payment_subscriptions_deleted`) AS `ts` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `ts`.`pending_id`=`ttp`.`id` LEFT JOIN `sys_profiles` AS `tpc` ON `ttp`.`client_id`=`tpc`.`id` LEFT JOIN `sys_accounts` AS `tac` ON `tpc`.`account_id`=`tac`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_subscriptions', 'id', 'date_add', '', '', 100, NULL, 'start', '', 'tac`.`email,ts`.`customer_id,ts`.`subscription_id,ts`.`date_add', '', 'auto', '', '', 192, 0, 'BxPaymentGridSbsAdministration', 'modules/boonex/payment/classes/BxPaymentGridSbsAdministration.php'),
 ('bx_payment_grid_sbs_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `ttp`.`client_id` AS `client_id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `tt`.`item_count` AS `item_count`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''recurring'' ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridSbsHistory', 'modules/boonex/payment/classes/BxPaymentGridSbsHistory.php'),
 
 ('bx_payment_grid_orders_history', 'Sql', 'SELECT `tt`.`id` AS `id`, `tt`.`seller_id` AS `seller_id`, `tt`.`module_id` AS `module_id`, `tt`.`item_id` AS `item_id`, `ttp`.`order` AS `transaction`, `tt`.`license` AS `license`, `tt`.`amount` AS `amount`, `tt`.`currency` AS `currency`, `tt`.`date` AS `date` FROM `bx_payment_transactions` AS `tt` LEFT JOIN `bx_payment_transactions_pending` AS `ttp` ON `tt`.`pending_id`=`ttp`.`id` WHERE 1 AND `ttp`.`type`=''single'' ', 'bx_payment_transactions', 'id', 'date', '', '', 100, NULL, 'start', '', 'ttp`.`order,tt`.`license,tt`.`amount,tt`.`date', '', 'auto', '', '', 2147483647, 0, 'BxPaymentGridHistory', 'modules/boonex/payment/classes/BxPaymentGridHistory.php'),
@@ -676,6 +676,18 @@ INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALU
 ('bx_payment_currencies', 'USD', 5, 'USD', '&#36;'),
 ('bx_payment_currencies', 'JPY', 6, 'YEN', '&#165;');
 
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`, `extendable`) VALUES
+('bx_payment_reasons_cancel', '_bx_payment_pre_lists_reasons_cancel', 'bx_payment', '0', '1');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_payment_reasons_cancel', 'rc_0', 7, '_bx_payment_pre_values_rc_0', ''),
+('bx_payment_reasons_cancel', 'rc_1', 1, '_bx_payment_pre_values_rc_1', ''),
+('bx_payment_reasons_cancel', 'rc_2', 2, '_bx_payment_pre_values_rc_2', ''),
+('bx_payment_reasons_cancel', 'rc_3', 3, '_bx_payment_pre_values_rc_3', ''),
+('bx_payment_reasons_cancel', 'rc_4', 4, '_bx_payment_pre_values_rc_4', ''),
+('bx_payment_reasons_cancel', 'rc_5', 5, '_bx_payment_pre_values_rc_5', ''),
+('bx_payment_reasons_cancel', 'rc_6', 6, '_bx_payment_pre_values_rc_6', '');
+
 -- STUDIO PAGE & WIDGET
 INSERT INTO `sys_std_pages`(`index`, `name`, `header`, `caption`, `icon`) VALUES
 (3, @sName, '_bx_payment', '_bx_payment', 'bx_payment@modules/boonex/payment/|std-icon.svg');

+ 45 - 21
modules/boonex/payment/js/subscriptions.js

@@ -9,51 +9,75 @@
  */
 
 function BxPaymentSubscriptions(oOptions) {
-	this.init(oOptions);
+    this.init(oOptions);
 }
 
 BxPaymentSubscriptions.prototype = new BxPaymentMain();
 
 BxPaymentSubscriptions.prototype.init = function(oOptions) {
-	if($.isEmptyObject(oOptions))
-		return;
+    if($.isEmptyObject(oOptions))
+        return;
 
-	this._sActionsUrl = oOptions.sActionUrl;
+    this._sActionsUrl = oOptions.sActionUrl;
     this._sObjName = oOptions.sObjName == undefined ? 'oPmtSubscriptions' : oOptions.sObjName;
     this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
     this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
 };
 
 BxPaymentSubscriptions.prototype.getDetails = function(oLink, iId) {
-	this._performRequest(oLink, iId, 'subscription_get_details');
+    this._performRequest(oLink, iId, 'subscription_get_details');
 };
 
 BxPaymentSubscriptions.prototype.changeDetails = function(oLink, iId) {
-	this._performRequest(oLink, iId, 'subscription_change_details');
+    this._performRequest(oLink, iId, 'subscription_change_details');
 };
 
 BxPaymentSubscriptions.prototype.getBilling = function(oLink, iId) {
-	this._performRequest(oLink, iId, 'subscription_get_billing');
+    this._performRequest(oLink, iId, 'subscription_get_billing');
 };
 
 BxPaymentSubscriptions.prototype.changeBilling = function(oLink, iId) {
-	this._performRequest(oLink, iId, 'subscription_change_billing');
+    this._performRequest(oLink, iId, 'subscription_change_billing');
 };
 
 BxPaymentSubscriptions.prototype.requestCancelation = function(oLink, iId) {
-	this._performRequest(oLink, iId, 'subscription_cancelation');
+    this._performRequest(oLink, iId, 'subscription_cancelation');
 };
 
-BxPaymentSubscriptions.prototype.cancel = function(oLink, iId, sGrid) {
-	var $this = this;
+BxPaymentSubscriptions.prototype.onSubmitCancelationReason = function(oForm) {
+    oForm = $(oForm);
 
-	var oParams = {};
-	if(sGrid != undefined)
-            oParams.grid = sGrid;
+    if(oForm.find("[name = 'items']:checked").val() == 'rc_0' && oForm.find("[name = 'other']").val() == '') {
+        oForm.find(".bx-payment-cs-other .bx-form-warn").html(_t('_bx_payment_form_input_err')).show();
+        return false;
+    }
 
-	bx_confirm(_t('_bx_payment_msg_confirm_cancelation'), function() {
-            $this._performRequest(oLink, iId, 'subscription_cancel', oParams);
-	}, function() {}, {
+    return true;
+};
+
+BxPaymentSubscriptions.prototype.onChangeCancelationReason = function(oElement) {
+    var bOther = $(oElement).val() == 'rc_0';
+    var oOther = $(oElement).parents('.bx-form-element-wrapper:first').siblings('.bx-payment-cs-other');
+    oOther.toggleClass('bx-payment-cs-hidden', !bOther);
+    if(!bOther)
+        oOther.find("[name = 'other']").val('');
+};
+
+BxPaymentSubscriptions.prototype.cancel = function(oLink, iId, sGrid, iConfirm) {
+    var $this = this;
+
+    var oParams = {};
+    if(sGrid != undefined)
+        oParams.grid = sGrid;
+
+    var fPerformYes = function() {
+        $this._performRequest(oLink, iId, 'subscription_cancel', oParams);
+    };
+
+    if(iConfirm != undefined && parseInt(iConfirm) == 0)
+        fPerformYes();
+    else
+        bx_confirm(_t('_bx_payment_msg_confirm_cancelation'), fPerformYes, function() {}, {
             yes: {
                 title: _t('_bx_payment_txt_unsubscribe_yes')
             },
@@ -64,7 +88,7 @@ BxPaymentSubscriptions.prototype.cancel = function(oLink, iId, sGrid) {
 };
 
 BxPaymentSubscriptions.prototype._performRequest = function(oLink, iId, sUri, oParams) {
-	var $this = this;
+    var $this = this;
     var oDate = new Date();
 
     this.loadingInPopup(oLink, true);
@@ -73,11 +97,11 @@ BxPaymentSubscriptions.prototype._performRequest = function(oLink, iId, sUri, oP
         this._sActionsUrl + sUri + '/' + iId,
         $.extend({}, {_t:oDate.getTime()}, oParams),
         function(oData){
-        	$this.loadingInPopup(oLink, false);
+            $this.loadingInPopup(oLink, false);
 
-        	$(".bx-popup-applied:visible").dolPopupHide();
+            $(".bx-popup-applied:visible").dolPopupHide();
 
-        	processJsonData(oData);
+            processJsonData(oData);
         },
         'json'
     );

+ 5 - 0
modules/boonex/payment/template/css/subscriptions.css

@@ -5,6 +5,11 @@
 	max-height: 20px;
 }
 
+/*--- Actions Menu ---*/
+div.bx-payment-cs-hidden {
+    display: none;
+}
+
 /*--- View Details ---*/
 div.bx-payment-view-details {
     border-top-width: 0px;

+ 3 - 0
modules/boonex/payment/template/order_subscription.html

@@ -36,6 +36,9 @@
                 <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
                     <div class="bx-payment-vo-caption">__txt_deleted__</div><div class="bx-payment-vo-content">__deleted__</div>
                 </div>
+                <div class="bx-payment-vo-row bx-def-padding-thd bx-def-border-top bx-clearfix">
+                    <div class="bx-payment-vo-caption">__txt_deleted_reason__</div><div class="bx-payment-vo-content">__deleted_reason__</div>
+                </div>
             </bx_if:show_deleted>
         </div>
     </div>

+ 19 - 0
modules/boonex/payment/template/subscription_form.html

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

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

@@ -13,6 +13,7 @@
     <string name="_bx_payment_option_extended_mode"><![CDATA[Расширенный режим (позволяет продавцам использовать тестовый режим и т. д.).]]></string>
     <string name="_bx_payment_option_credits_only"><![CDATA[Режим оплаты только кредитами (приложение 'Кредиты' должно быть установлено).]]></string>
     <string name="_bx_payment_option_single_seller"><![CDATA[Режим единого продавца (все продается от имени 'Главный продавец').]]></string>
+    <string name="_bx_payment_option_sbs_cancel_survey"><![CDATA[Включите опрос 'Причина отмены подписки'.]]></string>
     <string name="_bx_payment_option_commissions"><![CDATA[Включить расчет комиссий]]></string>
     <string name="_bx_payment_option_inv_issue_day"><![CDATA[День месяца, когда автоматически генерятся счета-фактуры (1, 2, 3 и тп)]]></string>
     <string name="_bx_payment_option_inv_lifetime"><![CDATA[Срок оплаты - количество дней после даты выставления счета-фактуры]]></string>
@@ -273,11 +274,26 @@
     <string name="_bx_payment_form_invoices_input_cancel_sys"><![CDATA[Отменить]]></string>
     <string name="_bx_payment_form_invoices_input_cancel"><![CDATA[Отменить]]></string>
 
+    <string name="_bx_payment_form_cs_input_items"><![CDATA[Почему вы хотите отменить подписку?]]></string>
+    <string name="_bx_payment_form_cs_input_other"><![CDATA[Ваш вариант]]></string>
+    <string name="_bx_payment_form_cs_input_submit"><![CDATA[Отправить]]></string>
+    <string name="_bx_payment_form_cs_input_cancel"><![CDATA[Отменить]]></string>
+
+    <string name="_bx_payment_form_input_err"><![CDATA[Это поле необходимо. Пожалуйста, заполните его.]]></string>
     <string name="_bx_payment_form_input_email_err_cor_or_emp"><![CDATA[Используйте правильный адрес электронной почты или оставьте поле пустым.]]></string>
 
     <!-- Predefined Values -->
     <string name="_bx_payment_pre_lists_currencies"><![CDATA[Валюты]]></string>
 
+    <string name="_bx_payment_pre_lists_reasons_cancel"><![CDATA[Причины для отмены подписки]]></string>
+    <string name="_bx_payment_pre_values_rc_0"><![CDATA[Другое]]></string>
+    <string name="_bx_payment_pre_values_rc_1"><![CDATA[Затраты и бюджетирование]]></string>
+    <string name="_bx_payment_pre_values_rc_2"><![CDATA[Скрытые платежи и проблемы с выставлением счетов]]></string>
+    <string name="_bx_payment_pre_values_rc_3"><![CDATA[Низкий уровень использования]]></string>
+    <string name="_bx_payment_pre_values_rc_4"><![CDATA[Потеря интереса]]></string>
+    <string name="_bx_payment_pre_values_rc_5"><![CDATA[Неудовлетворительный пользовательский опыт]]></string>
+    <string name="_bx_payment_pre_values_rc_6"><![CDATA[Есть альтернативы получше]]></string>
+
     <!-- ACL -->
     <string name="_bx_payment_acl_action_purchase"><![CDATA[Покупать]]></string>
     <string name="_bx_payment_acl_action_sell"><![CDATA[Продавать]]></string>
@@ -409,6 +425,7 @@
     <string name="_bx_payment_txt_message"><![CDATA[Результат]]></string>
     <string name="_bx_payment_txt_date"><![CDATA[Дата]]></string>
     <string name="_bx_payment_txt_deleted"><![CDATA[Дата отмены]]></string>
+    <string name="_bx_payment_txt_deleted_reason"><![CDATA[Причина отмены]]></string>
     <string name="_bx_payment_txt_products"><![CDATA[Продукты]]></string>
     <string name="_bx_payment_txt_buyer_name_mask"><![CDATA[{0} {1}]]></string>
     <string name="_bx_payment_txt_none"><![CDATA[нет]]></string>