Plumbing stable for GUI to call upon via inserted ENUM DICT

This commit is contained in:
SimplifiedPrivacy 2026-10-13 21:19:49 -04:00
parent 69f4e7114f
commit 7ba8e1e6d3
4 changed files with 85 additions and 40 deletions

View file

@ -3,7 +3,7 @@ from core.infrastructure.error_popup import PopupProtocol
from core.infrastructure.service_registry import ServiceLocator
from core.models.Result import Result, ResultError
from core.infrastructure.action_registry import ENUM_MAP
# from core.infrastructure.action_registry import ENUM_MAP
from core.errors.logger import logger
# from infrastructure.observer_service import notify
@ -23,11 +23,12 @@ class ThreadPlumbing:
Manage Execution of functions on threads, and orchestrate their retries,
then pass the data through to popup prompts for the user to decide how to solve any error, by enum type.
"""
def __init__(self, action: Callable, ui_dispatcher: MainThreadDispatcher, error_implementation: Type[PopupProtocol], auto_navigate_dict: dict, ui_caller: Optional[Callable] = None, *args, **kwargs):
def __init__(self, action: Callable, ui_dispatcher: MainThreadDispatcher, error_implementation: Type[PopupProtocol], ENUM_MAP: dict, auto_navigate_dict: dict, ui_caller: Optional[Callable] = None, *args, **kwargs):
self.action = action
self.ui_dispatcher = ui_dispatcher
self.ui_caller = ui_caller
self.error_implementation = error_implementation
self.ENUM_MAP = ENUM_MAP
self.auto_navigate_dict = auto_navigate_dict
self.navigator = ServiceLocator.get("navigator")
self.args = args
@ -55,7 +56,7 @@ class ThreadPlumbing:
if not isinstance(result, Result):
result = convert_to_result(result)
if not result.valid:
result.function_choice = resolve_prescription(result, *self.args, **self.kwargs)
result.function_choice = resolve_prescription(result, self.ENUM_MAP, *self.args, **self.kwargs)
except Exception as e:
error_msg = f"There was an error: {str(e)}"
# notify(error_msg)
@ -121,7 +122,7 @@ def normalize_seq(s):
"""Ensures input is a tuple regardless of if it was a list or tuple."""
return tuple(s) if s is not None else ()
def resolve_prescription(result: Result, *args, **kwargs):
def resolve_prescription(result: Result, ENUM_MAP: dict, *args, **kwargs):
"""
Find the correct solution to the type of enum problem,
And then add the args from either the original caller's args,
@ -133,6 +134,7 @@ def resolve_prescription(result: Result, *args, **kwargs):
return result.function_choice
# Priority 2: Look up the Enum map
# logger.info(f"self.ENUM_MAP is {self.ENUM_MAP}")
if result.error_type not in ENUM_MAP:
return None # No solution

View file

