yoomoney_api-2.5.2/yoomoney_api.module

yoomoney_api.module
<?php
use YooKassa\Client;
use YooKassa\Model\Notification\NotificationFactory;
use YooKassa\Model\NotificationEventType;
use YooKassa\Model\Payment;
use YooKassa\Model\PaymentMethodType;
use YooKassa\Model\PaymentStatus;
use YooKassa\Request\Payments\Payment\CreateCaptureRequest;
use YooKassa\Request\Payments\Payment\CreateCaptureResponse;

define('MODULE_PATH', drupal_get_path('module', 'yoomoney_api'));
require_once MODULE_PATH.DIRECTORY_SEPARATOR.'YooMoneyLogger.php';
require_once MODULE_PATH.DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR.'autoload.php';
require_once MODULE_PATH.DIRECTORY_SEPARATOR.'YooMoneySecondReceiptModel.php';
require_once MODULE_PATH.DIRECTORY_SEPARATOR.'YooMoneyOauth.php';
require_once MODULE_PATH.DIRECTORY_SEPARATOR.'YooMoneyClientFactory.php';
require_once MODULE_PATH.DIRECTORY_SEPARATOR.'YooMoneyWebhookSubscriber.php';
require_once MODULE_PATH.DIRECTORY_SEPARATOR.'YooMoneyKassaLogger.php';

define('YOOMONEY_API_CHECK_RESULT_CODE_SUCCESS', 0);
define('YOOMONEY_API_CHECK_RESULT_CODE_ERROR_MD5', 1);
define('YOOMONEY_API_CHECK_RESULT_CODE_ERROR_CUSTOM', 100);
define('YOOMONEY_API_CHECK_RESULT_CODE_ERROR_REQUEST', 200);
define('YOOMONEY_API_DEFAULT_TAX_RATE_ID', 1);
define('YOOMONEY_MODULE_VERSION', '2.5.2');

define('YOOMONEY_API_ORDER_STATUS_PENDING', 'pending');
define('YOOMONEY_API_ORDER_STATUS_PROCESSING', 'processing');
define('YOOMONEY_API_ORDER_STATUS_CANCELED', 'canceled');
define('YOOMONEY_API_ORDER_STATUS_COMPLETED', 'completed');

define('CMS_NAME_COMMERCE', 'yoo_api_drupal_commerce_epl');
define('CMS_NAME_COMMERCE_OLD', 'yoo_api_drupal_commerce');

define('CMS_NAME_UBERCART', 'yoo_api_drupal_ubercart_epl');
define('CMS_NAME_UBERCART_OLD', 'yoo_api_drupal_ubercart');

define('MODULES_NAME_COMMERCE', 'yoo_commerce_api');
define('MODULES_NAME_UBERCART', 'yoo_ubercart_api');

/**
 * Implements hook_init().
 */
function yoomoney_api_init()
{
    module_load_include('inc', 'yoomoney_api', 'transactions');
}

/**
 * Проверяет, включен или выключен модуль
 * @param string $moduleName
 * @param int $status
 * @return bool
 */
function isModuleEnabled($moduleName, $status)
{
    $existing = db_query("SELECT status FROM {system} WHERE type = :type AND name = :name", array(
        ':type' => 'module',
        ':name' => $moduleName))
        ->fetchObject();

    if (empty($existing)) {
        return false;
    }
    if ($existing->status == $status) {
        return true;
    }
    return false;
}

/**
 * Обработка hook_modules_disabled().
 * Отключение подмодулей в списке модулей
 * @param array $modules
 * @return void
 */
function yoomoney_api_modules_disabled($modules)
{
    foreach ($modules as $module) {
        if ($module === MODULES_NAME_COMMERCE || $module === MODULES_NAME_UBERCART) {
            $kassaLogger = getKassaLog();
            $kassaLogger->sendHeka(array("module.uninstall.init"));

            if (isModuleEnabled($module, 0)) {
                $kassaLogger->sendHeka(array("module.uninstall.success"));
                return;
            }

            $kassaLogger->sendHeka(array("module.uninstall.fail"));
        }
    }
}

/**
 * Обработка hook_modules_enabled().
 * Включение подмодулей в списке модулей
 * @param array $modules
 * @return void
 */
function yoomoney_api_modules_enabled($modules)
{
    foreach ($modules as $module) {
        if ($module === MODULES_NAME_COMMERCE || $module === MODULES_NAME_UBERCART) {
            $kassaLogger = getKassaLog();
            $kassaLogger->sendHeka(array("module.install.init"));
            if (isModuleEnabled($module, 1)) {
                $kassaLogger->sendHeka(array("module.install.success"));
                return;
            }

            $kassaLogger->sendHeka(array("module.install.fail"));
        }
    }
}

/**
 * Создание объекта YooMoneyKassaLogger
 * @return YooMoneyKassaLogger
 */
function getKassaLog()
{
    return new YooMoneyKassaLogger(variable_get('yoomoney_api_shop_id', 'null'));
}

/**
 * Implements hook_permission().
 */
