Esempio n. 1
0
class FPSTestCase(unittest.TestCase):

    def setUp(self):
        self.fps = FPSConnection(host='fps.sandbox.amazonaws.com')
        if advanced:
            self.activity = self.fps.get_account_activity(\
                                StartDate='2012-01-01')
            result = self.activity.GetAccountActivityResult
            self.transactions = result.Transaction

    @unittest.skipUnless(simple, "skipping simple test")
    def test_get_account_balance(self):
        response = self.fps.get_account_balance()
        self.assertTrue(hasattr(response, 'GetAccountBalanceResult'))
        self.assertTrue(hasattr(response.GetAccountBalanceResult,
                                                'AccountBalance'))
        accountbalance = response.GetAccountBalanceResult.AccountBalance
        self.assertTrue(hasattr(accountbalance, 'TotalBalance'))
        self.assertIsInstance(accountbalance.TotalBalance, ComplexAmount)
        self.assertTrue(hasattr(accountbalance, 'AvailableBalances'))
        availablebalances = accountbalance.AvailableBalances
        self.assertTrue(hasattr(availablebalances, 'RefundBalance'))

    @unittest.skipUnless(simple, "skipping simple test")
    def test_complex_amount(self):
        response = self.fps.get_account_balance()
        accountbalance = response.GetAccountBalanceResult.AccountBalance
        asfloat = float(accountbalance.TotalBalance.Value)
        self.assertIn('.', str(asfloat))

    @unittest.skipUnless(simple, "skipping simple test")
    def test_required_arguments(self):
        with self.assertRaises(KeyError):
            self.fps.write_off_debt(AdjustmentAmount=123.45)

    @unittest.skipUnless(simple, "skipping simple test")
    def test_cbui_url(self):
        inputs = {
            'transactionAmount':    123.45,
            'pipelineName':         'SingleUse',
            'returnURL':            'https://localhost/',
            'paymentReason':        'a reason for payment',
            'callerReference':      'foo',
        }
        result = self.fps.cbui_url(**inputs)
        print "cbui_url() yields {0}".format(result)

    @unittest.skipUnless(simple, "skipping simple test")
    def test_get_account_activity(self):
        response = self.fps.get_account_activity(StartDate='2012-01-01')
        self.assertTrue(hasattr(response, 'GetAccountActivityResult'))
        result = response.GetAccountActivityResult
        self.assertTrue(hasattr(result, 'BatchSize'))
        try:
            int(result.BatchSize)
        except:
            self.assertTrue(False)

    @unittest.skipUnless(advanced, "skipping advanced test")
    def test_get_transaction(self):
        assert len(self.transactions)
        transactionid = self.transactions[0].TransactionId
        result = self.fps.get_transaction(TransactionId=transactionid)
        self.assertTrue(hasattr(result.GetTransactionResult, 'Transaction'))

    @unittest.skip('cosmetic')
    def test_bad_request(self):
        try:
            self.fps.write_off_debt(CreditInstrumentId='foo',
                                    AdjustmentAmount=123.45)
        except Exception as e:
            print e

    @unittest.skip('cosmetic')
    def test_repr(self):
        print self.fps.get_account_balance()
