Всего 123 794 комментария

Vladimir
21 июня 2023, 11:57
0
Если вы ничего не меняли в моём файле, то должно работать, я ниже добавил так же файл assets его тоже создайте, и замените model на Handlers так как было у меня, а так же такие методы
$modx->getOption('epay_debug')
замените для начало просто строкой, если всё заработает то верните эти конструкции и создайте в системных настройках эти параметры и заполните, могу скинуть скрин как их нужно заполнить
Vladimir
21 июня 2023, 11:51
0
Почему у вас «model» в пути? какая у вас версия modx

Всё зависит от работы сервиса оплаты, в случае с epayment, то там запутанои уже не помню точно, но суть такая, на сервер отправляется запрос на получение ключа, формируется заказ в виде словаря, отправляется на фронт и с помощью библиотеки epayment которая указана в доках отправляется заказ, без этой библиотеки(именно js создаёт конечный урл с параметрами, который валиден и позволит оплатить, в тех поддержки сказали что без их js никак) не будет рабоать оплата.
Giant Dad
21 июня 2023, 11:38
0
Ну, вот я Ваш метод беру, вот этот:
<?php

if (!class_exists('msPaymentInterface')) {
    require_once dirname(__FILE__, 3) . '/handlers/mspaymenthandler.class.php';
}

class EpayHalykBank extends msPaymentHandler implements msPaymentInterface
{

    /**
    * EpayHalykBank constructor.
    *
    * @param xPDOObject $object
    * @param array $config
    */
    function __construct(xPDOObject $object, $config = array())
    {
        parent::__construct($object, $config);

        $siteUrl = $this->modx->getOption('site_url');
        $assetsUrl = $this->modx->getOption('assets_url') . 'components/minishop2/';
        $paymentUrl = $siteUrl . substr($assetsUrl, 1) . 'payment/mspepayhalykbank.php';

        $this->config = array_merge(array(
            'grant_type' => 'client_credentials',
            'debug' => $modx->getOption('epay_debug'),
            'epayTokenAuthUrl' => $this->config['debug'] == 1 ? $modx->getOption('epay_test_auth_url') : $modx->getOption('epay_prod_auth_url'),
            'payPageUrl' => $this->config['debug'] == 1 ? $modx->getOption('epay_test_pay_page_url') : $modx->getOption('epay_pay_page_url'),
            'scope' => 'webapi usermanagement email_send verification statement statistics payment',
            'client_id' => $modx->getOption('epay_client_id'),
            'client_secret' => $modx->getOption('epay_client_secret'),
            'currency' => $modx->getOption('epay_payment_currency'),
            'terminal_id' => $modx->getOption('epay_terminal_id'),
            'postLink' => $modx->makeUrl($modx->getOption('epay_post_success_page_id')),
            'failurePostLink' => $modx->makeUrl($modx->getOption('epay_post_error_page_id'))
        ), $config);
    }



    /**
    * Create Auth Token
    *
    * @param 
    *
    * @return string
    */
    public function paymentAuth(msOrder $order)
    {
        $authUrl = $this->config['epayTokenAuthUrl'];

        $params = array(
            'grant_type' => $this->config['grant_type'],
            'scope' => $this->config['scope'],
            'client_id' => $this->config['client_id'],
            'client_secret' => $this->config['client_secret'],
            'invoiceID' => $this->getOrderHash($order),
            'amount' => $order->get('cost'),
            'currency' => $this->config['currency'],
            'terminal' => $this->config['terminal_id'],
            'postLink' => $this->config['postLink'],
            'failurePostLink' => $this->config['failurePostLink']
        );

        $myCurl = curl_init();
        curl_setopt_array($myCurl, array(
            CURLOPT_URL => $authUrl,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query($params)
        ));

        $response = curl_exec($myCurl);
        curl_close($myCurl);

        return json_decode($response, true);

    }


    /**
    * Returns a direct link for continue payment process of existing order
    *
    * @param msOrder $order
    *
    * @return string
    */
    public function getPaymentLink(msOrder $order)
    {

        $authResponse = $this->paymentAuth($order);

        $msAddress = $order->getOne('Address');
        $orderPhone = $msAddress->get('phone');
        $orderEmail = $msAddress->get('email');
        $orderReceiver = $msAddress->get('receiver');
        $orderComment = $msAddress->get('comment');

        if(substr($orderPhone, 0, 1) == '7'){
            $orderPhone = '+' . $orderPhone;
        }
        // if($authResponse['access_token'])
        // 'data' => "{\"statement\":{\"name\":\"Arman      Ali\",\"invoiceID\":\"80000016\"}}",

        return $this->config['payPageUrl'] . '?' .
        http_build_query(array(
            'action' => 'continue',
            'msorder' => $order->get('id'),
            'mscode' => $this->getOrderHash($order),
            'invoiceId' => $this->getOrderHash($order),
            'backLink' => $this->config['postLink'].'?action=success',
            'failureBackLink' => $this->config['failurePostLink'].'?action=error',
            'postLink' => $this->$siteUrl,
            'failurePostLink' => $this->config['failurePostLink'].'?action=error',
            'language' => 'rus',
            'description' => 'Оплата в интернет магазине',
            'accountId' => $this->config['client_id'],
            'terminal' => $this->config['terminal_id'],
            'amount' => $order->get('cost'),
            'data' => array(
                'name' => $orderReceiver,
                'orderId' => $order->get('id'),
                'invoiceId' => $this->getOrderHash($order),
                'phone' => $orderPhone,
                'email' => $orderEmail,                
                'comment' => $orderComment
            ),
            'currency' => $this->config['currency'],
            'phone' => $orderPhone,
            'email' => $orderEmail,
            'cardSave' => true,
            'auth' => $authResponse

        ));
    }
}
Заменяю в
require_once dirname(__FILE__, 3) . '/handlers/mspaymenthandler.class.php';
путь на свой:
require_once dirname(__FILE__, 3) . '/model/minishop2/mspaymenthandler.class.php';
название класса оставляю прежним,
регистрирую через
if ($miniShop2 = $this->modx->getService('miniShop2')) {
    $miniShop2->addService('payment', 'EpayHalykBank',
        '{core_path}components/minishop2/custom/payment/epayhalykbank.class.php'
    );
}
Может быть я что-то ещё упускаю?
И ещё, а вот как это должно вообще работать (хотя бы в общих чертах)? После нажатия кнопки «Оплатить заказ» что должно происходить? в каких файлах какие функции должны отрабатывать? Для меня просто оплата в minishop2 пока новый опыт и я не совсем представляю как это вообще работает
Vladimir
21 июня 2023, 11:35
1
+2
Так же по этому пути должен быть ещё файл
/assets/components/minishop2/payment/epayhalykbank.php
/
<?php

const MODX_API_MODE = true;
/** @noinspection PhpIncludeInspection */
require dirname(__FILE__, 5) . '/index.php';

/** @var modX $modx */
$modx->getService('error', 'error.modError');
$modx->setLogLevel(modX::LOG_LEVEL_ERROR);
$modx->setLogTarget('FILE');


$isJsonRequest = (json_decode(file_get_contents('php://input')) != NULL) ? true : false;

if ($_SERVER['REQUEST_METHOD'] === 'POST' && $isJsonRequest) {

    // $modx->log(modX::LOG_LEVEL_ERROR,'ЗАШЛИ ');

    $requestData = json_decode(file_get_contents('php://input'), true);

    $get_array = array();
    
    parse_str($requestData['data'], $get_array);
    
    $requestData['data'] = $get_array;


    if(isset($requestData['invoiceId']) && !empty($requestData['invoiceId']) && isset($requestData['data']) && !empty($requestData['data']) && isset($requestData['data']['orderId']) && !empty($requestData['data']['orderId']) && isset($requestData['data']['orderHash']) && !empty($requestData['data']['orderHash'])){
        /** @var miniShop2 $miniShop2 */
        $miniShop2 = $modx->getService('miniShop2');
        $miniShop2->loadCustomClasses('payment');



        if (!class_exists('EpayHalykBank')) {
            exit('Error payment not exist');
        }


        /** @var msOrder $order */
        $order = $modx->newObject('msOrder');    
        $handler = new EpayHalykBank($order);

        $orderId = $requestData['data']['orderId'];
        $orderHash = $requestData['data']['orderHash'];
        $paymentInvocieId = $requestData['invoiceId'];

        if ($order = $modx->getObject('msOrder', array('id' => $orderId, 'order_hash' => $orderHash))) {
            /** @var msPaymentInterface|EpayHalykBank $handler */
            $verifyingOrderPayment = $handler->handlePaymentVerification($order, array(
                'invoiceID' => $paymentInvocieId,
                'orderID' => $orderId,
                'orderHash' => $orderId,
            ));
            if(!$verifyingOrderPayment){
                die('Error when continuing order');
            }
            die('True');
        } else {
            exit('Error when continuing order, cannot get order');
        }

    }



}