function yoomoney_api_permission()
{
    return array(
        'access yoomoney_api_ money transaction'     => array(
            'title'       => t('Access YooMoney transaction'),
            'description' => t('Display the YooMoney transaction.'),
        ),
        'access own yoomoney_api_ money transaction' => array(
            'title'       => t('Access own YooMoney transaction'),
            'description' => t('Display the YooMoney transaction by own user.'),
        ),
        'access yoomoney_api settings'               => array(
            'title'       => t('Access YooMoney API'),
            'description' => t('Access to YooMoney API variables.'),
        ),
    );
}

/**
 * Implements hook_menu().
 */
function yoomoney_api_menu()
{
    $items = array();

    // Config page
    $items['admin/config/system/yoomoney_api'] = array(
        'title'            => t('YooMoney Core'),
        'description'      => t('YooMoney base settings page.'),
        'page callback'    => 'drupal_get_form',
        'page arguments'   => array('yoomoney_api_admin_settings'),
        'access arguments' => array('access yoomoney_api settings'),
        'type'             => MENU_NORMAL_ITEM,
        'file'             => 'yoomoney_api.admin.inc',
    );

    // Transactions page menu
    $items['admin/reports/yoomoney_api_transactions'] = array(
        'title'            => t('YooMoney transactions '),
        'description'      => t('YooMoney all transactions page.'),
        'page callback'    => 'yoomoney_api_transactions_page',
        'access arguments' => array('access yoomoney_api_ money transaction'),
        'type'             => MENU_NORMAL_ITEM,
        'file'             => 'transactions.inc',
    );

    // yoomoney_api actions
    $items['admin/yoomoney_api/actions'] = array(
        'page callback'    => 'yoomoney_api_actions',
        'access arguments' => array('access yoomoney_api_ money transaction'),
        'type'             => MENU_CALLBACK,
    );

    // Account transaction table
    $items['user/%user/yoomoney_api_payments'] = array(
        'title'            => t('My transactions'),
        'description'      => t('YooMoney user transactions page.'),
        'page callback'    => 'yoomoney_api_transactions_user_page',
        'page arguments'   => array(1),
        'access arguments' => array('access own yoomoney_api_ money transaction'),
        'type'             => MENU_LOCAL_TASK,
        'file'             => 'transactions.inc',
    );

    // Payment callbacks
    $items['yoomoney_api/commerce/return'] = array(
        'page callback'   => 'yoomoney_api_commerce_return_page',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );
    // Payment callbacks
    $items['yoomoney_api/ubercart/return'] = array(
        'page callback'   => 'yoomoney_api_ubercart_return_page',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );

    $items['yoomoney_api/ubercart/notify'] = array(
        'page callback'   => 'yoomoney_api_ubercart_notify',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );

    $items['yoomoney_api/commerce/notify'] = array(
        'page callback'   => 'yoomoney_api_commerce_notify',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );

    $items['yoomoney_api/success'] = array(
        'page callback'   => 'yoomoney_api_complete_page',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );
    $items['yoomoney_api/fail']    = array(
        'page callback'   => 'yoomoney_api_fail_page',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );
    $items['yoomoney_api/temp']    = array(
        'page callback'   => 'yoomoney_api_temp_page',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );
    $items['yoomoney_api/get_oauth_url']    = array(
        'page callback'   => 'yoomoney_api_get_oauth_url',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );
    $items['yoomoney_api/get_oauth_token']    = array(
        'page callback'   => 'yoomoney_api_get_oauth_token',
        'access callback' => true,
        'type'            => MENU_CALLBACK,
    );

    return $items;
}

/**
 * @return Client
 * @throws Exception
 */
function yoomoney_api__common__get_api_client()
{
    return YooMoneyClientFactory::getYooKassaClient();
}

function yoomoney_api_ubercart_return_page()
{
    YooMoneyLogger::info('Return url init ubercart');
    $failUrl    = 'yoomoney_api/fail';
    $successUrl = 'yoomoney_api/success';
    $backToCart = 'cart/checkout';

    $params = drupal_get_query_parameters();
    if (!isset($params['orderId'])) {
        YooMoneyLogger::info('Payment failed. Empty params orderId');
        drupal_goto($failUrl);
    }

    $order = uc_order_load($params['orderId']);
    if (!$order) {
        YooMoneyLogger::info('Payment failed. Can not load oder id #'.$params['orderId']);
        drupal_goto($failUrl);
    }
    YooMoneyLogger::info('Order: '.json_encode($order));

    $transaction = yoomoney_api_transaction_load_by_order($order->order_id);
    if (!$transaction) {
        YooMoneyLogger::info('Payment failed. Transaction not found for order id #'.$params['orderId']);
        drupal_goto($failUrl);
    }
    YooMoneyLogger::info('Transaction: '.json_encode($transaction));

    $apiClient = yoomoney_api__common__get_api_client();

    $paymentId = $transaction->payment_id;

    try {
        $payment = $apiClient->getPaymentInfo($paymentId);
        if (!$payment) {
            YooMoneyLogger::info('Payment failed. Empty payment info. PaymentId #'.$paymentId);
            drupal_goto($failUrl);
        }
        $transaction->status = $payment->getStatus();
        yoomoney_api_transaction_save($transaction);
        $url = $payment->getPaid() ? $successUrl : $backToCart;
        uc_cart_complete_sale($order, true);
        drupal_goto($url);
    } catch (Exception $e) {
        YooMoneyLogger::info('Payment failed. Redirect: '.url($failUrl, array('absolute' => true)));
        YooMoneyLogger::error('Error: '.$e->getMessage());
        drupal_goto($failUrl);
    }
}

