Как подружить Яндекс Кассу с Shopkeeper3?

Приветствую! Погуглил инфу и не нашел дельного ответа на свой вопрос. Пишу сюда, в надежде что кто-нибудь поможет мне.
Итак. Есть сайт. Стоит задача сделать форму бронирования услуги на сайте. По клику на кнопку товара забронировать всплывает форма, далее после заполнения всех полей и нажатия по кнопке отправить это все дело должно редиректиться на платежную платформу Яндекса. НО перенаправления не происходит. В логах пусто.
Шаблон карточки товара:
<div class="column">
	<div class="sc-top-event-item shk-item" data-equalizer-watch>
		<a class="sc-bl" href="[[+link_attributes:is=``:then=`[[+uri]]`:else=`[[+link_attributes]]`]]">
		<img class="lazy" title="[[+pagetitle]]" alt="[[+pagetitle]]" data-original="[[+tv.PageImage]]" height="180" width="289">
		</a>
		<div class="sc-top-event-time">[[+tv.datebegin:date=`%e %b`]]  [[+tv.dateend:date=`- %e %b`]]</div>
		<div class="sc-top-event-price">[[+tv.price]] руб.</div>
		<div class="sc-top-event-title">[[+pagetitle]]</div>
		<ul class="no-bullet sc-top-event-groups">
		[[!pdoPage ?
		&includeTVs=`datebegin`
		&includeContent=`1`
		&select=`uri,pagetitle`
		&parents=`[[+id]]`
		&limit=`0`
		&tpl=`groups.tpl`
		&sortby=`datebegin` 
        &sortdir=`ASC`
		]]
        </ul>

        <a aria-controls="subscribeModal" aria-haspopup="true" class="button" data-toggle="subscribeModal" tabindex="0"  data-idtovar="[[+id]]" >Забронировать место</a>

		<div class="sc-top-read"><a class="sc-top-event-link" href="[[+link_attributes:is=``:then=`[[+uri]]`:else=`[[+link_attributes]]`]]">Подробнее</a></div>
		<div class="sc-top-item-line"></div>
	</div>
</div>
Форму с корзиной вызываю так:

<div class="reveal" id="subscribeModal" data-reveal data-vOffset=0 data-vOffset=30>
[[!Shopkeeper3@cart_catalog]]
[[!AjaxForm?
&form=`tpl.AjaxForm` 
&snippet=`FormIt` 
&hooks=`spam,shk_fihook,YandexMoneyHook,email,FormItAutoResponder`
&submitVar=`order`
&emailTpl=`shopOrderReport`
&emailSubject=`В интернет-магазине "[[++site_name]]" сделан новый заказ`
&emailTo=`info@blabla.ru`
&emailFrom=`info@blabla.ru`

&fiarSubject=`Вы сделали заказ в интернет-магазине "[[++site_name]]"`
&fiarTpl=`shopOrderReport`
&fiarFromName=`[[++site_name]]`
&_fiarReplyTo=`[[++emailsender]]`
&fiarToField=`email`

&fiarReplyTo=`info@blabla.ru`
&fiarSender=`info@blabla.ru`
  &emailTpl=`tpl.email`
  &validate=`agree:required,email:required,fullname:required,phone:required:regexp="^\+7\s\(\d{3}\)\s\d{3}\s\d{2}\s\d{2}$",course:required,g-recaptcha-response:required`
  &validationErrorMessage=`В форме содержатся ошибки!`
  &successMessage=`Сообщение успешно отправлено`
  &phone.vTextRequired=`Укажите Ваш телефон`
  &errTpl=`<br /><span class="error">[[+error]]</span>`
]]



<!--- info@blabla.ru,  spam,shk_fihook,recaptchav2,FormItIsChecked,email,FormItAutoResponder,YandexMoneyHook,FormItSaveForm--->
    <button class="close-button" data-close aria-label="Закрыть" type="button"><span aria-hidden="true">×</span></button>
</div>
Для добавления товара повесил обработчик на кнопку «Забронировать место»
$('.button').click(function(){
var idtovar = $(this).attr('data-idtovar');
    SHK.fillCart(idtovar,1);
});
Для того чтобы содержимое корзины обновлялось при клике на кнопку — добавил
function SHKloadCartCallback(){
    SHK.refreshCart();
}
Кто подскажет что?
Roman
22 июня 2019, 17:56
modx.pro
1 556
0

Комментарии: 16

