18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2012 Andy Davidoff http://www.disruptek.com/
28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2010 Jason R. Coombs http://www.jaraco.com/
38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Copyright (c) 2008 Chris Moyer http://coredumped.org/
48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# Permission is hereby granted, free of charge, to any person obtaining a
68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# copy of this software and associated documentation files (the
78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# "Software"), to deal in the Software without restriction, including
88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# without limitation the rights to use, copy, modify, merge, publish, dis-
98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# tribute, sublicense, and/or sell copies of the Software, and to permit
108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# persons to whom the Software is furnished to do so, subject to the fol-
118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# lowing conditions:
128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# The above copyright notice and this permission notice shall be included
148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# in all copies or substantial portions of the Software.
158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#
168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi# IN THE SOFTWARE.
238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport urllib
258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport uuid
268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.connection import AWSQueryConnection
278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.fps.exception import ResponseErrorFactory
288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoifrom boto.fps.response import ResponseFactory
298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiimport boto.fps.response
308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi__all__ = ['FPSConnection']
328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidecorated_attrs = ('action', 'response')
348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidef add_attrs_from(func, to):
378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    for attr in decorated_attrs:
388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        setattr(to, attr, getattr(func, attr, None))
398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return to
408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidef complex_amounts(*fields):
438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def decorator(func):
448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        def wrapper(self, *args, **kw):
458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            for field in filter(kw.has_key, fields):
468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                amount = kw.pop(field)
478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                kw[field + '.Value'] = getattr(amount, 'Value', str(amount))
488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                kw[field + '.CurrencyCode'] = getattr(amount, 'CurrencyCode',
498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                      self.currencycode)
508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return func(self, *args, **kw)
518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        wrapper.__doc__ = "{0}\nComplex Amounts: {1}".format(func.__doc__,
528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                 ', '.join(fields))
538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return add_attrs_from(func, to=wrapper)
548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return decorator
558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidef requires(*groups):
588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def decorator(func):
608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        def wrapper(*args, **kw):
628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            hasgroup = lambda x: len(x) == len(filter(kw.has_key, x))
638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            if 1 != len(filter(hasgroup, groups)):
648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                message = ' OR '.join(['+'.join(g) for g in groups])
658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                message = "{0} requires {1} argument(s)" \
668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                          "".format(getattr(func, 'action', 'Method'), message)
678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                raise KeyError(message)
688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return func(*args, **kw)
698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        message = ' OR '.join(['+'.join(g) for g in groups])
708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        wrapper.__doc__ = "{0}\nRequired: {1}".format(func.__doc__,
718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                           message)
728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return add_attrs_from(func, to=wrapper)
738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return decorator
748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidef needs_caller_reference(func):
778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def wrapper(*args, **kw):
798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        kw.setdefault('CallerReference', uuid.uuid4())
808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return func(*args, **kw)
818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    wrapper.__doc__ = "{0}\nUses CallerReference, defaults " \
828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                      "to uuid.uuid4()".format(func.__doc__)
838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return add_attrs_from(func, to=wrapper)
848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoidef api_action(*api):
878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def decorator(func):
898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        action = ''.join(api or map(str.capitalize, func.__name__.split('_')))
908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        response = ResponseFactory(action)
918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        if hasattr(boto.fps.response, action + 'Response'):
928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            response = getattr(boto.fps.response, action + 'Response')
938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        def wrapper(self, *args, **kw):
958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            return func(self, action, response, *args, **kw)
968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        wrapper.action, wrapper.response = action, response
978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        wrapper.__doc__ = "FPS {0} API call\n{1}".format(action,
988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                                         func.__doc__)
998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return wrapper
1008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    return decorator
1018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass FPSConnection(AWSQueryConnection):
1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    APIVersion = '2010-08-28'
1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    ResponseError = ResponseErrorFactory
1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    currencycode = 'USD'
1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def __init__(self, *args, **kw):
1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        self.currencycode = kw.pop('CurrencyCode', self.currencycode)
1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        kw.setdefault('host', 'fps.sandbox.amazonaws.com')
1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        super(FPSConnection, self).__init__(*args, **kw)
1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def _required_auth_capability(self):
1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return ['fps']
1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('SettlementAmount')
1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['CreditInstrumentId', 'SettlementAmount.Value',
1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi               'SenderTokenId',      'SettlementAmount.CurrencyCode'])
1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def settle_debt(self, action, response, **kw):
1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Allows a caller to initiate a transaction that atomically transfers
1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        money from a sender's payment instrument to the recipient, while
1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        decreasing corresponding debt balance.
1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['TransactionId'])
1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_transaction_status(self, action, response, **kw):
1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Gets the latest status of a transaction.
1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['StartDate'])
1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_account_activity(self, action, response, **kw):
1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns transactions for a given date range.
1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['TransactionId'])
1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_transaction(self, action, response, **kw):
1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns all details of a transaction.
1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_outstanding_debt_balance(self, action, response):
1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the total outstanding balance for all the credit instruments
1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        for the given creditor account.
1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, {}, response)
1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['PrepaidInstrumentId'])
1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_prepaid_balance(self, action, response, **kw):
1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the balance available on the given prepaid instrument.
1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_total_prepaid_liability(self, action, response):
1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the total liability held by the given account corresponding to
1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        all the prepaid instruments owned by the account.
1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, {}, response)
1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_account_balance(self, action, response):
1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the account balance for an account in real time.
1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, {}, response)
1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['PaymentInstruction', 'TokenType'])
1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def install_payment_instruction(self, action, response, **kw):
1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Installs a payment instruction for caller.
1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['returnURL', 'pipelineName'])
1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def cbui_url(self, **kw):
1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Generate a signed URL for the Co-Branded service API given arguments as
1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        payload.
2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        sandbox = 'sandbox' in self.host and 'payments-sandbox' or 'payments'
2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        endpoint = 'authorize.{0}.amazon.com'.format(sandbox)
2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        base = '/cobranded-ui/actions/start'
2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        validpipelines = ('SingleUse', 'MultiUse', 'Recurring', 'Recipient',
2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                          'SetupPrepaid', 'SetupPostpaid', 'EditToken')
2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        assert kw['pipelineName'] in validpipelines, "Invalid pipelineName"
2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        kw.update({
2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'signatureMethod':  'HmacSHA256',
2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi            'signatureVersion': '2',
2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        })
2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        kw.setdefault('callerKey', self.aws_access_key_id)
2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        safestr = lambda x: x is not None and str(x) or ''
2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        safequote = lambda x: urllib.quote(safestr(x), safe='~')
2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        payload = sorted([(k, safequote(v)) for k, v in kw.items()])
2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        encoded = lambda p: '&'.join([k + '=' + v for k, v in p])
2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        canonical = '\n'.join(['GET', endpoint, base, encoded(payload)])
2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        signature = self._auth_handler.sign_string(canonical)
2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        payload += [('signature', safequote(signature))]
2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        payload.sort()
2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return 'https://{0}{1}?{2}'.format(endpoint, base, encoded(payload))
2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('TransactionAmount')
2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['SenderTokenId', 'TransactionAmount.Value',
2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                'TransactionAmount.CurrencyCode'])
2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def reserve(self, action, response, **kw):
2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Reserve API is part of the Reserve and Settle API conjunction that
2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        serve the purpose of a pay where the authorization and settlement have
2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        a timing difference.
2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('TransactionAmount')
2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['SenderTokenId', 'TransactionAmount.Value',
2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                'TransactionAmount.CurrencyCode'])
2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def pay(self, action, response, **kw):
2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Allows calling applications to move money from a sender to a recipient.
2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['TransactionId'])
2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def cancel(self, action, response, **kw):
2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Cancels an ongoing transaction and puts it in cancelled state.
2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('TransactionAmount')
2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['ReserveTransactionId', 'TransactionAmount.Value',
2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                       'TransactionAmount.CurrencyCode'])
2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def settle(self, action, response, **kw):
2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        The Settle API is used in conjunction with the Reserve API and is used
2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        to settle previously reserved transaction.
2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('RefundAmount')
2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['TransactionId',   'RefundAmount.Value',
2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi               'CallerReference', 'RefundAmount.CurrencyCode'])
2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def refund(self, action, response, **kw):
2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Refunds a previously completed transaction.
2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['RecipientTokenId'])
2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_recipient_verification_status(self, action, response, **kw):
2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the recipient status.
2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['CallerReference'], ['TokenId'])
2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_token_by_caller(self, action, response, **kw):
2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the details of a particular token installed by this calling
2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        application using the subway co-branded UI.
2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['UrlEndPoint', 'HttpParameters'])
2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def verify_signature(self, action, response, **kw):
2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Verify the signature that FPS sent in IPN or callback urls.
3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_tokens(self, action, response, **kw):
3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns a list of tokens installed on the given account.
3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['TokenId'])
3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_token_usage(self, action, response, **kw):
3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the usage of a token.
3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['TokenId'])
3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def cancel_token(self, action, response, **kw):
3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Cancels any token installed by the calling application on its own
3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        account.
3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('FundingAmount')
3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['PrepaidInstrumentId', 'FundingAmount.Value',
3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi               'SenderTokenId',       'FundingAmount.CurrencyCode'])
3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def fund_prepaid(self, action, response, **kw):
3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Funds the prepaid balance on the given prepaid instrument.
3368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['CreditInstrumentId'])
3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_debt_balance(self, action, response, **kw):
3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the balance corresponding to the given credit instrument.
3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('AdjustmentAmount')
3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['CreditInstrumentId', 'AdjustmentAmount.Value',
3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                                     'AdjustmentAmount.CurrencyCode'])
3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def write_off_debt(self, action, response, **kw):
3538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Allows a creditor to write off the debt balance accumulated partially
3558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        or fully at any time.
3568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['SubscriptionId'])
3608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_transactions_for_subscription(self, action, response, **kw):
3628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the transactions for a given subscriptionID.
3648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['SubscriptionId'])
3688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_subscription_details(self, action, response, **kw):
3708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Returns the details of Subscription for a given subscriptionID.
3728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @needs_caller_reference
3768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @complex_amounts('RefundAmount')
3778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['SubscriptionId'])
3788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def cancel_subscription_and_refund(self, action, response, **kw):
3808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Cancels a subscription.
3828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        message = "If you specify a RefundAmount, " \
3848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                  "you must specify CallerReference."
3858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        assert not 'RefundAmount.Value' in kw \
3868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi                or 'CallerReference' in kw, message
3878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
3888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi
3898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @requires(['TokenId'])
3908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    @api_action()
3918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi    def get_payment_instruction(self, action, response, **kw):
3928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        Gets the payment instruction of a token.
3948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        """
3958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi        return self.get_object(action, kw, response)
396