function yoomoney_api_commerce_return_page()
{
    YooMoneyLogger::info('Return url init');
    $failUrl    = 'yoomoney_api/fail';
    $successUrl = 'yoomoney_api/success';

    $params = drupal_get_query_parameters();
    if (!isset($params['orderId'])) {
        YooMoneyLogger::info('Payment failed. Empty params orderId');
        drupal_goto($failUrl);
    }
    $order = commerce_order_load($params['orderId']);
    if (!$order) {
        YooMoneyLogger::info('Payment failed. Can not load oder id #'.$params['orderId']);
        drupal_goto($failUrl);
    }

    $transaction = yoomoney_api_transaction_load_by_order($order->order_id);
    if (!$transaction) {
        YooMoneyLogger::info('Payment failed. Transaction not found for order id #'.$params['orderId']);
        drupal_goto($failUrl);
    }
    $apiClient = yoomoney_api__common__get_api_client();

    $paymentId = $transaction->payment_id;

    try {
        $payment = $apiClient->getPaymentInfo($paymentId);
        if (!$payment) {
            YooMoneyLogger::info('Payment failed. Empty payment info. PaymentId #'.$paymentId);
            drupal_goto($failUrl);
        }

        $transaction->status = $payment->getStatus();
        yoomoney_api_transaction_save($transaction);
        $url = $payment->getPaid() ? $successUrl : $failUrl;
        drupal_goto($url);
    } catch (Exception $e) {
        YooMoneyLogger::info('Payment failed. Redirect: '.url($failUrl, array('absolute' => true)));
        YooMoneyLogger::error('Api error: '.$e->getMessage());
        drupal_goto($failUrl);
    }
}

function yoomoney_api_ubercart_notify()
{
    $kassaLogger = getKassaLog();
    $kassaLogger->sendHeka(array('payment.notification.init'));
    YooMoneyLogger::info('Return notification init ubercart');
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        exit();
    }
    $callbackParams = yoomoney_api_common_get_payment_info_from_input();

    try {
        $factory = new NotificationFactory();
        $notification = $factory->factory($callbackParams);
    } catch (Exception $e) {
        $kassaLogger->sendAlertLog(
            'Invalid notification object',
            array('exception' => $e),
            array('payment.notification.fail'));
        YooMoneyLogger::error('Invalid notification object');
        header('HTTP/1.1 400 Bad Request');
        exit();
    }

    $metadata = $notification->getObject()->getMetadata();

    if (
        !empty($metadata['cms_name'])
        && !in_array($metadata['cms_name'], array(CMS_NAME_UBERCART, CMS_NAME_UBERCART_OLD))
    ) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        YooMoneyLogger::info('This notification not for Drupal 7 Ubercart. This notification for: ' . $metadata['cms_name']);
        yoomoney_api_common_exit_200();
    }

    $paymentId = $notification->getObject()->getId();
    $apiClient = yoomoney_api__common__get_api_client();

    $transaction = yoomoney_api_transaction_load_by_payment($paymentId);
    if (!$transaction) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        YooMoneyLogger::error('Transaction not found');
        header('HTTP/1.1 404 Not Found');
        exit();
    }
    $orderResult = uc_order_load($transaction->order_id);
    if ($orderResult && is_array($orderResult)) {
        $order = $orderResult[0];
    } else {
        $order = $orderResult;
    }

    if (!$order) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        YooMoneyLogger::error('Order not found');
        header('HTTP/1.1 404 Not Found');
        exit();
    }

    if ($order->order_status === YOOMONEY_API_ORDER_STATUS_COMPLETED) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        yoomoney_api_common_exit_200();
    }

    $payment = $apiClient->getPaymentInfo($paymentId);
    if (!$payment) {
        $kassaLogger->sendHeka(array('payment.notification.fail'));
        YooMoneyLogger::error('Empty payment info');
        header('HTTP/1.1 400 Bad Request');
        exit();
    }

    if ($notification->getEvent() === NotificationEventType::PAYMENT_WAITING_FOR_CAPTURE
        && $payment->getStatus() === PaymentStatus::WAITING_FOR_CAPTURE
    ) {
        if (yoomoney_api__common__is_enable_hold_mode()
            && $payment->getPaymentMethod()->getType() === PaymentMethodType::BANK_CARD
        ) {
            $kassaLogger->sendHeka(array(
                'shop.'.$kassaLogger->getShopId().'.payment.waiting_for_capture',
                'order-status.change.init'
            ));
            YooMoneyLogger::info('Hold payment for order: '.$order->order_id);
            if (uc_order_update_status($order->order_id, YOOMONEY_API_ORDER_STATUS_PROCESSING)) {
                $kassaLogger->sendHeka(array('order-status.change.success'));
            } else {
                $kassaLogger->sendHeka(array('order-status.change.fail'));
            }
            uc_order_comment_save($order->order_id, 0,
                sprintf(t('New payment received. Capture until %1$s, after that date it will be automatically canceled'),
                    $payment->getExpiresAt()->format('d.m.Y H:i')));
        } else {
            $payment = capturePayment($apiClient, $payment, $kassaLogger);
            if (!$payment) {
                $kassaLogger->sendHeka(array('payment.notification.fail'));
                YooMoneyLogger::error('Empty capture payment info');
                header('HTTP/1.1 400 Bad Request');
                exit();
            }
            $kassaLogger->sendHeka(array('shop.'.$kassaLogger->getShopId().'.payment.succeeded'));
        }
        sendPaymentCountMetrics($kassaLogger);
        yoomoney_api_update_transaction_status($paymentId, $payment->getStatus());
        $kassaLogger->sendHeka(array(
            'shop.'.$kassaLogger->getShopId().'.payment.succeeded',
            'payment.notification.success'
        ));
        yoomoney_api_common_exit_200();
    }

    if ($notification->getEvent() === NotificationEventType::PAYMENT_SUCCEEDED
        && $payment->getStatus() === PaymentStatus::SUCCEEDED
    ) {
        YooMoneyLogger::info('Order status completed');
        $kassaLogger->sendHeka(array('order-status.change.init'));
        if (uc_order_update_status($order->order_id, YOOMONEY_API_ORDER_STATUS_COMPLETED)) {
            $kassaLogger->sendHeka(array('order-status.change.success'));
        } else {
            $kassaLogger->sendHeka(array('order-status.change.fail'));
        }
        yoomoney_api_update_transaction_status($paymentId, $payment->getStatus());
        yoomoney_api_update_transaction_amount($paymentId, $payment->getAmount()->getValue());
        $kassaLogger->sendHeka(array(
            'shop.'.$kassaLogger->getShopId().'.payment.succeeded',
            'payment.notification.success'
        ));
        sendPaymentCountMetrics($kassaLogger);
        yoomoney_api_common_exit_200();
    }
    YooMoneyLogger::error('Wrong payment status: '.$payment->getStatus());
    $kassaLogger->sendHeka(array('payment.notification.skip'));
    yoomoney_api_common_exit_400();
}