Esempio n. 2
0
class FPSTestCase(unittest.TestCase):
    def setUp(self):
        self.fps = FPSConnection(host="fps.sandbox.amazonaws.com")
        if advanced:
            self.activity = self.fps.get_account_activity(StartDate="2012-01-01")
            result = self.activity.GetAccountActivityResult
            self.transactions = result.Transaction

    @unittest.skipUnless(simple, "skipping simple test")
    def test_get_account_balance(self):
        response = self.fps.get_account_balance()
        self.assertTrue(hasattr(response, "GetAccountBalanceResult"))
        self.assertTrue(hasattr(response.GetAccountBalanceResult, "AccountBalance"))
        accountbalance = response.GetAccountBalanceResult.AccountBalance
        self.assertTrue(hasattr(accountbalance, "TotalBalance"))
        self.assertIsInstance(accountbalance.TotalBalance, ComplexAmount)
        self.assertTrue(hasattr(accountbalance, "AvailableBalances"))
        availablebalances = accountbalance.AvailableBalances
        self.assertTrue(hasattr(availablebalances, "RefundBalance"))

    @unittest.skipUnless(simple, "skipping simple test")
    def test_complex_amount(self):
        response = self.fps.get_account_balance()
        accountbalance = response.GetAccountBalanceResult.AccountBalance
        asfloat = float(accountbalance.TotalBalance.Value)
        self.assertIn(".", str(asfloat))

    @unittest.skipUnless(simple, "skipping simple test")
    def test_required_arguments(self):
        with self.assertRaises(KeyError):
            self.fps.write_off_debt(AdjustmentAmount=123.45)

    @unittest.skipUnless(simple, "skipping simple test")
    def test_cbui_url(self):
        inputs = {
            "transactionAmount": 123.45,
            "pipelineName": "SingleUse",
            "returnURL": "https://localhost/",
            "paymentReason": "a reason for payment",
            "callerReference": "foo",
        }
        result = self.fps.cbui_url(**inputs)
        print "cbui_url() yields {0}".format(result)

    @unittest.skipUnless(simple, "skipping simple test")
    def test_get_account_activity(self):
        response = self.fps.get_account_activity(StartDate="2012-01-01")
        self.assertTrue(hasattr(response, "GetAccountActivityResult"))
        result = response.GetAccountActivityResult
        self.assertTrue(hasattr(result, "BatchSize"))
        try:
            int(result.BatchSize)
        except:
            self.assertTrue(False)

    @unittest.skipUnless(advanced, "skipping advanced test")
    def test_get_transaction(self):
        assert len(self.transactions)
        transactionid = self.transactions[0].TransactionId
        result = self.fps.get_transaction(TransactionId=transactionid)
        self.assertTrue(hasattr(result.GetTransactionResult, "Transaction"))

    @unittest.skip("cosmetic")
    def test_bad_request(self):
        try:
            self.fps.write_off_debt(CreditInstrumentId="foo", AdjustmentAmount=123.45)
        except Exception, e:
            print e
