async def get_monthly_earnings(self, year: int, month: int) -> HandlingResult: # Allowed only for employees orders = self.helpers.get_monthly_paid_orders_by_month_and_year( month, year) if orders: earnings: Dict[int, int] = {} total_earnings = 0 for order in orders: total_earnings += order.earnings try: earnings[order.taker_vk_id] += order.earnings except KeyError: earnings[order.taker_vk_id] = order.earnings earnings_as_strings: List[str] = [] for employee_vk_id, taker_earnings in earnings.items(): employee_info = await (self.managers_container.users_manager. get_user_info_by_vk_id(employee_vk_id)) earned_word = ("заработал" if employee_info.sex is Sex.MALE else "заработала") employee_tag = self.helpers.get_tag_from_vk_user_dataclass( employee_info) earnings_as_strings.append( f"{employee_tag} {earned_word} {taker_earnings} руб.") return HandlingResult(Notification(text_for_employees="\n".join(( f"Общий доход: {total_earnings} руб.", *earnings_as_strings))), commit_needed=True) return HandlingResult(Notification(text_for_employees=( f"За {month} месяц {year} года не заработано ни рубля!")), commit_needed=False)
async def create_order_offline(self, employee_vk_id: int, client_vk_id_or_tag: str, text: str) -> HandlingResult: try: client_info = await ( self.managers_container.users_manager.get_user_info_by_vk_id( client_vk_id_or_tag, GrammaticalCases.GENITIVE)) except simple_avk.MethodError: return HandlingResult(Notification(text_for_employees=( f"Пользователя с VK ID {client_vk_id_or_tag} нет!")), commit_needed=False) else: client_vk_id = client_info.id order = models.Order(creator_vk_id=client_vk_id, real_creator_vk_id=employee_vk_id, text=text) self.managers_container.orders_manager.add(order) self.managers_container.orders_manager.flush() full_client_tag = self.helpers.get_tag_from_vk_user_dataclass( client_info) employee_tag = self.helpers.get_tag_from_vk_user_dataclass( await (self.managers_container.users_manager.get_user_info_by_vk_id( employee_vk_id, GrammaticalCases.INSTRUMENTAL))) return HandlingResult(Notification( text_for_employees=(f"Заказ с ID {order.id} создан от лица " f"{full_client_tag}!"), additional_messages=[ Message((f"От твоего лица {employee_tag} создан заказ с " f"ID {order.id} и текстом \"{text}\"! Если вы " f"не просили этого делать - напишите " f"администрации."), client_vk_id) ]), commit_needed=True)
async def request_orders_as_notification( self, client_vk_id: int, current_chat_peer_id: int, filters: tuple, no_orders_found_client_error: str, no_orders_found_employees_error: str, limit: Optional[int] = None) -> HandlingResult: request_is_from_employee = ( current_chat_peer_id == self.vk_config.EMPLOYEES_CHAT_PEER_ID) filters = (filters if request_is_from_employee else (*filters, models.Order.creator_vk_id == client_vk_id) ) # Old filters isn't needed anymore orders = self.managers_container.orders_manager.get_orders(*filters, limit=limit) if not orders: return HandlingResult( Notification( # Here text_for_client will be sent to employees if orders # is requested in the employees' chat text_for_client=(no_orders_found_employees_error if request_is_from_employee else no_orders_found_client_error)), commit_needed=False) notification_with_orders = ( await self.get_notification_with_orders( orders, # If client requested the orders - creator info isn't needed, # because client is the creator include_creator_info=request_is_from_employee, limit_for_header=limit)) return HandlingResult(notification_with_orders, commit_needed=True)
async def mark_orders_as_paid(self, employee_vk_id: int, order_ids: Tuple[int], earnings_amount: int) -> HandlingResult: client_callback_messages = UserCallbackMessages() found_orders = (self.managers_container.orders_manager. get_orders_by_ids(order_ids)) already_paid_order_ids = [] canceled_order_ids = [] not_taken_order_ids = [] taken_by_other_employee_order_ids = [] marked_as_paid_order_ids = [] for order in found_orders.successful_rows: if order.is_paid: already_paid_order_ids.append(order.id) elif order.is_canceled: canceled_order_ids.append(order.id) elif not order.is_taken: not_taken_order_ids.append(order.id) elif order.taker_vk_id != employee_vk_id: taken_by_other_employee_order_ids.append(order.id) else: order.earnings = earnings_amount order.earning_date = datetime.date.today() marked_as_paid_order_ids.append(order.id) client_callback_messages.add_message( order.creator_vk_id, f"ID {order.id} (\"{order.text}\")") additional_messages = () if client_callback_messages.messages: employee_info = await (self.managers_container.users_manager. get_user_info_by_vk_id(employee_vk_id)) employee_tag = ( self.helpers.get_tag_from_vk_user_dataclass(employee_info)) marked_word = ("отметил" if employee_info.sex == Sex.MALE else "отметила") additional_messages = client_callback_messages.to_messages( prefix=( f"{employee_tag} {marked_word} оплаченными твои заказы " f"на сумму {earnings_amount} руб.: "), separator=", ", postfix=".") output = self.helpers.get_order_manipulation_results_as_list( ResultSection("ID заказов, которых просто нет", found_orders.failed_ids), ResultSection("ID уже оплаченных заказов", already_paid_order_ids), ResultSection( ("ID заказов, которые уже кто-то отменил, поэтому их " "нельзя оплатить"), canceled_order_ids), ResultSection(("ID заказов, которые еще никто не взял, поэтому их " "нельзя оплатить"), not_taken_order_ids), ResultSection( ("ID заказов, которые взяты не тобой, поэтому их нельзя " "оплатить"), taken_by_other_employee_order_ids), ResultSection( (f"ID заказов, успешно отмеченных оплаченными на сумму " f"{earnings_amount} руб."), marked_as_paid_order_ids)) return HandlingResult(Notification( text_for_employees="\n".join(output) if output else None, additional_messages=additional_messages), commit_needed=True)
async def clear_cache(self, user_vk_id: int) -> HandlingResult: user_tag = self.helpers.get_tag_from_vk_user_dataclass( await self.vk_worker.get_user_info(user_vk_id)) try: self.managers_container.users_manager.delete_user_info( models.CachedVKUser.vk_id == user_vk_id) except orm.exceptions.NoRowsFound: return HandlingResult(Notification(text_for_client=( f"{user_tag}, информация о тебе не сохранена! (Сейчас " f"твои имя и фамилия были скачаны временно, не " f"сохранены)")), commit_needed=False) return HandlingResult(Notification( text_for_client=(f"{user_tag}, твои имена очищены! (Сейчас " f"твои имя и фамилия были скачаны временно, не " f"сохранены)")), commit_needed=True)
async def get_help_message( self, current_chat_peer_id: int, full_commands_help_message: str, commands_only_for_clients_message: str) -> HandlingResult: return HandlingResult(Notification(text_for_client=( full_commands_help_message if current_chat_peer_id == self.vk_config. EMPLOYEES_CHAT_PEER_ID else commands_only_for_clients_message)), commit_needed=False)
async def get_monthly_paid_orders(self, year: int, month: int) -> HandlingResult: orders = self.helpers.get_monthly_paid_orders_by_month_and_year( month, year) if orders: notification_with_orders = ( await self.helpers.get_notification_with_orders(orders)) return HandlingResult(notification_with_orders, commit_needed=True) return HandlingResult(Notification(text_for_employees=( f"За {month} месяц {year} года не оплачено еще ни " f"одного заказа!")), commit_needed=False)
async def create_order(self, current_chat_peer_id: int, client_vk_id: int, text: str) -> HandlingResult: order = models.Order(creator_vk_id=client_vk_id, text=text) self.managers_container.orders_manager.add(order) self.managers_container.orders_manager.flush() if current_chat_peer_id != self.vk_config.EMPLOYEES_CHAT_PEER_ID: client_info = ( await (self.managers_container.users_manager.get_user_info_by_vk_id( client_vk_id))) # This looks ugly and not pythonic :( made_word = "сделал" if client_info.sex is Sex.MALE else "сделала" client_tag = self.helpers.get_tag_from_vk_user_dataclass( client_info) return HandlingResult(Notification( text_for_client=f"Заказ с ID {order.id} создан!", text_for_employees=( f"Клиент {client_tag} {made_word} заказ с ID " f"{order.id}: \"{order.text}\".")), commit_needed=True) return HandlingResult( Notification(text_for_employees=f"Заказ с ID {order.id} создан!"), commit_needed=True)
async def get_notification_with_orders( self, orders: List[models.Order], include_creator_info: bool = True, limit_for_header: Optional[int] = None) -> Notification: orders_as_strings = await self.get_orders_as_strings( orders, include_creator_info) if limit_for_header is not None: if limit_for_header == 1: # limit_for_header is greater than 0 orders_word = "заказ" elif limit_for_header in (2, 3, 4): orders_word = "заказа" else: orders_word = "заказов" orders_as_strings.insert( 0, f"Лимит - {limit_for_header} {orders_word}.") return Notification(text_for_client="\n\n".join(orders_as_strings))
async def take_orders(self, user_vk_id: int, order_ids: Tuple[int]) -> HandlingResult: # Allowed only for employees client_callback_messages = UserCallbackMessages() found_orders = (self.managers_container.orders_manager. get_orders_by_ids(order_ids)) already_taken_order_ids = [] canceled_order_ids = [] taken_order_ids = [] for order in found_orders.successful_rows: if order.is_taken: already_taken_order_ids.append(order.id) elif order.is_canceled: canceled_order_ids.append(order.id) else: order.taker_vk_id = user_vk_id taken_order_ids.append(order.id) client_callback_messages.add_message( order.creator_vk_id, f"ID {order.id} (\"{order.text}\")") additional_messages = () if client_callback_messages.messages: employee_info = await (self.managers_container.users_manager. get_user_info_by_vk_id(user_vk_id)) employee_tag = ( self.helpers.get_tag_from_vk_user_dataclass(employee_info)) taken_word = "взял" if employee_info.sex == Sex.MALE else "взяла" additional_messages = client_callback_messages.to_messages( prefix=(f"{employee_tag} {taken_word} твои заказы: "), separator=", ", postfix=(". Открой ЛС, чтобы сотрудник мог отправить тебе " "результаты или обсудить некоторые детали.")) output = self.helpers.get_order_manipulation_results_as_list( ResultSection("ID заказов, которых просто нет", found_orders.failed_ids), ResultSection("ID заказов, которые уже взяты", already_taken_order_ids), ResultSection("ID отмененных заказов, их нельзя взять", canceled_order_ids), ResultSection("ID успешно взятых заказов", taken_order_ids)) return HandlingResult(Notification( text_for_employees="\n".join(output) if output else None, additional_messages=additional_messages), commit_needed=True)
async def get_order_by_id(self, client_vk_id: int, current_chat_peer_id: int, order_ids: Tuple[int, ...]) -> HandlingResult: found_orders = (self.managers_container.orders_manager. get_orders_by_ids(order_ids)) output: List[str] = [ f"Заказ с ID {failed_id} не найден!" for failed_id in found_orders.failed_ids ] request_is_from_client = (current_chat_peer_id != self.vk_config.EMPLOYEES_CHAT_PEER_ID) for order in found_orders.successful_rows: if request_is_from_client and order.creator_vk_id != client_vk_id: output.append(f"Заказ с ID {order.id} тебе не принадлежит!") else: output.append(await self.helpers.get_order_as_string( order, # If request is from the client - no need to include # creator info, because client is the creator include_creator_info=not request_is_from_client)) return HandlingResult( Notification(text_for_client="\n\n".join(output)), commit_needed=True)
async def get_help_message_for_specific_commands( self, command_descriptions: Dict[str, List[Callable[..., str]]], command_names: Tuple[str, ...]) -> HandlingResult: command_descriptions_as_strings = [] quoted_not_found_commands: List[str] = [] for command_name in command_names: try: command_descriptions_as_strings.extend( # Here desc_func is a Command.get_full_description, # if I set Command.get_full_description as a type - # I wouldn't get any IDE hints anyway desc_func() for desc_func in command_descriptions[command_name]) except KeyError: quoted_not_found_commands.append(f"\"{command_name}\"") successful_output = "\n".join(command_descriptions_as_strings) return HandlingResult(Notification(text_for_client="\n\n".join(( f"Команда с названием " f"{quoted_not_found_commands[0]} не найдена!" if len( quoted_not_found_commands) == 1 else f"Команды с названиями " f"{', '.join(quoted_not_found_commands)} " f"не найдены!", successful_output )) if quoted_not_found_commands else successful_output), commit_needed=False)
async def cancel_orders(self, client_vk_id: int, current_chat_peer_id: int, order_ids: Tuple[int], cancellation_reason: str) -> HandlingResult: employees_callback: List[str] = [] client_callback_messages = UserCallbackMessages() found_orders = (self.managers_container.orders_manager. get_orders_by_ids(order_ids)) not_owned_by_user_order_ids = [] paid_order_ids = [] already_canceled_order_ids = [] taken_by_other_employee_order_ids = [] canceled_order_ids = [] request_is_from_client = (current_chat_peer_id != self.vk_config.EMPLOYEES_CHAT_PEER_ID) for order in found_orders.successful_rows: if request_is_from_client and order.creator_vk_id != client_vk_id: not_owned_by_user_order_ids.append(order.id) elif order.is_paid: paid_order_ids.append(order.id) elif order.is_canceled: already_canceled_order_ids.append(order.id) elif (order.is_taken and order.taker_vk_id != client_vk_id and order.creator_vk_id != client_vk_id): taken_by_other_employee_order_ids.append(order.id) else: order.canceler_vk_id = client_vk_id order.cancellation_reason = cancellation_reason canceled_order_ids.append(order.id) callback_str = f"ID {order.id} (\"{order.text}\")" if request_is_from_client: employees_callback.append(callback_str) else: client_callback_messages.add_message( order.creator_vk_id, callback_str) user_output = self.helpers.get_order_manipulation_results_as_list( ResultSection("ID заказов, которых просто нет", found_orders.failed_ids), ResultSection("ID оплаченных заказов, их нельзя отменить", paid_order_ids), ResultSection("ID уже отмененных заказов", already_canceled_order_ids), ResultSection( ("ID заказов, которые тебе не принадлежат, поэтому их " "нельзя отменить"), not_owned_by_user_order_ids), ResultSection(("ID заказов, которые уже взяты другим сотрудником, " "поэтому их нельзя отменить"), taken_by_other_employee_order_ids), ResultSection("ID успешно отмененных заказов", canceled_order_ids)) sender_info = (await self.managers_container.users_manager. get_user_info_by_vk_id(client_vk_id)) canceled_word = "отменил" if sender_info.sex is Sex.MALE else "отменила" canceler_tag = self.helpers.get_tag_from_vk_user_dataclass(sender_info) additional_messages = (client_callback_messages.to_messages( prefix=(f"{canceler_tag} {canceled_word} твои заказы по причине " f"\"{cancellation_reason}\": "), separator=", ", postfix=".") if client_callback_messages.messages else ()) return HandlingResult(Notification( text_for_employees=( (f"Клиент {canceler_tag} {canceled_word} заказы " f"по причине \"{cancellation_reason}\": " + "\n".join(employees_callback)) if employees_callback else None), text_for_client="\n".join(user_output) if user_output else None, additional_messages=additional_messages), commit_needed=True)
async def get_memo(self) -> HandlingResult: return HandlingResult( Notification(text_for_client=(f"Памятка по использованию бота:\n\n" f"{self.vk_config.MEMO_FOR_USERS}")), commit_needed=False)