function yoomoney_api_commerce_notify()
{
    $kassaLogger = getKassaLog();
    $kassaLogger->sendHeka(array('payment.notification.init'));
    YooMoneyLogger::info('Return notification init commerce');
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        exit();
    }

    $callbackParams = yoomoney_api_common_get_payment_info_from_input();

    try {
        $factory = new NotificationFactory();
        $notification = $factory->factory($callbackParams);
    } catch (Exception $e) {
        $kassaLogger->sendAlertLog(
            'Invalid notification object',
            array('exception' => $e),
            array('payment.notification.fail'));
        YooMoneyLogger::error('Invalid notification object');
        header('HTTP/1.1 400 Bad Request');
        exit();
    }

    $metadata = $notification->getObject()->getMetadata();

    if (
        !empty($metadata['cms_name'])
        && !in_array($metadata['cms_name'], array(CMS_NAME_COMMERCE, CMS_NAME_COMMERCE_OLD))
    ) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        YooMoneyLogger::info('This notification not for Drupal 7 Commerce. This notification for: ' . $metadata['cms_name']);
        yoomoney_api_common_exit_200();
    }

    $paymentId    = $notification->getObject()->getId();
    $transaction  = yooCommerceApiPaymentTransactioLoad($paymentId);
    if (!$transaction) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        YooMoneyLogger::error('Transaction not found');
        header('HTTP/1.1 404 Not Found');
        exit();
    }

    $order = commerce_order_load($transaction->order_id);
    if (!$order) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        YooMoneyLogger::error('Order not found');
        header('HTTP/1.1 404 Not Found');
        exit();
    }

    $apiClient = yoomoney_api__common__get_api_client();

    if ($order->status === YOOMONEY_API_ORDER_STATUS_COMPLETED) {
        $kassaLogger->sendHeka(array('payment.notification.skip'));
        yoomoney_api_common_exit_200();
    }
    $payment = $apiClient->getPaymentInfo($paymentId);
    if (!$payment) {
        $kassaLogger->sendHeka(array('payment.notification.fail'));
        YooMoneyLogger::error('Empty payment info');
        header('HTTP/1.1 400 Bad Request');
        exit();
    }

    if ($notification->getEvent() === NotificationEventType::PAYMENT_WAITING_FOR_CAPTURE
        && $payment->getStatus() === PaymentStatus::WAITING_FOR_CAPTURE
    ) {
        if (yoomoney_api__common__is_enable_hold_mode()
            && $payment->getPaymentMethod()->getType() === PaymentMethodType::BANK_CARD
        ) {
            $kassaLogger->sendHeka(array(
                'shop.'.$kassaLogger->getShopId().'.payment.waiting_for_capture',
                'order-status.change.init'
            ));
            YooMoneyLogger::info('Hold payment for order: '.$order->order_number);
            $order = commerce_order_status_update($order, YOOMONEY_API_ORDER_STATUS_PROCESSING);
            if ($order->status === YOOMONEY_API_ORDER_STATUS_PROCESSING) {
                $kassaLogger->sendHeka(array('order-status.change.success'));
            } else {
                $kassaLogger->sendHeka(array('order-status.change.fail'));
            }
            $transaction->remote_status = $payment->getStatus();
            $transaction->message       = sprintf(t('New payment received. Capture until %1$s, after that date it will be automatically canceled'),
                $payment->getExpiresAt()->format('d.m.Y H:i'));
            commerce_payment_transaction_save($transaction);
        } else {
            $payment = capturePayment($apiClient, $payment, $kassaLogger);
            if (!$payment) {
                $kassaLogger->sendHeka(array('payment.notification.fail'));
                YooMoneyLogger::error('Empty capture payment info');
                header('HTTP/1.1 400 Bad Request');
                exit();
            }
        }
        sendPaymentCountMetrics($kassaLogger);
        yoomoney_api_update_transaction_status($paymentId, $payment->getStatus());
        $kassaLogger->sendHeka(array(
            'shop.'.$kassaLogger->getShopId().'.payment.succeeded',
            'payment.notification.success'
        ));
        yoomoney_api_common_exit_200();
    }

    if ($notification->getEvent() === NotificationEventType::PAYMENT_SUCCEEDED
        && $payment->getStatus() === PaymentStatus::SUCCEEDED
    ) {
        YooMoneyLogger::info('Order status completed');
        commerce_checkout_complete($order);
        $kassaLogger->sendHeka(array('order-status.change.init'));
        $order = commerce_order_status_update($order, YOOMONEY_API_ORDER_STATUS_PROCESSING);
        if ($order->status === YOOMONEY_API_ORDER_STATUS_PROCESSING) {
            $kassaLogger->sendHeka(array('order-status.change.success'));
        } else {
            $kassaLogger->sendHeka(array('order-status.change.fail'));
        }
        $transaction->status        = COMMERCE_PAYMENT_STATUS_SUCCESS;
        $transaction->remote_status = $payment->getStatus();
        commerce_payment_transaction_save($transaction);
        yoomoney_api_update_transaction_status($paymentId, $payment->getStatus());
        yoomoney_api_update_transaction_amount($paymentId, $payment->getAmount()->getValue());
        $kassaLogger->sendHeka(array(
            'shop.'.$kassaLogger->getShopId().'.payment.succeeded',
            'payment.notification.success'
        ));
        sendPaymentCountMetrics($kassaLogger);
        yoomoney_api_common_exit_200();
    }
    YooMoneyLogger::error('Wrong payment status: '.$payment->getStatus());
    $kassaLogger->sendHeka(array('payment.notification.skip'));
    yoomoney_api_common_exit_400();
}

