Good progession

This commit is contained in:
2025-09-18 13:01:58 -04:00
parent 630584512e
commit 4bdfb4238d
4 changed files with 102 additions and 40 deletions

View File

@@ -90,7 +90,7 @@ def update_transaction_for_capture(db: Session, auth_net_transaction_id: str, ch
return None return None
transaction.charge_amount = charge_amount if status == 0 else Decimal("0.0") transaction.charge_amount = charge_amount if status == 0 else Decimal("0.0")
transaction.transaction_type = 3 transaction.transaction_type = 2
transaction.status = status transaction.status = status
if rejection_reason: if rejection_reason:
transaction.rejection_reason = rejection_reason transaction.rejection_reason = rejection_reason

View File

@@ -56,7 +56,7 @@ class Transaction(Base):
preauthorize_amount = Column(Numeric(10, 2), nullable=True) preauthorize_amount = Column(Numeric(10, 2), nullable=True)
charge_amount = Column(Numeric(10, 2), nullable=True) charge_amount = Column(Numeric(10, 2), nullable=True)
customer_id = Column(Integer) customer_id = Column(Integer)
transaction_type = Column(Integer) transaction_type = Column(Integer)# 0 = charge, 1 = auth, 2 = capture
status = Column(Integer) status = Column(Integer)
auth_net_transaction_id = Column(String, unique=True, index=True, nullable=True) auth_net_transaction_id = Column(String, unique=True, index=True, nullable=True)
service_id = Column(Integer, nullable=True) service_id = Column(Integer, nullable=True)

View File

@@ -36,55 +36,87 @@ STATE_ID_TO_ABBREVIATION = {
6: "NY" 6: "NY"
} }
# This helper function is perfect, keep it.
def _parse_authnet_response(response: Optional[AuthNetResponse]) -> Tuple[TransactionStatus, Optional[str], Optional[str]]: def _parse_authnet_response(response: Optional[AuthNetResponse]) -> Tuple[TransactionStatus, Optional[str], Optional[str]]:
# ... (Your existing _parse_authnet_response function code) ... """
Parse Authorize.net response with proper attribute access for SDK objects.
Authorize.net response objects don't have .text properties, they're direct attributes.
"""
print(f"DEBUG: Parsing response, type: {type(response)}")
print(f"DEBUG: Response exists: {response is not None}")
if response is not None:
print("DEBUG: Checking for messages attribute...")
if hasattr(response, 'messages'):
print(f"DEBUG: Messages exist, resultCode: {getattr(response.messages, 'resultCode', 'NO resultCode')}")
else:
print("DEBUG: No messages attribute")
if response is not None and hasattr(response, 'messages') and response.messages.resultCode == "Ok": if response is not None and hasattr(response, 'messages') and response.messages.resultCode == "Ok":
print("DEBUG: Taking APPROVED path")
status = TransactionStatus.APPROVED status = TransactionStatus.APPROVED
auth_net_transaction_id = str(response.transactionResponse.transId) if hasattr(response, 'transactionResponse') and response.transactionResponse.transId else None auth_net_transaction_id = None
# Extract transaction ID with proper error handling
try:
if hasattr(response, 'transactionResponse') and response.transactionResponse:
if hasattr(response.transactionResponse, 'transId') and response.transactionResponse.transId:
auth_net_transaction_id = str(response.transactionResponse.transId)
print(f"DEBUG: FOUND transaction ID: {auth_net_transaction_id}")
else:
print("DEBUG: transactionResponse exists but no transId")
else:
print("DEBUG: No transactionResponse in approved response")
except Exception as e:
print(f"DEBUG: Exception extracting transaction ID: {e}")
print(f"DEBUG: Response object inspection:")
print(type(response))
if hasattr(response, 'transactionResponse'):
print(f"TransactionResponse type: {type(response.transactionResponse)}")
print(dir(response.transactionResponse))
rejection_reason = None rejection_reason = None
print(f"DEBUG: APPROVED - ID: {auth_net_transaction_id}, rejection: {rejection_reason}")
else: else:
print("DEBUG: Taking DECLINED path")
status = TransactionStatus.DECLINED status = TransactionStatus.DECLINED
auth_net_transaction_id = None auth_net_transaction_id = None
rejection_reason = "Payment declined by gateway." rejection_reason = "Payment declined by gateway."
print("DEBUG: Full response object")
print(response)
print("DEBUG: response.messages")
print(response.messages)
print("DEBUG: response.messages.resultCode")
print(response.messages.resultCode)
if response is not None: if response is not None:
if hasattr(response, 'transactionResponse') and response.transactionResponse and hasattr(response.transactionResponse, 'errors') and response.transactionResponse.errors: # Handle transaction response errors
print("DEBUG: Using transactionResponse.errors") if hasattr(response, 'transactionResponse') and response.transactionResponse:
error = response.transactionResponse.errors[0] if hasattr(response.transactionResponse, 'errors') and response.transactionResponse.errors:
rejection_reason = f"{error.errorCode.text}: {error.errorText.text}" print("DEBUG: Using transactionResponse.errors")
elif hasattr(response, 'messages') and response.messages and hasattr(response.messages, 'message') and response.messages.message: try:
print("DEBUG: Using response.messages.message") error = response.transactionResponse.errors[0]
msg = response.messages.message[0] # Remove the .text access - use direct attributes
print("DEBUG: msg object") error_code = getattr(error, 'errorCode', 'Unknown')
print(msg) error_text = getattr(error, 'errorText', 'Unknown error')
print("DEBUG: msg attributes") rejection_reason = f"{error_code}: {error_text}"
print(dir(msg)) print(f"DEBUG: Transaction error: {rejection_reason}")
print("DEBUG: msg.code") except Exception as e:
print(getattr(msg, 'code', 'NO code ATTR')) print(f"DEBUG: Exception parsing transaction error: {e}")
print("DEBUG: msg.text") rejection_reason = "Failed to parse transaction error"
print(getattr(msg, 'text', 'NO text ATTR'))
code_val = None # Handle message-level errors
text_val = None elif hasattr(response, 'messages') and response.messages:
if hasattr(msg, 'code') and msg.code is not None and hasattr(msg.code, 'text'): if hasattr(response.messages, 'message') and response.messages.message:
code_val = msg.code.text print("DEBUG: Using response.messages.message")
elif hasattr(msg, 'code'): try:
code_val = str(msg.code) msg = response.messages.message
if isinstance(msg, list):
msg = msg[0] if msg else None
if msg:
code = getattr(msg, 'code', 'Unknown')
text = getattr(msg, 'text', 'Unknown error')
rejection_reason = f"{code}: {text}"
print(f"DEBUG: Message error: {rejection_reason}")
except Exception as e:
print(f"DEBUG: Exception parsing message error: {e}")
rejection_reason = "Failed to parse message error"
if hasattr(msg, 'text') and msg.text is not None and hasattr(msg.text, 'text'): print(f"DEBUG: FINAL RESULT - Status: {status}, ID: {auth_net_transaction_id}, Reason: {rejection_reason}")
text_val = msg.text.text
elif hasattr(msg, 'text'):
text_val = str(msg.text)
rejection_reason = f"{code_val}: {text_val}" if code_val and text_val and text_val != "None" else f"{code_val}" if code_val else f"Error: {getattr(msg, 'text', 'Unknown error')}"
print("DEBUG: Constructed rejection_reason")
print(rejection_reason)
return status, auth_net_transaction_id, rejection_reason return status, auth_net_transaction_id, rejection_reason
@router.post("/customers/{customer_id}/cards", summary="Add a new payment card for a customer") @router.post("/customers/{customer_id}/cards", summary="Add a new payment card for a customer")

View File

@@ -276,3 +276,33 @@ def capture_authorized_transaction(transaction_req: schemas.TransactionCapture):
controller = createTransactionController(createtransactionrequest) controller = createTransactionController(createtransactionrequest)
controller.execute() controller.execute()
return controller.getresponse() return controller.getresponse()
def charge_customer_profile(customer_profile_id: str, payment_profile_id: str, transaction_req: schemas.TransactionCreateByCardID):
"""
Creates an AUTH_CAPTURE transaction (charge now) against a customer profile.
This charges the customer immediately for the full amount.
"""
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.customerProfilePaymentType()
profile_to_charge.customerProfileId = customer_profile_id
profile_to_charge.customerPaymentProfileId = payment_profile_id
transactionRequest = apicontractsv1.transactionRequestType(
transactionType="authCaptureTransaction",
amount=f"{transaction_req.charge_amount:.2f}",
profile=profile_to_charge
)
createtransactionrequest = apicontractsv1.createTransactionRequest(
merchantAuthentication=merchantAuth,
transactionRequest=transactionRequest
)
controller = createTransactionController(createtransactionrequest)
controller.execute()
# The response is returned directly to the router to be parsed there
return controller.getresponse()