exit('Access Denied');
А файл что в коре такой, самое последне изменёный
<?php

if (!class_exists('msPaymentInterface')) {
    require_once dirname(__FILE__, 3) . '/handlers/mspaymenthandler.class.php';
}


class EpayHalykBank extends msPaymentHandler implements msPaymentInterface
{

    /**
    * EpayHalykBank constructor.
    *
    * @param xPDOObject $object
    * @param array $config
    */
    function __construct(xPDOObject $object, $config = array())
    {
        parent::__construct($object, $config);

        $siteUrl = $this->modx->getOption('site_url');
        $assetsUrl = $this->modx->getOption('assets_url') . 'components/minishop2/';
        $this->$paymentUrl = $siteUrl . substr($assetsUrl, 1) . 'payment/epayhalykbank.php';
        $this->debugPayment = $this->modx->getOption('epay_debug');

        $this->config = array_merge(array(
            'grant_type' => 'client_credentials',
            'epayTokenAuthUrl' => $this->debugPayment == 1 ? $this->modx->getOption('epay_test_auth_url') : $this->modx->getOption('epay_prod_auth_url'),
            'payPageUrl' => $this->debugPayment == 1 ? $this->modx->getOption('epay_test_pay_page_url') : $this->modx->getOption('epay_pay_page_url'),
            'scope' => 'webapi usermanagement email_send verification statement statistics payment',
            'client_id' => $this->modx->getOption('epay_client_id'),
            'client_secret' => $this->modx->getOption('epay_client_secret'),
            'currency' => $this->modx->getOption('epay_payment_currency'),
            'terminal_id' => $this->modx->getOption('epay_terminal_id'),
            'transactionCheckStatusUrl' =>  $this->debugPayment == 1 ? $this->modx->getOption('transaction_chech_test_url') : $this->modx->getOption('transaction_chech_prod_url'),
            'postLink' => $this->modx->makeUrl((int) $this->modx->getOption('epay_post_success_page_id'), '', '', 'full'),
            'failurePostLink' => $this->modx->makeUrl((int) $this->modx->getOption('epay_post_error_page_id'), '', '', 'full')
        ), $config);
    }


    public function getOrderHashOld(msOrder $order)
    {
        
        return md5(
            $order->get('id') .
            $order->get('num') .
            $order->get('createdon') .
            $order->get('cart_cost') .
            $order->get('delivery_cost')
        );
        
    }

    public function getOrderHash(msOrder $order)
    {
        
        return substr(preg_replace('/[^0-9]/', '', md5(
            $order->get('id') .
            $order->get('num') .
            $order->get('createdon') .
            $order->get('cart_cost') .
            $order->get('delivery_cost')
        )), 0, 15);
        
    }


    /**
    * @param msOrder $order
    * @param array params
    *
    * @return array|string
    */
    public function handlePaymentVerification(msOrder $order, $params = array()){

        if(isset($params['invoiceID']) && !empty($params['invoiceID'])){

            $generateOrderInoiceId = $this->getOrderHash($order);

            if($params['invoiceID'] == $generateOrderInoiceId){

                $authResponse = $this->paymentAuth($order);
                $verifiedResponse = false;

                if($authResponse['access_token']){
                    $getPaymentStatus = $this->jwt_request(
                        $this->config['transactionCheckStatusUrl'].$generateOrderInoiceId,
                        $authResponse['access_token']
                    );

                    $verifiedResponse = $getPaymentStatus;


                }



                return $this->receive($order, array(
                    'verifyedResponse' => $verifiedResponse
                ));
            }


        }

        return false;

    }