/**
 * @return array
 */
function yoomoney_api_common_get_payment_info_from_input()
{
    $body = @file_get_contents('php://input');
    YooMoneyLogger::info('Notification: ' . $body);
    return json_decode($body, true);
}

function yoomoney_api_actions()
{
    $action    = filter_input(INPUT_POST, 'action', FILTER_SANITIZE_STRING);
    $paymentId = filter_input(INPUT_POST, 'paymentId', FILTER_SANITIZE_STRING);
    $module    = filter_input(INPUT_POST, 'module', FILTER_SANITIZE_STRING);

    $transaction = yoomoney_api_transaction_load_by_payment($paymentId);
    yoomoney_api_common_check_value_is_not_empty($transaction, '404 Not Found', 'Transaction not found');

    $apiClient = yoomoney_api__common__get_api_client();

    $payment = $apiClient->getPaymentInfo($paymentId);
    yoomoney_api_common_check_value_is_not_empty($payment, '400 Bad Request', 'Empty payment info');

    $rightStatus = $payment->getStatus() === PaymentStatus::WAITING_FOR_CAPTURE;
    yoomoney_api_common_check_value_is_not_empty($rightStatus, '400 Bad Request',
        'Capture payment error: wrong payment status: '.$payment->getStatus());

    if ($module === 'uc_payment') {
        $orderResult = uc_order_load($transaction->order_id);
        if ($orderResult && is_array($orderResult)) {
            $order = $orderResult[0];
        } else {
            $order = $orderResult;
        }
        yoomoney_api_common_check_value_is_not_empty($order, '404 Not Found', 'Order not found');
        switch ($action) {
            case 'capturePayment':
                yoo_ubercart_api_capture_payment($payment, $order);
                break;
            case 'cancelPayment':
                yoo_ubercart_api_cancel_payment($paymentId, $order);
                break;
        }
    } elseif ($module === 'commerce') {
        $order = commerce_order_load($transaction->order_id);
        yoomoney_api_common_check_value_is_not_empty($order, '404 Not Found', 'Order not found');
        switch ($action) {
            case 'capturePayment':
                yoo_commerce_api_capture_payment($payment, $order);
                break;
            case 'cancelPayment':
                yoo_commerce_api_cancel_payment($paymentId, $order);
                break;
        }
    }

    YooMoneyLogger::error('Capture payment error: module or order not found');
}

function yoomoney_api_common_check_json_last_error()
{
    if (json_last_error()) {
        YooMoneyLogger::info('Parse POST body failed');
        header('HTTP/1.1 400 Bad Request');
        header('Status: 400 Bad Request');
        exit();
    }
}

/**
 * @param mixed $value
 * @param string $status
 * @param string $logMessage
 */
function yoomoney_api_common_check_value_is_not_empty($value, $status, $logMessage)
{
    if (!$value) {
        YooMoneyLogger::error($logMessage);
        header('HTTP/1.1 '.$status);
        header('Status: '.$status);
        exit();
    }
}