class AmazonFpsIntegration(Integration):
    """
    Fields required:
    transactionAmount: Amount to be charged/authorized
    paymentReason: Description of the transaction
    paymentPage: Page to direct the user on completion/failure of transaction
    """

    display_name = "Amazon Flexible Payment Service"
    template = "billing/amazon_fps.html"

    def __init__(self, options=None):
        if not options:
            options = {}
        merchant_settings = getattr(settings, "MERCHANT_SETTINGS")
        if not merchant_settings or not merchant_settings.get("amazon_fps"):
            raise IntegrationNotConfigured("The '%s' integration is not correctly "
                                       "configured." % self.display_name)
        amazon_fps_settings = merchant_settings["amazon_fps"]
        self.aws_access_key = options.get("aws_access_key", None) or amazon_fps_settings['AWS_ACCESS_KEY']
        self.aws_secret_access_key = options.get("aws_secret_access_key", None) or amazon_fps_settings['AWS_SECRET_ACCESS_KEY']
        super(AmazonFpsIntegration, self).__init__(options=options)
        options.setdefault('host', self.service_url)
        self.fps_connection = FPSConnection(self.aws_access_key, self.aws_secret_access_key, **options)

    @property
    def service_url(self):
        if self.test_mode:
            return FPS_SANDBOX_API_ENDPOINT
        return FPS_PROD_API_ENDPOINT

    @property
    def link_url(self):
        tmp_fields = self.fields.copy()
        tmp_fields.pop("aws_access_key", None)
        tmp_fields.pop("aws_secret_access_key", None)
        tmp_fields.pop("paymentPage", None)
        return self.fps_connection.cbui_url(returnURL=tmp_fields.pop("returnURL"),
                                            paymentReason=tmp_fields.pop("paymentReason"),
                                            pipelineName=tmp_fields.pop("pipelineName"),
                                            transactionAmount=str(tmp_fields.pop("transactionAmount")),
                                            **tmp_fields)

    def purchase(self, amount, options=None):
        if not options:
            options = {}
        tmp_options = options.copy()
        permissible_options = ["SenderTokenId", "CallerReference",
            "SenderDescription", "CallerDescription", "TransactionTimeoutInMins"
            "TransactionAmount", "OverrideIPNURL", "DescriptorPolicy"]
        tmp_options['TransactionAmount'] = amount
        if 'tokenID' in options:
            tmp_options["SenderTokenId"] = options["tokenID"]
        if 'callerReference' in options:
            tmp_options['CallerReference'] = options["callerReference"]
        for key in options:
            if key not in permissible_options:
                tmp_options.pop(key)
        resp = self.fps_connection.pay(**tmp_options)
        return {"status": resp.PayResult.TransactionStatus, "response": resp.PayResult}

    def authorize(self, amount, options=None):
        """ 
        amount: the amount of money to authorize.
        options:
            Required:
                CallerReference
                SenderTokenId
                TransactionAmount

            Conditional:
                SenderDescription

            Optional:
                CallerDescription
                DescriptorPolicy
                OverrideIPNURL
                TransactionTimeoutInMins

            See: http://docs.aws.amazon.com/AmazonFPS/latest/FPSBasicGuide/Reserve.html
            for more info
        """
        if not options:
            options = {}
        options['TransactionAmount'] = amount
        resp = self.fps_connection.reserve(**options)
        return {"status": resp.ReserveResult.TransactionStatus, "response": resp.ReserveResult}

    def capture(self, amount, options=None):
        if not options:
            options = {}
        assert "ReserveTransactionId" in options, "Expecting 'ReserveTransactionId' in options"
        resp = self.fps_connection.settle(options["ReserveTransactionId"], amount)
        return {"status": resp.SettleResult.TransactionStatus, "response": resp.SettleResult}

    def credit(self, amount, options=None):
        if not options:
            options = {}
        assert "CallerReference" in options, "Expecting 'CallerReference' in options"
        assert "TransactionId" in options, "Expecting 'TransactionId' in options"
        resp = self.fps_connection.refund(options["CallerReference"],
                                          options["TransactionId"],
                                          refundAmount=amount,
                                          callerDescription=options.get("description", None))
        return {"status": resp.RefundResult.TransactionStatus, "response": resp.RefundResult}

    def void(self, identification, options=None):
        if not options:
            options = {}
        # Requires the TransactionID to be passed as 'identification'
        resp = self.fps_connection.cancel(identification,
                                          options.get("description", None))
        return {"status": resp.CancelResult.TransactionStatus, "response": resp.CancelResult}

    def get_urls(self):
        urlpatterns = patterns('',
           url(r'^fps-notify-handler/$', self.fps_ipn_handler, name="fps_ipn_handler"),
           url(r'^fps-return-url/$', self.fps_return_url, name="fps_return_url"),
                               )
        return urlpatterns

    @csrf_exempt_m
    @require_POST_m
    def fps_ipn_handler(self, request):
        uri = request.build_absolute_uri()
        parsed_url = urlparse.urlparse(uri)
        resp = self.fps_connection.verify_signature(UrlEndPoint="%s://%s%s" % (parsed_url.scheme,
                                                                  parsed_url.netloc,
                                                                  parsed_url.path),
                                                    HttpParameters=request.raw_post_data)
        if not resp.VerifySignatureResult.VerificationStatus == "Success":
            return HttpResponseForbidden()

        data = dict(map(lambda x: x.split("="), request.raw_post_data.split("&")))
        for (key, val) in data.iteritems():
            data[key] = urllib.unquote_plus(val)
        if AmazonFPSResponse.objects.filter(transactionId=data["transactionId"]).count():
            resp = AmazonFPSResponse.objects.get(transactionId=data["transactionId"])
        else:
            resp = AmazonFPSResponse()
        for (key, val) in data.iteritems():
            attr_exists = hasattr(resp, key)
            if attr_exists and not callable(getattr(resp, key, None)):
                if key == "transactionDate":
                    val = datetime.datetime(*time.localtime(float(val))[:6])
                setattr(resp, key, val)
        resp.save()
        if resp.statusCode == "Success":
            transaction_was_successful.send(sender=self.__class__,
                                            type=data["operation"],
                                            response=resp)
        else:
            if not "Pending" in resp.statusCode:
                transaction_was_unsuccessful.send(sender=self.__class__,
                                                  type=data["operation"],
                                                  response=resp)
        # Return a HttpResponse to prevent django from complaining
        return HttpResponse(resp.statusCode)

    def fps_return_url(self, request):
        uri = request.build_absolute_uri()
        parsed_url = urlparse.urlparse(uri)
        resp = self.fps_connection.verify_signature(UrlEndPoint="%s://%s%s" % (parsed_url.scheme,
                                                                  parsed_url.netloc,
                                                                  parsed_url.path),
                                                    HttpParameters=parsed_url.query)
        if not resp.VerifySignatureResult.VerificationStatus == "Success":
            return HttpResponseForbidden()

        return self.transaction(request)

    def transaction(self, request):
        """Has to be overridden by the subclasses"""
        raise NotImplementedError