Иван
03 июля 2019, 10:46
0
Такая же проблема!
Подключил Яндекс кассу, форма с корзиной на Ajax.
При нажатии на кнопку отправить перенаправление на платежную систему Яндекс не происходит.
Автор, удалось разобраться в чем дело и решить проблему?
    Roman
    03 июля 2019, 10:50
    0
    Опытным путем выяснил что нужно только через Formit, через AjaxForm ни в какую не хотел работать. Так же если у Вас Shopkeeper3 а ЯндексКасса самая старая — yandexmoney-1.1.0-pl то возникнут проблемы, для их устранения нужно поменять в YandexMoneyHook следующие строки:
    $modx->addPackage('shopkeeper',  $modx->getOption('core_path').'components/shopkeeper/model/');
    
        $order = $modx->getObject('SHKorder', $order_id);
    на
    $modx->addPackage('shopkeeper3',  $modx->getOption('core_path').'components/shopkeeper3/model/');
      $order = $modx->getObject('shk_order', $order_id);
    а так же нужно поменять строки в обработчике connector_result.php
      Иван
      05 июля 2019, 12:02
      0
      Может возникнет схожая проблема.
      Откорректировал дополнительно следующие файлы:

      assets/components/yandexmoney/connector_result.php

      core/components/yandexmoney/model/yandexmoney.class.php
      (!) в последнем файле необходимо заменить все элементы
      SHKorder
      на
      shk_order
    Иван
    05 июля 2019, 12:01
    0
    Может возникнет схожая проблема.
    Откорректировал дополнительно следующие файлы:

    assets/components/yandexmoney/connector_result.php

    core/components/yandexmoney/model/yandexmoney.class.php
    (!) в последнем файле необходимо заменить все элементы SHKorder на shk_order
      Roman
      05 июля 2019, 12:28
      0
      Совсем забыл сказать, тоже проводил данные манипуляции с файликом
      core/components/yandexmoney/model/yandexmoney.class.php
      а так же менял параметр в функции addPackage, там где стоял shopkeeper просто добавлял цифру 3
      addPackage('shopkeeper3' ...... );
      и пути прописывал
      components/shopkeeper3/model/
        Vadimilian
        17 сентября 2019, 16:50
        0
        А какую версию пакета yandexmoney вы используете? Я скачал версию 1.0.4-pl отсюда yandex.ru/support/checkout/instructions/modx.html и выполнил замены во всех файлах, но все равно не работает.
          Иван
          18 сентября 2019, 15:18
          0
          Качал с того же сайта.
          1.0.4-pl
            Vadimilian
            18 сентября 2019, 15:53
            0
            И все работает? У меня в хуке и в файлах
            assets/components/yandexmoney/connector_result.php
            core/components/yandexmoney/model/yandexmoney.class.php
            по дефолту было
            $modx->addPackage('shopkeeper', MODX_CORE_PATH."components/shopkeeper/model/");
            $order = $modx->getObject('SHKorder', array('id' => $order_id));
            а это не совсем то, что в комментарии Романа. У вас не так было? Я везде поменял на
            $modx->addPackage('shopkeeper3', MODX_CORE_PATH."components/shopkeeper3/model/");
            $order = $modx->getObject('shk_order', array('id' => $order_id));
            и заменил все остальные элементы SHKorder на shk_order, но все равно не пашет.
            Может быть надо поменять
            MODX_CORE_PATH
            на
            $modx->getOption('core_path')
            и
            array('id' => $order_id)
            на
            $order_id
            или я что-то еще упускаю? Заранее благодарю за ответ.
              Иван
              18 сентября 2019, 16:17
              0
              assets/components/yandexmoney/connector_result.php

              core/components/yandexmoney/model/yandexmoney.class.php

              эти файлы редактировали?
                Vadimilian
                18 сентября 2019, 16:19
                0
                Да. ВЫ MODX_CORE_PATH не меняли?
                  Иван
                  18 сентября 2019, 16:23
                  0
                  Нет, его оставил без изменений
                    Vadimilian
                    18 сентября 2019, 16:27
                    0
                    Причем, если выбрать метод оплаты, не связанный с яндекс кассой, то заказ тоже не отправится. Видимо YandexMoneyHook не позволяет.
                      Vadimilian
                      10 октября 2019, 15:53
                      0
                      Продолжаю свои мучения… Подскажете, какая у вас версия modx и php? У меня modx 2.7.2 (до этого пробовал на 2.7.0) и php 7.0. Может дело в этом? Я уже не знаю, почему может не работать. Поддержка яндекса не помогает вообще, только отписки.
                        Roman
                        10 октября 2019, 16:49
                        0
                        Я делал все по гайду яндекса и у меня не заработала. Ниже привел правки в коде
        Roman
        10 октября 2019, 16:47
        0
        Конфиг:
        MODX Revolution 2.7.1-pl
        shopkeeper3 3.2.7-pl3
        yandexmoney 1.0.4-pl
        Вывожу через Formit.
        [[!FormIt?
        &hooks=`spam,shk_fihook,email,FormItAutoResponder,YandexMoneyHook,redirect`
        &submitVar=`order-[[+id]]`
        &emailTpl=`shopOrderReport`
        &emailSubject=`В интернет-магазине [[++site_name]] сделан новый заказ`
        &emailTo=`info@blabla.ru`
        &emailFrom=`info@blabla.ru`
        
        &fiarSubject=`Вы сделали заказ в интернет-магазине [[++site_name]]`
        &fiarTpl=`shopOrderReport`
        &fiarFromName=`[[++site_name]]`
        &fiarFrom=`info@blabla.ru`
        &fiarReplyTo=`[[++emailsender]]`
        &fiarToField=`email`
        
        
        &redirectTo=`357`
        &validate=`agree:required,email:required,fullname:required,phone:required:regexp="^\+7\s\(\d{3}\)\s\d{3}\s\d{2}\s\d{2}$",course:required,g-recaptcha-response:required`
        &errTpl=`<br /><span class="error">[[+error]]</span>`
        ]]
        Сниппет: shk_fihook
        <?php
        /**
         * FormIt hook for Shopkeeper 3.x
         */
        
        //ini_set('display_errors',1);
        //error_reporting(E_ALL);
        
        $output = false;
        
        if(!defined('SHOPKEEPER_PATH')){
            define('SHOPKEEPER_PATH', MODX_CORE_PATH."components/shopkeeper3/");
        }
        
        //Определяем параметры сниппета Shopkeeper
        $sys_property_sets = $modx->getOption( 'shk3.property_sets', $modx->config, 'default' );
        $sys_property_sets = explode( ',', $sys_property_sets );
        $propertySetName = trim( current( $sys_property_sets ) );
        
        $snippet = $modx->getObject('modSnippet',array('name'=>'Shopkeeper3'));
        $properties = $snippet->getProperties();
        if( $propertySetName != 'default' && $modx->getCount( 'modPropertySet', array( 'name' => $propertySetName ) ) > 0 ){
            $propSet = $modx->getObject( 'modPropertySet', array( 'name' => $propertySetName ) );
            $propSetProperties = $propSet->getProperties();
            if(is_array($propSetProperties)) $properties = array_merge($properties,$propSetProperties);
        }
        
        $lang = $modx->getOption( 'lang', $properties, 'ru' );
        $modx->getService( 'lexicon', 'modLexicon' );
        $modx->lexicon->load( $lang . ':shopkeeper3:default' );
        
        if( !empty( $_SESSION['shk_order'] ) ){
            
            require_once SHOPKEEPER_PATH . "model/shopkeeper.class.php";
            $shopCart = new Shopkeeper( $modx, $properties );
            
            $modx->addPackage( 'shopkeeper3', SHOPKEEPER_PATH . 'model/' );
            
            //shopkeeper settings
            $contacts_fields = array();
            $response = $modx->runProcessor('getsettings',
                array( 'settings' => array('contacts_fields') ),
                array( 'processors_path' => $modx->getOption( 'core_path' ) . 'components/shopkeeper3/processors/mgr/' )
            );
            if ($response->isError()) {
                echo $response->getMessage();
            }
            if($result = $response->getResponse()){
                
                $temp_arr = !empty( $result['object']['contacts_fields'] ) ? $result['object']['contacts_fields'] : array();
                if( !empty( $temp_arr ) ){
                    
                    foreach( $temp_arr as $opt ){
                        
                        $contacts_fields[$opt['name']] = $opt;
                        
                    }
                    
                }
                
            }
            
            $userId = $modx->getLoginUserID( $modx->context->key );
            if( !$userId ) $userId = 0;
            
            //Контактные данные
            $contacts = array();
            $allFormFields = $hook->getValues();
            foreach( $allFormFields as $key => $val ){
                
                if( in_array( $key, array_keys( $contacts_fields ) ) ){
                    
                    $temp_arr = array(
                        'name' => $contacts_fields[$key]['name'],
                        'value' => $val,
                        'label' => $contacts_fields[$key]['label']
                    );
                    
                    array_push( $contacts, $temp_arr );
                    
                }
                
            }
            
            $contacts = json_encode( $contacts );
            
            $emailField = $modx->getOption( 'fiarToField', $hook->config, 'email' );
            $phoneField = $modx->getOption( 'phoneField', $hook->config, 'phone' );
            $deliveryField = $modx->getOption( 'deliveryField', $hook->config, 'shk_delivery' );
            $paymentField = $modx->getOption( 'paymentField', $hook->config, 'payment' );
            
            //Доставка
            $delivery_price = !empty( $shopCart->delivery['price'] ) ? $shopCart->delivery['price'] : 0;
            $delivery_name = !empty( $shopCart->delivery['label'] ) ? $shopCart->delivery['label'] : '';
            if( !$delivery_name ){
        	$delivery_name = !empty( $allFormFields[$deliveryField] ) ? $allFormFields[$deliveryField] : '';
            }
            
            //Сохраняем данные заказа
            $order = $modx->newObject('shk_order');
            $insert_data = array(
                'contacts' => $contacts,
                'options' => '',
                'price' => Shopkeeper::$price_total,
                'currency' => $shopCart->config['currency'],
                'date' => strftime('%Y-%m-%d %H:%M:%S'),
                'sentdate' => strftime('%Y-%m-%d %H:%M:%S'),
                'note' => '',
                'email' => isset( $allFormFields[$emailField] ) ? $allFormFields[$emailField] : '',
                'delivery' => $delivery_name,
                'delivery_price' => $delivery_price,
                'payment' => isset( $allFormFields[$paymentField] ) ? $allFormFields[$paymentField] : '',
                'tracking_num' => '',
                'phone' => isset( $allFormFields[$phoneField] ) ? $allFormFields[$phoneField] : '',
                'status' => $modx->getOption( 'shk3.first_status', null, '1' )
            );
            if( $userId ){
                $insert_data['userid'] = $userId;
            }
            $order->fromArray($insert_data);
            $saved = $order->save();
            
            //Сохраняем товары заказа
            if( $saved ){
        
                $purchasesData = $shopCart->getProductsData( true );
        
                foreach( $shopCart->data as $key => $p_data ){
        
                    $options = !empty( $p_data['options'] ) ? json_encode( $p_data['options'] ) : '';
                    $fields_data = !empty( $purchasesData[ $key ] ) ? $purchasesData[ $key ] : array();
                    $fields_data['url'] = !empty( $p_data['url'] ) ? $p_data['url'] : '';
                    unset( $fields_data['id'] );
                    $fields_data_str = json_encode( $fields_data );
        
                    $insert_data = array(
                        'p_id' => $p_data['id'],
                        'order_id' => $order->id,
                        'name' => $p_data['name'],
                        'price' => $p_data['price'],
                        'count' => $p_data['count'],
                        'class_name' => $p_data['className'],
                        'package_name' => $p_data['packageName'],
                        'data' => $fields_data_str,
                        'options' => $options
                    );
        
                    $purchase = $modx->newObject('shk_purchases');
                    $purchase->fromArray( $insert_data );
                    $purchase->save();
        
                }
        
                $shopCart->setOrderDataSession( $order->toArray() );
        
            }
            
            $modx->invokeEvent( 'OnSHKChangeStatus', array( 'order_ids' => array( $order->id ), 'status' => $order->status ) );
            
            $orderOutputData = $shopCart->getOrderData( $order->id );
            
            //OnSHKsaveOrder
            $evtOut = $modx->invokeEvent('OnSHKsaveOrder',array('order_id' => $order->get('id')));
            if(is_array($evtOut)) $orderOutputData .= implode('',$evtOut);
            
            $hook->setValues(array(
                'orderID' => $order->get('id'),
                'orderDate' => $order->get('date'),
                'orderPrice' => $order->get('price'),
                'orderCurrency' => $shopCart->config['currency'],
                'orderOutputData' => $orderOutputData
            ));
            
            $shopCart->request_empty( false );
            
            $output = true;
            
        }else{
            
            $hook->addError( 'error_message', $modx->lexicon('shk.order_empty') );
            $output = false;
            
        }
        
        return $output;
        assets/components/yandexmoney/connector_result.php
        <?php
        require_once dirname(dirname(dirname(dirname(__FILE__)))).'/config.core.php';
        
        require_once MODX_CORE_PATH.'config/'.MODX_CONFIG_KEY.'.inc.php';
        require_once MODX_CORE_PATH.'model/modx/modx.class.php';
        
        $modx = new modX();
        $modx->initialize('web');
        
        $snippet = $modx->getObject('modSnippet', array('name' => 'YandexMoney'));
        $config  = $snippet->getProperties();
        
        if (!defined('YANDEXMONEY_PATH')) {
            define('YANDEXMONEY_PATH', MODX_CORE_PATH."components/yandexmoney/");
        }
        
        require_once YANDEXMONEY_PATH.'model/yandexmoney.class.php';
        
        if (isset($_GET['fail']) && $_GET['fail'] == 1) {
            if ($res = $modx->getObject('modResource', $config['fail_page_id'])) {
                $modx->sendRedirect($modx->makeUrl($config['fail_page_id'], '', '', 'full'));
            }
            exit;
        } elseif (isset($_GET['success']) && $_GET['success'] == 1) {
            if ($res = $modx->getObject('modResource', $config['success_page_id'])) {
                $modx->sendRedirect($modx->makeUrl($config['success_page_id'], '', '', 'full'));
            }
            exit;
        } elseif (isset($_GET['return']) && $_GET['return'] == 1) {
            $orderId = isset($_GET['order_id']) ? (int)$_GET['order_id'] : 0;
            if ($orderId !== 0) {
                $modx->addPackage('shopkeeper3',  $modx->getOption('core_path').'components/shopkeeper3/model/');;
                $order = $modx->getObject('shk_order',array('id'=>$orderId));
                if ($order) {
                    $sql  = 'SELECT payment_id FROM '.$modx->getTableName('YandexMoneyKassaPayment').' WHERE `order_id` = :orderId';
                    $stmt = $modx->prepare($sql);
                    $stmt->bindValue(':orderId', $orderId, \PDO::PARAM_INT);
                    $stmt->execute();
                    $dataSet = $stmt->fetch();
                    $stmt->closeCursor();
                    if (!empty($dataSet)) {
                        $paymentId = $dataSet[0];
                        $ym        = new Yandexmoney($modx, $config);
                        $payment   = $ym->getPaymentById($paymentId);
                        if ($payment !== null) {
                            if ($payment->getPaid()) {
                                if ($payment->getStatus() === \YandexCheckout\Model\PaymentStatus::WAITING_FOR_CAPTURE) {
                                    $ym->capturePayment($payment, false);
                                }
                                $paymentInfo = $ym->getPaymentById($paymentId);
                                if ($paymentInfo->getStatus() == \YandexCheckout\Model\PaymentStatus::SUCCEEDED) {
                                    $ym->updateOrderStatus($order, $config['ya_billing_status']);
                                }
                                if ($res = $modx->getObject('modResource', $config['success_page_id'])) {
                                    $modx->sendRedirect($modx->makeUrl($config['success_page_id'], '', '', 'full'));
                                }
                                exit;
                            }
                        }
                    }
                }
            }
            if ($res = $modx->getObject('modResource', $config['fail_page_id'])) {
                $modx->sendRedirect($modx->makeUrl($config['fail_page_id'], '', '', 'full'));
            }
            exit;
        } elseif (isset($_GET['notification']) && $_GET['notification'] == 1) {
            $source = file_get_contents('php://input');
            $ym     = new Yandexmoney($modx, $config);
            if (empty($source)) {
                $ym->log('notice', 'Call capture notification controller without body');
                header('HTTP/1.1 400 Empty notification object');
        
                return;
            }
            $ym->log('info', 'Notification body: '.$source);
            $json = json_decode($source, true);
            if (empty($json)) {
                if (json_last_error() === JSON_ERROR_NONE) {
                    $message = 'empty object in body';
                } else {
                    $message = 'invalid object in body: '.json_last_error_msg();
                }
                $ym->log('warning', 'Invalid parameters in capture notification controller - '.$message);
                header('HTTP/1.1 400 Invalid notification object');
        
                return;
            }
            try {
                if ($json['event'] == \YandexCheckout\Model\NotificationEventType::PAYMENT_WAITING_FOR_CAPTURE) {
                    $object = new YandexCheckout\Model\Notification\NotificationWaitingForCapture($json);
                    $ym->log('error', 'Notification waiting for capture init');
                } else {
                    $object = new YandexCheckout\Model\Notification\NotificationSucceeded($json);
                    $ym->log('error', 'Notification succeeded init');
                }
            } catch (\Exception $e) {
                $ym->log('error', 'Invalid notification object - '.$e->getMessage());
                header('HTTP/1.1 500 Server error: '.$e->getMessage());
        
                return;
            }
            $payment = $ym->getPaymentById($object->getObject()->getId());
            if ($payment === null) {
                $ym->log('error', 'Payment not found ');
                echo json_encode(array('success' => false, 'reason' => 'Payment not found'));
                exit();
            }
            $result = $ym->capturePayment($object->getObject());
            if (!$result) {
                header('HTTP/1.1 500 Server error 1');
                exit();
            }
            if ($result->getStatus() === \YandexCheckout\Model\PaymentStatus::SUCCEEDED) {
                try {
                    $orderId = $object->getObject()->getMetadata()->offsetGet('order_id');
                    $modx->addPackage('shopkeeper3',  $modx->getOption('core_path').'components/shopkeeper3/model/');
                    $order = $modx->getObject('shk_order',array('id'=>$orderId));
                    
                    $res   = $ym->updateOrderStatus($order, $config['ya_billing_status']);
                } catch (Exception $e) {
                    $ym->log('info', var_export($e, true));
                }
            } else {
                $ym->log('info', 'Failed');
            }
        
            echo json_encode(array('success' => ($result->getStatus() === \YandexCheckout\Model\PaymentStatus::SUCCEEDED)));
            exit();
        }
        
        $ym = new Yandexmoney($modx, $config);
        $ym->ProcessResult();
        Не помню, вносил ли правки но кину сюда же
        core/components/yandexmoney/model/yandexmoney.class.php
        <?php
        
        /**
         * YandexMoney for MODX Revo
         *
         * Payment
         *
         * @author YandexMoney
         * @package yandexmoney
         * @version 2.0.0
         */
        
        use YandexCheckout\Model\Payment;
        
        require_once YANDEXMONEY_PATH.'lib/autoload.php';
        
        $modx->addPackage('yandexmoney', YANDEXMONEY_PATH . 'model/');
        
        class Yandexmoney
        {
            /** @var int Оплата через yandex.деньги вообще не используется */
            const MODE_NONE = 0;
        
            /** @var int Оплата производится через Яндекс.Кассу */
            const MODE_KASSA = 1;
        
            /** @var int Оплата производится через Яндекс.Деньги */
            const MODE_MONEY = 2;
        
            /** @var int Оплата производится через Яндекс.Платёжку */
            const MODE_BILLING = 3;
        
            /** @var int Какой способ оплаты используется, одна из констант MODE_XXX */
            private $mode;
        
            private $paymode;
        
            public $email = false;
            public $phone = false;
        
            public $test_mode;
            public $org_mode;
        
            public $orderId;
            public $orderTotal;
            public $userId;
        
            public $successUrl;
            public $failUrl;
        
            public $reciver;
            public $formcomment;
            public $short_dest;
            public $writable_targets = 'false';
            public $comment_needed = 'true';
            public $label;
            public $quickpay_form = 'shop';
            public $payment_type = '';
            public $targets;
            public $sum;
            public $comment;
            public $need_fio = 'true';
            public $need_email = 'true';
            public $need_phone = 'true';
            public $need_address = 'true';
        
            public $shopid;
            public $account;
            public $password;
        
            public $method_ym;
            public $method_cards;
            public $method_cash;
            public $method_wm;
            public $method_ab;
            public $method_sb;
            public $method_installments;
        
            public $pay_method;
        
            public $alfaLogin;
            public $qiwiPhone;
        
            public $debug_log;
        
            /** @var string Идентификатор магазина в Яндекс.Платёжке */
            public $ya_billing_id;
        
            /** @var string Описание платежа, заданное из админки */
            public $ya_billing_purpose;
        
            /** @var string ФИО плательщика, переданное из запроса пользователя */
            public $ya_billing_fio;
        
            private $_apiClient;
        
            function __construct(modX &$modx, $config = array())
            {
                $this->mode = self::MODE_NONE;
                switch ($config['mode']) {
                    case 1:
                        $this->mode = self::MODE_MONEY;
                        break;
                    case 2:
                    case 3:
                        $this->mode = self::MODE_KASSA;
                        break;
                    case 4:
                        $this->mode = self::MODE_BILLING;
                        break;
                }
        
                $this->org_mode = ($config['mode'] == 2 || $config['mode'] == 3);
                $this->paymode = (bool) ($config['mode'] == 3);
        
                if (isset($config) && is_array($config)){
                    foreach ($config as $k=>$v){
                        if ($k != 'mode') {
                            $this->$k = $v;
                        }
                    }
                }
                $this->modx =& $modx;
                $this->config = $config;
        
                if (empty($this->debug_log)) {
                    $this->debug_log = false;
                } else {
                    $this->debug_log = true;
                }
            }
        
            public function getFormUrl()
            {
                if ($this->mode != self::MODE_BILLING) {
                    $demo = ($this->test_mode) ? 'demo' : '';
                    $mode = ($this->org_mode) ? '/eshop.xml' : '/quickpay/confirm.xml';
                    return 'https://' . $demo . 'money.yandex.ru' . $mode;
                }
                return 'https://money.yandex.ru/fastpay/confirm';
            }
        
            public function checkPayMethod()
            {
                if ($this->mode == self::MODE_BILLING) {
                    $fio = explode(' ', $_POST['ya-billing-fio']);
                    if (count($fio) != 3) {
                        return false;
                    }
                    foreach ($fio as $index => $value) {
                        $value = trim($value);
                        if (empty($value)) {
                            return false;
                        }
                        $fio[$index] = $value;
                    }
                    $this->ya_billing_fio = implode(' ', $fio);
                    return true;
                }
                if ($this->mode == self::MODE_KASSA) {
                    if (!$this->paymode) {
                        if (in_array($this->pay_method, \YandexCheckout\Model\PaymentMethodType::getEnabledValues())) {
                            if ($this->pay_method === \YandexCheckout\Model\PaymentMethodType::QIWI) {
                                $phone = preg_replace('/[^\d]+/', '', $this->qiwiPhone);
                                if (empty($phone)) {
                                    return false;
                                }
                                $this->qiwiPhone = $phone;
                            }
                            if ($this->pay_method === \YandexCheckout\Model\PaymentMethodType::ALFABANK) {
                                $login = trim($this->alfaLogin);
                                if (empty($login)) {
                                    return false;
                                }
                                $this->alfaLogin = $login;
                            }
                        }
                    }
                    return true;
                }
                return (in_array($this->pay_method, array('PC','AC','MC','GP','WM','AB','SB','MA','PB','QW', 'installments')) || $this->paymode);
            }
        
            public function getSelectHtml()
            {
                $result = json_encode(array('mode' => $this->mode));
                if ($this->mode == self::MODE_MONEY) {
                    return "<option value=''>Яндекс.Касса (банковские карты, электронные деньги и другое)</option>";
                } elseif ($this->mode == self::MODE_KASSA) {
                    if ($this->paymode) {
                        return "<option value=''>Яндекс.Касса (банковские карты, электронные деньги и другое)</option>";
                    }
                    $translations = array(
                        \YandexCheckout\Model\PaymentMethodType::ALFABANK => array('ab', 'Оплата через Альфа-Клик'),
                        \YandexCheckout\Model\PaymentMethodType::MOBILE_BALANCE => array('ma', 'Платеж со счета мобильного телефона'),
                        \YandexCheckout\Model\PaymentMethodType::CASH => array('cash', 'Оплата наличными через кассы и терминалы'),
                        \YandexCheckout\Model\PaymentMethodType::WEBMONEY => array('wm', 'Оплата из кошелька в системе WebMoney'),
                        \YandexCheckout\Model\PaymentMethodType::QIWI => array('qw', 'Оплата через QIWI Wallet'),
                        \YandexCheckout\Model\PaymentMethodType::SBERBANK => array('sb', 'Оплата через Сбербанк: оплата по SMS или Сбербанк Онлайн'),
                        \YandexCheckout\Model\PaymentMethodType::YANDEX_MONEY => array('ym', 'Оплата из кошелька в Яндекс.Деньгах'),
                        \YandexCheckout\Model\PaymentMethodType::BANK_CARD => array('cards', 'Оплата с произвольной банковской карты'),
                        \YandexCheckout\Model\PaymentMethodType::INSTALLMENTS => array('installments', 'Заплатить по частям'),
                        \YandexCheckout\Model\PaymentMethodType::TINKOFF_BANK => array('tinkoff_bank', 'Интернет-банк Тинькофф'),
                    );
                    $list_methods = array();
                    foreach (\YandexCheckout\Model\PaymentMethodType::getEnabledValues() as $paymentMethodCode) {
                        $list_methods[$paymentMethodCode] = array(
                            'key'   => $translations[$paymentMethodCode][0],
                            'label' => $translations[$paymentMethodCode][1],
                        );
                    }
                    $output = '';
                    foreach ($list_methods as $long_name => $method_desc) {
                        $key = $method_desc['key'];
                        $by_default = (in_array($key, array('ym', 'cards'))) ? true : $this->org_mode;
                        if ($this->{'method_' . $key} == 1 && $by_default) {
                            $output .= '<option value="' . $long_name . '"';
                            if ($this->pay_method == $long_name) {
                                $output .= ' selected ';
                            }
                            $output .= '>' . $method_desc['label'] . '</option>';
                        }
                    }
                    return $output;
                } elseif ($this->mode == self::MODE_BILLING) {
                    return "<option value='4'>Яндекс.Платежка (банковские карты, кошелек)</option>";
                }
                return $result;
            }
        
            public function createFormHtml()
            {
                global $modx;
        
                /** @var shk_order $order */
                $order = $modx->getObject('shk_order',array('id' => $this->orderId));
        
                if ($this->mode == self::MODE_KASSA) {
                    $redirectUrl = 'https://' . str_replace(array('http://', 'https://'), '' , $modx->config['site_url'])
                        . 'assets/components/yandexmoney/connector_result.php?return=1&order_id=' . $this->orderId;
                    $payment = $this->createKassaPayment($order, $redirectUrl);
                    if ($payment === null) {
                        header('Location: ' . $root.'assets/components/yandexmoney/connector_result.php?fail=1');
                        exit();
                    }
                }
        
                $html = '';
        
                $site_url = $modx->config['site_url'];
                $payType = ($this->paymode) ? '' : $this->pay_method;
                $addInfo = ($this->email!==false)?'<input type="hidden" name="cps_email" value="'.$this->email.'" >':'';
                $addInfo .= ($this->phone!==false)?'<input type="hidden" name="cps_phone" value="'.$this->phone.'" >':'';
                $html .= '<form method="POST" action="'.$this->getFormUrl().'"  id="paymentform" name = "paymentform">';
                if ($this->mode == self::MODE_KASSA) {
                    /** @var \YandexCheckout\Model\Confirmation\ConfirmationRedirect $confirmation */
                    $confirmation = $payment->getConfirmation();
                    if ($confirmation !== null && $confirmation->getType() === \YandexCheckout\Model\ConfirmationType::REDIRECT) {
                        $redirectUrl = $confirmation->getConfirmationUrl();
                    }
                    $html = '<script> document.location = "' . $redirectUrl . '"; </script>';
                } elseif ($this->mode == self::MODE_MONEY) {
                    $html .= '  <input type="hidden" name="receiver" value="'.$this->account.'">
                               <input type="hidden" name="formcomment" value="Order '.$this->orderId.'">
                               <input type="hidden" name="short-dest" value="Order '.$this->orderId.'">
                               <input type="hidden" name="writable-targets" value="'.$this->writable_targets.'">
                               <input type="hidden" name="comment-needed" value="'.$this->comment_needed.'">
                               <input type="hidden" name="label" value="'.$this->orderId.'">
                               <input type="hidden" name="quickpay-form" value="'.$this->quickpay_form.'">
                               <input type="hidden" name="paymentType" value="'.$this->pay_method.'">
                               <input type="hidden" name="targets" value="Заказ '.$this->orderId.'">
                               <input type="hidden" name="sum" value="'.$this->orderTotal.'" data-type="number" >
                               <input type="hidden" name="comment" value="'.$this->comment.'" >
                               <input type="hidden" name="need-fio" value="'.$this->need_fio.'">
                               <input type="hidden" name="need-email" value="'.$this->need_email.'" >
                               <input type="hidden" name="need-phone" value="'.$this->need_phone.'">
                               <input type="hidden" name="need-address" value="'.$this->need_address.'">
                                <input type="hidden" name="successUrl" value="'.$site_url.'assets/components/yandexmoney/connector_result.php?success=1">';
                } elseif ($this->mode == self::MODE_BILLING) {
                    $narrative = $this->parsePlaceholders($this->ya_billing_purpose, $order);
                    $html .= '<input type="hidden" name="formId" value="'.$this->ya_billing_id.'" />
                        <input type="hidden" name="narrative" value="'.htmlspecialchars($narrative).'" />
                        <input type="hidden" name="fio" value="'.htmlspecialchars($this->ya_billing_fio).'" />
                        <input type="hidden" name="sum" value="'.$this->orderTotal.'" />
                        <input type="hidden" name="quickPayVersion" value="2" />';
                    $this->updateOrderStatus($order, $this->config['ya_billing_status']);
                }
                if ($this->mode !== self::MODE_KASSA) {
                    $html .= '<input type="hidden" name="cms_name" value="modx" >
                        </form>
                        <script type="text/javascript">
                            document.getElementById("paymentform").submit();
                        </script>';
                }
        
                echo $html;
                exit;
            }
        
            /**
             * @param shk_order $order
             * @param string $redirectUrl
             * @return \YandexCheckout\Model\PaymentInterface
             */
            private function createKassaPayment($order, $redirectUrl)
            {
                try {
                    $builder = \YandexCheckout\Request\Payments\CreatePaymentRequest::builder();
                    $builder->setClientIp($_SERVER['REMOTE_ADDR'])
                        ->setAmount($this->orderTotal)
                        ->setCapture(true)
                        ->setDescription($this->createDescription($order))
                        ->setMetadata(array(
                            'order_id' => $this->orderId,
                            'cms_name' => 'ya_api_modx_revolution',
                            'module_version' => '1.0.4',
                        ));
                    $confirmation = array(
                        'type' => \YandexCheckout\Model\ConfirmationType::REDIRECT,
                        'returnUrl' => $redirectUrl,
                    );
                    if (!$this->paymode) {
                        if ($this->pay_method === \YandexCheckout\Model\PaymentMethodType::ALFABANK) {
                            $paymentMethod = array(
                                'type' => $this->pay_method,
                                'login' => $this->alfaLogin,
                            );
                            $confirmation = \YandexCheckout\Model\ConfirmationType::EXTERNAL;
                        } elseif ($this->pay_method === \YandexCheckout\Model\PaymentMethodType::QIWI) {
                            $paymentMethod = array(
                                'type' => $this->pay_method,
                                'phone' => $this->qiwiPhone,
                            );
                        } else {
                            $paymentMethod = $this->pay_method;
                        }
                        $builder->setPaymentMethodData($paymentMethod);
                    }
                    $builder->setConfirmation($confirmation);
                    if (isset($this->config['ya_kassa_send_check']) && $this->config['ya_kassa_send_check']) {
                        $this->addReceipt($builder, $order);
                    }
                    $request = $builder->build();
                    if (isset($this->config['ya_kassa_send_check']) && $this->config['ya_kassa_send_check']) {
                        $request->getReceipt()->normalize($request->getAmount());
                    }
                } catch (\Exception $e) {
                    $this->log('error', 'Failed to create request: ' . $e->getMessage());
                    return null;
                }
        
                try {
                    $response = $this->getClient()->createPayment($request);
                } catch (\Exception $e) {
                    $this->log('error', 'Failed to create payment: ' . $e->getMessage());
                    return null;
                }
        
                global $modx;
        
                /** @var YandexMoneyKassaPayment $record */
                $record = $modx->getObject('YandexMoneyKassaPayment', $this->orderId);
                $this->log('debug', 'Fetching payment from db: ' . ($record === null ? 'null' : $record->get('payment_id')));
                if ($record === null) {
                    $this->log('debug', 'Create db payment');
                    $record = $modx->newObject('YandexMoneyKassaPayment');
                    $record->set('order_id', $this->orderId);
                }
                $record->set('payment_id', $response->getId());
                $record->save();
        
                return $response;
            }
        
            /**
             * @param string $paymentId
             * @return \YandexCheckout\Model\PaymentInterface|null
             */
            public function getPaymentById($paymentId)
            {
                try {
                    $payment = $this->getClient()->getPaymentInfo($paymentId);
                } catch (Exception $e) {
                    $this->log('error', 'Failed to find payment ' . $paymentId);
                    $payment = null;
                }
                return $payment;
            }
        
            /**
             * @param \YandexCheckout\Model\PaymentInterface $payment
             * @param bool $fetch
             * @return \YandexCheckout\Model\PaymentInterface|null
             */
            public function capturePayment($payment, $fetch = true)
            {
                if ($fetch) {
                    $payment = $this->getPaymentById($payment->getId());
                    if ($payment === null) {
                        return null;
                    }
                }
                if ($payment->getStatus() === \YandexCheckout\Model\PaymentStatus::WAITING_FOR_CAPTURE) {
                    try {
                        $builder = \YandexCheckout\Request\Payments\Payment\CreateCaptureRequest::builder();
                        $builder->setAmount($payment->getAmount());
                        $request = $builder->build();
                    } catch (Exception $e) {
                        return null;
                    }
                    try {
                        $response = $this->getClient()->capturePayment($request, $payment->getId());
                    } catch (\Exception $e) {
                        return null;
                    }
                } else {
                    $response = $payment;
                }
                return $response;
            }
        
            /**
             * @param \YandexCheckout\Request\Payments\CreatePaymentRequestBuilder $builder
             * @param shk_order $order
             */
            private function addReceipt($builder, $order)
            {
                $builder->setReceiptEmail($order->_fields['email']);
        
                $shippingMethod = null;
                $shippingPrice = 0;
                if ($content = unserialize($order->_fields['content'])) {
                    foreach ($content as $item) {
                        if ($item['price'] > 0) {
                            $builder->addReceiptItem($item['name'], $item['price'], $item['count'], $this->config['tax_id']);
                        } elseif (isset($item['tv_add']['shk_delivery'])) {
                            $shippingMethod = $item['tv_add']['shk_delivery'];
                        }
                    }
                }
        
                if (!empty($shippingMethod)) {
                    foreach (unserialize($order->_fields['addit']) as $items) {
                        foreach ($items as $item) {
                            if (isset($item[0]) && $item[0] === $shippingMethod) {
                                $shippingPrice = $item[1];
                            }
                        }
                    }
                }
        
                if ($shippingMethod && $shippingPrice > 0) {
                    $builder->addReceiptShipping($shippingMethod, $shippingPrice, $this->config['tax_id']);
                }
            }
        
            public function checkSign($callbackParams)
            {
                if ($this->org_mode) {
                    $string = $callbackParams['action'].';'.$callbackParams['orderSumAmount'].';'.$callbackParams['orderSumCurrencyPaycash'].';'.$callbackParams['orderSumBankPaycash'].';'.$callbackParams['shopId'].';'.$callbackParams['invoiceId'].';'.$callbackParams['customerNumber'].';'.$this->password;
                    $md5 = strtoupper(md5($string));
                    return ($callbackParams['md5']==$md5);
                } else {
                    $string = $callbackParams['notification_type'].'&'.$callbackParams['operation_id'].'&'.$callbackParams['amount'].'&'.$callbackParams['currency'].'&'.$callbackParams['datetime'].'&'.$callbackParams['sender'].'&'.$callbackParams['codepro'].'&'.$this->password.'&'.$callbackParams['label'];
                    $check = (sha1($string) == $callbackParams['sha1_hash']);
                    if (!$check){
                        header('HTTP/1.0 401 Unauthorized');
                        return false;
                    }
                    return true;
                }
            }
        
            public function sendCode($callbackParams, $code)
            {
                if (!$this->org_mode) {
                    if ($code === 0) {
                        header('HTTP/1.0 200 OK');
                    } else {
                        header('HTTP/1.0 401 Unauthorized');
                    }
                    return;
                }
                header("Content-type: text/xml; charset=utf-8");
                $xml = '<?xml version="1.0" encoding="UTF-8"?>
                    <'.$callbackParams['action'].'Response performedDatetime="'.date("c").'" code="'.$code.'" invoiceId="'.$callbackParams['invoiceId'].'" shopId="'.$this->shopid.'"/>';
                echo $xml;
            }
        
            /* оплачивает заказ */
            public function ProcessResult()
            {
                $callbackParams = $_POST;
                if ($this->checkSign($callbackParams)) {
                    $order_id = ($this->org_mode)? intval($callbackParams["orderNumber"]):intval($callbackParams["label"]);
                    if ($order_id) {
                        $this->modx->addPackage('shopkeeper3', MODX_CORE_PATH."components/shopkeeper3/model/");
                        $order = $this->modx->getObject('shk_order',array('id'=>$order_id));
                        $amount = number_format($order->get('price'),2,".",'');
                        $pay_amount = number_format($callbackParams[($this->org_mode)?'orderSumAmount':'amount'], 2, '.', '');
                        if ($pay_amount === $amount) {
                            if ($callbackParams['action'] == 'paymentAviso' || !$this->org_mode){
                                $order->set('status', 5);
                                $order->save();
                            }
                            $this->sendCode($callbackParams, 0);
                        } else {
                            $this->sendCode($callbackParams, 100);
                        }
                    } else {
                        $this->sendCode($callbackParams, 200);
                    }
                } else {
                    $this->sendCode($callbackParams, 1);
                }
            }
        
            /**
             * @return int
             */
            public function getMode()
            {
                return $this->mode;
            }
        
            /**
             * Преобразует шаблон назначения платежа в удобоваримую строку
             * @param string $template Шаблон назначения платежя
             * @param shk_order $order Информация о заказе
             * @return string Строка для отправки в Яндекс.Деньги
             */
            private function parsePlaceholders($template, shk_order $order)
            {
                $replace = array(
                    '%order_id%' => $order->id,
                );
                foreach ($order->toArray() as $key => $value) {
                    if (is_scalar($value)) {
                        $replace['%' . $key . '%'] = $value;
                    }
                }
                return strtr($template, $replace);
            }
        
            /**
             * Устанавливает новый статус исполнения заказа
             * @param shk_order $order Инстанс изменяемого заказа
             * @param string $status Новый статус заказа
             */
            public function updateOrderStatus(shk_order $order, $status)
            {
        
                if ($status > 0) {
                    $order->set('status', $status);
                    return $order->save();
                }
            }
        
            private function getClient()
            {
                if ($this->_apiClient === null) {
                    $this->_apiClient = new \YandexCheckout\Client();
                    $this->_apiClient->setAuth($this->shopid, $this->password);
                    $this->_apiClient->setLogger($this);
                }
                return $this->_apiClient;
            }
        
            public function log($level, $message, $context = array())
            {
                if (!$this->debug_log) {
                    return;
                }
                if (!empty($context) && (is_array($context) || $context instanceof Traversable)) {
                    $search = array();
                    $replace = array();
                    foreach ($context as $key => $value) {
                        $search[] = '{' . $key . '}';
                        $replace[] = $value;
                    }
                    $message = str_replace($search, $replace, $message);
                }
                $path = YANDEXMONEY_PATH . '/logs';
                if (!file_exists($path)) {
                    mkdir($path);
                }
                $fileName = $path . '/module.log';
                $fd = fopen($fileName, 'a');
                flock($fd, LOCK_EX);
                fwrite($fd, date(DATE_ATOM) . ' [' . $level . '] - ' . $message . PHP_EOL);
                flock($fd, LOCK_UN);
                fclose($fd);
            }
        
            /**
             * @param $order
             * @return string
             */
            private function createDescription($order)
            {
                $descriptionTemplate = !empty($this->config['description_template'])
                    ? $this->config['description_template']
                    : 'Оплата заказа №%id%';
        
                $replace  = array();
                $patterns = explode('%', $descriptionTemplate);
                foreach ($patterns as $pattern) {
                    $value = $order->get($pattern);
                    if (!is_null($value) && is_scalar($value)) {
                        $replace['%'.$pattern.'%'] = $value;
                    }
                }
        
                $description = strtr($descriptionTemplate, $replace);
        
                return (string)mb_substr($description, 0, Payment::MAX_LENGTH_DESCRIPTION);
            }
        }
          Roman
          11 октября 2019, 13:19
          0
          Хук YandexMoneyHook
          <?php
          $eventName = $modx->event->name;
          $_isAdmin = ($modx->user->sudo == 1);
          
          if (!defined('YANDEXMONEY_PATH')) {
              define('YANDEXMONEY_PATH', MODX_CORE_PATH."components/yandexmoney/");
          }
          require_once YANDEXMONEY_PATH.'model/yandexmoney.class.php';
          
          $snippet = $modx->getObject('modSnippet',array('name' => 'YandexMoney'));
          $config = $snippet->getProperties();
          
          $ym = new Yandexmoney($modx, $config);
          
          if (!empty($_SESSION['shk_lastOrder']) && !empty($_SESSION['shk_lastOrder']['id'])) {
              $ym->pay_method = !empty($_SESSION['shk_lastOrder']['payment']) ? $_SESSION['shk_lastOrder']['payment'] : '';
              $order_id = (int)$_SESSION['shk_lastOrder']['id'];
          }
          if (!empty($_POST['payment'])) $ym->pay_method = $_POST['payment'];
          if (!empty($_POST['email'])) $ym->email = $_POST['email'];
          if (!empty($_POST['phone'])) $ym->phone = $_POST['phone'];
          if (!empty($_POST['alfaLogin'])) $ym->alfaLogin = $_POST['alfaLogin'];
          if (!empty($_POST['qiwiPhone'])) $ym->qiwiPhone = $_POST['qiwiPhone'];
          
          if (!$ym->checkPayMethod()) {
              return false;
          }
          $modx->addPackage('shopkeeper3',  $modx->getOption('core_path').'components/shopkeeper3/model/');
          $order = $modx->getObject('shk_order', $order_id);
          
          if (!$order) {
              return false;
          }
          $output = '';
          
          if ($order_id && $_POST['order']) {
              $ym->userId = $modx->getLoginUserID('web') ? $modx->getLoginUserID('web') : 0;
              $ym->orderId = $order_id;
              $ym->orderTotal = $_SESSION['shk_lastOrder']['price'];
              $ym->orderTotal = floatval(str_replace(array(',',' '), array('.',''), $ym->orderTotal));
              $ym->comment = $_POST['message'];
          
              $_host = str_replace(array('http://', 'https://'), '' , $modx->config['site_url']);
              $host = 'https://' . $_host . 'assets/components/yandexmoney/connector_result.php';
              $ym->successUrl = $host.'?success=1';
              $ym->failUrl = $host.'?fail=1';
          
              echo $ym->createFormHtml();
              exit;
          }
          return true;
          Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
          16