function yoomoney_api_common_exit_200()
{
    header('HTTP/1.1 200 OK');
    header('Status: 200 OK');
    exit();
}

function yoomoney_api_common_exit_400()
{
    header('HTTP/1.1 400 Bad Request');
    header('Status: 400 Bad Request');
    exit();
}

/**
 * Returns text message for success transaction
 * @return mixed
 */
function yoomoney_api_complete_page()
{
    drupal_set_title(t('Congratulations!'));
    module_invoke_all('yoomoney_api_complete');
    $success = variable_get('yoomoney_api_success_text', array('value' => ''));
    $page    = array(
        '#markup' => $success['value'],
    );
    drupal_alter('yoomoney_api_complete_page', $page);

    return $page;
}

/**
 * Returns text message for failed transaction.
 * @return mixed
 */
function yoomoney_api_fail_page()
{
    drupal_set_title(t('Sorry!'));
    module_invoke_all('yoomoney_api_fail');
    $fail = variable_get('yoomoney_api_fail_text', array('value' => ''));
    $page = array(
        '#markup' => $fail['value'],
    );
    drupal_alter('yoomoney_api_fail_page', $page);

    return $page;
}

/**
 * One callback to handle both Success and Fail pages.
 */
function yoomoney_api_temp_page()
{
    if (isset($_GET['action']) && $_GET['action'] === 'PaymentSuccess') {
        drupal_goto('yoomoney_api/complete', array('query' => $_GET));
    } else {
        drupal_goto('yoomoney_api/fail', array('query' => $_GET));
    }
}

/**
 * Check YooMoney IP
 * @return bool
 */
function yoomoney_api_check_server_ip()
{
    $ip          = ip_address();
    $allowed_ips = variable_get('yoomoney_api_ip', '0.0.0.0');
    $allowed_ips = explode("\n", $allowed_ips);
    foreach ($allowed_ips as $allowed_ip) {
        $allowed_ip = trim($allowed_ip);
        if (empty($allowed_ip)) {
            continue;
        }
        if ($allowed_ip === '0.0.0.0' || $ip === $allowed_ip) {
            return true;
        }
    }

    return false;
}

/**
 * @param YooMoneyApiTransaction $transaction
 *
 * @return array
 */
function yoomoney_api_get_order_submission_params(YooMoneyApiTransaction $transaction)
{
    if (variable_get('yoomoney_api_shop', 0)) {
        $params = yoomoney_api_get_shop_params($transaction);
    }

    drupal_alter('yoomoney_api_order_submission_params', $params);

    return $params;
}

/**
 * @param YooMoneyApiTransaction $transaction
 *
 * @return array
 */
function yoomoney_api_get_shop_params(YooMoneyApiTransaction $transaction)
{
    $params = array();

    // Идентификатор Контрагента
    $params['shopId'] = variable_get('yoomoney_api_shop_id', '');

    // Идентификатор товара
    //$params['shopArticleId'] = '';

    // Сумма заказа
    $params['sum'] = $transaction->amount;

    // Идентификатор плательщика. Номер оплачиваемого мобильного телефона, договора и т. п., специфично для Контрагента.
    $params['customerNumber'] = $transaction->uid;

    // Уникальный для данного shopId номер заказа в ИС Контрагента.
    $params['orderNumber'] = $transaction->order_id;

    // URL, на который должен быть осуществлен редирект в случае успеха перевода (urlencoded значение).
    $params['shopSuccessURL'] = url('yoomoney_api/complete', array('absolute' => true));

    // URL, на который должен быть осуществлен редирект в случае ошибки (urlencoded значение).
    $params['shopFailURL'] = url('yoomoney_api/fail', array('absolute' => true));

    // Provide CMS name
    $params['cms_name'] = 'drupal';

    // Internally used field
    $params['order_id'] = $transaction->order_id;

    // Internally used field
    $params['transaction_id'] = $transaction->ymid;

    drupal_alter('yoomoney_api_shop_params', $params);

    return $params;
}

/**
 * @return string
 */
function yoomoney_api_get_order_submission_url()
{
    if (variable_get('yoomoney_api_shop')) {
        return '/';
    }
}


/**
 * @return bool
 */
function yoomoney_api__common__is_enable_hold_mode()
{
    return (bool)variable_get('yoomoney_api_enable_hold_mode', 0);
}

function yoomoney_api_send_second_receipt($orderInfo)
{
    $kassaLogger = getKassaLog();
    $kassaLogger->sendHeka(array('second-receipt.send.init'));
    $transaction = yoomoney_api_transaction_load_by_order($orderInfo['order_id']);
    $result = array(
        'is_send' => false,
        'message' => null,
    );

    if (empty($transaction->payment_id)) {
        YooMoneyLogger::info("Second receipt isn't need, reason: paymentId is empty");
        return (object)$result;
    }

    try {
        $apiClient   = yoomoney_api__common__get_api_client();
        $paymentInfo = $apiClient->getPaymentInfo($transaction->payment_id);
    } catch (Exception $e) {
        YooMoneyLogger::info("Second receipt isn't need, reason: {$e->getMessage()}");
        return (object)$result;
    }

    $secondReceiptModel = new YooMoneySecondReceiptModel($paymentInfo, $orderInfo, $apiClient, $kassaLogger);

    if (!$secondReceiptModel->sendSecondReceipt()) {
        $kassaLogger->sendHeka(array('second-receipt.send.fail'));
        return (object)$result;
    }

    $kassaLogger->sendHeka(array('second-receipt.send.success'));
    YooMoneyLogger::info("Second receipt send. Write history change");

    $sum = number_format($secondReceiptModel->getSettlementsSum(), 2, '.', ' ');

    $result['is_send'] = true;
    $result['message'] = sprintf(t('Second receipt sent. Amount %s rubles'), $sum);

    return (object)$result;
}

