diff --git a/gui/v2/actions/error_handlers.py b/gui/v2/actions/error_handlers.py index a9fb72b..8bebf8d 100644 --- a/gui/v2/actions/error_handlers.py +++ b/gui/v2/actions/error_handlers.py @@ -13,3 +13,7 @@ def empty_filler(result: Result) -> Result: def evaluate_bad_state() -> Result: """Start core's evaluation of state with a GUI observer.""" return coordinate_evaluation(connection_observer=connection_observer) + +@register_action(ResultError.SUBSCRIPTION) +def navigate_to_new_sub_page() -> Result: + return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="id") diff --git a/gui/v2/actions/menu_coordinator.py b/gui/v2/actions/menu_coordinator.py index b18c73f..4524e49 100644 --- a/gui/v2/actions/menu_coordinator.py +++ b/gui/v2/actions/menu_coordinator.py @@ -21,6 +21,7 @@ from gui.v2.infrastructure.setup_observers import ( application_version_observer, connection_observer, profile_observer, ticket_observer, ) +from gui.v2.actions.error_handlers import navigate_to_new_sub_page # generic from typing import Callable, Optional @@ -34,21 +35,6 @@ def get_profile(profile_id: int): return Result(valid=True, data=profile) -@register_action(ResultError.SUBSCRIPTION) -def navigate_to_new_sub_page() -> Result: - return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="id") - - -@register_action(ResultError.EXPIRED_SUB) -def wipe_expired_subscription(profile_id: int) -> Result: - """Call core to wipe a subscription, then navigate to the billing page""" - wiped = wipe_subscription(profile_id) - if wiped.valid: - return navigate_to_new_sub_page() - else: - return wiped - - @register_action(ResultError.NO_TICKET) def start_and_navigate_to_ticketing(): """Starts a new ticketing cycle. (assumes the user opted in).""" diff --git a/gui/v2/actions/payment_actions.py b/gui/v2/actions/payment_actions.py index 6d284dc..e3399b9 100644 --- a/gui/v2/actions/payment_actions.py +++ b/gui/v2/actions/payment_actions.py @@ -4,11 +4,14 @@ from core.services.payment_phase.check_payment_loop import CheckPaidTimer from core.services.subscriptions.subscriptions_by_protocol import ( create_new_invoice, save_billing_code, get_profile_subscription, wipe_billing_cycle, - start_new_payment_cycle + start_new_payment_cycle, return_pre_existing_invoice, + wipe_subscription, ) from core.models.enum_models import PaymentType, PaymentCategory from core.models.Result import Result, ResultError from core.errors.logger import logger +from core.utils.type_checker import type_checker + # gui from gui.v2.infrastructure.action_registry import register_action @@ -16,11 +19,56 @@ from gui.v2.actions.ticket_actions import fetch_ticket_invoice from gui.v2.infrastructure.ThreadSafetyTool import ThreadSafetyTool from gui.v2.infrastructure.take_plumbing_action import take_action from gui.v2.infrastructure.setup_observers import connection_observer -from core.utils.type_checker import type_checker +from gui.v2.actions.error_handlers import navigate_to_new_sub_page # generic from typing import Callable, Optional + + +def _wipe_and_navigate(profile_id: Optional[int] = None): + cleared_cycle = wipe_billing_cycle(profile_id) + if cleared_cycle: + return navigate_to_new_sub_page() + else: + return cleared_cycle + + + +@register_action(ResultError.EXPIRED_INVOICE) +def reset_individual_billing_cycle() -> Result: + payment_cycle = OverallPaymentCycle() + + if not payment_cycle.category == PaymentCategory.INDIVIDUAL: + return Result(valid=False, error_type=ResultError.INVALID_INPUT, message="This function isn't for tickets.") + + billing_data = payment_cycle.billing_data + + if not billing_data: + return _wipe_and_navigate() + + profile_id = billing_data.instance_id + + if profile_id: + return wipe_subscription(profile_id) + else: + return _wipe_and_navigate() + + +@register_action(ResultError.EXPIRED_SUB) +def wipe_expired_subscription(profile_id: int) -> Result: + """Call core to wipe a subscription, then navigate to the billing page""" + logger.info(f"Wiping the subscription for {profile_id}") + + wiped_result = wipe_subscription(profile_id) + if wiped_result.valid: + logger.info("Successfully wiped") + # also clear the whole billing cycle, so it's ready for an individual purchase, + return _wipe_and_navigate(profile_id) + else: + return wiped_result + + @type_checker def start_individual_payment(profile_id: int, ui_caller: Callable) -> Result: logger.info(f"Attempting to start individual billing state for profile {str(profile_id)}") @@ -140,8 +188,7 @@ def stop_payment_timer() -> Result: error_msg = f"Unable to stop the payment timer: {str(e)}" logger.error(error_msg) return Result(valid=False, error_type=ResultError.UNKNOWN, message=error_msg) - - + diff --git a/gui/v2/actions/ticket_actions.py b/gui/v2/actions/ticket_actions.py index fac026d..d129d88 100644 --- a/gui/v2/actions/ticket_actions.py +++ b/gui/v2/actions/ticket_actions.py @@ -4,6 +4,7 @@ from core.models.BaseProfile import BaseProfile as Profile from core.controllers.ProfileController import ProfileController 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.models.enum_models import PaymentCategory from core.services.prepare_tickets.ticket_tracker import get_all_unused_tickets @@ -11,6 +12,7 @@ from core.models.Result import Result, ResultError from core.errors.logger import logger # 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 @@ -122,6 +124,11 @@ class TicketUser(): self.ui_caller(result) -def wipe_ticket_billing(): +@register_action(ResultError.TICKET_EXPIRED) +def wipe_ticket_billing() -> Result: """Wipe existing data and start over.""" - \ No newline at end of file + 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") diff --git a/gui/v2/infrastructure/action_registry.py b/gui/v2/infrastructure/action_registry.py index 4136b65..0e60ab3 100644 --- a/gui/v2/infrastructure/action_registry.py +++ b/gui/v2/infrastructure/action_registry.py @@ -7,6 +7,7 @@ ENUM_MAP = { ResultError.UNKNOWN: None, ResultError.NEED_SYNC: (new_sync), ResultError.ACTIVE_BILLING: (wipe_billing_cycle), + ResultError.EXPIRED_INVOICE: (wipe_billing_cycle), ResultError.INVALID_API_REPLY: None, ResultError.ENCRYPTION: None } diff --git a/gui/v2/ui/pages/id_page.py b/gui/v2/ui/pages/id_page.py index 9608669..a0c9558 100755 --- a/gui/v2/ui/pages/id_page.py +++ b/gui/v2/ui/pages/id_page.py @@ -18,7 +18,7 @@ from gui.v2.ui.pages.Page import Page from gui.v2.ui.popups.message_box import style_message_box, mark_confirm_button from gui.v2.actions.menu_tasks import enable_profile from gui.v2.actions.payment_actions import start_individual_payment -from gui.v2.actions.ticket_actions import start_ticket +from gui.v2.actions.ticket_actions import start_ticket, fetch_ticket_invoice HOW_MANY_PROFILES_DEFAULT = 6 diff --git a/gui/v2/ui/pages/payments2.py b/gui/v2/ui/pages/payments2.py index 7b66d11..ddcadb6 100644 --- a/gui/v2/ui/pages/payments2.py +++ b/gui/v2/ui/pages/payments2.py @@ -189,6 +189,7 @@ class PaymentDetailsPage(Page): # this is not used here, but this is the right place to put it. Since we should have it by now: self.currency = self._get_currency() if not self.currency: + self.custom_window.navigator.navigate("currency_selection") return # error is already displayed in subfunction. # launches background thread tasks: @@ -223,6 +224,8 @@ class PaymentDetailsPage(Page): if message: self.show_a_popup(str(message)) + self.custom_window.navigator.navigate("menu") + # # Turn it back on if off: # else: # self.begin_invoice() @@ -283,6 +286,7 @@ class PaymentDetailsPage(Page): if not invoice: self.show_a_popup("Missing Invoice from API call's data") + self.custom_window.navigator.navigate("id") return # Fill in UI: @@ -431,8 +435,8 @@ class PaymentDetailsPage(Page): currency = billing_singleton.currency if not currency: - self.show_a_popup('Missing Currency') - + return None + # self.show_a_popup('Missing Currency') if not isinstance(currency, Currency): self.display_error(