Esempio n. 4
0
class AmazonFpsIntegration(Integration):
    """
    Fields required:
    transactionAmount: Amount to be charged/authorized
    paymentReason: Description of the transaction
    paymentPage: Page to direct the user on completion/failure of transaction
    """

    display_name = "Amazon Flexible Payment Service"

    def __init__(self, options=None):
        if not options:
            options = {}
        merchant_settings = getattr(settings, "MERCHANT_SETTINGS")
        if not merchant_settings or not merchant_settings.get("amazon_fps"):
            raise IntegrationNotConfigured(
                "The '%s' integration is not correctly "
                "configured." % self.display_name)
        amazon_fps_settings = merchant_settings["amazon_fps"]
        self.aws_access_key = options.get(
            "aws_access_key", None) or amazon_fps_settings['AWS_ACCESS_KEY']
        self.aws_secret_access_key = options.get(
            "aws_secret_access_key",
            None) or amazon_fps_settings['AWS_SECRET_ACCESS_KEY']
        super(AmazonFpsIntegration, self).__init__(options=options)
        self.fps_connection = FPSConnection(self.aws_access_key,
                                            self.aws_secret_access_key,
                                            **options)

    @property
    def service_url(self):
        if self.test_mode:
            return FPS_SANDBOX_API_ENDPOINT
        return FPS_PROD_API_ENDPOINT

    @property
    def link_url(self):
        tmp_fields = self.fields.copy()
        tmp_fields.pop("aws_access_key", None)
        tmp_fields.pop("aws_secret_access_key", None)
        tmp_fields.pop("paymentPage", None)
        return self.fps_connection.cbui_url(
            returnURL=tmp_fields.pop("returnURL"),
            paymentReason=tmp_fields.pop("paymentReason"),
            pipelineName=tmp_fields.pop("pipelineName"),
            transactionAmount=str(tmp_fields.pop("transactionAmount")),
            **tmp_fields)

    def purchase(self, amount, options=None):
        if not options:
            options = {}
        tmp_options = options.copy()
        permissible_options = [
            "senderTokenId", "recipientTokenId", "chargeFeeTo",
            "callerReference", "senderReference", "recipientReference",
            "senderDescription", "recipientDescription", "callerDescription",
            "metadata", "transactionDate", "reserve"
        ]
        tmp_options["senderTokenId"] = options["tokenID"]
        for key in options:
            if key not in permissible_options:
                tmp_options.pop(key)
        resp = self.fps_connection.pay(
            amount,
            tmp_options.pop("senderTokenId"),
            callerReference=tmp_options.pop("callerReference"),
            **tmp_options)
        return {"status": resp[0].TransactionStatus, "response": resp[0]}

    def authorize(self, amount, options=None):
        if not options:
            options = {}
        options["reserve"] = True
        return self.purchase(amount, options)

    def capture(self, amount, options=None):
        if not options:
            options = {}
        assert "ReserveTransactionId" in options, "Expecting 'ReserveTransactionId' in options"
        resp = self.fps_connection.settle(options["ReserveTransactionId"],
                                          amount)
        return {"status": resp[0].TransactionStatus, "response": resp[0]}

    def credit(self, amount, options=None):
        if not options:
            options = {}
        assert "CallerReference" in options, "Expecting 'CallerReference' in options"
        assert "TransactionId" in options, "Expecting 'TransactionId' in options"
        resp = self.fps_connection.refund(options["CallerReference"],
                                          options["TransactionId"],
                                          refundAmount=amount,
                                          callerDescription=options.get(
                                              "description", None))
        return {"status": resp[0].TransactionStatus, "response": resp[0]}

    def void(self, identification, options=None):
        if not options:
            options = {}
        # Requires the TransactionID to be passed as 'identification'
        resp = self.fps_connection.cancel(identification,
                                          options.get("description", None))
        return {"status": resp[0].TransactionStatus, "response": resp[0]}

    def get_urls(self):
        urlpatterns = patterns(
            '',
            url(r'^fps-notify-handler/$',
                self.fps_ipn_handler,
                name="fps_ipn_handler"),
            url(r'^fps-return-url/$',
                self.fps_return_url,
                name="fps_return_url"),
        )
        return urlpatterns

    @csrf_exempt_m
    @require_POST_m
    def fps_ipn_handler(self, request):
        uri = request.build_absolute_uri()
        parsed_url = urlparse.urlparse(uri)
        resp = self.fps_connection.verify_signature(
            "%s://%s%s" %
            (parsed_url.scheme, parsed_url.netloc, parsed_url.path),
            request.raw_post_data)
        if not resp[0].VerificationStatus == "Success":
            return HttpResponseForbidden()

        data = dict(
            map(lambda x: x.split("="), request.raw_post_data.split("&")))
        for (key, val) in data.iteritems():
            data[key] = urllib.unquote_plus(val)
        if AmazonFPSResponse.objects.filter(
                transactionId=data["transactionId"]).count():
            resp = AmazonFPSResponse.objects.get(
                transactionId=data["transactionId"])
        else:
            resp = AmazonFPSResponse()
        for (key, val) in data.iteritems():
            attr_exists = hasattr(resp, key)
            if attr_exists and not callable(getattr(resp, key, None)):
                if key == "transactionDate":
                    val = datetime.datetime(*time.localtime(float(val))[:6])
                setattr(resp, key, val)
        resp.save()
        if resp.statusCode == "Success":
            transaction_was_successful.send(sender=self.__class__,
                                            type=data["operation"],
                                            response=resp)
        else:
            if not "Pending" in resp.statusCode:
                transaction_was_unsuccessful.send(sender=self.__class__,
                                                  type=data["operation"],
                                                  response=resp)
        # Return a HttpResponse to prevent django from complaining
        return HttpResponse(resp.statusCode)

    def fps_return_url(self, request):
        uri = request.build_absolute_uri()
        parsed_url = urlparse.urlparse(uri)
        resp = self.fps_connection.verify_signature(
            "%s://%s%s" %
            (parsed_url.scheme, parsed_url.netloc, parsed_url.path),
            parsed_url.query)
        if not resp[0].VerificationStatus == "Success":
            return HttpResponseForbidden()

        return self.transaction(request)

    def transaction(self, request):
        """Has to be overridden by the subclasses"""
        raise NotImplementedError