Esempio n. 1
0
    def refund(self, order, amount):
        logger.info('Credit...')

        annotation = IAnnotations(order)
        transaction_id = annotation[GetPaidInterfaces.keys.processor_txn_id]

        client = PayflowProClient(partner=self.options.partner,
                                  vendor=self.options.vendor,
                                  username=self.options.username,
                                  password=self.options.password,
                                  url_base=self._sites.get(self.options.server_url))

        responses, unconsumed_data = client.credit_referenced(transaction_id)
        
        annotation[CREDIT_RESULT] = responses[0].result
        annotation[CREDIT_RESPMSG] = responses[0].respmsg

        if responses[0].result == '0':
            ret = GetPaidInterfaces.keys.results_success
        else:
            ret = responses[0].respmsg

        logger.info("CREDIT_PNREF: %s" % annotation[GetPaidInterfaces.keys.processor_txn_id])
        logger.info("CREDIT_RESULT: %s" % annotation[CREDIT_RESULT])
        logger.info("CREDIT_RESPMSG: %s" % annotation[CREDIT_RESPMSG])

        return ret
Esempio n. 2
0
    def authorize( self, order, payment ):
        logger.info('Authorize...')
        
        client = PayflowProClient(partner=self.options.partner,
                                  vendor=self.options.vendor,
                                  username=self.options.username,
                                  password=self.options.password,
                                  url_base=self._sites.get(self.options.server_url))

        card_exp_date = ''
        if hasattr(payment.cc_expiration, 'strftime'):
            card_exp_date = payment.cc_expiration.strftime('%m%y')
        else:
            # If cc_expiration is not of type date, then it should be 
            # a string like this: '2011-08-03 00:00'
            # This is a bug in getpaid.formgen's single page checkout
            # and the correct fix is to swap out it's expiration date
            # widget with one that returns a date.
            yearMonthDay = payment.cc_expiration.split(' ')[0].split('-')
            _date = date(int(yearMonthDay[0]), 
                         int(yearMonthDay[1]), 
                         int(yearMonthDay[2]))
            card_exp_date = _date.strftime('%m%y')

        credit_card = CreditCard(acct=payment.credit_card,
                                 expdate=card_exp_date,
                                 cvv2=payment.cc_cvc)

        ba = order.billing_address
        responses, unconsumed_data = client.authorization(credit_card,
                                                          Amount(amt=order.getTotalPrice(),
                                                                 currency=self.options.currency),
                                                          extras=[Address(street=ba.bill_first_line,
                                                                          city=ba.bill_city,
                                                                          state=ba.bill_state,
                                                                          zip=ba.bill_postal_code)])
        order.user_payment_info_trans_id = responses[0].pnref

        annotation = IAnnotations(order)
        annotation[GetPaidInterfaces.keys.processor_txn_id] = responses[0].pnref
        annotation[RESULT] = responses[0].result
        annotation[RESPMSG] = responses[0].respmsg
        annotation[CVV2_MATCH] = responses[0].cvv2match
        annotation[AUTH_CODE] = responses[0].authcode
        annotation[LAST_FOUR] = payment.credit_card[-4:]

        if responses[0].result == '0':
            ret = GetPaidInterfaces.keys.results_success
        else:
            ret = responses[0].respmsg

        logger.info("PNREF: %s" % annotation[GetPaidInterfaces.keys.processor_txn_id])
        logger.info("RESULT: %s" % annotation[RESULT])
        logger.info("RESPMSG: %s" % annotation[RESPMSG])
        logger.info("CVV2_MATCH: %s" % annotation[CVV2_MATCH])
        logger.info("AUTH_CODE: %s" % annotation[AUTH_CODE])

        return ret
Esempio n. 3
0
    def __init__(self, settings):
        super(PaymentProcessor, self).__init__('payflowpro', settings)
        partner = self.settings.PARTNER.value
        vendor = self.settings.VENDOR.value
        username = self.settings.USER.value
        password = self.settings.PASSWORD.value
        testing = not self.settings.LIVE.value
        if testing:
            url_base = PayflowProClient.URL_BASE_TEST
        else:
            url_base = PayflowProClient.URL_BASE_LIVE

        self.payflow = PayflowProClient(partner=partner, vendor=vendor,
                                        username=username, password=password,
                                        url_base=url_base)
Esempio n. 4
0
    def __init__(self, **kwargs):
        super(PayPalConnection, self).__init__(**kwargs)

        if not self.debug:
            logging.getLogger('payflow_pro').setLevel(logging.WARNING)


        url_base = PayflowProClient.URL_BASE_TEST if self.test_mode \
                   else PayflowProClient.URL_BASE_LIVE
        self.cc = PayflowProClient(url_base=url_base, **self.auth)
Esempio n. 5
0
    def __init__(self, settings):
        super(PaymentProcessor, self).__init__('payflowpro', settings)
        partner = self.settings.PARTNER.value
        vendor = self.settings.VENDOR.value
        username = self.settings.USER.value
        password = self.settings.PASSWORD.value
        testing = not self.settings.LIVE.value
        if testing:
            url_base = PayflowProClient.URL_BASE_TEST
        else:
            url_base = PayflowProClient.URL_BASE_LIVE

        self.payflow = PayflowProClient(partner=partner, vendor=vendor,
                                        username=username, password=password,
                                        url_base=url_base)
Esempio n. 6
0
from payflowpro.classes import (CreditCard, Amount, Profile, Address, Tracking, Response, CustomerInfo, AchPayment)
from payflowpro.client import PayflowProClient, find_classes_in_list, find_class_in_list

#PARTNER_ID = 'Paypal'
#VENDOR_ID = 'wiremine'
#USERNAME = '******'
#PASSWORD = '******'



client = PayflowProClient(partner=PARTNER_ID, vendor=VENDOR_ID, username=USERNAME, password=PASSWORD, url_base='https://pilot-payflowpro.paypal.com')
credit_card = CreditCard(acct=5555555555554444, expdate="1212")
responses, unconsumed_data = client.sale(credit_card, Amount(amt=15, currency="USD"), extras=[Address(street="82 E 38th Street", zip="49423")])

#arc_payment = AchPayment(aba='111111118', acct='1111111111', accttype='S')
#customer = CustomerInfo(firstname='Bob Smith')
#responses, unconsumed_data = client.sale(arc_payment, Amount(amt=15, currency="USD"), extras=[customer])

print responses[0]
Esempio n. 7
0
class PaymentProcessor(BasePaymentProcessor):
    """
    PayflowPro payment processing module
    You must have an account with PayPal in order to use this module.
    """
    def __init__(self, settings):
        super(PaymentProcessor, self).__init__('payflowpro', settings)
        partner = self.settings.PARTNER.value
        vendor = self.settings.VENDOR.value
        username = self.settings.USER.value
        password = self.settings.PASSWORD.value
        testing = not self.settings.LIVE.value
        if testing:
            url_base = PayflowProClient.URL_BASE_TEST
        else:
            url_base = PayflowProClient.URL_BASE_LIVE

        self.payflow = PayflowProClient(partner=partner, vendor=vendor,
                                        username=username, password=password,
                                        url_base=url_base)

    def get_charge_data(self, amount=None):
        """
        Build the dictionary needed to process a credit card charge.

        Return: a dictionary with the following key-values:
            * log_string: the transaction data without the sensible
                           buyer data. Suitable for logs.
            * credit_card, amount, address, ship_address, customer_info :
                 the payflowpro.classes.* instances to be passed to
                 self.payflow
        """
        order = self.order
        if amount is None:
            amount = order.balance
        balance = trunc_decimal(amount, 2)


        ret = {
            'credit_card': CreditCard(
                acct=order.credit_card.decryptedCC,
                expdate="%02d%02d" % (order.credit_card.expire_month,
                                      order.credit_card.expire_year % 100),
                cvv2=order.credit_card.ccv,
                ),
            
            'amount': Amount(amt=balance,),

            'address': Address(
                street=order.full_bill_street,
                zip=order.bill_postal_code,
                city=order.bill_city,
                state=order.bill_state,
                country=order.bill_country,
                ),

            'ship_address': ShippingAddress(
                shiptostreet=order.full_ship_street,
                shiptocity=order.ship_city,
                shiptofirstname=order.ship_first_name,
                shiptolastname=order.ship_last_name,
                shiptostate=order.ship_state,
                shiptocountry=order.ship_country,
                shiptozip=order.ship_postal_code,
                ),

            'customer_info': CustomerInfo(
                firstname=order.contact.first_name,
                lastname=order.contact.last_name,
                ),
            }

        redacted_data = ret.copy()
        redacted_data['credit_card'] = {
            'acct': order.credit_card.display_cc,
            'expdate': "%d%d" % (order.credit_card.expire_year,
                                 order.credit_card.expire_month),
            'cvv2': "REDACTED",
            }

        dicts = [getattr(d, 'data', d) for d in redacted_data.values()]
        ret['log_string'] = "\n".join("%s: %s" % (k, v) for d in dicts
                                      for k, v in d.items())

        return ret

    def _handle_unconsumed(self, unconsumed_data):
        """
        Handler for when we've got unconsumed data from the response
        """
        if unconsumed_data:
            self.log.warn("Something went wrong with python-payflowpro. "
                          "We got some unconsumed data: %s" % 
                          str(unconsumed_data))

    def _log_responses(self, responses):
        """
        Log the responses from PayflowPro for debugging
        """
        self.log_extra("Response variables from payflowpro:")
        for response in responses:
            self.log_extra("%(classname)s: %(response_fields)s" % {
                    'classname': response.__class__.__name__,
                    'response_fields': "%s" % response.data })


    def authorize_payment(self, order=None, amount=None, testing=False):
        """
        Authorize a single payment.

        Returns: ProcessorResult
        """
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        if order.paid_in_full:
            self.log_extra('%s is paid in full, no authorization attempted.',
                           order)
            result = ProcessorResult(self.key, True,
                                      _("No charge needed, paid in full."))
        else:
            self.log_extra('Authorizing payment of %s for %s', amount, order)

            data = self.get_charge_data(amount=amount)
            data['extras'] = [data['address'], data['ship_address'], 
                              data['customer_info'],]

            result = self.send_post(data=data, testing=testing,
                                    post_func=self.send_authorize_post,)

        return result

    def can_authorize(self):
        return True

    #def can_recur_bill(self):
    #    return True

    def capture_authorized_payment(self, authorization, testing=False,
                                   order=None, amount=None):
        """
        Capture a single payment
        """
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        if order.authorized_remaining == Decimal('0.00'):
            self.log_extra('No remaining authorizations on %s', order)
            return ProcessorResult(self.key, True, _("Already complete"))

        self.log_extra('Capturing Authorization #%i for %s',
                       authorization.id, order)
        data = self.get_charge_data()
        data['authorization_id'] = authorization.transaction_id
        result = self.send_post(data=data, testing=testing,
                                post_func=self.send_capture_post,)

        return result

    def capture_payment(self, testing=False, order=None, amount=None):
        """
        Process payments without an authorization step.
        """
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        if order.paid_in_full:
            self.log_extra('%s is paid in full, no capture attempted.', order)
            result = ProcessorResult(self.key, True, _("No charge needed, "
                                                        "paid in full."))
            self.record_payment()
        else:
            self.log_extra('Capturing payment for %s', order)

            data = self.get_charge_data(amount=amount)
            data['extras'] = [data['address'], data['ship_address'], 
                              data['customer_info'],]
            result = self.send_post(data=data, post_func=self.send_sale_post,
                                     testing=testing,)

        return result

    def release_authorized_payment(self, order=None, auth=None, testing=False):
        """Release a previously authorized payment."""
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        self.log_extra('Releasing Authorization #%i for %s', auth.id, order)
        data = self.get_charge_data()
        data['authorization_id'] = auth.transaction_id
        result = self.send_post(data=data, post_func=self.send_release_post,
                                testing=testing)
        if result.success:
            auth.complete = True
            auth.save()

        return result

    def send_authorize_post(self, data):
        """
        Authorize sell with PayflowPro
        """
        responses, unconsumed_data = self.payflow.authorization(
            credit_card=data['credit_card'], amount=data['amount'],
            extras=data['extras'])
        return responses, unconsumed_data, self.record_authorization

    def send_capture_post(self, data):
        """
        Capture previously authorized sale
        """
        responses, unconsumed_data = self.payflow.capture(
            data['authorization_id'])
        return responses, unconsumed_data, self.record_payment

    def send_release_post(self, data):
        """
        Release previously authorized sale
        """
        responses, unconsumed_data = self.payflow.void(
            data['authorization_id'])
        def nothing(*args, **kwargs):
            return None
        return responses, unconsumed_data, nothing 

    def send_sale_post(self, data):
        """
        Immediately charge a credit card
        """
        responses, unconsumed_data = self.payflow.sale(
            credit_card=data['credit_card'], amount=data['amount'],
            extras=data['extras'])
        return responses, unconsumed_data, self.record_payment

    def send_post(self, data, post_func, testing=False):
        """
        Execute the post to PayflowPro.

        Params:
        - data: the argument expected by `post_func`. Usually a dict which this
                function knows how to use
        - post_func: a function that takes `data` as argument, and sends the
                     actual request to the PayflowPro Gateway. It should return
                     a 3-tuple (responses, unconsumed_data, record_* function)
        - testing: if true, then don't record the payment

        Returns:
        - ProcessorResult
        """
        self.log_extra("About to send PayflowPro a request: %s",
                       data['log_string'])

        if 'amount' in data:
            amount = data['amount'].amt
        else:
            amount = self.order.balance

        responses, unconsumed_data, record_function = post_func(data)
        self._handle_unconsumed(unconsumed_data)
        self._log_responses(responses)

        response = responses[0]

        success = response.result == '0'
        transaction_id = response.pnref
        response_text = response.respmsg
        reason_code = response.result
        if success:
            # success!
            self.log.info("successful %s for order #%d",
                          post_func.__name__, self.order.id)
            if not testing:
                self.log_extra("Success, calling %s", record_function.__name__)
                payment = record_function(
                    order=self.order, amount=amount,
                    transaction_id=transaction_id, reason_code=reason_code)
        else:
            # failure =(
            self.log.info("failed %s for order #%d",
                          post_func.__name__, self.order.id)
            if not testing:
                payment = self.record_failure(
                    amount=amount, transaction_id=transaction_id,
                    reason_code=reason_code, details=response_text)
                
        self.log_extra("Returning success=%s, reason=%s, response_text=%s",
                       success, reason_code, response_text)

        return ProcessorResult(self.key, success, response_text,
                                 payment=payment)
