Ticket Inovices Stable with Big Bang Refactor. Still need to resolve issues with ticket billing invoice config already existing
This commit is contained in:
parent
f9698ced68
commit
6a445eba41
9 changed files with 192 additions and 96 deletions
|
|
@ -18,7 +18,7 @@ class Constants:
|
||||||
|
|
||||||
# ticketing group:
|
# ticketing group:
|
||||||
TICKET_API_BASE_URL: Final[str] = os.environ.get(
|
TICKET_API_BASE_URL: Final[str] = os.environ.get(
|
||||||
"TICKET_API_BASE_URL", "https://ticket.hydraveil.net"
|
"TICKET_API_BASE_URL", "https://api.hydraveil.net"
|
||||||
)
|
)
|
||||||
|
|
||||||
SP_API_BASE_URL: Final[str] = os.environ.get('SP_API_BASE_URL', 'https://api.hydraveil.net/api/v1')
|
SP_API_BASE_URL: Final[str] = os.environ.get('SP_API_BASE_URL', 'https://api.hydraveil.net/api/v1')
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,7 @@ def check_if_paid(
|
||||||
def check_if_ticket_paid(
|
def check_if_ticket_paid(
|
||||||
temp_billing_code: str,
|
temp_billing_code: str,
|
||||||
connection_observer: ConnectionObserver,
|
connection_observer: ConnectionObserver,
|
||||||
) -> dict:
|
) -> Result:
|
||||||
"""Coordinate a request with the ticket billing code, to check if an invoice is paid"""
|
"""Coordinate a request with the ticket billing code, to check if an invoice is paid"""
|
||||||
|
|
||||||
billing_folder = Constants.HV_TICKETING_CONFIG_HOME
|
billing_folder = Constants.HV_TICKETING_CONFIG_HOME
|
||||||
|
|
@ -189,46 +189,44 @@ def check_if_ticket_paid(
|
||||||
logger.error(f"{error_msg} inside the check_if_paid function")
|
logger.error(f"{error_msg} inside the check_if_paid function")
|
||||||
return Result(valid=False, error_type=ResultError.SUBSCRIPTION, message=error_msg)
|
return Result(valid=False, error_type=ResultError.SUBSCRIPTION, message=error_msg)
|
||||||
|
|
||||||
|
# prep the JSON payload:
|
||||||
|
payload = {"temp_billing_code": temp_billing_code}
|
||||||
|
|
||||||
|
# prep endpoint:
|
||||||
|
which_endpoint = "check_paid"
|
||||||
|
url = make_url(which_endpoint)
|
||||||
|
|
||||||
|
# literally send:
|
||||||
|
api_reply_object = connect.single_endpoint(
|
||||||
|
method="post",
|
||||||
|
url=url,
|
||||||
|
observer=connection_observer,
|
||||||
|
payload=payload
|
||||||
|
)
|
||||||
|
|
||||||
|
if not api_reply_object.valid:
|
||||||
|
error_msg = f"Connection/API Error: {api_reply_object.message}"
|
||||||
|
logger.error(f"[TICKET PayController] 2nd Post Request inside ticketpay controller had a {error_msg}")
|
||||||
|
return Result(valid=False, error_type=ResultError.CONNECTION, message=error_msg)
|
||||||
|
|
||||||
|
# return the payload with GUI/CLI to interpret results:
|
||||||
|
reply_dict = api_reply_object.data
|
||||||
|
logger.debug(f"[TICKET PayController] We have a valid reply from the API inside ticketpay controller of {reply_dict}")
|
||||||
|
print(f"reply_dict is {reply_dict}")
|
||||||
|
if isinstance(reply_dict, dict):
|
||||||
|
payment_status = reply_dict.get('payment_status', None)
|
||||||
|
message = reply_dict.get('message', None)
|
||||||
else:
|
else:
|
||||||
|
payment_status = str(reply_dict)
|
||||||
|
|
||||||
# prep the JSON payload:
|
if payment_status == "paid":
|
||||||
payload = {"temp_billing_code": temp_billing_code}
|
saved = update_json(filepath=filepath, key_to_add="paid", value_to_update="paid")
|
||||||
|
if saved:
|
||||||
# prep endpoint:
|
return Result(valid=True, data=payment_status)
|
||||||
which_endpoint = "check_paid"
|
|
||||||
url = make_url(which_endpoint)
|
|
||||||
|
|
||||||
# literally send:
|
|
||||||
api_reply_object = connect.single_endpoint(
|
|
||||||
method="post",
|
|
||||||
url=url,
|
|
||||||
observer=connection_observer,
|
|
||||||
payload=payload
|
|
||||||
)
|
|
||||||
|
|
||||||
if not api_reply_object.valid:
|
|
||||||
error_msg = f"Connection/API Error: {api_reply_object.message}"
|
|
||||||
logger.error(f"[TICKET PayController] 2nd Post Request inside ticketpay controller had a {error_msg}")
|
|
||||||
return Result(valid=False, error_type=ResultError.CONNECTION, message=error_msg)
|
|
||||||
|
|
||||||
# return the payload with GUI/CLI to interpret results:
|
|
||||||
reply_dict = api_reply_object.data
|
|
||||||
logger.debug(f"[TICKET PayController] We have a valid reply from the API inside ticketpay controller of {reply_dict}")
|
|
||||||
print(f"reply_dict is {reply_dict}")
|
|
||||||
if isinstance(reply_dict, dict):
|
|
||||||
payment_status = reply_dict.get('payment_status', None)
|
|
||||||
message = reply_dict.get('message', None)
|
|
||||||
else:
|
else:
|
||||||
payment_status = str(reply_dict)
|
return Result(valid=False, error_type=ResultError.FILE_SYSTEM, message="You paid, but it was unable to save that to the config")
|
||||||
|
|
||||||
if payment_status == "paid":
|
elif message == "bad_code":
|
||||||
saved = update_json(filepath=filepath, key_to_add="paid", value_to_update="paid")
|
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message="This is not a valid subscription code to check.")
|
||||||
if saved:
|
|
||||||
return Result(valid=True, data=payment_status)
|
|
||||||
else:
|
|
||||||
return Result(valid=False, error_type=ResultError.FILE_SYSTEM, message="You paid, but it was unable to save that to the config")
|
|
||||||
|
|
||||||
elif message == "bad_code":
|
return Result(valid=False, error_type=ResultError.UNPAID, message="Not yet paid")
|
||||||
return Result(valid=False, error_type=ResultError.INVALID_INPUT, message="This is not a valid subscription code to check.")
|
|
||||||
|
|
||||||
return Result(valid=False, error_type=ResultError.UNPAID, message="Not yet paid")
|
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ if TYPE_CHECKING:
|
||||||
from core.observers.TicketObserver import TicketObserver
|
from core.observers.TicketObserver import TicketObserver
|
||||||
|
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
from core.observers.BaseObserver import BaseObserver
|
# from core.observers.BaseObserver import BaseObserver
|
||||||
# from core.services.networking.api_requests.step1_get_or_post import get_data_from_api
|
from core.models.manage.server_reply_tools import translate_server_failure, invalid_server_format
|
||||||
|
from core.models.pydantic_models.type_checker import validate_model
|
||||||
|
from core.models.pydantic_models.ServerReply import ServerReply
|
||||||
|
|
||||||
from core.services.networking.httpx import connect
|
from core.services.networking.httpx import connect
|
||||||
from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
|
# from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
|
||||||
from core.services.networking.api_requests.step5_solve_api_problems import solve_api_problems
|
from core.models.Result import Result, ResultError
|
||||||
|
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
|
|
||||||
|
|
@ -19,8 +21,9 @@ from core.errors.logger import logger
|
||||||
def sync_ticket_prices(
|
def sync_ticket_prices(
|
||||||
ticket_observer: TicketObserver,
|
ticket_observer: TicketObserver,
|
||||||
connection_observer: ConnectionObserver
|
connection_observer: ConnectionObserver
|
||||||
) -> dict:
|
) -> Result:
|
||||||
notification = f"Connecting to get Ticket Pricing..."
|
|
||||||
|
notification = "Connecting to get Ticket Pricing..."
|
||||||
ticket_observer.notify("connecting", subject=notification)
|
ticket_observer.notify("connecting", subject=notification)
|
||||||
|
|
||||||
rejected_list = [None, False, ""]
|
rejected_list = [None, False, ""]
|
||||||
|
|
@ -33,36 +36,50 @@ def sync_ticket_prices(
|
||||||
return {"valid": False, "error_code": "invalid_url"}
|
return {"valid": False, "error_code": "invalid_url"}
|
||||||
|
|
||||||
url = f"{base_url}/sync"
|
url = f"{base_url}/sync"
|
||||||
try:
|
api_response = connect.single_endpoint(
|
||||||
# api_result = get_data_from_api(url, None, connection_observer)
|
method="get",
|
||||||
api_result = connect.single_endpoint(
|
url=url,
|
||||||
method="get",
|
observer=connection_observer,
|
||||||
url=url,
|
payload=None
|
||||||
observer=connection_observer,
|
)
|
||||||
payload=None
|
|
||||||
)
|
|
||||||
|
|
||||||
# 2nd try:
|
#-----------------------------
|
||||||
if not api_result.valid:
|
# EVALUATE CONNECTION FAILURE
|
||||||
logger.error(f"Invalid API call result: {api_result.error_type}")
|
#-----------------------------
|
||||||
return {"valid": False, "error_code": "sync_failed"}
|
# Layer 1: API failure:
|
||||||
|
if not api_response.valid:
|
||||||
|
error_msg = f"Connection/500s Error prevented the server from replying: {api_response.error_type} {api_response.message}"
|
||||||
|
logger.error(error_msg)
|
||||||
|
return Result(valid=False, error_type=ResultError.CONNECTION, message=error_msg)
|
||||||
|
|
||||||
# if not api_result.valid:
|
#-----------------------------
|
||||||
# error_msg = api_result.message
|
# EVALUATE SERVER-SIDE ISSUES (assuming it replied)
|
||||||
# logger.error(f"[TICKET SYNC Controller] There's an issue with the sync of endpoint {url} the API Reply: {error_msg}")
|
#-----------------------------
|
||||||
# api_result = solve_api_problems(
|
# Layer 2: Validity of Server's Reply:
|
||||||
# api_reply_object=api_result,
|
raw_reply = api_response.data
|
||||||
# get_or_post="get",
|
logger.info("Validating the Validity of the Server's Reply..")
|
||||||
# url=url,
|
server_reply = validate_model(ServerReply, raw_reply)
|
||||||
# payload=None,
|
|
||||||
# connection_observer=connection_observer,
|
|
||||||
# client_observer=None
|
|
||||||
# )
|
|
||||||
# # 2nd try:
|
|
||||||
# if not api_result.valid:
|
|
||||||
# return {"valid": False, "error_code": "sync_failed"}
|
|
||||||
|
|
||||||
return {"valid": True, "data": api_result.data}
|
if not server_reply:
|
||||||
|
logger.error(f"Invalid Structure for ServerReply! The raw data is {raw_reply}")
|
||||||
|
return invalid_server_format()
|
||||||
|
|
||||||
|
if not server_reply.valid:
|
||||||
|
logger.error(f"Server reply was correctly structured, but the actual invoice failed to be created. The raw data is {raw_reply}")
|
||||||
|
# translate by enum error code:
|
||||||
|
return translate_server_failure(server_reply)
|
||||||
|
|
||||||
|
#-----------------------------
|
||||||
|
# EVALUATE SERVER'S ACTUAL DATA
|
||||||
|
#-----------------------------
|
||||||
|
# Layer 3: Payload Data
|
||||||
|
payload_data = server_reply.data
|
||||||
|
|
||||||
|
if not payload_data:
|
||||||
|
logger.error(f"Failed to create an invoice object with this data: {payload_data}")
|
||||||
|
return invalid_server_format()
|
||||||
|
|
||||||
|
return Result(valid=True, data=payload_data)
|
||||||
|
|
||||||
|
# return {"valid": True, "data": payload_data}
|
||||||
|
|
||||||
except:
|
|
||||||
return {"valid": False, "error_code": "sync_failed"}
|
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,7 @@ class StatePersistenceMixin(ValidatedDataclass):
|
||||||
return os.path.exists(self._data_file)
|
return os.path.exists(self._data_file)
|
||||||
|
|
||||||
|
|
||||||
|
HOW_MANY_PROFILES_DEFAULT = 6
|
||||||
|
|
||||||
@singleton
|
@singleton
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -146,7 +147,7 @@ class TicketPaymentData(StatePersistenceMixin):
|
||||||
|
|
||||||
# for only tickets:
|
# for only tickets:
|
||||||
which_key: str = None
|
which_key: str = None
|
||||||
how_many_profiles: int = None
|
how_many_profiles: int = HOW_MANY_PROFILES_DEFAULT
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
# Global mode, assuming tickets here:
|
# Global mode, assuming tickets here:
|
||||||
|
|
|
||||||
|
|
@ -8,18 +8,23 @@ if TYPE_CHECKING:
|
||||||
# from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
|
# from core.services.networking.api_requests.ApiResponseModel import ApiResponse, ErrorType
|
||||||
# from core.services.networking.api_requests.step5_solve_api_problems import solve_api_problems
|
# from core.services.networking.api_requests.step5_solve_api_problems import solve_api_problems
|
||||||
from core.models.Result import Result, ResultError
|
from core.models.Result import Result, ResultError
|
||||||
from core.models.invoice.TicketInvoice import TicketInvoice
|
# from core.models.invoice.TicketInvoice import TicketInvoice
|
||||||
|
|
||||||
|
from core.models.manage.server_reply_tools import translate_server_failure, invalid_server_format
|
||||||
|
from core.models.pydantic_models.type_checker import validate_model
|
||||||
|
from core.models.pydantic_models.ServerReply import ServerReply, SubscriptionInvoice
|
||||||
|
|
||||||
from core.utils.basic_operations.write_or_read_from_json import update_json
|
from core.utils.basic_operations.write_or_read_from_json import update_json
|
||||||
from core.Constants import Constants
|
from core.Constants import Constants
|
||||||
from core.services.networking.httpx import connect
|
from core.services.networking.httpx import connect
|
||||||
|
from core.utils.basic_operations.enum_tools import serialize_enums
|
||||||
from core.services.networking.make_url import make_url
|
from core.services.networking.make_url import make_url
|
||||||
# from core.services.payment_phase.extract_payment_details import extract_payment_details
|
# from core.services.payment_phase.extract_payment_details import extract_payment_details
|
||||||
from core.services.payment_phase.save_billing_choices import save_billing_choices
|
from core.services.payment_phase.save_billing_choices import save_billing_choices
|
||||||
from core.errors.logger import logger
|
from core.errors.logger import logger
|
||||||
|
|
||||||
# generic:
|
# generic:
|
||||||
from pydantic import ValidationError
|
# from pydantic import ValidationError
|
||||||
|
|
||||||
filepath = f"{Constants.HV_TICKETING_CONFIG_HOME}/billing_choices.json"
|
filepath = f"{Constants.HV_TICKETING_CONFIG_HOME}/billing_choices.json"
|
||||||
|
|
||||||
|
|
@ -39,6 +44,9 @@ def save_and_send_intitial_billing(
|
||||||
Errors:
|
Errors:
|
||||||
No. Does NOT raise errors.
|
No. Does NOT raise errors.
|
||||||
"""
|
"""
|
||||||
|
# convert any enums:
|
||||||
|
payload = serialize_enums(payload)
|
||||||
|
|
||||||
# SAVE CHOICES:
|
# SAVE CHOICES:
|
||||||
saved_choices = save_billing_choices(payload)
|
saved_choices = save_billing_choices(payload)
|
||||||
if not saved_choices:
|
if not saved_choices:
|
||||||
|
|
@ -50,41 +58,82 @@ def save_and_send_intitial_billing(
|
||||||
which_endpoint = "start_payment"
|
which_endpoint = "start_payment"
|
||||||
url = make_url(which_endpoint)
|
url = make_url(which_endpoint)
|
||||||
print(f"saved, now sending choices to {url}")
|
print(f"saved, now sending choices to {url}")
|
||||||
api_reply_object = connect.single_endpoint(
|
api_response = connect.single_endpoint(
|
||||||
method="post",
|
method="post",
|
||||||
url=url,
|
url=url,
|
||||||
observer=connection_observer,
|
observer=connection_observer,
|
||||||
payload=payload
|
payload=payload
|
||||||
)
|
)
|
||||||
if not api_reply_object.valid:
|
|
||||||
error_msg = f"API Error! {api_reply_object.message}"
|
|
||||||
logger.error(f"{api_reply_object.error_type} {error_msg}")
|
|
||||||
raise ConnectionError(error_msg)
|
|
||||||
|
|
||||||
# Extract from API Response into Invoice Object
|
|
||||||
server_reply = api_reply_object.data
|
|
||||||
|
|
||||||
# Validate and create the Pydantic model
|
# if not api_reply_object.valid:
|
||||||
try:
|
# error_msg = f"API Error! {api_reply_object.message}"
|
||||||
ticket_invoice = TicketInvoice.model_validate(server_reply)
|
# logger.error(f"{api_reply_object.error_type} {error_msg}")
|
||||||
except ValidationError as e:
|
# raise ConnectionError(error_msg)
|
||||||
error_msg = f"Server's Reply is Missing {str(e)}"
|
|
||||||
|
# # Extract from API Response into Invoice Object
|
||||||
|
# server_reply = api_reply_object.data
|
||||||
|
|
||||||
|
# # Validate and create the Pydantic model
|
||||||
|
# try:
|
||||||
|
# ticket_invoice = SubscriptionInvoice.model_validate(server_reply)
|
||||||
|
# except ValidationError as e:
|
||||||
|
# error_msg = f"Server's Reply is Missing {str(e)}"
|
||||||
|
# logger.error(error_msg)
|
||||||
|
# raise ValueError(error_msg)
|
||||||
|
|
||||||
|
#-----------------------------
|
||||||
|
# EVALUATE CONNECTION FAILURE
|
||||||
|
#-----------------------------
|
||||||
|
# Layer 1: API failure:
|
||||||
|
if not api_response.valid:
|
||||||
|
error_msg = f"Connection/500s Error prevented the server from replying: {api_response.error_type} {api_response.message}"
|
||||||
logger.error(error_msg)
|
logger.error(error_msg)
|
||||||
raise ValueError(error_msg)
|
return Result(valid=False, error_type=ResultError.CONNECTION, message=error_msg)
|
||||||
|
|
||||||
|
#-----------------------------
|
||||||
|
# EVALUATE SERVER-SIDE ISSUES (assuming it replied)
|
||||||
|
#-----------------------------
|
||||||
|
# Layer 2: Validity of Server's Reply:
|
||||||
|
raw_reply = api_response.data
|
||||||
|
logger.info("Validating the Validity of the Server's Reply..")
|
||||||
|
server_reply = validate_model(ServerReply, raw_reply)
|
||||||
|
|
||||||
|
if not server_reply:
|
||||||
|
logger.error(f"Invalid Structure for ServerReply! The raw data is {raw_reply}")
|
||||||
|
return invalid_server_format()
|
||||||
|
|
||||||
|
if not server_reply.valid:
|
||||||
|
logger.error(f"Server reply was correctly structured, but the actual invoice failed to be created. The raw data is {raw_reply}")
|
||||||
|
# translate by enum error code:
|
||||||
|
return translate_server_failure(server_reply)
|
||||||
|
|
||||||
|
#-----------------------------
|
||||||
|
# EVALUATE SERVER'S ACTUAL DATA
|
||||||
|
#-----------------------------
|
||||||
|
# Layer 3: Payload Data
|
||||||
|
payload_data = server_reply.data
|
||||||
|
logger.info("Validating the final invoice")
|
||||||
|
final_invoice = validate_model(SubscriptionInvoice, payload_data)
|
||||||
|
|
||||||
|
if not final_invoice:
|
||||||
|
logger.error(f"Failed to create an invoice object with this data: {payload_data}")
|
||||||
|
return invalid_server_format()
|
||||||
|
|
||||||
# save the temp_billing_code:
|
# save the temp_billing_code:
|
||||||
print("saving to ticket tracker json..")
|
print("saving to ticket tracker json..")
|
||||||
did_it_save = update_json(
|
did_it_save = update_json(
|
||||||
filepath=filepath,
|
filepath=filepath,
|
||||||
key_to_add="temp_billing_code",
|
key_to_add="temp_billing_code",
|
||||||
value_to_update=ticket_invoice.temp_billing_code
|
value_to_update=final_invoice.billing_code
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"did_it_save is {did_it_save}")
|
print(f"did_it_save is {did_it_save}")
|
||||||
|
|
||||||
if did_it_save == True:
|
if did_it_save == True:
|
||||||
return Result(valid=True, data=ticket_invoice)
|
return Result(valid=True, data=final_invoice)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
error_msg = f"Error: could NOT save the temp_billing_code {ticket_invoice.temp_billing_code}. Check your local file permissions and storage."
|
error_msg = f"Error: could NOT save the billing_code {final_invoice.billing_code}. Check your local file permissions and storage."
|
||||||
logger.error(error_msg, exc_info=True)
|
logger.error(error_msg, exc_info=True)
|
||||||
return Result(valid=False, error_type=ResultError.FILE_SYSTEM, message=error_msg)
|
return Result(valid=False, error_type=ResultError.FILE_SYSTEM, message=error_msg)
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ def get_from_server_and_save(
|
||||||
# extract:
|
# extract:
|
||||||
public_key = public_key_results.data
|
public_key = public_key_results.data
|
||||||
|
|
||||||
|
print(f"public_key is {public_key}")
|
||||||
|
|
||||||
# save it:
|
# save it:
|
||||||
did_it_save = write_string_to_text_file(public_key, file_path)
|
did_it_save = write_string_to_text_file(public_key, file_path)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ def wipe_billing_cycle():
|
||||||
payment_cycle.wipe()
|
payment_cycle.wipe()
|
||||||
|
|
||||||
|
|
||||||
def start_billing_state(category: PaymentCategory, profile_id: Optional[int], wipe_existing: Optional[bool] = False) -> Result:
|
def start_billing_state(category: PaymentCategory, profile_id: Optional[int] = None, wipe_existing: Optional[bool] = False) -> Result:
|
||||||
"""Start a new billing process. Wipe the existing one. And never save these 'overall' states to disk."""
|
"""Start a new billing process. Wipe the existing one. And never save these 'overall' states to disk."""
|
||||||
|
|
||||||
if not category:
|
if not category:
|
||||||
|
|
|
||||||
19
core/utils/basic_operations/enum_tools.py
Normal file
19
core/utils/basic_operations/enum_tools.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
def serialize_enums(data: Any) -> Any:
|
||||||
|
"""
|
||||||
|
Recursively traverses a data structure and replaces Enum members with their values.
|
||||||
|
"""
|
||||||
|
if isinstance(data, Enum):
|
||||||
|
return data.value
|
||||||
|
|
||||||
|
if isinstance(data, dict):
|
||||||
|
return {k: serialize_enums(v) for k, v in data.items()}
|
||||||
|
|
||||||
|
if isinstance(data, list):
|
||||||
|
return [serialize_enums(item) for item in data]
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
@ -5,6 +5,8 @@ import os
|
||||||
from typing import Any
|
from typing import Any
|
||||||
import tempfile
|
import tempfile
|
||||||
import shutil
|
import shutil
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
def write_json_to_file(data: dict, filepath: str) -> bool:
|
def write_json_to_file(data: dict, filepath: str) -> bool:
|
||||||
try:
|
try:
|
||||||
|
|
@ -24,6 +26,14 @@ def write_json_to_file(data: dict, filepath: str) -> bool:
|
||||||
|
|
||||||
except TypeError as e:
|
except TypeError as e:
|
||||||
logger.error(f"Data is not JSON serializable: {e}")
|
logger.error(f"Data is not JSON serializable: {e}")
|
||||||
|
|
||||||
|
# Attempt to sanitize Enums by extracting their .value
|
||||||
|
sanitized_data = {k: (v.value if isinstance(v, Enum) else v) for k, v in data.items()}
|
||||||
|
|
||||||
|
# Only retry if we actually modified the data to prevent infinite recursion
|
||||||
|
if sanitized_data != data:
|
||||||
|
return write_json_to_file(sanitized_data, filepath)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
logger.error(f"File not found: {filepath}")
|
logger.error(f"File not found: {filepath}")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue