forked from Support/sp-hydra-veil-gui
Individual Profile Payments Bigbang is now Stable. It allows for detached payment checks with proper error prompts, if users try to open a 2nd individual payments. Additionally we introduced core's threading plumbing, with a registry wrapper for actions to be routed to automatically on error prompt
This commit is contained in:
parent
20f405e878
commit
1308b025c2
11 changed files with 485 additions and 230 deletions
72
gui/v2/actions/menu_coordinator.py
Normal file
72
gui/v2/actions/menu_coordinator.py
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
from core.services.subscriptions.subscriptions_by_protocol import get_profile_subscription, start_new_payment_cycle
|
||||||
|
from core.models.enum_models import PaymentCategory
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
from gui.v2.infrastructure.take_plumbing_action import take_action
|
||||||
|
|
||||||
|
# generic
|
||||||
|
from typing import Callable, Optional
|
||||||
|
|
||||||
|
|
||||||
|
def confirm_prereqs(PRE_REQS: list, allow_false: Optional[bool] = False) -> Result:
|
||||||
|
for each_prereq in PRE_REQS:
|
||||||
|
if allow_false:
|
||||||
|
if each_prereq == None:
|
||||||
|
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=f"You are missing {each_prereq}")
|
||||||
|
else:
|
||||||
|
if not each_prereq:
|
||||||
|
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=f"You are missing {each_prereq}")
|
||||||
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
|
def filter_subscription(profile_id: int) -> Result:
|
||||||
|
"""Evaluate if this profile has a subscription that's ready to connect."""
|
||||||
|
|
||||||
|
logger.info(f"Checking the subscription on profile id {profile_id}")
|
||||||
|
subscription = get_profile_subscription(profile_id=profile_id)
|
||||||
|
|
||||||
|
if not subscription or not subscription.billing_code:
|
||||||
|
# auto check tickets would be here.
|
||||||
|
return Result(valid=False, error_type=ResultError.NAVIGATE_TO, navigate_to="id", message="No subscription. Pick a payment method.")
|
||||||
|
|
||||||
|
if subscription.billing_pending:
|
||||||
|
start_result = start_new_payment_cycle(category=PaymentCategory.INDIVIDUAL, profile_id=profile_id)
|
||||||
|
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="payment_details", message="Finish the subscription payment")
|
||||||
|
else:
|
||||||
|
logger.info(f"Returning the error of start_result {start_result}")
|
||||||
|
return start_result
|
||||||
|
|
||||||
|
# has a valid sub:
|
||||||
|
logger.info(f"Profile id {profile_id} has a valid subscription ready to go..")
|
||||||
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _connect_profile(profile_id: int) -> Result:
|
||||||
|
# Step 1: Subscription filter:
|
||||||
|
sub_result = filter_subscription(profile_id=profile_id)
|
||||||
|
if not sub_result.valid:
|
||||||
|
return sub_result
|
||||||
|
|
||||||
|
# fake connection
|
||||||
|
logger.info(f"Profile id {profile_id} is ready to connect..")
|
||||||
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
|
def connect_profile(profile_id: int, ui_caller: Callable) -> Result:
|
||||||
|
PRE_REQS = [profile_id, ui_caller]
|
||||||
|
|
||||||
|
confirmed_result = confirm_prereqs(PRE_REQS)
|
||||||
|
if not confirmed_result.valid:
|
||||||
|
return confirmed_result
|
||||||
|
|
||||||
|
take_action(
|
||||||
|
action=_connect_profile,
|
||||||
|
ui_caller=ui_caller,
|
||||||
|
profile_id=profile_id
|
||||||
|
)
|
||||||
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
|
from core.services.subscriptions.subscriptions_by_protocol import get_profile_subscription
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import Any, Iterable, Mapping
|
from typing import Any, Iterable, Mapping
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt
|
from PyQt6.QtCore import Qt
|
||||||
|
|
||||||
from gui.v2.actions.menu_results import MenuCallback
|
from gui.v2.actions.menu_results import MenuCallback
|
||||||
from gui.v2.actions.profile_operations import execute_menu_task
|
from gui.v2.actions.profile_operations import execute_menu_task
|
||||||
from gui.v2.infrastructure.screen_size import get_max_screensize
|
from gui.v2.infrastructure.screen_size import get_max_screensize
|
||||||
|
|
@ -29,6 +33,14 @@ def _start_task(request: Mapping[str, Any], on_result: MenuCallback) -> Worker:
|
||||||
return worker
|
return worker
|
||||||
|
|
||||||
|
|
||||||
|
def pre_connect_clear(profile_id: int) -> Result:
|
||||||
|
subscription = get_profile_subscription(profile_id=profile_id)
|
||||||
|
if not subscription or not subscription.billing_code:
|
||||||
|
return Result(valid=False, error_type=ResultError.SUBSCRIPTION, message="No Subscription")
|
||||||
|
|
||||||
|
return Result(valid=True)
|
||||||
|
|
||||||
|
|
||||||
def enable_profile(profile_data: Mapping[str, Any], on_result: MenuCallback, allow_uninstalled_tor: bool = False) -> Worker:
|
def enable_profile(profile_data: Mapping[str, Any], on_result: MenuCallback, allow_uninstalled_tor: bool = False) -> Worker:
|
||||||
"""Start the complete activation workflow with billing and retry data kept in one request."""
|
"""Start the complete activation workflow with billing and retry data kept in one request."""
|
||||||
return _start_task({**profile_data, "task": "enable", "allow_uninstalled_tor": allow_uninstalled_tor}, on_result)
|
return _start_task({**profile_data, "task": "enable", "allow_uninstalled_tor": allow_uninstalled_tor}, on_result)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
# core
|
# core
|
||||||
from core.services.payment_phase.payment_state import OverallPaymentCycle, PaymentData, TicketPaymentData
|
from core.services.payment_phase.payment_state import OverallPaymentCycle, PaymentData, TicketPaymentData
|
||||||
from core.services.payment_phase.check_payment_loop import CheckPaidTimer
|
from core.services.payment_phase.check_payment_loop import CheckPaidTimer
|
||||||
from core.services.subscriptions.subscriptions_by_protocol import create_individual_invoice, save_billing_code, get_profile_subscription, start_billing_state, wipe_billing_cycle
|
from core.services.subscriptions.subscriptions_by_protocol import (
|
||||||
|
create_new_invoice, save_billing_code,
|
||||||
|
get_profile_subscription, wipe_billing_cycle
|
||||||
|
)
|
||||||
from core.models.enum_models import PaymentType, PaymentCategory
|
from core.models.enum_models import PaymentType, PaymentCategory
|
||||||
from core.models.Result import Result, ResultError
|
from core.models.Result import Result, ResultError
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
|
|
||||||
# gui
|
# gui
|
||||||
|
from gui.v2.infrastructure.action_registry import register_action
|
||||||
from gui.v2.actions.ticket_actions import fetch_ticket_invoice
|
from gui.v2.actions.ticket_actions import fetch_ticket_invoice
|
||||||
from gui.v2.infrastructure.ThreadSafetyTool import ThreadSafetyTool
|
from gui.v2.infrastructure.ThreadSafetyTool import ThreadSafetyTool
|
||||||
from gui.v2.infrastructure.take_plumbing_action import take_action
|
from gui.v2.infrastructure.take_plumbing_action import take_action
|
||||||
|
|
@ -16,16 +20,6 @@ from gui.v2.infrastructure.setup_observers import connection_observer
|
||||||
from typing import Callable, Optional
|
from typing import Callable, Optional
|
||||||
|
|
||||||
|
|
||||||
def new_individual_billing(profile_id: int):
|
|
||||||
"""Wipes pre-existing global payment cycle. And Calls upon core to setup a new individual profile cycle & data state."""
|
|
||||||
logger.info("starting a new individual profile state. And wiping the old one")
|
|
||||||
return start_billing_state(
|
|
||||||
category=PaymentCategory.INDIVIDUAL,
|
|
||||||
profile_id=profile_id,
|
|
||||||
wipe_existing=True
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def gui_starts_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable, profile_id: Optional[int] = None) -> str | None:
|
def gui_starts_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable, profile_id: Optional[int] = None) -> str | None:
|
||||||
|
|
||||||
logger.info(f"gui_starts_invoice is being called with profile id {profile_id}")
|
logger.info(f"gui_starts_invoice is being called with profile id {profile_id}")
|
||||||
|
|
@ -33,103 +27,62 @@ def gui_starts_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callabl
|
||||||
# Is there currently a process?
|
# Is there currently a process?
|
||||||
payment_cycle = OverallPaymentCycle()
|
payment_cycle = OverallPaymentCycle()
|
||||||
|
|
||||||
# start a new individual one if not existing:
|
|
||||||
if not payment_cycle:
|
if not payment_cycle:
|
||||||
logger.info("There's no current payment cycle")
|
error_msg = "There is no payment cycle yet"
|
||||||
if profile_id:
|
logger.error(error_msg)
|
||||||
return fetch_individual_invoice(invoice_ui_caller=invoice_ui_caller, timer_resume_caller=timer_resume_caller, profile_id=profile_id)
|
return error_msg
|
||||||
|
|
||||||
|
if not payment_cycle.active:
|
||||||
|
error_msg = "Process is not yet active"
|
||||||
|
logger.error(error_msg)
|
||||||
|
return error_msg
|
||||||
|
|
||||||
|
if payment_cycle.got_invoice:
|
||||||
|
print("Cycle already got an invoice")
|
||||||
|
billing_code = payment_cycle.billing_code
|
||||||
|
|
||||||
|
if not billing_code:
|
||||||
|
error_msg = "Did not save the invoice from last time."
|
||||||
|
logger.error(error_msg)
|
||||||
|
# insert function here to get it via the data inside.
|
||||||
|
return error_msg
|
||||||
else:
|
else:
|
||||||
return "Need a profile id for an individual profile."
|
return return_pre_existing_invoice(billing_code=billing_code, connection_observer=connection_observer)
|
||||||
|
|
||||||
billing_data = payment_cycle.instance
|
|
||||||
category = payment_cycle.category
|
|
||||||
|
|
||||||
if not billing_data:
|
|
||||||
msg = "There is a payment cycle, but no current billing data in it. So we're starting a new cycle.."
|
|
||||||
logger.info(msg)
|
|
||||||
result = new_individual_billing(profile_id=profile_id)
|
|
||||||
if not result.valid:
|
|
||||||
return result
|
|
||||||
billing_data = result.data
|
|
||||||
|
|
||||||
#----------------------------
|
|
||||||
# INVOICE DATA
|
|
||||||
#----------------------------
|
|
||||||
if category == PaymentCategory.INDIVIDUAL:
|
|
||||||
# already conflicting one:
|
|
||||||
if not profile_id:
|
|
||||||
return "Need a profile id for an individual profile."
|
|
||||||
|
|
||||||
if profile_id != payment_cycle.profile_id:
|
|
||||||
logger.info("The new profile id request is different than the pre-existing running one. So we're wiping it and stopping the timer.")
|
|
||||||
worked, message = stop_payment_timer()
|
|
||||||
if not worked:
|
|
||||||
return message
|
|
||||||
|
|
||||||
# start over:
|
|
||||||
payment_cycle.wipe()
|
|
||||||
new_data = new_individual_billing(profile_id)
|
|
||||||
if not new_data.valid:
|
|
||||||
return new_data # result object
|
|
||||||
category = PaymentCategory.INDIVIDUAL
|
|
||||||
# billing_data = new_cycle.data
|
|
||||||
|
|
||||||
return fetch_individual_invoice(invoice_ui_caller=invoice_ui_caller, timer_resume_caller=timer_resume_caller, profile_id=profile_id)
|
|
||||||
|
|
||||||
|
|
||||||
elif category == PaymentCategory.TICKET:
|
|
||||||
logger.info("Starting ticketing invoicing..")
|
|
||||||
return fetch_ticket_invoice(invoice_ui_caller=invoice_ui_caller, timer_resume_caller=timer_resume_caller)
|
|
||||||
|
|
||||||
|
|
||||||
def fetch_individual_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable, profile_id: int) -> str | None:
|
|
||||||
"""
|
|
||||||
Purpose:
|
|
||||||
Create a new invoice if we don't have one yet, or re-uses the saved data.
|
|
||||||
And starts polling if it's not already.
|
|
||||||
|
|
||||||
Context:
|
|
||||||
For individual profiles.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Returns any errors as strings for UI to display.
|
|
||||||
"""
|
|
||||||
# Fetch:
|
|
||||||
take_action(
|
take_action(
|
||||||
action=create_individual_invoice,
|
action=create_new_invoice,
|
||||||
ui_caller=invoice_ui_caller,
|
ui_caller=invoice_ui_caller,
|
||||||
profile_id=profile_id,
|
# profile_id=profile_id,
|
||||||
connection_observer=connection_observer
|
connection_observer=connection_observer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def start_polling(billing_code: str, profile_id: int, ui_caller: Callable) -> str | None:
|
||||||
|
"""Kickstart an independent timer on a background thread to check if it's paid."""
|
||||||
|
|
||||||
|
payment_cycle = OverallPaymentCycle()
|
||||||
|
|
||||||
|
if not payment_cycle.active:
|
||||||
|
logger.error("Not yet active to start polling.")
|
||||||
|
|
||||||
#----------------------------
|
#----------------------------
|
||||||
# FILTER ALREADY POLLING
|
# FILTER ALREADY POLLING
|
||||||
#----------------------------
|
#----------------------------
|
||||||
payment_cycle = OverallPaymentCycle()
|
|
||||||
if payment_cycle.already_polling:
|
if payment_cycle.already_polling:
|
||||||
logger.info("This cycle is already polling, so we don't need to start another poll")
|
error_msg = "This cycle is already polling, so we don't need to start another poll"
|
||||||
|
logger.info(error_msg)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
#----------------------------
|
#----------------------------
|
||||||
# FILTER LACK OF DATA
|
# FILTER LACK OF DATA
|
||||||
#----------------------------
|
#----------------------------
|
||||||
subscription = get_profile_subscription(profile_id)
|
if not billing_code:
|
||||||
|
return "Requires a billing code"
|
||||||
if not subscription:
|
|
||||||
logger.info(f"Started a New Invoice for Profile {profile_id}..")
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not subscription.billing_pending:
|
|
||||||
logger.error("This function should not have been called if the invoice is already paid.")
|
|
||||||
return "Invoice already paid."
|
|
||||||
|
|
||||||
if not subscription.billing_code:
|
|
||||||
return "Previous subscription didn't have a billing code."
|
|
||||||
|
|
||||||
#----------------------------
|
#----------------------------
|
||||||
# CHECK PAID ON PRE-EXISTING INVOICE
|
# CHECK PAID ON PRE-EXISTING INVOICE
|
||||||
#----------------------------
|
#----------------------------
|
||||||
logger.info("Resuming a pre-existing payment..")
|
logger.info("Starting a check paid timer..")
|
||||||
|
|
||||||
# Setup PyQt6 GUI as mainthread to bring back to:
|
# Setup PyQt6 GUI as mainthread to bring back to:
|
||||||
pyqt_threader = ThreadSafetyTool()
|
pyqt_threader = ThreadSafetyTool()
|
||||||
|
|
@ -140,63 +93,21 @@ def fetch_individual_invoice(invoice_ui_caller: Callable, timer_resume_caller: C
|
||||||
# setup the timer with the callback:
|
# setup the timer with the callback:
|
||||||
# it doesn't return result here. It calls the view_callback function.
|
# it doesn't return result here. It calls the view_callback function.
|
||||||
check_paid_timer = CheckPaidTimer(
|
check_paid_timer = CheckPaidTimer(
|
||||||
view_callback=timer_resume_caller,
|
view_callback=ui_caller,
|
||||||
billing_code=subscription.billing_code,
|
billing_code=billing_code,
|
||||||
ui_dispatcher=pyqt_threader,
|
ui_dispatcher=pyqt_threader,
|
||||||
payment_type=PaymentType.CRYPTO,
|
payment_type=PaymentType.CRYPTO,
|
||||||
connection_observer=connection_observer,
|
connection_observer=connection_observer,
|
||||||
profile_id=profile_id
|
profile_id=profile_id
|
||||||
)
|
)
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def save_and_begin_timer(
|
|
||||||
ticketing: bool,
|
|
||||||
gui_callback: Callable,
|
|
||||||
billing_code: str,
|
|
||||||
profile_id: Optional[int] = None,
|
|
||||||
expires_at: Optional[str] = None,
|
|
||||||
) -> bool:
|
|
||||||
"""
|
|
||||||
First saves the billing code & profile expiration, if it's an individual (non-ticket) crypto-based one.
|
|
||||||
Then it Starts a loop of checking if the invoice is paid and saves it.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if ticketing:
|
|
||||||
payment_type = PaymentType.TICKET
|
|
||||||
logger.error("Ticketing already saves the billing code on it's own when it recieves it.")
|
|
||||||
|
|
||||||
# NON-ticketing:
|
|
||||||
elif profile_id and expires_at:
|
|
||||||
payment_type = PaymentType.CRYPTO
|
|
||||||
saved = save_billing_code(profile_id=profile_id, billing_code=billing_code, expires_at=expires_at)
|
|
||||||
if not saved.valid:
|
|
||||||
return False
|
|
||||||
else:
|
|
||||||
logger.error("You need a profile id and expires_at for individual profiles")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Setup PyQt6 GUI as mainthread to bring back to:
|
|
||||||
pyqt_threader = ThreadSafetyTool()
|
|
||||||
|
|
||||||
# setup the timer with the callback:
|
|
||||||
# it doesn't return result here. It calls the gui_callback function.
|
|
||||||
check_paid_timer = CheckPaidTimer(
|
|
||||||
view_callback=gui_callback,
|
|
||||||
billing_code=billing_code,
|
|
||||||
ui_dispatcher=pyqt_threader,
|
|
||||||
payment_type=payment_type,
|
|
||||||
connection_observer=connection_observer,
|
|
||||||
profile_id=profile_id
|
|
||||||
)
|
|
||||||
logger.info("starting polling from GUI action..")
|
|
||||||
check_paid_timer.start_polling()
|
check_paid_timer.start_polling()
|
||||||
return True # this is just that it started
|
return None
|
||||||
|
|
||||||
|
|
||||||
def stop_payment_timer() -> tuple:
|
@register_action(ResultError.ACTIVE_BILLING)
|
||||||
|
def stop_payment_timer() -> Result:
|
||||||
"""Gets the single instance of the payment checker timer, and stops it."""
|
"""Gets the single instance of the payment checker timer, and stops it."""
|
||||||
|
logger.info("Stopping the check paid timer & wiping the cycle..")
|
||||||
try:
|
try:
|
||||||
# Wipe the cycle, so this is not the active poller (blocking others)
|
# Wipe the cycle, so this is not the active poller (blocking others)
|
||||||
wipe_billing_cycle()
|
wipe_billing_cycle()
|
||||||
|
|
@ -207,12 +118,174 @@ def stop_payment_timer() -> tuple:
|
||||||
check_paid_timer.stop_polling()
|
check_paid_timer.stop_polling()
|
||||||
|
|
||||||
content_to_display = "Stopped! You can resume a different profile's invoice now"
|
content_to_display = "Stopped! You can resume a different profile's invoice now"
|
||||||
return True, content_to_display
|
return Result(valid=True, message=content_to_display)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
error_msg = f"Unable to stop the payment timer: {str(e)}"
|
error_msg = f"Unable to stop the payment timer: {str(e)}"
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
return False, error_msg
|
return Result(valid=False, error_type=ResultError.UNKNOWN, message=error_msg)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# def new_individual_billing(profile_id: int):
|
||||||
|
# """Wipes pre-existing global payment cycle. And Calls upon core to setup a new individual profile cycle & data state."""
|
||||||
|
# logger.info("starting a new individual profile state. And wiping the old one")
|
||||||
|
# return start_billing_state(
|
||||||
|
# category=PaymentCategory.INDIVIDUAL,
|
||||||
|
# profile_id=profile_id,
|
||||||
|
# wipe_existing=True
|
||||||
|
# )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# billing_data = payment_cycle.instance
|
||||||
|
# category = payment_cycle.category
|
||||||
|
|
||||||
|
# if not billing_data:
|
||||||
|
# msg = "There is a payment cycle, but no current billing data in it."
|
||||||
|
# print(msg)
|
||||||
|
# return msg
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# #----------------------------
|
||||||
|
# # INDIVIDUAL
|
||||||
|
# #----------------------------
|
||||||
|
# if category == PaymentCategory.INDIVIDUAL:
|
||||||
|
# # already conflicting one:
|
||||||
|
# if not profile_id:
|
||||||
|
# return "Need a profile id for an individual profile."
|
||||||
|
|
||||||
|
# take_action(
|
||||||
|
# action=create_individual_invoice,
|
||||||
|
# ui_caller=invoice_ui_caller,
|
||||||
|
# profile_id=profile_id,
|
||||||
|
# connection_observer=connection_observer
|
||||||
|
# )
|
||||||
|
# #----------------------------
|
||||||
|
# # TICKETS
|
||||||
|
# #----------------------------
|
||||||
|
# elif category == PaymentCategory.TICKET:
|
||||||
|
# logger.info("Starting ticketing invoicing..")
|
||||||
|
# take_action(
|
||||||
|
# action=create_individual_invoice,
|
||||||
|
# ui_caller=invoice_ui_caller,
|
||||||
|
# connection_observer=connection_observer
|
||||||
|
# )
|
||||||
|
|
||||||
|
# else:
|
||||||
|
# error_msg = "Unsupported Payment Category"
|
||||||
|
# logger.error(error_msg)
|
||||||
|
# return error_msg
|
||||||
|
|
||||||
|
# # Finally:
|
||||||
|
# payment_cycle.got_invoice = True
|
||||||
|
# return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# return fetch_individual_invoice(invoice_ui_caller=invoice_ui_caller, timer_resume_caller=timer_resume_caller, profile_id=profile_id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# # if profile_id != payment_cycle.profile_id:
|
||||||
|
# # logger.info("The new profile id request is different than the pre-existing running one. So we're wiping it and stopping the timer.")
|
||||||
|
# # worked, message = stop_payment_timer()
|
||||||
|
# # if not worked:
|
||||||
|
# # return message
|
||||||
|
|
||||||
|
# # # start over:
|
||||||
|
# # payment_cycle.wipe()
|
||||||
|
# # new_data = new_individual_billing(profile_id)
|
||||||
|
# # if not new_data.valid:
|
||||||
|
# # return new_data # result object
|
||||||
|
# # category = PaymentCategory.INDIVIDUAL
|
||||||
|
# # # billing_data = new_cycle.data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# elif category == PaymentCategory.TICKET:
|
||||||
|
# logger.info("Starting ticketing invoicing..")
|
||||||
|
# return fetch_ticket_invoice(invoice_ui_caller=invoice_ui_caller, timer_resume_caller=timer_resume_caller)
|
||||||
|
|
||||||
|
|
||||||
|
# def fetch_individual_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable, profile_id: int) -> str | None:
|
||||||
|
# """
|
||||||
|
# Purpose:
|
||||||
|
# Create a new invoice if we don't have one yet, or re-uses the saved data.
|
||||||
|
# And starts polling if it's not already.
|
||||||
|
|
||||||
|
# Context:
|
||||||
|
# For individual profiles.
|
||||||
|
|
||||||
|
# Returns:
|
||||||
|
# Returns any errors as strings for UI to display.
|
||||||
|
# """
|
||||||
|
# # Fetch:
|
||||||
|
# take_action(
|
||||||
|
# action=create_individual_invoice,
|
||||||
|
# ui_caller=invoice_ui_caller,
|
||||||
|
# profile_id=profile_id,
|
||||||
|
# connection_observer=connection_observer
|
||||||
|
# )
|
||||||
|
|
||||||
|
|
||||||
|
# def save_and_begin_timer(
|
||||||
|
# ticketing: bool,
|
||||||
|
# gui_callback: Callable,
|
||||||
|
# billing_code: str,
|
||||||
|
# profile_id: Optional[int] = None,
|
||||||
|
# expires_at: Optional[str] = None,
|
||||||
|
# ) -> bool:
|
||||||
|
# """
|
||||||
|
# First saves the billing code & profile expiration, if it's an individual (non-ticket) crypto-based one.
|
||||||
|
# Then it Starts a loop of checking if the invoice is paid and saves it.
|
||||||
|
# """
|
||||||
|
|
||||||
|
# if ticketing:
|
||||||
|
# payment_type = PaymentType.TICKET
|
||||||
|
# logger.error("Ticketing already saves the billing code on it's own when it recieves it.")
|
||||||
|
|
||||||
|
# # NON-ticketing:
|
||||||
|
# elif profile_id and expires_at:
|
||||||
|
# payment_type = PaymentType.CRYPTO
|
||||||
|
# saved = save_billing_code(profile_id=profile_id, billing_code=billing_code, expires_at=expires_at)
|
||||||
|
# if not saved.valid:
|
||||||
|
# return False
|
||||||
|
# else:
|
||||||
|
# logger.error("You need a profile id and expires_at for individual profiles")
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# # Setup PyQt6 GUI as mainthread to bring back to:
|
||||||
|
# pyqt_threader = ThreadSafetyTool()
|
||||||
|
|
||||||
|
# # setup the timer with the callback:
|
||||||
|
# # it doesn't return result here. It calls the gui_callback function.
|
||||||
|
# check_paid_timer = CheckPaidTimer(
|
||||||
|
# view_callback=gui_callback,
|
||||||
|
# billing_code=billing_code,
|
||||||
|
# ui_dispatcher=pyqt_threader,
|
||||||
|
# payment_type=payment_type,
|
||||||
|
# connection_observer=connection_observer,
|
||||||
|
# profile_id=profile_id
|
||||||
|
# )
|
||||||
|
# logger.info("starting polling from GUI action..")
|
||||||
|
# check_paid_timer.start_polling()
|
||||||
|
# return True # this is just that it started
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,12 @@ def _enable(request: dict[str, Any], emit: MenuCallback, max_resolution: str | N
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Skipping billing resume check")
|
print(f"Skipping billing resume check")
|
||||||
|
|
||||||
|
# print("checking sub")
|
||||||
|
# if not profile.subscription.billing:
|
||||||
|
# raise MissingSubscriptionError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print(f"checking preparation")
|
print(f"checking preparation")
|
||||||
|
|
||||||
preparation = _prepare_subscription(profile, request)
|
preparation = _prepare_subscription(profile, request)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from core.controllers.tickets.UseTicketController import use_ticket
|
||||||
from core.models.BaseProfile import BaseProfile as Profile
|
from core.models.BaseProfile import BaseProfile as Profile
|
||||||
from core.controllers.ProfileController import ProfileController
|
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_billing_state, save_subscription
|
from core.services.subscriptions.subscriptions_by_protocol import start_new_payment_cycle, save_subscription
|
||||||
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.models.enum_models import PaymentCategory
|
||||||
from core.services.prepare_tickets.ticket_tracker import get_all_unused_tickets
|
from core.services.prepare_tickets.ticket_tracker import get_all_unused_tickets
|
||||||
|
|
@ -21,50 +21,54 @@ from typing import Callable
|
||||||
def start_ticket(ui_caller: Callable) -> Result:
|
def start_ticket(ui_caller: Callable) -> Result:
|
||||||
logger.info("started ticketing billing state")
|
logger.info("started ticketing billing state")
|
||||||
return take_action(
|
return take_action(
|
||||||
action=start_billing_state,
|
action=start_new_payment_cycle,
|
||||||
ui_caller=ui_caller,
|
|
||||||
category=PaymentCategory.TICKET
|
category=PaymentCategory.TICKET
|
||||||
|
# ui_caller=ui_caller,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def fetch_ticket_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable) -> str | None:
|
def fetch_ticket_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable) -> str | None:
|
||||||
"""Start the Ticketing process on the background thread with the relevant billing data."""
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
logger.info("fetching ticket invoice..")
|
# def fetch_ticket_invoice(invoice_ui_caller: Callable, timer_resume_caller: Callable) -> str | None:
|
||||||
|
# """Start the Ticketing process on the background thread with the relevant billing data."""
|
||||||
|
|
||||||
payment_cycle = OverallPaymentCycle()
|
# logger.info("fetching ticket invoice..")
|
||||||
|
|
||||||
if not payment_cycle:
|
# payment_cycle = OverallPaymentCycle()
|
||||||
"No payment cycle, and therefore no data."
|
|
||||||
|
|
||||||
# already existing but wrong format:
|
# if not payment_cycle:
|
||||||
if payment_cycle.category != PaymentCategory.TICKET:
|
# "No payment cycle, and therefore no data."
|
||||||
return "Wrong payment cycle category."
|
|
||||||
|
|
||||||
billing_data = payment_cycle.instance
|
# # already existing but wrong format:
|
||||||
|
# if payment_cycle.category != PaymentCategory.TICKET:
|
||||||
|
# return "Wrong payment cycle category."
|
||||||
|
|
||||||
if not billing_data:
|
# billing_data = payment_cycle.instance
|
||||||
return "No billing data"
|
|
||||||
|
|
||||||
# if not isinstance(billing_data, TicketPaymentData):
|
# if not billing_data:
|
||||||
# return "Billing data in the wrong format."
|
# return "No billing data"
|
||||||
|
|
||||||
which_key = billing_data.which_key
|
# # if not isinstance(billing_data, TicketPaymentData):
|
||||||
currency = billing_data.currency
|
# # return "Billing data in the wrong format."
|
||||||
how_many_profiles = billing_data.how_many_profiles
|
|
||||||
|
|
||||||
# Fetch (this function will complain if missing data):
|
# which_key = billing_data.which_key
|
||||||
take_action(
|
# currency = billing_data.currency
|
||||||
action=initiate_payment,
|
# how_many_profiles = billing_data.how_many_profiles
|
||||||
ui_caller=invoice_ui_caller,
|
|
||||||
how_many_profiles=how_many_profiles,
|
# # Fetch (this function will complain if missing data):
|
||||||
which_key=which_key,
|
# take_action(
|
||||||
which_cryptocurrency=currency,
|
# action=initiate_payment,
|
||||||
ticket_observer=ticket_observer,
|
# ui_caller=invoice_ui_caller,
|
||||||
connection_observer=connection_observer,
|
# how_many_profiles=how_many_profiles,
|
||||||
bypass_existing=True,
|
# which_key=which_key,
|
||||||
)
|
# which_cryptocurrency=currency,
|
||||||
logger.info("Initiated payment")
|
# ticket_observer=ticket_observer,
|
||||||
|
# connection_observer=connection_observer,
|
||||||
|
# bypass_existing=True,
|
||||||
|
# )
|
||||||
|
# logger.info("Initiated payment")
|
||||||
|
|
||||||
|
|
||||||
def get_ticket_data() -> Result:
|
def get_ticket_data() -> Result:
|
||||||
|
|
|
||||||
40
gui/v2/infrastructure/action_registry.py
Normal file
40
gui/v2/infrastructure/action_registry.py
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
from core.controllers.SyncController import new_sync
|
||||||
|
|
||||||
|
# from gui.v2.actions.payment_actions import stop_payment_timer
|
||||||
|
|
||||||
|
ENUM_MAP = {
|
||||||
|
ResultError.UNKNOWN: None,
|
||||||
|
ResultError.NEED_SYNC: (new_sync),
|
||||||
|
ResultError.INVALID_API_REPLY: None,
|
||||||
|
ResultError.ENCRYPTION: None,
|
||||||
|
# ResultError.ACTIVE_BILLING: (stop_payment_timer),
|
||||||
|
}
|
||||||
|
|
||||||
|
def register_action(error_code):
|
||||||
|
def wrapper(func):
|
||||||
|
ENUM_MAP[error_code] = (func)
|
||||||
|
return func
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Add later potentially:
|
||||||
|
|
||||||
|
# ResultError.NO_TICKET: (start_billing),
|
||||||
|
# ResultError.NO_PROFILE: (go_to_new_profile_page),
|
||||||
|
# ResultError.ALREADY_EXISTS: (get_invoice), # bypass_existing: True
|
||||||
|
# ResultError.BILLING_CODE_EXISTS: (get_invoice) # bypass_existing: True
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Potential future upgrade to multiple error codes per function:
|
||||||
|
|
||||||
|
# def register_action(*error_codes):
|
||||||
|
# def wrapper(func):
|
||||||
|
# for code in error_codes:
|
||||||
|
# ACTION_REGISTRY[code] = func
|
||||||
|
# return func
|
||||||
|
# return wrapper
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
from core.infrastructure.plumbing import ThreadPlumbing
|
from core.infrastructure.plumbing import ThreadPlumbing
|
||||||
from core.models.Result import ResultError
|
from core.models.Result import ResultError
|
||||||
|
|
||||||
|
from gui.v2.infrastructure.action_registry import ENUM_MAP
|
||||||
from gui.v2.infrastructure.ThreadSafetyTool import ThreadSafetyTool
|
from gui.v2.infrastructure.ThreadSafetyTool import ThreadSafetyTool
|
||||||
from gui.v2.ui.popups.error_popup import ErrorPopup
|
from gui.v2.ui.popups.error_popup import ErrorPopup
|
||||||
|
|
||||||
|
|
@ -17,6 +19,7 @@ def take_action(action: Callable, ui_caller: Callable, *args, **kwargs):
|
||||||
action=action,
|
action=action,
|
||||||
ui_dispatcher=ThreadSafetyTool(), # PyQt6 as mainthread
|
ui_dispatcher=ThreadSafetyTool(), # PyQt6 as mainthread
|
||||||
error_implementation=ErrorPopup, # PyQt6 ErrorPopup
|
error_implementation=ErrorPopup, # PyQt6 ErrorPopup
|
||||||
|
ENUM_MAP=ENUM_MAP,
|
||||||
auto_navigate_dict=AUTO_NAVIGATE_REGISTRY,
|
auto_navigate_dict=AUTO_NAVIGATE_REGISTRY,
|
||||||
ui_caller=ui_caller,
|
ui_caller=ui_caller,
|
||||||
*args,
|
*args,
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@
|
||||||
from core.services.payment_phase.payment_state import PaymentData
|
from core.services.payment_phase.payment_state import PaymentData
|
||||||
from gui.v2.infrastructure.take_plumbing_action import take_action
|
from gui.v2.infrastructure.take_plumbing_action import take_action
|
||||||
from core.controllers.profile_state.data_filters import get_plans_for_profile
|
from core.controllers.profile_state.data_filters import get_plans_for_profile
|
||||||
from core.models.Result import Result #, ResultError
|
from core.services.subscriptions.subscriptions_by_protocol import get_current_billing_data
|
||||||
|
from core.models.enum_models import PaymentCategory
|
||||||
|
from core.models.Result import Result
|
||||||
|
|
||||||
# GUI
|
# GUI
|
||||||
from gui.v2.actions.payment_actions import new_individual_billing
|
# from gui.v2.actions.payment_actions import new_individual_billing
|
||||||
from gui.v2.ui.styles.payment_styles import DURATION_SELECTION_STYLE, NEXT_BUTTON_STYLE
|
from gui.v2.ui.styles.payment_styles import DURATION_SELECTION_STYLE, NEXT_BUTTON_STYLE
|
||||||
from gui.v2.ui.pages.Page import Page
|
from gui.v2.ui.pages.Page import Page
|
||||||
|
|
||||||
|
|
@ -52,19 +54,6 @@ class DurationSelectionPage(Page):
|
||||||
# get profile id:
|
# get profile id:
|
||||||
profile_id = int(self.update_status.current_profile_id)
|
profile_id = int(self.update_status.current_profile_id)
|
||||||
|
|
||||||
# start entire payment cycle process:
|
|
||||||
result = new_individual_billing(profile_id=profile_id)
|
|
||||||
if not result.valid:
|
|
||||||
self.show_a_popup(str(result.message))
|
|
||||||
return
|
|
||||||
|
|
||||||
# setup singleton
|
|
||||||
self.billing_data = result.data
|
|
||||||
# PaymentData(instance_id=profile_id)
|
|
||||||
|
|
||||||
if self.billing_data:
|
|
||||||
print(f"we have billing data: {self.billing_data}")
|
|
||||||
|
|
||||||
# Thread SQL in background:
|
# Thread SQL in background:
|
||||||
take_action(
|
take_action(
|
||||||
action=get_plans_for_profile,
|
action=get_plans_for_profile,
|
||||||
|
|
@ -100,13 +89,26 @@ class DurationSelectionPage(Page):
|
||||||
plan_id = self.dict_of_choices[current_choice]
|
plan_id = self.dict_of_choices[current_choice]
|
||||||
|
|
||||||
# save to singleton across pages:
|
# save to singleton across pages:
|
||||||
print(f"saving plan_id to the billing data")
|
data_result = get_current_billing_data(category=PaymentCategory.INDIVIDUAL)
|
||||||
self.billing_data.plan_id = plan_id
|
|
||||||
|
if not data_result.valid:
|
||||||
|
message = data_result.message
|
||||||
|
if not message:
|
||||||
|
message = "Error fetching data"
|
||||||
|
self.show_a_popup(str(message))
|
||||||
|
|
||||||
|
billing_data = data_result.data
|
||||||
|
|
||||||
|
if billing_data:
|
||||||
|
print(f"we have billing data: {billing_data}")
|
||||||
|
print(f"saving plan_id to the billing data")
|
||||||
|
billing_data.plan_id = plan_id
|
||||||
|
else:
|
||||||
|
message = "No Billing Data"
|
||||||
|
self.show_a_popup(message)
|
||||||
|
|
||||||
# go to next page:
|
# go to next page:
|
||||||
print("going to the next page")
|
print("going to the next page")
|
||||||
# currency_page = self.custom_window.navigator.get_cached("currency_selection")
|
|
||||||
# if currency_page is not None:
|
|
||||||
self.custom_window.navigator.navigate("currency_selection")
|
self.custom_window.navigator.navigate("currency_selection")
|
||||||
|
|
||||||
def reverse(self):
|
def reverse(self):
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ from PyQt6.QtGui import QIcon, QPixmap
|
||||||
from PyQt6.QtCore import Qt
|
from PyQt6.QtCore import Qt
|
||||||
from PyQt6 import QtCore
|
from PyQt6 import QtCore
|
||||||
|
|
||||||
from core.services.payment_phase.ticket_config_tools import do_we_have_billing_id
|
from core.services.subscriptions.subscriptions_by_protocol import start_new_payment_cycle
|
||||||
|
from core.models.enum_models import PaymentCategory
|
||||||
|
# from core.services.payment_phase.ticket_config_tools import do_we_have_billing_id
|
||||||
from core.services.prepare_tickets.ticket_tracker import delete_ticket_data
|
from core.services.prepare_tickets.ticket_tracker import delete_ticket_data
|
||||||
|
|
||||||
from gui.v2.ui.pages.Page import Page
|
from gui.v2.ui.pages.Page import Page
|
||||||
|
|
@ -152,14 +154,35 @@ class IdPage(Page):
|
||||||
self.separator_right.setGeometry(540, 60, 2, 420)
|
self.separator_right.setGeometry(540, 60, 2, 420)
|
||||||
self.separator_right.setStyleSheet(separator_style)
|
self.separator_right.setStyleSheet(separator_style)
|
||||||
|
|
||||||
|
|
||||||
def go_single_profile(self):
|
def go_single_profile(self):
|
||||||
self.text_edit.clear()
|
self.text_edit.clear()
|
||||||
self.custom_window.navigator.navigate("duration_selection")
|
print("starting a single profile payment cycle")
|
||||||
|
result = start_new_payment_cycle(
|
||||||
|
category=PaymentCategory.INDIVIDUAL,
|
||||||
|
profile_id=int(self.update_status.current_profile_id)
|
||||||
|
)
|
||||||
|
if not result:
|
||||||
|
print("no result.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if result.valid:
|
||||||
|
billing_code = result.data
|
||||||
|
print(f"billing_code is {billing_code}")
|
||||||
|
self.custom_window.navigator.navigate("duration_selection")
|
||||||
|
else:
|
||||||
|
self.show_a_popup(str(result.message))
|
||||||
|
|
||||||
def go_multiple_profiles(self):
|
def go_multiple_profiles(self):
|
||||||
billing_id = do_we_have_billing_id()
|
result = start_new_payment_cycle(
|
||||||
if billing_id:
|
category=PaymentCategory.TICKET,
|
||||||
self._prompt_existing_tickets(billing_id)
|
)
|
||||||
|
if not result.valid:
|
||||||
|
self.show_a_popup(str(result.message))
|
||||||
|
|
||||||
|
billing_code = result.billing_code
|
||||||
|
if billing_code:
|
||||||
|
self._prompt_existing_tickets(billing_code)
|
||||||
else:
|
else:
|
||||||
self._continue_multiple_flow()
|
self._continue_multiple_flow()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
import os
|
import os
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
@ -10,10 +12,12 @@ from PyQt6.QtWidgets import (
|
||||||
QMessageBox, QPushButton, QScrollArea, QTextEdit, QVBoxLayout, QWidget,
|
QMessageBox, QPushButton, QScrollArea, QTextEdit, QVBoxLayout, QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from gui.v2.actions.menu_coordinator import connect_profile
|
||||||
|
|
||||||
from gui.v2.actions.menu_profiles import find_verification_icon, get_profile_details, load_menu_profiles, menu_icons
|
from gui.v2.actions.menu_profiles import find_verification_icon, get_profile_details, load_menu_profiles, menu_icons
|
||||||
from gui.v2.actions.menu_tasks import (
|
from gui.v2.actions.menu_tasks import (
|
||||||
continue_menu_task, create_profile, delete_profile, disable_profile,
|
continue_menu_task, create_profile, delete_profile, disable_profile,
|
||||||
download_update, edit_profile, enable_profile,
|
download_update, edit_profile, enable_profile
|
||||||
)
|
)
|
||||||
from gui.v2.actions.menu_results import MenuResult
|
from gui.v2.actions.menu_results import MenuResult
|
||||||
from gui.v2.ui.pages.Page import Page
|
from gui.v2.ui.pages.Page import Page
|
||||||
|
|
@ -393,7 +397,10 @@ class MenuPage(Page):
|
||||||
|
|
||||||
def _render_profile_details(self, details):
|
def _render_profile_details(self, details):
|
||||||
self.reverse_id = details["id"]
|
self.reverse_id = details["id"]
|
||||||
|
|
||||||
|
# THIS IS UPDATING THE PROFILE ID
|
||||||
self.update_status.current_profile_id = self.reverse_id
|
self.update_status.current_profile_id = self.reverse_id
|
||||||
|
|
||||||
self.current_profile_location = details["location"]
|
self.current_profile_location = details["location"]
|
||||||
target_button = self.profile_button_map.get(self.reverse_id)
|
target_button = self.profile_button_map.get(self.reverse_id)
|
||||||
if target_button is not None:
|
if target_button is not None:
|
||||||
|
|
@ -514,12 +521,36 @@ class MenuPage(Page):
|
||||||
self.boton_edit.setEnabled(not busy and self.reverse_id is not None
|
self.boton_edit.setEnabled(not busy and self.reverse_id is not None
|
||||||
and not self.connection_manager.is_profile_connected(self.reverse_id))
|
and not self.connection_manager.is_profile_connected(self.reverse_id))
|
||||||
|
|
||||||
|
|
||||||
|
def handle_result(self, result: Result):
|
||||||
|
print(f"handle error got result {result}")
|
||||||
|
if result.error_type == ResultError.NAVIGATE_TO:
|
||||||
|
print(f"Navigating to page {result.navigate_to}")
|
||||||
|
self.custom_window.navigator.navigate(result.navigate_to)
|
||||||
|
|
||||||
|
elif result.error_type == ResultError.SUBSCRIPTION:
|
||||||
|
print("going to sub page")
|
||||||
|
self.update_status.update_status("Select Subscription Choice")
|
||||||
|
self.custom_window.navigator.navigate("id")
|
||||||
|
else:
|
||||||
|
error_type = result.error_type.value
|
||||||
|
print(f"handle_error was called, but we do not currently have a pre-made solution for the unknown situation of {error_type}")
|
||||||
|
self.update_status.update_status(error_type)
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
print(f"hit connect to enable profile. self.reverse_id is {self.reverse_id}")
|
print(f"hit connect to enable profile. self.reverse_id is {self.reverse_id}")
|
||||||
|
pre_thread_result = connect_profile(profile_id=self.reverse_id, ui_caller=self.handle_result)
|
||||||
|
|
||||||
|
if not pre_thread_result.valid:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Temporary until moved to menu coordinator:
|
||||||
|
print("connecting...")
|
||||||
self._set_task_busy(True)
|
self._set_task_busy(True)
|
||||||
self.update_status.update_status("Attempting to connect...")
|
self.update_status.update_status("Attempting to connect...")
|
||||||
self.worker = enable_profile({"id": self.reverse_id}, self.handle_task_result)
|
self.worker = enable_profile({"id": self.reverse_id}, self.handle_task_result)
|
||||||
|
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
self._set_task_busy(True)
|
self._set_task_busy(True)
|
||||||
self.update_status.update_status("Disconnecting...")
|
self.update_status.update_status("Disconnecting...")
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ from core.models.Result import Result
|
||||||
|
|
||||||
# GUI
|
# GUI
|
||||||
from gui.v2.actions.payment_actions import (
|
from gui.v2.actions.payment_actions import (
|
||||||
save_and_begin_timer,
|
start_polling,
|
||||||
gui_starts_invoice,
|
gui_starts_invoice,
|
||||||
stop_payment_timer,
|
stop_payment_timer,
|
||||||
)
|
)
|
||||||
|
|
@ -76,8 +76,8 @@ class PaymentDetailsPage(Page):
|
||||||
|
|
||||||
self.create_initial_elements()
|
self.create_initial_elements()
|
||||||
self.button_reverse.setVisible(True)
|
self.button_reverse.setVisible(True)
|
||||||
# self.begin_invoice()
|
|
||||||
|
|
||||||
|
# self.begin_invoice()
|
||||||
|
|
||||||
def showEvent(self, event):
|
def showEvent(self, event):
|
||||||
"""Refresh data. This runs every time the widget is displayed"""
|
"""Refresh data. This runs every time the widget is displayed"""
|
||||||
|
|
@ -183,11 +183,7 @@ class PaymentDetailsPage(Page):
|
||||||
print(f"profile_id is {self.profile_id}")
|
print(f"profile_id is {self.profile_id}")
|
||||||
|
|
||||||
if not self.ticketing and not self.profile_id:
|
if not self.ticketing and not self.profile_id:
|
||||||
self.display_error(
|
self.show_a_popup(f"Missing a profile id for an individual profile.")
|
||||||
whats_wrong=DataError.BLANK,
|
|
||||||
whats_it_called="Profile ID",
|
|
||||||
the_thing=profile_id,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# this is not used here, but this is the right place to put it. Since we should have it by now:
|
# this is not used here, but this is the right place to put it. Since we should have it by now:
|
||||||
|
|
@ -214,9 +210,11 @@ class PaymentDetailsPage(Page):
|
||||||
"""Toggle On/Off Polling"""
|
"""Toggle On/Off Polling"""
|
||||||
# If it's on:
|
# If it's on:
|
||||||
if self.polling:
|
if self.polling:
|
||||||
stopped, message = stop_payment_timer()
|
timer_result = stop_payment_timer()
|
||||||
|
|
||||||
if stopped:
|
message = timer_result.message
|
||||||
|
|
||||||
|
if not timer_result.valid:
|
||||||
self.update_status.update_status("Stopped checking!")
|
self.update_status.update_status("Stopped checking!")
|
||||||
self.stop_button.setDisabled(True)
|
self.stop_button.setDisabled(True)
|
||||||
self.switch_to_background_button.setDisabled(True)
|
self.switch_to_background_button.setDisabled(True)
|
||||||
|
|
@ -225,9 +223,9 @@ class PaymentDetailsPage(Page):
|
||||||
if message:
|
if message:
|
||||||
self.show_a_popup(str(message))
|
self.show_a_popup(str(message))
|
||||||
|
|
||||||
# Turn it back on if off:
|
# # Turn it back on if off:
|
||||||
else:
|
# else:
|
||||||
self.begin_invoice()
|
# self.begin_invoice()
|
||||||
|
|
||||||
def background_fetch_mode(self):
|
def background_fetch_mode(self):
|
||||||
"""Continue checking if paid, but navigate back to the menu page"""
|
"""Continue checking if paid, but navigate back to the menu page"""
|
||||||
|
|
@ -284,37 +282,22 @@ class PaymentDetailsPage(Page):
|
||||||
invoice = invoice_result.data
|
invoice = invoice_result.data
|
||||||
|
|
||||||
if not invoice:
|
if not invoice:
|
||||||
self.display_error(
|
self.show_a_popup("Missing Invoice from API call's data")
|
||||||
whats_wrong=DataError.BLANK,
|
|
||||||
whats_it_called="invoice",
|
|
||||||
the_thing=invoice,
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# if not isinstance(invoice, SubscriptionInvoice):
|
# Fill in UI:
|
||||||
# self.display_error(
|
|
||||||
# whats_wrong=DataError.FORMAT,
|
|
||||||
# whats_it_called="invoice",
|
|
||||||
# the_thing=invoice,
|
|
||||||
# )
|
|
||||||
# return
|
|
||||||
|
|
||||||
self.fill_in_invoice_data(invoice)
|
self.fill_in_invoice_data(invoice)
|
||||||
self.update_status.update_status("Invoice generated. Awaiting payment...")
|
|
||||||
|
|
||||||
# kick off the timer and save the billing id,
|
# Start polling:
|
||||||
saved_and_started = save_and_begin_timer(
|
error_msg = start_polling(
|
||||||
ticketing=paying_for_tickets(),
|
|
||||||
gui_callback=self.timer_updates_gui,
|
|
||||||
billing_code=invoice.billing_code,
|
billing_code=invoice.billing_code,
|
||||||
profile_id=int(self.update_status.current_profile_id),
|
profile_id=int(self.update_status.current_profile_id),
|
||||||
expires_at=invoice.expires_at,
|
ui_caller=self.timer_updates_gui
|
||||||
)
|
)
|
||||||
if not saved_and_started:
|
if error_msg:
|
||||||
self.show_a_popup(
|
self.show_a_popup(error_msg)
|
||||||
"The save and start checking if paid did not even begin. Please see the error logs/"
|
else:
|
||||||
)
|
self.update_status.update_status("Invoice generated. Awaiting payment...")
|
||||||
self.update_status.update_status("Could not begin")
|
|
||||||
|
|
||||||
def fill_in_invoice_data(self, invoice: SubscriptionInvoice):
|
def fill_in_invoice_data(self, invoice: SubscriptionInvoice):
|
||||||
"""Extract and populate invoice data into the labels"""
|
"""Extract and populate invoice data into the labels"""
|
||||||
|
|
@ -439,6 +422,8 @@ class PaymentDetailsPage(Page):
|
||||||
# get the singleton (this was created on a previous page)
|
# get the singleton (this was created on a previous page)
|
||||||
billing_singleton = data_result.data
|
billing_singleton = data_result.data
|
||||||
|
|
||||||
|
print(f"Inside payments screen GUI of _get_currency, the billing_singleton is {billing_singleton}")
|
||||||
|
|
||||||
if not billing_singleton:
|
if not billing_singleton:
|
||||||
message = "Error, no billing data"
|
message = "Error, no billing data"
|
||||||
self.show_a_popup(str(message))
|
self.show_a_popup(str(message))
|
||||||
|
|
@ -477,3 +462,7 @@ class PaymentDetailsPage(Page):
|
||||||
prep_page = self.custom_window.navigator.get_cached("ticket_prep")
|
prep_page = self.custom_window.navigator.get_cached("ticket_prep")
|
||||||
if prep_page is not None:
|
if prep_page is not None:
|
||||||
prep_page.start_prep()
|
prep_page.start_prep()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue