Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base: 8506166902
...
compare: dacb21d4d4
  • 2 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
15 hiicart/gateway/base.py
View
@@ -147,10 +147,12 @@ def __init__(self, type, url=None):
class SubmitResult(object):
"""
The result of a submit operation.
- Currently supported result types are url, form, and None.
+ Currently supported result types are url, form, direct, and None.
url: The user should to be redirected to result.url.
form: form_action is the target url; form_fields is a dict of form data.
+ direct: form_action is the form target; form_fields is a dict of hidden form
+ required by the gateway.
None: type is set to None if no further action is required.
"""
def __init__(self, type, url=None, form_data=None):
@@ -164,3 +166,14 @@ def __init__(self, type, url=None, form_data=None):
else:
self.form_action = None
self.form_fields = None
+
+
+class PaymentResult(object):
+ """
+ Result for a payment confirmation.
+ Currently only supported with direct payment gateways.
+ """
+ def __init__(self, success, status, errors=None):
+ self.success = success
+ self.status = status
+ self.errors = errors
71 hiicart/gateway/braintree/forms.py
View
@@ -0,0 +1,71 @@
+import braintree
+
+from django import forms
+from django.forms.util import ErrorDict
+
+class PaymentForm(forms.Form):
+ """
+ Braintree payment form.
+ """
+ tr_data = forms.CharField(widget=forms.HiddenInput)
+ transaction__credit_card__cardholder_name = forms.CharField()
+ transaction__credit_card__number = forms.CharField()
+ transaction__credit_card__cvv = forms.CharField(min_length=3, max_length=4)
+ transaction__credit_card__expiration_month = forms.CharField(min_length=1, max_length=2)
+ transaction__credit_card__expiration_year = forms.CharField(min_length=4, max_length=4)
+ transaction__billing__first_name = forms.CharField(max_length=255)
+ transaction__billing__last_name = forms.CharField(max_length=255)
+ transaction__billing__street_address = forms.CharField(max_length=80)
+ transaction__billing__extended_address = forms.CharField(max_length=80)
+ transaction__billing__locality = forms.CharField(max_length=50)
+ transaction__billing__region = forms.CharField(max_length=50)
+ transaction__billing__postal_code = forms.CharField(max_length=30)
+ transaction__billing__country_code_alpha2 = forms.CharField(max_length=2)
+ transaction__shipping__first_name = forms.CharField(max_length=255)
+ transaction__shipping__last_name = forms.CharField(max_length=255)
+ transaction__shipping__street_address = forms.CharField(max_length=80)
+ transaction__shipping__extended_address = forms.CharField(max_length=80)
+ transaction__shipping__locality = forms.CharField(max_length=50)
+ transaction__shipping__region = forms.CharField(max_length=50)
+ transaction__shipping__postal_code = forms.CharField(max_length=30)
+ transaction__shipping__country_code_alpha2 = forms.CharField(max_length=2)
+
+ def __init__(self, *args, **kwargs):
+ tr_data = kwargs.pop('tr_data', '')
+ super(PaymentForm, self).__init__(*args, **kwargs)
+
+ def set_transaction(self, tr_data):
+ if self.is_bound:
+ self.data['tr_data'] = tr_data
+ else:
+ self.fields['tr_data'].initial = tr_data
+
+ def set_result(self, result):
+ """
+ Use the results of the gateway payment confirmation to set
+ validation errors on the form.
+ """
+ self._errors = ErrorDict()
+ self.is_bound = True
+ if not result.success:
+ for name, error in result.errors.items():
+ if name == 'cardholder_name':
+ name = 'transaction__credit_card__cardholder_name'
+ elif name == 'number':
+ name = 'transaction__credit_card__number'
+ elif name == 'cvv':
+ name = 'transaction__credit_card__cvv'
+ elif name == 'expiration_month':
+ name = 'transaction__credit_card__expiration_month'
+ elif name == 'expiration_year':
+ name = 'transaction__credit_card__expiration_year'
+ elif name == 'non_field_errors':
+ name = forms.forms.NON_FIELD_ERRORS
+ self._errors[name] = self.error_class([error])
+
+ @property
+ def action(self):
+ """
+ Action to post the form to.
+ """
+ return braintree.TransparentRedirect.url()
41 hiicart/gateway/braintree/gateway.py
View
@@ -2,7 +2,8 @@
from django.template import Context, loader
-from hiicart.gateway.base import PaymentGatewayBase, CancelResult, SubmitResult
+from hiicart.gateway.base import PaymentGatewayBase, CancelResult, SubmitResult, PaymentResult
+from hiicart.gateway.braintree.forms import PaymentForm
from hiicart.gateway.braintree.ipn import BraintreeIPN
from hiicart.gateway.braintree.settings import SETTINGS as default_settings
@@ -35,32 +36,46 @@ def store_return_url(self, request):
return self.settings["RETURN_URL"]
def submit(self, collect_address=False, cart_settings_kwargs=None, submit=False):
- """Returns the type of Gateway"""
+ """Submits a transaction to Braintree."""
return SubmitResult("direct")
- def form_data(self, return_url):
+ @property
+ def form(self):
+ """Return the payment form for the Braintree gateway."""
+ return PaymentForm()
+
+ def start_transaction(self, request):
"""Submits transaction details to Braintree and gets form data."""
- submit_url = braintree.TransparentRedirect.url()
tr_data = braintree.Transaction.tr_data_for_sale({
"transaction": {"type": "sale",
"order_id": self.cart.cart_uuid,
"amount": self.cart.total,
"options": {"submit_for_settlement": True}}},
- return_url)
- return {"action": submit_url,
- "fields": {"tr_data": tr_data}}
+ request.build_absolute_uri(request.path))
+ return tr_data
def confirm_payment(self, request):
"""Confirms payment with Braintree."""
try:
result = braintree.TransparentRedirect.confirm(request.META['QUERY_STRING'])
- except:
- return False
-
+ except Exception, e:
+ errors = {'non_field_errors': 'Request to payment gateway failed.'}
+ return PaymentResult(success=False, status=None, errors=errors)\
+
if result.is_success:
handler = BraintreeIPN(self.cart)
created = handler.new_order(result.transaction)
if created:
- self.cart.set_state("SUBMITTED")
- return True
- return False
+ return PaymentResult(success=True, status=result.transaction.status)
+ errors = {}
+ if not result.transaction:
+ status = None
+ for error in result.errors.deep_errors:
+ errors[error.attribute] = error.message
+ else:
+ status = result.transaction.status
+ if result.transaction.status == "processor_declined":
+ errors = {'non_field_errors': result.transaction.processor_response_text}
+ elif result.transaction.status == "gateway_rejected":
+ errors = {'non_field_errors': result.transaction.gateway_rejection_reason}
+ return PaymentResult(success=False, status=status, errors=errors)
33 hiicart/gateway/braintree/ipn.py
View
@@ -48,21 +48,22 @@ def new_order(self, transaction):
"""Save a new order."""
if not self.cart:
return
- self.cart.ship_first_name = transaction.shipping["first_name"]
- self.cart.ship_last_name = transaction.shipping["last_name"]
- self.cart.ship_street1 = transaction.shipping["street_address"]
- self.cart.ship_street2 = transaction.shipping["extended_address"]
- self.cart.ship_city = transaction.shipping["locality"]
- self.cart.ship_state = transaction.shipping["region"]
- self.cart.ship_postal_code = transaction.shipping["postal_code"]
- self.cart.ship_country = transaction.shipping["country_code_alpha2"]
- self.cart.bill_first_name = transaction.billing["first_name"]
- self.cart.bill_last_name = transaction.billing["last_name"]
- self.cart.bill_street1 = transaction.billing["street_address"]
- self.cart.bill_street2 = transaction.billing["extended_address"]
- self.cart.bill_city = transaction.billing["locality"]
- self.cart.bill_state = transaction.billing["region"]
- self.cart.bill_postal_code = transaction.billing["postal_code"]
- self.cart.bill_country = transaction.billing["country_code_alpha2"]
+ self.cart.ship_first_name = transaction.shipping["first_name"] or self.cart.ship_first_name
+ self.cart.ship_last_name = transaction.shipping["last_name"] or self.cart.ship_last_name
+ self.cart.ship_street1 = transaction.shipping["street_address"] or self.cart.ship_street1
+ self.cart.ship_street2 = transaction.shipping["extended_address"] or self.cart.ship_street2
+ self.cart.ship_city = transaction.shipping["locality"] or self.cart.ship_city
+ self.cart.ship_state = transaction.shipping["region"] or self.cart.ship_state
+ self.cart.ship_postal_code = transaction.shipping["postal_code"] or self.cart.ship_postal_code
+ self.cart.ship_country = transaction.shipping["country_code_alpha2"] or self.cart.ship_country
+ self.cart.bill_first_name = transaction.billing["first_name"] or self.cart.bill_first_name
+ self.cart.bill_last_name = transaction.billing["last_name"] or self.cart.bill_last_name
+ self.cart.bill_street1 = transaction.billing["street_address"] or self.cart.bill_street1
+ self.cart.bill_street2 = transaction.billing["extended_address"] or self.cart.bill_street2
+ self.cart.bill_city = transaction.billing["locality"] or self.cart.bill_city
+ self.cart.bill_state = transaction.billing["region"] or self.cart.bill_state
+ self.cart.bill_postal_code = transaction.billing["postal_code"] or self.cart.bill_postal_code
+ self.cart.bill_country = transaction.billing["country_code_alpha2"] or self.cart.bill_country
+ self.cart._cart_state = "SUBMITTED"
self.cart.save()
self.create_payment(transaction)

No commit comments for this range

Something went wrong with that request. Please try again.