Use of a pre-existing billing code, to then connect

This commit is contained in:
SimplifiedPrivacy 2026-10-22 21:20:59 -04:00
parent b68d1ea6bd
commit f54ed5686a
5 changed files with 117 additions and 18 deletions

View file

@ -7,6 +7,7 @@ from datetime import datetime
from enum import Enum from enum import Enum
from typing import Any, Optional from typing import Any, Optional
class ServerError(str, Enum): class ServerError(str, Enum):
"""Why the Server's Operation was False.""" """Why the Server's Operation was False."""
NONE = "none" NONE = "none"
@ -24,8 +25,9 @@ class ServerError(str, Enum):
SERVER_SIDE = "server_side" SERVER_SIDE = "server_side"
# @validate_types
@dataclass_json @dataclass_json
@validate_types
@dataclass @dataclass
class ServerReply(): class ServerReply():
"""Server-Client Communication Format.""" """Server-Client Communication Format."""
@ -38,7 +40,12 @@ class ServerReply():
boolean_result: Optional[bool] = None boolean_result: Optional[bool] = None
conf: Optional[str] = None conf: Optional[str] = None
payment_status: Optional[bool] = None payment_status: Optional[bool] = None
expires_at: Optional[datetime] = None expires_at: Optional[datetime] = field(
default=None,
metadata=config(
decoder=lambda x: datetime.fromisoformat(x.replace('Z', '+00:00')) if x else None
)
)

View file

@ -9,6 +9,7 @@ from core.errors.logger import logger
from core.errors.error_shortcuts import not_supported from core.errors.error_shortcuts import not_supported
from core.observers.Notifications import Notifications, EventType from core.observers.Notifications import Notifications, EventType
from typing import Optional
def _mark_profile_as_paid(profile_id: int): def _mark_profile_as_paid(profile_id: int):
"""Save to disk that an individual profile is paid.""" """Save to disk that an individual profile is paid."""
@ -68,7 +69,7 @@ def mark_as_paid() -> Result:
return Result(valid=True) return Result(valid=True)
def check_paid(billing_code: str, connection_observer: ConnectionObserver) -> Result: def check_paid(billing_code: str, connection_observer: ConnectionObserver, get_expired_date: Optional[bool] = False) -> Result:
""" """
Purpose: Purpose:
Evaluates Payment Status for EITHER payment category Evaluates Payment Status for EITHER payment category
@ -95,22 +96,51 @@ def check_paid(billing_code: str, connection_observer: ConnectionObserver) -> Re
"billing_code": billing_code "billing_code": billing_code
} }
result = api_call_and_extraction( #-----------------
desired_type="payment_status", # Just get paid or not
#-----------------
if not get_expired_date:
result = api_call_and_extraction(
desired_type="payment_status",
method=ApiCall.POST,
url=url,
connection_observer=connection_observer,
payload=submit_data
)
if not result.valid:
return result
payment_status = result.data
# paid
if payment_status:
return Result(valid=True, message="paid")
else:
return Result(valid=False, error_type=ResultError.UNPAID, message="The API call went through, but this subscription is not yet paid.")
#-----------------
# Find out if Paid & Get expiration:
#-----------------
# Get entire ServerReply
server_reply = api_call_and_extraction(
desired_type=None,
method=ApiCall.POST, method=ApiCall.POST,
url=url, url=url,
connection_observer=connection_observer, connection_observer=connection_observer,
payload=submit_data payload=submit_data,
return_server_reply=True # get server reply
) )
if not result.valid: if not server_reply.valid:
return result return server_reply
payment_status = result.data payment_status = server_reply.payment_status
expires_at = server_reply.expires_at
# paid if payment_status and expires_at:
if payment_status: return Result(valid=True, data=expires_at, message="Paid with an expiration")
return Result(valid=True, message="paid")
else:
return Result(valid=False, error_type=ResultError.UNPAID, message="The API call went through, but this subscription is not yet paid.")
return Result(valid=False, error_type=ResultError.UNPAID, message="The API call went through, but this subscription is not yet paid.")

View file

