import authorizenet.apicontrollers as controllers from authorizenet import apicontractsv1 from .. import crud, database, schemas from config import load_config from sqlalchemy.orm import Session # Set Authorize.net environment based on configuration from authorizenet.constants import constants from config import load_config # Assuming you have this # Load Authorize.net credentials ApplicationConfig = load_config() # Set Authorize.net environment based on configuration if ApplicationConfig.CURRENT_SETTINGS == 'PRODUCTION': constants.environment = constants.PRODUCTION VALIDATION_MODE = "liveMode" API_LOGIN_ID = ApplicationConfig.API_LOGIN_ID TRANSACTION_KEY = ApplicationConfig.TRANSACTION_KEY else: constants.environment = constants.SANDBOX constants.show_url_on_request = True VALIDATION_MODE = "testMode" API_LOGIN_ID = ApplicationConfig.API_LOGIN_ID TRANSACTION_KEY = ApplicationConfig.TRANSACTION_KEY def verify_customer_authorize_account(db: Session, customer_id: int) -> dict: """ Verify if customer has a valid Authorize.net account set up for charging. Args: db: Database session customer_id: Customer ID from database Returns: Dict with verification status and missing components """ try: # Get customer from database customer = crud.get_customer(db, customer_id) if not customer: return { "profile_exists": False, "has_payment_methods": False, "missing_components": ["customer_not_found"], "valid_for_charging": False } # Check if customer has auth_net_profile_id if not customer.auth_net_profile_id: return { "profile_exists": False, "has_payment_methods": False, "missing_components": ["authorize_net_profile"], "valid_for_charging": False } # Verify profile exists in Authorize.net response = _get_customer_profile(customer.auth_net_profile_id) # Enhanced profile validation - check multiple conditions for profile existence profile_valid = _is_profile_valid(response) if not profile_valid: print(f"Profile {customer.auth_net_profile_id} for customer {customer_id} is invalid/not found. Nulling out in database.") # Profile not found or invalid - set auth_net_profile_id to NULL in database try: # Update the customer record to null out the invalid profile_id customer.auth_net_profile_id = None db.add(customer) # Mark for update db.commit() # Persist the change print(f"Successfully nulled out auth_net_profile_id for customer {customer_id}") except Exception as update_error: print(f"Failed to update customer auth_net_profile_id to NULL: {update_error}") db.rollback() # Rollback on error return { "profile_exists": False, "has_payment_methods": False, "missing_components": ["authorize_net_profile_invalid"], "valid_for_charging": False } # Check for payment profiles (cards) has_payment_methods = False if hasattr(response, 'profile') and response.profile: payment_profiles = response.profile.paymentProfiles if payment_profiles and len(payment_profiles) > 0: has_payment_methods = True missing_components = [] if not has_payment_methods: missing_components.append("payment_method") return { "profile_exists": True, "has_payment_methods": has_payment_methods, "missing_components": missing_components, "valid_for_charging": len(missing_components) == 0 } except Exception as e: print(f"Error verifying customer authorize account for customer {customer_id}: {str(e)}") return { "profile_exists": False, "has_payment_methods": False, "missing_components": ["api_error"], "valid_for_charging": False } def _is_profile_valid(response) -> bool: """ Check if the Authorize.net API response indicates a valid customer profile. Args: response: Authorize.net API response object Returns: bool: True if profile exists and is valid, False otherwise """ try: # Check basic response validity if not response: return False # Check if result code indicates success if response.messages.resultCode != "Ok": return False # Check if profile data actually exists if not hasattr(response, 'profile') or response.profile is None: return False # Check for any error messages that indicate profile doesn't exist if hasattr(response, 'messages') and response.messages.message: for message in response.messages.message: # Check for specific error codes that indicate profile doesn't exist if hasattr(message, 'code'): # Common error codes for non-existent profiles if message.code in ['E00040', 'E00035']: # Customer not found, etc. return False # Additional validation - check if profile has basic required fields if hasattr(response.profile, 'customerProfileId'): profile_id = getattr(response.profile, 'customerProfileId', None) if not profile_id: return False else: return False return True except Exception as e: print(f"Error validating profile response: {str(e)}") return False def _get_customer_profile(profile_id: str): """ Get customer profile from Authorize.net API. Args: profile_id: Authorize.net customer profile ID Returns: API response object or None if error """ try: merchant_auth = apicontractsv1.merchantAuthenticationType( name=API_LOGIN_ID, transactionKey=TRANSACTION_KEY ) request = apicontractsv1.getCustomerProfileRequest( merchantAuthentication=merchant_auth, customerProfileId=profile_id ) controller = controllers.getCustomerProfileController(request) if ApplicationConfig.CURRENT_SETTINGS == 'PRODUCTION': controller.setenvironment(constants.PRODUCTION) controller.execute() else: controller.execute() response = controller.getresponse() return response except Exception as e: print(f"Error getting customer profile {profile_id}: {str(e)}") return None