
Подробнее о хостинге для размещения Телеграм бота можно узнать из статьи
Продолжение статей : (Часть 1, Часть 2, Часть 3)
После оформления заказа добавим возможность оплатить заказ через Яндекс.Деньги на пользовательский кошелек. Для этого заменим кнопку, которая была в предыдущих статьях на экране просмотра заказа. Установим кнопку с ссылкой на страницу Яндекс.Денег с предзаполненой формой оплаты. Форма заполняется переданными в ссылке данными, саму ссылку генерирует метод getUrl
<?php
/** Формируем ссылку для оплаты
* @param $sum
* @param $user_id
* @param $order_id
* @return string
*/
private function getUrl($sum, $user_id, $order_id)
{
return "https://money.yandex.ru/quickpay/confirm.xml?receiver=" . $this->receiver
. "&quickpay-form=shop&targets=" . urlencode($this->nameShop)
. "&paymentType=AC&sum=" . $sum
. "&label=" . $user_id . ":" . $order_id . ":" . md5(rand(0, 1000))
. "&comment=" . urlencode("Оплата заказа #" . $order_id)
. "&successURL=" . $this->urlBot;
}
Кнопку заменим в методе drawOrder
<?php
/** Рисуем заказ
* @param $user_id
* @param $begin
* @return array
*/
private function drawOrder($user_id, $begin)
{
// ......
if(!$orderRaw['status']) {
// готовим кнопку для перехода в Яндекс.Деньги
$url = $this->getUrl($total, $user_id, $orderRaw['id']);
$buttons[][] = $this->buildInlineKeyBoardButton('Оплатить через Яндекс.Деньги', '', $url);
} else {
// если заказ оплачен то уведомляем
$text .= "\n<b>Заказ оплачен</b>\n";
}
// .......
}
Для полноты формы создадим дополнительные свойства в начале нашего обработчика
<?php
// Яндекс.Кошелек для приема оплаты
private $receiver = "ВАШ_ЯНДЕКС_КОШЕЛЕК";
// адрес на который переадресует пользователя в случае успешного платежа
private $urlBot = "t.me/forarticlebot";
// название магазина
private $nameShop = "Телеграм Чат-Бот-Магазин";
Теперь нам необходимо в настройках Яндекс.Денег настроить прием уведомлений на специальный адрес обработчика, который будет уведомлять пользователя и администратора о совершенном платеже, и в случае успешного выполнения задуманного сценария - менять статус заказа.
Для этого на странице https://money.yandex.ru/myservices/online.xml необходимо указать путь до файла ya_success.php - перед сохранением изменений убедитесь, что чекбокс установлен у "Отправлять уведомления". Вы можете дополнительно сделать проверку уведомлений использовав секретное слово.
Файл - ya_success.php
<?php
// отсекаем лишние запросы
if ($_SERVER["REQUEST_METHOD"] != "POST") {
echo "Hello world!";
exit();
}
// запускаем
new Yandex();
/**
* Class Yandex
*/
class Yandex
{
private $data;
// первичные данные
private $token = "ВАШ_ТОКЕН";
private $admin = 0;
// для соединения с БД
private $host = 'localhost';
private $db = '';
private $user = '';
private $pass = '';
private $charset = 'utf8mb4';
/**
* @var PDO
*/
private $pdo;
public function __construct()
{
$this->data = $_POST;
$this->setPdo();
$this->getPay();
}
/** Получаем Label
* @return mixed
*/
private function getLabel()
{
return $this->data['label'];
}
/** Получаем id пользователя
* @return mixed
*/
private function getIdUser()
{
return explode(":", $this->getLabel())[0];
}
/** Получаем id заказа
* @return mixed
*/
private function getIdOrder()
{
return explode(":", $this->getLabel())[1];
}
/** Получаем сумму
* @return mixed
*/
private function getFullSum()
{
return $this->data['withdraw_amount'];
}
/**
* Принимаем оплату
*/
private function getPay()
{
// делаем запрос в бд по пришедшим данным
$order = $this->pdo->prepare("SELECT * FROM bot_shop_order WHERE user_id = :user_id AND id = :order_id AND status = 0");
$order->execute(['user_id' => $this->getIdUser(), 'order_id' => $this->getIdOrder()]);
// если запись в бд найдена
if ($order->rowCount() > 0) {
// запрос на обновление статуса заказа
$update = $this->pdo->prepare("UPDATE bot_shop_order SET status = 1 WHERE id = :id");
// если обновили то уведомляем
if ($update->execute(['id' => $this->getIdOrder()])) {
// шлем пользователю уведомление о заказ оплачен
$this->sendMsg([
'chat_id' => $this->getIdUser(),
'text' => "Заказ #" .
$this->getIdOrder() . " успешно оплачен. В ближайшее время с вами свяжется менеджер."]);
// шлем алмину уведомление о заказ оплачен
$this->sendMsg([
'chat_id' => $this->getIdUser(),
'text' => "Заказ #" .
$this->getIdOrder() . " успешно оплачен. Сумма " .
$this->getFullSum() . "."]);
} else {
// шлем пользователю уведомление о том что пришли деньги за заказ, но есть проблемы
$this->sendMsg([
'chat_id' => $this->getIdUser(),
'text' => 'Пришли деньги ' .
$this->getFullSum() . ' РУБ, за заказ ' .
$this->getIdOrder() . ' но не удалось обновить статус заказа. С вами свяжется менеджер.']);
// шлем админу уведомление о том что пришли деньги за заказ, но есть проблемы
$this->sendMsg([
'chat_id' => $this->admin,
'text' => 'Пришли деньги ' .
$this->getFullSum() . ' РУБ, за заказ ' .
$this->getIdOrder() . ' от пользователя ' .
$this->getIdUser() . ' но не удалось обновить статус заказа.']);
}
} else {
// шлем админу уведомление о том что пришли какие-то деньги
$this->sendMsg([
'chat_id' => $this->admin,
'text' => 'Пришли деньги ' .
$this->getFullSum() . ' руб, но назначение не понятно ']);
}
}
/** Отправляем сообщение
* @param $fields
* @return mixed
*/
public function sendMsg($fields)
{
$ch = curl_init('https://api.telegram.org/bot' . $this->token . '/sendMessage');
curl_setopt_array($ch, array(
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => http_build_query($fields),
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_TIMEOUT => 10
));
$r = json_decode(curl_exec($ch), true);
curl_close($ch);
return $r;
}
/**
* Соединение с базой
*/
private function setPdo()
{
$dsn = "mysql:host=$this->host;dbname=$this->db;charset=$this->charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
];
$this->pdo = new PDO($dsn, $this->user, $this->pass, $opt);
}
}
Это была последняя часть по строительству Чат-Бот-Магазина в Телеграм. Стиль программирования со временем конечно у меня меняется (прошло, наверное, больше полгода с начала первой статьи) и уже если честно, то прикручивать оплату в этот проект бота было уже не привычно, даже я скажу: "Как вообще я мог так пис`ать?", но чтобы не ломать логику настроенную в самом начале - пришлось подстраиваться.
По итогу "скелет" бот-магазина готов. По вашим потребностям вы можете прикручивать любой функционал, менять и использовать этого бота без каких-либо ограничений. Огромная просьба не использовать бот в целях, которые нарушают законы.
Авторизуйтесь через Telegram, чтобы оставить комментарий.
Откройте бот @SiteAuthBot,
нажмите кнопку Старт/Start. Следуйте инструкциям бота.
Массив данных (
'Тип клавиатуры' =>
Массив строк кнопок (
Массив кнопок строки (
Массив параметров кнопки (
)
)
),
// если предусмотрено
'Дополнительный параметр',
)
private function drawOrder($user_id, $begin)
{
// ......
$buttons[] = [
$this->buildInlineKeyBoardButton('Оплатить через Яндекс.Деньги', '', $url),
$this->buildInlineKeyBoardButton('Наличными при получении', 'getNal_' . $orderRaw['id'])
];
}
/**
* Обработчик кнопки "За наличные"
*/
public function getNal($data)
{
// ......
// Получаем id заказа через данные от кнопки
$param = explode("_", $data['data']);
$order_id = $param[1];
// Далее логика - например записать в бд
// что этот заказ будет оплачен наличными,
// выслать инструкцию ...
}
private function savePhoneUser($text, $data)
{
$user_id = $this->getChatId($data);
// проверяем телефон
if (preg_match("/^ [0-9]{9,14}$/i", $text)) {
if ($this->setActionUser("step_2_adress", $user_id)) {
if ($this->setParamUser('phone', $text, $user_id)) {
$text_ = "<b>Оформление заказа</b>nn";
// сумма заказа
$text_ .= "Сумма заказа: " . $this->totalSumOrder($user_id) . " рублей";
// телефон
$text_ .= "nТелефон: " . $text;
$text_ .= "nnУкажите ваш адрес для доставки:";
private function savePhoneUser($text, $data)
Вопрос 2:private function savePhoneUser($text, $data)
Я у вас решения спрашивал, я не знаю как это реализовать самостоятельно.
Этот участок кода включается когда пользователь нажал на кнопку для оплаты наличными,
по моей логике должно происходить следующее:
1. Установить флаг в заказе о том что оплата будет за наличные
2. Вывести на экран инструкцию как это будет происходить:
" ... с вами свяжется менеджер для подтверждения заказа, после курьер вам доставит товар
и вы произведете оплату на месте вручения товара ..."
3. К инструкции я еще бы добавил кнопку на переход в личный кабинет для просмотра заказа в нем
private function getType($data)
{
if (isset($data['callback_query'])) {
return "callback_query";
} elseif (isset($data['message']['text'])) {
return "message";
} elseif (isset($data['message']['photo'])) {
return "photo";
} else {
return false;
}
}
http://skrinshoter.ru/s/260619/MYTzC8AP?a
Код кнопок оплаты
if(!$orderRaw['status']) {
// готовим кнопку для перехода в Яндекс.Деньги
$url = $this->getUrl($total, $user_id, $orderRaw['id']);
$buttons[] = [ $this->buildInlineKeyBoardButton('Оплатить через Яндекс.Деньги', '', $url),
$this->buildInlineKeyBoardButton(
'При отправлении Наличными',
'getNal_' . $orderRaw['id']),
$this->buildInlineKeyBoardButton(
'При отправлении Сканирование QR-Кода Яндекс.Деньги',
'getQrYandex_' . $orderRaw['id']),
];
} else {
// если заказ оплачен то уведомляем
$text .= "n<b>Заказ оплачен</b>n";
}
$justKeyboard = $this->getKeyBoard([[["text" => "Голосовать"], ["text" => "Помощь"]]]);
$this->sendMsg([
'chat_id' => $this->admin,
'text' => "Заказ #" .
$this->getIdOrder() . " успешно оплачен. Сумма " .
$this->getFullSum() . "."]);