Esempio n. 8
0
from payflowpro.classes import (CreditCard, Amount, Profile, Address, Tracking,
                                Response, CustomerInfo, AchPayment)
from payflowpro.client import PayflowProClient, find_classes_in_list, find_class_in_list

#PARTNER_ID = 'Paypal'
#VENDOR_ID = 'wiremine'
#USERNAME = '******'
#PASSWORD = '******'

client = PayflowProClient(partner=PARTNER_ID,
                          vendor=VENDOR_ID,
                          username=USERNAME,
                          password=PASSWORD,
                          url_base='https://pilot-payflowpro.paypal.com')
credit_card = CreditCard(acct=5555555555554444, expdate="1212")
responses, unconsumed_data = client.sale(
    credit_card,
    Amount(amt=15, currency="USD"),
    extras=[Address(street="82 E 38th Street", zip="49423")])

#arc_payment = AchPayment(aba='111111118', acct='1111111111', accttype='S')
#customer = CustomerInfo(firstname='Bob Smith')
#responses, unconsumed_data = client.sale(arc_payment, Amount(amt=15, currency="USD"), extras=[customer])

print responses[0]
Esempio n. 9
0
class PaymentProcessor(BasePaymentProcessor):
    """
    PayflowPro payment processing module
    You must have an account with PayPal in order to use this module.
    """
    def __init__(self, settings):
        super(PaymentProcessor, self).__init__('payflowpro', settings)
        partner = self.settings.PARTNER.value
        vendor = self.settings.VENDOR.value
        username = self.settings.USER.value
        password = self.settings.PASSWORD.value
        testing = not self.settings.LIVE.value
        if testing:
            url_base = PayflowProClient.URL_BASE_TEST
        else:
            url_base = PayflowProClient.URL_BASE_LIVE

        self.payflow = PayflowProClient(partner=partner, vendor=vendor,
                                        username=username, password=password,
                                        url_base=url_base)

    def get_charge_data(self, amount=None):
        """
        Build the dictionary needed to process a credit card charge.

        Return: a dictionary with the following key-values:
            * log_string: the transaction data without the sensible
                           buyer data. Suitable for logs.
            * credit_card, amount, address, ship_address, customer_info :
                 the payflowpro.classes.* instances to be passed to
                 self.payflow
        """
        order = self.order
        if amount is None:
            amount = order.balance
        balance = trunc_decimal(amount, 2)


        ret = {
            'credit_card': CreditCard(
                acct=order.credit_card.decryptedCC,
                expdate="%02d%02d" % (order.credit_card.expire_month,
                                      order.credit_card.expire_year % 100),
                cvv2=order.credit_card.ccv,
                ),
            
            'amount': Amount(amt=balance,),

            'address': Address(
                street=order.full_bill_street,
                zip=order.bill_postal_code,
                city=order.bill_city,
                state=order.bill_state,
                country=order.bill_country,
                ),

            'ship_address': ShippingAddress(
                shiptostreet=order.full_ship_street,
                shiptocity=order.ship_city,
                shiptofirstname=order.ship_first_name,
                shiptolastname=order.ship_last_name,
                shiptostate=order.ship_state,
                shiptocountry=order.ship_country,
                shiptozip=order.ship_postal_code,
                ),

            'customer_info': CustomerInfo(
                firstname=order.bill_first_name,
                lastname=order.bill_last_name,
                ),
            }

        redacted_data = ret.copy()
        redacted_data['credit_card'] = {
            'acct': order.credit_card.display_cc,
            'expdate': "%d%d" % (order.credit_card.expire_year,
                                 order.credit_card.expire_month),
            'cvv2': "REDACTED",
            }

        dicts = [getattr(d, 'data', d) for d in redacted_data.values()]
        ret['log_string'] = "\n".join("%s: %s" % (k, v) for d in dicts
                                      for k, v in d.items())

        return ret

    def _handle_unconsumed(self, unconsumed_data):
        """
        Handler for when we've got unconsumed data from the response
        """
        if unconsumed_data:
            self.log.warn("Something went wrong with python-payflowpro. "
                          "We got some unconsumed data: %s" % 
                          str(unconsumed_data))

    def _log_responses(self, responses):
        """
        Log the responses from PayflowPro for debugging
        """
        self.log_extra("Response variables from payflowpro:")
        for response in responses:
            self.log_extra("%(classname)s: %(response_fields)s" % {
                    'classname': response.__class__.__name__,
                    'response_fields': "%s" % response.data })


    def authorize_payment(self, order=None, amount=None, testing=False):
        """
        Authorize a single payment.

        Returns: ProcessorResult
        """
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        if order.paid_in_full:
            self.log_extra('%s is paid in full, no authorization attempted.',
                           order)
            result = ProcessorResult(self.key, True,
                                      _("No charge needed, paid in full."))
        else:
            self.log_extra('Authorizing payment of %s for %s', amount, order)

            data = self.get_charge_data(amount=amount)
            data['extras'] = [data['address'], data['ship_address'], 
                              data['customer_info'],]

            result = self.send_post(data=data, testing=testing,
                                    post_func=self.send_authorize_post,)

        return result

    def can_authorize(self):
        return True

    #def can_recur_bill(self):
    #    return True

    def capture_authorized_payment(self, authorization, testing=False,
                                   order=None, amount=None):
        """
        Capture a single payment
        """
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        if order.authorized_remaining == Decimal('0.00'):
            self.log_extra('No remaining authorizations on %s', order)
            return ProcessorResult(self.key, True, _("Already complete"))

        self.log_extra('Capturing Authorization #%i for %s',
                       authorization.id, order)
        data = self.get_charge_data()
        data['authorization_id'] = authorization.transaction_id
        result = self.send_post(data=data, testing=testing,
                                post_func=self.send_capture_post,)

        return result

    def capture_payment(self, testing=False, order=None, amount=None):
        """
        Process payments without an authorization step.
        """
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        if order.paid_in_full:
            self.log_extra('%s is paid in full, no capture attempted.', order)
            result = ProcessorResult(self.key, True, _("No charge needed, "
                                                        "paid in full."))
            self.record_payment()
        else:
            self.log_extra('Capturing payment for %s', order)

            data = self.get_charge_data(amount=amount)
            data['extras'] = [data['address'], data['ship_address'], 
                              data['customer_info'],]
            result = self.send_post(data=data, post_func=self.send_sale_post,
                                     testing=testing,)

        return result

    def release_authorized_payment(self, order=None, auth=None, testing=False):
        """Release a previously authorized payment."""
        if order:
            self.prepare_data(order)
        else:
            order = self.order

        self.log_extra('Releasing Authorization #%i for %s', auth.id, order)
        data = self.get_charge_data()
        data['authorization_id'] = auth.transaction_id
        result = self.send_post(data=data, post_func=self.send_release_post,
                                testing=testing)
        if result.success:
            auth.complete = True
            auth.save()

        return result

    def send_authorize_post(self, data):
        """
        Authorize sell with PayflowPro
        """
        responses, unconsumed_data = self.payflow.authorization(
            credit_card=data['credit_card'], amount=data['amount'],
            extras=data['extras'])
        return responses, unconsumed_data, self.record_authorization

    def send_capture_post(self, data):
        """
        Capture previously authorized sale
        """
        responses, unconsumed_data = self.payflow.capture(
            data['authorization_id'])
        return responses, unconsumed_data, self.record_payment

    def send_release_post(self, data):
        """
        Release previously authorized sale
        """
        responses, unconsumed_data = self.payflow.void(
            data['authorization_id'])
        def nothing(*args, **kwargs):
            return None
        return responses, unconsumed_data, nothing 

    def send_sale_post(self, data):
        """
        Immediately charge a credit card
        """
        responses, unconsumed_data = self.payflow.sale(
            credit_card=data['credit_card'], amount=data['amount'],
            extras=data['extras'])
        return responses, unconsumed_data, self.record_payment

    def send_post(self, data, post_func, testing=False):
        """
        Execute the post to PayflowPro.

        Params:
        - data: the argument expected by `post_func`. Usually a dict which this
                function knows how to use
        - post_func: a function that takes `data` as argument, and sends the
                     actual request to the PayflowPro Gateway. It should return
                     a 3-tuple (responses, unconsumed_data, record_* function)
        - testing: if true, then don't record the payment

        Returns:
        - ProcessorResult
        """
        self.log_extra("About to send PayflowPro a request: %s",
                       data['log_string'])

        if 'amount' in data:
            amount = data['amount'].amt
        else:
            amount = self.order.balance

        responses, unconsumed_data, record_function = post_func(data)
        self._handle_unconsumed(unconsumed_data)
        self._log_responses(responses)

        response = responses[0]

        success = response.result == '0'
        transaction_id = response.pnref
        response_text = response.respmsg
        reason_code = response.result
        if success:
            # success!
            self.log.info("successful %s for order #%d",
                          post_func.__name__, self.order.id)
            if not testing:
                self.log_extra("Success, calling %s", record_function.__name__)
                payment = record_function(
                    order=self.order, amount=amount,
                    transaction_id=transaction_id, reason_code=reason_code)
        else:
            # failure =(
            self.log.info("failed %s for order #%d",
                          post_func.__name__, self.order.id)
            if not testing:
                payment = self.record_failure(
                    amount=amount, transaction_id=transaction_id,
                    reason_code=reason_code, details=response_text)
                
        self.log_extra("Returning success=%s, reason=%s, response_text=%s",
                       success, reason_code, response_text)

        return ProcessorResult(self.key, success, response_text,
                                 payment=payment)
