Plumbing stable for GUI to call upon via inserted ENUM DICT
This commit is contained in:
parent
69f4e7114f
commit
7ba8e1e6d3
4 changed files with 85 additions and 40 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue