## File: your_app/services/payment_service.py import logging from authorizenet import apicontractsv1 from authorizenet.apicontrollers import ( createTransactionController, createCustomerProfileController, createCustomerPaymentProfileController ) from .. import schemas from config import load_config # Assuming you have this from decimal import Decimal logger = logging.getLogger(__name__) # Load Authorize.net credentials ApplicationConfig = load_config() API_LOGIN_ID = ApplicationConfig.API_LOGIN_ID TRANSACTION_KEY = ApplicationConfig.TRANSACTION_KEY # --- NEW CIM CORE FUNCTIONS --- def create_customer_profile(customer: schemas.Customer, card_info: schemas.CardCreate): logger.info(f"Creating Auth.Net profile for internal customer ID: {customer.id}") merchantAuth = apicontractsv1.merchantAuthenticationType() merchantAuth.name = API_LOGIN_ID merchantAuth.transactionKey = TRANSACTION_KEY creditCard = apicontractsv1.creditCardType( cardNumber=card_info.card_number, expirationDate=card_info.expiration_date, cardCode=card_info.cvv ) billTo = apicontractsv1.customerAddressType( firstName=customer.customer_first_name, lastName=customer.customer_last_name, address=customer.customer_address, city=customer.customer_town, zip=customer.customer_zip, country="USA" ) paymentProfile = apicontractsv1.customerPaymentProfileType() paymentProfile.billTo = billTo paymentProfile.payment = apicontractsv1.paymentType(creditCard=creditCard) customerProfile = apicontractsv1.customerProfileType( merchantCustomerId=str(customer.id), email=customer.customer_email, paymentProfiles=[paymentProfile] ) request = apicontractsv1.createCustomerProfileRequest( merchantAuthentication=merchantAuth, profile=customerProfile, validationMode="liveMode" ) controller = createCustomerProfileController(request) controller.execute() response = controller.getresponse() if response is not None and response.messages.resultCode == "Ok": profile_id = response.customerProfileId payment_id = response.customerPaymentProfileIdList[0] if response.customerPaymentProfileIdList else None return str(profile_id), str(payment_id) if payment_id else None else: error_msg = response.messages.message[0].text.text if response and response.messages and response.messages.message else "Unknown Error" logger.error(f"Failed to create customer profile: {error_msg}") return None, None def add_payment_profile_to_customer(customer_profile_id: str, customer: schemas.Customer, card_info: schemas.CardCreate): logger.info(f"Adding new payment profile to Auth.Net customer profile ID: {customer_profile_id}") merchantAuth = apicontractsv1.merchantAuthenticationType(name=API_LOGIN_ID, transactionKey=TRANSACTION_KEY) creditCard = apicontractsv1.creditCardType( cardNumber=card_info.card_number, expirationDate=card_info.expiration_date, cardCode=card_info.cvv ) paymentProfile = apicontractsv1.customerPaymentProfileType( billTo=apicontractsv1.customerAddressType(firstName=customer.customer_first_name, lastName=customer.customer_last_name), payment=apicontractsv1.paymentType(creditCard=creditCard) ) request = apicontractsv1.createCustomerPaymentProfileRequest( merchantAuthentication=merchantAuth, customerProfileId=customer_profile_id, paymentProfile=paymentProfile, validationMode="liveMode" ) controller = createCustomerPaymentProfileController(request) controller.execute() response = controller.getresponse() if response is not None and response.messages.resultCode == "Ok": return str(response.customerPaymentProfileId) else: error_msg = response.messages.message[0].text.text if response and response.messages and response.messages.message else "Unknown Error" logger.error(f"Failed to add payment profile: {error_msg}") return None # --- NEW CHARGE FUNCTION --- def charge_customer_profile(customer_profile_id: str, payment_profile_id: str, transaction_req: schemas.TransactionCreateByCardID): logger.info(f"Charging profile {customer_profile_id} / payment {payment_profile_id} for ${transaction_req.charge_amount}") merchantAuth = apicontractsv1.merchantAuthenticationType(name=API_LOGIN_ID, transactionKey=TRANSACTION_KEY) profile_to_charge = apicontractsv1.profileTransAuthCaptureType( customerProfileId=customer_profile_id, paymentProfileId=payment_profile_id ) transactionRequest = apicontractsv1.transactionRequestType( transactionType="authCaptureTransaction", amount=f"{transaction_req.charge_amount:.2f}", profile=profile_to_charge ) # --- THIS IS THE KEY FOR LOWER RATES (LEVEL 2/3 DATA) --- if transaction_req.tax_amount and transaction_req.tax_amount > 0: transactionRequest.tax = apicontractsv1.extendedAmountType(amount=f"{transaction_req.tax_amount:.2f}", name="Sales Tax") createtransactionrequest = apicontractsv1.createTransactionRequest( merchantAuthentication=merchantAuth, transactionRequest=transactionRequest ) controller = createTransactionController(createtransactionrequest) controller.execute() return controller.getresponse() # --- Your existing authorize/capture functions can remain --- # (They are not included here for brevity but should be kept in your file if you still need them) def authorize_customer_profile( customer_profile_id: str, payment_profile_id: str, transaction_req: schemas.TransactionAuthorizeByCardID ): """ Creates an AUTH_ONLY transaction against a customer profile. This holds the funds but does not capture them. """ logger.info(f"Authorizing profile {customer_profile_id} / payment {payment_profile_id} for ${transaction_req.preauthorize_amount}") merchantAuth = apicontractsv1.merchantAuthenticationType(name=API_LOGIN_ID, transactionKey=TRANSACTION_KEY) # Note the type here: profileTransAuthOnlyType profile_to_authorize = apicontractsv1.profileTransAuthOnlyType( customerProfileId=customer_profile_id, paymentProfileId=payment_profile_id ) transactionRequest = apicontractsv1.transactionRequestType( # The key difference: transactionType is "authOnlyTransaction" transactionType="authOnlyTransaction", amount=f"{transaction_req.preauthorize_amount:.2f}", profile=profile_to_authorize ) # --- LEVEL 2/3 DATA IS STILL CRITICAL HERE --- # The initial authorization is what the card issuers use to determine your rates. if transaction_req.tax_amount and transaction_req.tax_amount > 0: transactionRequest.tax = apicontractsv1.extendedAmountType(amount=f"{transaction_req.tax_amount:.2f}", name="Sales Tax") createtransactionrequest = apicontractsv1.createTransactionRequest( merchantAuthentication=merchantAuth, transactionRequest=transactionRequest ) controller = createTransactionController(createtransactionrequest) controller.execute() return controller.getresponse()