    /**
    * @param msOrder $order
    * @param array $params
    *
    * @return bool
    */
    public function receive(msOrder $order, $params = array())
    {
        if(!empty($params['verifyedResponse']) && !empty($params['verifyedResponse'])  && !empty($params['verifyedResponse']['resultCode'])){

            if ($params['verifyedResponse']['resultCode'] == '100') {
                $this->ms2->changeOrderStatus($order->get('id'), 2); // Set status "paid"
                return true;
            } else {
                $this->ms2->changeOrderStatus($order->get('id'), 1002); // Set status "Payment error"

                $msOrder->set('payment_response_status', $result);
                $msOrder->save();
                return false;
            }

        }



        return false;
    }



    /**
    * @param msOrder $order
    *
    * @return array|string
    */
    public function send(msOrder $order)
    {
        if ($order->get('status') > 1) {
            return $this->error('ms2_err_status_wrong');
        }



        $authResponse = $this->paymentAuth($order);


        if (is_array($authResponse) && !empty($authResponse['access_token'])) {
            // $this->modx->log(1, 'OPLATA_NACHALAS');

            $msAddress = $order->getOne('Address');
            $orderPhone = $msAddress->get('phone');
            $orderEmail = $msAddress->get('email');
            $orderReceiver = $msAddress->get('receiver');

            if(substr($orderPhone, 0, 1) == '7'){
                $orderPhone = '+' . $orderPhone;
            }

            $orderHash = $this->getOrderHash($order);

            // $this->modx->log(1, $this->getOrderHash($order));
            
            $backLinkParams = '&msorder='.$order->get('id').'&mscode='.$this->getOrderHashOld($order).'&invoice_id='.$orderHash;
            

            $reqParams = array(
                'invoiceId' => $orderHash,
                'backLink' => $this->config['postLink'].'?action=success'.$backLinkParams,
                'failureBackLink' => $this->$paymentUrl,
                'postLink' => $this->$paymentUrl,
                'failurePostLink' => $this->$paymentUrl,
                'language' => 'rus',
                'description' => 'Оплата в интернет магазине',
                'accountId' => $this->config['client_id'],
                'terminal' => $this->config['terminal_id'],
                'amount' => $order->get('cost'),
                'data' => array(
                    'name' => $orderReceiver,
                    'orderId' => $order->get('id'),
                    'orderHash' => $this->getOrderHashOld($order),
                    'invoiceId' => $orderHash,
                    'phone' => $orderPhone,
                    'email' => $orderEmail
                ),
                'currency' => $this->config['currency'],
                'phone' => $orderPhone,
                'email' => $orderEmail,
                'cardSave' => true,
                'auth' => $authResponse

            );

            return $this->success('', array('payment_response' => $reqParams));
        } else {
            $this->modx->log(
                modX::LOG_LEVEL_ERROR,
                '[miniShop2] Payment error while request. Request: ' . print_r(
                    $params,
                    1
                ) . ', authResponse: ' . print_r(
                    $authResponse,
                    1
                )
            );

            return $this->success('', array('msorder' => $order->get('id')));
        }
    }




    private function jwt_request($url, $token) {

        header('Content-Type: application/json'); // Specify the type of data
        $ch = curl_init($url); // Initialise cURL
        $authorization = "Authorization: Bearer ".$token; // Prepare the authorisation token
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization )); // Inject the token into the header
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // This will follow any redirects
        $result = curl_exec($ch); // Execute the cURL statement
        curl_close($ch); // Close the cURL connection
        return json_decode($result, true); // Return the received data

    }


    /**
    * Create Auth Token
    *
    * @param 
    *
    * @return string
    */
    public function paymentAuth(msOrder $order)
    {
        $authUrl = $this->config['epayTokenAuthUrl'];
        
        $params = array(
            'grant_type' => $this->config['grant_type'],
            'scope' => $this->config['scope'],
            'client_id' => $this->config['client_id'],
            'client_secret' => $this->config['client_secret'],
            'invoiceID' => $this->getOrderHash($order),
            'amount' => $order->get('cost'),
            'currency' => $this->config['currency'],
            'terminal' => $this->config['terminal_id'],
            'postLink' => $this->$paymentUrl,
            'failurePostLink' => $this->$paymentUrl
        );

        $myCurl = curl_init();
        curl_setopt_array($myCurl, array(
            CURLOPT_URL => $authUrl,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => http_build_query($params)
        ));

        $response = curl_exec($myCurl);
        curl_close($myCurl);
        // $this->modx->log(1, $response);
        return json_decode($response, true);

    }


    /**
    * Returns a direct link for continue payment process of existing order
    *
    * @param msOrder $order
    *
    * @return string
    */
    public function getPaymentLink(msOrder $order)
    {

        $redirectPaymentUrl = $this->config['payPageUrl'];

        return $redirectPaymentUrl;
    }
}
Vladimir
21 июня 2023, 11:25
0
Значит у вас ошибка в коде, либо не совпадают названия, у меня так же было, если у вас не подсвечиваются ошибки php кода, закиньте в любой php sandbox, и проверьте, можете написать в тг или скиньте сюда файлы относящиеся к оплате
Giant Dad
21 июня 2023, 11:23
0
а видели я пишу выше «регистрирую через $this->modx»? это я как раз про регистрацию в системе через консоль. делаю как раз по документации, на которую вы ссылаетесь.
Создаю класс, подключаю его через консоль, в ms2_services сервис прописывается,
{«cart»:[],«order»:[],«payment»:{«epayhalykbank»:"{core_path}components\/minishop2\/custom\/payment\/epayhalykbank.class.php"},«delivery»:[]}
но класс-обработчик не появляется в выпадашке при создании нового способа оплаты
Антон Тарасов
21 июня 2023, 11:20
+6
Низкий вам, ребята, поклон за такую стильную, вкусную и функциональную имплементацию документации!
Очень она нужна и крайне важна. И выручала не раз, и пуще прежнего будет.