@ -0,0 +1,38 @@
from core.services.payment_phase.payment_update_tools import check_paid
from core.services.subscriptions.subscriptions_by_protocol import save_billing_code, wipe_billing_cycle_IF_its_this_profile
from core.services.payment_phase.payment_state import OverallPaymentCycle
from core.models.Result import Result
from core.errors.logger import logger
from core.observers.ConnectionObserver import ConnectionObserver
def check_then_save_billing_code(profile_id: int, billing_code: str, connection_observer: ConnectionObserver) -> Result:
"""Check if a billing code is paid for, and if it is, then save it and wipe the profile's billing cycle"""
logger.info(f"Checking payment status of a pre-existing billing code for profile {str(profile_id)}")
payment_result = check_paid(billing_code=billing_code, connection_observer=connection_observer, get_expired_date=True)
if not payment_result.valid:
logger.error(f"Check of paid came back that it's NOT paid, despite the user using a pre-existing billing code. {payment_result.message}")
return payment_result
expires_at = payment_result.data
saved = save_billing_code(
profile_id=profile_id,
billing_code=billing_code,
expires_at=expires_at,
which_ticket=None,
billing_pending=False
)
if saved.valid:
print("save worked, we are clearing the billing cycle")
wiped = wipe_billing_cycle_IF_its_this_profile(profile_id)
if not wiped.valid:
logger.error(f"Unable to wipe the current billing cycle: {wiped.message}")
return wiped
else:
logger.error(f"failed to save the new billing code, returning the saved result {saved}")
return saved

View file

@ -14,6 +14,8 @@ from core.observers.TicketObserver import TicketObserver
from core.services.assassin.ticket_respawn import respawn_profile from core.services.assassin.ticket_respawn import respawn_profile
from core.services.assassin import assassin_tools from core.services.assassin import assassin_tools
from core.errors.logger import logger from core.errors.logger import logger
from core.services.payment_phase.payment_state import OverallPaymentCycle
from core.services.subscriptions.subscriptions_by_protocol import wipe_billing_cycle_IF_its_this_profile
from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError from core.Errors import InvalidSubscriptionError, MissingSubscriptionError, ConnectionTerminationError, ProfileActivationError, ProfileDeactivationError, MissingLocationError, ConnectionUnprotectedError, EndpointVerificationError, ProfileStateConflictError
from core.controllers.ApplicationController import ApplicationController from core.controllers.ApplicationController import ApplicationController
@ -310,6 +312,14 @@ def destroy_profile(
2) Disabling it, 2) Disabling it,
3) Destroying it on disk & cache 3) Destroying it on disk & cache
""" """
####################################
# ACTIVE BILLING STATE:
####################################
wiped = wipe_billing_cycle_IF_its_this_profile(profile.id)
if not wiped.valid:
logger.error(f"Unable to wipe the current billing cycle: {wiped.message}")
return wiped
#################################### ####################################
# RESPAWN TICKET # RESPAWN TICKET
#################################### ####################################

View file

@ -474,6 +474,20 @@ def get_current_billing_data(category: Optional[PaymentCategory] = None, profile
return Result(valid=True, data=billing_data) return Result(valid=True, data=billing_data)
def wipe_billing_cycle_IF_its_this_profile(profile_id) -> Result:
# Overall State:
payment_cycle = OverallPaymentCycle()
if not payment_cycle:
return Result(valid=True)
if payment_cycle.billing_code != profile_id:
return Result(valid=True)
return wipe_billing_cycle(inserted_profile_id=profile.id)
def wipe_billing_cycle(inserted_profile_id: Optional[int] = None) -> Result: def wipe_billing_cycle(inserted_profile_id: Optional[int] = None) -> Result:
"""Wipes the entire overall cycle""" """Wipes the entire overall cycle"""
logger.info("Wiping the overall cycle, so this cycle no longer blocks other new ones") logger.info("Wiping the overall cycle, so this cycle no longer blocks other new ones")
@ -573,10 +587,10 @@ def wipe_subscription(profile_id: int) -> Result:
@type_checker @type_checker
def save_billing_code(profile_id: int, billing_code: str, expires_at: datetime, which_ticket: Optional[int] = None) -> Result: def save_billing_code(profile_id: int, billing_code: str, expires_at: datetime, which_ticket: Optional[int] = None, billing_pending: bool = True) -> Result:
"""Checks if the billing code is already saved, and if not, saves it.""" """Checks if the billing code is already saved, and if not, saves it."""
logger.info("Saving billing code..") logger.info(f"Saving billing code with the billing_pending as {billing_pending}")
PRE_REQS = [profile_id, billing_code, expires_at] PRE_REQS = [profile_id, billing_code, expires_at]
if None in PRE_REQS: if None in PRE_REQS:
@ -595,7 +609,7 @@ def save_billing_code(profile_id: int, billing_code: str, expires_at: datetime,
profile.subscription = Subscription( profile.subscription = Subscription(
billing_code=billing_code, billing_code=billing_code,
expires_at=expires_at, expires_at=expires_at,
billing_pending=True billing_pending=billing_pending
) )
if which_ticket: if which_ticket:
profile.ticket = which_ticket profile.ticket = which_ticket