Проблема с aiogram-calendar и FSM

День добрый! Народ, стою на асфальте в лыжах... Понимаю что проблема не в лыжах и не в асфальте, поэтому прошу помощи. Значит так! Telegram бот c применением aiogram. Проблема в чём? Добавил aiogram-calendar + FSM. Всё вроде бы работает пока не до ходит до календаря. При выборе даты или месяца, повторно запускается календарь ( set_date) и на следующий handler не хочет прыгать. Функция process_dialog_calendar отвечает за выбор даты или месяца. Блок if выполняется только если дата выбрана.

class FSMClient(StatesGroup):
    state_master = State()
    state_calendar = State()
#
#
#
async def set_masters(call: types.CallbackQuery):
    await call.message.delete_reply_markup()
    await call.message.delete()
    await call.message.answer(str.GET_MASTERS, reply_markup=keyboards_client.btn_add_masters)
    await FSMClient.state_master.set()


async def set_date(call: types.CallbackQuery):
    await call.message.delete_reply_markup()
    await call.message.delete()
    await call.message.answer(str.SET_DATE, reply_markup=await SimpleCalendar().start_calendar())
    await FSMClient.next() 

    # Здесь функция set_date вызывается повторно снова и снова после каждого нажатия выбора даты. Следующий handler не вызывается.
    

@dp.callback_query_handler(simple_cal_callback.filter())
async def process_dialog_calendar(call: types.CallbackQuery, callback_data: dict):
    selected, date = await SimpleCalendar().process_selection(call, callback_data)
    if selected:
        str.USER_DATE_SELECT = str.USER_DATE + f' {date.strftime("%d.%m.%Y")} \n'
        await call.message.answer(str.USER_DATE_SELECT)


async def set_time(call: types.CallbackQuery):
    await call.message.delete()
    inline_timepicker.init(
        datetime.time(12),
        datetime.time(1),
        datetime.time(23),
    )

    await call.message.answer(text=str.YOUR_TIME,
                              reply_markup=inline_timepicker.get_keyboard())
#
#
#
def register_handlers_client(dp: Dispatcher):
    dp.register_callback_query_handler(set_date, state=FSMClient.state_master)
    dp.register_callback_query_handler(set_time, state=FSMClient.state_calendar)

Если финишировать state в set_date вот так:

async def set_date(call: types.CallbackQuery, state: FSMContext):
    # После финиша state handler выбора даты выполняется.
    await state.finish()       
    await call.message.delete_reply_markup()
    await call.message.delete()
    await call.message.answer(str.SET_DATE, reply_markup=await SimpleCalendar().start_calendar())

следующий handler(process_dialog_calendar) срабатывает, выбираю дату и всё set_time запускаться не хочет. И казалось бы в process_dialog_calendar в блоке if отличное место для установки state(Ну! я так думал).

@dp.callback_query_handler(simple_cal_callback.filter())
async def process_dialog_calendar(call: types.CallbackQuery, callback_data: dict):
    selected, date = await SimpleCalendar().process_selection(call, callback_data)
    if selected:
        str.USER_DATE_SELECT = str.USER_DATE + f' {date.strftime("%d.%m.%Y")} \n'
        await call.message.answer(str.USER_DATE_SELECT)
        # Здесь магия не произошла set_time не сработал.
        await FSMClient.state_calendar.set()

Но нет. У aiogram вместе FSM и aiogram-calendar были другие планы и рога мне запилили быстро. Следующий handler set_time не сработал. Короче ребята, спасайте! Иначе заказчица разорвёт мою тощую задницу на кусочки, а так как это моя жена, мне вдвойне страшно. Надеюсь доступно описал проблему. Извините если что не так. Заранее спасибо! Пример календаря https://github.com/noXplode/aiogram_calendar.

Единственное что приходит в голову выполнить функцию process_dialog_calendarгде-то на стороне и вернуть результат в set_date. Только как это реализовать не могу сообразить. Спасибо!

Ребятушки, разобрался! Полезная функция у FSM имеется reset_state(with_data=False), параметр with_data отвечает за сохранение данных при сбросе состояния. Ну и так, ещё немного на говнокодил и вроде бы всё поехало. Всем спасибо!

По просьбе Vlad Mikliaiev добавляю код:

async def set_master(call: types.CallbackQuery, state: FSMContext):
    await call.message.answer(strings_client.CHECK_MASTER, reply_markup=keyboards_client.btn_add_masters)
    await FSMClient.state_master.set() # Установка состояния.

async def set_date(call: types.CallbackQuery, state: FSMContext):
   await state.update_data(master=call.data) # Запись данных в "state".
    await state.reset_state(with_data=False) # Здесь выполняется сброс "state". Календарь начинает работать.
    await call.message.answer(strings_client.CHECK_DATE, reply_markup=await start_calendar()) # Запуск календаря.

@dp_client.callback_query_handler(calendar_callback.filter()) # "handler" выбора даты либо обновления календаря.
async def select_date(call: types.CallbackQuery, callback_data: dict, state: FSMContext):
    selected, date = await process_selection(call, callback_data)
    if selected:
        await FSMClient.state_calendar.set() # Снова запускаю "state".
        await state.update_data(date=f'{date.strftime("%d.%m.%Y")}') # Запись даты в "state".

Ответы (2 шт):

Автор решения: Vlad Mikliaiev

Расскажите, пожалуйста, подробнее, как получилось разобраться с этим aiogram-calendar и FSM?

→ Ссылка
Автор решения: Creeper Hack

вообще всё фигово)

две хендлеры зарегистрированы внизу. один хендлер - декоратор.

а то что хендлер обрабатывается бесконечно: в классе две State, ты в последнем, и ты пытаешься перейти на следующий НЕ существующий State

вот код который я как то попытался пофиксить

class FSMClient(StatesGroup):
    state_date = State()
    state_process = State()
    state_time = State()



async def set_masters(call: types.CallbackQuery):
    await call.message.delete_reply_markup()
    await call.message.delete()
    await call.message.answer(str.GET_MASTERS, reply_markup=keyboards_client.btn_add_masters)
    await FSMClient.state_date.set()

async def set_date(call: types.CallbackQuery):
    await call.message.delete_reply_markup()
    await call.message.delete()
    await call.message.answer(str.SET_DATE, reply_markup=await SimpleCalendar().start_calendar())
    await FSMClient.next()
    
async def process_dialog_calendar(call: types.CallbackQuery, callback_data: dict):
    selected, date = await SimpleCalendar().process_selection(call, callback_data)
    if selected:
        str.USER_DATE_SELECT = str.USER_DATE + f' {date.strftime("%d.%m.%Y")} \n'
        await call.message.answer(str.USER_DATE_SELECT)
    await FSMClient.next()

async def set_time(call: types.CallbackQuery):
    await call.message.delete()
    inline_timepicker.init(
        datetime.time(12),
        datetime.time(1),
        datetime.time(23),
    )

    await call.message.answer(text=str.YOUR_TIME,
                              reply_markup=inline_timepicker.get_keyboard())



def register_handlers_client(dp: Dispatcher):
    dp.register_callback_query_handler(set_date, state=FSMClient.state_date)
    dp.register_callback_query_handler(process_dialog_calendar, simple_cal_callback.filter(), state=FSMClient.state_process)
    dp.register_callback_query_handler(set_time, state=FSMClient.state_time)
→ Ссылка