Beispiel #1
0
 def create_short_uid(self):
     """
     Generate a unique id based on the primary key which is shorter
     (14 chars) than an average uuid (32 chars).
     """
     codes = {
         constants.PROVIDER_BANGO: 'ba',
         constants.PROVIDER_BRAINTREE: 'bt',
     }
     return (
         '{}-{}-{}'.format(
             # Get a provider code or dk for dont know.
             codes.get(self.provider, 'dk'),
             # Should be unique within this db.
             shorter(self.pk),
             # If pk is repeated (eg. in tests, dev) should still
             # be unique.
             shorter(int(time.time())))
     )
Beispiel #2
0
 def test_data(self):
     hook = self.process(subscription())
     eq_(hook.data['braintree']['kind'],
         'subscription_charged_successfully')
     eq_(hook.data['mozilla']['buyer']['resource_pk'], self.buyer.pk)
     eq_(hook.data['mozilla']['transaction']['generic']['resource_pk'],
         Transaction.objects.get().pk)
     eq_(hook.data['mozilla']['transaction']['braintree']['resource_pk'],
         BraintreeTransaction.objects.get().pk)
     eq_(hook.data['mozilla']['paymethod']['resource_pk'], self.method.pk)
     eq_(hook.data['mozilla']['product']['resource_pk'],
         self.seller_product.pk)
     eq_(hook.data['mozilla']['subscription']['resource_pk'],
         self.braintree_sub.pk)
     assert (hook.data['mozilla']['transaction']['generic']['uuid']
             .startswith('bt-' + shorter(Transaction.objects.get().pk)))
Beispiel #3
0
 def test_data(self):
     hook = self.process(subscription())
     eq_(hook.data['braintree']['kind'],
         'subscription_charged_successfully')
     eq_(hook.data['mozilla']['buyer']['resource_pk'], self.buyer.pk)
     eq_(hook.data['mozilla']['transaction']['generic']['resource_pk'],
         Transaction.objects.get().pk)
     eq_(hook.data['mozilla']['transaction']['braintree']['resource_pk'],
         BraintreeTransaction.objects.get().pk)
     eq_(hook.data['mozilla']['paymethod']['resource_pk'], self.method.pk)
     eq_(hook.data['mozilla']['product']['resource_pk'],
         self.seller_product.pk)
     eq_(hook.data['mozilla']['subscription']['resource_pk'],
         self.braintree_sub.pk)
     assert (hook.data['mozilla']['transaction']['generic']
             ['uuid'].startswith('bt-' +
                                 shorter(Transaction.objects.get().pk)))
Beispiel #4
0
 def test_shorter(self):
     eq_(shorter(40000), 'nUs')
Beispiel #5
0
 def test_shorter(self):
     eq_(shorter(40000), 'nUs')
Beispiel #6
0
    def update_transactions(self):
        """
        We are going to make an assumption that there are only
        some transactions that we care about.

        A full list is here: http://bit.ly/1T23ehV

        We are going to record the following:
        * settled
        * failed
        * gateway_rejected
        * processor_declined
        * settlement_declined
        * submitted_for_settlement

        We are going to ignore the following:
        * authorized
        * authorizing
        * authorization_expired
        * settling
        * settlement_pending
        * settlement_confirmed
        * voided

        All of the ignored states are temporary statuses and we don't
        really care about those.

        Transactions on a subscription are:

            Transactions associated with the subscription,
            sorted by creation date with the most recent first.

        The creation time in a transaction is set to the time it was
        created in solitude. Because of lack of millisecond precision on
        data queries, the best way to find the most recent transaction
        is ordering by id.
        """
        if not self.subscription:
            raise ValueError('No subscription, call `get_subscription` first.')

        their_subscription = self.webhook.subscription
        for their_transaction in their_subscription.transactions:
            status = their_transaction.status
            if status not in settings.BRAINTREE_TRANSACTION_STATUSES:
                log.info('Ignoring transaction status: {}'.format(status))
                continue

            log.info('Processing transaction status: {}'.format(status))
            # These are really the only two end statuses we care about.
            our_status = (constants.STATUS_CHECKED if status in [
                'settled', 'submitted_for_settlement'
            ] else constants.STATUS_FAILED)

            # Write some reason in for the failure.
            reason = ''
            if status == 'processor_declined':
                reason = their_transaction.processor_response_code
            elif status == 'settlement_declined':
                reason = their_transaction.processor_settlement_response_code
            elif status == 'gateway_rejected':
                # There doesn't seem to be a code for gateway rejection.
                reason = their_transaction.gateway_rejection_reason

            reason = (their_transaction.status + ' ' + reason).rstrip()

            try:
                our_transaction = Transaction.objects.get(
                    uid_support=their_transaction.id, )
                log.info('Transaction exists: {}'.format(our_transaction.pk))
                # Just a maybe pointless sanity check that the status they are
                # sending in their transaction matches our record.
                if our_transaction.status != our_status:
                    raise ValueError(
                        'Status: {} does not match: {} in transaction: {}'.
                        format(their_transaction.status, our_status,
                               our_transaction.pk))

            except ObjectDoesNotExist:
                our_transaction = Transaction.objects.create(
                    amount=their_transaction.amount,
                    buyer=self.subscription.paymethod.braintree_buyer.buyer,
                    currency=their_transaction.currency_iso_code,
                    provider=constants.PROVIDER_BRAINTREE,
                    seller=self.subscription.seller_product.seller,
                    seller_product=self.subscription.seller_product,
                    status=our_status,
                    status_reason=reason,
                    type=constants.TYPE_PAYMENT,
                    uid_support=their_transaction.id)

                # Make the transaction short and helpful
                # (14 chars, still 4 chars less than the mocks)
                our_transaction.uuid = (
                    'bt-{}-{}'.format(
                        # Should be unique within this db.
                        shorter(our_transaction.pk),
                        # If pk is repeated (eg. in tests, dev) should still
                        # be unique.
                        shorter(int(time.time()))))
                our_transaction.save()

                log.info('Transaction created: {}'.format(our_transaction.pk))

                braintree_transaction = BraintreeTransaction.objects.create(
                    transaction=our_transaction,
                    subscription=self.subscription,
                    paymethod=self.subscription.paymethod,
                    kind=self.webhook.kind,
                    billing_period_end_date=(
                        their_subscription.billing_period_end_date),
                    billing_period_start_date=(
                        their_subscription.billing_period_start_date),
                    next_billing_date=their_subscription.next_billing_date,
                    next_billing_period_amount=(
                        their_subscription.next_billing_period_amount),
                )
                log.info('BraintreeTransaction created: {}'.format(
                    braintree_transaction.pk))

            self.transactions.append(our_transaction)