added receiver registration

This commit is contained in:
Arsen Mirzaev Tatyano-Muradovich 2024-12-17 02:24:01 +03:00
parent 9944e5309c
commit e89353e726
8 changed files with 871 additions and 62 deletions

View File

@ -142,7 +142,6 @@ class core extends model
return null; return null;
} }
/** /**
* Write * Write
* *

View File

@ -21,6 +21,9 @@ use Zanzara\Zanzara,
Zanzara\Middleware\MiddlewareNode as Node, Zanzara\Middleware\MiddlewareNode as Node,
Zanzara\Telegram\Type\User as user; Zanzara\Telegram\Type\User as user;
// Framework for ArangoDB
use mirzaev\arangodb\document;
/** /**
* Model of chat (telegram) * Model of chat (telegram)
* *
@ -627,6 +630,198 @@ final class telegram extends core
// Unsharing the cart // Unsharing the cart
$cart->unshare(); $cart->unshare();
if ($cart instanceof cart) {
// Initialized the cart
// Connecting the cart to the account
$edge = $account->connect($cart);
if (!empty($edge)) {
// Connected the cart to the account
// Initializing products in the cart
$products = $cart->products(language: $account->language ?? language::ru, currency: $account->currency ?? currency::rub);
if (!empty($products)) {
// Initialized products in the cart
// Declaring total cost of products
$cost = 0;
// Declaring formatted list of products for message
$list = '';
// Initializing iterator of rows
$row = 0;
foreach ($products as $product) {
// Iterating over products
// Generating formatted list of products for message
$list .= static::unmarkdown(++$row . '. ' . $product['document']['name'] . ' (' . $product['amount'] . 'шт)') . "\n";
// Generating total cost of products
$cost += $product['document']['cost'] * $product['amount'];
}
// Deinitializing unnecessary variables
unset($products, $product, $row);
// Initializing identifier of the cart
$identifier = $cart->getKey();
// Initializing currency symbol
$symbol = ($account->currency ?? currency::rub)->symbol();
// Initializing delivery cost for message
$delivery_cost = $cart->buffer['delivery']['cost'];
// Initializing delivery days for message
$delivery_days = $cart->buffer['delivery']['days'];
// Initializing delivery address for message
$delivery_address = $cart->buffer['delivery']['location']['name'] . ', ' . $cart->buffer['delivery']['street'];
$ctx->sendMessage(
<<<TXT
🛒 *Добавлена корзина \#$identifier*
$list
*Стоимость:* $cost$symbol \+ $delivery_cost$symbol \($delivery_days дней\)
*Адрес доставки:* $delivery_address
TXT
)->then(function ($message) use ($ctx, $account, $cart) {
// Sended the message
// Writing to the runtime buffer
$ctx->setUserDataItem('cart', $cart);
if (empty($account->receiver['sim']) || empty($account->receiver['name'])) {
// Not registered account
$ctx->sendMessage(
<<<TXT
⚠️ *Необходимо завершить регистрацию для продолжения*
TXT
)->then(function ($message) use ($ctx) {
// Sended message
// Sending account parameters menu
static::account_parameters($ctx);
});
} else {
// Registered account
$ctx->sendMessage(
<<<TXT
🛡 *Все проверки пройдены*
TXT
)->then(function ($message) use ($ctx) {
// Sended message
// Sending order request
static::order_request($ctx);
});
}
});
}
// Deinitializing unnecessary variables
unset($cart, $list);
}
}
// Deinitializing unnecessary variables
unset($cart);
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Order request
*
* @param context $ctx
*
* @return void
*/
public static function order_request(context $ctx): void
{
// Initializing the account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
$ctx->getUserDataItem('cart')->then(function ($cart) use ($ctx) {
// Readed the cart from the session buffer
if (!empty($cart)) {
// Initialized the cart
// Initializing identifier of the cart
$identifier = $cart->getKey();
$ctx->sendMessage(
<<<TXT
🛒 *Корзина \#$identifier*
TXT,
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '📦 Оформить заказ', 'callback_data' => 'order'],
],
[
['text' => '⚡ Помощь с заказом', 'url' => 'https://t.me/iarming'],
]
],
'disable_notification' => true
]
]
);
}
});
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Order request
*
* @param context $ctx
*
* @return void
*/
public static function order(context $ctx): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
var_dump($ctx->getCbData());
die;
// Initializing cart
$cart = cart::_read(
filter: 'd.share == @share',
sort: 'd.updated DESC, d.created DESC, d._key DESC',
amount: 1,
page: 1,
parameters: ['share' => $share]
);
// Deinitializing unnecessary variables
unset($share);
// Unsharing the cart
$cart->unshare();
if ($cart instanceof cart) { if ($cart instanceof cart) {
// Initialized the cart // Initialized the cart
@ -692,7 +887,8 @@ final class telegram extends core
'inline_keyboard' => [ 'inline_keyboard' => [
[ [
/* ['text' => '🧾 Оплатить', 'web_app' => ['url' => 'https://arming.dev.mirzaev.sexy']] */ /* ['text' => '🧾 Оплатить', 'web_app' => ['url' => 'https://arming.dev.mirzaev.sexy']] */
['text' => '📦 Оформить заказ', 'url' => 'https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=demo&OutSum=11&Description=Покупка в демо магазине&SignatureValue=2c113e992e2c985e43e348ff3c12f32b'], /* ['text' => '📦 Оформить заказ', 'url' => 'https://auth.robokassa.ru/Merchant/Index.aspx?MerchantLogin=demo&OutSum=11&Description=Покупка в демо магазине&SignatureValue=2c113e992e2c985e43e348ff3c12f32b'], */
['text' => '📦 Оформить заказ', 'callback_data' => 'order'],
] ]
], ],
'disable_notification' => true 'disable_notification' => true
@ -713,4 +909,537 @@ final class telegram extends core
// Deinitializing unnecessary variables // Deinitializing unnecessary variables
unset($account); unset($account);
} }
/**
* Account parameters
*
* Menu for request parameters for the account
*
* @param context $ctx
*
* @return void
*/
public static function account_parameters(context $ctx): void
{
// Initializing the account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
$ctx->getUserDataItem('cart')
->then(
function ($cart) use ($ctx, $account) {
// Readed the cart from the session buffer
if (!empty($cart) && !empty($account->receiver['sim']) && !empty($account->receiver['name'])) {
// Found process for the cart offering and initialized all required account parameters
// Sending the menu of requesting order
static::order_request($ctx);
} else {
// Not found process for the cart offering or not initialized all required account parameters
$ctx->sendMessage(
<<<TXT
📑 *Настройка параметров получателя*
TXT,
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => (empty($account->receiver['sim']) ? '🔴' : '🟢') . ' SIM-номер получателя', 'callback_data' => 'receiver_sim_choose']
],
[
['text' => (empty($account->receiver['name']) ? '🔴' : '🟢') . ' Имя получателя', 'callback_data' => 'receiver_name_choose'],
]
],
'disable_notification' => true,
]
]
);
}
}
);
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver SIM-number
*
* Request the receiver SIM-number and write into account
*
* @param context $ctx
*
* @return void
*/
public static function receiver_sim_choose(context $ctx): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
// Sending the message
$ctx->sendMessage(
<<<TXT
📞 *SIM\-номер получателя*
Используется для генерации договора с компанией осуществляющией доставку товаров из магазина
TXT,
[
'reply_markup' => [
'keyboard' => [
[
['text' => '📂 Использовать номер аккаунта', 'request_contact' => true]
],
],
'disable_notification' => true
]
]
)->then(function ($message) use ($ctx) {
// Sended the message
// Sending the message
$ctx->sendMessage(
<<<TXT
Если SIM\-номер *отличается* от привязанного к аккаунту, то введите его вручную
TXT,
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '✏️ Ввести вручную', 'callback_data' => 'receiver_sim_request']
],
],
'disable_notification' => true,
]
]
);
});
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver SIM-number request
*
* Request SIM-number
*
* @param context $ctx
*
* @return void
*/
public static function receiver_sim_request(context $ctx): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
$ctx->sendMessage(
<<<TXT
📞 *Пришлите SIM\-номер получателя*
*Пример:* 79099995522
TXT,
[
'reply_markup' => [
'disable_notification' => true,
'remove_keyboard' => true
]
]
)->then(function ($message) use ($ctx) {
// Sended message
$ctx->nextStep([static::class, 'receiver_sim_input'], true);
});
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver SIM-number from input
*
* Receive SIM-number from message
*
* @param context $ctx
*
* @return void
*/
public static function receiver_sim_input(context $ctx): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
// Initializing received text (SIM-number)
$text = $ctx->getMessage()?->getText();
if (!empty($text)) {
// Initialized received text (SIM-number)
// Sanitizing received text (only numbers)
$sanitized = preg_replace('/[^\d]/', '', $text);
if (!empty($sanitized)) {
// Initialized sanitized received text (only numbers)
if (strlen($sanitized) > 6) {
// Length of received SIM-number is more than 6 symbols
if (strlen($sanitized) < 20) {
// Length of received SIM-number is less than 20 symbols
// Writing to the buffer
$ctx->setUserDataItem('receiver_sim', $sanitized);
$ctx->sendMessage(
<<<TXT
📞 *SIM\-номер:* $sanitized
TXT,
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '✅ Сохранить', 'callback_data' => 'receiver_sim_write'],
['text' => '❎ Отменить', 'callback_data' => 'receiver_sim_choose']
]
],
'disable_notification' => true
]
]
);
// Resetting the buffer
$ctx->endConversation();
} else {
// Length of received SIM-number is NOT less than 20 symbols
// Sending the message
$ctx->sendMessage('⚠️ *SIM\-номер должен быть короче 20\-ти символов*');
}
} else {
// Length of received SIM-number is NOT more than 6 symbols
// Sending the message
$ctx->sendMessage('⚠️ *SIM\-номер должен быть длиннее 3\-х символов*');
}
}
}
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver SIM-number write
*
* Write received and accepted receiver SIM-number into account
*
* @param context $ctx
*
* @return void
*/
public static function receiver_sim_write(context $ctx): void
{
// initializing account
$account = $ctx->get('account');
if ($account) {
// initialized the account
$ctx->getUserDataItem('receiver_sim')->then(function ($sim) use ($ctx, $account) {
// Initialized receiver SIM-number
if (!empty($sim)) {
// Initialized receiver SIM-number
// Writing receiver SIM-number into the account
$account->receiver = ['sim' => (int) $sim] + ($account->receiver ?? []);
// Deabstracting the language parameter
$account->language = $account->language->name;
if (document::update($account->__document())) {
// Writed the account instance into the ArangoDB document
$ctx->sendMessage(
<<<TXT
*SIM\-номер зарегистрирован:* $sim
TXT,
[
'reply_markup' => [
'disable_notification' => true,
'remove_keyboard' => true
]
]
)->then(function ($message) use ($ctx) {
// Sended message
// Deinitializing receiver SIM-number
$ctx->setUserDataItem('receiver_sim', null);
// Sending the account parameters menu
static::account_parameters($ctx);
});
} else {
// Not writed the account instance into the ArangoDB document
// Sending the message
$ctx->sendMessage('⚠️ *Не удалось записать SIM\-номер*');
}
} else {
// Not initialized receiver SIM-number
// Sending the message
$ctx->sendMessage('⚠️ *Ошибка при регистрации SIM\-номера*');
}
});
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver name
*
* Request the receiver name and write into account
*
* @param context $ctx
*
* @return void
*/
public static function receiver_name_choose(context $ctx): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
// Sending the message
$ctx->sendMessage(
<<<TXT
📞 *ФИО получателя*
Используется для генерации договора с компанией осуществляющией доставку товаров из магазина
TXT,
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '✏️ Ввести вручную', 'callback_data' => 'receiver_name_request']
],
],
'disable_notification' => true,
]
]
);
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver name request
*
* Request name
*
* @param context $ctx
*
* @return void
*/
public static function receiver_name_request(context $ctx): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
$ctx->sendMessage(
<<<TXT
📞 *Пришлите ФИО получателя*
*Пример:* Иван Иванов Иванович
TXT,
[
'reply_markup' => [
'disable_notification' => true,
'remove_keyboard' => true
]
]
)->then(function ($message) use ($ctx) {
// Sended message
$ctx->nextStep([static::class, 'receiver_name_input'], true);
});
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver name from input
*
* Receive name from message
*
* @param context $ctx
*
* @return void
*/
public static function receiver_name_input(context $ctx): void
{
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
// Initializing received text (name)
$text = $ctx->getMessage()?->getText();
if (!empty($text)) {
// Initialized received text (name)
// Sanitizing received text (only numbers)
$sanitized = static::unmarkdown(preg_replace('/[^\s\w\-]/u', '', $text));
if (!empty($sanitized)) {
// Initialized sanitized received text (only numbers)
if (mb_strlen($sanitized) > 3) {
// Length of received name is more than 3 symbols
if (mb_strlen($sanitized) < 256) {
// Length of received name is less than 256 symbols
// Writing to the buffer
$ctx->setUserDataItem('receiver_name', $sanitized);
$ctx->sendMessage(
<<<TXT
🪪 *ФИО:* $sanitized
TXT,
[
'reply_markup' => [
'inline_keyboard' => [
[
['text' => '✅ Сохранить', 'callback_data' => 'receiver_name_write'],
['text' => '❎ Отменить', 'callback_data' => 'receiver_name_choose']
]
],
'disable_notification' => true
]
]
);
// Resetting the buffer
$ctx->endConversation();
} else {
// Length of received name is NOT less than 20 symbols
// Sending the message
$ctx->sendMessage('⚠️ *ФИО должны быть короче 256\-ти символов*');
}
} else {
// Length of received name is NOT more than 6 symbols
// Sending the message
$ctx->sendMessage('⚠️ *ФИО должны быть длиннее 3\-х символов*');
}
}
}
}
// Deinitializing unnecessary variables
unset($account);
}
/**
* Receiver name write
*
* Write received and accepted receiver name into account
*
* @param context $ctx
*
* @return void
*/
public static function receiver_name_write(context $ctx): void
{
// initializing account
$account = $ctx->get('account');
if ($account) {
// initialized the account
$ctx->getUserDataItem('receiver_name')->then(function ($name) use ($ctx, $account) {
// Initialized receiver name
if (!empty($name)) {
// Initialized receiver name
// Writing receiver name into the account
$account->receiver = ['name' => $name] + ($account->receiver ?? []);
// Deabstracting the language parameter
$account->language = $account->language->name;
if (document::update($account->__document())) {
// Writed the account instance into the ArangoDB document
$ctx->sendMessage(
<<<TXT
*ФИО зарегистрированы:*
$name
TXT,
[
'reply_markup' => [
'disable_notification' => true,
'remove_keyboard' => true
]
]
)->then(function ($message) use ($ctx) {
// Sended message
// Deinitializing receiver name
$ctx->setUserDataItem('receiver_name', null);
// Sending the account parameters menu
static::account_parameters($ctx);
});
} else {
// Not writed the account instance into the ArangoDB document
// Sending the message
$ctx->sendMessage('⚠️ *Не удалось записать ФИО*');
}
} else {
// Not initialized receiver name
// Sending the message
$ctx->sendMessage('⚠️ *Ошибка при регистрации ФИО*');
}
});
}
// Deinitializing unnecessary variables
unset($account);
}
} }

View File

@ -38,7 +38,7 @@ $core->router
->write('/cart/product', new route('cart', 'product', 'cart'), 'PATCH') ->write('/cart/product', new route('cart', 'product', 'cart'), 'PATCH')
->write('/cart/summary', new route('cart', 'summary', 'cart'), 'GET') ->write('/cart/summary', new route('cart', 'summary', 'cart'), 'GET')
/* ->write('/cart/share', new route('cart', 'share', 'cart'), 'POST') */ /* ->write('/cart/share', new route('cart', 'share', 'cart'), 'POST') */
->write('/cart/pay', new route('cart', 'pay', 'cart'), 'POST') ->write('/cart/share', new route('cart', 'share', 'cart'), 'POST')
->write('/order/robokassa', new route('cart', 'robokassa', 'cart'), 'GET') ->write('/order/robokassa', new route('cart', 'robokassa', 'cart'), 'GET')
->write('/account/write', new route('account', 'write', 'account'), 'PATCH') ->write('/account/write', new route('account', 'write', 'account'), 'PATCH')
->write('/session/write', new route('session', 'write', 'session'), 'PATCH') ->write('/session/write', new route('session', 'write', 'session'), 'PATCH')

View File

@ -843,7 +843,7 @@ Object.assign(
) { ) {
try { try {
// Request // Request
return await core.request("/cart/pay", undefined, "POST") return await core.request("/cart/share", undefined, "POST")
.then((json) => { .then((json) => {
if (json) { if (json) {
// Received a JSON-response // Received a JSON-response
@ -860,7 +860,7 @@ Object.assign(
} else { } else {
// Success (not received errors) // Success (not received errors)
/* if (json.share) { if (json.share) {
// Received sharing hash // Received sharing hash
// Request to the chat-robot // Request to the chat-robot
@ -870,9 +870,9 @@ Object.assign(
hash: json.share, hash: json.share,
}), }),
); );
} */ }
if (json.robokassa) { /* if (json.robokassa) {
// Received data for the Robokassa acquiring // Received data for the Robokassa acquiring
// Initializing iframe // Initializing iframe
@ -889,7 +889,7 @@ Object.assign(
}), }),
SignatureValue: json.robokassa.hash, SignatureValue: json.robokassa.hash,
}); });
} } */
// Exit (success) // Exit (success)
resolve(json); resolve(json);

View File

@ -49,7 +49,10 @@ export default function damper(func, timeout = 300, force) {
// Requested execution with ignoring the timer // Requested execution with ignoring the timer
// Deleting the force argument // Deleting the force argument
if (typeof force === "number") args.splice(force, force); if (typeof force === "number") args = [
...args.splice(0, force),
...args.splice(force + 1)
];
// Writing promise handlers into the arguments variable // Writing promise handlers into the arguments variable
args.push(resolve, reject); args.push(resolve, reject);
@ -60,7 +63,10 @@ export default function damper(func, timeout = 300, force) {
// Normal execution // Normal execution
// Deleting the force argument // Deleting the force argument
if (typeof force === "number") args.splice(force, force); if (typeof force === "number") args = [
...args.splice(0, force),
...args.splice(force + 1)
];
// Writing promise handlers into the arguments variable // Writing promise handlers into the arguments variable
args.push(resolve, reject); args.push(resolve, reject);

View File

@ -15,6 +15,9 @@ use Zanzara\Zanzara,
Zanzara\Context, Zanzara\Context,
Zanzara\Config; Zanzara\Config;
// Framework for ArangoDB
use mirzaev\arangodb\document;
ini_set('error_reporting', E_ALL ^ E_DEPRECATED); ini_set('error_reporting', E_ALL ^ E_DEPRECATED);
ini_set('display_errors', 1); ini_set('display_errors', 1);
ini_set('display_startup_errors', 1); ini_set('display_startup_errors', 1);
@ -63,11 +66,14 @@ $config->useReactFileSystem(true);
$bot = new Zanzara(TELEGRAM_KEY, $config); $bot = new Zanzara(TELEGRAM_KEY, $config);
$bot->onUpdate(function (Context $ctx): void { $bot->onUpdate(function (Context $ctx): void {
// Initializing 'web app" data // Initializing the message
$app = $ctx->getMessage()?->getWebAppData(); $message = $ctx->getMessage();
// Initializing the "web app" data
$app = $message?->getWebAppData();
if (!empty($app)) { if (!empty($app)) {
// Initialized "web app" data // Initialized the "web app" data
// Initializing request from "web app" data // Initializing request from "web app" data
$request = json_decode($app->getData(), false, 10); $request = json_decode($app->getData(), false, 10);
@ -76,7 +82,65 @@ $bot->onUpdate(function (Context $ctx): void {
// Cart attaching // Cart attaching
// Attaching cart to the Telegram account // Attaching cart to the Telegram account
telegram::cart_attach($ctx, $request->hash, $request->delivery); telegram::cart_attach($ctx, $request->hash);
}
} else {
// Not initialized the "web app" data
// Initializing account
$account = $ctx->get('account');
if ($account) {
// Initialized the account
if (!empty($message)) {
// Initialized the message
// Initializing the contact data
$contact = $message?->getContact();
if (!empty($contact)) {
// Initialized the contact data
// Sanitizing received SIM-number (only numbers)
$sanitized = preg_replace('/[^\d]/', '', $contact->getPhoneNumber());
if (!empty($sanitized)) {
// Sanitized receiver SIM-number
// Writing receiver SIM-number into the account
$account->receiver = ['sim' => (int) $sanitized] + ($account->receiver ?? []);
// Deabstracting the language parameter
$account->language = $account->language->name;
if (document::update($account->__document())) {
// Writed the account instance into the ArangoDB document
$ctx->sendMessage(
<<<TXT
*SIM\-номер зарегистрирован:* $sanitized
TXT,
[
'reply_markup' => [
'remove_keyboard' => true
]
]
)->then(function ($message) use ($ctx) {
// Sended message
// Sending the account parameters menu
telegram::account_parameters($ctx);
});
} else {
// Not writed the account instance into the ArangoDB document
// Sending the message
$ctx->sendMessage('⚠️ *Не удалось записать SIM\-номер*');
}
}
}
}
} }
} }
@ -96,9 +160,20 @@ $bot->onText('⚙️ Настройки', fn($ctx) => telegram::settings($ctx))
$bot->onCbQueryData(['mail'], fn($ctx) => telegram::_mail($ctx)); $bot->onCbQueryData(['mail'], fn($ctx) => telegram::_mail($ctx));
$bot->onCbQueryData(['import_request'], fn($ctx) => telegram::import_request($ctx)); $bot->onCbQueryData(['import_request'], fn($ctx) => telegram::import_request($ctx));
$bot->onCbQueryData(['order'], fn($ctx) => telegram::order($ctx));
$bot->onCbQueryData(['tuning'], fn($ctx) => telegram::tuning($ctx)); $bot->onCbQueryData(['tuning'], fn($ctx) => telegram::tuning($ctx));
$bot->onCbQueryData(['brands'], fn($ctx) => telegram::brands($ctx)); $bot->onCbQueryData(['brands'], fn($ctx) => telegram::brands($ctx));
$bot->onCbQueryData(['receiver_sim_choose'], fn($ctx) => telegram::receiver_sim_choose($ctx));
$bot->onCbQueryData(['receiver_sim_request'], fn($ctx) => telegram::receiver_sim_request($ctx));
$bot->onCbQueryData(['receiver_sim_input'], fn($ctx) => telegram::receiver_sim_input($ctx));
$bot->onCbQueryData(['receiver_sim_write'], fn($ctx) => telegram::receiver_sim_write($ctx));
$bot->onCbQueryData(['receiver_name_choose'], fn($ctx) => telegram::receiver_name_choose($ctx));
$bot->onCbQueryData(['receiver_name_request'], fn($ctx) => telegram::receiver_name_request($ctx));
$bot->onCbQueryData(['receiver_name_input'], fn($ctx) => telegram::receiver_name_input($ctx));
$bot->onCbQueryData(['receiver_name_write'], fn($ctx) => telegram::receiver_name_write($ctx));
$bot->onException(function (Context $ctx, $exception) { $bot->onException(function (Context $ctx, $exception) {
var_dump($exception); var_dump($exception);
}); });