# core from core.services.using_tickets.use_ticket_orchestrator import use_ticket_orchestrator from core.controllers.tickets.TicketPrepController import prepare_tickets from core.controllers.ConfigurationController import ConfigurationController from core.services.prepare_tickets.ticket_tracker import get_a_random_ticket from core.services.subscriptions.subscriptions_by_protocol import start_new_payment_cycle, get_ticket_invoice from core.services.payment_phase.ticket_cycle import wipe_ticket_cycle from core.services.payment_phase.payment_state import TicketPaymentData from core.models.enum_models import PaymentCategory from core.services.prepare_tickets.ticket_tracker import get_all_unused_tickets from core.utils.type_checker import type_checker from core.models.Result import Result, ResultError from core.errors.logger import logger from core.observers.Notifications import Notifications, EventType # gui from gui.v2.infrastructure.action_registry import register_action from gui.v2.infrastructure.take_plumbing_action import take_action from gui.v2.infrastructure.setup_observers import connection_observer, ticket_observer from gui.v2.actions.error_handlers import navigate_to_new_sub_page # generic: from typing import Callable # from core.controllers.tickets.UseTicketController import use_ticket # from core.models.BaseProfile import BaseProfile as Profile # from core.controllers.ProfileController import ProfileController # from core.controllers.tickets.TicketPayController import initiate_payment @register_action(ResultError.TICKET_EXPIRED) def wipe_ticket_billing() -> Result: """Wipe existing data and start over.""" wiped = wipe_ticket_cycle() if wiped.valid: return Result(valid=True, error_type=ResultError.NAVIGATE_TO, navigate_to="plan_picker") else: return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="plan_picker") @register_action(ResultError.NO_TICKET) def start_and_navigate_to_ticketing() -> Result: """Starts a new ticketing cycle. (assumes the user opted in).""" start_result = start_new_payment_cycle(category=PaymentCategory.TICKET) if start_result.valid: logger.info("creating a new payment cycle was valid, it worked.") return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="plan_picker") else: logger.info(f"Returning the error of start_result {start_result}") return start_result @type_checker def random_ticket_dispatch(profile_id: int, passed_ui_caller: Callable) -> Result: """ User explicitly wants a random ticket. The reason this is in GUI repo, is because use_a_ticket is. """ random_ticket_result = get_a_random_ticket() if not random_ticket_result.valid: return random_ticket_result which_ticket = random_ticket_result.data # this is a redundant sanity check: if not which_ticket: Result(valid=False, error_type=ResultError.NO_TICKET, message="No tickets left. Would you like to get some?") # thread work that calls the caller, not return: take_action( action=use_ticket_orchestrator, ui_caller=passed_ui_caller, profile_id=profile_id, which_ticket=which_ticket, connection_observer=connection_observer, ticket_observer=ticket_observer ) return Result(valid=True) @type_checker def dispatch_ticketing(profile_id: int, passed_ui_caller: Callable) -> Result: """Evaluate if a random ticket will be used.""" use_random_setting = ConfigurationController.use_random() if use_random_setting: return random_ticket_dispatch(profile_id=profile_id, passed_ui_caller=passed_ui_caller) # User does NOT want an automated selection, so they can pick from their tickets: do_they_have_tickets = get_ticket_data() if do_they_have_tickets.valid: return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="ticket_or_billing_choice") else: # user can decide if they want to setup tickets or do an individual profile: return navigate_to_new_sub_page() def start_ticket(ui_caller: Callable): """Start the entire billing cycle for tickets""" logger.info("started ticketing billing state") notification = "Started Ticket Billing" Notifications.emit(EventType.STATUS_UPDATE, notification) take_action( action=start_new_payment_cycle, category=PaymentCategory.TICKET, ui_caller=ui_caller ) def fetch_ticket_invoice(ui_caller: Callable): """Fetch the invoice for tickets""" take_action( action=get_ticket_invoice, ui_caller=ui_caller, connection_observer=connection_observer ) def start_bulk_ticket_prep(ui_caller: Callable) -> Result: """After paid for, start the actual math""" ticket_cycle = TicketPaymentData() how_many_profiles = ticket_cycle.how_many_profiles return take_action( action=prepare_tickets, ui_caller=ui_caller, how_many_profiles=how_many_profiles, connection_observer=connection_observer, ticket_observer=ticket_observer, which_ticket=None, billing_code=None ) def get_ticket_data() -> Result: """This is running in the background ALREADY. Get & format a list of unused tickets from core""" ticket_results = get_all_unused_tickets() valid = ticket_results.get('valid') if not valid: message = ticket_results.get('message') if not message: message = "Error gathering ticket data" Result(valid=False, error_type=ResultError.MISSING_FILE, message=message) raw_tickets = ticket_results.get('data') print(f"raw_tickets is {raw_tickets}") if not raw_tickets: Result(valid=False, error_type=ResultError.NO_TICKET, message="No tickets available. Would you like to get some?") formatted_data = [(f"Ticket #{t}", t) for t in raw_tickets] print(f"formatted_data is {formatted_data}") return Result(valid=True, data=formatted_data) def use_a_ticket(profile_id: int, which_ticket: int, ui_caller: Callable): """Use of a given ticket.""" take_action( action=use_ticket_orchestrator, ui_caller=ui_caller, profile_id=profile_id, which_ticket=which_ticket, ticket_observer=ticket_observer, connection_observer=connection_observer )