yandex money api редиректы

Темы, не касающиеся фреймворка, но относящиеся к программированию в целом.
Ответить
louisvuitton
Сообщения: 203
Зарегистрирован: 2014.02.16, 03:09

yandex money api редиректы

Сообщение louisvuitton »

Здравствуйте,
Делаю платежи c банковских карт с помощью api яндекс денег.
Возникли несколько вопросов. Посмотрите пожалуйса кто может.


У яндекса есть тестовое приложение, мне нужна часть где пользователи могут вносить платежи с карты на кошелек ЯД, поэтому делал по подобиям методов

$app->post("/wallet/process-external/" ... ) {...}
$app->get("/wallet/external-success/" ... ) {...}




Делаю так

Код: Выделить всё

// в этот метод приходит сумма из формы заполненной пользователем
public function actionPaycard() {
    $cookie_expired = time() + (20 * 60);
    $walletTo = $this->getWalletTo();
    $sum = Yii::$app->request->post('sumcard');

    // получаю instace_id
    $instance_id_json = ExternalPayment::getInstanceId('ID_YM');

    // добавляю instance_id в куки
    Yii::$app->response->cookies->add(new \yii\web\Cookie([
        'name' => 'instance_id',
        'value' => $instance_id_json->instance_id,
        'expire' => $cookie_expired,
    ]));

    $instance_id = $instance_id_json->instance_id;


    $api = new ExternalPayment($instance_id);

    // запрос процесса платежа
    $request_result = $api->request(array(
        "pattern_id" => "p2p",
        "to" => $walletTo,
        "amount_due" => $sum,
    ));

    if($request_result->status != "success") {
        Yii::$app->getSession()->setFlash('error', [
            'message' =>  'Ошибка на стороне системы платежей',
        ]);
        return $this->redirect('/');
    }

    Yii::$app->response->cookies->add(new \yii\web\Cookie([
        'name' => 'request_id',
        'value' => $request_result->request_id,
        'expire' => $cookie_expired,
    ]));

    // получаю результат платежа и url для перенаправления на  дальнейшие действия в зависимости от того прошел платеж или нет
    $process_result = $api->process(array(
        "request_id" => $request_result->request_id,
        "ext_auth_success_uri" =>  Url::to('card-success', true),
        "ext_auth_fail_uri" =>  Url::to('card-fail', true),
    ));

    Yii::$app->response->cookies->add(new \yii\web\Cookie([
        'name' => 'result/request',
        'value' => json_encode($request_result),
        'expire' => $cookie_expired,
    ]));

    // перенаправляю на полученый url
    $url = sprintf("%s?%s", $process_result->acs_uri,
        http_build_query($process_result->acs_params));
    return $this->redirect($url);
}



// если в предыдущем методе платеж прошел, перенаправление идет сюда
public function actionCardSuccess() {

	//из кук берутся параметры платежа
    $request_id = Yii::$app->request->cookies->getValue('request_id');
    $instance_id = Yii::$app->request->cookies->getValue('instance_id');

    if(is_null($request_id) || is_null($instance_id)) {
        Yii::$app->getSession()->setFlash('error', [
            'message' =>  'Ошишибка системы платежей (cookie expired)',
        ]);
        return $this->redirect('/');
    }

    // еще раз проверяется все ли нормально прошли ли деньги по этому платежу (второй раз не снимутся)
    $api = new ExternalPayment($instance_id);
    do {
        $result = $api->process(array(
            "request_id" => $request_id,
            "ext_auth_success_uri" => Url::to('card-success', true),
            "ext_auth_fail_uri" => Url::to('card-fail', true),
        ));
        if($result->status == "in_progress") {
            sleep(1);
        }
    } while ($result->status == "in_progress");

    // если все прошло мне надо сохранить у себя платеж пользоватля и вывести что все ок (почему то бывает, что в этот if попадаю более одного раза!  см вопрос 1 )
    if($result->status == "success") {
    	$req = json_decode(Yii::$app->request->cookies->getValue("result/request"));
        $sum = $req->contract_amount - $req->fees->service; // получаю сумму из куки запроса платежа (снятые деньги - комиссия), т.к. она не передается в ответе от банка $api->process(...) а только в $api->request(...) 
        $user = Yii::$app->user->identity;
        if($user->addPay($sum, PAY_METHOD_CARD)) {
            Yii::$app->getSession()->setFlash('success', [
                'message' =>  'Платеж успешно выполнен на сумму <strong>' . $sum . '</strong> руб.',
            ]);
            $this->removeCardCookies();
            return $this->redirect('/');
        }
    }
    // если после всех попыток платеж будет "refused"
    else {
        $this->removeCardCookies();
        Yii::$app->getSession()->setFlash('error', [
            'message' =>  'Ошишибка на стороне системы платежей (process)',
        ]);
        return $this->redirect('/');
    }
}

