import re
from aiogram import types
from aiogram.dispatcher import filters, FSMContext

from app.models import Product, ShoppingList, ShoppingListToProduct

from app.misc import dp
from app.states.state_ingredients import IngredientsForRecipe


@dp.callback_query_handler(filters.Regexp(r'select_all_product_for_recipe'),
                           state=IngredientsForRecipe.ingredients)
async def select_all_product_for_recipe(query: types.CallbackQuery,
                                        state: FSMContext):
    async with state.proxy() as st:
        name = re.match(r'select_all_product_for_recipe', query.data).groups()
        products = await Product.query.where(
            Product.user_id == query.from_user.id).gino.all()
        shopping_list_product_connections = await ShoppingList \
            .join(ShoppingListToProduct, ShoppingListToProduct.shopping_list_id == ShoppingList.id) \
            .select(ShoppingList.user_id == query.from_user.id) \
            .gino.all()
        shopping_list_product_ids = [
            data[3] for data in shopping_list_product_connections
        ]
        products = list(
            filter(lambda item: item.id not in shopping_list_product_ids,
                   products))
        if len(st.get("ingredients", [])) == 0:
            st["ingredients"] = []
        for prod in products:
Пример #2
0
import re

from aiogram import types
from aiogram.dispatcher import filters, FSMContext

from app.misc import dp, bot
from app.states import IngredientsForRecipe


@dp.callback_query_handler(filters.Regexp(r'(\d*)_kcal'), state=IngredientsForRecipe.kcal)
async def calories_filter_handler(query: types.CallbackQuery, state: FSMContext):
    groups = re.match(r'(\d*)_kcal', query.data).groups()
    async with state.proxy() as kcal:
        kcal['kcal'] = groups[0]
    await IngredientsForRecipe.previous()
    await query.answer()
    await bot.delete_message(query.from_user.id, query.message.message_id)
Пример #3
0
import re
from typing import List

from aiogram import types
from aiogram.dispatcher import filters, FSMContext

from app.keyboards.inline.recipes_keyboard import RecipesListKeyboard
from app.misc import dp, bot
from app.recipe_parser.parser import ParserHelper, Parser
from app.recipe_parser.recipe_models import Recipe
from app.states.state_ingredients import IngredientsForRecipe


@dp.callback_query_handler(filters.Regexp(r'find_recipe'),
                           state=IngredientsForRecipe.ingredients)
