Как подружить Яндекс Кассу с 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;
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.