def test_config_errors(self): api = PayerPostAPI(agent_id=None, key_1=None, key_2=None) # Checksums (keys 1 & 2) self.assertRaises(PayerPostAPIError, api.get_checksum, "data") api.key_1 = "key1" self.assertRaises(PayerPostAPIError, api.get_checksum, "data") api.key_2 = "key2" raised = False try: api.get_checksum("data") except: raised = True try: api.get_post_data() except PayerPostAPIError as e: self.assertEqual(e.code, PayerPostAPIError.ERROR_MISSING_ORDER) api.set_order(self.getOrder()) self.assertFalse(raised, 'Exception raised') self.assertIsNotNone(api.get_checksum("data")) # Order, Processing control, agent ID self.assertRaises(PayerPostAPIError, api.get_post_data) try: api.get_post_data() except PayerPostAPIError as e: self.assertEqual( e.code, PayerPostAPIError.ERROR_MISSING_PROCESSING_CONTROL) self.assertEqual( str(e), repr("Error %s: %s" % (e.code, e.ERROR_MESSAGES.get(e.code, "Unknown Error")))) api.agent_id = "AGENT_ID" api.set_processing_control(self.getProcessingControl()) raised = False try: api.get_post_data() except: raised = True self.assertFalse(raised, 'Exception raised') api.agent_id = None self.assertRaises(PayerPostAPIError, api._generate_xml)
class GenericPayerBackend(object): url_namespace = 'payer' backend_name = _('Payer') template = 'payer_backend/redirect.html' payment_methods = [ PAYMENT_METHOD_CARD, PAYMENT_METHOD_BANK, PAYMENT_METHOD_PHONE, PAYMENT_METHOD_INVOICE, ] def __init__(self, shop): self.shop = shop self.api = PayerPostAPI( agent_id=getattr(settings, 'SHOP_PAYER_BACKEND_AGENT_ID', ''), key_1=getattr(settings, 'SHOP_PAYER_BACKEND_ID1', ''), key_2=getattr(settings, 'SHOP_PAYER_BACKEND_ID2', ''), payment_methods=self.payment_methods, test_mode=getattr(settings, 'SHOP_PAYER_BACKEND_TEST_MODE', False), debug_mode=getattr(settings, 'SHOP_PAYER_BACKEND_DEBUG_MODE', DEBUG_MODE_SILENT), hide_details=getattr(settings, 'SHOP_PAYER_BACKEND_HIDE_DETAILS', False), ) for ip in getattr(settings, 'SHOP_PAYER_BACKEND_IP_WHITELIST', []): self.api.add_whitelist_ip(ip) for ip in getattr(settings, 'SHOP_PAYER_BACKEND_IP_BLACKLIST', []): self.api.add_blacklist_ip(ip) def get_url_name(self, name=None): if not name: return self.url_namespace return '%s-%s' % (self.url_namespace, name,) def get_urls(self): urlpatterns = patterns( '', url(r'^$', self.payer_redirect_view, name=self.get_url_name()), url(r'^authorize/$', self.callback_notification_view, name=self.get_url_name('authorize')), url(r'^settle/$', self.callback_notification_view, name=self.get_url_name('settle')), ) return urlpatterns def get_processing_control(self, request): return PayerProcessingControl( success_redirect_url=request.build_absolute_uri(self.shop.get_finished_url()), authorize_notification_url=request.build_absolute_uri(reverse(self.get_url_name('authorize'))), settle_notification_url=request.build_absolute_uri(reverse(self.get_url_name('settle'))), redirect_back_to_shop_url=request.build_absolute_uri(self.shop.get_cancel_url()), ) @on_method(shop_login_required) @on_method(order_required) def payer_redirect_view(self, request): """ This view generates the order XML data and other key-value pairs needed, outputs the as hidden input elemens in a form and redirects to Payer. """ order = self.shop.get_order(request) description = self.shop.get_order_short_name(order) order_id = self.shop.get_order_unique_id(order) user = None if request.user.is_authenticated(): user = request.user payer_order = PayerOrder( order_id=order_id, description=description, ) payer_order.set_buyer_details(buyer_details_from_user(user=user, order=order)) for order_item in order.items.all(): payer_order.add_order_item(payer_order_item_from_order_item(order_item)) for extra_order_price in order.extraorderpricefield_set.all(): payer_order.add_order_item(payer_order_item_from_extra_order_price(extra_order_price)) for info in order.extra_info.all(): for t in list(string_chunks(info.text, 255)): payer_order.add_info_line(t) self.api.set_processing_control(self.get_processing_control(request)) self.api.set_order(payer_order) redirect_data = self.api.get_post_data() form = PayerRedirectForm(redirect_data=redirect_data) ctx_data = { 'order': order, 'redirect_data': redirect_data, 'form_action': self.api.get_post_url(), 'form': form, } if settings.DEBUG: ctx_data['xml_data'] = self.api.get_xml_data(pretty_print=True) context = RequestContext(request, ctx_data) return render_to_response(self.template, context) def is_valid_remote_addr(self, request): def get_remote_addr(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') return ip try: remote_addr = get_remote_addr(request) return self.api.validate_callback_ip(remote_addr) except Exception as e: logging.error(u"IP address callback did not validate: %s" % unicode(e)) return False def is_valid_callback(self, request): try: url = request.build_absolute_uri(request.get_full_path()) return self.api.validate_callback_url(url) except Exception as e: logging.error(u"Callback URL did not validate: %s" % unicode(e)) return False def callback_notification_view(self, request): valid_callback = self.is_valid_remote_addr(request) and self.is_valid_callback(request) if valid_callback: try: self.handle_order_notifications(request.GET) except Exception as e: logging.error(u"Error handling order notification: %s" % unicode(e)) return HttpResponse("TRUE" if valid_callback else "FALSE", content_type="text/plain") def handle_order_notifications(self, data): order_id = data.get(PayerXMLDocument.ORDER_ID_URL_PARAMETER_NAME, data.get('payer_merchant_reference_id', None)) payment_method = data.get('payer_payment_type', 'unknown') transaction_id = data.get('payer_payment_id', data.get('payread_payment_id', None)) callback_type = data.get('payer_callback_type', '').lower() # testmode = bool(data.get('payer_testmode', 'false') == 'true') # added_fee = data.get('payer_added_fee', 0) if order_id is not None: order = Order.objects.get(pk=order_id) if callback_type == 'auth': # Payment approved, update order status, empty cart order.status = Order.CONFIRMED order.save() try: cart = Cart.objects.get(pk=order.cart_pk) cart.empty() except Cart.DoesNotExist: pass confirmed.send(sender=self, order=order) elif callback_type == 'settle': # Payment completed, update order status, add payment order.status = Order.COMPLETED self.shop.confirm_payment(order, self.shop.get_order_total(order), transaction_id, u"Payer %s (%s)" % (unicode(self.backend_name).lower(), payment_method,)) completed.send(sender=self, order=order)