Как подружить Яндекс Кассу с 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();
}Кто подскажет что?Комментарии: 16
                Такая же проблема!
Подключил Яндекс кассу, форма с корзиной на Ajax.
При нажатии на кнопку отправить перенаправление на платежную систему Яндекс не происходит.
Автор, удалось разобраться в чем дело и решить проблему?
                    Подключил Яндекс кассу, форма с корзиной на Ajax.
При нажатии на кнопку отправить перенаправление на платежную систему Яндекс не происходит.
Автор, удалось разобраться в чем дело и решить проблему?
                Опытным путем выяснил что нужно только через 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            
                Может возникнет схожая проблема.
Откорректировал дополнительно следующие файлы:
assets/components/yandexmoney/connector_result.php
core/components/yandexmoney/model/yandexmoney.class.php
(!) в последнем файле необходимо заменить все элементы
                    Откорректировал дополнительно следующие файлы:
assets/components/yandexmoney/connector_result.php
core/components/yandexmoney/model/yandexmoney.class.php
(!) в последнем файле необходимо заменить все элементы
SHKorderна shk_order            
                Может возникнет схожая проблема.
Откорректировал дополнительно следующие файлы:
assets/components/yandexmoney/connector_result.php
core/components/yandexmoney/model/yandexmoney.class.php
(!) в последнем файле необходимо заменить все элементы SHKorder на shk_order
                    Откорректировал дополнительно следующие файлы:
assets/components/yandexmoney/connector_result.php
core/components/yandexmoney/model/yandexmoney.class.php
(!) в последнем файле необходимо заменить все элементы SHKorder на shk_order
                Совсем забыл сказать, тоже проводил данные манипуляции с файликом 
core/components/yandexmoney/model/yandexmoney.class.php
а так же менял параметр в функции addPackage, там где стоял shopkeeper просто добавлял цифру 3
                    core/components/yandexmoney/model/yandexmoney.class.php
а так же менял параметр в функции addPackage, там где стоял shopkeeper просто добавлял цифру 3
addPackage('shopkeeper3' ...... );и пути прописывалcomponents/shopkeeper3/model/            
                А какую версию пакета yandexmoney вы используете? Я скачал версию 1.0.4-pl отсюда yandex.ru/support/checkout/instructions/modx.html и выполнил замены во всех файлах, но все равно не работает.            
                    
                Качал с того же сайта.
1.0.4-pl
                    1.0.4-pl
                И все работает? У меня в хуке и в файлах 
assets/components/yandexmoney/connector_result.php
core/components/yandexmoney/model/yandexmoney.class.php
по дефолту было
Может быть надо поменять
                    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или я что-то еще упускаю? Заранее благодарю за ответ.            
                assets/components/yandexmoney/connector_result.php
core/components/yandexmoney/model/yandexmoney.class.php
эти файлы редактировали?
                    core/components/yandexmoney/model/yandexmoney.class.php
эти файлы редактировали?
                Да. ВЫ MODX_CORE_PATH не меняли?            
                    
                Нет, его оставил без изменений            
                    
                Причем, если выбрать метод оплаты, не связанный с яндекс кассой, то заказ тоже не отправится. Видимо YandexMoneyHook не позволяет.            
                    
                Продолжаю свои мучения… Подскажете, какая у вас версия modx и php? У меня modx 2.7.2 (до этого пробовал на 2.7.0) и php 7.0. Может дело в этом? Я уже не знаю, почему может не работать. Поддержка яндекса не помогает вообще, только отписки.            
                    
                Я делал все по гайду яндекса и у меня не заработала. Ниже привел правки в коде            
                    
                Конфиг:
MODX Revolution 2.7.1-pl
shopkeeper3 3.2.7-pl3
yandexmoney 1.0.4-pl
Вывожу через Formit.
core/components/yandexmoney/model/yandexmoney.class.php
                    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);
    }
}            
                Хук 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;            
                            Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.