Updated charge close to working

This commit is contained in:
2025-09-09 18:28:41 -04:00
parent 8c37b6aeab
commit 8d134f691b
15 changed files with 40 additions and 113 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
__pycache__/
*.pyc
*.pyo
*.pyd

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -12,17 +12,17 @@ def get_customers(db: Session, skip: int = 0, limit: int = 100):
def create_transaction(db: Session, transaction: schemas.TransactionBase, customer_id: int, status: int, auth_net_transaction_id: str = None): def create_transaction(db: Session, transaction: schemas.TransactionBase, customer_id: int, status: int, auth_net_transaction_id: str = None):
db_transaction = models.Transaction( db_transaction = models.Transaction(
preauthorize_amount=transaction.preauthorize_amount, preauthorize_amount=transaction.preauthorize_amount if status == 0 else 0, # Only save pre-auth amount if approved
charge_amount=transaction.charge_amount, charge_amount=transaction.charge_amount if transaction.transaction_type != 0 or status == 0 else 0, # Only save charge amount for charges if approved
transaction_type=transaction.transaction_type, transaction_type=transaction.transaction_type,
customer_id=customer_id, customer_id=customer_id,
status=status, status=status,
auth_net_transaction_id=auth_net_transaction_id, auth_net_transaction_id=auth_net_transaction_id,
service_id=transaction.service_id, service_id=transaction.service_id,
delivery_id=transaction.delivery_id, delivery_id=transaction.delivery_id,
card_id=transaction.card_id, card_id=transaction.card_id,
payment_gateway=transaction.payment_gateway, payment_gateway=transaction.payment_gateway,
rejection_reason=transaction.rejection_reason rejection_reason=transaction.rejection_reason
) )
db.add(db_transaction) db.add(db_transaction)
db.commit() db.commit()
@@ -50,7 +50,8 @@ def update_transaction_for_capture(db: Session, auth_net_transaction_id: str, ch
if not transaction: if not transaction:
return None return None
transaction.charge_amount = charge_amount # Set charge_amount only if approved (status == 0), otherwise set to 0
transaction.charge_amount = charge_amount if status == 0 else 0
transaction.transaction_type = 3 # capture transaction.transaction_type = 3 # capture
transaction.status = status transaction.status = status
if rejection_reason: if rejection_reason:
@@ -58,4 +59,4 @@ def update_transaction_for_capture(db: Session, auth_net_transaction_id: str, ch
db.commit() db.commit()
db.refresh(transaction) db.refresh(transaction)
return transaction return transaction

View File

@@ -34,19 +34,39 @@ def _parse_authnet_response(response: Optional[AuthNetResponse]) -> Tuple[Transa
Parses the response from the Authorize.Net service. Parses the response from the Authorize.Net service.
(This is the same helper from before, it's a good change to keep) (This is the same helper from before, it's a good change to keep)
""" """
if response and hasattr(response, 'messages') and response.messages.resultCode == "Ok": if response is not None and hasattr(response, 'messages') and response.messages.resultCode == "Ok":
status = TransactionStatus.APPROVED status = TransactionStatus.APPROVED
auth_net_transaction_id = str(response.transactionResponse.transId) if hasattr(response, 'transactionResponse') else None auth_net_transaction_id = str(response.transactionResponse.transId) if hasattr(response, 'transactionResponse') else None
rejection_reason = None rejection_reason = None
else: else:
status = TransactionStatus.DECLINED status = TransactionStatus.DECLINED
auth_net_transaction_id = None auth_net_transaction_id = None
if hasattr(response, '_rejection_reason'):
# Improved rejection reason extraction
rejection_reason = "Payment declined by gateway."
if hasattr(response, '_rejection_reason') and response._rejection_reason:
rejection_reason = str(response._rejection_reason) rejection_reason = str(response._rejection_reason)
elif response is not None:
# Check transaction response for errors
if hasattr(response, 'transactionResponse') and response.transactionResponse:
tr = response.transactionResponse
if hasattr(tr, 'errors') and tr.errors:
for error in tr.errors:
if hasattr(error, 'errorCode') and hasattr(error, 'errorText'):
error_code = error.errorCode.text if error.errorCode else "Unknown"
error_text = error.errorText.text if error.errorText else "No error details"
rejection_reason = f"{error_code}: {error_text}"
break
elif hasattr(tr, 'messages') and tr.messages:
if len(tr.messages) > 0:
msg = tr.messages[0]
if hasattr(msg, 'code') and hasattr(msg, 'description'):
code = msg.code.text if msg.code else "Unknown"
desc = msg.description.text if msg.description else "No description"
rejection_reason = f"{code}: {desc}"
elif response is None: elif response is None:
rejection_reason = "No response received from payment gateway." rejection_reason = "No response received from payment gateway."
else:
rejection_reason = "Payment declined by gateway."
return status, auth_net_transaction_id, rejection_reason return status, auth_net_transaction_id, rejection_reason
@@ -74,9 +94,6 @@ def authorize_card(customer_id: int, transaction: schemas.TransactionAuthorize,
@router.post("/charge/{customer_id}", response_model=schemas.Transaction) @router.post("/charge/{customer_id}", response_model=schemas.Transaction)
def charge_card(customer_id: int, transaction: schemas.TransactionCreate, db: Session = Depends(database.get_db)): def charge_card(customer_id: int, transaction: schemas.TransactionCreate, db: Session = Depends(database.get_db)):
# Add debug logging
print(f"DEBUG: Received charge request for customer_id: {customer_id}")
print(f"DEBUG: Transaction data: {transaction.dict() if hasattr(transaction, 'dict') else transaction}")
try: try:
auth_net_response = payment_service.charge_credit_card(transaction) auth_net_response = payment_service.charge_credit_card(transaction)
@@ -90,7 +107,6 @@ def charge_card(customer_id: int, transaction: schemas.TransactionCreate, db: Se
card_id=transaction.card_id, card_id=transaction.card_id,
rejection_reason=rejection_reason rejection_reason=rejection_reason
) )
print(f"DEBUG: Transaction data to create: {transaction_data.dict()}")
result = crud.create_transaction( result = crud.create_transaction(
db=db, db=db,
@@ -99,7 +115,6 @@ def charge_card(customer_id: int, transaction: schemas.TransactionCreate, db: Se
status=status, status=status,
auth_net_transaction_id=auth_net_transaction_id auth_net_transaction_id=auth_net_transaction_id
) )
print(f"DEBUG: Created transaction: {result.dict()}")
return result return result
except Exception as e: except Exception as e:
print(f"DEBUG: Exception in charge_card: {str(e)}") print(f"DEBUG: Exception in charge_card: {str(e)}")

View File

@@ -55,46 +55,15 @@ def charge_credit_card(transaction: schemas.TransactionCreate):
response = controller.getresponse() response = controller.getresponse()
# Extract rejection reason if payment failed # Log response status if payment failed
rejection_reason = None
if response is not None and response.messages is not None: if response is not None and response.messages is not None:
logger.info(f"Charge response: {response.messages.resultCode}") logger.info(f"Charge response: {response.messages.resultCode}")
# If payment was declined (resultCode is "Error"), extract error details
if response.messages.resultCode == "Error":
rejection_reason = "Authorize.Net Charge Error"
if hasattr(response.messages, 'message'):
try:
if len(response.messages.message) > 0:
for msg in response.messages.message:
if hasattr(msg, 'code') and hasattr(msg, 'text'):
# Convert lxml StringElement objects to Python strings
code_str = msg.code.text if msg.code else "Unknown"
text_str = msg.text.text if msg.text else "No details available"
rejection_reason = f"{code_str}: {text_str}"
break # Use the first error message
elif hasattr(msg, 'text'):
# Convert lxml StringElement to Python string
text_str = msg.text.text if msg.text else "No details available"
rejection_reason = f"Error: {text_str}"
break
else:
rejection_reason = "Charge declined - no specific error details available"
except Exception as e:
rejection_reason = f"Charge declined - error details could not be parsed: {str(e)}"
else:
rejection_reason = "Charge declined - no error message available"
if hasattr(response.messages, 'message') and len(response.messages.message) > 0: if hasattr(response.messages, 'message') and len(response.messages.message) > 0:
for msg in response.messages.message: for msg in response.messages.message:
logger.info(f"Message: {msg.text.text if msg.text else 'No message text'}") logger.info(f"Message: {msg.text.text if msg.text else 'No message text'}")
else: else:
logger.error("No response from Authorize.net") logger.error("No response from Authorize.net")
rejection_reason = "No response received from Authorize.Net"
# Attach rejection reason to response for the router to use
if response is not None:
response._rejection_reason = rejection_reason
return response return response
@@ -128,46 +97,15 @@ def authorize_credit_card(transaction: schemas.TransactionAuthorize):
response = controller.getresponse() response = controller.getresponse()
# Extract rejection reason if payment failed # Log response status
rejection_reason = None
if response is not None and response.messages is not None: if response is not None and response.messages is not None:
logger.info(f"Preauthorization response: {response.messages.resultCode}") logger.info(f"Preauthorization response: {response.messages.resultCode}")
# If payment was declined (resultCode is "Error"), extract error details
if response.messages.resultCode == "Error":
rejection_reason = "Authorize.Net Error"
if hasattr(response.messages, 'message'):
try:
if len(response.messages.message) > 0:
for msg in response.messages.message:
if hasattr(msg, 'code') and hasattr(msg, 'text'):
# Convert lxml StringElement objects to Python strings
code_str = msg.code.text if msg.code else "Unknown"
text_str = msg.text.text if msg.text else "No details available"
rejection_reason = f"{code_str}: {text_str}"
break # Use the first error message
elif hasattr(msg, 'text'):
# Convert lxml StringElement to Python string
text_str = msg.text.text if msg.text else "No details available"
rejection_reason = f"Error: {text_str}"
break
else:
rejection_reason = "Payment declined - no specific error details available"
except Exception as e:
rejection_reason = f"Payment declined - error details could not be parsed: {str(e)}"
else:
rejection_reason = "Payment declined - no error message available"
if hasattr(response.messages, 'message') and len(response.messages.message) > 0: if hasattr(response.messages, 'message') and len(response.messages.message) > 0:
for msg in response.messages.message: for msg in response.messages.message:
logger.info(f"Message: {msg.text.text if msg.text else 'No message text'}") logger.info(f"Message: {msg.text.text if msg.text else 'No message text'}")
else: else:
logger.error("No response from Authorize.net for preauthorization") logger.error("No response from Authorize.net for preauthorization")
rejection_reason = "No response received from Authorize.Net"
# Attach rejection reason to response for the router to use
if response is not None:
response._rejection_reason = rejection_reason
return response return response
@@ -191,45 +129,14 @@ def capture_authorized_transaction(transaction: schemas.TransactionCapture):
response = controller.getresponse() response = controller.getresponse()
# Extract rejection reason if capture failed # Log response status
rejection_reason = None
if response is not None and response.messages is not None: if response is not None and response.messages is not None:
logger.info(f"Capture response: {response.messages.resultCode}") logger.info(f"Capture response: {response.messages.resultCode}")
# If capture was declined (resultCode is "Error"), extract error details
if response.messages.resultCode == "Error":
rejection_reason = "Authorize.Net Capture Error"
if hasattr(response.messages, 'message'):
try:
if len(response.messages.message) > 0:
for msg in response.messages.message:
if hasattr(msg, 'code') and hasattr(msg, 'text'):
# Convert lxml StringElement objects to Python strings
code_str = msg.code.text if msg.code else "Unknown"
text_str = msg.text.text if msg.text else "No details available"
rejection_reason = f"{code_str}: {text_str}"
break # Use the first error message
elif hasattr(msg, 'text'):
# Convert lxml StringElement to Python string
text_str = msg.text.text if msg.text else "No details available"
rejection_reason = f"Error: {text_str}"
break
else:
rejection_reason = "Capture declined - no specific error details available"
except Exception as e:
rejection_reason = f"Capture declined - error details could not be parsed: {str(e)}"
else:
rejection_reason = "Capture declined - no error message available"
if hasattr(response.messages, 'message') and len(response.messages.message) > 0: if hasattr(response.messages, 'message') and len(response.messages.message) > 0:
for msg in response.messages.message: for msg in response.messages.message:
logger.info(f"Message: {msg.text.text if msg.text else 'No message text'}") logger.info(f"Message: {msg.text.text if msg.text else 'No message text'}")
else: else:
logger.error("No response from Authorize.net for capture") logger.error("No response from Authorize.net for capture")
rejection_reason = "No response received from Authorize.Net for capture"
# Attach rejection reason to response for the router to use
if response is not None:
response._rejection_reason = rejection_reason
return response return response