New refactored Use of tickets and payment of tickets loops/state, integrated with existing system
This commit is contained in:
parent
6a445eba41
commit
10e46cd8ea
8 changed files with 97 additions and 39 deletions
|
|
@ -179,3 +179,7 @@ def change_systemwide_connection(profile: Profile, new_value: str) -> Result:
|
||||||
profile.connection.code = new_value
|
profile.connection.code = new_value
|
||||||
# final_data = "edit_session"
|
# final_data = "edit_session"
|
||||||
return Result(valid=True, data=profile)
|
return Result(valid=True, data=profile)
|
||||||
|
|
||||||
|
|
||||||
|
def save_billing_code(profile: Profile, billing_code: str) -> bool:
|
||||||
|
|
||||||
|
|
@ -109,7 +109,7 @@ def initiate_payment(
|
||||||
payload = {
|
payload = {
|
||||||
"which_key": which_key,
|
"which_key": which_key,
|
||||||
"payment_type": "crypto",
|
"payment_type": "crypto",
|
||||||
"which_cryptocurrency": which_cryptocurrency,
|
"currency": which_cryptocurrency,
|
||||||
"how_many_profiles": how_many_profiles,
|
"how_many_profiles": how_many_profiles,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ ENUM_MAP = {
|
||||||
ResultError.NEED_SYNC: (new_sync),
|
ResultError.NEED_SYNC: (new_sync),
|
||||||
ResultError.INVALID_API_REPLY: None,
|
ResultError.INVALID_API_REPLY: None,
|
||||||
ResultError.ENCRYPTION: None,
|
ResultError.ENCRYPTION: None,
|
||||||
# ResultError.NO_TICKETS: (start_billing),
|
# ResultError.NO_TICKET: (start_billing),
|
||||||
|
|
||||||
# ResultError.NO_PROFILE: (go_to_new_profile_page),
|
# ResultError.NO_PROFILE: (go_to_new_profile_page),
|
||||||
# ResultError.ALREADY_EXISTS: (get_invoice), # bypass_existing: True
|
# ResultError.ALREADY_EXISTS: (get_invoice), # bypass_existing: True
|
||||||
# ResultError.BILLING_CODE_EXISTS: (get_invoice) # bypass_existing: True
|
# ResultError.BILLING_CODE_EXISTS: (get_invoice) # bypass_existing: True
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class ResultError(Enum):
|
||||||
SUBSCRIPTION = "subscription"
|
SUBSCRIPTION = "subscription"
|
||||||
EXPIRED = "expired" # meant for invoice
|
EXPIRED = "expired" # meant for invoice
|
||||||
TICKET = "ticket"
|
TICKET = "ticket"
|
||||||
|
NO_TICKET = "no_ticket"
|
||||||
ALREADY_EXISTS = "already_exists"
|
ALREADY_EXISTS = "already_exists"
|
||||||
BILLING_CODE_EXISTS = "billing_code_exists"
|
BILLING_CODE_EXISTS = "billing_code_exists"
|
||||||
PROCESS_GOT_KILLED = "process_got_killed"
|
PROCESS_GOT_KILLED = "process_got_killed"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from core.infrastructure.thread_dispatch import MainThreadDispatcher
|
from core.infrastructure.thread_dispatch import MainThreadDispatcher
|
||||||
from core.services.subscriptions.subscriptions_by_protocol import check_paid, mark_as_paid
|
from core.services.subscriptions.subscriptions_by_protocol import check_paid, mark_as_paid, mark_global_tickets_paid
|
||||||
|
|
||||||
from core.controllers.tickets.TicketPayController import check_if_ticket_paid
|
from core.controllers.tickets.TicketPayController import check_if_ticket_paid
|
||||||
|
|
||||||
|
|
@ -8,6 +8,7 @@ from core.models.enum_models import PaymentType
|
||||||
from core.models.Result import Result, ResultError
|
from core.models.Result import Result, ResultError
|
||||||
# from infrastructure.observer_service import notify
|
# from infrastructure.observer_service import notify
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
|
from core.models.Result import Result, ResultError
|
||||||
|
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from typing import Callable
|
from typing import Callable
|
||||||
|
|
@ -112,8 +113,19 @@ class CheckPaidTimer:
|
||||||
# Reset instance:
|
# Reset instance:
|
||||||
CheckPaidTimer._instance = None
|
CheckPaidTimer._instance = None
|
||||||
|
|
||||||
# SAVE:
|
# SAVE INDIVIDUAL:
|
||||||
marked = mark_as_paid(profile_id=self.profile_id)
|
if self.payment_type == PaymentType.CRYPTO:
|
||||||
|
marked = mark_as_paid(profile_id=self.profile_id)
|
||||||
|
|
||||||
|
# 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.")
|
||||||
|
|
||||||
|
# Either way evaluate:
|
||||||
if not marked.valid:
|
if not marked.valid:
|
||||||
message = marked.message
|
message = marked.message
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import json
|
||||||
import os
|
import os
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any
|
from typing import Any, Optional
|
||||||
|
|
||||||
def singleton(cls):
|
def singleton(cls):
|
||||||
instances = {}
|
instances = {}
|
||||||
|
|
@ -100,7 +100,10 @@ class StatePersistenceMixin(ValidatedDataclass):
|
||||||
def load(self):
|
def load(self):
|
||||||
"""Load state from file, if each item passes a type check. With Enum translation"""
|
"""Load state from file, if each item passes a type check. With Enum translation"""
|
||||||
|
|
||||||
|
logger.info("Starting load of pre-existing data")
|
||||||
|
|
||||||
if not os.path.exists(self._data_file):
|
if not os.path.exists(self._data_file):
|
||||||
|
logger.info("does NOT exist already")
|
||||||
return
|
return
|
||||||
|
|
||||||
with open(self._data_file, "r") as f:
|
with open(self._data_file, "r") as f:
|
||||||
|
|
@ -108,18 +111,20 @@ class StatePersistenceMixin(ValidatedDataclass):
|
||||||
|
|
||||||
for field in fields(self):
|
for field in fields(self):
|
||||||
value = data.get(field.name)
|
value = data.get(field.name)
|
||||||
|
logger.info(f"testing {field.name} of {value}")
|
||||||
if value is None:
|
if value is None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Translation: If the expected type is an Enum, convert the raw value back into an Enum member
|
# Translation: If the expected type is an Enum, convert the raw value back into an Enum member
|
||||||
if isinstance(field.type, type) and issubclass(field.type, Enum):
|
if isinstance(field.type, type) and issubclass(field.type, Enum):
|
||||||
|
logger.info("testing enum")
|
||||||
try:
|
try:
|
||||||
value = field.type(value)
|
value = field.type(value)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.error(f"Invalid enum value {value} for {field.name}")
|
logger.error(f"Invalid enum value {value} for {field.name}")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Now the type check works because 'value' is now an actual Enum member
|
# type check works because 'value' is now an actual Enum member
|
||||||
if isinstance(value, field.type):
|
if isinstance(value, field.type):
|
||||||
setattr(self, field.name, value)
|
setattr(self, field.name, value)
|
||||||
|
|
||||||
|
|
@ -133,30 +138,32 @@ HOW_MANY_PROFILES_DEFAULT = 6
|
||||||
@singleton
|
@singleton
|
||||||
@dataclass
|
@dataclass
|
||||||
class TicketPaymentData(StatePersistenceMixin):
|
class TicketPaymentData(StatePersistenceMixin):
|
||||||
PAYLOAD_FIELDS = {"billing_code", "currency", "which_key", "how_many_profiles", "payment_type"}
|
PAYLOAD_FIELDS = {"currency", "which_key", "how_many_profiles", "payment_type"}
|
||||||
|
|
||||||
# metadata on it's own GLOBAL instance:
|
# metadata on it's own GLOBAL instance:
|
||||||
parent_folder = None
|
|
||||||
folder_path: str = None
|
folder_path: str = None
|
||||||
_data_file: str = None
|
_data_file: str = None
|
||||||
|
|
||||||
# actual payload data:
|
# actual payload data:
|
||||||
# billing_code: str = None
|
|
||||||
currency: Currency = None
|
currency: Currency = None
|
||||||
payment_type: PaymentType = PaymentType.CRYPTO
|
payment_type: PaymentType = PaymentType.CRYPTO
|
||||||
|
|
||||||
# for only tickets:
|
|
||||||
which_key: str = None
|
which_key: str = None
|
||||||
how_many_profiles: int = HOW_MANY_PROFILES_DEFAULT
|
how_many_profiles: int = HOW_MANY_PROFILES_DEFAULT
|
||||||
|
|
||||||
|
use_random: bool = False
|
||||||
|
temp_billing_code: Optional[str] = None
|
||||||
|
billing_pending: bool = True
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
# Global mode, assuming tickets here:
|
# Global mode, assuming tickets here:
|
||||||
self.folder_path = Constants.HV_TICKETING_CONFIG_HOME
|
self.folder_path = Constants.HV_TICKETING_CONFIG_HOME
|
||||||
self._data_file = "billing.json"
|
os.makedirs(self.folder_path, exist_ok=True)
|
||||||
|
self._data_file = os.path.join(self.folder_path, "billing_choices.json")
|
||||||
|
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
@dataclass
|
@dataclass
|
||||||
class PaymentData(StatePersistenceMixin):
|
class PaymentData(StatePersistenceMixin):
|
||||||
|
|
@ -175,7 +182,6 @@ class PaymentData(StatePersistenceMixin):
|
||||||
location_id: int = None
|
location_id: int = None
|
||||||
protocol_choice: ProtocolChoice = None
|
protocol_choice: ProtocolChoice = None
|
||||||
|
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
# Localized mode: each ID gets its own folder
|
# Localized mode: each ID gets its own folder
|
||||||
self.parent_folder = Constants.HV_PROFILE_CONFIG_HOME
|
self.parent_folder = Constants.HV_PROFILE_CONFIG_HOME
|
||||||
|
|
@ -183,6 +189,8 @@ class PaymentData(StatePersistenceMixin):
|
||||||
os.makedirs(self.folder_path, exist_ok=True)
|
os.makedirs(self.folder_path, exist_ok=True)
|
||||||
self._data_file = os.path.join(self.folder_path, "billing.json")
|
self._data_file = os.path.join(self.folder_path, "billing.json")
|
||||||
|
|
||||||
|
logger.info(f"full path of self._data_file {self._data_file}")
|
||||||
|
|
||||||
self.load()
|
self.load()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,11 +100,12 @@ def start_billing_state(category: PaymentCategory, profile_id: Optional[int] = N
|
||||||
return Result(valid=True, data=billing_data)
|
return Result(valid=True, data=billing_data)
|
||||||
|
|
||||||
elif category == PaymentCategory.TICKET:
|
elif category == PaymentCategory.TICKET:
|
||||||
billing_data = TicketPaymentData(
|
billing_data = TicketPaymentData()
|
||||||
which_key=None,
|
# billing_data = TicketPaymentData(
|
||||||
how_many_profiles=HOW_MANY_PROFILES_DEFAULT,
|
# which_key=None,
|
||||||
payment_type=None
|
# how_many_profiles=HOW_MANY_PROFILES_DEFAULT,
|
||||||
)
|
# payment_type=None
|
||||||
|
# )
|
||||||
payment_cycle.instance = billing_data
|
payment_cycle.instance = billing_data
|
||||||
return Result(valid=True, data=billing_data)
|
return Result(valid=True, data=billing_data)
|
||||||
|
|
||||||
|
|
@ -330,8 +331,19 @@ def get_profile_subscription(profile_id: int) -> Subscription:
|
||||||
return profile.subscription
|
return profile.subscription
|
||||||
|
|
||||||
|
|
||||||
|
def mark_global_tickets_paid() -> Result:
|
||||||
|
"""Conclude the payment phase, by marking the global tickets as paid"""
|
||||||
|
try:
|
||||||
|
ticket_payments = TicketPaymentData()
|
||||||
|
ticket_payments.billing_pending = False
|
||||||
|
ticket_payments.save()
|
||||||
|
return Result(valid=True)
|
||||||
|
except Exception as e:
|
||||||
|
return Result(valid=False, error_type=ResultError.UNKNOWN, message=str(e))
|
||||||
|
|
||||||
|
|
||||||
def mark_as_paid(profile_id: int) -> Result:
|
def mark_as_paid(profile_id: int) -> Result:
|
||||||
"""Conclude the payment phase, by marking the sub as paid"""
|
"""Conclude the payment phase, by marking an individual subscription as paid"""
|
||||||
|
|
||||||
logger.info("Marking as paid..")
|
logger.info("Marking as paid..")
|
||||||
|
|
||||||
|
|
@ -379,25 +391,17 @@ def save_billing_code(profile_id: int, billing_code: str, expires_at: datetime)
|
||||||
return Result(valid=False, message=error_msg, error_type=ResultError.INVALID_INPUT)
|
return Result(valid=False, message=error_msg, error_type=ResultError.INVALID_INPUT)
|
||||||
|
|
||||||
|
|
||||||
|
# this can be modified to accept an id, once the UI has a cache layer:
|
||||||
|
def save_subscription(profile: Profile, subscription: Subscription) -> bool:
|
||||||
|
"""Saves subscription with the code and date."""
|
||||||
|
|
||||||
# # get the payment data singleton:
|
PRE_REQS = [profile, subscription]
|
||||||
# billing_data = PaymentData(instance_id=profile_id)
|
if None in PRE_REQS:
|
||||||
|
return False
|
||||||
|
|
||||||
# # new
|
profile.subscription = subscription
|
||||||
# if billing_data.billing_code is None:
|
profile.save()
|
||||||
# billing_data.billing_code = billing_code
|
return True
|
||||||
# billing_data.save()
|
|
||||||
# logger.info("saved billing_code")
|
|
||||||
# return Result(valid=True)
|
|
||||||
|
|
||||||
# # Already exists and is different:
|
|
||||||
# if regular_billing.billing_code != billing_code:
|
|
||||||
# error_msg = "Critical Error! Billing codes do NOT match"
|
|
||||||
# logger.error(error_msg)
|
|
||||||
# return Result(valid=False, error_type=ResultError.UNKNOWN, message=error_msg)
|
|
||||||
|
|
||||||
# # already saved:
|
|
||||||
# return Result(valid=True, message="Already saved.")
|
|
||||||
|
|
||||||
|
|
||||||
def return_pre_existing_payment_data(profile_id: int, subscription: SubscriptionInvoice) -> Result:
|
def return_pre_existing_payment_data(profile_id: int, subscription: SubscriptionInvoice) -> Result:
|
||||||
|
|
@ -469,3 +473,25 @@ def return_pre_existing_payment_data(profile_id: int, subscription: Subscription
|
||||||
# "payment_type": "crypto"
|
# "payment_type": "crypto"
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Was cut from the end of save a billing code:
|
||||||
|
|
||||||
|
# # get the payment data singleton:
|
||||||
|
# billing_data = PaymentData(instance_id=profile_id)
|
||||||
|
|
||||||
|
# # new
|
||||||
|
# if billing_data.billing_code is None:
|
||||||
|
# billing_data.billing_code = billing_code
|
||||||
|
# billing_data.save()
|
||||||
|
# logger.info("saved billing_code")
|
||||||
|
# return Result(valid=True)
|
||||||
|
|
||||||
|
# # Already exists and is different:
|
||||||
|
# if regular_billing.billing_code != billing_code:
|
||||||
|
# error_msg = "Critical Error! Billing codes do NOT match"
|
||||||
|
# logger.error(error_msg)
|
||||||
|
# return Result(valid=False, error_type=ResultError.UNKNOWN, message=error_msg)
|
||||||
|
|
||||||
|
# # already saved:
|
||||||
|
# return Result(valid=True, message="Already saved.")
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ if TYPE_CHECKING:
|
||||||
from core.services.using_tickets.send_unblinded import send_unblinded_ticket_to_server
|
from core.services.using_tickets.send_unblinded import send_unblinded_ticket_to_server
|
||||||
from core.utils.basic_operations.write_string_to_text_file import write_string_to_text_file
|
from core.utils.basic_operations.write_string_to_text_file import write_string_to_text_file
|
||||||
from core.services.prepare_tickets.ticket_tracker import update_ticket_tracker
|
from core.services.prepare_tickets.ticket_tracker import update_ticket_tracker
|
||||||
|
from core.models.Subscription import Subscription
|
||||||
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
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
|
|
@ -71,6 +72,7 @@ def use_ticket_orchestrator(
|
||||||
###################################
|
###################################
|
||||||
valid = raw_data_dict.get("valid", None)
|
valid = raw_data_dict.get("valid", None)
|
||||||
billing_code = raw_data_dict.get("billing_code", None)
|
billing_code = raw_data_dict.get("billing_code", None)
|
||||||
|
expires_at = raw_data_dict.get("expires_at", None)
|
||||||
message = raw_data_dict.get("message", None)
|
message = raw_data_dict.get("message", None)
|
||||||
|
|
||||||
logger.info(f"Was the ticket use valid? {valid}")
|
logger.info(f"Was the ticket use valid? {valid}")
|
||||||
|
|
@ -94,9 +96,13 @@ def use_ticket_orchestrator(
|
||||||
billing_code=billing_code
|
billing_code=billing_code
|
||||||
)
|
)
|
||||||
|
|
||||||
|
subscription = Subscription(
|
||||||
|
billing_code=billing_code,
|
||||||
|
expires_at=expires_at,
|
||||||
|
)
|
||||||
|
|
||||||
# even if not saved return it back, so it can be saved with the profile by other functions,
|
# even if not saved return it back, so it can be saved with the profile by other functions,
|
||||||
return Result(valid=True, data=billing_code)
|
return Result(valid=True, data=subscription)
|
||||||
# return {"valid": True, "data": billing_code}
|
|
||||||
|
|
||||||
# EXPIRED
|
# EXPIRED
|
||||||
if not valid and message == "expired":
|
if not valid and message == "expired":
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue