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()))) )
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)))
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)))
def test_shorter(self): eq_(shorter(40000), 'nUs')
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)