Esempio n. 10
0
def purchase(userprofile=None,
             amt=15.00,
             shippingprice=5.00,
             tax=0.00,
             cctype='Visa',
             ccnum=settings.TEST_VISA_ACCOUNT_NO,
             expdate=settings.TEST_VISA_EXPIRATION,
             csc=settings.TEST_CVV2,
             firstname='John',
             middlename='',
             lastname='Doe',
             street='1313 Mockingbird Lane',
             street2='',
             city='Beverly Hills',
             state='CA',
             zip='90110',
             countrycode='US',
             currencycode='USD',
             journal_id=0,
             email=settings.TEST_EMAIL_PERSONAL,
             phone='',
             ipaddress='',
             quantity=0,
             coupon=''):
    """
		Direct purchase through paypal.
	"""

    # make sure all amounts are not more precise than cents
    amt = Decimal(amt).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
    shippingprice = Decimal(shippingprice).quantize(Decimal('0.01'),
                                                    rounding=ROUND_HALF_UP)
    tax = Decimal(tax).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
    total_amt = amt + shippingprice + tax

    settings.SHOP_LOGGER.info(
        "Purchase called: amt: %s, shipping: %s, tax: %s, cctype: %s, ccnum: %s, expdate: %s, csc: %s, firstname: %s, middlename: %s, lastname: %s, street: %s, street2: %s, city: %s, state: %s, zip: %s, countrycode: %s, currencycode: %s, journal_id: %s, email: %s, phone: %s, ipaddress: %s, coupon: %s"
        %
        (amt, shippingprice, tax, cctype, ccnum, expdate, csc, firstname,
         middlename, lastname, street, street2, city, state, zip, countrycode,
         currencycode, journal_id, email, phone, ipaddress, coupon))

    if not validate_totals(state, shippingprice, tax, amt, quantity, coupon):
        return 'FAILURE: price hacked'

    try:

        if total_amt == 0:
            response_message = 'Approved'
            result = '0'
            auth_code = transaction_id = 'zero_value_from_coupon'

        else:
            # Setup the client object.
            client = PayflowProClient(partner=settings.PAYPAL_PARTNER_ID,
                                      vendor=settings.PAYPAL_VENDOR_ID,
                                      username=settings.PAYPAL_USERNAME,
                                      password=settings.PAYPAL_PASSWORD,
                                      url_base='https://payflowpro.paypal.com')

            # Here's a VISA Credit Card for testing purposes.
            credit_card = CreditCard(acct=ccnum, expdate=expdate, cvv2=csc)

            # Let's do a quick sale, auth only, with manual capture later
            responses, unconsumed_data = client.authorization(
                credit_card,
                Amount(amt=total_amt, currency="USD"),
                extras=[
                    Address(street=street + ',' + street2,
                            city=city,
                            billtocountry=countrycode,
                            state=state,
                            country=countrycode,
                            companyname='',
                            zip=zip)
                ])

            # If the sale worked, we'll have a transaction ID
            transaction_id = responses[0].pnref  # little string
            response_message = responses[
                0].respmsg  # 'Approved', 'Invalid account number'
            auth_code = responses[0].authcode  # little string, None on failure
            result = responses[0].result  # 0, positive numbers are error codes
            auth_errors = responses[0].errors  # {}

            if len(responses) > 1:
                # on error responses[1] may not exist
                avsaddr = responses[1].avsaddr  # 'Y'
                iavs = responses[1].iavs  # ?
                avszip = responses[1].avszip  # ?
                addr_errors = responses[1].errors  # {}

        if response_message == 'Approved' and result == '0':
            settings.SHOP_LOGGER.info(
                "Purchase called: response from paypal was SUCCESS: success: %s, transactionid: %s, auth_code: %s, response_message: %s"
                % (result, transaction_id, auth_code, response_message))

            # create order-related db entries
            # XXX unitprice: replace with product's unit price HACK TODO FIXME
            shipping = create_shipping(firstname=firstname,
                                       middlename=middlename,
                                       lastname=lastname,
                                       addr1=street,
                                       addr2=street2,
                                       city=city,
                                       state=state,
                                       zip=zip,
                                       country=countrycode,
                                       telephone=phone)
            order = create_order(userprofile=userprofile,
                                 shipping=shipping,
                                 journal_id=journal_id,
                                 quantity=quantity,
                                 status='sold',
                                 ccauth=auth_code,
                                 notes='transaction_id: %s' % transaction_id,
                                 unitprice=Decimal("15.00"),
                                 shippingprice=shippingprice,
                                 tax=tax,
                                 coupon_id=coupon)

            # create validation ticket
            return get_ticket(journal_id)

        settings.SHOP_LOGGER.info(
            "Purchase called: response from paypal was FAILURE: success: %s, transactionid: %s, auth_errors: %s, response_message: %s"
            % (result, transaction_id, auth_errors, response_message))
        return 'FAILURE: %s' % (result)

    except Exception, err:
        traceback.print_exc()
        settings.SHOP_LOGGER.info(
            "Purchase called: FAILURE, see exception log")
        settings.SHOP_LOGGER.exception("Exception:")
        return 'FAILURE: exception'