Интересно, а наши западные партнеры не желают ли по образу и подобию освежить docs.modx.com?

Ну и конечно же искренне задонатил.
Giant Dad
21 июня 2023, 11:18
0
я так и делаю, как раз по вашему топику, регистрирую в консоли, указываю свой название класса и файла, в сервисах путь появляется, но в выборе способа оплаты — пусто, только стандартный PayPal (я, кстати, тоже для ХалыкБанка пытаюсь сделать)
inkeri21
21 июня 2023, 10:36
0
[2023-06-15 13:43:35] (ERROR @ /var/www/fastuser/data/www/stropspb.ru/core/cache/includes/elements/modsnippet/24.include.cache.php: 69) [migxResourceMediaPath]: docid could not be determined.
2023-06-15 12:48:35] (ERROR @ /var/www/fastuser/data/www/stropspb.ru/assets/components/modsliderrevolution/vendor/revslider/application/helpers/general_helper.php: 1164) PHP warning: Use of undefined constant MODX_SLIDER_REV_IS_ADMIN — assumed 'MODX_SLIDER_REV_IS_ADMIN' (this will throw an Error in a future version of PHP)

вот такие ошибки в журнале ошибок
Dan
Dan
21 июня 2023, 09:42
+1
Так получается у вас класс 8 внутри класс 10 находится, в этом и проблема. Вынесите класс 8 на один уровень с класс 10, либо в msProducts укажите depth 1
inkeri21
21 июня 2023, 09:18
0
Может вы мне подскажите еще. Я когда обновляю в галерее фото товара, то исчезает превью в админке. Хотя до этого, когда вставляла в галерею новое фото, в превью в админке сразу вставлялось новое фото. И в Галерее местами не поменять фото, не дает, чтобы одно стало главным, а другое второстепенным. Только если оба фото удалить и вставить сначала
inkeri21
21 июня 2023, 09:12
0
Спасибо. Буду разбираться)) Единственное, когда в классе 10 я снимаю галочку «Показывать вложенные товары, то из класса 10 товары 8 класса исчезают. Но когда нажимаю сохранить, галочка все равно появляется.
Максим
21 июня 2023, 08:23
0
Да, у меня тоже есть базовый пакет настроек)) Если это так можно назвать… Через Vapor делаю бэк-ап сайта с базовыми настройками, потом где надо разворачиваю, меняю ключи от modstore и другие настройки под новый сайт))
Vladimir
21 июня 2023, 01:17
0
Вставил в нескольких местах — некуда не отправил- подскажите в моем случае в каком виде и в какое место вставить?
Vladimir
21 июня 2023, 00:26
0
cтавить — ответте точно
Vladimir
21 июня 2023, 00:26
0
в какое место mail.php именно в моем случае sendredirect в return $modx->sendRedirect('/?q=good', 0, 'REDIRECT_HEADER', 'HTTP/1.1 301 Moved Permanently');