/**
 * @param $new_status string
 * @return bool
 */
function yoomoney_api_is_need_second_receipt($new_status)
{
    $isSendReceipt       = variable_get('yoomoney_api_send_check', 0);
    $isSendSecondReceipt = variable_get('yoomoney_api_send_second_receipt', 0);
    $secondReceiptStatus = variable_get('yoomoney_api_second_receipt_status', 0);

    if (!$isSendReceipt) {
        YooMoneyLogger::error('54 fz dont activate');
        return false;
    } elseif (!$isSendSecondReceipt) {
        YooMoneyLogger::error('Send second receipt dont activate');
        return false;
    } elseif (!$secondReceiptStatus) {
        YooMoneyLogger::error('Not selected second receipt status');
        return false;
    } elseif ($secondReceiptStatus != $new_status) {
        YooMoneyLogger::error('Incorrect order status, expected status = ' . $secondReceiptStatus
            . ' current status = ' . $new_status);
        return false;
    }

    return true;
}

/**
 * Делает запрос к OAuth приложению для получения ссылки на авторизацию
 *
 * @return void
 * @throws Exception
 */
function yoomoney_api_get_oauth_url()
{
    header('Content-Type: application/json');

    if (
        empty($_SERVER['HTTP_X_REQUESTED_WITH'])
        || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest'
    ) {
        echo json_encode(array('status' => 'error', 'error' => 'Unknown', 'code' => 'unknown'));
        exit;
    }

    $kassaLogger = getKassaLog();
    $kassaLogger->sendHeka(array("oauth.process.init"));

    try {
        $result = YooMoneyOauth::generateOauthUrl();
    } catch (Exception $e) {
        $kassaLogger->sendHeka(array('oauth.process.fail'));
        yoomoney_api_error_exit('Exception: ' . $e->getMessage(), $e->getMessage(), 500);
    }
    $code = $result['code'];

    if ($code != 200) {
        $kassaLogger->sendHeka(array('oauth.process.fail'));
        yoomoney_api_error_exit('Got error while getting OAuth link.');
    }

    $body = json_decode($result['response'], true);

    if (!isset($body['oauth_url'])) {
        $kassaLogger->sendHeka(array('oauth.process.fail'));
        $error = empty($body['error']) ? 'OAuth URL not found' : $body['error'];
        yoomoney_api_error_exit('Got error while getting OAuth link. Response body: ' . json_encode($body), $error);
    }

    $kassaLogger->sendHeka(array('oauth.process.success'));
    echo json_encode(array('oauth_url' => $body['oauth_url']));
    exit;
}

/**
 * Функция обработки ajax запроса на получение OAuth токена через OAuth-приложение
 *
 * @return void
 * @throws Exception
 */