Esempio n. 11
0
class PayPalConnection (OnlinePaymentBase):
    # map codes to exceptions - tuples denote ranges
    CODE_MAP = OnlinePaymentBase._explode_map({
        1         : OnlinePaymentBase.AuthError,
        2         : OnlinePaymentBase.InvalidCardType,
        4         : OnlinePaymentBase.AmountInvalid,
        12        : OnlinePaymentBase.TransactionDeclined,
        23        : OnlinePaymentBase.CardNumberInvalid,
        24        : OnlinePaymentBase.CardExpirationInvalid,
        26        : OnlinePaymentBase.AuthError,
        30        : OnlinePaymentBase.DuplicateTransaction,
        33        : OnlinePaymentBase.RecurringOrderDoesNotExist,
        50        : OnlinePaymentBase.TransactionDeclined,
        51        : OnlinePaymentBase.AmountTooHigh,
        102       : OnlinePaymentBase.TryAgainLater,
        106       : OnlinePaymentBase.TryAgainLater,
        112       : OnlinePaymentBase.AVSFailure,
        114       : OnlinePaymentBase.CCVInvalid,
        (125,128) : OnlinePaymentBase.FraudCheckFailed,
    })

    TRANS_STATES = {
          1: 'error',
          6: 'settlement pending',
          7: 'settlement in progress',
          8: 'settlement completed/successfully',
          11: 'settlement failed',
          14: 'settlement incomplete',
    }

    FIELD_MAP = {
        'card_num'           : 'acct',
        'card_code'          : 'cvv2',
        'exp_date'           : 'expdate',
        'amount'             : 'amt',
        'address'            : 'street',
        'company'            : 'companyname',
        'description'        : 'comment1',
        'ship_to_address'    : 'shiptostreet',
        'ship_to_first_name' : 'shiptofirstname',
        'ship_to_last_name'  : 'shiptolastname',
        'ship_to_country'    : 'shiptocountry',
        'ship_to_city'       : 'shiptocity',
        'ship_to_state'      : 'shiptostate',
        'ship_to_zip'        : 'shiptozip',
        'first_name'         : 'firstname',
        'last_name'          : 'lastname',
        'phone'              : 'phonenum',
        'invoice_num'        : 'ponum',

        # recurring fields
        'recurring_id'    : 'profile_id',
        'recurring_start'       : 'start',
        'recurring_period'      : 'payperiod',
        'recurring_total_occurrences' : 'term',
    }

    RECURRING_FIELD_MAPPING = {
        'AMT'             : 'amount',
        'START'           : 'start',
        'NEXTPAYMENT'     : 'next',
        'AGGREGATEAMT'    : 'total',
        'NUMFAILPAYMENTS' : 'failed_payments'
    }

    PAY_PERIOD_MAPPING = {
        'months': 'MONT',
        'weeks' : 'WEEK',
    }

    REVERSE_PAY_PERIOD_MAPPING = dict(
        (v,k) for (k,v) in PAY_PERIOD_MAPPING.items())

    def __init__(self, **kwargs):
        super(PayPalConnection, self).__init__(**kwargs)

        if not self.debug:
            logging.getLogger('payflow_pro').setLevel(logging.WARNING)


        url_base = PayflowProClient.URL_BASE_TEST if self.test_mode \
                   else PayflowProClient.URL_BASE_LIVE
        self.cc = PayflowProClient(url_base=url_base, **self.auth)

    def validate_auth(self, auth):
        for key in ("partner", "vendor", "username", "password"):
            if not key in auth:
                raise InvalidAuthException("Missing required '%s' parameter."\
                                           % key)

    def authorize(self, **kwargs):
        (card, amount, extras) = self._process_params(kwargs)

        sale_result = self.cc.authorization(card, amount, extras=extras)
        result = self._munge_result(sale_result)
        
        self._handle_errors(result)

        return result

    def capture(self, **kwargs):
        trans_id = kwargs['trans_id']
        del(kwargs['trans_id'])

        # card and amount aren't really used here
        (card, amount, extras) = self._process_params(kwargs)

        sale_result = self.cc.capture(trans_id, extras=extras)
        result = self._munge_result(sale_result)
        
        self._handle_errors(result)

        return result


    def sale(self, **kwargs):
        (card, amount, extras) = self._process_params(kwargs)

        sale_result = self.cc.sale(card, amount, extras=extras)
        result = self._munge_result(sale_result)
        
        self._handle_errors(result)

        return result

    def void(self, **kwargs):
        trans_id = kwargs['trans_id']
        del(kwargs['trans_id'])

        # card and amount aren't really used here
        (card, amount, extras) = self._process_params(kwargs)

        void_result = self.cc.void(trans_id, extras=extras)
        result = self._munge_result(void_result)
        
        self._handle_errors(result)

        return result

    def credit(self, **kwargs):
        trans_id = kwargs['trans_id']
        del(kwargs['trans_id'])

        # card and amount aren't really used here
        (card, amount, extras) = self._process_params(kwargs)

        credit_result = self.cc.credit_referenced(trans_id, extras=extras)
        result = self._munge_result(credit_result)
        
        self._handle_errors(result)

        return result

    def inquiry(self, **kwargs):
        trans_id = kwargs['trans_id']
        del(kwargs['trans_id'])

        inquiry_result = self.cc.inquiry(original_pnref=trans_id)
        result = self._munge_result(inquiry_result)

        self._handle_errors(result)

        return result


    def recurring_order_create(self, **kwargs):

        (card, amount, extras) = self._process_params(kwargs)
        (profile,) = find_classes_in_list(Profile, extras)

        result = self.cc.profile_add(profile, card, amount, extras=extras)
        result = self._munge_result(result)

        self._handle_errors(result)

        logging.debug('result = %s' % (result,))

        return result

    def recurring_order_update(self, **kwargs):
        profile_id = kwargs['recurring_id']
        del(kwargs['recurring_id'])

        (card, amount, extras) = self._process_params(kwargs)

        # everything is an extra for update
        extras.append(amount)
        extras.append(card)

        result = self.cc.profile_modify(profile_id, extras=extras)
        result = self._munge_result(result)

        self._handle_errors(result)

        return result


    def recurring_order_cancel(self, **kwargs):
        profile_id = kwargs['recurring_id']
        del(kwargs['recurring_id'])

        result = self.cc.profile_cancel(profile_id)
        result = self._munge_result(result)

        self._handle_errors(result)

        return result

    def recurring_order_payments(self, **kwargs):
        profile_id = kwargs['recurring_id']
        del(kwargs['recurring_id'])

        payment_history_only = kwargs.get('payment_history_only', True)

        result = self.cc.profile_inquiry(
            profile_id, payment_history_only=payment_history_only)
        result = self._munge_result(result)

        self._handle_errors(result)

        return result

    def recurring_order_inquiry(self, **kwargs):
        return \
            self.recurring_order_payments(payment_history_only=False, **kwargs)

    # override process params to build payflow objects after mapping names
    def _process_params(self, kwargs):
        # check and process params
        kwargs = super(PayPalConnection, self)._process_params(kwargs)

        card = self._build_card(kwargs)
        amount = self._build_amount(kwargs)
        extras = self._build_extras(kwargs)

        # if there's anything left in kwargs it's not getting to
        # paypal, so log a warning.  I'm tempted to make this fatal,
        # but I imagine in many cases it's not such a big deal - just
        # a trivial extra field that would be accepted by another
        # processor that's not applicable to paypal.
        if len(kwargs):
            self.log.warning("Extra parameters found: %s" % ','.join(kwargs))

        return (card, amount, extras)

    # Code to build the objects the payflow pro lib uses, only to
    # flatten them again later.  Yeesh.
    def _build_card(self, param):
        return CreditCard(acct    = param.pop('acct', ''),
                          expdate = param.pop('expdate', ''),
                          cvv2    = param.pop('cvv2', ''))

    def _build_amount(self, param):
        return Amount(amt      = param.pop('amt', ''),
                      currency = param.pop('currency', 'USD'),
                      taxamt   = param.pop('tax',''))


    def _build_extras(self, param):
        extras = []

        extras.append(self._build_address(param))
        extras.append(self._build_tracking(param))
        extras.append(self._build_shipping_address(param))
        extras.append(self._build_cust_info(param))
        extras.append(self._build_purchase_info(param))
        extras.append(self._build_recurring_info(param))

        return extras

    def _build_recurring_info(self, param):
        
        start = '%s' % param.pop('start', '')
        if re.match(r'\d{4}-\d{2}-\d{2}', start):
            start = re.sub(r'^(\d{4})-(\d{2})-(\d{2})', r'\2\3\1', start)

        profilename = param.pop('profilename', '')
        if not profilename:
            profilename = 'Default Profile Name'

        term = param.pop('term', '0') # default to forever

        payperiod = param.pop('payperiod', 'MONT')
        if payperiod in self.PAY_PERIOD_MAPPING:
            payperiod = self.PAY_PERIOD_MAPPING[payperiod]

        # For some reason having a blank desc is an error.  And it's
        # only an error on the live server, of course.
        desc = param.pop('desc', '')
        if not len(desc):
            desc = "unused"

        return Profile(
            profilename             = profilename,
            start                   = start,
            term                    = term,
            payperiod               = payperiod,
            maxfailpayments         = param.pop('maxfailpayments', ''),
            desc                    = desc,
            optionaltrx             = param.pop('optionaltrx', ''),
            optionaltrxamt          = param.pop('optionaltrxamt', ''),
            status                  = param.pop('status', ''),
            paymentsleft            = param.pop('paymentsleft', ''),
            nextpayment             = param.pop('nextpayment', ''),
            end                     = param.pop('end', ''),
            numfailpayments         = param.pop('numfailpayments', ''),
            retrynumdays            = param.pop('retrynumdays', ''),
            aggregateamt            = param.pop('aggregateamt', ''),
            aggregateoptionalamt    = param.pop('aggregateoptionalamt', ''))

    def _build_address(self, param):
        return Address(street      = param.pop('street', ''),
                       zip         = param.pop('zip', ''),
                       city        = param.pop('city', ''),
                       state       = param.pop('state', ''),
                       country     = param.pop('country', ''),
                       companyname = param.pop('companyname', ''))

    def _build_tracking(self, param):
        return Tracking(comment1   = param.pop('comment1',''),
                        comment2   = param.pop('comment2',''),
                        verbosity  = param.pop('verbosity',''))

    def _build_shipping_address(self, param):
        return ShippingAddress(
            shiptostreet           = param.pop('shiptostreet',''),
            shiptocity             = param.pop('shiptocity',''),
            shiptofirstname        = param.pop('shiptofirstname',''),
            shiptomiddlename       = param.pop('shiptomiddlename',''),
            shiptolastname         = param.pop('shiptolastname',''),
            shiptostate            = param.pop('shiptostate',''),
            shiptocountry          = param.pop('shiptocountry',''),
            shiptozip              = param.pop('shiptozip',''))
           
    def _build_cust_info(self, param):
        return CustomerInfo(
            custcode               = param.pop('custcode',''),
            email                  = param.pop('email',''),
            firstname              = param.pop('firstname',''),
            name                   = param.pop('name',''),
            middlename             = param.pop('middlename',''),
            lastname               = param.pop('lastname',''),
            phonenum               = param.pop('phonenum',''))

    def _build_purchase_info(self, param):
        return PurchaseInfo(
            ponum                  = param.pop('ponum',''))

    def _parse_transaction_time(self, ts):
        # '24-Nov-09  04:33 AM'
        parsed  = datetime.strptime(ts, '%d-%b-%y  %I:%M %p')
        pacific = pytz.timezone('America/Los_Angeles')
        return pacific.localize(parsed).astimezone(pytz.utc)
        # return datetime(utc.year, utc.month, utc.day, utc.hour, utc.second)

    def _build_recurring_payment(self, payment):
        return OnlinePaymentRecurringPayment(
            trans_id        = payment.p_pnref,
            amount          = payment.p_amt,
            trans_timestamp = self._parse_transaction_time(payment.p_transtime),
            success         = payment.p_result == '0',
            original        = payment,
        )

    def _munge_result(self, orig):

        (response,) = find_classes_in_list([Response],orig[0])
        if (self.debug):
            self.log.debug("Result: %s" % repr(response.__dict__))

        result = {}

        result['code']     = int(response.result)
        result['message']  = response.respmsg
        result['success']  = True if result['code'] == 0 else False
        result['trans_id'] = response.pnref
        result['orig']     = response

        # recurring response of some kind
        (profile_response,) = find_classes_in_list([ProfileResponse], orig[0])
        if profile_response:
            return self._munge_recurring_result(profile_response, result, orig)

        return OnlinePaymentResult(**result)

    def _munge_recurring_result(self, profile_response, result, orig):

        result['trans_id'] = profile_response.rpref
        if hasattr(profile_response, 'profileid'):
            result['recurring_id'] = profile_response.profileid
        else:
            result['recurring_id'] = None

        # Profile, means a profile status request?
        (profile,) = find_classes_in_list([Profile], orig[0])
        if profile:
            payperiod = self.REVERSE_PAY_PERIOD_MAPPING.get(
                           profile.payperiod, profile.payperiod)
            result['profile'] = OnlinePaymentRecurringProfile(
                recurring_id  = profile_response.profileid,
                payperiod           = payperiod,
                status              = profile.status,
                start               = profile.start,
                next                = profile.nextpayment,
                amount              = '', # profile.amt does not exist, amount not included!?
                total               = profile.aggregateamt,
                failed_payments     = profile.numfailpayments,
                orig                = profile
            )

        # RecurringPayments, means we've got a payment history
        (profile_payments,) = find_classes_in_list([RecurringPayments], orig[0])
        if profile_payments:
            result['payments'] = [ self._build_recurring_payment(p) 
                                   for p in profile_payments.payments ]

        return OnlinePaymentRecurringResult(**result)