@ -134,11 +134,13 @@ def api_call_and_extraction(
# EVALUATE SERVER-SIDE ISSUES (assuming it replied)
#-----------------------------
# Layer 2: Validity of Server's Reply:
raw_reply = api_response.data
pre_validated_reply = api_response.data
logger.info("Validating the Validity of the Server's Reply..")
worked, server_reply = validate_model(ServerReply, raw_reply)
worked, server_reply = validate_model(ServerReply, pre_validated_reply)
error_msg = f"Invalid Structure for ServerReply! The raw data is {raw_reply}"
error_msg = f"Validation of the Server's Reply had issues! Pre-validate: {pre_validated_reply}. Post validate: {server_reply}"
logger.info("Checking if validation worked..")
if not worked:
logger.error(error_msg)
@ -148,21 +150,29 @@ def api_call_and_extraction(
logger.error(error_msg)
return invalid_server_format()
logger.info("Validation successfull. Checking if the server's reply says the operation worked..")
if not server_reply.valid:
error_message = f"Server reply was correctly structured, but the actual invoice failed to be created. The raw data is {raw_reply}"
logger.error(error_message)
# translate by enum error code:
return translate_server_failure(server_reply)
logger.info(f"Checking for the desired data type of {desired_type}")
if not hasattr(server_reply, desired_type):
error_msg = "Developer Error: You're asking for a data type that isn't in the object!"
logger.error(error_msg)
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
print(f"right before check, server_reply is {server_reply} and desired_type is {desired_type}")
data = getattr(server_reply, desired_type)
if data:
return Result(valid=True, data=data)
else:
return Result(valid=False, error_type=ResultError.MISSING_DATA, message="Server Replied it was valid, but failed to provide the data.")
logger.info(f"Successfully returning the data of {data}")
return Result(valid=True, data=data)
# else:
# error_msg = f"Server Replied it was valid, but failed to provide the data for the desired type of {desired_type}."
# logger.error(error_msg)
# return Result(valid=False, error_type=ResultError.MISSING_DATA, message=error_msg)

View file

@ -115,17 +115,19 @@ class CheckPaidTimer:
# Reset instance:
CheckPaidTimer._instance = None
# SAVE INDIVIDUAL:
if self.payment_type == PaymentType.CRYPTO:
marked = mark_as_paid(profile_id=self.profile_id)
marked = mark_as_paid(profile_id=self.profile_id)
# SAVE TICKETS PAID:
elif self.payment_type == PaymentType.TICKET:
marked = mark_global_tickets_paid()
# # SAVE INDIVIDUAL:
# if self.payment_type == PaymentType.CRYPTO:
# marked = mark_as_paid(profile_id=self.profile_id)
else:
logger.error("Invalid payment type picked.")
marked = Result(valid=False, error_type=ResultError.INVALID_INPUT, message="Unsupported protocol.")
# # SAVE TICKETS PAID:
# elif self.payment_type == PaymentType.TICKET:
# marked = mark_global_tickets_paid()
# else:
# logger.error("Invalid payment type picked.")
# marked = Result(valid=False, error_type=ResultError.INVALID_INPUT, message="Unsupported protocol.", billing_code=self.billing_code)
# Either way evaluate:
if not marked.valid:
@ -141,27 +143,27 @@ class CheckPaidTimer:
print("Not yet paid, but continue to check..")
self.total_attempts = self.total_attempts + 1
message = f"Status: Not yet Paid ({self.total_attempts} Checks)"
self.view_callback(paid=False, stopped=False, message=message)
self.view_callback(paid=False, stopped=False, message=message, billing_code=self.billing_code)
# invalid inputs, stop immediately,
elif result.error_type == ResultError.INVALID_INPUT:
print("immediately stop, the billing code or other input is invalid")
self.stop_polling()
CheckPaidTimer._instance = None # Reset instance
self.view_callback(paid=False, stopped=True, message=result.message)
self.view_callback(paid=False, stopped=True, message=result.message, billing_code=self.billing_code)
# connection error (timed out). Not related to payment status:
elif self.failed_connections > MAX_FAILED_CONNECTIONS:
self.stop_polling()
CheckPaidTimer._instance = None # Reset instance
message = f"Your network connection timed out after {self.failed_connections} failed attempts"
self.view_callback(paid=False, stopped=True, message=message)
self.view_callback(paid=False, stopped=True, message=message, billing_code=self.billing_code)
# evaluate timeouts:
elif result.error_type == ResultError.CONNECTION:
self.failed_connections = self.failed_connections + 1
message = f"The number of failed connections is {self.failed_connections}. This will time you out after {MAX_FAILED_CONNECTIONS} in total."
self.view_callback(paid=False, stopped=True, message=message)
self.view_callback(paid=False, stopped=True, message=message, billing_code=self.billing_code)
else:
print("Other errors/unknown errors")
@ -169,5 +171,5 @@ class CheckPaidTimer:
print(f"result.message is {result.error_type}")
self.stop_polling()
CheckPaidTimer._instance = None
self.view_callback(paid=False, stopped=True, message=result.message)
self.view_callback(paid=False, stopped=True, message=result.message, billing_code=self.billing_code)

View file

@ -74,6 +74,22 @@ def the_same_payment_cycle(payment_cycle: OverallPaymentCycle, profile_id: Optio
return False
def is_payment_active_for(profile_id: int) -> tuple:
"""
Evaluates if a payment is active, and is it for a given profile.
Returns a Tuple. First is it active. Second is it active for THIS PROFILE
"""
payment_cycle = OverallPaymentCycle()
if not payment_cycle.active:
return False, False
if profile_id == payment_cycle.profile_id:
return True, True
else:
return False, False
def start_new_payment_cycle(category: PaymentCategory, profile_id: Optional[int] = None) -> Result:
if not profile_id and category == PaymentCategory.INDIVIDUAL:
@ -89,7 +105,7 @@ def start_new_payment_cycle(category: PaymentCategory, profile_id: Optional[int]
logger.info("It's the same as before, returning the code")
return Result(valid=True, data=payment_cycle.billing_code)
else:
error_msg = "There's already a billing process active, do you want to stop that?"
error_msg = f"There's already a billing process active, do you want to stop that?"
logger.error(error_msg)
return Result(valid=False, error_type=ResultError.ACTIVE_BILLING, message=error_msg)
@ -100,7 +116,7 @@ def start_new_payment_cycle(category: PaymentCategory, profile_id: Optional[int]
if category == PaymentCategory.INDIVIDUAL:
payment_cycle.profile_id = profile_id
payment_cycle.active_data = PaymentData(instance_id=profile_id)
subscription = get_profile_subscription(profile_id)
subscription = get_profile_subscription(profile_id=profile_id, save_pending=True) # save to disk that it's pending
if subscription:
billing_code = subscription.billing_code
else:
@ -343,7 +359,7 @@ def check_paid(billing_code: str, connection_observer: ConnectionObserver) -> Re
if not result.valid:
return result
payment_status = result.payment_status
payment_status = result.data
# paid
if payment_status:
@ -368,7 +384,7 @@ def paying_for_tickets() -> bool:
return False
def get_current_billing_data() -> Result:
def get_current_billing_data(category: Optional[PaymentCategory] = None) -> Result:
"""
Goal:
Get whatever current billing data is relevant by the overall cycle, for either billing category
@ -380,30 +396,39 @@ def get_current_billing_data() -> Result:
# Is there currently a process?
payment_cycle = OverallPaymentCycle()
if not payment_cycle:
error_msg = "There is no current billing cycle."
return Result(valid=False, error_type=ResultError.INVALID, message=error_msg)
if not payment_cycle and not category:
error_msg = "There is no current billing cycle AND no category provided."
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
# if not payment_cycle and category:
billing_data = payment_cycle.active_data
if not billing_data:
error_msg = "There is no current billing data."
return Result(valid=False, error_type=ResultError.INVALID, message=error_msg)
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
return Result(valid=True, data=billing_data)
def wipe_billing_cycle():
def wipe_billing_cycle() -> Result:
"""Wipes the entire overall cycle"""
logger.info("Wiping the overall cycle, so this cycle no longer blocks other new ones")
payment_cycle = OverallPaymentCycle()
if payment_cycle:
payment_cycle.wipe()
return Result(valid=True)
def get_profile_subscription(profile_id: int, save_pending: Optional[bool] = False) -> Subscription:
"""
Main Purpose:
Lookup the full profile object & get it's subscription. (metaphor of a GET request)
def get_profile_subscription(profile_id: int) -> Subscription:
"""Lookup the full profile object & get it's subscription"""
2nd Feature:
Optional flag to SAVE that the billing is pending. (metaphor of a POST request)
"""
print(f"starting lookup of profile id {profile_id}")
profile = Profile.find_by_id(profile_id)
if not profile:
@ -411,6 +436,12 @@ def get_profile_subscription(profile_id: int) -> Subscription:
logger.error(error_msg)
return Result(valid=False, message=error_msg, error_type=ResultError.INVALID_INPUT)
# Optional save pending flag:
if save_pending:
profile.billing_pending = True
profile.save()
print(f"returning profile {profile}")
return profile.subscription
@ -424,13 +455,13 @@ def mark_as_paid() -> Result:
if not payment_cycle:
error_msg = "There is no current billing cycle."
return Result(valid=False, error_type=ResultError.INVALID, message=error_msg)
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
billing_data = payment_cycle.instance
if not billing_data:
error_msg = "There is no current billing data."
return Result(valid=False, error_type=ResultError.INVALID, message=error_msg)
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message=error_msg)
category = payment_cycle.category