async def find_recipe(query: types.CallbackQuery, state: FSMContext):
    await IngredientsForRecipe.next()
    await IngredientsForRecipe.next()
    f = True
    async with state.proxy() as ingredients:
        await query.answer("Ищем рецепты...")
        ingredients_list = ingredients['ingredients']
        helper = ParserHelper(ingredients_list)
        search_url = await helper.get_search_string()
        parser = Parser(search_url)
        recipes_list: List = parser.get_recipes()
        if not ingredients.get("kcal", None):
            ingredients['recipes'] = recipes_list
        else:
            ingredients['recipes'] = [
                i for i in recipes_list
Пример #4
0
import re

from aiogram import types
from aiogram.dispatcher import filters, FSMContext
from loguru import logger

from app.keyboards.inline.product_list_keyboard import ProductListKeyboard
from app.keyboards.inline.recipe_product_list_keyboard import RecipeProductListKeyboard
from app.misc import dp, bot
from app.models import Product, ShoppingList, ShoppingListToProduct, User
from app.states import IngredientsForRecipe


@dp.callback_query_handler(
    filters.Regexp(r'(previous_page|next_page)_recipe_(\d*)'),
    state=IngredientsForRecipe.ingredients)
async def page_callback_handler(query: types.CallbackQuery, state: FSMContext):
    groups = re.match(r'(previous_page|next_page)_recipe_(\d*)',
                      query.data).groups()
    new_page = 0
    if groups[0] == 'previous_page':
        new_page = int(groups[1]) - 1
    elif groups[0] == 'next_page':
        new_page = int(groups[1]) + 1

    logger.info(f"Next page: {new_page}")

    products = await Product.query.where(Product.user_id == query.from_user.id
                                         ).gino.all()
    shopping_list_product_connections = await ShoppingList \
        .join(ShoppingListToProduct, ShoppingListToProduct.shopping_list_id == ShoppingList.id) \
Пример #5
0
from datetime import datetime, timedelta

from aiogram import types

from aiogram.dispatcher import filters

from app.misc import dp, bot

from app.keyboards.inline.automatic_setting_of_the_purchase_date_keyboard import \
    AutomaticSettingOfThePurchaseDateListKeyboard
from app.keyboards.inline.default_list_of_products_keyboard import DefaultListOfProductsListKeyboard
from app.models import Product, UserSettings


@dp.callback_query_handler(
    filters.Regexp(r'other_(default_list_of_products|auto_set_purchase_date)'))
async def other_settings_callback_handler(query: types.CallbackQuery):
    groups = re.match(
        r'other_(default_list_of_products|auto_set_purchase_date)',
        query.data).groups()
    source = groups[0]
    if source == 'auto_set_purchase_date':
        await bot.edit_message_text(
            'Настройка автоматической выставления даты:',
            query.from_user.id,
            query.message.message_id,
            reply_markup=AutomaticSettingOfThePurchaseDateListKeyboard.create(
            ))
    elif source == 'default_list_of_products':
        await bot.edit_message_text(
            'Настройка дефолтного списка покупок:',
Пример #6
0
    if not match:
        await message.answer(_("Wrong invoice link."))
        return

    product_index, product_filters, product_size = match.groups()
    await answer_product_invoice(
        message,
        state,
        locale,
        int(product_index),
        ProductFilters(product_filters),
        int(product_size),
    )


@dp.callback_query_handler(filters.Regexp(rf"list_sizes:{PRODUCT_REGEX}"),
                           state=any_state)
@handle_product_params
async def list_product_sizes(
    callback_query: types.CallbackQuery,
    *,
    state: FSMContext,
    handled_params: tuple,
    locale: str,
    **kwargs,
) -> None:
    product_index, product_filters = handled_params
    product = await get_product(state, product_index, product_filters)
    await callback_query.message.reply(
        emojize(_(":shoe: Choose shoe size")),
        reply_markup=get_product_sizes_keyboard(product, product_index,
Пример #7
0
def edit_info_product_message(name: str, exp_date: datetime,
                              bought_date: datetime, info: str):
    bubble = f'Продукт:\n{name}\n'
    if exp_date is not None:
        e = parse(str(exp_date)).strftime('%d.%m.%Y')
        bubble += f'Срок годности: до {e}\n'
    if bought_date is not None:
        b = parse(str(bought_date)).strftime('%d.%m.%Y')
        bubble += f'Дата покупки: {b}\n'
    bubble += info if info else ''
    bubble += 'Что изменить?'
    return bubble


@dp.callback_query_handler(filters.Regexp(r'change_(\d+)'))
async def edit_callback_handler(query: types.CallbackQuery):
    groups = re.match(r'change_(\d*)', query.data).groups()
    product = await Product.query.where(Product.id == int(groups[0])
                                        ).gino.first()
    await bot.send_message(
        query.from_user.id,
        "Что изменить?",
        reply_markup=ChangeInfoAboutProductKeyboard.create(product))
    await query.answer()


@dp.callback_query_handler(filters.Regexp(r'change_name_(\d+)'))
async def change_name_callback_handler(query: types.CallbackQuery):
    groups = re.match(r'change_name_(\d+)', query.data).groups()
    ChangeProductState.id = groups[0]
import re

from aiogram import types
from aiogram.dispatcher import filters

from app.misc import dp, bot
from app.models import Product, ShoppingList, ShoppingListToProduct


@dp.callback_query_handler(filters.Regexp(r'add_to_shop_list_(\d*)'))
async def add_to_shop_list_from_fridge(query: types.CallbackQuery):
    groups = re.match(r'add_to_shop_list_(\d*)', query.data).groups()
    product = await Product.query.where(Product.id == int(groups[0])
                                        ).gino.first()
    shop_list = await ShoppingList.query.where(
        ShoppingList.user_id == query.from_user.id).gino.first()
    new_product = await Product.create(user_id=query.from_user.id,
                                       name=product.name,
                                       info=None)
    await ShoppingListToProduct.create(product_id=new_product.id,
                                       shopping_list_id=shop_list.id)
    await bot.send_message(query.from_user.id,
                           "Продукт добавлен в список покупок")
    await query.answer()
Пример #9
0
from typing import Match

from aiogram import types
from aiogram.dispatcher import FSMContext, filters
from aiogram.dispatcher.filters.state import any_state
from aiogram.utils.exceptions import Throttled

from ..bot import _, dp  # type: ignore
from ..product_answers import get_bookmark_answer, get_product, get_product_slide_answer
from .common import PRODUCT_REGEX, answer_product_slide, handle_product_params

logger = logging.getLogger(__name__)


@dp.callback_query_handler(
    filters.Regexp(rf"controls:(?:previous|next):{PRODUCT_REGEX}"), state=any_state
)
@handle_product_params
async def process_browse_controls(
    callback_query: types.CallbackQuery,
    *,
    state: FSMContext,
    handled_params: tuple,
    locale: str,
    **kwargs,
) -> None:
    next_product_index, product_filters = handled_params
    product_slide = await get_product_slide_answer(
        state, locale, next_product_index, product_filters
    )
    await answer_product_slide(
import re

from aiogram import types
from aiogram.dispatcher import filters

from app.keyboards.inline.delete_product_keyboard import ConfirmDeleteProductKeyboard
from app.misc import dp, bot
from app.models import Product


def delete_product_confirm_message(name: str):
    return f'Вы действительно хотите удалить продукт "{name}"?'


@dp.callback_query_handler(filters.Regexp(r'delete_(\d+)'))
async def delete_confirm_callback_handler(query: types.CallbackQuery):
    groups = re.match(r'delete_(\d*)', query.data).groups()
    product = await Product.query.where(Product.id == int(groups[0])
                                        ).gino.first()

    await bot.send_message(query.from_user.id,
                           delete_product_confirm_message(product.name),
                           reply_markup=ConfirmDeleteProductKeyboard.create(
                               product, query.message.message_id))
    await query.answer()


@dp.callback_query_handler(filters.Regexp(r'delete_yes_(\d+)_(\d+)'))
async def delete_yes_callback_handler(query: types.CallbackQuery):
    groups = re.match(r'delete_yes_(\d+)_(\d+)', query.data).groups()
Пример #11
0
from app.keyboards.inline.product_keyboard import ProductKeyboard
from app.misc import dp, bot
from app.models import Product
from dateutil.parser import parse


def create_info_product_message(name: str, exp_date: datetime, bought_date: datetime, info: str):
    bubble = f'{name}\n'
    if exp_date is not None:
        e = parse(str(exp_date)).strftime('%d.%m.%Y')
        bubble += f'Срок годности: до {e}\n'
    if bought_date is not None:
        b = parse(str(bought_date)).strftime('%d.%m.%Y')
        bubble += f'Дата покупки: {b}\n'
    bubble += info if info else ''
    return bubble


@dp.callback_query_handler(filters.Regexp(r'show_(fridge|shopping_list)_(\d*)'))
async def handler_product_button(query: types.CallbackQuery):
    groups = re.match(r'show_(fridge|shopping_list)_(\d*)', query.data).groups()
    product = await Product.query.where(Product.id == int(groups[1])).gino.first()
    if groups[0] == 'fridge':
        await bot.send_message(query.from_user.id,
                               create_info_product_message(product.name, product.expiration_date, product.bought_date, product.info),
                               reply_markup=ProductKeyboard.create(product))
    elif groups[0] == 'shopping_list':
        await bot.send_message(query.from_user.id,
                               create_info_product_message(product.name, product.expiration_date, product.bought_date, product.info),
                               reply_markup=ShoppingListProductInfoKeyboard.create(product))
    await query.answer()
import re

from aiogram import types
from aiogram.dispatcher import filters
from loguru import logger

from app.keyboards.inline.product_list_keyboard import ProductListKeyboard
from app.keyboards.inline.recipe_product_list_keyboard import RecipeProductListKeyboard
from app.misc import dp, bot
from app.models import Product, ShoppingList, ShoppingListToProduct, User


@dp.callback_query_handler(
    filters.Regexp(r'(previous_page|next_page)_(fridge|shopping_list)_(\d*)'))
async def page_callback_handler(query: types.CallbackQuery):
    groups = re.match(
        r'(previous_page|next_page)_(fridge|shopping_list)_(\d*)',
        query.data).groups()
    new_page = 0
    if groups[0] == 'previous_page':
        new_page = int(groups[2]) - 1
    elif groups[0] == 'next_page':
        new_page = int(groups[2]) + 1
    source = groups[1]

    logger.info(f"Source: {source}")
    logger.info(f"Next page: {new_page}")

    keyboard = None
    products = None
    if source == 'fridge':
Пример #13
0
import re

from aiogram import types
from aiogram.dispatcher import filters

from app.keyboards.inline.add_product_method import AddProductMethod
from app.misc import dp, bot


@dp.callback_query_handler(filters.Regexp(r'add_to_(fridge|shopping_list)'))
async def add_to_callback_handler(query: types.CallbackQuery):
    info = re.findall(r'(fridge|shopping_list)', query.data)
    await bot.send_message(query.from_user.id,
                           "Выберите тип добавления продукта",
                           reply_markup=AddProductMethod.create(
                               info, query.message.message_id))
    await query.answer()
Пример #14
0
    await answer_next_filter_or_results(callback_query.message, state, locale,
                                        next_filter)
    await callback_query.answer()


@dp.callback_query_handler(filters.Text(r"filter:skip_all"),
                           state=ProductFiltersForm.all_states)
async def process_filter_skip_all(callback_query: types.CallbackQuery,
                                  state: FSMContext, locale: str) -> None:
    # None state finishes the filtering
    await answer_next_filter_or_results(callback_query.message, state, locale,
                                        None)
    await callback_query.answer()


@dp.callback_query_handler(filters.Regexp(r"filter:choice:(\w+):(\w+)"),
                           state=ProductFiltersForm.all_states)
@handle_regex_params(None, None)
async def process_filter_choice(
    callback_query: types.CallbackQuery,
    *,
    state: FSMContext,
    locale: str,
    handled_params: tuple,
    **kwargs,
) -> None:
    filter_name, query_value = handled_params
    logger.debug("Filter name: %s. Filter query value: %s", filter_name,
                 query_value)

    store_name = settings.PRODUCT_FILTERS[filter_name].query_name or filter_name
Пример #15
0
import re

from aiogram import types
from aiogram.dispatcher import filters, FSMContext

from app.misc import dp
from app.states.state_ingredients import IngredientsForRecipe


@dp.callback_query_handler(filters.Regexp(r'add_to_recipe_(\w*)'),
                           state=IngredientsForRecipe.ingredients)
async def add_to_recipe(query: types.CallbackQuery, state: FSMContext):
    name = re.match(r'add_to_recipe_(\w*)', query.data).groups()
    await query.answer()
    async with state.proxy() as ingredients:
        if len(ingredients.get("ingredients", [])) == 0:
            ingredients["ingredients"] = []
        ingredients["ingredients"].append(name[0])
from aiogram import types
from aiogram.dispatcher import filters, FSMContext

from app.keyboards.inline.calories_keyboard import CaloriesKeyboard
from app.misc import dp, bot
from app.states import IngredientsForRecipe


@dp.callback_query_handler(filters.Regexp(r'calories_keyboard'),state=IngredientsForRecipe.ingredients)
async def calories_keyboard_handler(query: types.CallbackQuery,state: FSMContext):
    await IngredientsForRecipe.next()
    await bot.send_message(query.from_user.id,'Выберите максимальноее число ккал в 100 гр блюда',reply_markup=CaloriesKeyboard.create())
    await query.answer()
Пример #17
0
async def noticker_on_yahoo(message: types.Message):
    return await message.reply("Ticker not found", reply_markup=kb.cancel_kb)


""" Setting amount """
@dp.message_handler(state=PaperFSM.ticker)
async def paper_setticker_getamount(message: types.Message, state: FSMContext):
    new_paper.ticker = message.text.upper()
    new_paper.get_yahoo()  # Load data from yahoo to fetch currency
    await PaperFSM.next()
    await bot.send_message(message.chat.id, "Enter amount of papers",
                           reply_markup=kb.cancel_kb)


""" Setting price """
@dp.message_handler(filters.Regexp(regexp='^-?\d+(?:\.\d+)?$'), state=PaperFSM.amount)
async def paper_setamount_getprice(message: types.Message, state: FSMContext):
    new_paper.amount = int(message.text)
    await PaperFSM.next()
    await bot.send_message(message.chat.id, "Enter price of papers",
                           reply_markup=kb.cancel_kb)


""" Finish FSM, save object to DB """
@dp.message_handler(state=PaperFSM.price)
async def portfolio_setprice_finishmachine(message: types.Message, state: FSMContext):
    new_paper.price = float(message.text)
    new_paper.margin = query.fetch('portfolios', ['margin'], id=new_paper.portfolio_id)[0]['margin']
    new_paper.set_commission()
    new_paper.add_transaction(new_paper.amount, new_paper.price, new_paper.commission)
    new_paper.save()
Пример #18
0
from aiogram import types
from aiogram.dispatcher import filters

from utils.database.api import get_rhash

from loader import dp

REGULAR_LINK_REGEX = "^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?(?!t\.me)([a-z0-9])+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$"


@dp.message_handler(filters.Regexp(regexp=REGULAR_LINK_REGEX))
async def bot_link_format(message: types.Message):
    domain_name = message.text.split("//")[1].split("/")[0].replace('www.', '')
    rhash = get_rhash(user_id=message.from_user.id, domain_name=domain_name)
    if rhash:
        await message.answer(f"[⁠](https://t.me/iv?url={message.text}&rhash={rhash}){message.text}",
                             parse_mode="Markdown")
        await message.answer(f"[⁠](https://t.me/iv?url={message.text}&rhash={rhash})",
                             parse_mode="Markdown", disable_web_page_preview=True)
    else:
        await message.answer(f"You don't have Template for your domain {domain_name}")
Пример #19
0
import datetime
import re

from aiogram import types
from aiogram.dispatcher import filters

from app.misc import dp, bot
from app.models import Product, ShoppingListToProduct


@dp.callback_query_handler(filters.Regexp(r'buy_(\d*)'))
async def buy_product(query: types.CallbackQuery):
    groups = re.match(r'buy_(\d*)', query.data).groups()
    product = await Product.query.where(Product.id == int(groups[0])
                                        ).gino.first()
    await ShoppingListToProduct.delete.where(
        product.id == ShoppingListToProduct.product_id).gino.status()
    await product.update(bought_date=datetime.datetime.now()).apply()
    await bot.delete_message(query.from_user.id, query.message.message_id)
    await bot.send_message(
        query.from_user.id,
        f"Продукт \"{product.name}\" добавлен в ваш холодильник")
    await query.answer()
Пример #20
0
import re

from aiogram import types
from aiogram.dispatcher import filters

from app.keyboards.inline.delete_product_keyboard import ConfirmDeleteProductKeyboard
from app.misc import dp, bot
from app.models import Product


def delete_product_confirm_message(name: str):
    return f'Вы действительно хотите удалить продукт "{name}" из списка покупок?'


@dp.callback_query_handler(filters.Regexp(r'delete_from_shopping_list_(\d*)'))
async def delete_confirm_callback_handler(query: types.CallbackQuery):
    groups = re.match(r'delete_from_shopping_list_(\d*)', query.data).groups()
    product = await Product.query.where(Product.id == int(groups[0])).gino.first()

    await bot.send_message(query.from_user.id,
                           delete_product_confirm_message(product.name),
                           reply_markup=ConfirmDeleteProductKeyboard.create(product, query.message.message_id))
    await query.answer()


@dp.callback_query_handler(filters.Regexp(r'delete_yes_(\d+)_(\d+)'))
async def delete_yes_callback_handler(query: types.CallbackQuery):
    groups = re.match(r'delete_yes_(\d+)_(\d+)', query.data).groups()

    await Product.delete.where(Product.id == int(groups[0])).gino.status()
Пример #21
0
from aiogram.dispatcher import filters, FSMContext

from app.misc import dp, bot
from app.recipe_parser.parser import Parser
from app.recipe_parser.recipe_models import RecipeDetails
from app.states import IngredientsForRecipe


def recipe_details_helper(rd: RecipeDetails):
    # steps = rd.instructions
    ingredients = ", ".join(map(lambda x: str(x), rd.ingredients))
    if rd.instructions is None:
        steps = '\n'.join(rd.steps)
        return f'{rd.name}\n\nКБЖУ: {rd.weight} гр - {rd.PFC}\nВремя приготовления {rd.cooking_time}\n\nДля {rd.portions_count} порций: {ingredients}\n\n{steps}'
    return f'{rd.name}\n\nКБЖУ: {rd.weight} гр - {rd.PFC}\nВремя приготовления {rd.cooking_time}\n\nДля {rd.portions_count} порций: {ingredients}\n\n{rd.instructions}'


@dp.callback_query_handler(filters.Regexp(r'select_recipe_([0-9a-f]{32}\Z)'),
                           state=IngredientsForRecipe.recipes)
async def select_recipe(query: types.CallbackQuery, state: FSMContext):
    recipe_id = re.match(r'select_recipe_([0-9a-f]{32}\Z)',
                         query.data).groups()
    async with state.proxy() as list_recipes:
        recipes = list_recipes['recipes']
        recipe = next((x for x in recipes if x.id == recipe_id[0]), None)
        recipe_details = await Parser.get_recipe_details(recipe)
        await bot.send_message(query.from_user.id,
                               recipe_details_helper(recipe_details))
    await state.finish()
    await query.answer()
import re

from aiogram import types
from aiogram.dispatcher import filters, FSMContext

from app.keyboards.inline.recipes_keyboard import RecipesListKeyboard
from app.misc import dp, bot
from app.states import IngredientsForRecipe


@dp.callback_query_handler(
    filters.Regexp(r'(previous|next)_page_recipes_(\d+)'),
    state=IngredientsForRecipe.recipes)
async def change_page_recipe(query: types.CallbackQuery, state: FSMContext):
    groups = re.match(r'(previous|next)_page_recipes_(\d+)',
                      query.data).groups()
    new_page = 0
    if groups[0] == 'previous':
        new_page = int(groups[1]) - 1
    elif groups[0] == 'next':
        new_page = int(groups[1]) + 1
    async with state.proxy() as recipes:
        await bot.edit_message_reply_markup(
            query.from_user.id,
            query.message.message_id,
            reply_markup=RecipesListKeyboard.create(recipes['recipes'],
                                                    new_page))
    await query.answer()
Пример #23
0
from aiogram import types
from aiogram.dispatcher import filters
from urllib.parse import urlsplit, parse_qs, unquote

from utils.database.api import add_domain

from loader import dp

IV_LINK_REGEX = "^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?t\.me(\/.*rhash=.*)$"
BROKEN_IV_LINK_REGEX = "^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?t\.me(\/*.*)$"


@dp.message_handler(filters.Regexp(regexp=IV_LINK_REGEX))
async def bot_link_telegram(message: types.Message):
    iv_link = unquote(message.text)
    iv_link_query = urlsplit(iv_link).query
    iv_link_params = parse_qs(iv_link_query)
    iv_link_params_dict = {
        param: value[0]
        for param, value in iv_link_params.items()
    }

    try:
        domain_name = iv_link_params_dict['url'].split("//")[-1].split(
            "/")[0].replace('www.', '')
        rhash = iv_link_params_dict['rhash']

        add_domain(user_id=message.from_user.id,
                   domain_name=domain_name,
                   rhash=rhash)
Пример #24
0
async def add_product_photo_check_shoplist_handler(query: types.CallbackQuery):
    await ShoppingAddPhotoCheckState.name.set()
    await bot.send_message(query.message.chat.id,
                           "Отправьте фото чека в хорошем качестве (без лишних предметов и надписей):")
    await query.answer('Распознаю продукты...')


@dp.callback_query_handler(filters.Text('add_product_photo_[\'fridge\']'))
async def add_product_photo_fridge_handler(query: types.CallbackQuery):
    await FridgeAddPhotoState.name.set()
    await bot.send_message(query.message.chat.id,
                           "Отправьте фото продукта/этикетки в хорошем качестве (без лишних предметов и надписей):")
    await query.answer('Распознаю продукт...')


@dp.callback_query_handler(filters.Regexp(r'add_product_photo_name_ok_\[\'fridge\']\+.*'))
async def add_product_photo_fridge_nameok_handler(query: types.CallbackQuery, state: FSMContext):
    name = re.findall(r'[^+]*$', query.data)[0]
    async with state.proxy() as data:
        data['name'] = name
    await FridgeProductState.expiration_date.set()
    await bot.send_message(query.message.chat.id, 'Введите срок годности продукта (пропустить - /skip, пропустить остальные шаги /skipall)')
    await query.answer()


@dp.callback_query_handler(filters.Text('add_product_photo_[\'shopping_list\']'))
async def add_product_photo_shoplist_handler(query: types.CallbackQuery):
    await ShoppingAddPhotoState.name.set()
    await bot.send_message(query.message.chat.id,
                           "Отправьте фото продукта/этикетки в хорошем качестве (без лишних предметов и надписей):")
    await query.answer('Распознаю продукт...')