Esempio n. 12
0
def purchase(userprofile=None, amt=15.00, shippingprice=5.00, tax=0.00, cctype='Visa', ccnum=settings.TEST_VISA_ACCOUNT_NO, expdate=settings.TEST_VISA_EXPIRATION, csc=settings.TEST_CVV2, firstname='John', middlename='',
			lastname='Doe', street='1313 Mockingbird Lane', street2='', city='Beverly Hills', state='CA', zip='90110',
			countrycode='US', currencycode='USD', journal_id=0, email=settings.TEST_EMAIL_PERSONAL, phone='', ipaddress='', quantity=0, coupon=''):
	"""
		Direct purchase through paypal.
	"""

	# make sure all amounts are not more precise than cents
	amt =  Decimal(amt).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
	shippingprice = Decimal(shippingprice).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
	tax =  Decimal(tax).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
	total_amt = amt + shippingprice + tax

	settings.SHOP_LOGGER.info("Purchase called: amt: %s, shipping: %s, tax: %s, cctype: %s, ccnum: %s, expdate: %s, csc: %s, firstname: %s, middlename: %s, lastname: %s, street: %s, street2: %s, city: %s, state: %s, zip: %s, countrycode: %s, currencycode: %s, journal_id: %s, email: %s, phone: %s, ipaddress: %s, coupon: %s" % 
		(amt, shippingprice, tax, cctype, ccnum, expdate, csc, firstname, middlename, lastname, street, street2, city, state, zip, countrycode, currencycode, journal_id, email, phone, ipaddress, coupon))

	if not validate_totals(state, shippingprice, tax, amt, quantity, coupon):
		return 'FAILURE: price hacked'

	try:

		if total_amt == 0:
			response_message = 'Approved'
			result = '0'
			auth_code = transaction_id = 'zero_value_from_coupon'
			
		else:
			# Setup the client object.
			client = PayflowProClient(partner=settings.PAYPAL_PARTNER_ID, vendor=settings.PAYPAL_VENDOR_ID, username=settings.PAYPAL_USERNAME, password=settings.PAYPAL_PASSWORD, url_base='https://payflowpro.paypal.com')

			# Here's a VISA Credit Card for testing purposes.
			credit_card = CreditCard(acct=ccnum, expdate=expdate, cvv2=csc)

			# Let's do a quick sale, auth only, with manual capture later
			responses, unconsumed_data = client.authorization(credit_card, Amount(amt=total_amt, currency="USD"), 
												extras=[Address(street=street + ',' + street2, city=city, billtocountry=countrycode, state=state, country=countrycode, companyname='', zip=zip)])

			# If the sale worked, we'll have a transaction ID
			transaction_id = responses[0].pnref # little string
			response_message = responses[0].respmsg # 'Approved', 'Invalid account number'
			auth_code = responses[0].authcode # little string, None on failure
			result = responses[0].result # 0, positive numbers are error codes
			auth_errors = responses[0].errors # {}

			if len(responses) > 1:
				# on error responses[1] may not exist
				avsaddr = responses[1].avsaddr # 'Y'
				iavs = responses[1].iavs # ?
				avszip = responses[1].avszip # ?
				addr_errors = responses[1].errors # {}

		if response_message == 'Approved' and result == '0':
			settings.SHOP_LOGGER.info("Purchase called: response from paypal was SUCCESS: success: %s, transactionid: %s, auth_code: %s, response_message: %s" % (result, transaction_id, auth_code, response_message))

			# create order-related db entries
			# XXX unitprice: replace with product's unit price HACK TODO FIXME
			shipping = create_shipping(firstname=firstname, middlename=middlename, lastname=lastname, addr1=street, addr2=street2, city=city, state=state, zip=zip, country=countrycode, telephone=phone)
			order = create_order(userprofile=userprofile, shipping=shipping, journal_id=journal_id, quantity=quantity, status='sold', ccauth=auth_code, notes='transaction_id: %s' % transaction_id,
								 unitprice=Decimal("15.00"), shippingprice=shippingprice, tax=tax, coupon_id=coupon)

			# create validation ticket
			return get_ticket(journal_id)

		settings.SHOP_LOGGER.info("Purchase called: response from paypal was FAILURE: success: %s, transactionid: %s, auth_errors: %s, response_message: %s" % (result, transaction_id, auth_errors, response_message))
		return 'FAILURE: %s' % (result)

	except Exception, err:
		traceback.print_exc()
		settings.SHOP_LOGGER.info("Purchase called: FAILURE, see exception log")
		settings.SHOP_LOGGER.exception("Exception:")
		return 'FAILURE: exception'