From 34b2880a68717c500abbeea52af07595dfadd1e2 Mon Sep 17 00:00:00 2001 From: grigorij Date: Sat, 13 Jun 2026 19:34:57 +0400 Subject: [PATCH 1/4] init --- .DS_Store | Bin 0 -> 6148 bytes app/.DS_Store | Bin 0 -> 8196 bytes app/__pycache__/config.cpython-314.pyc | Bin 0 -> 407 bytes app/__pycache__/main.cpython-314.pyc | Bin 0 -> 1483 bytes app/db/__pycache__/memory.cpython-314.pyc | Bin 0 -> 193 bytes app/handlers/__pycache__/about.cpython-314.pyc | Bin 0 -> 1026 bytes app/handlers/__pycache__/booking.cpython-314.pyc | Bin 0 -> 6033 bytes .../__pycache__/contacts.cpython-314.pyc | Bin 0 -> 1037 bytes .../__pycache__/mybookings.cpython-314.pyc | Bin 0 -> 1691 bytes app/handlers/__pycache__/profile.cpython-314.pyc | Bin 0 -> 1401 bytes app/handlers/__pycache__/start.cpython-314.pyc | Bin 0 -> 1161 bytes app/keyboards/__pycache__/menu.cpython-314.pyc | Bin 0 -> 724 bytes app/keyboards/calendar.py | 0 app/keyboards/confirm_booking.py | 0 app/keyboards/services.py | 0 app/keyboards/time_slots.py | 0 .../__pycache__/booking_service.cpython-314.pyc | Bin 0 -> 730 bytes app/states/__pycache__/booking.cpython-314.pyc | Bin 0 -> 563 bytes 18 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 .DS_Store create mode 100644 app/.DS_Store create mode 100644 app/__pycache__/config.cpython-314.pyc create mode 100644 app/__pycache__/main.cpython-314.pyc create mode 100644 app/db/__pycache__/memory.cpython-314.pyc create mode 100644 app/handlers/__pycache__/about.cpython-314.pyc create mode 100644 app/handlers/__pycache__/booking.cpython-314.pyc create mode 100644 app/handlers/__pycache__/contacts.cpython-314.pyc create mode 100644 app/handlers/__pycache__/mybookings.cpython-314.pyc create mode 100644 app/handlers/__pycache__/profile.cpython-314.pyc create mode 100644 app/handlers/__pycache__/start.cpython-314.pyc create mode 100644 app/keyboards/__pycache__/menu.cpython-314.pyc create mode 100644 app/keyboards/calendar.py create mode 100644 app/keyboards/confirm_booking.py create mode 100644 app/keyboards/services.py create mode 100644 app/keyboards/time_slots.py create mode 100644 app/services/__pycache__/booking_service.cpython-314.pyc create mode 100644 app/states/__pycache__/booking.cpython-314.pyc diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7cdad9aa1944075e4ec265c609b915675edcb421 GIT binary patch literal 6148 zcmeHKPfrs;6n|5yY(Zp!7BOnFp%)VxtQauHgUf<3!~=vSSOQpf+oi5-XX@^jf`p`J z{Q!OdKY)oRkNN@h=+%Q?z>8;m^QVD=UX_@A$;|J~y!U42{dRU|2LOoGtlkFD0YJmT zG2MsNZ-m=j`bhI-3CxQ)P%;$rbDN%f>JT8}qT45}3JG$ep`d+K7 zXXhA=9iMuk2=J>Ox@@k}RIy;p z6pM$487-H;b$_|M6VxetB}pgvO%gJoumi7AQQ7#FU6l>_+{xyfu6Odu^z~mFxICy2 z4UY_EhjO{x=#{an!`H5t^%2*p?9@WO&N&va&i6nY+AuZ4bfaeF)R;?fCyjn7sISr9C-$d7$S*EYoL zu~%Q9+YD#qD_CrBQ?%-Z5#pJc(wY;74y}3C{$}8~Ua&|l7RRh!@-Yj(axtada4J5n zMtn%pHOnI+3)ooo?@JeTpQ&Lh5|##2BdRMaEhwL=;(TEiah z-3xWx?mkeM#7)0{YSX_*kCU5ThY&nmTN5L=R>wjih6tl$*n_w`o{XQ0$L9GJMV{7w zewUc6EMXvF;2$x-zYhi$j;6x4MDgjsDuqpMPjlpgy7>7=G*sJE*p`SE6e2?rWhhZs z45IE1M24f?RQ_#=G8~AQ8OKpG6Lmu&>gquZ;SR)^vI^p&;N&izW;Xz zC9Q;kgn|Ex0g|4#=PgW0ovmk*<7cgbWeW=z?$?$mLakuW#AXx67B{7 literal 0 HcmV?d00001 diff --git a/app/.DS_Store b/app/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..fb7bc82e89ef1200559cecce2d6c244fd5599509 GIT binary patch literal 8196 zcmeHMPfrs;6n_HIcxHR}X#xFP`zup8{KNg6UK*rHweUEC@c=%QUjuq$WicsuR-X4ewCF+Vn zWH{O_?v9vMSdl2hfyi(mYGk5rC`62oah7lgl9i}y&46a0kpaHkM;_JyFv)7}MVGN|$SQ0HU78rayY3juf#LR9Nd`s@4?u#SE^;NV!RZw)3$aZ$>#gT;!i-84H}MZaZ_n zw_Pxkj6}ig+ua=*zB6bIk7o7;t=)UW znL%qbliAx#7^(EF`!j|0V1u$(xC#`aUS!ZAKOfYuQ9FhUzqqAVM!r;6_T4nAYfD^g zztnNL)9mW*=}LB`QmNi6eOJ4$T`!nDj$K?Yg?!HAEMQ?S*z^i!XM`)CEHXMBdRw^S z`Ph3A=lz#x>aGiz@!Y3}O|v^?^hq8zh)y4co<|o;q3=$uu0~!we?(v4qZLCI1k)_? zW1rE5B{6#JZA{Wth9mMBOqIDQn)AX4u_0!D!45;4mb~1~a$q}NFhz4Lj@ib%kE`G_ z7enUDcG0J$^n;(0&_p_WQ)(ups~j82s-}>nKW$WmK1&((Flbs@(%Hw##ee}AgFGz3 zbEv>ucn9y{Gkk>~@C)`y2k9mKWPl8k5ptJg$rza-i)4k^aH{cnt`*%0BM=XPw*pt^^8(KL4Lxpu&iL=!u=`|MF>{hg}00A nIO4${hNxT0mQ`4hh!&K8{zHI13geaT%pQgH{x7oP?^nM8A*(>C literal 0 HcmV?d00001 diff --git a/app/__pycache__/config.cpython-314.pyc b/app/__pycache__/config.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..108a69f3e9ab3964ecae9b124582939cb757c45f GIT binary patch literal 407 zcmdPq_P-S&M-5V-N=hn4yf%IY34OLmWd8qbEZNh-UI+^k6Dsl4pozQe-fJ zDg*Ku0@z@h5ws#h5VHv*gkQoE%c2gIO6O!?kYR{r1m)FGTZlX-=wL5f9KT zkZ+5PfW!x8Mn=Zl44iiv`?%nkmjqjX#(~LuC4rrLdA0%k6j$USK;~ z$H-S8j(I3}YXB4iJ~a<_Jg)(Tpzrl}Wst{YI^=uneWA(6^?jegbXDT)|1!hpju|~S zv+dl>_S4Klm+#AyhTZr0{(ArT9Z7}_r zT0LR6)t3KZgylJ`6rbN((ltviS*Gs@8cfwJCvv=sp;xOIo!8$S)?c7(n7nKf31=wt z$W)k_sW7#oGj$;|y3kt?V+nU!k&&Rw2S21H*OX$>5!jOU9*%GX zSSO#`bg!nDm#WGLyNV|NUzl0^914Vx&k+3%$pc6nz`#BXx$nq6$HTwHC`lY%0UCa_ cVha~{Y0Jy;wedIft@w%d{1Sl1SQ5kh1*vaE{Qv*} literal 0 HcmV?d00001 diff --git a/app/db/__pycache__/memory.cpython-314.pyc b/app/db/__pycache__/memory.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5af35a3bb2b270f69f603764cacd4e5dc468e828 GIT binary patch literal 193 zcmdPq^Md_YD6gFZtEgC0W(V-SNfgC?V&Cetm}(&E&j z;#(X^`T5zIdFjO~89sxw+_KXT1xe_q7iFgB7iDJY2UI3!Bo^fc6y;~7CYKZg`6U_o zc~Gu?VnKm^N|JtVYHof}rCvehEe@O9{FKt1RJ$T}pm88)6!Qa#56p~=j5j#A8dz^| L^EPo5u>!>aPi8V% literal 0 HcmV?d00001 diff --git a/app/handlers/__pycache__/about.cpython-314.pyc b/app/handlers/__pycache__/about.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bc0abd02f92577e898a1cfa48da53cdbab8ca51 GIT binary patch literal 1026 zcmZWn-%C?*6hGhlb1r{YFqLvsL0Hn(gPDw4gkTd?)|Gro9k=beDckP&-aFE_Wm1@g z)k6|UJqJPdlu6mYaLotdf~5B3Q`&;)t@FL^D%64R`JQvW-}B>h&grbJ@dDC^wcykp z0`Q$FE(sN({1}B2jDte@Ax2CR<4n%abgrL|38vu4e7_izOvw*pq!qdWM zm0$$Mxt=+I6xzZt08e=u zSsVCS14!I$4cc6Chj9}Wm_n~%FzUF&j8|{rurx>B-*9SsW%#Urc5-mD-Y;H|}W^8(oE- zl&!PDfOT}xYP@XG=@ez_CbPFNvVBCillobOz?xFz^3!MEdWSPadFtfp(5-sqMP z{VGHcMGzZzh3Frn5q)OQM#u}&Ei5%g$UD*_tjH0vN+M(^c*>U5Nj*)~9A)^afXuF` zm_p`EK{K2su+O-*2_qLu9xbS|8MZ{7O?DvI0$W_C;5R^PSwshj=W0$*6|-8DHldA8 z#)u$0;0Yn$;QThUZo`G$s=9^7lC(qQM=keTo{}Z$nPfG0Z`5~hk}JPB+<-CzkAN>s;p2L(zC}p55DeV>~AEP$(m;t*NTiyu;*Ar7-0QE zQs@_x;%bt`0ZYG>lsIo0u=dMIne)2!sbKW}O=vR^o=j8!szbonDyltSOzcN|b zUzMy{&GrhdY-4`9qCG6b~D9 zo9)TE|750!vrL-{+A7Ml)vut<-pckW;qK!4OwL@HSw=ifLMO ze+;a$+c7eVt`J?@6Ny73@%_9Oa^;X3L;K*qTs726W3hND z;~a{{hhn3HB&1-pOrJ3(^^f&S`X~DI5Pj|Z7iSW93-Tfz)CAkjo)fnmV{908UiP$b zK!^x?(2`3LaS!Y~mx5v&yI}c}g3d*CgJ`sf_I9-vMMln9h}sOHk{TZa`4Zc|sZ>pMo#;BbJ}r54 z$uqB1PX$f{=Ivdd*EeLX%-OKWEKd1rX0gg&5m~S>>#7A2+&#?;9g}t2nDD0Xh;*g} z%q8Jb>9P&Xi~w@C0UfgMy#Di&t?ARor12`YIQ8AxrCNb`)M^mFpw^(s*&g3Hw-ruk zF$IHhlEHwS_hhNK*vKWd9(|TKn7^Xszcd(OIfE&hOPKD>l4Rn_{RRZ{b1dl$5$4BV zEo%7|=C>2(*MY3$O)&K|#_6vaC-vXymy8LR;G}-ZXB;(-=vR%S`iI8Rtx9jer=P>u zJA%q-{j$;*@I4dWrffj34srgMT49N1fsYI2t;weMH5VM2;2eK%UN`Q zMXWy*#zoi`8keTs;=`yK#@F$#2!18@Dwe}#1n&kQ*7Tf8lrKM9#IiXL$FTh+x}e8a zq9D)iA$#H}T(|>fP0`m`M%(g0E`9S}aBD`9`;ps_UHk^gY71t(OE2f`x8D8Nl_{V8 z9zDIraa@(F`m|5~1DM~_-7;Ru-!5KNK>I7`cEv|y_zPfm>L_^zraN{4-qv7_6g}Sh zYot)WXsWx&k@cwW!JHDh#r#T6`1*PRJrDUWSotDT^c-a0Iep%zzk@zA#xeA}YP_1F zn+2?XlWzG8t%a7%*QZ}ek&)d#_D8<6U;Ffr(Boq?PGhbsXeQXiShN5N^iKc-)A~oi z`ICM*Bav&vZ+XU<8Xu+y93-mJtCxcUi7Ne;;>(qBz=ha1GCUlMYxLH(xBGIhSmn@x zL_&)Vn%F@ehNba-+X2LRQyDI-gR)%B33D1 zGtr@Bi7d#>Q3cdUD@}&d^zM`I?|g5kt~AXly=kdemwHP8rORmSnp3*dQnxO3=K*Ej zz7+}yL_`7+kcC>(sxWKcEvb7!Ld`wx2`p{0b9<}sfv~+n`t3S!vo*r@CTX^|o%n}^ z?ak8c)>YuIp?%hrh4{ zC~QNC`12#`m|rSlh1x~E2|}V8J#D~>JXkpMU_t1j_Ms_+to;e(e?|(=``-7w94P{6 zDWFS%o7E4TX*u08SKXR+woW`=0vyYEBJ;|svvp@j-d?S*@@JXQSwCOjaJK!8J*Rd- zYI|JBT13Ya!lFeYY>^0CKo&fCYzf|SwsJ=WmG`tCV?UFfAvfS9Bm-W+0bW9Oz>A0Y zP9da7vt8}ruT={nmvpUWJ@JnTp-SmGvw^>E7lbPds6es9JW9ZBq0qhl)Br%L9KsmNCal847*8vpT>sWt1K*Tw=ke(rG+ zFl4F_5zkIppiN9zM(aPzs3lCp&mP&3bw_*M)spQS8WF;3E$G4oXYky=cF`OEW zJ*tM#L@|-}Pmrud5QHyS^9|N|gLU3u9sgimH`wMcSkEm-)yY*8a@Nj7`|*||EvJMt z@@e^u>$L0j%69{XyJt@5y(8l9*rJ7reOcnNHD!JE#!ZHM)12_o9TERTsN3c&aoLu9 zx6{tEJJa4C!`n0G?wu3*?uZC6so#byaoLS!{ni`a^>gmPoDjSt!e^v@Jz3(ikCgQ* P)d#5O`o0pu@zeM>2mtau literal 0 HcmV?d00001 diff --git a/app/handlers/__pycache__/contacts.cpython-314.pyc b/app/handlers/__pycache__/contacts.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60424dc5668dc8ac2ae05529d324f20b582cc912 GIT binary patch literal 1037 zcmZV+?@JS5_<8Scck}XRKiG`YsUWP;mSv?w`p`mWsH}_pq>f{ro8orky&LJbX+fBj zMUW9vpMxOjQwT|a!Yw}t2a?t&ziA7iZ$0mAr%(?(Ki~KH{e0I8k5MSX1Sn(>;>09z&g5E|&JFT$!4w>sAN0gUQ*4EC(gxjCS5q375>0NvV?NF$ zP9AHnqzFB6fNrdVf#UIjBKlyq@hFh=S*$RES$lw2X9}z30SYKP3v=M(OS1QN{glC6iZW01*}ybv3vv;$; ziMDfahh&IC#_**A3OB~Na)iTz_9kI#XCjIDR7R!Q1l4D>lxd)DX7pTDji~v2B%|ggXPHk5TT}5*I6rUK zCX;F|r?Y&?B(1~PUPPk>NfCYnPi~Pzhpr7AIQ;$XieAPakUHuE71sX)#PS@Hc4%dD zAPILuXmi0`#{eiWgI;r_$PamB^caN%i}DXB#9itC9tw1T1VgQe-mCmH334NaPV~o> zJqcKA)@EtJ+OR%a>+<(kPXnRrf!^NUDk8%h@T6unmD-}3Gwy2?XI_KelpVFfn(OSO zwa9F*J2cAfPGZjyB>ULpuH3K^S_&;++!lP6;MDhRtNG@Z9NQLRUxnDA2R!~g zA@;}cqtD{$D0xY)39J4n`9OMvbty_dkti7np0Fi#T2E6oOW7ExfW)q=n!@IMUNfAN zuur+RDI*(ZmEom2cVdgwIccX0TX5{G;CDdlS;R^&eOZ07Fst35&1ho_GWw7l@Pv?W zaDE5ccHqKZO~bOkDDD#JQOiQhGqNf^7p=2hrN*u;a`_j>4x`Kicjc!eI??|Ewrk~O literal 0 HcmV?d00001 diff --git a/app/handlers/__pycache__/mybookings.cpython-314.pyc b/app/handlers/__pycache__/mybookings.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9d55276f3c698679fbf94353f14dd707aff54155 GIT binary patch literal 1691 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 Xt_EIqd?t}S4x6^g0~h_xkjwlRm;3_d literal 0 HcmV?d00001 diff --git a/app/keyboards/__pycache__/menu.cpython-314.pyc b/app/keyboards/__pycache__/menu.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b27d2bda3212ff9a44ef114dd5a18157c981e5ac GIT binary patch literal 724 zcmY*X&1=(O7=Pa+tx21FPW= z7$T^MYzQKF>qU%noBzTa$i-Y_dh%q-`~!TFwyQpem*@BVKAwk=^Vv)aLEU_OuKJci z=w}25CG?xa_t3P^0#flUG>dIK%h=3mG><3HJTrk*MrDh*ryB+34JQxUaQpcaiN2&A`jxug8tr&(Z^K*jHVZi5Z2f`ljKr#E?>x*UtMX7^91I*0d~^%syYwSOb?z1tK}M?>Wunz(yJ_kcVL?JT zcml4jH=H0{(i$bbwitmA=nx1L+)(aYI2)m z7?m#h;^l8qGv$j{!vrg&x+#&2QevZ|+&`D}eIxn?1G&z%L!tVpPuZ zHaZ0y11Hbn8Og~OaH9j9cHnd)H#pk`yK%0;Hc{qDn!b&aq4cpF=%b~HhvHf8p(xwqE&>PBaR0UkX8oBvft4~iB+I-n9&DU3Da)}`DHNF-T zosyxa=oG+_BTfc{8v}z=&K#D}ONRRY_^F=*Y{P&)sQBJOUw?|wyo;7ry1r^koOU8r z)ARG_4A~O8C5BlRCV|cV$G7UwWC-hayLZI8##_D!_14v`xP{4b_xtD+@YB3LdpKVy zYsTj0#_aB5t#Pec?EkT#(f)Aw?r^sMoo&vq-Y5=)g^vzws@gb3FF5JNVVsI-Iayix kGn9~3YjZD7gUM<5Sak52URP@77nBh419mPLQeDFT0!$;E(f|Me literal 0 HcmV?d00001 diff --git a/app/states/__pycache__/booking.cpython-314.pyc b/app/states/__pycache__/booking.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2dfd4f0a751b4dc4b22d41aea8322a8e9c42dd81 GIT binary patch literal 563 zcmY*VJx{|h5IrX;Ewp^86h>4rMWBYE5(5Y!Kx$bK3Sul)2qCyMaj{*bZXFN{3;Yab zCVmQD7?{|QikP{4bik7D-jnaWyYu?o>C#Of)Dz-kP<(u%%YK#@g9N^bU+ao zlyPn?AMX5`2 z5H&^AjFW-&fpdmZ>4buXT(GWlGW4%K5uFI$4SXe$t7{(T)baX#Cov49bCHeT=nusd zI;A1`TDgMZ0p91TkKw5GUS4?I8XczWz9kkWmB+TF7d^&9;YE!r88uQ@kr<>KWuD2L mnPw4@F70HWvMZ`c30}E`;oBsHe8A?9Ws>Em?O(u@s{R0{Ad33{ literal 0 HcmV?d00001 From 9282c1bbfb7f0ab65599774b4ed2d7e46d434572 Mon Sep 17 00:00:00 2001 From: grigorij Date: Sat, 13 Jun 2026 19:51:11 +0400 Subject: [PATCH 2/4] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=BE=D1=86=D0=B5=D0=BD=D0=BD?= =?UTF-8?q?=D1=8B=D0=B9=20=D1=81=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8=D0=B9?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - выбор услуги через inline-кнопки - выбор даты через календарь - выбор времени через кнопки - подтверждение записи - отмена записи - редактирование записи - сохранение времени записи - исправлена работа FSM - исправлены callback-обработчики - улучшен интерфейс бота --- app/handlers/booking.py | 215 +++++++++++++++++++++---------- app/handlers/mybookings.py | 6 +- app/keyboards/calendar.py | 24 ++++ app/keyboards/confirm_booking.py | 28 ++++ app/keyboards/services.py | 28 ++++ app/keyboards/time_slots.py | 30 +++++ app/services/booking_service.py | 10 +- app/states/booking.py | 1 + 8 files changed, 274 insertions(+), 68 deletions(-) diff --git a/app/handlers/booking.py b/app/handlers/booking.py index f2afef0..cc08d39 100644 --- a/app/handlers/booking.py +++ b/app/handlers/booking.py @@ -1,11 +1,17 @@ +import re + from aiogram import Router, F -from aiogram.types import Message from aiogram.fsm.context import FSMContext from aiogram.filters import StateFilter +from aiogram.types import Message, CallbackQuery +from app.keyboards.services import get_services_keyboard from app.states.booking import BookingState from app.services.booking_service import create_booking from app.keyboards.menu import menu, cancel_menu +from app.keyboards.calendar import get_dates_keyboard +from app.keyboards.time_slots import get_time_keyboard +from app.keyboards.confirm_booking import get_confirm_booking_keyboard router = Router() @@ -28,95 +34,172 @@ async def start_booking(message: Message, state: FSMContext): await state.set_state(BookingState.service) await message.answer( - "Выберите услугу:\n" - "1. Массаж\n" - "2. SPA\n" - "3. Косметология", - reply_markup=cancel_menu + "Выберите услугу:", + reply_markup=get_services_keyboard() ) -# выбор услуги -@router.message(StateFilter(BookingState.service)) -async def choose_service(message: Message, state: FSMContext): +@router.callback_query( + StateFilter(BookingState.service), + F.data.startswith("service_") +) +async def choose_service( + callback: CallbackQuery, + state: FSMContext +): + services = { + "service_massage": "Массаж", + "service_spa": "SPA", + "service_cosmetology": "Косметология" + } - forbidden = [ - "📅 Записаться", - "👤 Профиль", - "📖 Мои записи", - "ℹ️ О компании", - "📞 Контакты" - ] + service_name = services[callback.data] - if message.text in forbidden: - await message.answer( - "⚠️ Сначала завершите запись или напишите 'отмена'" - ) - return - - await state.update_data(service=message.text) - - await state.set_state(BookingState.date) - - await message.answer( - "Введите дату (например 20.06)" + await state.update_data( + service=service_name ) + await state.set_state( + BookingState.date + ) + await callback.message.edit_text( + "📅 Выберите дату:", + reply_markup=get_dates_keyboard() + ) + + await callback.answer() + # выбор даты -@router.message(StateFilter(BookingState.date)) -async def choose_date(message: Message, state: FSMContext): +@router.callback_query( + StateFilter(BookingState.date), + F.data.startswith("date_") +) +async def choose_date( + callback: CallbackQuery, + state: FSMContext +): + selected_date = callback.data.replace( + "date_", + "" + ) - forbidden = [ - "📅 Записаться", - "👤 Профиль", - "📖 Мои записи", - "ℹ️ О компании", - "📞 Контакты" - ] + await state.update_data( + date=selected_date + ) - if message.text in forbidden: - await message.answer( - "⚠️ Сначала завершите запись или напишите 'отмена'" - ) - return + await state.set_state( + BookingState.time + ) - await state.update_data(date=message.text) + await callback.message.edit_text( + "🕒 Выберите время:", + reply_markup=get_time_keyboard() + ) + + await callback.answer() + + +@router.callback_query( + StateFilter(BookingState.time), + F.data.startswith("time_") +) +async def choose_time( + callback: CallbackQuery, + state: FSMContext +): + selected_time = callback.data.replace( + "time_", + "" + ) + + await state.update_data( + time=selected_time + ) data = await state.get_data() - await state.set_state(BookingState.confirm) - - await message.answer( - f"Услуга: {data['service']}\n" - f"Дата: {data['date']}\n\n" - f"Напишите 'да' для подтверждения" + await state.set_state( + BookingState.confirm ) + await callback.message.edit_text( + f"📋 Проверьте запись:\n\n" + f"💆 Услуга: {data['service']}\n" + f"📅 Дата: {data['date']}\n" + f"🕒 Время: {selected_time}", + reply_markup=get_confirm_booking_keyboard() + ) + + await callback.answer() + # подтверждение -@router.message(StateFilter(BookingState.confirm)) -async def confirm_booking(message: Message, state: FSMContext): - - if message.text.lower() != "да": - await state.clear() - - await message.answer( - "❌ Запись отменена", - reply_markup=menu - ) - +@router.callback_query( + StateFilter(BookingState.confirm), + F.data == "confirm_booking" +) +async def confirm_booking_callback( + callback: CallbackQuery, + state: FSMContext +): data = await state.get_data() create_booking( - user_id=message.from_user.id, + user_id=callback.from_user.id, service=data["service"], - date=data["date"] + date=data["date"], + time=data["time"] ) await state.clear() - await message.answer( - "✅ Вы успешно записаны!", - reply_markup=menu - ) \ No newline at end of file + await callback.message.edit_text( + "✅ Запись успешно создана" + ) + await callback.answer() + + +@router.callback_query( + StateFilter(BookingState.confirm), + F.data == "cancel_booking" +) +async def cancel_booking_callback( + callback: CallbackQuery, + state: FSMContext +): + await state.clear() + + await callback.message.edit_text( + "❌ Запись отменена" + ) + + await callback.answer() + + +@router.callback_query( + StateFilter(BookingState.confirm), + F.data == "edit_booking" +) +async def edit_booking_callback( + callback: CallbackQuery, + state: FSMContext +): + old_data = await state.get_data() + + await state.clear() + + await state.update_data( + service=old_data.get("service") + ) + + await state.set_state( + BookingState.service + ) + + from app.keyboards.services import get_services_keyboard + + await callback.message.edit_text( + "Выберите услугу:", + reply_markup=get_services_keyboard() + ) diff --git a/app/handlers/mybookings.py b/app/handlers/mybookings.py index cf560f3..13bc8a8 100644 --- a/app/handlers/mybookings.py +++ b/app/handlers/mybookings.py @@ -23,6 +23,10 @@ async def my_bookings(message: Message, state: FSMContext): text = "📖 Ваши записи:\n\n" for b in user_bookings: - text += f"💆 {b['service']} — 📅 {b['date']}\n" + text += ( + f"💆 {b['service']}\n" + f"📅 {b['date']}\n" + f"🕒 {b['time']}\n\n" + ) await message.answer(text) \ No newline at end of file diff --git a/app/keyboards/calendar.py b/app/keyboards/calendar.py index e69de29..1e02289 100644 --- a/app/keyboards/calendar.py +++ b/app/keyboards/calendar.py @@ -0,0 +1,24 @@ +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from datetime import datetime, timedelta + + +def get_dates_keyboard(): + buttons = [] + + today = datetime.now() + + for i in range(7): + day = today + timedelta(days=i) + + buttons.append( + [ + InlineKeyboardButton( + text=day.strftime("%d.%m"), + callback_data=f"date_{day.strftime('%d.%m')}" + ) + ] + ) + + return InlineKeyboardMarkup( + inline_keyboard=buttons + ) \ No newline at end of file diff --git a/app/keyboards/confirm_booking.py b/app/keyboards/confirm_booking.py index e69de29..8f7a28a 100644 --- a/app/keyboards/confirm_booking.py +++ b/app/keyboards/confirm_booking.py @@ -0,0 +1,28 @@ +from aiogram.types import InlineKeyboardMarkup +from aiogram.types import InlineKeyboardButton + + +def get_confirm_booking_keyboard(): + + return InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="✅ Подтвердить", + callback_data="confirm_booking" + ) + ], + [ + InlineKeyboardButton( + text="✏️ Изменить", + callback_data="edit_booking" + ) + ], + [ + InlineKeyboardButton( + text="❌ Отменить", + callback_data="cancel_booking" + ) + ] + ] + ) \ No newline at end of file diff --git a/app/keyboards/services.py b/app/keyboards/services.py index e69de29..813ffbc 100644 --- a/app/keyboards/services.py +++ b/app/keyboards/services.py @@ -0,0 +1,28 @@ +from aiogram.types import InlineKeyboardMarkup +from aiogram.types import InlineKeyboardButton + + +def get_services_keyboard(): + + return InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="💆 Массаж", + callback_data="service_massage" + ) + ], + [ + InlineKeyboardButton( + text="🌿 SPA", + callback_data="service_spa" + ) + ], + [ + InlineKeyboardButton( + text="✨ Косметология", + callback_data="service_cosmetology" + ) + ] + ] + ) \ No newline at end of file diff --git a/app/keyboards/time_slots.py b/app/keyboards/time_slots.py index e69de29..9dc16e1 100644 --- a/app/keyboards/time_slots.py +++ b/app/keyboards/time_slots.py @@ -0,0 +1,30 @@ +from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton + + +def get_time_keyboard(): + + times = [ + "10:00", + "11:00", + "12:00", + "13:00", + "14:00", + "15:00", + "16:00" + ] + + buttons = [] + + for t in times: + buttons.append( + [ + InlineKeyboardButton( + text=t, + callback_data=f"time_{t}" + ) + ] + ) + + return InlineKeyboardMarkup( + inline_keyboard=buttons + ) \ No newline at end of file diff --git a/app/services/booking_service.py b/app/services/booking_service.py index fe182df..938ace9 100644 --- a/app/services/booking_service.py +++ b/app/services/booking_service.py @@ -1,12 +1,20 @@ from app.db.memory import bookings -def create_booking(user_id: int, service: str, date: str): + +def create_booking( + user_id: int, + service: str, + date: str, + time: str +): booking = { "user_id": user_id, "service": service, "date": date, + "time": time, "status": "active" } bookings.append(booking) + return booking \ No newline at end of file diff --git a/app/states/booking.py b/app/states/booking.py index 12e607a..9b31367 100644 --- a/app/states/booking.py +++ b/app/states/booking.py @@ -3,4 +3,5 @@ from aiogram.fsm.state import StatesGroup, State class BookingState(StatesGroup): service = State() date = State() + time = State() confirm = State() \ No newline at end of file From 8d95ad393147fa6452bc3afa2604313302a6f920 Mon Sep 17 00:00:00 2001 From: grigorij Date: Sat, 13 Jun 2026 20:01:26 +0400 Subject: [PATCH 3/4] =?UTF-8?q?-=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=20=D0=BC=D0=B0=D1=81=D1=82?= =?UTF-8?q?=D0=B5=D1=80=D0=B0;=20-=D1=80=D0=B0=D1=81=D1=88=D0=B8=D1=80?= =?UTF-8?q?=D0=B8=D0=BB=20FSM=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=BC=20=D1=81?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D0=B5=D0=BC=20master?= =?UTF-8?q?;=20-=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D1=83=D1=8E=20=D0=BA=D0=BB=D0=B0=D0=B2=D0=B8=D0=B0=D1=82?= =?UTF-8?q?=D1=83=D1=80=D1=83=20masters.py;=20-=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=BB=20=D1=81=D1=86=D0=B5=D0=BD=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8;=20-=D0=B4=D0=BE?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=BB=20=D0=BE=D0=BA=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=BF=D0=BE=D0=B4=D1=82=D0=B2=D0=B5=D1=80=D0=B6=D0=B4?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D0=B8?= =?UTF-8?q?;=20-=D1=80=D0=B0=D1=81=D1=88=D0=B8=D1=80=D0=B8=D0=BB=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=83=20=D1=85=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B1=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B9.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/handlers/booking.py | 37 ++++++++++++++++++++++++++++++++- app/keyboards/masters.py | 28 +++++++++++++++++++++++++ app/services/booking_service.py | 2 ++ app/states/booking.py | 1 + 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 app/keyboards/masters.py diff --git a/app/handlers/booking.py b/app/handlers/booking.py index cc08d39..eae1d1f 100644 --- a/app/handlers/booking.py +++ b/app/handlers/booking.py @@ -5,7 +5,7 @@ from aiogram.fsm.context import FSMContext from aiogram.filters import StateFilter from aiogram.types import Message, CallbackQuery from app.keyboards.services import get_services_keyboard - +from app.keyboards.masters import get_masters_keyboard from app.states.booking import BookingState from app.services.booking_service import create_booking from app.keyboards.menu import menu, cancel_menu @@ -59,9 +59,42 @@ async def choose_service( service=service_name ) + await state.set_state( + BookingState.master + ) + await callback.message.edit_text( + "👤 Выберите специалиста:", + reply_markup=get_masters_keyboard() + ) + + await callback.answer() + +#выбор мастера +@router.callback_query( + StateFilter(BookingState.master), + F.data.startswith("master_") +) +async def choose_master( + callback: CallbackQuery, + state: FSMContext +): + + masters = { + "master_anna": "Анна", + "master_maria": "Мария", + "master_alex": "Алексей" + } + + master_name = masters[callback.data] + + await state.update_data( + master=master_name + ) + await state.set_state( BookingState.date ) + await callback.message.edit_text( "📅 Выберите дату:", reply_markup=get_dates_keyboard() @@ -127,6 +160,7 @@ async def choose_time( f"📋 Проверьте запись:\n\n" f"💆 Услуга: {data['service']}\n" f"📅 Дата: {data['date']}\n" + f"👤 Мастер:{data['master']}\n" f"🕒 Время: {selected_time}", reply_markup=get_confirm_booking_keyboard() ) @@ -149,6 +183,7 @@ async def confirm_booking_callback( user_id=callback.from_user.id, service=data["service"], date=data["date"], + master=data["master"], time=data["time"] ) diff --git a/app/keyboards/masters.py b/app/keyboards/masters.py new file mode 100644 index 0000000..94272f2 --- /dev/null +++ b/app/keyboards/masters.py @@ -0,0 +1,28 @@ +from aiogram.types import InlineKeyboardMarkup +from aiogram.types import InlineKeyboardButton + + +def get_masters_keyboard(): + + return InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="👩 Анна", + callback_data="master_anna" + ) + ], + [ + InlineKeyboardButton( + text="👩 Мария", + callback_data="master_maria" + ) + ], + [ + InlineKeyboardButton( + text="👨 Алексей", + callback_data="master_alex" + ) + ] + ] + ) \ No newline at end of file diff --git a/app/services/booking_service.py b/app/services/booking_service.py index 938ace9..6dbee9a 100644 --- a/app/services/booking_service.py +++ b/app/services/booking_service.py @@ -5,12 +5,14 @@ def create_booking( user_id: int, service: str, date: str, + master:str, time: str ): booking = { "user_id": user_id, "service": service, "date": date, + "master": master, "time": time, "status": "active" } diff --git a/app/states/booking.py b/app/states/booking.py index 9b31367..6b5a03a 100644 --- a/app/states/booking.py +++ b/app/states/booking.py @@ -2,6 +2,7 @@ from aiogram.fsm.state import StatesGroup, State class BookingState(StatesGroup): service = State() + master = State() date = State() time = State() confirm = State() \ No newline at end of file From 8b20de1da5d4df645ff667f336a8b851de9135f7 Mon Sep 17 00:00:00 2001 From: grigorij Date: Sat, 13 Jun 2026 20:28:32 +0400 Subject: [PATCH 4/4] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D1=81=D0=B8=D1=81=D1=82=D0=B5=D0=BC=D0=B0=20?= =?UTF-8?q?=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BF=D0=B8=D1=81=D1=8F=D0=BC=D0=B8=20=D0=B8=20?= =?UTF-8?q?=D1=83=D0=BB=D1=83=D1=87=D1=88=D0=B5=D0=BD=20=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=86=D0=B5=D1=81=D1=81=20=D0=B1=D1=80=D0=BE=D0=BD=D0=B8=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Реализован выбор мастера - Добавлен выбор даты и времени - Добавлено подтверждение записи - Реализован раздел «Мои записи» - Добавлена отмена записи - Добавлена возможность редактирования записи - Реализована проверка занятых временных слотов - Улучшена логика FSM и пользовательский сценарий бронирования --- app/handlers/booking.py | 51 ++++++++++++--- app/handlers/mybookings.py | 107 ++++++++++++++++++++++++++------ app/keyboards/my_booking.py | 25 ++++++++ app/keyboards/time_slots.py | 23 +++++-- app/main.py | 6 +- app/services/booking_service.py | 82 ++++++++++++++++++++++-- 6 files changed, 252 insertions(+), 42 deletions(-) create mode 100644 app/keyboards/my_booking.py diff --git a/app/handlers/booking.py b/app/handlers/booking.py index eae1d1f..057c212 100644 --- a/app/handlers/booking.py +++ b/app/handlers/booking.py @@ -7,7 +7,11 @@ from aiogram.types import Message, CallbackQuery from app.keyboards.services import get_services_keyboard from app.keyboards.masters import get_masters_keyboard from app.states.booking import BookingState -from app.services.booking_service import create_booking +from app.services.booking_service import ( + create_booking, + update_booking, + get_busy_times +) from app.keyboards.menu import menu, cancel_menu from app.keyboards.calendar import get_dates_keyboard from app.keyboards.time_slots import get_time_keyboard @@ -121,13 +125,22 @@ async def choose_date( date=selected_date ) + data = await state.get_data() + + busy_times = get_busy_times( + master=data["master"], + date=selected_date + ) + await state.set_state( BookingState.time ) await callback.message.edit_text( "🕒 Выберите время:", - reply_markup=get_time_keyboard() + reply_markup=get_time_keyboard( + busy_times + ) ) await callback.answer() @@ -179,18 +192,38 @@ async def confirm_booking_callback( ): data = await state.get_data() - create_booking( - user_id=callback.from_user.id, - service=data["service"], - date=data["date"], - master=data["master"], - time=data["time"] + editing_booking_id = data.get( + "editing_booking_id" ) + if editing_booking_id: + + update_booking( + booking_id=editing_booking_id, + service=data["service"], + master=data["master"], + date=data["date"], + time=data["time"] + ) + + result_text = "✅ Запись успешно обновлена" + + else: + + create_booking( + user_id=callback.from_user.id, + service=data["service"], + master=data["master"], + date=data["date"], + time=data["time"] + ) + + result_text = "✅ Запись успешно создана" + await state.clear() await callback.message.edit_text( - "✅ Запись успешно создана" + result_text ) await callback.answer() diff --git a/app/handlers/mybookings.py b/app/handlers/mybookings.py index 13bc8a8..6f69a63 100644 --- a/app/handlers/mybookings.py +++ b/app/handlers/mybookings.py @@ -1,32 +1,99 @@ from aiogram import Router, F -from aiogram.types import Message +from aiogram.types import ( + Message, + CallbackQuery +) + from aiogram.fsm.context import FSMContext -from app.db.memory import bookings +from app.states.booking import BookingState +from app.keyboards.services import get_services_keyboard + +from app.services.booking_service import ( + get_user_bookings, + cancel_booking, +) + +from app.keyboards.my_booking import ( + get_booking_actions +) router = Router() -@router.message(F.text == "📖 Мои записи") -async def my_bookings(message: Message, state: FSMContext): - await state.clear() - user_id = message.from_user.id +@router.message( + F.text == "📖 Мои записи" +) +async def my_bookings( + message: Message +): + bookings = get_user_bookings( + message.from_user.id + ) - user_bookings = [ - b for b in bookings if b["user_id"] == user_id - ] - - if not user_bookings: - await message.answer("У вас нет записей") + if not bookings: + await message.answer( + "У вас нет активных записей" + ) return - text = "📖 Ваши записи:\n\n" - - for b in user_bookings: - text += ( - f"💆 {b['service']}\n" - f"📅 {b['date']}\n" - f"🕒 {b['time']}\n\n" + for booking in bookings: + await message.answer( + f"💆 {booking['service']}\n" + f"👤 {booking['master']}\n" + f"📅 {booking['date']}\n" + f"🕒 {booking['time']}", + reply_markup=get_booking_actions( + booking["id"] + ) ) - await message.answer(text) \ No newline at end of file + +@router.callback_query( + F.data.startswith( + "cancel_booking_" + ) +) +async def cancel_booking_handler( + callback: CallbackQuery +): + booking_id = int( + callback.data.split("_")[-1] + ) + + cancel_booking( + booking_id + ) + + await callback.message.edit_text( + "❌ Запись отменена" + ) + + await callback.answer() + +@router.callback_query( + F.data.startswith("edit_booking_") +) +async def edit_booking_handler( + callback: CallbackQuery, + state: FSMContext +): + + booking_id = int( + callback.data.split("_")[-1] + ) + + await state.update_data( + editing_booking_id=booking_id + ) + + await state.set_state( + BookingState.service + ) + + await callback.message.edit_text( + "✏️ Выберите новую услугу:", + reply_markup=get_services_keyboard() + ) + + await callback.answer() \ No newline at end of file diff --git a/app/keyboards/my_booking.py b/app/keyboards/my_booking.py new file mode 100644 index 0000000..c161135 --- /dev/null +++ b/app/keyboards/my_booking.py @@ -0,0 +1,25 @@ +from aiogram.types import ( + InlineKeyboardMarkup, + InlineKeyboardButton +) + + +def get_booking_actions( + booking_id: int +): + return InlineKeyboardMarkup( + inline_keyboard=[ + [ + InlineKeyboardButton( + text="✏️ Изменить", + callback_data=f"edit_booking_{booking_id}" + ) + ], + [ + InlineKeyboardButton( + text="❌ Отменить", + callback_data=f"cancel_booking_{booking_id}" + ) + ] + ] + ) \ No newline at end of file diff --git a/app/keyboards/time_slots.py b/app/keyboards/time_slots.py index 9dc16e1..b93663c 100644 --- a/app/keyboards/time_slots.py +++ b/app/keyboards/time_slots.py @@ -1,7 +1,13 @@ -from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from aiogram.types import InlineKeyboardMarkup +from aiogram.types import InlineKeyboardButton -def get_time_keyboard(): +def get_time_keyboard( + busy_times=None +): + + if busy_times is None: + busy_times = [] times = [ "10:00", @@ -10,17 +16,22 @@ def get_time_keyboard(): "13:00", "14:00", "15:00", - "16:00" + "16:00", + "17:00" ] buttons = [] - for t in times: + for time in times: + + if time in busy_times: + continue + buttons.append( [ InlineKeyboardButton( - text=t, - callback_data=f"time_{t}" + text=time, + callback_data=f"time_{time}" ) ] ) diff --git a/app/main.py b/app/main.py index 614b1b3..8ce7621 100644 --- a/app/main.py +++ b/app/main.py @@ -10,7 +10,11 @@ from app.handlers.profile import router as profile_router from app.handlers.mybookings import router as mybooking_router from app.handlers.about import router as about_router from app.handlers.contacts import router as contacts_router - +from app.services.booking_service import ( + create_booking, + update_booking, + get_busy_times +) async def main(): bot = Bot(token=BOT_TOKEN) diff --git a/app/services/booking_service.py b/app/services/booking_service.py index 6dbee9a..fe6de45 100644 --- a/app/services/booking_service.py +++ b/app/services/booking_service.py @@ -2,13 +2,14 @@ from app.db.memory import bookings def create_booking( - user_id: int, - service: str, - date: str, - master:str, - time: str + user_id: int, + service: str, + date: str, + master: str, + time: str ): booking = { + "id": len(bookings) + 1, "user_id": user_id, "service": service, "date": date, @@ -19,4 +20,73 @@ def create_booking( bookings.append(booking) - return booking \ No newline at end of file + return booking + + +def get_busy_times( + master: str, + date: str +): + busy_times = [] + + for booking in bookings: + + if ( + booking["master"] == master + and booking["date"] == date + and booking["status"] == "active" + ): + busy_times.append( + booking["time"] + ) + + return busy_times + + +def get_user_bookings( + user_id: int +): + result = [] + + for booking in bookings: + + if ( + booking["user_id"] == user_id + and booking["status"] == "active" + ): + result.append(booking) + + return result + +def cancel_booking( + booking_id: int +): + + for booking in bookings: + + if booking["id"] == booking_id: + booking["status"] = "cancelled" + return True + + return False + +def update_booking( + booking_id: int, + service: str, + master: str, + date: str, + time: str +): + + for booking in bookings: + + if booking["id"] == booking_id: + + booking["service"] = service + booking["master"] = master + booking["date"] = date + booking["time"] = time + + return booking + + return None