forked from Support/sp-hydra-veil-gui
Improved error handling for billing conflicts of individual profiles at the same time. Overall flow is stable in this version
This commit is contained in:
parent
39925ad546
commit
ea12aecf05
8 changed files with 117 additions and 72 deletions
|
|
@ -1,19 +1,21 @@
|
|||
# core
|
||||
from core.controllers.ConfigurationController import ConfigurationController
|
||||
from core.services.prepare_tickets.ticket_tracker import get_a_random_ticket
|
||||
# from core.services.prepare_tickets.ticket_tracker import get_a_random_ticket
|
||||
from core.services.profiles.profile_connections import enable_profile #, disable_profile
|
||||
from core.controllers.ProfileController import ProfileController
|
||||
from core.models.Configuration import Configuration, ConnectionChoice
|
||||
from core.services.subscriptions.subscriptions_by_protocol import get_profile_subscription, start_new_payment_cycle, wipe_subscription
|
||||
from core.services.subscriptions.subscriptions_by_protocol import get_profile_subscription, start_new_payment_cycle, wipe_subscription, evaluate_repeat_cycle
|
||||
from core.utils.check_if_time_lapsed import check_if_time_lapsed
|
||||
from core.models.enum_models import PaymentCategory
|
||||
from core.utils.type_checker import type_checker
|
||||
from core.models.Result import Result, ResultError
|
||||
from core.errors.logger import logger
|
||||
from core.errors.translate_error import translate_error, get_ignored_exceptions
|
||||
from core.services.payment_phase.payment_state import OverallPaymentCycle
|
||||
|
||||
# gui
|
||||
from gui.v2.actions.ticket_actions import get_ticket_data, use_a_ticket
|
||||
from gui.v2.actions.payment_actions import wipe_expired_subscription
|
||||
from gui.v2.actions.ticket_actions import dispatch_ticketing
|
||||
from gui.v2.infrastructure.action_registry import register_action
|
||||
from gui.v2.infrastructure.take_plumbing_action import take_action
|
||||
from gui.v2.infrastructure.screen_size import get_max_screensize
|
||||
|
|
@ -25,6 +27,7 @@ from gui.v2.actions.error_handlers import navigate_to_new_sub_page
|
|||
|
||||
# generic
|
||||
from typing import Callable, Optional
|
||||
from functools import partial
|
||||
|
||||
@type_checker
|
||||
def get_profile(profile_id: int):
|
||||
|
|
@ -35,56 +38,21 @@ def get_profile(profile_id: int):
|
|||
return Result(valid=True, data=profile)
|
||||
|
||||
|
||||
@register_action(ResultError.NO_TICKET)
|
||||
def start_and_navigate_to_ticketing():
|
||||
"""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")
|
||||
def dispatch_individual(profile_id: int, ui_caller: Callable) -> Result:
|
||||
payment_cycle = OverallPaymentCycle()
|
||||
|
||||
print(f"payment_cycle is {payment_cycle}")
|
||||
|
||||
if payment_cycle.active:
|
||||
same_result = evaluate_repeat_cycle(payment_cycle=payment_cycle, profile_id=profile_id)
|
||||
if not same_result.valid:
|
||||
return same_result
|
||||
else:
|
||||
error_msg = "There's an error in the dispatch_individual function"
|
||||
logger.error(f"This shouldn't be going off. {error_msg}")
|
||||
return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="home", message=error_msg)
|
||||
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?")
|
||||
|
||||
# calls GUI repo function:
|
||||
return use_a_ticket(profile_id=profile_id, which_ticket=which_ticket, ui_caller=passed_ui_caller)
|
||||
|
||||
@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:
|
||||
# Starting fresh. Pick a billing type:
|
||||
return navigate_to_new_sub_page()
|
||||
|
||||
|
||||
|
|
@ -103,8 +71,7 @@ def filter_subscription(profile_id: int, passed_ui_caller: Callable) -> Result:
|
|||
# already opted into ticketing:
|
||||
return dispatch_ticketing(profile_id=profile_id, passed_ui_caller=passed_ui_caller)
|
||||
else:
|
||||
# Starting fresh. Pick a billing type:
|
||||
return navigate_to_new_sub_page()
|
||||
return dispatch_individual(profile_id=profile_id, ui_caller=passed_ui_caller)
|
||||
|
||||
#-----------------------------
|
||||
# Pending Subscription
|
||||
|
|
@ -128,7 +95,8 @@ def filter_subscription(profile_id: int, passed_ui_caller: Callable) -> Result:
|
|||
|
||||
expired = check_if_time_lapsed(expiration_date)
|
||||
if expired:
|
||||
return Result(valid=False, error_type=ResultError.EXPIRED_SUB, message="This subscription is expired, would you like to wipe it and get a new one?")
|
||||
function_choice = partial(wipe_subscription, profile_id=profile_id)
|
||||
return Result(valid=False, function_choice=function_choice, error_type=ResultError.EXPIRED_SUB, message="This subscription is expired, would you like to wipe it and get a new one?")
|
||||
|
||||
#-----------------------------
|
||||
# Proceed with Valid Sub
|
||||
|
|
|
|||
|
|
@ -162,6 +162,22 @@ def start_polling(billing_code: str, profile_id: int, ui_caller: Callable) -> st
|
|||
check_paid_timer.start_polling()
|
||||
return None
|
||||
|
||||
@register_action(ResultError.BILLING_CONFLICT)
|
||||
def stop_current() -> Result:
|
||||
wiped_result = wipe_billing_cycle()
|
||||
|
||||
logger.info("Stopping current!")
|
||||
|
||||
# if not wiped_result.valid:
|
||||
# return wiped_result
|
||||
|
||||
# new_cycle_result = start_new_payment_cycle(category=PaymentCategory.INDIVIDUAL, profile_id=profile_id)
|
||||
|
||||
# if not new_cycle_result.valid:
|
||||
# return new_cycle_result
|
||||
|
||||
return Result(valid=True, error_type=ResultError.NAVIGATE_TO, navigate_to="menu")
|
||||
|
||||
|
||||
@register_action(ResultError.ACTIVE_BILLING)
|
||||
def stop_payment_timer() -> Result:
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
# core
|
||||
from core.controllers.ConfigurationController import ConfigurationController
|
||||
from core.controllers.tickets.UseTicketController import use_ticket
|
||||
from core.services.prepare_tickets.ticket_tracker import get_a_random_ticket
|
||||
from core.models.BaseProfile import BaseProfile as Profile
|
||||
from core.controllers.ProfileController import ProfileController
|
||||
from core.controllers.tickets.TicketPayController import initiate_payment
|
||||
# from core.controllers.tickets.TicketPayController import initiate_payment
|
||||
from core.services.subscriptions.subscriptions_by_protocol import start_new_payment_cycle, save_subscription, get_ticket_invoice
|
||||
from core.services.payment_phase.ticket_cycle import wipe_ticket_cycle
|
||||
from core.services.payment_phase.payment_state import OverallPaymentCycle
|
||||
# from core.services.payment_phase.payment_state import OverallPaymentCycle
|
||||
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
|
||||
|
||||
|
|
@ -15,11 +18,66 @@ from core.errors.logger import logger
|
|||
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
|
||||
|
||||
|
||||
@register_action(ResultError.NO_TICKET)
|
||||
def start_and_navigate_to_ticketing():
|
||||
"""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?")
|
||||
|
||||
# calls GUI repo function:
|
||||
return use_a_ticket(profile_id=profile_id, which_ticket=which_ticket, ui_caller=passed_ui_caller)
|
||||
|
||||
|
||||
@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) -> Result:
|
||||
logger.info("started ticketing billing state")
|
||||
return take_action(
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ class Navigator(QObject):
|
|||
self._preload_dispatched += 1
|
||||
idx = self._preload_dispatched
|
||||
name = self._preload_queue.pop(0)
|
||||
logger.debug(f"[preload] ---- {idx}/{self._preload_total} ----")
|
||||
# logger.debug(f"[preload] ---- {idx}/{self._preload_total} ----")
|
||||
if name in ASYNC_PREPARE:
|
||||
self._dispatch_async_preload(name)
|
||||
else:
|
||||
|
|
@ -220,11 +220,12 @@ class Navigator(QObject):
|
|||
self._emit_preload_summary()
|
||||
|
||||
def _emit_preload_summary(self):
|
||||
total_s = time.perf_counter() - self._preload_t_start
|
||||
logger.debug(f"[preload] ============================================================")
|
||||
logger.debug(f"[preload] complete: {self._preload_done} loaded, "
|
||||
f"{self._preload_failed} failed, "
|
||||
f"{self._preload_skipped_runtime} skipped (user beat us to it) "
|
||||
f"in {total_s:.2f}s")
|
||||
logger.debug(f"[preload] cached pages now: {sorted(self._instances.keys())}")
|
||||
logger.debug(f"[preload] ============================================================")
|
||||
pass
|
||||
# total_s = time.perf_counter() - self._preload_t_start
|
||||
# logger.debug(f"[preload] ============================================================")
|
||||
# logger.debug(f"[preload] complete: {self._preload_done} loaded, "
|
||||
# f"{self._preload_failed} failed, "
|
||||
# f"{self._preload_skipped_runtime} skipped (user beat us to it) "
|
||||
# f"in {total_s:.2f}s")
|
||||
# logger.debug(f"[preload] cached pages now: {sorted(self._instances.keys())}")
|
||||
# logger.debug(f"[preload] ============================================================")
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ class CurrencySelectionPage(Page):
|
|||
|
||||
# get the singleton (this was created on a previous page)
|
||||
print("doing the new method")
|
||||
data_result = get_current_billing_data()
|
||||
data_result = get_current_billing_data(profile_id=profile_id)
|
||||
|
||||
if not data_result.valid:
|
||||
message = data_result.message
|
||||
|
|
|
|||
|
|
@ -89,7 +89,8 @@ class DurationSelectionPage(Page):
|
|||
plan_id = self.dict_of_choices[current_choice]
|
||||
|
||||
# save to singleton across pages:
|
||||
data_result = get_current_billing_data(category=PaymentCategory.INDIVIDUAL)
|
||||
profile_id = int(self.update_status.current_profile_id)
|
||||
data_result = get_current_billing_data(category=PaymentCategory.INDIVIDUAL, profile_id=profile_id)
|
||||
|
||||
if not data_result.valid:
|
||||
message = data_result.message
|
||||
|
|
|
|||
|
|
@ -759,12 +759,13 @@ class MenuPage(Page):
|
|||
self.update_action_button_visuals(profile_id)
|
||||
|
||||
@mainthread
|
||||
def turn_off_session_visuals(self, profile_id: int):
|
||||
def turn_off_session_visuals(self, profile_id: int, surpress_output: Optional[bool] = False):
|
||||
"""
|
||||
Flip off the Visual buttons for a given profile.
|
||||
And re-enable the edit button if its currently selected.
|
||||
"""
|
||||
print(f"Stopping Session {profile_id}!")
|
||||
if not surpress_output:
|
||||
print(f"Stopping Session {profile_id}!")
|
||||
# If you want the border to stay when off, set is_active=True
|
||||
# If you want the border to disappear when off, set is_active=False
|
||||
self._update_profile_icon(profile_id, self.not_connected_profile, is_active=True)
|
||||
|
|
@ -853,4 +854,4 @@ class MenuPage(Page):
|
|||
else:
|
||||
# DEFAULT STARTING PLACE:
|
||||
# If it's not system-wide and not a session, it must be off.
|
||||
self.turn_off_session_visuals(pid)
|
||||
self.turn_off_session_visuals(profile_id=pid, surpress_output=True)
|
||||
|
|
|
|||
|
|
@ -415,7 +415,7 @@ class PaymentDetailsPage(Page):
|
|||
)
|
||||
|
||||
# get the singleton (this was created on a previous page)
|
||||
data_result = get_current_billing_data()
|
||||
data_result = get_current_billing_data(profile_id=self.profile_id)
|
||||
|
||||
if not data_result.valid:
|
||||
message = data_result.message
|
||||
|
|
|
|||
Loading…
Reference in a new issue