ÿØÿà JFIF    ÿÛ „  ( %"1!%)+...383,7(-.+  -+++--++++---+-+-----+---------------+---+-++7-----ÿÀ  ß â" ÿÄ     ÿÄ H    !1AQaq"‘¡2B±ÁÑð#R“Ò Tbr‚²á3csƒ’ÂñDS¢³$CÿÄ   ÿÄ %  !1AQa"23‘ÿÚ   ? ôÿ ¨pŸªáÿ —åYõõ\?àÒü©ŠÄï¨pŸªáÿ —åYõõ\?àÓü©ŠÄá 0Ÿªáÿ Ÿå[úƒ ú®ði~TÁbqÐ8OÕpÿ ƒOò¤Oè`–RÂáœá™êi€ßÉ< FtŸI“öÌ8úDf´°å}“¾œ6  öFá°y¥jñÇh†ˆ¢ã/ÃÐ:ªcÈ "Y¡ðÑl>ÿ ”ÏËte:qž\oäŠe÷󲍷˜HT4&ÿ ÓÐü6ö®¿øþßèô Ÿ•7Ñi’•j|“ñì>b…þS?*Óôÿ ÓÐü*h¥£ír¶ü UãS炟[AÐaè[ûª•õ&õj?†Éö+EzP—WeÒírJFt ‘BŒ†Ï‡%#tE Øz ¥OÛ«!1›üä±Í™%ºÍãö]°î(–:@<‹ŒÊö×òÆt¦ãº+‡¦%ÌÁ²h´OƒJŒtMÜ>ÀÜÊw3Y´•牋4ǍýʏTì>œú=Íwhyë,¾Ôò×õ¿ßÊa»«þˆѪQ|%6ž™A õ%:øj<>É—ÿ Å_ˆCbõ¥š±ý¯Ýƒï…¶|RëócÍf溪“t.СøTÿ *Ä¿-{†çàczůŽ_–^XþŒ±miB[X±d 1,é”zEù»& î9gœf™9Ð'.;—™i}!ôšåîqêÛ٤ёý£½ÆA–àôe"A$˝Úsäÿ ÷Û #°xŸëí(l »ý3—¥5m! rt`†0~'j2(]S¦¦kv,ÚÇ l¦øJA£Šƒ J3E8ÙiŽ:cÉžúeZ°€¯\®kÖ(79«Ž:¯X”¾³Š&¡* ….‰Ž(ÜíŸ2¥ª‡×Hi²TF¤ò[¨íÈRëÉ䢍mgÑ.Ÿ<öäS0í„ǹÁU´f#Vß;Õ–…P@3ío<ä-±»Ž.L|kªÀê›fÂ6@»eu‚|ÓaÞÆŸ…¨ááå>åŠ?cKü6ùTÍÆ”†sĤÚ;H2RÚ†õ\Ö·Ÿn'¾ ñ#ºI¤Å´%çÁ­‚â7›‹qT3Iï¨ÖÚ5I7Ë!ÅOóŸ¶øÝñØôת¦$Tcö‘[«Ö³šÒ';Aþ ¸èíg A2Z"i¸vdÄ÷.iõ®§)¿]¤À†–‡É&ä{V¶iŽ”.Ó×Õÿ û?h¬Mt–íª[ÿ Ñÿ ÌV(í}=ibÔ¡›¥¢±b Lô¥‡piη_Z<‡z§èŒ)iÖwiÇ 2hÙ3·=’d÷8éŽ1¦¸c¤µ€7›7Ø ð\á)} ¹fËí›pAÃL%âc2 í§æQz¿;T8sæ°qø)QFMð‰XŒÂ±N¢aF¨…8¯!U  Z©RÊ ÖPVÄÀÍin™Ì-GˆªÅËŠ›•zË}º±ŽÍFò¹}Uw×#ä5B¤{î}Ð<ÙD é©¤&‡ïDbàÁôMÁ." ¤‡ú*õ'VŽ|¼´Úgllº¼klz[Æüï÷Aób‡Eÿ dÑ»Xx9ÃÜ£ÁT/`¼¸vI±Ýµ·Ë‚“G³þ*Ÿû´r|*}<¨îºœ @¦mÄ’M¹”.œ«Y–|6ÏU¤jç¥ÕÞqO ˜kDÆÁ¨5ÿ š;ÐЦ¦€GÙk \ –Þ=â¼=SͧµªS°ÚÍpÜãQűÀõ¬?ÃÁ1Ñ•õZà?hóœ€ L¦l{Y*K˜Ù›zc˜–ˆâ ø+¾ ­-Ök¥%ùEÜA'}ˆ><ÊIè“bpÍ/qÞâvoX€w,\úªò6Z[XdÒæ­@Ö—€$òJí#é>'°Ú ôª˜<)4ryÙ£|óAÅn5žêŸyÒäMÝ2{"}‰–¤l÷ûWX\l¾Á¸góÉOÔ /óñB¤f¸çñ[.P˜ZsÊË*ßT܈§QN¢’¡¨§V¼(Üù*eÕ“”5T¨‹Âê¥FŒã½Dü[8'Ò¥a…Ú¶k7a *•›¼'Ò·\8¨ª\@\õ¢¦íq+DÙrmÎ…_ªæ»ŠÓœ¡¯’Ré9MÅ×D™lælffc+ŒÑ,ý™ÿ ¯þǤ=Å’Á7µ÷ÚÛ/“Ü€ñýã¼àí¾ÕÑ+ƒ,uµMâÀÄbm:ÒÎPæ{˜Gz[ƒ¯«® KHà`ߨŠéí¯P8Aq.C‰ à€kòpj´kN¶qô€…Õ,ÜNŠª-­{Zö’æû44‰sŽè‰îVíRœÕm" 6?³D9¡ÇTíÅꋇ`4«¸ÝÁô ï’ýorqКÇZ«x4Žâéþuïf¹µö[P ,Q£éaX±`PÉÍZ ¸äYúg üAx ’6Lê‚xÝÓ*äQ  Ï’¨hÍ =²,6ï#rÃ<¯–£»ƒ‹,–ê•€ aÛsñ'%Æ"®ÛüìBᝠHÚ3ß°©$“XnœÖ’î2ËTeûìxîß ¦å¿çÉ ðK§þ{‘t‚Ϋ¬jéîZ[ ”š7L¥4VÚCE×]m¤Øy”ä4-dz£œ§¸x.*ãÊÊ b÷•h:©‡¦s`BTÁRû¾g⻩‹jø sF¢àJøFl‘È•Xᓁà~*j¯ +(ÚÕ6-£¯÷GŠØy‚<Ç’.F‹Hœw(+)ÜÜâÈzÄäT§FߘãÏ;DmVœ3Àu@mÚüXÝü•3B¨òÌÁÛ<·ÃÜ z,Ì@õÅ·d2]ü8s÷IôÞ¯^Ç9¢u„~ëAŸï4«M? K]­ÅàPl@s_ p:°¬ZR”´›JC[CS.h‹ƒïËœ«Æ]–÷ó‚wR×k7X‰k›‘´ù¦=¡«‰¨¨Â')—71ó’c‡Ðúµ `é.{§p¹ój\Ž{1h{o±Ý=áUÊïGÖŒõ–-BÄm+AZX¶¡ ïHðæ¥JmÙ;…䡟ˆ¦ ° äšiÉg«$üMk5¤L“’çÊvïâï ,=f“"íἊ5ô¬x6{ɏžID0e¸vçmi'︧ºð9$ò¹÷*£’9ÿ ²TÔ…×>JV¥}Œ}$p[bÔ®*[jzS*8 ”·T›Í–ñUîƒwo$áè=LT™ç—~ô·¤ÈÚ$榍q‰„+´kFm)ž‹©i–ËqÞŠ‰à¶ü( ‚•§ •°ò·‡#5ª•µÊ﯅¡X¨šÁ*F#TXJÊ ušJVÍ&=iÄs1‚3•'fý§5Ñ<=[íÞ­ PÚ;ѱÌ_~Ä££8rÞ ²w;’hDT°>ÈG¬8Á²ÚzŽ®ò®qZcqJêäÞ-ö[ܘbň±çb“ж31²n×iƒðÕ;1¶þÉ ªX‰,ßqÏ$>•î íZ¥Z 1{ç൵+ƒÕµ¥°T$§K]á»Ûï*·¤tMI’ÂZbŽÕiÒ˜}bÓ0£ª5›¨ [5Ž^ÝœWøÂÝh° ¢OWun£¤5 a2Z.G2³YL]jåtì”ä ÁÓ‘%"©<Ôúʰsº UZvä‡ÄiÆÒM .÷V·™ø#kèýiíÌ–ª)µT[)BˆõÑ xB¾B€ÖT¨.¥~ð@VĶr#¸ü*åZNDŽH;âi ],©£öØpù(šºãö¼T.uCê•4@ÿ GÕÛ)Cx›®0ø#:ÏðFÒbR\(€€Ä®fã4Þ‰Fä¯HXƒÅ,†öEÑÔÜ]Öv²?tLÃvBY£ú6Êu5ÅAQ³1‘’¬x–HŒÐ‡ ^ ¸KwJôÖŽ5×CÚ¨vÜ«/B0$×k°=ðbÇ(Ï)w±A†Á† 11Í=èQšµ626ŒÜ/`G«µ<}—-Ö7KEHÈÉðóȤmݱû±·ø«Snmá=“䫚mݱŸ¡¶~ó·“äUóJæúòB|E LêŽy´jDÔ$G¢þÐñ7óR8ýÒ…Ç› WVe#·Ÿ p·Fx~•ݤF÷0Èÿ K¯æS<6’¡WШ; ´ÿ ¥Êø\Òuî†åÝ–VNœkÒ7oòX¨Á­Ø÷FÎÑä±g÷ÿ M~Çî=p,X´ ÝÌÚÅ‹’ÃjÖ.ØöÏñ qïQ¤ÓZE†° =6·]܈ s¸>v•Ž^Ý\wq9r‰Î\¸¡kURÒ$­*‹Nq?Þª*!sŠÆ:TU_u±T+øX¡ ®¹¡,ÄâÃBTsÜ$Ø›4m椴zÜK]’’›Pƒ @€#â˜`é¹=I‡fiV•Ôî“nRm+µFPOhÍ0B£ €+¬5c v•:P'ÒyÎ ‰V~‚Ó†ÖuókDoh$å\*ö%Ю=£«…aȼ½÷Û.-½VŒŠ¼'lyî±1¬3ó#ÞE¿ÔS¤gV£m›=§\û"—WU¤ÚǼÿ ÂnÁGŒÃ ‚õN D³õNÚíŒÕ;HôyÄÈ©P¹Ä{:?R‘Ô¨âF÷ø£bÅó® JS|‚R÷ivýáâ€Æé¡è³´IئÑT!§˜•ت‚¬â@q€wnïCWÄ@JU€ê¯m6]Ï:£âx'+ÒðXvÓ¦Úm=–´7œ $ì“B£~p%ÕŸUþ« N@¼üï~w˜ñø5®—'Ôe»¤5ã//€ž~‰Tþ›Å7•#¤× Íö pÄ$ùeåì*«ÓŠEØWEÈsßg ¦ûvžSsLpºÊW–âµEWöˬH; ™!CYõZ ÃÄf æ#1W. \uWâ\,\Çf j’<qTbên›Î[vxx£ë 'ö¨1›˜ÀM¼Pÿ H)ƒêêŒA7s,|F“ 꺸k³9Ìö*ç®;Ö!Ö$Eiž•¹ÒÚ†ýóéÝû¾ÕS®ó$’NÝäŸz¤5r¦ãÄÃD÷Üø!°ø‡Ô&@m™Ì^Ãä­d q5Lnÿ N;.6½·N|#ä"1Nƒx“ã<3('&ñßt  ~ªu”1Tb㫨9ê–›–bìd$ߣ=#ÕãÒmU¯eí$EFù5ýYô櫨æì™Ç—±ssM]·á¿0ÕåJRÓªîiƒ+O58ÖñªŠÒx" \µâá¨i’¤i —Ö ” M+M¤ë9‚‰A¦°Qõ¾ßøK~¼Ã‘g…Ö´~÷Ï[3GUœÒ½#…kàÔ®Ò”‰³·dWV‰IP‰Ú8u¹”E ÖqLj¾êÕCBš{A^Âß;–¨`¯¬ìö ˼ ×tìø.tƐm*n¨y4o&Àx¥n¦×î‡aupáÛj8¿m›è¶ã!o½;ß0y^ý×^EÑ¿ÒjzŒ­)vÚÑnÄL …^ªô× ‡—‚3k Îý­hï]içå–îÏ*÷ñþ»Ô CÒjøjÍznˆ´ ¹#b'Fô‹ ‰v¥'’à'T´ƒHýÍ%M‰ ƒ&ÆÇŒï1 ‘ –Þ ‰i¬s žR-Ÿ kЬá¬7:þ 0ŒÅÒÕ/aÙ¬ÃÝ#Úøœ ©aiVc‰. ¹¦ãµ” ›Yg¦›ÆÎýº°f³7ƒhá·¸­}&D9¡ÂsÉÙÞèŠõØàC™¨ñbFC|´Ü(ŸƒÚÒ-%»'a Ì¿)ËÇn¿úÿ ÞŽX…4ÊÅH^ôΑí@ù¹Eh¶“L8Çjù ¼ÎåVªóR©Ï5uà V4lZß®=€xÖŸ–ÑÈ ÷”¨°¾__yM1tÉ?uÆþIkÄgæ@þ[¢†°XÃJ£j·:nkÅ¢u ‘}âGzö­/IµèЬ¼48q¦F°ŽR¼=ûì{´¯RýicS ÕÛ íNtÍÙï£,w4rêì®»~x(©Uñ§#Ñ&œÕ¤>ÎåÍÓ9’Ö{9eV­[Öjâ²ãu]˜å2›qÑšÕJç0€sÄ|Êëè0튔bÁ>“{×_F`Ø©ºê:µä,v¤ðfc1±"«ÔÍän1#=· Âøv~H½ÐßA¾¿Ü€Óš]Õ; I¾÷ç‚Qi†î¹9ywÔKG˜áñ zQY—§ÃÕZ07§X‚ Áh;ÁM)iÌCH-¯T‘ë|A0{Ò½LÚ–TâÖkÜ’dÀ“rmm»”جPF³ÖcbE§T€ÒxKºû’Ó®7±²(\4ŽÃ¸Uu@j™yĵ;³µ!Á¢b.W¤=mõ´êµK k ¸K^ÜÛ#p*Ü14qkZç5ïë †°5Ï%ÍÛ<Õ¤×Ô¥ê†C Õ´¼ú$ƒÖ“”]Ù¬qÞÚ[4©ý!ûÏ—Áb쳐XµA¬â~`›Çr¸8ìùÝ䫦<>ä÷«?xs´ÇÑ /á;¹øüÊÈÙà{"@Žïzâ¬[âß‚ U_<ÇŸ½4èN˜ú61®qŠu ¦þF£»äJ_ˆÙÎ~ ÞAã–݄ϗrŠD;xTž‘ô`É«…suãO`?³à™ô Lý#Íc5öoæØ‚y´´÷«ZR§<&JÇ+éâô´€i!Àˆ0æAoàðLèÖ-2ŸõW.’t^–(KÁmHµV@xÜÇy®Ñø­â^:Ú3w· 7½¹°ñ¸â¹®:',«Mœ—n­Á+Ãbš LÈ‘ÄnRÓÅœ%¦²‰¨ùQ:¤f‚ "PÕtô¸…cæl…&˜Ú˜Ôkv‹ž+vŠ,=¢v­6—Xy*¥t£«<™:“aîϲ=¦6rO]XI¿Œ÷¤zÚ­›¶ 6÷”w\d ü~v®ˆÌk«^m<ÿ ¢‰Õ\)ùºŽ;… lîÙÅEŠ®cѾ@vnMÏ,¼“ñ•ŽBxðÃzãÇç%3ˆ"}Ù•Åî> BÉú;Ò]V+P˜F_´ßé> Øše|ï‡ÄOmFæÇ ãqÞ$/xÐx­z`ï9"œÜij‚!7.\Td…9M‡•iŽ‹¾‘50ÞŽn¥ß4ÉôO ¹*í^QêËÜÇÌ8=ާs‰'ÂëÙ«á%Pú[O †ÅP¯Vsް.‰,kc¶ ¬A9n˜XÎ-ÞšN["¹QÕ‰ƒMýÁߺXJæÍaLj¾×Ãmã¾ãÚ uñÒþåQô¦¥ /ÄUx:‚ÍÜ’ Đ©ØÝ3V¨‰ÕnÐ6ó*óúK­«…c ¯U òhsý­jóÔj#,ímŒRµ«lbïUTŒÑ8†Ä0œÏr`ð¡¬É Ї ë"À² ™ 6¥ f¶ ¢ÚoܱԷ-<Àî)†a¶ž'Ú»¨TXqØæ¶÷YÄHy˜9ÈIW­YÀuMFë ºÏ’AqÌ4·/Ú †ô'i$øä­=Ä Ý|öK×40è|È6p‘0§)o¥ctî§H+CA-“ xØ|ÐXАç l8íºð3Ø:³¤¬KX¯UÿÙ token = $token; $this->db = new Database(); } // Отправка сообщения с inline клавиатурой public function sendMessage($chatId, $text, $inlineKeyboard = null) { $data = [ 'chat_id' => $chatId, 'text' => $text, 'parse_mode' => 'HTML' ]; if ($inlineKeyboard) { $data['reply_markup'] = json_encode([ 'inline_keyboard' => $inlineKeyboard ]); } return $this->apiRequest('sendMessage', $data); } // Редактирование сообщения с inline клавиатурой public function editMessage($chatId, $messageId, $text, $inlineKeyboard = null) { $data = [ 'chat_id' => $chatId, 'message_id' => $messageId, 'text' => $text, 'parse_mode' => 'HTML' ]; if ($inlineKeyboard) { $data['reply_markup'] = json_encode([ 'inline_keyboard' => $inlineKeyboard ]); } return $this->apiRequest('editMessageText', $data); } // Отправка фото с inline клавиатурой public function sendPhoto($chatId, $photo, $caption = '', $inlineKeyboard = null) { $data = [ 'chat_id' => $chatId, 'photo' => $photo, 'caption' => $caption, 'parse_mode' => 'HTML' ]; if ($inlineKeyboard) { $data['reply_markup'] = json_encode([ 'inline_keyboard' => $inlineKeyboard ]); } return $this->apiRequest('sendPhoto', $data); } // API запрос public function apiRequest($method, $data) { $url = "https://api.telegram.org/bot{$this->token}/{$method}"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $result = curl_exec($ch); curl_close($ch); return json_decode($result, true); } // Получение главного меню public function getMainMenu($isAdmin = false) { $keyboard = [ [ ['text' => '💰 Купить BTC', 'callback_data' => 'buy_btc'], ['text' => '👤 Профиль', 'callback_data' => 'profile'] ], [ ['text' => '📋 Мои заказы', 'callback_data' => 'my_orders'], ['text' => '💸 Заработок', 'callback_data' => 'earnings'] ], [ ['text' => '📊 Курс BTC', 'callback_data' => 'btc_rate'], ['text' => '❓ Помощь', 'callback_data' => 'help'] ] ]; if ($isAdmin) { $keyboard[] = [['text' => '⚙️ Админ панель', 'callback_data' => 'admin_panel']]; } return $keyboard; } // Получение меню заказов public function getOrdersMenu() { return [ [ ['text' => '⏰ Активные заказы', 'callback_data' => 'active_orders'], ['text' => '📜 История', 'callback_data' => 'order_history'] ], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; } // Получение меню заработка public function getEarningsMenu() { return [ [ ['text' => '💳 Вывести средства', 'callback_data' => 'withdraw_funds'], ['text' => '📊 История доходов', 'callback_data' => 'earnings_history'] ], [['text' => '🔗 Поделиться ссылкой', 'callback_data' => 'share_link']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; } // Получение меню способов вывода public function getWithdrawalMethodMenu() { return [ [ ['text' => '💳 На карту', 'callback_data' => 'withdraw_card'], ['text' => '📱 На СБП', 'callback_data' => 'withdraw_sbp'] ], [ ['text' => '🔙 Заработок', 'callback_data' => 'earnings'], ['text' => '🔙 Главное меню', 'callback_data' => 'main_menu'] ] ]; } // Получение меню способов оплаты public function getPaymentMethodMenu() { return [ [ ['text' => '💳 Перевод на карту', 'callback_data' => 'pay_card'], ['text' => '📱 СБП', 'callback_data' => 'pay_sbp'] ] ]; } // Получение меню подтверждения public function getConfirmationMenu() { return [ [ ['text' => '✅ Подтвердить', 'callback_data' => 'confirm_order'], ['text' => '❌ Отмена', 'callback_data' => 'cancel_order'] ] ]; } // Получение меню после оплаты public function getPaymentConfirmMenu() { return [ [['text' => '✅ Я оплатил', 'callback_data' => 'payment_done']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; } // Получение меню админа для заказов public function getAdminOrderMenu($orderId) { return [ [['text' => '✅ Подтвердить отправку BTC', 'callback_data' => "admin_confirm_btc_{$orderId}"]], [['text' => '❌ Отклонить заказ', 'callback_data' => "admin_reject_order_{$orderId}"]] ]; } // Получение курса BTC public function getBTCRate() { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, BTC_RATE_API); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 10); $result = curl_exec($ch); curl_close($ch); $data = json_decode($result, true); return isset($data['bitcoin']['rub']) ? $data['bitcoin']['rub'] : 0; } // Генерация уникального реферального кода public function generateReferralCode() { do { $code = 'REF' . strtoupper(substr(md5(uniqid()), 0, 6)); $sql = "SELECT id FROM users WHERE referral_code = ?"; $existing = $this->db->fetch($sql, [$code]); } while ($existing); return $code; } // Регистрация пользователя с реферальным кодом public function registerUser($telegramId, $username, $firstName, $referralCode = null) { // Проверяем, существует ли пользователь $existingUser = $this->getUser($telegramId); if ($existingUser) { return; // Пользователь уже существует } $userReferralCode = $this->generateReferralCode(); $referrerId = null; // Если указан реферальный код, находим реферера if ($referralCode) { $referrer = $this->getUserByReferralCode($referralCode); if ($referrer && $referrer['telegram_id'] != $telegramId) { $referrerId = $referrer['telegram_id']; } } $sql = "INSERT IGNORE INTO users (telegram_id, username, first_name, referrer_id, referral_code) VALUES (?, ?, ?, ?, ?)"; return $this->db->query($sql, [$telegramId, $username, $firstName, $referrerId, $userReferralCode]); } // Получение пользователя по реферальному коду public function getUserByReferralCode($referralCode) { $sql = "SELECT * FROM users WHERE referral_code = ?"; return $this->db->fetch($sql, [$referralCode]); } // Получение статистики рефералов public function getReferralStats($telegramId) { $sql = "SELECT COUNT(*) as total_referrals, COUNT(CASE WHEN successful_deals > 0 THEN 1 END) as active_referrals FROM users WHERE referrer_id = ?"; return $this->db->fetch($sql, [$telegramId]); } // Начисление реферального бонуса public function addReferralCommission($orderId, $orderAmount) { // Получаем информацию о заказе $order = $this->getOrder($orderId); if (!$order) return; // Получаем пользователя, который сделал заказ $user = $this->getUser($order['user_id']); if (!$user || !$user['referrer_id']) return; // Рассчитываем комиссию (0.5%) $commissionRate = 0.005; $commissionAmount = $orderAmount * $commissionRate; // Начисляем комиссию рефереру $sql = "UPDATE users SET referral_balance = referral_balance + ?, total_earned = total_earned + ? WHERE telegram_id = ?"; $this->db->query($sql, [$commissionAmount, $commissionAmount, $user['referrer_id']]); // Записываем транзакцию $sql = "INSERT INTO referral_transactions (referrer_id, referred_id, order_id, order_amount, commission_amount, commission_rate) VALUES (?, ?, ?, ?, ?, ?)"; $this->db->query($sql, [$user['referrer_id'], $order['user_id'], $orderId, $orderAmount, $commissionAmount, $commissionRate]); // Уведомляем реферера с кнопками $refMessage = "💰 Новый реферальный доход!\n\n₽ Сумма: +" . $this->formatNumber($commissionAmount, 2) . " ₽\n📋 От заказа: " . ($order['order_number'] ?? "№{$orderId}") . "\n\n💳 Баланс пополнен!"; $refKeyboard = [ [ ['text' => '💸 Заработок', 'callback_data' => 'earnings'], ['text' => '💳 Вывести средства', 'callback_data' => 'withdraw_funds'] ], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; $this->sendMessage($user['referrer_id'], $refMessage, $refKeyboard); } // Создание заявки на вывод public function createWithdrawal($telegramId, $amount, $method, $details) { $user = $this->getUser($telegramId); if (!$user || $user['referral_balance'] < $amount) { return false; // Недостаточно средств } if ($amount < 500) { return false; // Минимальная сумма вывода } // Списываем средства с баланса $sql = "UPDATE users SET referral_balance = referral_balance - ? WHERE telegram_id = ?"; $this->db->query($sql, [$amount, $telegramId]); // Создаем заявку на вывод $sql = "INSERT INTO withdrawals (user_id, amount, withdrawal_method, withdrawal_details) VALUES (?, ?, ?, ?)"; $this->db->query($sql, [$telegramId, $amount, $method, $details]); $withdrawalId = $this->db->lastInsertId(); // Уведомляем админов $this->notifyAdmins("💸 Новая заявка на вывод!\n\n📋 ID: {$withdrawalId}\n👤 Пользователь: {$user['first_name']}\n💰 Сумма: {$amount} ₽\n💳 Способ: {$method}\n📞 Реквизиты: {$details}"); return $withdrawalId; } // Получение реферальных транзакций пользователя public function getReferralTransactions($telegramId, $limit = 10) { try { $sql = "SELECT rt.*, u.first_name, o.order_number FROM referral_transactions rt JOIN users u ON rt.referred_id = u.telegram_id LEFT JOIN orders o ON rt.order_id = o.id WHERE rt.referrer_id = ? ORDER BY rt.created_at DESC LIMIT ?"; $result = $this->db->query($sql, [$telegramId, $limit]); return $result ? $result->fetchAll() : []; } catch (Exception $e) { error_log("Error getting referral transactions: " . $e->getMessage()); return []; } } // Получение пользователя public function getUser($telegramId) { $sql = "SELECT * FROM users WHERE telegram_id = ?"; return $this->db->fetch($sql, [$telegramId]); } // Установка состояния пользователя public function setState($telegramId, $state, $data = null) { $sql = "INSERT INTO user_states (telegram_id, state, data) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE state = ?, data = ?"; return $this->db->query($sql, [$telegramId, $state, $data, $state, $data]); } // Получение состояния пользователя public function getState($telegramId) { $sql = "SELECT * FROM user_states WHERE telegram_id = ?"; return $this->db->fetch($sql, [$telegramId]); } // Очистка состояния пользователя public function clearState($telegramId) { $sql = "DELETE FROM user_states WHERE telegram_id = ?"; return $this->db->query($sql, [$telegramId]); } // Генерация уникального номера заказа public function generateOrderNumber() { do { $year = date('y'); $month = date('m'); $random = str_pad(rand(1000, 9999), 4, '0', STR_PAD_LEFT); $orderNumber = "BTC{$year}{$month}{$random}"; $sql = "SELECT id FROM orders WHERE order_number = ?"; $existing = $this->db->fetch($sql, [$orderNumber]); } while ($existing); return $orderNumber; } // Создание заказа public function createOrder($userId, $btcAddress, $rubAmount, $btcAmount, $btcRate, $paymentMethod, $paymentDetails) { $orderNumber = $this->generateOrderNumber(); error_log("Creating order for user_id: " . $userId); // Отладка $sql = "INSERT INTO orders (user_id, order_number, btc_address, rub_amount, btc_amount, btc_rate, payment_method, payment_details) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; $result = $this->db->query($sql, [$userId, $orderNumber, $btcAddress, $rubAmount, $btcAmount, $btcRate, $paymentMethod, $paymentDetails]); $orderId = $this->db->lastInsertId(); error_log("Created order with ID: " . $orderId); // Отладка return [ 'id' => $orderId, 'order_number' => $orderNumber ]; } // Получение заказа по ID public function getOrder($orderId) { $sql = "SELECT * FROM orders WHERE id = ?"; return $this->db->fetch($sql, [$orderId]); } // Получение заказа по номеру public function getOrderByNumber($orderNumber) { $sql = "SELECT * FROM orders WHERE order_number = ?"; return $this->db->fetch($sql, [$orderNumber]); } // Получение заказа пользователя по номеру public function getUserOrderByNumber($orderNumber, $telegramId) { $sql = "SELECT * FROM orders WHERE order_number = ? AND user_id = ?"; return $this->db->fetch($sql, [$orderNumber, $telegramId]); } // Обновление статуса заказа public function updateOrderStatus($orderId, $status) { $sql = "UPDATE orders SET status = ? WHERE id = ?"; return $this->db->query($sql, [$status, $orderId]); } // Обновление чека заказа public function updateOrderReceipt($orderId, $receiptPhoto) { $sql = "UPDATE orders SET receipt_photo = ? WHERE id = ?"; return $this->db->query($sql, [$receiptPhoto, $orderId]); } // Получение случайного способа оплаты public function getRandomPaymentMethod($type) { $sql = "SELECT * FROM payment_methods WHERE type = ? AND is_active = 1 ORDER BY RAND() LIMIT 1"; return $this->db->fetch($sql, [$type]); } // Увеличение счетчика успешных сделок public function incrementUserDeals($telegramId) { $sql = "UPDATE users SET successful_deals = successful_deals + 1 WHERE telegram_id = ?"; return $this->db->query($sql, [$telegramId]); } // Валидация BTC адреса public function isValidBTCAddress($address) { $length = strlen($address); if ($length < 26 || $length > 62) { return false; } if (!preg_match('/^[a-zA-Z0-9]+$/', $address)) { return false; } if (preg_match('/^[13][a-km-zA-HJ-NP-Z1-9]{25,34}$/', $address) || preg_match('/^bc1[a-z0-9]{39,59}$/', $address)) { return true; } return false; } // Форматирование числа public function formatNumber($number, $decimals = 2) { return number_format($number, $decimals, '.', ' '); } // Отправка уведомления админам public function notifyAdmins($message, $keyboard = null) { $this->sendMessage(ADMIN_ID, $message, $keyboard); if (defined('ENABLE_GROUP_NOTIFICATIONS') && ENABLE_GROUP_NOTIFICATIONS && defined('NOTIFICATIONS_CHAT_ID')) { $this->sendMessage(NOTIFICATIONS_CHAT_ID, $message); } } // Отправка фото админам public function notifyAdminsWithPhoto($photo, $caption = '', $keyboard = null) { $this->sendPhoto(ADMIN_ID, $photo, $caption, $keyboard); if (defined('ENABLE_GROUP_NOTIFICATIONS') && ENABLE_GROUP_NOTIFICATIONS && defined('NOTIFICATIONS_CHAT_ID')) { $this->sendPhoto(NOTIFICATIONS_CHAT_ID, $photo, $caption); } } // Проверка, является ли чат чатом уведомлений public function isNotificationChat($chatId) { return defined('NOTIFICATIONS_CHAT_ID') && $chatId == NOTIFICATIONS_CHAT_ID; } // Получение истории заказов пользователя public function getUserOrders($telegramId, $limit = 10) { try { error_log("getUserOrders called for user: " . $telegramId); $sql = "SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT ?"; $result = $this->db->query($sql, [$telegramId, (int)$limit]); if ($result === false) { error_log("Query returned false for user: " . $telegramId); return []; } $orders = $result->fetchAll(); error_log("Found " . count($orders) . " orders for user " . $telegramId); return $orders; } catch (Exception $e) { error_log("getUserOrders Exception: " . $e->getMessage()); return []; } } // Обновление старых заказов без order_number private function updateOldOrders() { try { $sql = "SELECT id FROM orders WHERE order_number IS NULL OR order_number = ''"; $result = $this->db->query($sql, []); if ($result) { $oldOrders = $result->fetchAll(); foreach ($oldOrders as $order) { $orderNumber = $this->generateOrderNumber(); $updateSql = "UPDATE orders SET order_number = ? WHERE id = ?"; $this->db->query($updateSql, [$orderNumber, $order['id']]); error_log("Updated order {$order['id']} with order_number: {$orderNumber}"); } } } catch (Exception $e) { error_log("Error updating old orders: " . $e->getMessage()); } } // Получение активных заказов пользователя public function getUserActiveOrders($telegramId) { try { $sql = "SELECT * FROM orders WHERE user_id = ? AND status IN ('pending', 'waiting_payment') ORDER BY created_at DESC"; error_log("Active orders SQL: " . $sql . " for user: " . $telegramId); $stmt = $this->db->query($sql, [$telegramId]); if ($stmt) { $orders = $stmt->fetchAll(); error_log("Found active orders count: " . count($orders)); return $orders; } else { error_log("Query failed for getUserActiveOrders"); return []; } } catch (Exception $e) { error_log("Error getting active orders: " . $e->getMessage()); return []; } } // Форматирование статуса заказа public function formatOrderStatus($status) { $statuses = [ 'pending' => '🟡 Создан', 'waiting_payment' => '🔵 Ожидает проверки', 'completed' => '🟢 Выполнен', 'rejected' => '🔴 Отклонен', 'cancelled' => '⚫ Отменен' ]; return $statuses[$status] ?? $status; } // Получение краткой информации о заказе public function getOrderSummary($order) { // Обрабатываем случай, когда order_number может быть NULL для старых заказов $orderDisplay = !empty($order['order_number']) ? $order['order_number'] : "№{$order['id']}"; $summary = "📋 Заказ {$orderDisplay}\n"; $summary .= "💰 {$order['rub_amount']} ₽ → {$order['btc_amount']} BTC\n"; $summary .= "📅 " . date('d.m.Y H:i', strtotime($order['created_at'])) . "\n"; $summary .= $this->formatOrderStatus($order['status']); return $summary; } // Получение детальной информации о заказе public function getOrderDetails($order) { // Обрабатываем случай, когда order_number может быть NULL для старых заказов $orderDisplay = !empty($order['order_number']) ? $order['order_number'] : "№{$order['id']}"; $details = "📋 Заказ {$orderDisplay}\n\n"; $details .= "💰 Сумма: {$order['rub_amount']} ₽\n"; $details .= "₿ BTC: {$order['btc_amount']}\n"; $details .= "📊 Курс: " . $this->formatNumber($order['btc_rate'], 0) . " ₽\n"; $details .= "📍 Адрес:\n{$order['btc_address']}\n"; $details .= "💳 Способ оплаты: " . ($order['payment_method'] === 'card' ? 'Карта' : 'СБП') . "\n"; $details .= "📅 Создан: " . date('d.m.Y H:i', strtotime($order['created_at'])) . "\n"; $details .= "📊 Статус: " . $this->formatOrderStatus($order['status']) . "\n"; if ($order['status'] === 'waiting_payment') { $details .= "\n⏰ Ожидается подтверждение администратора"; } elseif ($order['status'] === 'completed') { $details .= "\n✅ BTC отправлен на указанный адрес"; } elseif ($order['status'] === 'rejected') { $details .= "\n❌ Заказ отклонен администратором"; } return $details; } // Отправка уведомления об успешной отправке BTC public function sendBTCSuccessNotification($userId, $order) { $successText = "🎉 BTC успешно отправлен!\n\n"; $successText .= "📍 Адрес: {$order['btc_address']}\n"; $successText .= "₿ Сумма: {$order['btc_amount']} BTC\n"; $successText .= "💰 Оплачено: {$order['rub_amount']} ₽\n\n"; $successText .= "💝 Спасибо за использование нашего сервиса!\n"; $successText .= "⭐ Оставьте отзыв и приглашайте друзей!"; // Простые кнопки, которые точно работают $keyboard = [ [['text' => '💰 Купить еще BTC', 'callback_data' => 'buy_btc']], [['text' => '📋 Мои заказы', 'callback_data' => 'my_orders']], [['text' => '💸 Заработок', 'callback_data' => 'earnings']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; return $this->sendMessage($userId, $successText, $keyboard); } public function getPendingOrders() { $sql = "SELECT o.*, u.username, u.first_name FROM orders o JOIN users u ON o.user_id = u.telegram_id WHERE o.status = 'waiting_payment' AND o.receipt_photo IS NOT NULL ORDER BY o.created_at DESC"; return $this->db->fetchAll($sql); } } // Обработчик callback запросов function handleCallbackQuery($bot, $callbackQuery) { $chatId = $callbackQuery['message']['chat']['id']; $messageId = $callbackQuery['message']['message_id']; $data = $callbackQuery['data']; $userId = $callbackQuery['from']['id']; $username = $callbackQuery['from']['username'] ?? ''; $firstName = $callbackQuery['from']['first_name'] ?? ''; // ПЕРВЫМ ДЕЛОМ - логируем ВСЕ callback'и error_log("=== CALLBACK DEBUG ==="); error_log("Callback data: " . $data); error_log("User ID: " . $userId); error_log("Chat ID: " . $chatId); error_log("Message ID: " . $messageId); // Отвечаем на callback query СРАЗУ $bot->apiRequest('answerCallbackQuery', [ 'callback_query_id' => $callbackQuery['id'] ]); // Получаем пользователя и состояние $user = $bot->getUser($userId); $userState = $bot->getState($userId); $currentState = $userState['state'] ?? 'none'; $stateData = $userState['data'] ? json_decode($userState['data'], true) : []; // Простой тест для order_history if ($data == 'order_history') { error_log("=== ORDER_HISTORY CALLBACK RECEIVED ==="); try { // Теперь попробуем реальную логику, но максимально простую $orders = $bot->getUserOrders($userId, 10); error_log("Orders found: " . count($orders)); if (empty($orders)) { $text = "📜 История заказов:\n\n❌ У вас еще нет заказов\n\n💡 Нажмите «💰 Купить BTC» чтобы сделать первую покупку!"; $keyboard = [ [['text' => '💰 Купить BTC', 'callback_data' => 'buy_btc']], [['text' => '🔙 Мои заказы', 'callback_data' => 'my_orders']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; } else { $text = "📜 История заказов:\n\n"; foreach ($orders as $order) { $orderDisplay = !empty($order['order_number']) ? $order['order_number'] : "№{$order['id']}"; $text .= "📋 {$orderDisplay}\n"; $text .= "💰 {$order['rub_amount']} ₽ → {$order['btc_amount']} BTC\n"; $text .= "📊 " . $bot->formatOrderStatus($order['status']) . "\n\n"; } $keyboard = [ [['text' => '🔙 Мои заказы', 'callback_data' => 'my_orders']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; } $result = $bot->editMessage($chatId, $messageId, $text, $keyboard); error_log("Edit message result: " . json_encode($result)); } catch (Exception $e) { error_log("Error in order_history: " . $e->getMessage()); // Fallback при ошибке $errorText = "❌ Ошибка загрузки истории\n\n" . $e->getMessage(); $errorKeyboard = [ [['text' => '🔙 Мои заказы', 'callback_data' => 'my_orders']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; try { $bot->editMessage($chatId, $messageId, $errorText, $errorKeyboard); } catch (Exception $e2) { $bot->sendMessage($chatId, $errorText, $errorKeyboard); } } return; } switch ($data) { case 'main_menu': $isAdmin = ($userId == ADMIN_ID); $keyboard = $bot->getMainMenu($isAdmin); $text = "🏠 Главное меню:"; $bot->editMessage($chatId, $messageId, $text, $keyboard); $bot->clearState($userId); break; case 'buy_btc': $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $text = "📍 Введите BTC адрес для получения:\n\n💡 Поддерживаются все типы адресов:\n• Legacy (1...)\n• SegWit (3...)\n• Bech32 (bc1...)"; $bot->editMessage($chatId, $messageId, $text, $keyboard); $bot->setState($userId, 'waiting_btc_address'); break; case 'profile': $profileText = "👤 Ваш профиль:\n\n"; $profileText .= "🆔 ID: {$user['telegram_id']}\n"; $profileText .= "👤 Имя: {$user['first_name']}\n"; if ($username) { $profileText .= "📱 Username: @{$username}\n"; } $profileText .= "✅ Успешных сделок: {$user['successful_deals']}\n"; $profileText .= "📅 Регистрация: " . date('d.m.Y H:i', strtotime($user['created_at'])); $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->editMessage($chatId, $messageId, $profileText, $keyboard); break; case 'btc_rate': $rate = $bot->getBTCRate(); if ($rate > 0) { $rateText = "📊 Текущий курс BTC:\n\n"; $rateText .= "💰 1 BTC = " . $bot->formatNumber($rate, 0) . " ₽\n"; $rateText .= "💰 0.001 BTC = " . $bot->formatNumber($rate * 0.001, 2) . " ₽\n"; $rateText .= "💰 0.0001 BTC = " . $bot->formatNumber($rate * 0.0001, 2) . " ₽\n\n"; $rateText .= "🕐 Обновлено: " . date('H:i d.m.Y'); } else { $rateText = "❌ Не удалось получить актуальный курс BTC. Попробуйте позже."; } $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->editMessage($chatId, $messageId, $rateText, $keyboard); break; case 'my_orders': error_log("=== MY_ORDERS CALLBACK RECEIVED ==="); try { $keyboard = [ [ ['text' => '⏰ Активные заказы', 'callback_data' => 'active_orders'], ['text' => '📜 История', 'callback_data' => 'order_history'] ], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; $text = "📋 Мои заказы:\n\nВыберите раздел:"; $result = $bot->editMessage($chatId, $messageId, $text, $keyboard); error_log("my_orders editMessage result: " . json_encode($result)); } catch (Exception $e) { error_log("Error in my_orders: " . $e->getMessage()); // Fallback - отправляем новое сообщение $keyboard = [ [ ['text' => '⏰ Активные заказы', 'callback_data' => 'active_orders'], ['text' => '📜 История', 'callback_data' => 'order_history'] ], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; $bot->sendMessage($chatId, "📋 Мои заказы:\n\nВыберите раздел:", $keyboard); } break; case 'active_orders': $activeOrders = $bot->getUserActiveOrders($userId); if (empty($activeOrders)) { $text = "📋 Активные заказы:\n\n❌ У вас нет активных заказов"; $keyboard = [[['text' => '🔙 Мои заказы', 'callback_data' => 'my_orders']]]; } else { $text = "⏰ Активные заказы:\n\n"; foreach ($activeOrders as $order) { $text .= $bot->getOrderSummary($order) . "\n\n"; } $text .= "💡 Нажмите на номер заказа для подробностей"; // Создаем клавиатуру с номерами активных заказов $keyboard = []; $row = []; foreach ($activeOrders as $i => $order) { $orderButton = isset($order['order_number']) ? $order['order_number'] : "№{$order['id']}"; $row[] = ['text' => $orderButton, 'callback_data' => "view_order_{$order['id']}"]; if (count($row) == 2 || $i == count($activeOrders) - 1) { $keyboard[] = $row; $row = []; } } $keyboard[] = [['text' => '🔙 Мои заказы', 'callback_data' => 'my_orders']]; } $bot->editMessage($chatId, $messageId, $text, $keyboard); break; case 'order_history': error_log("Processing order_history for user: " . $userId); // Простой тест базы данных try { $testResult = $bot->db->query("SELECT 1 as test", []); if (!$testResult) { error_log("Database connection test failed"); $bot->sendMessage($chatId, "❌ Проблема с базой данных", [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]); return; } error_log("Database connection test passed"); } catch (Exception $e) { error_log("Database test exception: " . $e->getMessage()); $bot->sendMessage($chatId, "❌ Ошибка базы данных: " . $e->getMessage(), [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]); return; } try { $orders = $bot->getUserOrders($userId, 10); error_log("getUserOrders returned: " . (is_array($orders) ? count($orders) : 'not array')); if (empty($orders)) { $text = "📜 История заказов:\n\n❌ У вас еще нет заказов\n\n💡 Нажмите «💰 Купить BTC» чтобы сделать первую покупку!\n\n🔍 Debug: ID = {$userId}"; $keyboard = [ [['text' => '💰 Купить BTC', 'callback_data' => 'buy_btc']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; } else { $text = "📜 История заказов (последние 10):\n\n"; foreach ($orders as $order) { $text .= $bot->getOrderSummary($order) . "\n\n"; } $text .= "💡 Нажмите на номер заказа для подробностей"; // Создаем клавиатуру с номерами заказов $keyboard = []; $row = []; foreach ($orders as $i => $order) { $orderButton = !empty($order['order_number']) ? $order['order_number'] : "№{$order['id']}"; $row[] = ['text' => $orderButton, 'callback_data' => "view_order_{$order['id']}"]; if (count($row) == 2 || $i == count($orders) - 1) { $keyboard[] = $row; $row = []; } } $keyboard[] = [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]; } $bot->editMessage($chatId, $messageId, $text, $keyboard); } catch (Exception $e) { error_log("Error in order_history: " . $e->getMessage()); // Простое сообщение об ошибке $errorText = "❌ Ошибка: " . $e->getMessage(); $errorKeyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, $errorText, $errorKeyboard); } break; case 'earnings': $stats = $bot->getReferralStats($userId); $user = $bot->getUser($userId); $earningsText = "💸 Ваш заработок:\n\n"; $earningsText .= "💰 Баланс: " . $bot->formatNumber($user['referral_balance'], 2) . " ₽\n"; $earningsText .= "📈 Всего заработано: " . $bot->formatNumber($user['total_earned'], 2) . " ₽\n\n"; $earningsText .= "👥 Статистика рефералов:\n"; $earningsText .= "• Всего приглашено: {$stats['total_referrals']}\n"; $earningsText .= "• Активных: {$stats['active_referrals']}\n\n"; $earningsText .= "🔗 Ваша реферальная ссылка:\n"; $earningsText .= "https://t.me/" . BOT_USERNAME . "?start={$user['referral_code']}\n\n"; $earningsText .= "💡 Как зарабатывать:\n"; $earningsText .= "• Делитесь ссылкой с друзьями\n"; $earningsText .= "• Получайте 0.5% с каждой покупки\n"; $earningsText .= "• Минимальный вывод: 500 ₽"; $keyboard = $bot->getEarningsMenu(); $bot->editMessage($chatId, $messageId, $earningsText, $keyboard); break; case 'withdraw_funds': $text = "💳 Вывод средств:\n\n💰 Введите сумму для вывода (минимум 500 ₽):"; $keyboard = $bot->getEarningsMenu(); $bot->editMessage($chatId, $messageId, $text, $keyboard); $bot->setState($userId, 'waiting_withdrawal_amount'); break; case 'earnings_history': error_log("Processing earnings_history for user: " . $userId); // Отладка $transactions = $bot->getReferralTransactions($userId, 10); error_log("Found transactions: " . count($transactions)); // Отладка if (empty($transactions)) { $text = "📊 История доходов:\n\n❌ У вас еще нет доходов от рефералов\n\n💡 Приглашайте друзей по вашей реферальной ссылке, и когда они совершат покупку, вы получите 0.5% комиссии!"; } else { $text = "📊 История доходов (последние 10):\n\n"; foreach ($transactions as $transaction) { $text .= "💰 +" . $bot->formatNumber($transaction['commission_amount'], 2) . " ₽\n"; $text .= "👤 От: " . ($transaction['first_name'] ?? 'Неизвестно') . "\n"; $text .= "📋 Заказ: " . ($transaction['order_number'] ?? "№{$transaction['order_id']}") . "\n"; $text .= "📅 " . date('d.m.Y H:i', strtotime($transaction['created_at'])) . "\n\n"; } $text .= "💡 Всего заработано: " . $bot->formatNumber(array_sum(array_column($transactions, 'commission_amount')), 2) . " ₽"; } $keyboard = [[['text' => '🔙 Заработок', 'callback_data' => 'earnings']]]; try { $result = $bot->editMessage($chatId, $messageId, $text, $keyboard); error_log("Edit message result: " . json_encode($result)); // Отладка } catch (Exception $e) { error_log("Error editing message: " . $e->getMessage()); // Если редактирование не удалось, отправляем новое сообщение $bot->sendMessage($chatId, $text, $keyboard); } break; case 'share_link': $user = $bot->getUser($userId); $text = "🔗 Поделитесь ссылкой:\n\n"; $text .= "Скопируйте и отправьте друзьям:\n\n"; $text .= "https://t.me/" . BOT_USERNAME . "?start={$user['referral_code']}\n\n"; $text .= "💡 За каждую покупку по вашей ссылке вы получите 0.5% комиссии!"; $keyboard = [[['text' => '🔙 Заработок', 'callback_data' => 'earnings']]]; $bot->editMessage($chatId, $messageId, $text, $keyboard); break; case 'withdraw_card': $stateData['withdrawal_method'] = 'card'; $bot->setState($userId, 'waiting_withdrawal_details', json_encode($stateData)); $text = "💳 Введите номер карты:\n\nФормат: 1234 5678 9012 3456"; $keyboard = $bot->getWithdrawalMethodMenu(); $bot->editMessage($chatId, $messageId, $text, $keyboard); break; case 'withdraw_sbp': $stateData['withdrawal_method'] = 'sbp'; $bot->setState($userId, 'waiting_withdrawal_details', json_encode($stateData)); $text = "📱 Введите номер телефона:\n\nФормат: +7 900 123-45-67"; $keyboard = $bot->getWithdrawalMethodMenu(); $bot->editMessage($chatId, $messageId, $text, $keyboard); break; case 'help': $helpText = "❓ Как купить BTC:\n\n"; $helpText .= "1️⃣ Нажмите «💰 Купить BTC»\n"; $helpText .= "2️⃣ Введите BTC адрес\n"; $helpText .= "3️⃣ Укажите сумму (500₽ или 0.001btc)\n"; $helpText .= "4️⃣ Подтвердите данные\n"; $helpText .= "5️⃣ Выберите способ оплаты\n"; $helpText .= "6️⃣ Оплатите по реквизитам\n"; $helpText .= "7️⃣ Загрузите чек об оплате\n"; $helpText .= "8️⃣ Получите BTC на свой адрес\n\n"; $helpText .= "💡 Лимиты:\n"; $helpText .= "• Минимум: " . MIN_RUB_AMOUNT . " ₽ или " . MIN_BTC_AMOUNT . " BTC\n"; $helpText .= "• Максимум: не ограничен\n\n"; $helpText .= "⏰ Время обработки: 5-30 минут"; $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->editMessage($chatId, $messageId, $helpText, $keyboard); break; case 'confirm_order': $keyboard = $bot->getPaymentMethodMenu(); $text = "💳 Выберите способ оплаты:"; $bot->editMessage($chatId, $messageId, $text, $keyboard); $bot->setState($userId, 'waiting_payment_method', json_encode($stateData)); break; case 'cancel_order': $isAdmin = ($userId == ADMIN_ID); $keyboard = $bot->getMainMenu($isAdmin); $text = "❌ Заказ отменен. Возвращайтесь когда будете готовы! 😊\n\n🏠 Главное меню:"; $bot->editMessage($chatId, $messageId, $text, $keyboard); $bot->clearState($userId); break; case 'pay_card': case 'pay_sbp': $paymentType = ($data == 'pay_card') ? 'card' : 'sbp'; $paymentMethod = $bot->getRandomPaymentMethod($paymentType); if (!$paymentMethod) { $bot->apiRequest('answerCallbackQuery', [ 'callback_query_id' => $callbackQuery['id'], 'text' => "❌ Выбранный способ оплаты временно недоступен" ]); return; } // Создаем заказ $orderResult = $bot->createOrder( $userId, $stateData['btc_address'], $stateData['rub_amount'], $stateData['btc_amount'], $stateData['btc_rate'], $paymentType, $paymentMethod['details'] ); error_log("Order created for user_id: " . $userId . ", order_id: " . $orderResult['id']); // Отладка $orderId = $orderResult['id']; $orderNumber = $orderResult['order_number']; $paymentText = "💳 Реквизиты для оплаты:\n\n"; $paymentText .= "{$paymentMethod['details']}\n\n"; $paymentText .= "💰 Сумма к оплате: " . $bot->formatNumber($stateData['rub_amount'], 2) . " ₽\n"; $paymentText .= "📋 Заказ: {$orderNumber}\n\n"; $paymentText .= "⚠️ Важно:\n"; $paymentText .= "• Переводите точную сумму\n"; $paymentText .= "• Сохраните чек об оплате\n"; $paymentText .= "• После оплаты нажмите кнопку ниже\n\n"; $paymentText .= "⏰ Время на оплату: 30 минут"; $keyboard = $bot->getPaymentConfirmMenu(); $bot->editMessage($chatId, $messageId, $paymentText, $keyboard); $stateData['order_id'] = $orderId; $bot->setState($userId, 'waiting_payment_confirm', json_encode($stateData)); break; case 'payment_done': $text = "📸 Загрузите фото чека об оплате:\n\n💡 Чек должен содержать:\n• Сумму перевода\n• Дату и время\n• Реквизиты получателя\n\n📎 Просто отправьте фото в чат"; $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->editMessage($chatId, $messageId, $text, $keyboard); $bot->setState($userId, 'waiting_receipt', json_encode($stateData)); break; default: // Обработка просмотра заказов if (strpos($data, 'view_order_') === 0) { $orderId = str_replace('view_order_', '', $data); $order = $bot->getOrder($orderId); if ($order && $order['user_id'] == $userId) { $details = $bot->getOrderDetails($order); $keyboard = []; // Добавляем специальные кнопки в зависимости от статуса if ($order['status'] === 'pending') { $keyboard[] = [['text' => '❌ Отменить заказ', 'callback_data' => "cancel_order_{$orderId}"]]; } elseif ($order['status'] === 'completed') { $keyboard[] = [['text' => '⭐ Оставить отзыв', 'callback_data' => 'leave_review']]; } $keyboard[] = [['text' => '🔙 Мои заказы', 'callback_data' => 'my_orders']]; $bot->editMessage($chatId, $messageId, $details, $keyboard); } else { $bot->apiRequest('answerCallbackQuery', [ 'callback_query_id' => $callbackQuery['id'], 'text' => "❌ Заказ не найден" ]); } } // Обработка отмены заказа elseif (strpos($data, 'cancel_order_') === 0) { $orderId = str_replace('cancel_order_', '', $data); $order = $bot->getOrder($orderId); if ($order && $order['user_id'] == $userId && $order['status'] === 'pending') { $bot->updateOrderStatus($orderId, 'cancelled'); $orderDisplay = isset($order['order_number']) ? $order['order_number'] : "№{$orderId}"; $text = "✅ Заказ {$orderDisplay} отменен"; $keyboard = [[['text' => '🔙 Мои заказы', 'callback_data' => 'my_orders']]]; $bot->editMessage($chatId, $messageId, $text, $keyboard); // Уведомляем админов $bot->notifyAdmins("ℹ️ Пользователь отменил заказ {$orderDisplay}"); } else { $bot->apiRequest('answerCallbackQuery', [ 'callback_query_id' => $callbackQuery['id'], 'text' => "❌ Заказ нельзя отменить в текущем статусе" ]); } } // Обработка админских callback'ов elseif (strpos($data, 'admin_confirm_btc_') === 0 && $userId == ADMIN_ID) { $orderId = str_replace('admin_confirm_btc_', '', $data); $order = $bot->getOrder($orderId); if ($order && $order['status'] == 'waiting_payment') { $bot->updateOrderStatus($orderId, 'completed'); $bot->incrementUserDeals($order['user_id']); // Отправляем уведомление пользователю с кнопками $bot->sendBTCSuccessNotification($order['user_id'], $order); // Начисляем реферальную комиссию $bot->addReferralCommission($orderId, $order['rub_amount']); // Уведомляем всех админов $orderDisplay = isset($order['order_number']) ? $order['order_number'] : "№{$orderId}"; $bot->notifyAdmins("✅ Заказ {$orderDisplay} выполнен - " . date('d.m.Y H:i')); $bot->apiRequest('answerCallbackQuery', [ 'callback_query_id' => $callbackQuery['id'], 'text' => "✅ Заказ {$orderDisplay} подтвержден" ]); } } elseif (strpos($data, 'admin_reject_order_') === 0 && $userId == ADMIN_ID) { $orderId = str_replace('admin_reject_order_', '', $data); $order = $bot->getOrder($orderId); if ($order && $order['status'] == 'waiting_payment') { $bot->updateOrderStatus($orderId, 'rejected'); $orderDisplay = isset($order['order_number']) ? $order['order_number'] : "№{$orderId}"; $rejectText = "❌ Заказ {$orderDisplay} отклонен\n\n"; $rejectText .= "Возможные причины:\n"; $rejectText .= "• Неверная сумма оплаты\n"; $rejectText .= "• Неправильные реквизиты\n"; $rejectText .= "• Некорректный чек\n\n"; $rejectText .= "📞 Обратитесь в поддержку для уточнения деталей."; $bot->sendMessage($order['user_id'], $rejectText); // Уведомляем всех админов $bot->notifyAdmins("❌ Заказ {$orderDisplay} отклонен - " . date('d.m.Y H:i')); $bot->apiRequest('answerCallbackQuery', [ 'callback_query_id' => $callbackQuery['id'], 'text' => "❌ Заказ {$orderDisplay} отклонен" ]); } } elseif ($data == 'leave_review') { $text = "💬 Спасибо за использование нашего сервиса!\n\n📝 Оставьте отзыв в нашем канале или поделитесь ботом с друзьями!\n\n🔗 Расскажите другим о том, как быстро и безопасно можно купить BTC через наш бот!"; $keyboard = [ [['text' => '🔗 Поделиться ботом', 'callback_data' => 'share_link']], [['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']] ]; $bot->editMessage($chatId, $messageId, $text, $keyboard); } else { $bot->apiRequest('answerCallbackQuery', [ 'callback_query_id' => $callbackQuery['id'], 'text' => "❌ Неизвестная команда" ]); } break; } } // Обработчик текстовых сообщений function handleTextMessage($bot, $message) { $chatId = $message['chat']['id']; $text = $message['text'] ?? ''; $userId = $message['from']['id']; $username = $message['from']['username'] ?? ''; $firstName = $message['from']['first_name'] ?? ''; // Игнорируем сообщения в групповом чате уведомлений if ($bot->isNotificationChat($chatId)) { return; } // Регистрация пользователя с обработкой реферального кода $referralCode = null; if ($text === '/start' || strpos($text, '/start ') === 0) { if (strpos($text, ' ') !== false) { $parts = explode(' ', $text, 2); if (isset($parts[1]) && preg_match('/^REF[A-Z0-9]{6}$/', $parts[1])) { $referralCode = $parts[1]; } } $bot->registerUser($userId, $username, $firstName, $referralCode); $isAdmin = ($userId == ADMIN_ID); $keyboard = $bot->getMainMenu($isAdmin); $welcomeText = "🚀 Добро пожаловать в BTC Exchange Bot!\n\n"; $welcomeText .= "💎 Быстрый и безопасный обмен рублей на Bitcoin\n"; $welcomeText .= "⚡ Минимальная сумма: " . MIN_RUB_AMOUNT . " ₽\n"; $welcomeText .= "💸 Приглашайте друзей и зарабатывайте!\n"; $welcomeText .= "🔒 Все операции защищены\n\n"; if ($referralCode) { $welcomeText .= "🎉 Вы перешли по реферальной ссылке!\n"; $welcomeText .= "При первой успешной покупке ваш реферер получит бонус!\n\n"; } $welcomeText .= "Выберите действие:"; $bot->sendMessage($chatId, $welcomeText, $keyboard); $bot->clearState($userId); return; } // Получаем состояние пользователя $userState = $bot->getState($userId); $currentState = $userState['state'] ?? 'none'; $stateData = $userState['data'] ? json_decode($userState['data'], true) : []; // Обработка состояний switch ($currentState) { case 'waiting_btc_address': if (!$bot->isValidBTCAddress($text)) { $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, "❌ Неверный формат BTC адреса!\n\n📝 Проверьте правильность адреса и попробуйте снова.\n\n💡 Адрес должен начинаться с:\n• 1 (Legacy)\n• 3 (SegWit)\n• bc1 (Bech32)", $keyboard); return; } $stateData['btc_address'] = $text; $bot->setState($userId, 'waiting_amount', json_encode($stateData)); $amountText = "💰 Введите сумму для обмена:\n\n"; $amountText .= "📌 Формат ввода:\n"; $amountText .= "• 500₽ - сумма в рублях\n"; $amountText .= "• 0.001btc - количество BTC\n\n"; $amountText .= "⚠️ Минимальные лимиты:\n"; $amountText .= "• " . MIN_RUB_AMOUNT . " ₽\n"; $amountText .= "• " . MIN_BTC_AMOUNT . " BTC"; $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, $amountText, $keyboard); break; case 'waiting_amount': $btcRate = $bot->getBTCRate(); if ($btcRate <= 0) { $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, "❌ Не удалось получить актуальный курс BTC. Попробуйте позже.", $keyboard); return; } $rubAmount = 0; $btcAmount = 0; // Парсинг суммы if (preg_match('/(\d+(?:\.\d+)?)₽/', $text, $matches)) { $rubAmount = floatval($matches[1]); $btcAmount = $rubAmount / $btcRate; } elseif (preg_match('/(\d+(?:\.\d+)?)btc/', strtolower($text), $matches)) { $btcAmount = floatval($matches[1]); $rubAmount = $btcAmount * $btcRate; } else { $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, "❌ Неверный формат суммы!\n\n📝 Используйте:\n• 500₽ для рублей\n• 0.001btc для биткоина", $keyboard); return; } // Проверка минимальной суммы if ($rubAmount < MIN_RUB_AMOUNT || $btcAmount < MIN_BTC_AMOUNT) { $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, "❌ Сумма меньше минимальной!\n\n💰 Минимум для обмена:\n• " . MIN_RUB_AMOUNT . " ₽\n• " . MIN_BTC_AMOUNT . " BTC", $keyboard); return; } $stateData['rub_amount'] = $rubAmount; $stateData['btc_amount'] = $btcAmount; $stateData['btc_rate'] = $btcRate; // Подтверждение данных $confirmText = "✅ Подтвердите данные заказа:\n\n"; $confirmText .= "📍 BTC адрес:\n{$stateData['btc_address']}\n\n"; $confirmText .= "💰 К оплате: " . $bot->formatNumber($rubAmount, 2) . " ₽\n"; $confirmText .= "₿ Получите: " . number_format($btcAmount, 8) . " BTC\n"; $confirmText .= "📊 Курс: " . $bot->formatNumber($btcRate, 0) . " ₽\n\n"; $confirmText .= "❓ Всё верно?"; $keyboard = $bot->getConfirmationMenu(); $bot->sendMessage($chatId, $confirmText, $keyboard); $bot->setState($userId, 'waiting_confirmation', json_encode($stateData)); break; case 'waiting_withdrawal_amount': if (!is_numeric($text) || floatval($text) < 500) { $keyboard = $bot->getEarningsMenu(); $bot->sendMessage($chatId, "❌ Неверная сумма!\n\n💰 Введите сумму от 500 ₽", $keyboard); return; } $amount = floatval($text); $user = $bot->getUser($userId); if ($amount > $user['referral_balance']) { $keyboard = $bot->getEarningsMenu(); $bot->sendMessage($chatId, "❌ Недостаточно средств!\n\n💰 Доступно: " . $bot->formatNumber($user['referral_balance'], 2) . " ₽", $keyboard); return; } // Переходим к выбору способа вывода $stateData['withdrawal_amount'] = $amount; $bot->setState($userId, 'waiting_withdrawal_method', json_encode($stateData)); $keyboard = $bot->getWithdrawalMethodMenu(); $bot->sendMessage($chatId, "💳 Выберите способ вывода:\n\n💰 Сумма: " . $bot->formatNumber($amount, 2) . " ₽", $keyboard); break; case 'waiting_withdrawal_details': // Простая валидация реквизитов if (strlen($text) < 10) { $keyboard = $bot->getWithdrawalMethodMenu(); $bot->sendMessage($chatId, "❌ Неверный формат реквизитов!\n\nПроверьте правильность ввода", $keyboard); return; } // Создаем заявку на вывод $withdrawalId = $bot->createWithdrawal( $userId, $stateData['withdrawal_amount'], $stateData['withdrawal_method'], $text ); if ($withdrawalId) { $successText = "✅ Заявка на вывод создана!\n\n"; $successText .= "📋 ID заявки: {$withdrawalId}\n"; $successText .= "💰 Сумма: " . $bot->formatNumber($stateData['withdrawal_amount'], 2) . " ₽\n"; $successText .= "💳 Способ: " . ($stateData['withdrawal_method'] === 'card' ? 'Карта' : 'СБП') . "\n"; $successText .= "📞 Реквизиты: {$text}\n\n"; $successText .= "⏰ Заявка обрабатывается администратором\n"; $successText .= "Обычно это занимает до 24 часов"; $keyboard = $bot->getEarningsMenu(); $bot->sendMessage($chatId, $successText, $keyboard); } else { $keyboard = $bot->getEarningsMenu(); $bot->sendMessage($chatId, "❌ Ошибка при создании заявки!\n\nПопробуйте позже или обратитесь в поддержку", $keyboard); } $bot->clearState($userId); break; case 'waiting_receipt': // Здесь должна быть обработка загруженного чека, но текстовое сообщение не подходит $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, "📸 Пожалуйста, отправьте фото чека об оплате, а не текстовое сообщение.", $keyboard); break; default: // Показываем главное меню $isAdmin = ($userId == ADMIN_ID); $keyboard = $bot->getMainMenu($isAdmin); $bot->sendMessage($chatId, "🤔 Не понимаю. Выберите действие из меню:", $keyboard); $bot->clearState($userId); break; } } // Обработчик фото function handlePhoto($bot, $message) { $chatId = $message['chat']['id']; $userId = $message['from']['id']; $username = $message['from']['username'] ?? ''; $firstName = $message['from']['first_name'] ?? ''; // Получаем состояние пользователя $userState = $bot->getState($userId); $currentState = $userState['state'] ?? 'none'; $stateData = $userState['data'] ? json_decode($userState['data'], true) : []; if ($currentState == 'waiting_receipt') { $photo = $message['photo']; $fileId = end($photo)['file_id']; $orderId = $stateData['order_id']; $bot->updateOrderReceipt($orderId, $fileId); $bot->updateOrderStatus($orderId, 'waiting_payment'); // Уведомляем админа $order = $bot->getOrder($orderId); $orderDisplay = isset($order['order_number']) ? $order['order_number'] : "№{$orderId}"; $adminMessage = "🆕 Новый чек загружен!\n\n"; $adminMessage .= "📋 Заказ {$orderDisplay}\n"; $adminMessage .= "👤 Пользователь: " . ($username ? "@{$username}" : $firstName) . "\n"; $adminMessage .= "💰 Сумма: {$order['rub_amount']} ₽\n"; $adminMessage .= "₿ BTC: {$order['btc_amount']}\n"; $adminMessage .= "📍 Адрес: {$order['btc_address']}\n"; $adminMessage .= "💳 Способ: {$order['payment_method']}\n"; $adminMessage .= "🕐 Время: " . date('d.m.Y H:i') . "\n\n"; // Для главного админа добавляем кнопки $adminMessageWithButtons = $adminMessage . "⚡ Выберите действие:"; $keyboard = $bot->getAdminOrderMenu($orderId); // Отправляем главному админу с кнопками $bot->sendPhoto(ADMIN_ID, $fileId, $adminMessageWithButtons, $keyboard); // Отправляем в группу без кнопок if (defined('ENABLE_GROUP_NOTIFICATIONS') && ENABLE_GROUP_NOTIFICATIONS && defined('NOTIFICATIONS_CHAT_ID')) { $groupMessage = $adminMessage . "ℹ️ Для обработки используйте личный чат с ботом"; $bot->sendPhoto(NOTIFICATIONS_CHAT_ID, $fileId, $groupMessage); } $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, "✅ Чек загружен!\n\n🔍 Заказ отправлен на проверку администратору.\n⏰ Ожидайте подтверждения и отправки BTC на ваш адрес.", $keyboard); $bot->clearState($userId); } else { $keyboard = [[['text' => '🔙 Главное меню', 'callback_data' => 'main_menu']]]; $bot->sendMessage($chatId, "❌ Фото не ожидается в данный момент.", $keyboard); } } // Основной обработчик webhook try { error_log("=== WEBHOOK START ==="); $bot = new TelegramBot(BOT_TOKEN); $input = file_get_contents('php://input'); error_log("Raw input: " . $input); $update = json_decode($input, true); if (!$update) { error_log("Failed to decode JSON input"); http_response_code(200); exit; } error_log("Update type: " . (isset($update['callback_query']) ? 'callback_query' : (isset($update['message']) ? 'message' : 'unknown'))); // Обработка callback запросов if (isset($update['callback_query'])) { error_log("Processing callback query"); handleCallbackQuery($bot, $update['callback_query']); } // Обработка обычных сообщений elseif (isset($update['message'])) { error_log("Processing message"); $message = $update['message']; // Обработка фото if (isset($message['photo'])) { error_log("Processing photo"); handlePhoto($bot, $message); } // Обработка текстовых сообщений elseif (isset($message['text'])) { error_log("Processing text: " . $message['text']); handleTextMessage($bot, $message); } } error_log("=== WEBHOOK END ==="); http_response_code(200); } catch (Exception $e) { error_log("=== WEBHOOK ERROR ==="); error_log("Webhook error: " . $e->getMessage()); error_log("File: " . $e->getFile() . " Line: " . $e->getLine()); error_log("Stack trace: " . $e->getTraceAsString()); http_response_code(200); // Всегда отвечаем 200, чтобы Telegram не повторял запросы } ?>