function yoomoney_api_get_oauth_token()
{
    header('Content-Type: application/json');
    $kassaLogger = getKassaLog();
    $kassaLogger->sendHeka(array('oauth.callback.init'));

    if (
        empty($_SERVER['HTTP_X_REQUESTED_WITH'])
        || strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) != 'xmlhttprequest'
    ) {
        $kassaLogger->sendHeka(array('oauth.callback.skip'));
        echo json_encode(array('status' => 'error', 'error' => 'Unknown', 'code' => 'unknown'));
        exit;
    }

    $state = YooMoneyOauth::getOauthState();
    try {
        $kassaLogger->sendHeka(array('oauth.get-token.init'));
        $result = YooMoneyOauth::generateOauthToken($state);
    } catch (Exception $e) {
        $kassaLogger->sendHeka(array('oauth.callback.fail', 'oauth.get-token.fail'));
        yoomoney_api_error_exit('Exception: ' . $e->getMessage(), $e->getMessage(), 500);
    }

    $code = $result['code'];

    if ($code != 200) {
        if ($code == 422) {
            $kassaLogger->sendHeka(array('oauth.callback.fail', 'oauth.get-token.fail'));
            $error = empty($body['error']) ? 'Access token not found' : $body['error'];
            yoomoney_api_error_exit($error, 'Авторизация не пройдена');
        }
        $kassaLogger->sendHeka(array('oauth.callback.fail', 'oauth.get-token.fail'));
        yoomoney_api_error_exit('Got error while getting OAuth token.');
    }

    $body = json_decode($result['response'], true);

    if (!isset($body['access_token'])) {
        $kassaLogger->sendHeka(array('oauth.callback.fail', 'oauth.get-token.fail'));
        $error = empty($body['error']) ? 'Access token not found' : $body['error'];
        yoomoney_api_error_exit('Got error while getting OAuth token. Key access_token not found. Response body: '. json_encode($body), $error);
    }

    if (!isset($body['expires_in'])) {
        $kassaLogger->sendHeka(array('oauth.callback.fail', 'oauth.get-token.fail'));
        $error = empty($body['error']) ? 'Expires_in parameter not found' : $body['error'];
        yoomoney_api_error_exit('Got error while getting OAuth token. Key expires_in not found. Response body: '. json_encode($body), $error);
    }

    $token = variable_get('yoomoney_api_access_token');
    variable_set('yoomoney_api_access_token', $body['access_token']);
    variable_set('yoomoney_api_token_expires_in', $body['expires_in']);
    $kassaLogger->sendHeka(array('oauth.get-token.success'));

    if ($token) {
        try {
            $kassaLogger->sendHeka(array('token.revoke.init'));
            YooMoneyLogger::info('Old token found. Trying to revoke.');
            YooMoneyOauth::revokeOldToken($token, $state);
            $kassaLogger->sendHeka(array('token.revoke.success'));
        } catch (Exception $e) {
            $kassaLogger->sendHeka(array('oauth.callback.fail', 'token.revoke.fail'));
            yoomoney_api_error_exit('Error when revoking old token: ' . $e->getMessage(), $e->getMessage(), 500);
        }
    }

    try {
        $client = YooMoneyClientFactory::getYooKassaClient();
    } catch (Exception $e) {
        $kassaLogger->sendHeka(array('oauth.callback.fail'));
        yoomoney_api_error_exit('Error when creating a client: ' . $e->getMessage(), $e->getMessage(), 500);
    }

    try {
        $kassaLogger->sendHeka(array('oauth.get-shop.init'));
        YooMoneyOauth::saveShopInfoByOauth($client);
        $kassaLogger->sendHeka(array('oauth.get-shop.success'));
    } catch (Exception $e) {
        $kassaLogger->sendHeka( array('oauth.callback.fail', 'oauth.get-shop.fail'));
        yoomoney_api_error_exit('Error to get information about shop: ' . $e->getMessage(), $e->getMessage(), 500);
    }

    try {
        $kassaLogger->sendHeka(array('webhooks.subscribe.init'));
        YooMoneyLogger::info('Url:' . variable_get('notifyUrl', ''));
        YooMoneyWebhookSubscriber::subscribe($client);
        $kassaLogger->sendHeka(array('webhooks.subscribe.success'));
    } catch (Exception $e) {
        $kassaLogger->sendHeka(array('oauth.callback.fail', 'webhooks.subscribe.fail'));
        yoomoney_api_error_exit('Error occurred during creating webhooks: ' . $e->getMessage(), $e->getMessage(), 500);
    }

    $kassaLogger->sendHeka(array('oauth.callback.success'));
    echo json_encode(array(
        'status' => 'success',
    ));
    exit;
}

/**
 * Вывод сообщений об ошибках и остановка скрипта
 *
 * @param $errorLog
 * @param $errorFront
 * @param $code
 * @return void
 */
function yoomoney_api_error_exit($errorLog, $errorFront = null, $code = 502)
{
    $errorFront = $errorFront ?: $errorLog;
    YooMoneyLogger::error('Error: ' . $errorLog);
    echo json_encode(array('error' => $errorFront));
    exit($code);
}

/**
 * Функция создания запроса на подтверждение платежа
 *
 * @param Client $apiClient
 * @param Payment $payment
 * @param YooMoneyKassaLogger $kassaLogger
 * @return void|CreateCaptureResponse|null
 */
function capturePayment($apiClient, $payment, $kassaLogger)
{
    try {
        $captureRequest = CreateCaptureRequest::builder()->setAmount($payment->getAmount())->build();
        return $apiClient->capturePayment($captureRequest, $payment->getId());
    } catch (Exception $e) {
        YooMoneyLogger::error('Failed to capture payment: ' . $e->getMessage());
        $kassaLogger->sendAlertLog('Failed to capture payment', array(
            'methodid' => 'POST/capturePayment',
            'exception' => $e,
        ), array('payment.notification.fail'));
        header('HTTP/1.1 500 Internal Server Error');
        exit();
    }
}

/**
 * Отправка статистики по платежам
 *
 * @param YooMoneyKassaLogger $kassaLogger
 * @return void
 */
function sendPaymentCountMetrics($kassaLogger)
{
    global $base_url;
    $stat = getSuccessPaymentStat();

    if (empty($stat)) {
        return;
    }

    $host = str_replace(array('http://', 'https://', '.', '/', ':'), array('', '', '-', '-', '-'), trim($base_url, '/'));
    $kassaLogger->sendHeka(array(
        'shop.' . $kassaLogger->getShopId() . '.host.' . $host . '.payment-count' => array(
            'metric_type' => 'gauges',
            'metric_count' => $stat['count']
        ),
        'shop.' . $kassaLogger->getShopId() . '.host.' . $host . '.payment-total' => array(
            'metric_type' => 'gauges',
            'metric_count' => $stat['total']
        ),
    ));
}

/**
 * @param string $status
 * @return false|array
 */
function getSuccessPaymentStat($status = 'succeeded')
{
    $existing = db_query("SELECT COUNT(`payment_id`) AS count, SUM(`amount`) as total FROM {yoomoney_api_transaction} WHERE status = :status", array(
        ':status' => $status))
        ->fetchAssoc();

    if (empty($existing)) {
        return false;
    }

    return $existing;
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc