예제 #1
0
    def authorize_payment(self, purchase=None, amount=NOTSET, testing=False):
        """Authorize a single payment.
        
        Returns: ProcessorResult
        """
        assert (purchase)
        if purchase.remaining == Decimal('0.00'):
            self.log_extra('%s is paid in full, no authorization attempted.',
                           purchase)
            results = ProcessorResult(self.key, True,
                                      _("No charge needed, paid in full."))
        else:
            if amount == NOTSET:
                try:
                    pending = purchase.get_pending(self.key)
                    amount = pending.amount
                except PaymentPending.DoesNotExist:
                    amount = purchase.remaining
            self.log_extra('Authorizing payment of %s for %s', amount,
                           purchase)

            standard = self.get_standard_charge_data(authorize=True,
                                                     purchase=purchase,
                                                     amount=amount)
            results = self.send_post(standard, testing, purchase=purchase)

        return results
예제 #2
0
    def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
        """Process payments without an authorization step."""
        assert (purchase)
        recurlist = self.get_recurring_charge_data(purchase=purchase)
        if recurlist:
            success, results = self.process_recurring_subscriptions(
                recurlist, testing)
            if not success:
                self.log_extra(
                    'recur payment failed, aborting the rest of the module')
                return results

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

            standard = self.get_standard_charge_data(amount=amount,
                                                     purchase=purchase)
            results = self.send_post(standard, testing, purchase=purchase)

        return results
예제 #3
0
    def process_recurring_subscriptions(self,
                                        recurlist,
                                        purchase=None,
                                        testing=False):
        """Post all subscription requests."""
        assert (purchase)
        results = []
        for recur in recurlist:
            success, reason, response, subscription_id = self.process_recurring_subscription(
                recur, testing=testing)
            if success:
                if not testing:
                    payment = self.record_payment(
                        purchase=purchase,
                        amount=recur['charged_today'],
                        transaction_id=subscription_id,
                        reason_code=reason)
                    results.append(
                        ProcessorResult(self.key,
                                        success,
                                        response,
                                        payment=payment))
            else:
                self.log.info(
                    "Failed to process recurring subscription, %s: %s", reason,
                    response)
                break

        return success, results
예제 #4
0
    def capture_payment(self, testing=False, order=None, amount=NOTSET):
        """process the transaction through tclink"""
        if not order:
            order = self.order

        if amount == NOTSET:
            amount = order.balance
            
        if order.paid_in_full:
            self.log_extra('%s is paid in full, no capture attempted.', order)
            self.record_payment()
            return ProcessorResult(self.key, True, _("No charge needed, paid in full."))

        self.log_extra('Capturing payment for %s', order)

        self.prepare_post(order, amount)

        result = tclink.send(self.transactionData)
        status = result ['status']
        payment = None
        success = False
        
        if status == 'approved':
            payment = self.record_payment(order=order, amount=amount, 
                transaction_id="", reason_code=status)
            success = True
            msg = unicode(result)

        else:
            if status == 'decline':
                msg = _(u'Transaction was declined.  Reason: %s' % result['declinetype'])
                failmsg = u'Transaction was declined.  Reason: %s' % result['declinetype']

            elif status == 'baddata':
                msg = _(u'Improperly formatted data. Offending fields: %s' % result['offenders'])
                failmsg = u'Improperly formatted data. Offending fields: %s' % result['offenders']

            else:
                status = "error"
                msg = _(u'An error occurred: %s' % result['errortype'])
                failmsg = u'An error occurred: %s' % result['errortype']

            payment = self.record_failure(order=order, amount=amount, 
                transaction_id="", reason_code=status, 
                details=failmsg)

        return ProcessorResult(self.key, success, msg, payment=payment)
예제 #5
0
 def release_authorized_payment(self,
                                purchase=None,
                                auth=None,
                                testing=False):
     """Release a previously authorized payment."""
     auth.complete = True
     auth.save()
     return ProcessorResult(self.key, True, _('Success'))
예제 #6
0
 def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
     """Process the transaction and return a ProcessorResult:
     """
     assert (purchase)
     payment = self.record_payment(amount=amount,
                                   reason_code="0",
                                   purchase=purchase)
     return ProcessorResult(self.key, True, _('Success'), payment)
예제 #7
0
    def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
        """
        Creates and sends XML representation of transaction to Cybersource
        """
        if purchase.remaining == Decimal('0.00'):
            self.log_extra('%s is paid in full, no capture attempted.', purchase)
            self.record_payment(purchase=purchase)
            return ProcessorResult(self.key, True, _("No charge needed, paid in full."))

        self.log_extra('Capturing payment for %s', purchase)

        if amount==NOTSET:
            amount = purchase.remaining

        self.prepare_content(purchase, amount)
        
        invoice = "%s" % purchase.id
        failct = purchase.paymentfailures.count()
        if failct > 0:
            invoice = "%s_%i" % (invoice, failct)
        
        # XML format is very simple, using ElementTree for generation would be overkill
        t = loader.get_template('bursar/gateway/cybersource_gateway/request.xml')
        c = Context({
            'config' : self.configuration,
            'merchantReferenceCode' : invoice,
            'billTo' : self.bill_to,
            'purchaseTotals' : self.purchase_totals,
            'card' : self.card,
        })
        request = t.render(c)
        self.log_extra("Cybersource request: %s", request)
        conn = urllib2.Request(url=self.connection, data=request)
        try:
            f = urllib2.urlopen(conn)
        except urllib2.HTTPError, e:
            # we probably didn't authenticate properly
            # make sure the 'v' in your account number is lowercase
            return ProcessorResult(self.key, False, 'Problem parsing results')
예제 #8
0
    def authorize_payment(self, purchase=None, testing=False, amount=NOTSET):
        """
        Make an authorization for an purchase.  This payment will then be captured when the purchase
        is set marked 'shipped'.
        """
        assert (purchase)
        if amount == NOTSET:
            amount = self.pending_amount(purchase)

        cc = purchase.credit_card
        if cc:
            ccn = cc.decryptedCC
            ccv = cc.ccv
            if ccn == '4222222222222':
                if ccv == '222':
                    self.log_extra('Bad CCV forced')
                    payment = self.record_failure(amount=amount,
                                                  transaction_id='2',
                                                  reason_code='2',
                                                  details='CCV error forced')
                    return ProcessorResult(self.key, False,
                                           _('Bad CCV - order declined'),
                                           payment)
                else:
                    self.log_extra(
                        'Setting a bad credit card number to force an error')
                    payment = self.record_failure(
                        amount=amount,
                        transaction_id='2',
                        reason_code='2',
                        details='Credit card number error forced')
                    return ProcessorResult(
                        self.key, False,
                        _('Bad credit card number - order declined'), payment)

        orderauth = self.record_authorization(amount=amount,
                                              reason_code="0",
                                              purchase=purchase)
        return ProcessorResult(self.key, True, _('Success'), orderauth)
예제 #9
0
    def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
        """
        Purchase Orders are always successful.
        """
        if amount == NOTSET:
            amount = purchase.total

        payment = self.record_payment(purchase=purchase,
                                      amount=amount,
                                      transaction_id="PO",
                                      reason_code='0')

        return ProcessorResult(self.key, True, _('Success'), payment)
예제 #10
0
    def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
        assert (purchase)
        if amount == NOTSET:
            amount = purchase.total

        log.debug('Capturing payment of %s', amount)

        payment = self.record_payment(purchase=purchase,
                                      amount=amount,
                                      transaction_id=self.key,
                                      reason_code='0')

        return ProcessorResult(self.key, True, _('Success'), payment)
예제 #11
0
    def capture_payment(self, testing=False, order=None, amount=NOTSET):
        """
        Process the transaction and return a ProcessorResponse
        """
        if not order:
            order = self.order

        if amount == NOTSET:
            amount = order.balance

        payment = None

        valid_gc = False
        if self.order.paid_in_full:
            success = True
            reason_code = "0"
            response_text = _("No balance to pay")
            self.record_payment()

        else:
            try:
                gc = GiftCertificate.objects.from_order(self.order)
                valid_gc = gc.valid

            except GiftCertificate.DoesNotExist:
                success = False
                reason_code = "1"
                response_text = _("No such Gift Certificate")

            if not valid_gc:
                success = False
                reason_code = "2"
                response_text = _("Bad Gift Certificate")

            else:
                gc.apply_to_order(self.order)
                payment = gc.payment
                reason_code = "0"
                response_text = _("Success")
                success = True

                if not self.order.paid_in_full:
                    response_text = _(
                        "%s balance remains after gift certificate was applied"
                    ) % moneyfmt(self.order.balance)

        return ProcessorResult(self.key,
                               success,
                               response_text,
                               payment=payment)
예제 #12
0
    def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
        """
        COD is always successful.
        """
        assert (purchase)
        if amount == NOTSET:
            amount = purchase.total

        payment = self.record_payment(amount=amount,
                                      transaction_id=self.key,
                                      reason_code='0',
                                      purchase=purchase)

        return ProcessorResult(self.key, True, _('Success'), payment)
예제 #13
0
    def capture_authorized_payment(self,
                                   authorization,
                                   amount=NOTSET,
                                   purchase=None):
        """
        Capture a prior authorization
        """
        if not purchase:
            purchase = authorization.purchase
        if amount == NOTSET:
            amount = authorization.amount

        payment = self.record_payment(amount=amount,
                                      reason_code="0",
                                      transaction_id="dummy",
                                      authorization=authorization,
                                      purchase=purchase)

        return ProcessorResult(self.key, True, _('Success'), payment)
예제 #14
0
    def capture_authorized_payment(self,
                                   authorization,
                                   testing=False,
                                   purchase=None,
                                   amount=NOTSET):
        """Capture a single payment"""
        assert (purchase)
        if purchase.authorized_remaining == Decimal('0.00'):
            self.log_extra('No remaining authorizations on %s', purchase)
            return ProcessorResult(self.key, True, _("Already complete"))

        self.log_extra('Capturing Authorization #%i of %s', authorization.id,
                       amount)
        if amount == NOTSET:
            amount = authorization.amount
        data = self.get_prior_auth_data(authorization, amount=amount)
        results = None
        if data:
            results = self.send_post(data, testing, purchase=purchase)

        return results
예제 #15
0
    def send_post(self, data, testing=False, purchase=None, amount=NOTSET):
        """Execute the post to Authorize Net.
        
        Params:
        - data: dictionary as returned by get_standard_charge_data
        - testing: if true, then don't record the payment
        
        Returns:
        - ProcessorResult
        """
        assert (purchase)
        self.log.info(
            "About to send a request to authorize.net: %(connection)s\n%(logPostString)s",
            data)

        conn = urllib2.Request(url=data['connection'], data=data['postString'])
        try:
            f = urllib2.urlopen(conn)
            all_results = f.read()
            self.log_extra('Authorize response: %s', all_results)
        except urllib2.URLError, ue:
            self.log.error("error opening %s\n%s", data['connection'], ue)
            return ProcessorResult(
                self.key, False, _('Could not talk to Authorize.net gateway'))
예제 #16
0
                            reason_code=status)

                    else:
                        payment = self.record_failure(
                            purchase=purchase,
                            amount=amount,
                            transaction_id=transaction_id,
                            reason_code=status,
                            details=detail)

                    return ProcessorResult(self.key,
                                           success,
                                           detail,
                                           payment=payment)

                except Exception, e:
                    self.log.info('Error submitting payment: %s', e)
                    payment = self.record_failure(
                        purchase=purchase,
                        amount=amount,
                        transaction_id="",
                        reason_code="error",
                        details='Invalid response from bursar gateway')

                    return ProcessorResult(
                        self.key, False,
                        _('Invalid response from bursar gateway'))
        else:
            return ProcessorResult(self.key, False,
                                   _('Error processing payment.'))
예제 #17
0
class PaymentProcessor(BasePaymentProcessor):
    """
    Cybersource payment processing module
    You must have an account with Cybersource in order to use this module
    
    """
    def __init__(self, settings={}):
        
        working_settings = {
            #This is the address to submit live transactions
            'CONNECTION': 'https://ics2ws.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.26.wsdl',

            #This is the address to submit test transactions
            'CONNECTION_TEST': 'https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor/CyberSourceTransaction_1.26.wsdl',

            'LIVE': False,

            'LABEL': _('This will be passed to the translation utility'),

            'CURRENCY_CODE': 'USD',

            'CREDITCHOICES': (
                (('American Express', 'American Express')),
                (('Visa','Visa')),
                (('Mastercard','Mastercard')),
                #(('Discover','Discover'))
            ),

            #Your Cybersource merchant ID - REQUIRED
            'MERCHANT_ID': "",

            #Your Cybersource transaction key - REQUIRED
            'TRANKEY': "",

            'EXTRA_LOGGING': False
        }
        
        working_settings.update(settings)
        super(PaymentProcessor, self).__init__('cybersource', working_settings)

        self.require_settings('MERCHANT_ID', 'TRANKEY')
        
        self.contents = ''
        if self.is_live():
            self.testflag = 'FALSE'
            self.connection = self.settings['CONNECTION']
        else:
            self.testflag = 'TRUE'
            self.connection = self.settings['CONNECTION_TEST']
            
        self.configuration = {
            'merchantID' : self.settings['MERCHANT_ID'],
            'password' : self.settings['TRANKEY'],
        }

    def prepare_content(self, purchase, amount):
        self.bill_to = {
            'firstName' : purchase.first_name,
            'lastName' : purchase.last_name,
            'street1': purchase.full_bill_street,
            'city': purchase.bill_city,
            'state' : purchase.bill_state,
            'postalCode' : purchase.bill_postal_code,
            'country': purchase.bill_country,
            'email' : purchase.email,
            'phoneNumber' : purchase.phone,
            }
        exp = purchase.credit_card.expirationDate.split('/')
        self.card = {
            'accountNumber' : purchase.credit_card.decryptedCC,
            'expirationMonth' : exp[0],
            'expirationYear' : exp[1],
            'cvNumber' : purchase.credit_card.ccv
            }
        currency = self.settings['CURRENCY_CODE']
        currency = currency.replace("_", "")
        self.purchase_totals = {
            'currency' : currency,
            'grandTotalAmount' : trunc_decimal(amount, 2),
        }

    def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
        """
        Creates and sends XML representation of transaction to Cybersource
        """
        if purchase.remaining == Decimal('0.00'):
            self.log_extra('%s is paid in full, no capture attempted.', purchase)
            self.record_payment(purchase=purchase)
            return ProcessorResult(self.key, True, _("No charge needed, paid in full."))

        self.log_extra('Capturing payment for %s', purchase)

        if amount==NOTSET:
            amount = purchase.remaining

        self.prepare_content(purchase, amount)
        
        invoice = "%s" % purchase.id
        failct = purchase.paymentfailures.count()
        if failct > 0:
            invoice = "%s_%i" % (invoice, failct)
        
        # XML format is very simple, using ElementTree for generation would be overkill
        t = loader.get_template('bursar/gateway/cybersource_gateway/request.xml')
        c = Context({
            'config' : self.configuration,
            'merchantReferenceCode' : invoice,
            'billTo' : self.bill_to,
            'purchaseTotals' : self.purchase_totals,
            'card' : self.card,
        })
        request = t.render(c)
        self.log_extra("Cybersource request: %s", request)
        conn = urllib2.Request(url=self.connection, data=request)
        try:
            f = urllib2.urlopen(conn)
        except urllib2.HTTPError, e:
            # we probably didn't authenticate properly
            # make sure the 'v' in your account number is lowercase
            return ProcessorResult(self.key, False, 'Problem parsing results')

        f = urllib2.urlopen(conn)
        all_results = f.read()
        self.log_extra("Cybersource response: %s", all_results)
        tree = fromstring(all_results)
        parsed_results = tree.getiterator('{urn:schemas-cybersource-com:transaction-data-1.26}reasonCode')
        try:
            reason_code = parsed_results[0].text
        except KeyError:
            return ProcessorResult(self.key, False, 'Problem parsing results')

        response_text = CYBERSOURCE_RESPONSES.get(reason_code, 'Unknown Failure')

        if reason_code == '100':
            self.log_extra('%s successfully charged', purchase)
            payment = self.record_payment(purchase=purchase, amount=amount, 
                transaction_id="", reason_code=reason_code)
            return ProcessorResult(self.key, True, response_text, payment=payment)
        else:
            payment = self.record_failure(purchase=purchase, amount=amount, 
                transaction_id="", reason_code=reason_code, 
                details=response_text)
            
            return ProcessorResult(self.key, False, response_text)
예제 #18
0
    def capture_payment(self, testing=False, purchase=None, amount=NOTSET):
        """Execute the post to protx VSP DIRECT"""
        if not purchase:
            purchase = self.purchase

        if purchase.remaining == Decimal('0.00'):
            self.log_extra('%s is paid in full, no capture attempted.',
                           purchase)
            self.record_payment(purchase=purchase)
            return ProcessorResult(self.key, True,
                                   _("No charge needed, paid in full."))

        self.log_extra('Capturing payment for %s', purchase)

        if amount == NOTSET:
            amount = purchase.remaining

        self.prepare_post(purchase, amount)

        if self.valid:
            if self.settings['SKIP_POST']:
                self.log.info(
                    "TESTING MODE - Skipping post to server.  Would have posted %s?%s",
                    self.url, self.postString)
                payment = self.record_payment(purchase=purchase,
                                              amount=amount,
                                              transaction_id="TESTING",
                                              reason_code='0')

                return ProcessorResult(self.key,
                                       True,
                                       _('TESTING MODE'),
                                       payment=payment)

            else:
                self.log_extra("About to post to server: %s?%s", self.url,
                               self.postString)
                conn = urllib2.Request(self.url, data=self.postString)
                try:
                    f = urllib2.urlopen(conn)
                    result = f.read()
                    self.log_extra('Process: url=%s\nPacket=%s\nResult=%s',
                                   self.url, self.packet, result)

                except urllib2.URLError, ue:
                    self.log.error("error opening %s\n%s", self.url, ue)
                    return ProcessorResult(
                        self.key, False,
                        'ERROR: Could not talk to Protx gateway')

                try:
                    self.response = dict(
                        [row.split('=', 1) for row in result.splitlines()])
                    status = self.response['Status']
                    success = (status == 'OK')
                    detail = self.response['StatusDetail']

                    payment = None
                    transaction_id = ""
                    if success:
                        vpstxid = self.response.get('VPSTxID', '')
                        txauthno = self.response.get('TxAuthNo', '')
                        transaction_id = "%s,%s" % (vpstxid, txauthno)
                        self.log.info(
                            'Success on purchase #%i, recording payment',
                            self.purchase.id)
                        payment = self.record_payment(
                            purchase=purchase,
                            amount=amount,
                            transaction_id=transaction_id,
                            reason_code=status)

                    else:
                        payment = self.record_failure(
                            purchase=purchase,
                            amount=amount,
                            transaction_id=transaction_id,
                            reason_code=status,
                            details=detail)

                    return ProcessorResult(self.key,
                                           success,
                                           detail,
                                           payment=payment)

                except Exception, e:
                    self.log.info('Error submitting payment: %s', e)
                    payment = self.record_failure(
                        purchase=purchase,
                        amount=amount,
                        transaction_id="",
                        reason_code="error",
                        details='Invalid response from bursar gateway')

                    return ProcessorResult(
                        self.key, False,
                        _('Invalid response from bursar gateway'))
예제 #19
0
                payment = self.record_authorization(
                    purchase=purchase,
                    amount=amount,
                    transaction_id=transaction_id,
                    reason_code=reason_code)
            else:
                if amount <= 0:
                    self.log_extra('Success, recording refund')
                else:
                    self.log_extra('Success, recording payment')
                authorization = data.get('authorization', None)
                payment = self.record_payment(purchase=purchase,
                                              amount=amount,
                                              transaction_id=transaction_id,
                                              reason_code=reason_code,
                                              authorization=authorization)

        elif not testing:
            payment = self.record_failure(amount=amount,
                                          transaction_id=transaction_id,
                                          reason_code=reason_code,
                                          details=response_text,
                                          purchase=purchase)

        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)