public function actionCardFail() {
    Yii::$app->getSession()->setFlash('error', [
        'message' =>  'Ошишибка на стороне системы платежей (redirect failed)',
    ]);
    return $this->redirect('/');
}
Итак вопросы:
1) главный - Почему случается так, что иногда после всех редиректов, информация о платеже сохраняется (метод $user->addPay(..)) дважды (такое происходит не всегда, вообще непонятно в каких случаях воспроизводится баг и почему) Как этого избежать?

2) В какой момент удалять куки, чтобы не было ошибок и нельзя было повторить actionCardSuccess с этими же куками сохранив платеж еще раз?

2) Это нормально пердевать сумму в куки? ее никто не сможет подменить между редиректами, чтобы у меня сохранилось не то значение которое было снято с карты?
louisvuitton
Сообщения: 203
Зарегистрирован: 2014.02.16, 03:09

Re: yandex money api редиректы

Сообщение louisvuitton »

up
louisvuitton
Сообщения: 203
Зарегистрирован: 2014.02.16, 03:09

Re: yandex money api редиректы

Сообщение louisvuitton »

Снова здравствуйте, товарищи Сеньоры!
Помогите плз

Чтобы вам не читать простыню кода выше, попробую вкратце описать словами что происходит.

У api ЯДа есть два метода
1) $api->request() - создает запрос платежа, проверяет его параметры и возвращает request_id если все ок.
2) $api->process(request_id) - по полученному из предыдущего метода request_id проводит процесс платежа. Возвращает статус: refused, in_progress, или success (можно вызывать несколько раз пока статус не станет success, деньги два раза по одному request_id не уйдут)

Схема такая:

Код: Выделить всё

actionPay() // первый метод в который по нажатию кнопки "оплатить" приходит сумма из формы
{  
     - с помощью $api->request()  делаем "запрос перевода" и получаем request_id

    //если запрос перевода проверен и вернул success, запускаем процесс перевода 
     - пробуем процесс перевода $api->process(request_id) {
        если все хорошо редирект на action2success 
        если нет, редирект на action3fail показ ошибки
    }
}

Код: Выделить всё

action2success() // куда приходит редирект если $api->process(request_id) прошел удачно
{
	// но дело в том, что статус in_progress это тоже удачно, поэтому нужно посылать процесс еще, чтобы точно получить success (второй раз деньги по одному и тому же request_id не уйдут)

        do {
            $result = $api->process(request_id);
            if($result->status == "in_progress") {
                sleep(1);
            }
        } while ($result->status == "in_progress");
	
	//теперь если все ок, сохраняем платеж в свою базу
        if($result->status == "success") {
            - сохраняем платеж в базу
        }
        else {
        	- показываем ошибку
        }
}
Проблема в том, что у меня ИНОГДА платеж в свою базу сохраняется 2 раза (подметил что чаще всего это бывает на медленном соединении, если тестить например с телефона, но тоже не всегда)

Как такое происходит?
Как он умудряется два раза входить в

if($result->status == "success") {
- сохраняем платеж в базу
}

если он НЕ ДОЛЖЕН проходить дальше do-while пока статус первый раз не станет success :twisted:

HELP плз
andku83
Сообщения: 988
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

Re: yandex money api редиректы

Сообщение andku83 »

louisvuitton писал(а): 2018.10.22, 16:15 Как такое происходит?
Как он умудряется два раза входить в
Предполагаю что пользователь не дожидаясь ответа обновляет страницу и тем самым создает еще один запрос к серверу.
А скрипт при каждом выполнении добавляет новую запись, сделайте так чтобы если запись существует - она обновлялась.
louisvuitton
Сообщения: 203
Зарегистрирован: 2014.02.16, 03:09

Re: yandex money api редиректы

Сообщение louisvuitton »

Вообще пользователей нет, и я сам только тестирую, дожидаясь ответа.

Сейчас сделано так, что сразу после сохранения информации в мою базу, удаляются куки, и если еще раз зайти на action2success() без нужных кук, покажется ошибка еще до do-while
И ТЕМ НЕ МЕНЕЕ платеж как то умудряется сохраняться два раза. Не всегда, в некоторых казалось бы совершенно случайных случаях.
(вообще хотелось бы, чтобы на action2success() вообще нельзя было зайти никак кроме как редиректом от яндекса, можно это как то сделать? но это не столь важно, как решить вопрос с двойным добавлением платежа)

Если это поможет что то понять, по нажатию "оплатить" цепочка редиректов какая то такая
- actionpay - yandex (воод данных карты) - банк (ввод пароля из смс) - яндекс - action2success
andku83
Сообщения: 988
Зарегистрирован: 2016.07.01, 10:24
Откуда: Харьков

Re: yandex money api редиректы

Сообщение andku83 »

Смотрите в дебаг панели где происходит запись данных.
Ответить