Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc Google Checkout fixes #21

Closed
wants to merge 8 commits into from
33 changes: 19 additions & 14 deletions billing/integrations/google_checkout_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from django.http import HttpResponse
from billing.signals import transaction_was_successful, transaction_was_unsuccessful
from billing import signals
from django.conf.urls.defaults import patterns
from django.utils.decorators import method_decorator

Expand Down Expand Up @@ -64,6 +64,11 @@ def generate_cart_xml(self):
items = doc.createElement('items')
cart.appendChild(items)

merchant_private_data = doc.createElement('merchant-private-data')
cart.appendChild(merchant_private_data)
private_data = unicode(self.fields.get("private_data", ""))
merchant_private_data.appendChild(doc.createTextNode(private_data))

ip_items = self.fields.get("items", [])
for item in ip_items:
it = doc.createElement("item")
Expand Down Expand Up @@ -93,6 +98,7 @@ def generate_cart_xml(self):
return_url.appendChild(doc.createTextNode(self.fields["return_url"]))
merchant_checkout_flow.appendChild(return_url)


cart_xml = doc.toxml(encoding="utf-8")
hmac_signature = hmac.new(settings.GOOGLE_CHECKOUT_MERCHANT_KEY,
cart_xml,
Expand All @@ -112,6 +118,10 @@ def gc_notify_handler(self, request):
self.gc_new_order_notification(request)
elif request.POST['_type'] == 'order-state-change-notification':
self.gc_order_state_change_notification(request)
elif request.POST['_type'] == 'charge-amount-notification':
# TODO add support for this later
pass

return HttpResponse(request.POST['serial-number'])

def gc_cart_items_blob(self, post_data):
Expand Down Expand Up @@ -173,6 +183,7 @@ def gc_new_order_notification(self, request):
"financial-order-state" : "financial_order_state",
"fulfillment-order-state" : "fulfillment_order_state",
"timestamp" : "timestamp",
"shopping-cart.merchant-private-data": "private_data",
}

for (key, val) in resp_fields.iteritems():
Expand All @@ -181,24 +192,18 @@ def gc_new_order_notification(self, request):
data['num_cart_items'] = len(post_data.getlist('shopping-cart.items'))
data['cart_items'] = self.gc_cart_items_blob(post_data)

try:
resp = GCNewOrderNotification.objects.create(**data)
# TODO: Make the type more generic
# TODO: The person might have got charged and yet transaction
# might have failed here. Need a better way to communicate it
transaction_was_successful.send(sender=self.__class__, type="purchase", response=resp)
status = "SUCCESS"
except:
transaction_was_unsuccessful.send(sender=self.__class__, type="purchase", response=post_data)
status = "FAILURE"

return HttpResponse(status)

resp = GCNewOrderNotification.objects.create(**data)

def gc_order_state_change_notification(self, request):
post_data = request.POST.copy()
order = GCNewOrderNotification.objects.get(google_order_number=post_data['google-order-number'])
order.financial_order_state = post_data['new-financial-order-state']
# Send success signal when order state is charged
if order.financial_order_state == 'CHARGED':
signals.transaction_was_successful.send(sender=self.__class__,
type="purchase",
response=order)

order.fulfillment_order_state = post_data['new-fulfillment-order-state']
order.save()

Expand Down
3 changes: 3 additions & 0 deletions billing/models/gc_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ class GCNewOrderNotification(models.Model):
serial_number = models.CharField(max_length=255)
google_order_number = models.CharField(max_length=255)
buyer_id = models.CharField(max_length=255)

# Private merchant data
private_data = models.CharField(max_length=255, blank=True)

# Buyer Shipping Address details
shipping_contact_name = models.CharField(max_length=255, blank=True)
Expand Down
3 changes: 3 additions & 0 deletions billing/templatetags/google_checkout_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from django import template
from django.template.loader import render_to_string

register = template.Library()

class GoogleCheckoutNode(template.Node):
def __init__(self, integration):
self.integration = template.Variable(integration)
Expand All @@ -15,6 +17,7 @@ def render(self, context):
context)
return form_str

@register.tag
def google_checkout(parser, token):
try:
tag, int_obj = token.split_contents()
Expand Down
21 changes: 18 additions & 3 deletions billing/templatetags/paypal_tags.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@
'''
Template tags for paypal offsite payments
'''
from paypal.standard.forms import PayPalPaymentsForm
from paypal.standard.forms import PayPalPaymentsForm, PayPalEncryptedPaymentsForm
from django import template
from django.template.loader import render_to_string
register = template.Library()


class PayPalNode(template.Node):
def __init__(self, integration):
def __init__(self, integration, encrypted=False):
self.integration = template.Variable(integration)
self.encrypted = encrypted

def render(self, context):
int_obj = self.integration.resolve(context)
if self.encrypted:
form_class = PayPalEncryptedPaymentsForm
else:
form_class = PayPalPaymentsForm
form_str = render_to_string("billing/paypal.html",
{"form": PayPalPaymentsForm(initial=int_obj.fields),
{"form": form_class(initial=int_obj.fields),
"integration": int_obj}, context)
return form_str


@register.tag
def paypal(parser, token):
try:
tag, int_obj = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError("%r was expecting a single argument" %token.split_contents()[0])
return PayPalNode(int_obj)


@register.tag
def paypal_encrypted(parser, token):
try:
tag, int_obj = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError("%r was expecting a single argument" %token.split_contents()[0])
return PayPalNode(int_obj, encrypted=True)
2 changes: 1 addition & 1 deletion docs/offsite/google_checkout.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ In views.py::

In some_template.html::

{% load billing_tags %}
{% load google_checkout from google_checkout_tags %}
{% google_checkout obj %}

Template renders to something like below::
Expand Down