Modules
djstripe.admin
Django Administration interface definitions
Classes
djstripe.admin.APIKeyAdmin
djstripe.admin.APIKeyAdmin.list_display
djstripe.admin.APIKeyAdmin.list_filter
djstripe.admin.APIKeyAdmin.media
property
readonly
djstripe.admin.APIKeyAdmin.search_fields
Methods
djstripe.admin.APIKeyAdmin.get_fields(self, request, obj=None)
Hook for specifying fields.
Source code in djstripe/admin.py
def get_fields(self, request, obj=None):
fields = super().get_fields(request, obj)
fields.remove("id")
fields.remove("created")
if obj is None:
fields.remove("type")
fields.remove("livemode")
return fields
djstripe.admin.APIKeyAdmin.get_fieldsets(self, request, obj=None)
Hook for specifying fieldsets.
Source code in djstripe/admin.py
def get_fieldsets(self, request, obj=None):
"""
Hook for specifying fieldsets.
"""
if self.fieldsets:
return self.fieldsets
return [(None, {'fields': self.get_fields(request, obj)})]
djstripe.admin.AccountAdmin
djstripe.admin.AccountAdmin.list_display
djstripe.admin.AccountAdmin.list_filter
djstripe.admin.AccountAdmin.media
property
readonly
djstripe.admin.AccountAdmin.search_fields
djstripe.admin.ApplicationFeeAdmin
djstripe.admin.ApplicationFeeAdmin.list_display
djstripe.admin.ApplicationFeeAdmin.media
property
readonly
djstripe.admin.ApplicationFeeReversalAdmin
djstripe.admin.ApplicationFeeReversalAdmin.list_display
djstripe.admin.ApplicationFeeReversalAdmin.media
property
readonly
djstripe.admin.BalanceTransactionAdmin
djstripe.admin.BalanceTransactionAdmin.list_display
djstripe.admin.BalanceTransactionAdmin.list_filter
djstripe.admin.BalanceTransactionAdmin.media
property
readonly
djstripe.admin.BankAccountAdmin
djstripe.admin.BankAccountAdmin.list_display
djstripe.admin.BankAccountAdmin.list_select_related
djstripe.admin.BankAccountAdmin.media
property
readonly
djstripe.admin.BankAccountAdmin.search_fields
djstripe.admin.BaseHasSourceListFilter
djstripe.admin.BaseHasSourceListFilter.parameter_name
djstripe.admin.BaseHasSourceListFilter.title
Methods
djstripe.admin.BaseHasSourceListFilter.lookups(self, request, model_admin)
Return a list of tuples.
The first element in each tuple is the coded value for the option that will appear in the URL query. The second element is the human-readable name for the option that will appear in the right sidebar. source: https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
Source code in djstripe/admin.py
def lookups(self, request, model_admin):
"""
Return a list of tuples.
The first element in each tuple is the coded value for the option that will
appear in the URL query. The second element is the
human-readable name for the option that will appear
in the right sidebar.
source:
https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
"""
return (("yes", "Has a source"), ("no", "Has no source"))
djstripe.admin.BaseHasSourceListFilter.queryset(self, request, queryset)
Return the filtered queryset based on the value provided in the query string.
source: https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
Source code in djstripe/admin.py
def queryset(self, request, queryset):
"""
Return the filtered queryset based on the value provided in the query string.
source:
https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
"""
filter_args = {self._filter_arg_key: None}
if self.value() == "yes":
return queryset.exclude(**filter_args)
if self.value() == "no":
return queryset.filter(**filter_args)
djstripe.admin.CardAdmin
djstripe.admin.CardAdmin.list_display
djstripe.admin.CardAdmin.list_select_related
djstripe.admin.CardAdmin.media
property
readonly
djstripe.admin.CardAdmin.search_fields
djstripe.admin.ChargeAdmin
djstripe.admin.ChargeAdmin.list_display
djstripe.admin.ChargeAdmin.list_filter
djstripe.admin.ChargeAdmin.list_select_related
djstripe.admin.ChargeAdmin.media
property
readonly
djstripe.admin.ChargeAdmin.search_fields
djstripe.admin.CouponAdmin
djstripe.admin.CouponAdmin.list_display
djstripe.admin.CouponAdmin.list_filter
djstripe.admin.CouponAdmin.media
property
readonly
djstripe.admin.CouponAdmin.radio_fields
djstripe.admin.CustomerAdmin
djstripe.admin.CustomerAdmin.inlines
djstripe.admin.CustomerAdmin.list_display
djstripe.admin.CustomerAdmin.list_filter
djstripe.admin.CustomerAdmin.list_select_related
djstripe.admin.CustomerAdmin.media
property
readonly
djstripe.admin.CustomerAdmin.search_fields
djstripe.admin.CustomerHasSourceListFilter
djstripe.admin.CustomerSubscriptionStatusListFilter
A SimpleListFilter used with Customer admin.
djstripe.admin.CustomerSubscriptionStatusListFilter.parameter_name
djstripe.admin.CustomerSubscriptionStatusListFilter.title
Methods
djstripe.admin.CustomerSubscriptionStatusListFilter.lookups(self, request, model_admin)
Return a list of tuples.
The first element in each tuple is the coded value for the option that will appear in the URL query. The second element is the human-readable name for the option that will appear in the right sidebar. source: https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
Source code in djstripe/admin.py
def lookups(self, request, model_admin):
"""
Return a list of tuples.
The first element in each tuple is the coded value for the option that will
appear in the URL query. The second element is the
human-readable name for the option that will appear
in the right sidebar.
source:
https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
"""
statuses = [
[x, x.replace("_", " ").title()]
for x in models.Subscription.objects.values_list(
"status", flat=True
).distinct()
]
statuses.append(["none", "No Subscription"])
return statuses
djstripe.admin.CustomerSubscriptionStatusListFilter.queryset(self, request, queryset)
Return the filtered queryset based on the value provided in the query string.
source: https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
Source code in djstripe/admin.py
def queryset(self, request, queryset):
"""
Return the filtered queryset based on the value provided in the query string.
source:
https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
"""
if self.value() is None:
return queryset.all()
else:
return queryset.filter(subscriptions__status=self.value()).distinct()
djstripe.admin.DisputeAdmin
djstripe.admin.DisputeAdmin.list_display
djstripe.admin.DisputeAdmin.list_filter
djstripe.admin.DisputeAdmin.media
property
readonly
djstripe.admin.EventAdmin
djstripe.admin.EventAdmin.list_display
djstripe.admin.EventAdmin.list_filter
djstripe.admin.EventAdmin.media
property
readonly
djstripe.admin.EventAdmin.search_fields
djstripe.admin.FileAdmin
djstripe.admin.FileAdmin.list_display
djstripe.admin.FileAdmin.list_filter
djstripe.admin.FileAdmin.media
property
readonly
djstripe.admin.FileAdmin.search_fields
djstripe.admin.FileLinkAdmin
djstripe.admin.FileLinkAdmin.list_display
djstripe.admin.FileLinkAdmin.list_filter
djstripe.admin.FileLinkAdmin.media
property
readonly
djstripe.admin.IdempotencyKeyAdmin
djstripe.admin.IdempotencyKeyAdmin.list_display
djstripe.admin.IdempotencyKeyAdmin.list_filter
djstripe.admin.IdempotencyKeyAdmin.media
property
readonly
djstripe.admin.IdempotencyKeyAdmin.search_fields
djstripe.admin.InvoiceAdmin
djstripe.admin.InvoiceAdmin.inlines
djstripe.admin.InvoiceAdmin.list_display
djstripe.admin.InvoiceAdmin.list_filter
djstripe.admin.InvoiceAdmin.list_select_related
djstripe.admin.InvoiceAdmin.media
property
readonly
djstripe.admin.InvoiceAdmin.search_fields
djstripe.admin.InvoiceCustomerHasSourceListFilter
djstripe.admin.InvoiceItemInline
A TabularInline for use InvoiceItem.
djstripe.admin.InvoiceItemInline.extra
djstripe.admin.InvoiceItemInline.media
property
readonly
djstripe.admin.InvoiceItemInline.raw_id_fields
djstripe.admin.InvoiceItemInline.readonly_fields
djstripe.admin.InvoiceItemInline.show_change_link
Classes
djstripe.admin.InvoiceItemInline.model
Sometimes you want to add a charge or credit to a customer but only actually charge the customer's card at the end of a regular billing cycle. This is useful for combining several charges to minimize per-transaction fees or having Stripe tabulate your usage-based billing totals.
Stripe documentation: https://stripe.com/docs/api?lang=python#invoiceitems
djstripe.admin.InvoiceItemInline.model.amount
djstripe.admin.InvoiceItemInline.model.currency
djstripe.admin.InvoiceItemInline.model.customer
djstripe.admin.InvoiceItemInline.model.date
djstripe.admin.InvoiceItemInline.model.discountable
djstripe.admin.InvoiceItemInline.model.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.admin.InvoiceItemInline.model.invoice
djstripe.admin.InvoiceItemInline.model.period
djstripe.admin.InvoiceItemInline.model.period_end
djstripe.admin.InvoiceItemInline.model.period_start
djstripe.admin.InvoiceItemInline.model.plan
djstripe.admin.InvoiceItemInline.model.price
djstripe.admin.InvoiceItemInline.model.proration
djstripe.admin.InvoiceItemInline.model.quantity
djstripe.admin.InvoiceItemInline.model.subscription
djstripe.admin.InvoiceItemInline.model.tax_rates
djstripe.admin.InvoiceItemInline.model.unit_amount
djstripe.admin.InvoiceItemInline.model.unit_amount_decimal
djstripe.admin.InvoiceItemInline.model.DoesNotExist
djstripe.admin.InvoiceItemInline.model.MultipleObjectsReturned
djstripe.admin.InvoiceItemInline.model.stripe_class
djstripe.admin.InvoiceItemInline.model.__str__(self)
special
Source code in djstripe/admin.py
def __str__(self):
return self.description
djstripe.admin.InvoiceItemInline.model.api_retrieve(self, *args, **kwargs)
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string :param stripe_account: The optional connected account for which this request is being made. :type stripe_account: string
Source code in djstripe/admin.py
def api_retrieve(self, *args, **kwargs):
if "-il_" in self.id:
warnings.warn(
f"Attempting to retrieve InvoiceItem with id={self.id!r}"
" will most likely fail. "
"Run manage.py djstripe_update_invoiceitem_ids if this is a problem."
)
return super().api_retrieve(*args, **kwargs)
djstripe.admin.InvoiceItemInline.model.get_next_by_date(self, *, field=<djstripe.fields.StripeDateTimeField: date>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_next_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_next_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_previous_by_date(self, *, field=<djstripe.fields.StripeDateTimeField: date>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_previous_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_previous_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.InvoiceItemInline.model.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/admin.py
def get_stripe_dashboard_url(self):
return self.invoice.get_stripe_dashboard_url()
djstripe.admin.InvoiceItemInline.model.is_valid_object(data)
classmethod
Returns whether the data is a valid object for the class
Source code in djstripe/admin.py
@classmethod
def is_valid_object(cls, data):
return "object" in data and data["object"] in ("invoiceitem", "line_item")
djstripe.admin.PaymentIntentAdmin
djstripe.admin.PaymentIntentAdmin.list_display
djstripe.admin.PaymentIntentAdmin.list_select_related
djstripe.admin.PaymentIntentAdmin.media
property
readonly
djstripe.admin.PaymentIntentAdmin.search_fields
djstripe.admin.PaymentMethodAdmin
djstripe.admin.PaymentMethodAdmin.list_display
djstripe.admin.PaymentMethodAdmin.list_filter
djstripe.admin.PaymentMethodAdmin.list_select_related
djstripe.admin.PaymentMethodAdmin.media
property
readonly
djstripe.admin.PaymentMethodAdmin.search_fields
djstripe.admin.PlanAdmin
djstripe.admin.PlanAdmin.media
property
readonly
djstripe.admin.PlanAdmin.radio_fields
Methods
djstripe.admin.PlanAdmin.get_readonly_fields(self, request, obj=None)
Return extra readonly_fields.
Source code in djstripe/admin.py
def get_readonly_fields(self, request, obj=None):
"""Return extra readonly_fields."""
readonly_fields = super().get_readonly_fields(request, obj)
if obj:
readonly_fields += (
"amount",
"currency",
"interval",
"interval_count",
"trial_period_days",
)
return readonly_fields
djstripe.admin.PriceAdmin
djstripe.admin.PriceAdmin.list_display
djstripe.admin.PriceAdmin.list_filter
djstripe.admin.PriceAdmin.media
property
readonly
djstripe.admin.PriceAdmin.radio_fields
djstripe.admin.PriceAdmin.raw_id_fields
djstripe.admin.PriceAdmin.search_fields
djstripe.admin.ProductAdmin
djstripe.admin.ProductAdmin.list_display
djstripe.admin.ProductAdmin.list_filter
djstripe.admin.ProductAdmin.media
property
readonly
djstripe.admin.ProductAdmin.search_fields
djstripe.admin.ReadOnlyMixin
djstripe.admin.ReadOnlyMixin.has_add_permission(self, request)
Source code in djstripe/admin.py
def has_add_permission(self, request):
return False
djstripe.admin.ReadOnlyMixin.has_change_permission(self, request, obj=None)
Source code in djstripe/admin.py
def has_change_permission(self, request, obj=None):
return False
djstripe.admin.RefundAdmin
djstripe.admin.RefundAdmin.list_display
djstripe.admin.RefundAdmin.list_filter
djstripe.admin.RefundAdmin.media
property
readonly
djstripe.admin.RefundAdmin.search_fields
djstripe.admin.SessionAdmin
djstripe.admin.SessionAdmin.list_display
djstripe.admin.SessionAdmin.list_filter
djstripe.admin.SessionAdmin.media
property
readonly
djstripe.admin.SessionAdmin.search_fields
djstripe.admin.SetupIntentAdmin
djstripe.admin.SetupIntentAdmin.list_display
djstripe.admin.SetupIntentAdmin.list_filter
djstripe.admin.SetupIntentAdmin.list_select_related
djstripe.admin.SetupIntentAdmin.media
property
readonly
djstripe.admin.SetupIntentAdmin.search_fields
djstripe.admin.SourceAdmin
djstripe.admin.SourceAdmin.list_display
djstripe.admin.SourceAdmin.list_filter
djstripe.admin.SourceAdmin.list_select_related
djstripe.admin.SourceAdmin.media
property
readonly
djstripe.admin.StripeModelAdmin
Base class for all StripeModel-based model admins
djstripe.admin.StripeModelAdmin.change_form_template
djstripe.admin.StripeModelAdmin.media
property
readonly
Methods
djstripe.admin.StripeModelAdmin.__init__(self, *args, **kwargs)
special
Source code in djstripe/admin.py
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.raw_id_fields = get_forward_relation_fields_for_model(self.model)
djstripe.admin.StripeModelAdmin.get_fieldsets(self, request, obj=None)
Hook for specifying fieldsets.
Source code in djstripe/admin.py
def get_fieldsets(self, request, obj=None):
common_fields = ("livemode", "id", "djstripe_owner_account", "created")
# Have to remove the fields from the common set,
# otherwise they'll show up twice.
fields = [f for f in self.get_fields(request, obj) if f not in common_fields]
return (
(None, {"fields": common_fields}),
(self.model.__name__, {"fields": fields}),
)
djstripe.admin.StripeModelAdmin.get_list_display(self, request)
Return a sequence containing the fields to be displayed on the changelist.
Source code in djstripe/admin.py
def get_list_display(self, request):
return (
("__str__", "id", "djstripe_owner_account")
+ self.list_display
+ ("created", "livemode")
)
djstripe.admin.StripeModelAdmin.get_list_filter(self, request)
Return a sequence containing the fields to be displayed as filters in the right sidebar of the changelist page.
Source code in djstripe/admin.py
def get_list_filter(self, request):
return self.list_filter + ("created", "livemode")
djstripe.admin.StripeModelAdmin.get_readonly_fields(self, request, obj=None)
Hook for specifying custom readonly fields.
Source code in djstripe/admin.py
def get_readonly_fields(self, request, obj=None):
return self.readonly_fields + ("id", "djstripe_owner_account", "created")
djstripe.admin.StripeModelAdmin.get_search_fields(self, request)
Return a sequence containing the fields to be searched whenever somebody submits a search query.
Source code in djstripe/admin.py
def get_search_fields(self, request):
return self.search_fields + ("id",)
djstripe.admin.SubscriptionAdmin
djstripe.admin.SubscriptionAdmin.actions
djstripe.admin.SubscriptionAdmin.inlines
djstripe.admin.SubscriptionAdmin.list_display
djstripe.admin.SubscriptionAdmin.list_filter
djstripe.admin.SubscriptionAdmin.list_select_related
djstripe.admin.SubscriptionAdmin.media
property
readonly
djstripe.admin.SubscriptionInline
A TabularInline for use models.Subscription.
djstripe.admin.SubscriptionInline.extra
djstripe.admin.SubscriptionInline.media
property
readonly
djstripe.admin.SubscriptionInline.raw_id_fields
djstripe.admin.SubscriptionInline.readonly_fields
djstripe.admin.SubscriptionInline.show_change_link
Classes
djstripe.admin.SubscriptionInline.model
Subscriptions allow you to charge a customer's card on a recurring basis. A subscription ties a customer to a particular plan you've created.
A subscription still in its trial period is trialing
and moves to active
when the trial period is over.
When payment to renew the subscription fails, the subscription becomes past_due
.
After Stripe has exhausted all payment retry attempts, the subscription ends up
with a status of either canceled
or unpaid
depending on your retry settings.
Note that when a subscription has a status of unpaid
, no subsequent invoices
will be attempted (invoices will be created, but then immediately
automatically closed.
Additionally, updating customer card details will not lead to Stripe retrying the latest invoice.). After receiving updated card details from a customer, you may choose to reopen and pay their closed invoices.
Stripe documentation: https://stripe.com/docs/api?lang=python#subscriptions
djstripe.admin.SubscriptionInline.model.application_fee_percent
djstripe.admin.SubscriptionInline.model.billing_cycle_anchor
djstripe.admin.SubscriptionInline.model.billing_thresholds
djstripe.admin.SubscriptionInline.model.cancel_at
djstripe.admin.SubscriptionInline.model.cancel_at_period_end
djstripe.admin.SubscriptionInline.model.canceled_at
djstripe.admin.SubscriptionInline.model.collection_method
djstripe.admin.SubscriptionInline.model.current_period_end
djstripe.admin.SubscriptionInline.model.current_period_start
djstripe.admin.SubscriptionInline.model.customer
djstripe.admin.SubscriptionInline.model.days_until_due
djstripe.admin.SubscriptionInline.model.default_payment_method
djstripe.admin.SubscriptionInline.model.default_source
djstripe.admin.SubscriptionInline.model.default_tax_rates
djstripe.admin.SubscriptionInline.model.discount
djstripe.admin.SubscriptionInline.model.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.admin.SubscriptionInline.model.ended_at
djstripe.admin.SubscriptionInline.model.latest_invoice
djstripe.admin.SubscriptionInline.model.next_pending_invoice_item_invoice
djstripe.admin.SubscriptionInline.model.objects
djstripe.admin.SubscriptionInline.model.pending_invoice_item_interval
djstripe.admin.SubscriptionInline.model.pending_setup_intent
djstripe.admin.SubscriptionInline.model.pending_update
djstripe.admin.SubscriptionInline.model.plan
djstripe.admin.SubscriptionInline.model.quantity
djstripe.admin.SubscriptionInline.model.schedule
djstripe.admin.SubscriptionInline.model.start_date
djstripe.admin.SubscriptionInline.model.status
djstripe.admin.SubscriptionInline.model.stripe_dashboard_item_name
djstripe.admin.SubscriptionInline.model.trial_end
djstripe.admin.SubscriptionInline.model.trial_start
djstripe.admin.SubscriptionInline.model.DoesNotExist
djstripe.admin.SubscriptionInline.model.MultipleObjectsReturned
djstripe.admin.SubscriptionInline.model.stripe_class
djstripe.admin.SubscriptionInline.model.stripe_class.OBJECT_NAME
djstripe.admin.SubscriptionInline.model.stripe_class.delete_discount(self, **params)
Source code in djstripe/admin.py
def delete_discount(self, **params):
requestor = api_requestor.APIRequestor(
self.api_key,
api_version=self.stripe_version,
account=self.stripe_account,
)
url = self.instance_url() + "/discount"
_, api_key = requestor.request("delete", url, params)
self.refresh_from({"discount": None}, api_key, True)
djstripe.admin.SubscriptionInline.model.__str__(self)
special
Source code in djstripe/admin.py
def __str__(self):
subscriptions_lst = self.customer._get_valid_subscriptions()
products_lst = [
subscription.plan.product.name
for subscription in subscriptions_lst
if subscription and subscription.plan
]
return f"{self.customer} on {' and '.join(products_lst)}"
djstripe.admin.SubscriptionInline.model.cancel(self, at_period_end=True)
Cancels this subscription. If you set the at_period_end parameter to true, the subscription will remain active until the end of the period, at which point it will be canceled and not renewed. By default, the subscription is terminated immediately. In either case, the customer will not be charged again for the subscription. Note, however, that any pending invoice items that you've created will still be charged for at the end of the period unless manually deleted. If you've set the subscription to cancel at period end, any pending prorations will also be left in place and collected at the end of the period, but if the subscription is set to cancel immediately, pending prorations will be removed.
By default, all unpaid invoices for the customer will be closed upon subscription cancellation. We do this in order to prevent unexpected payment retries once the customer has canceled a subscription. However, you can reopen the invoices manually after subscription cancellation to have us proceed with automatic retries, or you could even re-attempt payment yourself on all unpaid invoices before allowing the customer to cancel the subscription at all.
:param at_period_end: A flag that if set to true will delay the cancellation of the subscription until the end of the current period. Default is False. :type at_period_end: boolean
.. important:: If a subscription is canceled during a trial period, the at_period_end
flag will be overridden to False so that the trial ends immediately and the customer's card isn't charged.
Source code in djstripe/admin.py
def cancel(self, at_period_end=djstripe_settings.CANCELLATION_AT_PERIOD_END):
"""
Cancels this subscription. If you set the at_period_end parameter to true,
the subscription will remain active until the end of the period, at which point
it will be canceled and not renewed. By default, the subscription is terminated
immediately. In either case, the customer will not be charged again for
the subscription. Note, however, that any pending invoice items that you've
created will still be charged for at the end of the period unless manually
deleted. If you've set the subscription to cancel at period end,
any pending prorations will also be left in place and collected at the end of
the period, but if the subscription is set to cancel immediately,
pending prorations will be removed.
By default, all unpaid invoices for the customer will be closed upon
subscription cancellation. We do this in order to prevent unexpected payment
retries once the customer has canceled a subscription. However, you can
reopen the invoices manually after subscription cancellation to have us proceed
with automatic retries, or you could even re-attempt payment yourself on all
unpaid invoices before allowing the customer to cancel the
subscription at all.
:param at_period_end: A flag that if set to true will delay the cancellation \
of the subscription until the end of the current period. Default is False.
:type at_period_end: boolean
.. important:: If a subscription is canceled during a trial period, \
the ``at_period_end`` flag will be overridden to False so that the trial ends \
immediately and the customer's card isn't charged.
"""
# If plan has trial days and customer cancels before
# trial period ends, then end subscription now,
# i.e. at_period_end=False
if self.trial_end and self.trial_end > timezone.now():
at_period_end = False
if at_period_end:
stripe_subscription = self._api_update(cancel_at_period_end=True)
else:
try:
stripe_subscription = self._api_delete()
except InvalidRequestError as exc:
if "No such subscription:" in str(exc):
# cancel() works by deleting the subscription. The object still
# exists in Stripe however, and can still be retrieved.
# If the subscription was already canceled (status=canceled),
# that api_retrieve() call will fail with "No such subscription".
# However, this may also happen if the subscription legitimately
# does not exist, in which case the following line will re-raise.
stripe_subscription = self.api_retrieve()
else:
raise
return Subscription.sync_from_stripe_data(stripe_subscription)
djstripe.admin.SubscriptionInline.model.extend(self, delta)
Extends this subscription by the provided delta.
:param delta: The timedelta by which to extend this subscription. :type delta: timedelta
Source code in djstripe/admin.py
def extend(self, delta):
"""
Extends this subscription by the provided delta.
:param delta: The timedelta by which to extend this subscription.
:type delta: timedelta
"""
if delta.total_seconds() < 0:
raise ValueError("delta must be a positive timedelta.")
if self.trial_end is not None and self.trial_end > timezone.now():
period_end = self.trial_end
else:
period_end = self.current_period_end
period_end += delta
return self.update(proration_behavior="none", trial_end=period_end)
djstripe.admin.SubscriptionInline.model.get_collection_method_display(self, *, field=<djstripe.fields.StripeEnumField: collection_method>)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_next_by_current_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_end>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_next_by_current_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_start>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_previous_by_current_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_end>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_previous_by_current_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_start>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionInline.model.is_period_current(self)
Returns True if this subscription's period is current, false otherwise.
Source code in djstripe/admin.py
def is_period_current(self):
"""
Returns True if this subscription's period is current, false otherwise.
"""
return self.current_period_end > timezone.now() or (
self.trial_end and self.trial_end > timezone.now()
)
djstripe.admin.SubscriptionInline.model.is_status_current(self)
Returns True if this subscription's status is current (active or trialing), false otherwise.
Source code in djstripe/admin.py
def is_status_current(self):
"""
Returns True if this subscription's status is current (active or trialing),
false otherwise.
"""
return self.status in ["trialing", "active"]
djstripe.admin.SubscriptionInline.model.is_status_temporarily_current(self)
A status is temporarily current when the subscription is canceled with the
at_period_end
flag.
The subscription is still active, but is technically canceled and we're just
waiting for it to run out.
You could use this method to give customers limited service after they've canceled. For example, a video on demand service could only allow customers to download their libraries and do nothing else when their subscription is temporarily current.
Source code in djstripe/admin.py
def is_status_temporarily_current(self):
"""
A status is temporarily current when the subscription is canceled with the
``at_period_end`` flag.
The subscription is still active, but is technically canceled and we're just
waiting for it to run out.
You could use this method to give customers limited service after they've
canceled. For example, a video on demand service could only allow customers
to download their libraries and do nothing else when their
subscription is temporarily current.
"""
return (
self.canceled_at
and self.cancel_at_period_end
and timezone.now() < self.current_period_end
)
djstripe.admin.SubscriptionInline.model.is_valid(self)
Returns True if this subscription's status and period are current, false otherwise.
Source code in djstripe/admin.py
def is_valid(self):
"""
Returns True if this subscription's status and period are current,
false otherwise.
"""
if not self.is_status_current():
return False
if not self.is_period_current():
return False
return True
djstripe.admin.SubscriptionInline.model.reactivate(self)
Reactivates this subscription.
If a customer's subscription is canceled with at_period_end
set to True and
it has not yet reached the end of the billing period, it can be reactivated.
Subscriptions canceled immediately cannot be reactivated.
(Source: https://stripe.com/docs/billing/subscriptions/cancel)
.. warning:: Reactivating a fully canceled Subscription will fail silently. Be sure to check the returned Subscription's status.
Source code in djstripe/admin.py
def reactivate(self):
"""
Reactivates this subscription.
If a customer's subscription is canceled with ``at_period_end`` set to True and
it has not yet reached the end of the billing period, it can be reactivated.
Subscriptions canceled immediately cannot be reactivated.
(Source: https://stripe.com/docs/billing/subscriptions/cancel)
.. warning:: Reactivating a fully canceled Subscription will fail silently. \
Be sure to check the returned Subscription's status.
"""
stripe_subscription = self.api_retrieve()
stripe_subscription.plan = self.plan.id
stripe_subscription.cancel_at_period_end = False
return Subscription.sync_from_stripe_data(stripe_subscription.save())
djstripe.admin.SubscriptionInline.model.update(self, plan=None, prorate=None, **kwargs)
See Customer.subscribe() <#djstripe.models.Customer.subscribe>
__
:param plan: The plan to which to subscribe the customer. :type plan: Plan or string (plan ID)
.. note:: The default value for prorate
is the DJSTRIPE_PRORATION_POLICY setting.
.. important:: Updating a subscription by changing the plan or quantity creates a new Subscription
in Stripe (and dj-stripe).
Source code in djstripe/admin.py
def update(
self,
plan: Union[StripeModel, str] = None,
prorate: bool = None,
**kwargs,
):
"""
See `Customer.subscribe() <#djstripe.models.Customer.subscribe>`__
:param plan: The plan to which to subscribe the customer.
:type plan: Plan or string (plan ID)
.. note:: The default value for ``prorate`` is the DJSTRIPE_PRORATION_POLICY \
setting.
.. important:: Updating a subscription by changing the plan or quantity \
creates a new ``Subscription`` in \
Stripe (and dj-stripe).
"""
# Convert Plan to id
if plan is not None and isinstance(plan, StripeModel):
plan = plan.id
if "proration_behavior" not in kwargs:
if prorate is not None:
warnings.warn(
"The `prorate` parameter to Subscription.update() is deprecated "
"by Stripe. Use `proration_behavior` instead.\n"
"Read more: "
"https://stripe.com/docs/billing/subscriptions/prorations"
)
else:
prorate = djstripe_settings.PRORATION_POLICY
if prorate:
kwargs.setdefault("proration_behavior", "create_prorations")
else:
kwargs.setdefault("proration_behavior", "none")
stripe_subscription = self._api_update(plan=plan, **kwargs)
return Subscription.sync_from_stripe_data(stripe_subscription)
djstripe.admin.SubscriptionItemInline
A TabularInline for use models.Subscription.
djstripe.admin.SubscriptionItemInline.extra
djstripe.admin.SubscriptionItemInline.media
property
readonly
djstripe.admin.SubscriptionItemInline.raw_id_fields
djstripe.admin.SubscriptionItemInline.readonly_fields
djstripe.admin.SubscriptionItemInline.show_change_link
Classes
djstripe.admin.SubscriptionItemInline.model
Subscription items allow you to create customer subscriptions with more than one plan, making it easy to represent complex billing relationships.
Stripe documentation: https://stripe.com/docs/api#subscription_items
djstripe.admin.SubscriptionItemInline.model.billing_thresholds
djstripe.admin.SubscriptionItemInline.model.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.admin.SubscriptionItemInline.model.plan
djstripe.admin.SubscriptionItemInline.model.price
djstripe.admin.SubscriptionItemInline.model.quantity
djstripe.admin.SubscriptionItemInline.model.subscription
djstripe.admin.SubscriptionItemInline.model.tax_rates
djstripe.admin.SubscriptionItemInline.model.DoesNotExist
djstripe.admin.SubscriptionItemInline.model.MultipleObjectsReturned
djstripe.admin.SubscriptionItemInline.model.stripe_class
djstripe.admin.SubscriptionItemInline.model.stripe_class.OBJECT_NAME
djstripe.admin.SubscriptionItemInline.model.stripe_class.create_usage_record(id, **params)
classmethod
Source code in djstripe/admin.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.admin.SubscriptionItemInline.model.stripe_class.list_usage_record_summaries(id, **params)
classmethod
Source code in djstripe/admin.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.admin.SubscriptionItemInline.model.stripe_class.usage_record_summaries(self, **params)
usage_record_summaries is deprecated, use SubscriptionItem.list_usage_record_summaries instead.
Source code in djstripe/admin.py
def usage_record_summaries(self, **params):
"""usage_record_summaries is deprecated, use SubscriptionItem.list_usage_record_summaries instead."""
return self.request(
"get", self.instance_url() + "/usage_record_summaries", params
)
djstripe.admin.SubscriptionItemInline.model.stripe_class.usage_record_summarys_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/admin.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.admin.SubscriptionItemInline.model.stripe_class.usage_record_summarys_url(id, nested_id=None)
classmethod
Source code in djstripe/admin.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.admin.SubscriptionItemInline.model.stripe_class.usage_records_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/admin.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.admin.SubscriptionItemInline.model.stripe_class.usage_records_url(id, nested_id=None)
classmethod
Source code in djstripe/admin.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.admin.SubscriptionItemInline.model.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionItemInline.model.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionItemInline.model.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.SubscriptionItemInline.model.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.TaxIdInline
A TabularInline for use models.Subscription.
djstripe.admin.TaxIdInline.extra
djstripe.admin.TaxIdInline.max_num
djstripe.admin.TaxIdInline.media
property
readonly
djstripe.admin.TaxIdInline.readonly_fields
djstripe.admin.TaxIdInline.show_change_link
Classes
djstripe.admin.TaxIdInline.model
Add one or multiple tax IDs to a customer. A customer's tax IDs are displayed on invoices and credit notes issued for the customer.
Stripe documentation: https://stripe.com/docs/api/customer_tax_ids
djstripe.admin.TaxIdInline.model.country
djstripe.admin.TaxIdInline.model.customer
djstripe.admin.TaxIdInline.model.description
djstripe.admin.TaxIdInline.model.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.admin.TaxIdInline.model.metadata
djstripe.admin.TaxIdInline.model.type
djstripe.admin.TaxIdInline.model.value
djstripe.admin.TaxIdInline.model.verification
djstripe.admin.TaxIdInline.model.DoesNotExist
djstripe.admin.TaxIdInline.model.MultipleObjectsReturned
djstripe.admin.TaxIdInline.model.stripe_class
djstripe.admin.TaxIdInline.model.stripe_class.OBJECT_NAME
djstripe.admin.TaxIdInline.model.stripe_class.instance_url(self)
Source code in djstripe/admin.py
def instance_url(self):
token = util.utf8(self.id)
customer = util.utf8(self.customer)
base = Customer.class_url()
cust_extn = quote_plus(customer)
extn = quote_plus(token)
return "%s/%s/tax_ids/%s" % (base, cust_extn, extn)
djstripe.admin.TaxIdInline.model.stripe_class.retrieve(id, api_key=None, **params)
classmethod
Source code in djstripe/admin.py
@classmethod
def retrieve(cls, id, api_key=None, **params):
raise NotImplementedError(
"Can't retrieve a tax id without a customer ID. Use customer.retrieve_tax_id('tax_id')"
)
djstripe.admin.TaxIdInline.model.__str__(self)
special
Source code in djstripe/admin.py
def __str__(self):
return f"{enums.TaxIdType.humanize(self.type)} {self.value} ({self.verification.get('status')})"
djstripe.admin.TaxIdInline.model.api_list(api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', **kwargs)
classmethod
Call the stripe API's list operation for this model. :param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string See Stripe documentation for accepted kwargs for each object. :returns: an iterator over all items in the query
Source code in djstripe/admin.py
@classmethod
def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
"""
Call the stripe API's list operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
See Stripe documentation for accepted kwargs for each object.
:returns: an iterator over all items in the query
"""
return stripe.Customer.list_tax_ids(
api_key=api_key, **kwargs
).auto_paging_iter()
djstripe.admin.TaxIdInline.model.api_retrieve(self, api_key=None, stripe_account=None)
Call the stripe API's retrieve operation for this model. :param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string :param stripe_account: The optional connected account for which this request is being made. :type stripe_account: string
Source code in djstripe/admin.py
def api_retrieve(self, api_key=None, stripe_account=None):
"""
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
:param stripe_account: The optional connected account \
for which this request is being made.
:type stripe_account: string
"""
nested_id = self.id
id = self.customer.id
# Prefer passed in stripe_account if set.
if not stripe_account:
stripe_account = self._get_stripe_account_id(api_key)
return stripe.Customer.retrieve_tax_id(
id=id,
nested_id=nested_id,
api_key=api_key or self.default_api_key,
expand=self.expand_fields,
stripe_account=stripe_account,
)
djstripe.admin.TaxIdInline.model.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.TaxIdInline.model.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.TaxIdInline.model.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.TaxIdInline.model.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.TaxIdInline.model.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/admin.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.admin.TaxRateAdmin
djstripe.admin.TaxRateAdmin.list_display
djstripe.admin.TaxRateAdmin.list_filter
djstripe.admin.TaxRateAdmin.media
property
readonly
djstripe.admin.TransferAdmin
djstripe.admin.TransferAdmin.list_display
djstripe.admin.TransferAdmin.media
property
readonly
djstripe.admin.TransferReversalAdmin
djstripe.admin.TransferReversalAdmin.list_display
djstripe.admin.TransferReversalAdmin.media
property
readonly
djstripe.admin.UsageRecordAdmin
djstripe.admin.UsageRecordAdmin.list_display
djstripe.admin.UsageRecordAdmin.media
property
readonly
djstripe.admin.UsageRecordSummaryAdmin
djstripe.admin.UsageRecordSummaryAdmin.list_display
djstripe.admin.UsageRecordSummaryAdmin.media
property
readonly
djstripe.admin.WebhookEventTriggerAdmin
djstripe.admin.WebhookEventTriggerAdmin.list_display
djstripe.admin.WebhookEventTriggerAdmin.list_filter
djstripe.admin.WebhookEventTriggerAdmin.list_select_related
djstripe.admin.WebhookEventTriggerAdmin.media
property
readonly
djstripe.admin.WebhookEventTriggerAdmin.raw_id_fields
djstripe.admin.WebhookEventTriggerAdmin.reprocess(self, request, queryset)
Source code in djstripe/admin.py
def reprocess(self, request, queryset):
for trigger in queryset:
if not trigger.valid:
self.message_user(request, "Skipped invalid trigger {}".format(trigger))
continue
trigger.process()
Functions
djstripe.admin.admin_display_for_field_override()
Source code in djstripe/admin.py
def admin_display_for_field_override():
admin.utils.display_for_field = custom_display_for_JSONfield
admin.helpers.display_for_field = custom_display_for_JSONfield
djstripe.admin.custom_display_for_JSONfield(value, field, empty_value_display)
Overriding display_for_field to correctly render JSONField READonly fields in django-admin. Relevant when DJSTRIPE_USE_NATIVE_JSONFIELD is False Note: This does not handle invalid JSON. That should be handled by the JSONField itself
Source code in djstripe/admin.py
def custom_display_for_JSONfield(value, field, empty_value_display):
"""
Overriding display_for_field to correctly render JSONField READonly fields
in django-admin. Relevant when DJSTRIPE_USE_NATIVE_JSONFIELD is False
Note: This does not handle invalid JSON. That should be handled by the JSONField itself
"""
# we manually JSON serialise in case field is from jsonfield module
if isinstance(field, JSONField) and value:
try:
return json.dumps(value)
except TypeError:
return display_for_value(value, empty_value_display)
return display_for_field(value, field, empty_value_display)
djstripe.admin.get_forward_relation_fields_for_model(model)
Return an iterable of the field names that are forward relations, I.E ManyToManyField, OneToOneField, and ForeignKey.
Useful for perhaps ensuring the admin is always using raw ID fields for newly added forward relation fields.
Source code in djstripe/admin.py
def get_forward_relation_fields_for_model(model):
"""Return an iterable of the field names that are forward relations,
I.E ManyToManyField, OneToOneField, and ForeignKey.
Useful for perhaps ensuring the admin is always using raw ID fields for
newly added forward relation fields.
"""
return [
field.name
for field in model._meta.get_fields()
# Get only relation fields
if field.is_relation
# Exclude auto relation fields, like reverse one to one.
and not field.auto_created
# We only want forward relations.
and any((field.many_to_many, field.one_to_one, field.many_to_one))
]
djstripe.apps
dj-stripe - Django + Stripe Made Easy
djstripe.apps.__version__
special
Classes
djstripe.apps.DjstripeAppConfig
An AppConfig for dj-stripe which loads system checks and event handlers once Django is ready.
djstripe.apps.DjstripeAppConfig.default_auto_field
djstripe.apps.DjstripeAppConfig.name
Methods
djstripe.apps.DjstripeAppConfig.ready(self)
Override this method in subclasses to run code when Django starts.
Source code in djstripe/apps.py
def ready(self):
import stripe
from . import ( # noqa: Register the checks and event handlers
checks,
event_handlers,
)
# Set app info
# https://stripe.com/docs/building-plugins#setappinfo
stripe.set_app_info(
"dj-stripe",
version=__version__,
url="https://github.com/dj-stripe/dj-stripe",
)
djstripe.checks
dj-stripe System Checks
Functions
djstripe.checks.check_djstripe_settings_foreign_key_to_field(app_configs=None, **kwargs)
Check that DJSTRIPE_FOREIGN_KEY_TO_FIELD is set to a valid value.
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_djstripe_settings_foreign_key_to_field(app_configs=None, **kwargs):
"""
Check that DJSTRIPE_FOREIGN_KEY_TO_FIELD is set to a valid value.
"""
from django.conf import settings
setting_name = "DJSTRIPE_FOREIGN_KEY_TO_FIELD"
hint = (
f'Set {setting_name} to "id" if this is a new installation, '
f'otherwise set it to "djstripe_id".'
)
messages = []
if not hasattr(settings, setting_name):
messages.append(
checks.Error(
"%s is not set." % (setting_name),
hint=hint,
id="djstripe.E002",
)
)
elif getattr(settings, setting_name) not in ("id", "djstripe_id"):
messages.append(
checks.Error(
"%r is not a valid value for %s."
% (getattr(settings, setting_name), setting_name),
hint=hint,
id="djstripe.E003",
)
)
return messages
djstripe.checks.check_native_jsonfield_postgres_engine(app_configs=None, **kwargs)
Check that the DJSTRIPE_USE_NATIVE_JSONFIELD isn't set unless Postgres is in use. Only used on Django < 3.1.
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_native_jsonfield_postgres_engine(app_configs=None, **kwargs):
"""
Check that the DJSTRIPE_USE_NATIVE_JSONFIELD isn't set unless Postgres is in use.
Only used on Django < 3.1.
"""
from .settings import djstripe_settings
messages = []
error_msg = (
"DJSTRIPE_USE_NATIVE_JSONFIELD is not compatible with engine {engine} "
"for database {name}"
)
# This error check is skipped on Django 3.1+, because the native JSONField
# will be used, which is compatible with mysql and sqlite.
# https://docs.djangoproject.com/en/dev/releases/3.1/#postgresql-jsonfield
if django.VERSION >= (3, 1):
return messages
if djstripe_settings.USE_NATIVE_JSONFIELD:
for db_name, db_config in settings.DATABASES.items():
# Hi there.
# You may be reading this because you are using Postgres, but
# dj-stripe is not detecting that correctly. For example, maybe you
# are using multiple databases with different engines, or you have
# your own backend. As long as you are certain you can support jsonb,
# you can use the SILENCED_SYSTEM_CHECKS setting to ignore this check.
engine = db_config.get("ENGINE", "")
if "postgresql" not in engine and "postgis" not in engine:
messages.append(
checks.Critical(
error_msg.format(name=repr(db_name), engine=repr(engine)),
hint="Switch to Postgres, or unset "
"DJSTRIPE_USE_NATIVE_JSONFIELD",
id="djstripe.C005",
)
)
return messages
djstripe.checks.check_native_jsonfield_set_on_recent_django_versions(app_configs=None, **kwargs)
Check that DJSTRIPE_USE_NATIVE_JSONFIELD is set on Django > 3.1.
This is only a suggestion, as existing installations need a migration path.
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_native_jsonfield_set_on_recent_django_versions(app_configs=None, **kwargs):
"""
Check that DJSTRIPE_USE_NATIVE_JSONFIELD is set on Django > 3.1.
This is only a suggestion, as existing installations need a migration path.
"""
messages = []
# This error check is skipped on Django < 3.1+, because the native JSONField
# was not available outside of Postgres engines then.
if django.VERSION < (3, 1):
return messages
# NOTE: Not using app_settings.USE_NATIVE_JSONFIELD.
# Only display this warning if the setting is unset.
if not hasattr(settings, "DJSTRIPE_USE_NATIVE_JSONFIELD"):
# TODO: Give more details on the migration path
messages.append(
checks.Warning(
"DJSTRIPE_USE_NATIVE_JSONFIELD is not set.",
hint=(
"On Django 3.1+, setting DJSTRIPE_USE_NATIVE_JSONFIELD = True is "
"recommended.\nPre-existing dj-stripe installations may require a "
"migration, in which case you may want to set it to False."
),
id="djstripe.W005",
)
)
return messages
djstripe.checks.check_stripe_api_host(app_configs=None, **kwargs)
Check that STRIPE_API_HOST is not being used in production.
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_stripe_api_host(app_configs=None, **kwargs):
"""
Check that STRIPE_API_HOST is not being used in production.
"""
from django.conf import settings
messages = []
if not settings.DEBUG and hasattr(settings, "STRIPE_API_HOST"):
messages.append(
checks.Warning(
"STRIPE_API_HOST should not be set in production! "
"This is most likely unintended.",
hint="Remove STRIPE_API_HOST from your Django settings.",
id="djstripe.W002",
)
)
return messages
djstripe.checks.check_stripe_api_key(app_configs=None, **kwargs)
Check the user has configured API live/test keys correctly.
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_stripe_api_key(app_configs=None, **kwargs):
"""Check the user has configured API live/test keys correctly."""
from .settings import djstripe_settings
messages = []
if not djstripe_settings.STRIPE_SECRET_KEY:
msg = "Could not find a Stripe API key."
hint = "Add STRIPE_TEST_SECRET_KEY and STRIPE_LIVE_SECRET_KEY to your settings."
messages.append(checks.Critical(msg, hint=hint, id="djstripe.C001"))
elif djstripe_settings.STRIPE_LIVE_MODE:
if not djstripe_settings.LIVE_API_KEY.startswith(("sk_live_", "rk_live_")):
msg = "Bad Stripe live API key."
hint = 'STRIPE_LIVE_SECRET_KEY should start with "sk_live_"'
messages.append(checks.Critical(msg, hint=hint, id="djstripe.C002"))
else:
if not djstripe_settings.TEST_API_KEY.startswith(("sk_test_", "rk_test_")):
msg = "Bad Stripe test API key."
hint = 'STRIPE_TEST_SECRET_KEY should start with "sk_test_"'
messages.append(checks.Critical(msg, hint=hint, id="djstripe.C003"))
return messages
djstripe.checks.check_stripe_api_version(app_configs=None, **kwargs)
Check the user has configured API version correctly.
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_stripe_api_version(app_configs=None, **kwargs):
"""Check the user has configured API version correctly."""
from .settings import djstripe_settings
messages = []
default_version = djstripe_settings.DEFAULT_STRIPE_API_VERSION
version = djstripe_settings.STRIPE_API_VERSION
if not validate_stripe_api_version(version):
msg = "Invalid Stripe API version: {}".format(version)
hint = "STRIPE_API_VERSION should be formatted as: YYYY-MM-DD"
messages.append(checks.Critical(msg, hint=hint, id="djstripe.C004"))
if version != default_version:
msg = (
"The Stripe API version has a non-default value of '{}'. "
"Non-default versions are not explicitly supported, and may "
"cause compatibility issues.".format(version)
)
hint = "Use the dj-stripe default for Stripe API version: {}".format(
default_version
)
messages.append(checks.Warning(msg, hint=hint, id="djstripe.W001"))
return messages
djstripe.checks.check_subscriber_key_length(app_configs=None, **kwargs)
Check that DJSTRIPE_SUBSCRIBER_CUSTOMER_KEY fits in metadata.
Docs: https://stripe.com/docs/api#metadata
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_subscriber_key_length(app_configs=None, **kwargs):
"""
Check that DJSTRIPE_SUBSCRIBER_CUSTOMER_KEY fits in metadata.
Docs: https://stripe.com/docs/api#metadata
"""
from .settings import djstripe_settings
messages = []
key = djstripe_settings.SUBSCRIBER_CUSTOMER_KEY
key_size = len(str(key))
if key and key_size > 40:
messages.append(
checks.Error(
"DJSTRIPE_SUBSCRIBER_CUSTOMER_KEY must be no more than "
"40 characters long",
hint="Current value: %r (%i characters)" % (key, key_size),
id="djstripe.E001",
)
)
return messages
djstripe.checks.check_webhook_secret(app_configs=None, **kwargs)
Check that DJSTRIPE_WEBHOOK_SECRET looks correct
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_webhook_secret(app_configs=None, **kwargs):
"""
Check that DJSTRIPE_WEBHOOK_SECRET looks correct
"""
from .settings import djstripe_settings
messages = []
secret = djstripe_settings.WEBHOOK_SECRET
if secret and not secret.startswith("whsec_"):
messages.append(
checks.Warning(
"DJSTRIPE_WEBHOOK_SECRET does not look valid",
hint="It should start with whsec_...",
id="djstripe.W003",
)
)
return messages
djstripe.checks.check_webhook_validation(app_configs=None, **kwargs)
Check that DJSTRIPE_WEBHOOK_VALIDATION is valid
Source code in djstripe/checks.py
@checks.register("djstripe")
def check_webhook_validation(app_configs=None, **kwargs):
"""
Check that DJSTRIPE_WEBHOOK_VALIDATION is valid
"""
from .settings import djstripe_settings
messages = []
validation_options = ("verify_signature", "retrieve_event")
if djstripe_settings.WEBHOOK_VALIDATION is None:
messages.append(
checks.Warning(
"Webhook validation is disabled, this is a security risk if the "
"webhook view is enabled",
hint="Set DJSTRIPE_WEBHOOK_VALIDATION to one of {}".format(
", ".join(validation_options)
),
id="djstripe.W004",
)
)
elif djstripe_settings.WEBHOOK_VALIDATION == "verify_signature":
if not djstripe_settings.WEBHOOK_SECRET:
messages.append(
checks.Critical(
"DJSTRIPE_WEBHOOK_VALIDATION='verify_signature' "
"but DJSTRIPE_WEBHOOK_SECRET is not set",
hint="Set DJSTRIPE_WEBHOOK_SECRET or set "
"DJSTRIPE_WEBHOOK_VALIDATION='retrieve_event'",
id="djstripe.C006",
)
)
elif djstripe_settings.WEBHOOK_VALIDATION not in validation_options:
messages.append(
checks.Critical(
"DJSTRIPE_WEBHOOK_VALIDATION is invalid",
hint="Set DJSTRIPE_WEBHOOK_VALIDATION to one of {} or None".format(
", ".join(validation_options)
),
id="djstripe.C007",
)
)
return messages
djstripe.checks.validate_stripe_api_version(version)
Check the API version is formatted correctly for Stripe.
The expected format is an iso8601 date: YYYY-MM-DD
:param version: The version to set for the Stripe API.
:type version: str
:returns bool: Whether the version is formatted correctly.
Source code in djstripe/checks.py
def validate_stripe_api_version(version):
"""
Check the API version is formatted correctly for Stripe.
The expected format is an iso8601 date: `YYYY-MM-DD`
:param version: The version to set for the Stripe API.
:type version: ``str``
:returns bool: Whether the version is formatted correctly.
"""
return date_re.match(version)
djstripe.context_managers
dj-stripe Context Managers
Functions
djstripe.context_managers.stripe_temporary_api_version(version, validate=True)
Temporarily replace the global api_version used in stripe API calls with the given value.
The original value is restored as soon as context exits.
Source code in djstripe/context_managers.py
@contextmanager
def stripe_temporary_api_version(version, validate=True):
"""
Temporarily replace the global api_version used in stripe API calls with
the given value.
The original value is restored as soon as context exits.
"""
old_version = djstripe_settings.STRIPE_API_VERSION
try:
djstripe_settings.set_stripe_api_version(version, validate=validate)
yield
finally:
# Validation is bypassed since we're restoring a previous value.
djstripe_settings.set_stripe_api_version(old_version, validate=False)
djstripe.enums
Classes
djstripe.enums.APIKeyType
API Key Types (internal model only)
djstripe.enums.APIKeyType.publishable
djstripe.enums.APIKeyType.restricted
djstripe.enums.APIKeyType.secret
djstripe.enums.APIKeyType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.AccountType
djstripe.enums.AccountType.custom
djstripe.enums.AccountType.express
djstripe.enums.AccountType.standard
djstripe.enums.AccountType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.ApiErrorCode
Charge failure error codes.
https://stripe.com/docs/error-codes
djstripe.enums.ApiErrorCode.account_already_exists
djstripe.enums.ApiErrorCode.account_country_invalid_address
djstripe.enums.ApiErrorCode.account_invalid
djstripe.enums.ApiErrorCode.account_number_invalid
djstripe.enums.ApiErrorCode.alipay_upgrade_required
djstripe.enums.ApiErrorCode.amount_too_large
djstripe.enums.ApiErrorCode.amount_too_small
djstripe.enums.ApiErrorCode.api_key_expired
djstripe.enums.ApiErrorCode.balance_insufficient
djstripe.enums.ApiErrorCode.bank_account_exists
djstripe.enums.ApiErrorCode.bank_account_unusable
djstripe.enums.ApiErrorCode.bank_account_unverified
djstripe.enums.ApiErrorCode.bitcoin_upgrade_required
djstripe.enums.ApiErrorCode.card_declined
djstripe.enums.ApiErrorCode.charge_already_captured
djstripe.enums.ApiErrorCode.charge_already_refunded
djstripe.enums.ApiErrorCode.charge_disputed
djstripe.enums.ApiErrorCode.charge_exceeds_source_limit
djstripe.enums.ApiErrorCode.charge_expired_for_capture
djstripe.enums.ApiErrorCode.country_unsupported
djstripe.enums.ApiErrorCode.coupon_expired
djstripe.enums.ApiErrorCode.customer_max_subscriptions
djstripe.enums.ApiErrorCode.email_invalid
djstripe.enums.ApiErrorCode.expired_card
djstripe.enums.ApiErrorCode.idempotency_key_in_use
djstripe.enums.ApiErrorCode.incorrect_address
djstripe.enums.ApiErrorCode.incorrect_cvc
djstripe.enums.ApiErrorCode.incorrect_number
djstripe.enums.ApiErrorCode.incorrect_zip
djstripe.enums.ApiErrorCode.instant_payouts_unsupported
djstripe.enums.ApiErrorCode.invalid_card_type
djstripe.enums.ApiErrorCode.invalid_charge_amount
djstripe.enums.ApiErrorCode.invalid_cvc
djstripe.enums.ApiErrorCode.invalid_expiry_month
djstripe.enums.ApiErrorCode.invalid_expiry_year
djstripe.enums.ApiErrorCode.invalid_number
djstripe.enums.ApiErrorCode.invalid_source_usage
djstripe.enums.ApiErrorCode.invalid_swipe_data
djstripe.enums.ApiErrorCode.invoice_no_customer_line_items
djstripe.enums.ApiErrorCode.invoice_no_subscription_line_items
djstripe.enums.ApiErrorCode.invoice_not_editable
djstripe.enums.ApiErrorCode.invoice_upcoming_none
djstripe.enums.ApiErrorCode.livemode_mismatch
djstripe.enums.ApiErrorCode.missing
djstripe.enums.ApiErrorCode.not_allowed_on_standard_account
djstripe.enums.ApiErrorCode.order_creation_failed
djstripe.enums.ApiErrorCode.order_required_settings
djstripe.enums.ApiErrorCode.order_status_invalid
djstripe.enums.ApiErrorCode.order_upstream_timeout
djstripe.enums.ApiErrorCode.out_of_inventory
djstripe.enums.ApiErrorCode.parameter_invalid_empty
djstripe.enums.ApiErrorCode.parameter_invalid_integer
djstripe.enums.ApiErrorCode.parameter_invalid_string_blank
djstripe.enums.ApiErrorCode.parameter_invalid_string_empty
djstripe.enums.ApiErrorCode.parameter_missing
djstripe.enums.ApiErrorCode.parameter_unknown
djstripe.enums.ApiErrorCode.parameters_exclusive
djstripe.enums.ApiErrorCode.payment_intent_authentication_failure
djstripe.enums.ApiErrorCode.payment_intent_incompatible_payment_method
djstripe.enums.ApiErrorCode.payment_intent_invalid_parameter
djstripe.enums.ApiErrorCode.payment_intent_payment_attempt_failed
djstripe.enums.ApiErrorCode.payment_intent_unexpected_state
djstripe.enums.ApiErrorCode.payment_method_unactivated
djstripe.enums.ApiErrorCode.payment_method_unexpected_state
djstripe.enums.ApiErrorCode.payouts_not_allowed
djstripe.enums.ApiErrorCode.platform_api_key_expired
djstripe.enums.ApiErrorCode.postal_code_invalid
djstripe.enums.ApiErrorCode.processing_error
djstripe.enums.ApiErrorCode.product_inactive
djstripe.enums.ApiErrorCode.rate_limit
djstripe.enums.ApiErrorCode.resource_already_exists
djstripe.enums.ApiErrorCode.resource_missing
djstripe.enums.ApiErrorCode.routing_number_invalid
djstripe.enums.ApiErrorCode.secret_key_required
djstripe.enums.ApiErrorCode.sepa_unsupported_account
djstripe.enums.ApiErrorCode.shipping_calculation_failed
djstripe.enums.ApiErrorCode.sku_inactive
djstripe.enums.ApiErrorCode.state_unsupported
djstripe.enums.ApiErrorCode.tax_id_invalid
djstripe.enums.ApiErrorCode.taxes_calculation_failed
djstripe.enums.ApiErrorCode.testmode_charges_only
djstripe.enums.ApiErrorCode.tls_version_unsupported
djstripe.enums.ApiErrorCode.token_already_used
djstripe.enums.ApiErrorCode.token_in_use
djstripe.enums.ApiErrorCode.transfers_not_allowed
djstripe.enums.ApiErrorCode.upstream_order_creation_failed
djstripe.enums.ApiErrorCode.url_invalid
djstripe.enums.ApiErrorCode.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.BalanceTransactionReportingCategory
https://stripe.com/docs/reports/reporting-categories
djstripe.enums.BalanceTransactionReportingCategory.advance
djstripe.enums.BalanceTransactionReportingCategory.advance_funding
djstripe.enums.BalanceTransactionReportingCategory.anticipation_repayment
djstripe.enums.BalanceTransactionReportingCategory.charge
djstripe.enums.BalanceTransactionReportingCategory.charge_failure
djstripe.enums.BalanceTransactionReportingCategory.connect_collection_transfer
djstripe.enums.BalanceTransactionReportingCategory.connect_reserved_funds
djstripe.enums.BalanceTransactionReportingCategory.dispute
djstripe.enums.BalanceTransactionReportingCategory.dispute_reversal
djstripe.enums.BalanceTransactionReportingCategory.fee
djstripe.enums.BalanceTransactionReportingCategory.issuing_authorization_hold
djstripe.enums.BalanceTransactionReportingCategory.issuing_authorization_release
djstripe.enums.BalanceTransactionReportingCategory.issuing_dispute
djstripe.enums.BalanceTransactionReportingCategory.issuing_transaction
djstripe.enums.BalanceTransactionReportingCategory.other_adjustment
djstripe.enums.BalanceTransactionReportingCategory.partial_capture_reversal
djstripe.enums.BalanceTransactionReportingCategory.payout
djstripe.enums.BalanceTransactionReportingCategory.payout_reversal
djstripe.enums.BalanceTransactionReportingCategory.platform_earning
djstripe.enums.BalanceTransactionReportingCategory.platform_earning_refund
djstripe.enums.BalanceTransactionReportingCategory.refund
djstripe.enums.BalanceTransactionReportingCategory.refund_failure
djstripe.enums.BalanceTransactionReportingCategory.risk_reserved_funds
djstripe.enums.BalanceTransactionReportingCategory.tax
djstripe.enums.BalanceTransactionReportingCategory.topup
djstripe.enums.BalanceTransactionReportingCategory.topup_reversal
djstripe.enums.BalanceTransactionReportingCategory.transfer
djstripe.enums.BalanceTransactionReportingCategory.transfer_reversal
djstripe.enums.BalanceTransactionReportingCategory.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.BalanceTransactionStatus
djstripe.enums.BalanceTransactionStatus.available
djstripe.enums.BalanceTransactionStatus.pending
djstripe.enums.BalanceTransactionStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.BalanceTransactionType
djstripe.enums.BalanceTransactionType.adjustment
djstripe.enums.BalanceTransactionType.advance
djstripe.enums.BalanceTransactionType.advance_funding
djstripe.enums.BalanceTransactionType.anticipation_repayment
djstripe.enums.BalanceTransactionType.application_fee
djstripe.enums.BalanceTransactionType.application_fee_refund
djstripe.enums.BalanceTransactionType.balance_transfer_inbound
djstripe.enums.BalanceTransactionType.balance_transfer_outbound
djstripe.enums.BalanceTransactionType.charge
djstripe.enums.BalanceTransactionType.connect_collection_transfer
djstripe.enums.BalanceTransactionType.contribution
djstripe.enums.BalanceTransactionType.issuing_authorization_hold
djstripe.enums.BalanceTransactionType.issuing_authorization_release
djstripe.enums.BalanceTransactionType.issuing_dispute
djstripe.enums.BalanceTransactionType.issuing_transaction
djstripe.enums.BalanceTransactionType.network_cost
djstripe.enums.BalanceTransactionType.payment
djstripe.enums.BalanceTransactionType.payment_failure_refund
djstripe.enums.BalanceTransactionType.payment_refund
djstripe.enums.BalanceTransactionType.payout
djstripe.enums.BalanceTransactionType.payout_cancel
djstripe.enums.BalanceTransactionType.payout_failure
djstripe.enums.BalanceTransactionType.refund
djstripe.enums.BalanceTransactionType.refund_failure
djstripe.enums.BalanceTransactionType.reserve_transaction
djstripe.enums.BalanceTransactionType.reserved_funds
djstripe.enums.BalanceTransactionType.stripe_fee
djstripe.enums.BalanceTransactionType.stripe_fx_fee
djstripe.enums.BalanceTransactionType.tax_fee
djstripe.enums.BalanceTransactionType.topup
djstripe.enums.BalanceTransactionType.topup_reversal
djstripe.enums.BalanceTransactionType.transfer
djstripe.enums.BalanceTransactionType.transfer_cancel
djstripe.enums.BalanceTransactionType.transfer_failure
djstripe.enums.BalanceTransactionType.transfer_refund
djstripe.enums.BalanceTransactionType.validation
djstripe.enums.BalanceTransactionType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.BankAccountHolderType
djstripe.enums.BankAccountHolderType.company
djstripe.enums.BankAccountHolderType.individual
djstripe.enums.BankAccountHolderType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.BankAccountStatus
djstripe.enums.BankAccountStatus.errored
djstripe.enums.BankAccountStatus.new
djstripe.enums.BankAccountStatus.validated
djstripe.enums.BankAccountStatus.verification_failed
djstripe.enums.BankAccountStatus.verified
djstripe.enums.BankAccountStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.BillingScheme
djstripe.enums.BillingScheme.per_unit
djstripe.enums.BillingScheme.tiered
djstripe.enums.BillingScheme.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.BusinessType
djstripe.enums.BusinessType.company
djstripe.enums.BusinessType.individual
djstripe.enums.BusinessType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.CaptureMethod
djstripe.enums.CaptureMethod.automatic
djstripe.enums.CaptureMethod.manual
djstripe.enums.CaptureMethod.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.CardBrand
djstripe.enums.CardBrand.AmericanExpress
djstripe.enums.CardBrand.DinersClub
djstripe.enums.CardBrand.Discover
djstripe.enums.CardBrand.JCB
djstripe.enums.CardBrand.MasterCard
djstripe.enums.CardBrand.UnionPay
djstripe.enums.CardBrand.Unknown
djstripe.enums.CardBrand.Visa
djstripe.enums.CardBrand.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.CardCheckResult
djstripe.enums.CardCheckResult.fail
djstripe.enums.CardCheckResult.pass_
djstripe.enums.CardCheckResult.unavailable
djstripe.enums.CardCheckResult.unchecked
djstripe.enums.CardCheckResult.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.CardFundingType
djstripe.enums.CardFundingType.credit
djstripe.enums.CardFundingType.debit
djstripe.enums.CardFundingType.prepaid
djstripe.enums.CardFundingType.unknown
djstripe.enums.CardFundingType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.CardTokenizationMethod
djstripe.enums.CardTokenizationMethod.android_pay
djstripe.enums.CardTokenizationMethod.apple_pay
djstripe.enums.CardTokenizationMethod.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.ChargeStatus
djstripe.enums.ChargeStatus.failed
djstripe.enums.ChargeStatus.pending
djstripe.enums.ChargeStatus.succeeded
djstripe.enums.ChargeStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.ConfirmationMethod
djstripe.enums.ConfirmationMethod.automatic
djstripe.enums.ConfirmationMethod.manual
djstripe.enums.ConfirmationMethod.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.CouponDuration
djstripe.enums.CouponDuration.forever
djstripe.enums.CouponDuration.once
djstripe.enums.CouponDuration.repeating
djstripe.enums.CouponDuration.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.CustomerTaxExempt
djstripe.enums.CustomerTaxExempt.exempt
djstripe.enums.CustomerTaxExempt.none
djstripe.enums.CustomerTaxExempt.reverse
djstripe.enums.CustomerTaxExempt.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.DisputeReason
djstripe.enums.DisputeReason.bank_cannot_process
djstripe.enums.DisputeReason.credit_not_processed
djstripe.enums.DisputeReason.customer_initiated
djstripe.enums.DisputeReason.debit_not_authorized
djstripe.enums.DisputeReason.duplicate
djstripe.enums.DisputeReason.fraudulent
djstripe.enums.DisputeReason.general
djstripe.enums.DisputeReason.incorrect_account_details
djstripe.enums.DisputeReason.insufficient_funds
djstripe.enums.DisputeReason.product_not_received
djstripe.enums.DisputeReason.product_unacceptable
djstripe.enums.DisputeReason.subscription_canceled
djstripe.enums.DisputeReason.unrecognized
djstripe.enums.DisputeReason.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.DisputeStatus
djstripe.enums.DisputeStatus.charge_refunded
djstripe.enums.DisputeStatus.lost
djstripe.enums.DisputeStatus.needs_response
djstripe.enums.DisputeStatus.under_review
djstripe.enums.DisputeStatus.warning_closed
djstripe.enums.DisputeStatus.warning_needs_response
djstripe.enums.DisputeStatus.warning_under_review
djstripe.enums.DisputeStatus.won
djstripe.enums.DisputeStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.DjstripePaymentMethodType
A djstripe-specific enum for the DjStripePaymentMethod model.
djstripe.enums.DjstripePaymentMethodType.alipay_account
djstripe.enums.DjstripePaymentMethodType.bank_account
djstripe.enums.DjstripePaymentMethodType.card
djstripe.enums.DjstripePaymentMethodType.source
djstripe.enums.DjstripePaymentMethodType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.Enum
djstripe.enums.Enum.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.EnumMetaClass
Methods
djstripe.enums.EnumMetaClass.__init__(cls, name, bases, classdict)
special
Source code in djstripe/enums.py
def __init__(cls, name, bases, classdict):
def _human_enum_values(enum):
return cls.__choices__[enum]
# add a class attribute
cls.humanize = _human_enum_values
djstripe.enums.EnumMetaClass.__new__(cls, name, bases, classdict)
special
staticmethod
Create and return a new object. See help(type) for accurate signature.
Source code in djstripe/enums.py
def __new__(cls, name, bases, classdict):
members = []
keys = {}
choices = OrderedDict()
for key, value in classdict.items():
if key.startswith("__"):
continue
members.append(key)
if isinstance(value, tuple):
value, alias = value
keys[alias] = key
else:
alias = None
keys[alias or key] = key
choices[alias or key] = value
for k, v in keys.items():
classdict[v] = k
classdict["__choices__"] = choices
classdict["__members__"] = members
# Note: Differences between Python 2.x and Python 3.x force us to
# explicitly use unicode here, and to explicitly sort the list. In
# Python 2.x, class members are unordered and so the ordering will
# vary on different systems based on internal hashing. Without this
# Django will continually require new no-op migrations.
classdict["choices"] = tuple(
(str(k), str(v))
for k, v in sorted(choices.items(), key=operator.itemgetter(0))
)
return type.__new__(cls, name, bases, classdict)
djstripe.enums.EnumMetaClass.__prepare__(name, bases)
classmethod
special
prepare() -> dict used to create the namespace for the class statement
Source code in djstripe/enums.py
@classmethod
def __prepare__(cls, name, bases):
return OrderedDict()
djstripe.enums.FilePurpose
djstripe.enums.FilePurpose.account_requirement
djstripe.enums.FilePurpose.additional_verification
djstripe.enums.FilePurpose.business_icon
djstripe.enums.FilePurpose.business_logo
djstripe.enums.FilePurpose.customer_signature
djstripe.enums.FilePurpose.dispute_evidence
djstripe.enums.FilePurpose.document_provider_identity_document
djstripe.enums.FilePurpose.finance_report_run
djstripe.enums.FilePurpose.identity_document
djstripe.enums.FilePurpose.identity_document_downloadable
djstripe.enums.FilePurpose.invoice_statement
djstripe.enums.FilePurpose.pci_document
djstripe.enums.FilePurpose.selfie
djstripe.enums.FilePurpose.sigma_scheduled_query
djstripe.enums.FilePurpose.tax_document_user_upload
djstripe.enums.FilePurpose.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.FileType
djstripe.enums.FileType.csv
djstripe.enums.FileType.docx
djstripe.enums.FileType.jpg
djstripe.enums.FileType.pdf
djstripe.enums.FileType.png
djstripe.enums.FileType.xls
djstripe.enums.FileType.xlsx
djstripe.enums.FileType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.IntentStatus
Status of Intents which apply both to PaymentIntents and SetupIntents.
djstripe.enums.IntentStatus.canceled
djstripe.enums.IntentStatus.processing
djstripe.enums.IntentStatus.requires_action
djstripe.enums.IntentStatus.requires_confirmation
djstripe.enums.IntentStatus.requires_payment_method
djstripe.enums.IntentStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.IntentUsage
djstripe.enums.IntentUsage.off_session
djstripe.enums.IntentUsage.on_session
djstripe.enums.IntentUsage.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.InvoiceBillingReason
djstripe.enums.InvoiceBillingReason.manual
djstripe.enums.InvoiceBillingReason.subscription
djstripe.enums.InvoiceBillingReason.subscription_create
djstripe.enums.InvoiceBillingReason.subscription_cycle
djstripe.enums.InvoiceBillingReason.subscription_threshold
djstripe.enums.InvoiceBillingReason.subscription_update
djstripe.enums.InvoiceBillingReason.upcoming
djstripe.enums.InvoiceBillingReason.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.InvoiceCollectionMethod
djstripe.enums.InvoiceCollectionMethod.charge_automatically
djstripe.enums.InvoiceCollectionMethod.send_invoice
djstripe.enums.InvoiceCollectionMethod.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.InvoiceStatus
djstripe.enums.InvoiceStatus.draft
djstripe.enums.InvoiceStatus.open
djstripe.enums.InvoiceStatus.paid
djstripe.enums.InvoiceStatus.uncollectible
djstripe.enums.InvoiceStatus.void
djstripe.enums.InvoiceStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.LegacySourceType
djstripe.enums.LegacySourceType.alipay_account
djstripe.enums.LegacySourceType.bank_account
djstripe.enums.LegacySourceType.bitcoin_receiver
djstripe.enums.LegacySourceType.card
djstripe.enums.LegacySourceType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.MandateStatus
djstripe.enums.MandateStatus.active
djstripe.enums.MandateStatus.inactive
djstripe.enums.MandateStatus.pending
djstripe.enums.MandateStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.MandateType
djstripe.enums.MandateType.multi_use
djstripe.enums.MandateType.single_use
djstripe.enums.MandateType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PaymentIntentCancellationReason
djstripe.enums.PaymentIntentCancellationReason.abandoned
djstripe.enums.PaymentIntentCancellationReason.automatic
djstripe.enums.PaymentIntentCancellationReason.duplicate
djstripe.enums.PaymentIntentCancellationReason.failed_invoice
djstripe.enums.PaymentIntentCancellationReason.fraudulent
djstripe.enums.PaymentIntentCancellationReason.requested_by_customer
djstripe.enums.PaymentIntentCancellationReason.void_invoice
djstripe.enums.PaymentIntentCancellationReason.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PaymentIntentStatus
djstripe.enums.PaymentIntentStatus.canceled
djstripe.enums.PaymentIntentStatus.processing
djstripe.enums.PaymentIntentStatus.requires_action
djstripe.enums.PaymentIntentStatus.requires_capture
djstripe.enums.PaymentIntentStatus.requires_confirmation
djstripe.enums.PaymentIntentStatus.requires_payment_method
djstripe.enums.PaymentIntentStatus.succeeded
djstripe.enums.PaymentIntentStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PaymentMethodType
djstripe.enums.PaymentMethodType.acss_debit
djstripe.enums.PaymentMethodType.afterpay_clearpay
djstripe.enums.PaymentMethodType.alipay
djstripe.enums.PaymentMethodType.au_becs_debit
djstripe.enums.PaymentMethodType.bacs_debit
djstripe.enums.PaymentMethodType.bancontact
djstripe.enums.PaymentMethodType.boleto
djstripe.enums.PaymentMethodType.card
djstripe.enums.PaymentMethodType.card_present
djstripe.enums.PaymentMethodType.eps
djstripe.enums.PaymentMethodType.fpx
djstripe.enums.PaymentMethodType.giropay
djstripe.enums.PaymentMethodType.grabpay
djstripe.enums.PaymentMethodType.ideal
djstripe.enums.PaymentMethodType.interac_present
djstripe.enums.PaymentMethodType.klarna
djstripe.enums.PaymentMethodType.oxxo
djstripe.enums.PaymentMethodType.p24
djstripe.enums.PaymentMethodType.sepa_debit
djstripe.enums.PaymentMethodType.sofort
djstripe.enums.PaymentMethodType.wechat_pay
djstripe.enums.PaymentMethodType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PayoutFailureCode
Payout failure error codes.
https://stripe.com/docs/api#payout_failures
djstripe.enums.PayoutFailureCode.account_closed
djstripe.enums.PayoutFailureCode.account_frozen
djstripe.enums.PayoutFailureCode.bank_account_restricted
djstripe.enums.PayoutFailureCode.bank_ownership_changed
djstripe.enums.PayoutFailureCode.could_not_process
djstripe.enums.PayoutFailureCode.debit_not_authorized
djstripe.enums.PayoutFailureCode.insufficient_funds
djstripe.enums.PayoutFailureCode.invalid_account_number
djstripe.enums.PayoutFailureCode.invalid_currency
djstripe.enums.PayoutFailureCode.no_account
djstripe.enums.PayoutFailureCode.unsupported_card
djstripe.enums.PayoutFailureCode.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PayoutMethod
djstripe.enums.PayoutMethod.instant
djstripe.enums.PayoutMethod.standard
djstripe.enums.PayoutMethod.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PayoutSourceType
djstripe.enums.PayoutSourceType.bank_account
djstripe.enums.PayoutSourceType.card
djstripe.enums.PayoutSourceType.fpx
djstripe.enums.PayoutSourceType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PayoutStatus
djstripe.enums.PayoutStatus.canceled
djstripe.enums.PayoutStatus.failed
djstripe.enums.PayoutStatus.in_transit
djstripe.enums.PayoutStatus.paid
djstripe.enums.PayoutStatus.pending
djstripe.enums.PayoutStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PayoutType
djstripe.enums.PayoutType.bank_account
djstripe.enums.PayoutType.card
djstripe.enums.PayoutType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PlanAggregateUsage
djstripe.enums.PlanAggregateUsage.last_during_period
djstripe.enums.PlanAggregateUsage.last_ever
djstripe.enums.PlanAggregateUsage.max
djstripe.enums.PlanAggregateUsage.sum
djstripe.enums.PlanAggregateUsage.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PlanInterval
djstripe.enums.PlanInterval.day
djstripe.enums.PlanInterval.month
djstripe.enums.PlanInterval.week
djstripe.enums.PlanInterval.year
djstripe.enums.PlanInterval.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PlanTiersMode
djstripe.enums.PlanTiersMode.graduated
djstripe.enums.PlanTiersMode.volume
djstripe.enums.PlanTiersMode.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PlanUsageType
djstripe.enums.PlanUsageType.licensed
djstripe.enums.PlanUsageType.metered
djstripe.enums.PlanUsageType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PriceTiersMode
djstripe.enums.PriceTiersMode.graduated
djstripe.enums.PriceTiersMode.volume
djstripe.enums.PriceTiersMode.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PriceType
djstripe.enums.PriceType.one_time
djstripe.enums.PriceType.recurring
djstripe.enums.PriceType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.PriceUsageType
djstripe.enums.PriceUsageType.licensed
djstripe.enums.PriceUsageType.metered
djstripe.enums.PriceUsageType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.ProductType
djstripe.enums.ProductType.good
djstripe.enums.ProductType.service
djstripe.enums.ProductType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.RefundFailureReason
djstripe.enums.RefundFailureReason.expired_or_canceled_card
djstripe.enums.RefundFailureReason.lost_or_stolen_card
djstripe.enums.RefundFailureReason.unknown
djstripe.enums.RefundFailureReason.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.RefundReason
djstripe.enums.RefundReason.duplicate
djstripe.enums.RefundReason.expired_uncaptured_charge
djstripe.enums.RefundReason.fraudulent
djstripe.enums.RefundReason.requested_by_customer
djstripe.enums.RefundReason.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.RefundStatus
djstripe.enums.RefundStatus.canceled
djstripe.enums.RefundStatus.failed
djstripe.enums.RefundStatus.pending
djstripe.enums.RefundStatus.succeeded
djstripe.enums.RefundStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.ScheduledQueryRunStatus
djstripe.enums.ScheduledQueryRunStatus.canceled
djstripe.enums.ScheduledQueryRunStatus.failed
djstripe.enums.ScheduledQueryRunStatus.timed_out
djstripe.enums.ScheduledQueryRunStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SessionBillingAddressCollection
djstripe.enums.SessionBillingAddressCollection.auto
djstripe.enums.SessionBillingAddressCollection.required
djstripe.enums.SessionBillingAddressCollection.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SessionMode
djstripe.enums.SessionMode.payment
djstripe.enums.SessionMode.setup
djstripe.enums.SessionMode.subscription
djstripe.enums.SessionMode.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SetupIntentCancellationReason
djstripe.enums.SetupIntentCancellationReason.abandoned
djstripe.enums.SetupIntentCancellationReason.duplicate
djstripe.enums.SetupIntentCancellationReason.requested_by_customer
djstripe.enums.SetupIntentCancellationReason.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SetupIntentStatus
djstripe.enums.SetupIntentStatus.canceled
djstripe.enums.SetupIntentStatus.processing
djstripe.enums.SetupIntentStatus.requires_action
djstripe.enums.SetupIntentStatus.requires_confirmation
djstripe.enums.SetupIntentStatus.requires_payment_method
djstripe.enums.SetupIntentStatus.succeeded
djstripe.enums.SetupIntentStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SourceCodeVerificationStatus
djstripe.enums.SourceCodeVerificationStatus.failed
djstripe.enums.SourceCodeVerificationStatus.pending
djstripe.enums.SourceCodeVerificationStatus.succeeded
djstripe.enums.SourceCodeVerificationStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SourceFlow
djstripe.enums.SourceFlow.code_verification
djstripe.enums.SourceFlow.none
djstripe.enums.SourceFlow.receiver
djstripe.enums.SourceFlow.redirect
djstripe.enums.SourceFlow.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SourceRedirectFailureReason
djstripe.enums.SourceRedirectFailureReason.declined
djstripe.enums.SourceRedirectFailureReason.processing_error
djstripe.enums.SourceRedirectFailureReason.user_abort
djstripe.enums.SourceRedirectFailureReason.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SourceRedirectStatus
djstripe.enums.SourceRedirectStatus.failed
djstripe.enums.SourceRedirectStatus.not_required
djstripe.enums.SourceRedirectStatus.pending
djstripe.enums.SourceRedirectStatus.succeeded
djstripe.enums.SourceRedirectStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SourceStatus
djstripe.enums.SourceStatus.canceled
djstripe.enums.SourceStatus.chargeable
djstripe.enums.SourceStatus.consumed
djstripe.enums.SourceStatus.failed
djstripe.enums.SourceStatus.pending
djstripe.enums.SourceStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SourceType
djstripe.enums.SourceType.ach_credit_transfer
djstripe.enums.SourceType.ach_debit
djstripe.enums.SourceType.acss_debit
djstripe.enums.SourceType.alipay
djstripe.enums.SourceType.au_becs_debit
djstripe.enums.SourceType.bancontact
djstripe.enums.SourceType.bitcoin
djstripe.enums.SourceType.card
djstripe.enums.SourceType.card_present
djstripe.enums.SourceType.eps
djstripe.enums.SourceType.giropay
djstripe.enums.SourceType.ideal
djstripe.enums.SourceType.klarna
djstripe.enums.SourceType.multibanco
djstripe.enums.SourceType.p24
djstripe.enums.SourceType.paper_check
djstripe.enums.SourceType.sepa_credit_transfer
djstripe.enums.SourceType.sepa_debit
djstripe.enums.SourceType.sofort
djstripe.enums.SourceType.three_d_secure
djstripe.enums.SourceType.wechat
djstripe.enums.SourceType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SourceUsage
djstripe.enums.SourceUsage.reusable
djstripe.enums.SourceUsage.single_use
djstripe.enums.SourceUsage.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SubmitTypeStatus
djstripe.enums.SubmitTypeStatus.auto
djstripe.enums.SubmitTypeStatus.book
djstripe.enums.SubmitTypeStatus.donate
djstripe.enums.SubmitTypeStatus.pay
djstripe.enums.SubmitTypeStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SubscriptionScheduleEndBehavior
djstripe.enums.SubscriptionScheduleEndBehavior.cancel
djstripe.enums.SubscriptionScheduleEndBehavior.release
djstripe.enums.SubscriptionScheduleEndBehavior.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SubscriptionScheduleStatus
djstripe.enums.SubscriptionScheduleStatus.active
djstripe.enums.SubscriptionScheduleStatus.canceled
djstripe.enums.SubscriptionScheduleStatus.completed
djstripe.enums.SubscriptionScheduleStatus.not_started
djstripe.enums.SubscriptionScheduleStatus.released
djstripe.enums.SubscriptionScheduleStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.SubscriptionStatus
djstripe.enums.SubscriptionStatus.active
djstripe.enums.SubscriptionStatus.canceled
djstripe.enums.SubscriptionStatus.incomplete
djstripe.enums.SubscriptionStatus.incomplete_expired
djstripe.enums.SubscriptionStatus.past_due
djstripe.enums.SubscriptionStatus.trialing
djstripe.enums.SubscriptionStatus.unpaid
djstripe.enums.SubscriptionStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.TaxIdType
djstripe.enums.TaxIdType.ae_trn
djstripe.enums.TaxIdType.au_abn
djstripe.enums.TaxIdType.br_cnp
djstripe.enums.TaxIdType.br_cpf
djstripe.enums.TaxIdType.ca_bn
djstripe.enums.TaxIdType.ca_qst
djstripe.enums.TaxIdType.ch_vat
djstripe.enums.TaxIdType.cl_tin
djstripe.enums.TaxIdType.es_cif
djstripe.enums.TaxIdType.eu_vat
djstripe.enums.TaxIdType.hk_br
djstripe.enums.TaxIdType.id_npw
djstripe.enums.TaxIdType.in_gst
djstripe.enums.TaxIdType.jp_cn
djstripe.enums.TaxIdType.jp_rn
djstripe.enums.TaxIdType.kr_brn
djstripe.enums.TaxIdType.li_uid
djstripe.enums.TaxIdType.mx_rfc
djstripe.enums.TaxIdType.my_frp
djstripe.enums.TaxIdType.my_itn
djstripe.enums.TaxIdType.my_sst
djstripe.enums.TaxIdType.no_vat
djstripe.enums.TaxIdType.nz_gst
djstripe.enums.TaxIdType.ru_inn
djstripe.enums.TaxIdType.ru_kpp
djstripe.enums.TaxIdType.sa_vat
djstripe.enums.TaxIdType.sg_gst
djstripe.enums.TaxIdType.sg_uen
djstripe.enums.TaxIdType.th_vat
djstripe.enums.TaxIdType.tw_vat
djstripe.enums.TaxIdType.unknown
djstripe.enums.TaxIdType.us_ein
djstripe.enums.TaxIdType.za_vat
djstripe.enums.TaxIdType.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.UsageAction
djstripe.enums.UsageAction.increment
djstripe.enums.UsageAction.set
djstripe.enums.UsageAction.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.enums.WebhookEndpointStatus
djstripe.enums.WebhookEndpointStatus.disabled
djstripe.enums.WebhookEndpointStatus.enabled
djstripe.enums.WebhookEndpointStatus.humanize(enum)
Source code in djstripe/enums.py
def _human_enum_values(enum):
return cls.__choices__[enum]
djstripe.event_handlers
Webhook event handlers for the various models
Stripe docs for Events: https://stripe.com/docs/api/events Stripe docs for Webhooks: https://stripe.com/docs/webhooks
Implement webhook event handlers for all the models that need to
respond to webhook events.
Note
Event data is not guaranteed to be in the correct API version format. See #116. When writing a webhook handler, make sure to first re-retrieve the object you wish to process.
djstripe.event_handlers.logger
Classes
djstripe.event_handlers.CrudType
Helper object to determine CRUD-like event state.
djstripe.event_handlers.CrudType.DELETED
djstripe.event_handlers.CrudType.UPDATED
Functions
djstripe.event_handlers.account_application_webhook_handler(event)
Handles updates to Connected Accounts External Accounts
Source code in djstripe/event_handlers.py
@webhooks.handler("account.external_account")
def account_application_webhook_handler(event):
"""
Handles updates to Connected Accounts External Accounts
"""
source_type = event.data.get("object", {}).get("object")
if source_type == PayoutType.card:
_handle_crud_like_event(target_cls=models.Card, event=event)
if source_type == PayoutType.bank_account:
_handle_crud_like_event(target_cls=models.BankAccount, event=event)
djstripe.event_handlers.account_updated_webhook_handler(event)
Handles updates to Connected Accounts - account: https://stripe.com/docs/api/accounts
Source code in djstripe/event_handlers.py
@webhooks.handler("account.updated")
def account_updated_webhook_handler(event):
"""
Handles updates to Connected Accounts
- account: https://stripe.com/docs/api/accounts
"""
_handle_crud_like_event(
target_cls=models.Account,
event=event,
crud_type=CrudType.UPDATED,
)
djstripe.event_handlers.charge_webhook_handler(event)
Handle updates to Charge objects - charge: https://stripe.com/docs/api/charges
Source code in djstripe/event_handlers.py
@webhooks.handler("charge")
def charge_webhook_handler(event):
"""Handle updates to Charge objects
- charge: https://stripe.com/docs/api/charges
"""
# will recieve all events of the type charge.X.Y so
# need to ensure the data object is related to Charge Object
target_object_type = event.data.get("object", {}).get("object", {})
if target_object_type == "charge":
_handle_crud_like_event(target_cls=models.Charge, event=event)
djstripe.event_handlers.customer_discount_webhook_handler(event)
Handle updates to customer discount objects.
Docs: https://stripe.com/docs/api#discounts
Because there is no concept of a "Discount" model in dj-stripe (due to the lack of a stripe id on them), this is a little different to the other handlers.
Source code in djstripe/event_handlers.py
@webhooks.handler("customer.discount")
def customer_discount_webhook_handler(event):
"""Handle updates to customer discount objects.
Docs: https://stripe.com/docs/api#discounts
Because there is no concept of a "Discount" model in dj-stripe (due to the
lack of a stripe id on them), this is a little different to the other
handlers.
"""
crud_type = CrudType.determine(event=event)
discount_data = event.data.get("object", {})
coupon_data = discount_data.get("coupon", {})
customer = event.customer
if crud_type is CrudType.DELETED:
coupon = None
coupon_start = None
coupon_end = None
else:
coupon, _ = _handle_crud_like_event(
target_cls=models.Coupon,
event=event,
data=coupon_data,
id=coupon_data.get("id"),
)
coupon_start = discount_data.get("start")
coupon_end = discount_data.get("end")
customer.coupon = coupon
customer.coupon_start = convert_tstamp(coupon_start)
customer.coupon_end = convert_tstamp(coupon_end)
customer.save()
djstripe.event_handlers.customer_source_webhook_handler(event)
Handle updates to customer payment-source objects.
Docs: https://stripe.com/docs/api/sources
Source code in djstripe/event_handlers.py
@webhooks.handler("customer.source")
def customer_source_webhook_handler(event):
"""Handle updates to customer payment-source objects.
Docs: https://stripe.com/docs/api/sources
"""
customer_data = event.data.get("object", {})
source_type = customer_data.get("object", {})
# TODO: handle other types of sources
# (https://stripe.com/docs/api/sources)
if source_type == SourceType.card:
if event.verb.endswith("deleted") and customer_data:
# On customer.source.deleted, we do not delete the object,
# we merely unlink it.
# customer = Customer.objects.get(id=customer_data["id"])
# NOTE: for now, customer.sources still points to Card
# Also, https://github.com/dj-stripe/dj-stripe/issues/576
models.Card.objects.filter(id=customer_data.get("id", "")).delete()
models.DjstripePaymentMethod.objects.filter(
id=customer_data.get("id", "")
).delete()
else:
_handle_crud_like_event(target_cls=models.Card, event=event)
djstripe.event_handlers.customer_subscription_webhook_handler(event)
Handle updates to customer subscription objects.
Docs an example subscription webhook response: https://stripe.com/docs/api#subscription_object
Source code in djstripe/event_handlers.py
@webhooks.handler("customer.subscription")
def customer_subscription_webhook_handler(event):
"""Handle updates to customer subscription objects.
Docs an example subscription webhook response:
https://stripe.com/docs/api#subscription_object
"""
# customer.subscription.deleted doesn't actually delete the subscription
# on the stripe side, it updates it to canceled status, so override
# crud_type to update to match.
crud_type = CrudType.determine(event=event)
if crud_type is CrudType.DELETED:
crud_type = CrudType.UPDATED
_handle_crud_like_event(
target_cls=models.Subscription, event=event, crud_type=crud_type
)
djstripe.event_handlers.customer_tax_id_webhook_handler(event)
Handle updates to customer tax ID objects.
Source code in djstripe/event_handlers.py
@webhooks.handler("customer.tax_id")
def customer_tax_id_webhook_handler(event):
"""
Handle updates to customer tax ID objects.
"""
_handle_crud_like_event(
target_cls=models.TaxId, event=event, crud_type=CrudType.determine(event=event)
)
djstripe.event_handlers.customer_webhook_handler(event)
Handle updates to customer objects.
First determines the crud_type and then handles the event if a customer exists locally. As customers are tied to local users, djstripe will not create customers that do not already exist locally.
And updates to the subscriber model and metadata fields of customer if present in checkout.sessions metadata key.
Docs and an example customer webhook response: https://stripe.com/docs/api#customer_object
Source code in djstripe/event_handlers.py
@webhooks.handler("customer")
def customer_webhook_handler(event):
"""Handle updates to customer objects.
First determines the crud_type and then handles the event if a customer
exists locally.
As customers are tied to local users, djstripe will not create customers that
do not already exist locally.
And updates to the subscriber model and metadata fields of customer if present
in checkout.sessions metadata key.
Docs and an example customer webhook response:
https://stripe.com/docs/api#customer_object
"""
# will recieve all events of the type customer.X.Y so
# need to ensure the data object is related to Customer Object
target_object_type = event.data.get("object", {}).get("object", {})
if event.customer and target_object_type == "customer":
metadata = event.data.get("object", {}).get("metadata", {})
customer_id = event.data.get("object", {}).get("id", "")
subscriber_key = djstripe_settings.SUBSCRIBER_CUSTOMER_KEY
# only update customer.subscriber if both the customer and subscriber already exist
update_customer_helper(metadata, customer_id, subscriber_key)
_handle_crud_like_event(target_cls=models.Customer, event=event)
djstripe.event_handlers.dispute_webhook_handler(event)
Handle updates to Dispute objects - dispute: https://stripe.com/docs/api/disputes
Source code in djstripe/event_handlers.py
@webhooks.handler("charge.dispute")
def dispute_webhook_handler(event):
"""Handle updates to Dispute objects
- dispute: https://stripe.com/docs/api/disputes
"""
# will recieve all events of the type charge.dispute.Y so
# need to ensure the data object is related to Dispute Object
target_object_type = event.data.get("object", {}).get("object", {})
if target_object_type == "dispute":
_handle_crud_like_event(target_cls=models.Dispute, event=event)
djstripe.event_handlers.other_object_webhook_handler(event)
Handle updates to checkout, coupon, file, invoice, invoiceitem, payment_intent, plan, product, setup_intent, subscription_schedule, source, tax_rate and transfer objects.
Docs for: - checkout: https://stripe.com/docs/api/checkout/sessions - coupon: https://stripe.com/docs/api/coupons - file: https://stripe.com/docs/api/files - invoice: https://stripe.com/docs/api/invoices - invoiceitem: https://stripe.com/docs/api/invoiceitems - payment_intent: https://stripe.com/docs/api/payment_intents - plan: https://stripe.com/docs/api/plans - price: https://stripe.com/docs/api/prices - product: https://stripe.com/docs/api/products - setup_intent: https://stripe.com/docs/api/setup_intents - subscription_schedule: https://stripe.com/docs/api/subscription_schedules - source: https://stripe.com/docs/api/sources - tax_rate: https://stripe.com/docs/api/tax_rates/ - transfer: https://stripe.com/docs/api/transfers
Source code in djstripe/event_handlers.py
@webhooks.handler(
"checkout",
"coupon",
"file",
"invoice",
"invoiceitem",
"payment_intent",
"plan",
"price",
"product",
"setup_intent",
"subscription_schedule",
"source",
"tax_rate",
"transfer",
)
def other_object_webhook_handler(event):
"""
Handle updates to checkout, coupon, file, invoice, invoiceitem, payment_intent,
plan, product, setup_intent, subscription_schedule, source, tax_rate
and transfer objects.
Docs for:
- checkout: https://stripe.com/docs/api/checkout/sessions
- coupon: https://stripe.com/docs/api/coupons
- file: https://stripe.com/docs/api/files
- invoice: https://stripe.com/docs/api/invoices
- invoiceitem: https://stripe.com/docs/api/invoiceitems
- payment_intent: https://stripe.com/docs/api/payment_intents
- plan: https://stripe.com/docs/api/plans
- price: https://stripe.com/docs/api/prices
- product: https://stripe.com/docs/api/products
- setup_intent: https://stripe.com/docs/api/setup_intents
- subscription_schedule: https://stripe.com/docs/api/subscription_schedules
- source: https://stripe.com/docs/api/sources
- tax_rate: https://stripe.com/docs/api/tax_rates/
- transfer: https://stripe.com/docs/api/transfers
"""
target_cls = {
"checkout": models.Session,
"coupon": models.Coupon,
"file": models.File,
"invoice": models.Invoice,
"invoiceitem": models.InvoiceItem,
"payment_intent": models.PaymentIntent,
"plan": models.Plan,
"price": models.Price,
"product": models.Product,
"transfer": models.Transfer,
"setup_intent": models.SetupIntent,
"subscription_schedule": models.SubscriptionSchedule,
"source": models.Source,
"tax_rate": models.TaxRate,
}.get(event.category)
_handle_crud_like_event(target_cls=target_cls, event=event)
djstripe.event_handlers.payment_method_handler(event)
Handle updates to payment_method objects :param event: :return:
Docs for: - payment_method: https://stripe.com/docs/api/payment_methods
Source code in djstripe/event_handlers.py
@webhooks.handler("payment_method")
def payment_method_handler(event):
"""
Handle updates to payment_method objects
:param event:
:return:
Docs for:
- payment_method: https://stripe.com/docs/api/payment_methods
"""
# will recieve all events of the type payment_method.X.Y so
# need to ensure the data object is related to PaymentMethod Object
target_object_type = event.data.get("object", {}).get("object", {})
if target_object_type == "payment_method":
id_ = event.data.get("object", {}).get("id", None)
if (
event.parts == ["payment_method", "detached"]
and id_
and id_.startswith("card_")
):
# Special case to handle a quirk in stripe's wrapping of legacy "card" objects
# with payment_methods - card objects are deleted on detach, so treat this as
# a delete event
_handle_crud_like_event(
target_cls=models.PaymentMethod,
event=event,
crud_type=CrudType.DELETED,
)
else:
_handle_crud_like_event(target_cls=models.PaymentMethod, event=event)
djstripe.event_handlers.update_customer_helper(metadata, customer_id, subscriber_key)
A helper function that updates customer's subscriber and metadata fields
Source code in djstripe/event_handlers.py
def update_customer_helper(metadata, customer_id, subscriber_key):
"""
A helper function that updates customer's subscriber and metadata fields
"""
# only update customer.subscriber if both the customer and subscriber already exist
if (
subscriber_key not in ("", None)
and metadata.get(subscriber_key, "")
and customer_id
):
try:
subscriber = djstripe_settings.get_subscriber_model().objects.get(
id=metadata.get(subscriber_key, "")
)
customer = models.Customer.objects.get(id=customer_id)
customer.subscriber = subscriber
customer.metadata = metadata
customer.save()
except ObjectDoesNotExist:
pass
djstripe.exceptions
dj-stripe Exceptions.
Classes
djstripe.exceptions.MultipleSubscriptionException
Raised when a Customer has multiple Subscriptions and only one is expected.
djstripe.exceptions.StripeObjectManipulationException
Raised when an attempt to manipulate a non-standalone stripe object is made not through its parent object.
djstripe.fields
dj-stripe Custom Field Definitions
Classes
djstripe.fields.JSONField
A field used to define a JSONField value according to djstripe logic.
djstripe.fields.PaymentMethodForeignKey
djstripe.fields.PaymentMethodForeignKey.__init__(self, **kwargs)
special
Source code in djstripe/fields.py
def __init__(self, **kwargs):
kwargs.setdefault("to", "DjstripePaymentMethod")
super().__init__(**kwargs)
djstripe.fields.StripeCurrencyCodeField
A field used to store a three-letter currency code (eg. usd, eur, ...)
djstripe.fields.StripeCurrencyCodeField.__init__(self, *args, **kwargs)
special
Source code in djstripe/fields.py
def __init__(self, *args, **kwargs):
defaults = {"max_length": 3, "help_text": "Three-letter ISO currency code"}
defaults.update(kwargs)
super().__init__(*args, **defaults)
djstripe.fields.StripeDateTimeField
A field used to define a DateTimeField value according to djstripe logic.
Methods
djstripe.fields.StripeDateTimeField.stripe_to_db(self, data)
Convert the raw timestamp value to a DateTime representation.
Source code in djstripe/fields.py
def stripe_to_db(self, data):
"""Convert the raw timestamp value to a DateTime representation."""
val = data.get(self.name)
# Note: 0 is a possible return value, which is 'falseish'
if val is not None:
return convert_tstamp(val)
djstripe.fields.StripeDecimalCurrencyAmountField
A legacy field to store currency amounts in dollars (etc).
Stripe is always in cents. Historically djstripe stored everything in dollars.
Note: Don't use this for new fields, use StripeQuantumCurrencyAmountField instead. We're planning on migrating existing fields in dj-stripe 3.0, see https://github.com/dj-stripe/dj-stripe/issues/955
Methods
djstripe.fields.StripeDecimalCurrencyAmountField.__init__(self, *args, **kwargs)
special
Assign default args to this field. By contacting stripe support, some accounts will have their limit raised to 11 digits
Source code in djstripe/fields.py
def __init__(self, *args, **kwargs):
"""
Assign default args to this field. By contacting stripe support, some accounts
will have their limit raised to 11 digits
"""
defaults = {"decimal_places": 2, "max_digits": 11}
defaults.update(kwargs)
super().__init__(*args, **defaults)
djstripe.fields.StripeDecimalCurrencyAmountField.stripe_to_db(self, data)
Convert the raw value to decimal representation.
Source code in djstripe/fields.py
def stripe_to_db(self, data):
"""Convert the raw value to decimal representation."""
val = data.get(self.name)
# If already a string, it's decimal in the API (eg. Prices).
if isinstance(val, str):
return decimal.Decimal(val)
# Note: 0 is a possible return value, which is 'falseish'
if val is not None:
return val / decimal.Decimal("100")
djstripe.fields.StripeEnumField
Methods
djstripe.fields.StripeEnumField.__init__(self, enum, *args, **kwargs)
special
Source code in djstripe/fields.py
def __init__(self, enum, *args, **kwargs):
self.enum = enum
choices = enum.choices
defaults = {"choices": choices, "max_length": max(len(k) for k, v in choices)}
defaults.update(kwargs)
super().__init__(*args, **defaults)
djstripe.fields.StripeEnumField.deconstruct(self)
Return enough information to recreate the field as a 4-tuple:
- The name of the field on the model, if contribute_to_class() has been run.
- The import path of the field, including the class:e.g. django.db.models.IntegerField This should be the most portable version, so less specific may be better.
- A list of positional arguments.
- A dict of keyword arguments.
Note that the positional or keyword arguments must contain values of the following types (including inner values of collection types):
- None, bool, str, int, float, complex, set, frozenset, list, tuple, dict
- UUID
- datetime.datetime (naive), datetime.date
- top-level classes, top-level functions - will be referenced by their full import path
- Storage instances - these have their own deconstruct() method
This is because the values here must be serialized into a text format (possibly new Python code, possibly JSON) and these are the only types with encoding handlers defined.
There's no need to return the exact way the field was instantiated this time, just ensure that the resulting field is the same - prefer keyword arguments over positional ones, and omit parameters with their default values.
Source code in djstripe/fields.py
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs["enum"] = self.enum
if "choices" in kwargs:
del kwargs["choices"]
return name, path, args, kwargs
djstripe.fields.StripeForeignKey
djstripe.fields.StripeForeignKey.setting_name
Methods
djstripe.fields.StripeForeignKey.__init__(self, *args, **kwargs)
special
Source code in djstripe/fields.py
def __init__(self, *args, **kwargs):
# The default value will only come into play if the check for
# that setting has been disabled.
kwargs["to_field"] = getattr(settings, self.setting_name, "id")
super().__init__(*args, **kwargs)
djstripe.fields.StripeForeignKey.deconstruct(self)
Return enough information to recreate the field as a 4-tuple:
- The name of the field on the model, if contribute_to_class() has been run.
- The import path of the field, including the class:e.g. django.db.models.IntegerField This should be the most portable version, so less specific may be better.
- A list of positional arguments.
- A dict of keyword arguments.
Note that the positional or keyword arguments must contain values of the following types (including inner values of collection types):
- None, bool, str, int, float, complex, set, frozenset, list, tuple, dict
- UUID
- datetime.datetime (naive), datetime.date
- top-level classes, top-level functions - will be referenced by their full import path
- Storage instances - these have their own deconstruct() method
This is because the values here must be serialized into a text format (possibly new Python code, possibly JSON) and these are the only types with encoding handlers defined.
There's no need to return the exact way the field was instantiated this time, just ensure that the resulting field is the same - prefer keyword arguments over positional ones, and omit parameters with their default values.
Source code in djstripe/fields.py
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs["to_field"] = SettingsReference(
getattr(settings, self.setting_name, "id"), self.setting_name
)
return name, path, args, kwargs
djstripe.fields.StripeForeignKey.get_default(self)
Return the to_field if the default value is an object.
Source code in djstripe/fields.py
def get_default(self):
# Override to bypass a weird bug in Django
# https://stackoverflow.com/a/14390402/227443
if isinstance(self.remote_field.model, str):
return self._get_default()
return super().get_default()
djstripe.fields.StripeIdField
A field with enough space to hold any stripe ID.
Methods
djstripe.fields.StripeIdField.__init__(self, *args, **kwargs)
special
Assign default args to this field.
As per: https://stripe.com/docs/upgrades You can safely assume object IDs we generate will never exceed 255 characters, but you should be able to handle IDs of up to that length.
Source code in djstripe/fields.py
def __init__(self, *args, **kwargs):
"""
Assign default args to this field.
As per: https://stripe.com/docs/upgrades
You can safely assume object IDs we generate will never exceed 255
characters, but you should be able to handle IDs of up to that
length.
"""
defaults = {"max_length": 255, "blank": False, "null": False}
defaults.update(kwargs)
super().__init__(*args, **defaults)
djstripe.fields.StripePercentField
A field used to define a percent according to djstripe logic.
Methods
djstripe.fields.StripePercentField.__init__(self, *args, **kwargs)
special
Assign default args to this field.
Source code in djstripe/fields.py
def __init__(self, *args, **kwargs):
"""Assign default args to this field."""
defaults = {
"decimal_places": 2,
"max_digits": 5,
"validators": [MinValueValidator(1), MaxValueValidator(100)],
}
defaults.update(kwargs)
super().__init__(*args, **defaults)
djstripe.fields.StripeQuantumCurrencyAmountField
A field used to store currency amounts in cents (etc) as per stripe. By contacting stripe support, some accounts will have their limit raised to 11 digits, hence the use of BigIntegerField instead of IntegerField
djstripe.fields.import_jsonfield()
Source code in djstripe/fields.py
def import_jsonfield():
if djstripe_settings.USE_NATIVE_JSONFIELD:
try:
# Django 3.1
from django.db.models import JSONField as BaseJSONField
except ImportError:
from django.contrib.postgres.fields import JSONField as BaseJSONField
else:
from jsonfield import JSONField as BaseJSONField
return BaseJSONField
djstripe.management
special
Modules
djstripe.management.commands
special
Modules
djstripe.management.commands.djstripe_clear_expired_idempotency_keys
djstripe.management.commands.djstripe_clear_expired_idempotency_keys.Command
djstripe.management.commands.djstripe_clear_expired_idempotency_keys.Command.help
djstripe.management.commands.djstripe_clear_expired_idempotency_keys.Command.handle(self, *args, **options)
The actual logic of the command. Subclasses must implement this method.
Source code in djstripe/management/commands/djstripe_clear_expired_idempotency_keys.py
def handle(self, *args, **options):
clear_expired_idempotency_keys()
djstripe.management.commands.djstripe_init_customers
init_customers command.
djstripe.management.commands.djstripe_init_customers.Command
Create customer objects for existing subscribers that don't have one.
djstripe.management.commands.djstripe_init_customers.Command.help
djstripe.management.commands.djstripe_init_customers.Command.handle(self, *args, **options)
Create Customer objects for Subscribers without Customer objects associated.
Source code in djstripe/management/commands/djstripe_init_customers.py
def handle(self, *args, **options):
"""
Create Customer objects for Subscribers without Customer objects associated.
"""
subscriber_qs = djstripe_settings.get_subscriber_model().objects.filter(
djstripe_customers=None
)
if subscriber_qs:
for subscriber in subscriber_qs:
# use get_or_create in case of race conditions on large subscriber bases
Customer.get_or_create(subscriber=subscriber)
self.stdout.write(f"Created subscriber for {subscriber.email}")
else:
self.stdout.write("All Customers already have subscribers")
djstripe.management.commands.djstripe_process_events
djstripe.management.commands.djstripe_process_events.Command
Command to process all Events.
Optional arguments are provided to limit the number of Events processed.
Note: this is only guaranteed go back at most 30 days based on the current limitation of stripe's events API. See: https://stripe.com/docs/api/events
djstripe.management.commands.djstripe_process_events.Command.help
djstripe.management.commands.djstripe_process_events.Command.add_arguments(self, parser)
Add optional arugments to filter Events by.
Source code in djstripe/management/commands/djstripe_process_events.py
def add_arguments(self, parser):
"""Add optional arugments to filter Events by."""
# Use a mutually exclusive group to prevent multiple arguments being
# specified together.
group = parser.add_mutually_exclusive_group()
group.add_argument(
"--ids",
nargs="*",
help="An optional space separated list of specific Event IDs to sync.",
)
group.add_argument(
"--failed",
action="store_true",
help="Syncs and processes only the events that have failed webhooks.",
)
group.add_argument(
"--type",
help=(
"A string containing a specific event name,"
" or group of events using * as a wildcard."
" The list will be filtered to include only"
" events with a matching event property."
),
)
djstripe.management.commands.djstripe_process_events.Command.handle(self, *args, **options)
Try to process Events listed from the API.
Source code in djstripe/management/commands/djstripe_process_events.py
def handle(self, *args, **options):
"""Try to process Events listed from the API."""
# Set the verbosity to determine how much we output, if at all.
self.set_verbosity(options)
event_ids = options["ids"]
failed = options["failed"]
type_filter = options["type"]
# Args are mutually exclusive,
# so output what we are doing based on that assumption.
if failed:
self.output("Processing all failed events")
elif type_filter:
self.output(
"Processing all events that match {filter}".format(filter=type_filter)
)
elif event_ids:
self.output("Processing specific events {events}".format(events=event_ids))
else:
self.output("Processing all available events")
# Either use the specific event IDs to retrieve data, or use the api_list
# if no specific event IDs are specified.
if event_ids:
listed_events = (
models.Event.stripe_class.retrieve(
id=event_id, api_key=djstripe_settings.STRIPE_SECRET_KEY
)
for event_id in event_ids
)
else:
list_kwargs = {}
if failed:
list_kwargs["delivery_success"] = False
if type_filter:
list_kwargs["type"] = type_filter
listed_events = models.Event.api_list(**list_kwargs)
self.process_events(listed_events)
djstripe.management.commands.djstripe_process_events.Command.process_events(self, listed_events)
Source code in djstripe/management/commands/djstripe_process_events.py
def process_events(self, listed_events):
# Process each listed event. Capture failures and continue,
# outputting debug information as verbosity dictates.
count = 0
total = 0
for event_data in listed_events:
try:
total += 1
event = models.Event.process(data=event_data)
count += 1
self.verbose_output(f"\tSynced Event {event.id}")
except Exception as exception:
self.verbose_output(f"\tFailed processing Event {event_data['id']}")
self.output(f"\t{exception}")
self.verbose_traceback()
if total == 0:
self.output("\t(no results)")
else:
self.output(f"\tProcessed {count} out of {total} Events")
djstripe.management.commands.djstripe_sync_customers
sync_customer command.
djstripe.management.commands.djstripe_sync_customers.Command
Sync subscriber data with stripe.
djstripe.management.commands.djstripe_sync_customers.Command.help
djstripe.management.commands.djstripe_sync_customers.Command.handle(self, *args, **options)
Call sync_subscriber on Subscribers without customers associated to them.
Source code in djstripe/management/commands/djstripe_sync_customers.py
def handle(self, *args, **options):
"""Call sync_subscriber on Subscribers without customers associated to them."""
qs = djstripe_settings.get_subscriber_model().objects.filter(
djstripe_customers__isnull=True
)
count = 0
total = qs.count()
for subscriber in qs:
count += 1
perc = int(round(100 * (float(count) / float(total))))
print(
"[{0}/{1} {2}%] Syncing {3} [{4}]".format(
count, total, perc, subscriber.email, subscriber.pk
)
)
sync_subscriber(subscriber)
djstripe.management.commands.djstripe_sync_models
Module for the djstripe_sync_model management command to sync all Stripe objects to the local db.
Invoke like so: 1) To sync all Objects: python manage.py djstripe_sync_models
2) To only sync Stripe Accounts:
python manage.py djstripe_sync_models Account
djstripe.management.commands.djstripe_sync_models.Command
Sync models from stripe.
djstripe.management.commands.djstripe_sync_models.Command.help
djstripe.management.commands.djstripe_sync_models.Command.add_arguments(self, parser)
Entry point for subclassed commands to add custom arguments.
Source code in djstripe/management/commands/djstripe_sync_models.py
def add_arguments(self, parser):
parser.add_argument(
"args",
metavar="ModelName",
nargs="*",
help="restricts sync to these model names (default is to sync all "
"supported models)",
)
djstripe.management.commands.djstripe_sync_models.Command.get_default_list_kwargs(model, accounts_set)
staticmethod
Returns default sequence of kwargs to sync all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_default_list_kwargs(model, accounts_set):
"""Returns default sequence of kwargs to sync
all Stripe Accounts"""
if getattr(model, "expand_fields", []):
default_list_kwargs = [
{
"expand": [f"data.{k}" for k in model.expand_fields],
"stripe_account": account,
}
for account in accounts_set
]
else:
default_list_kwargs = [
{"stripe_account": account} for account in accounts_set
]
return default_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs(self, model)
Returns a sequence of kwargs dicts to pass to model.api_list
This allows us to sync models that require parameters to api_list
:param model: :return: Sequence[dict]
Source code in djstripe/management/commands/djstripe_sync_models.py
def get_list_kwargs(self, model):
"""
Returns a sequence of kwargs dicts to pass to model.api_list
This allows us to sync models that require parameters to api_list
:param model:
:return: Sequence[dict]
"""
list_kwarg_handlers_dict = {
"PaymentMethod": self.get_list_kwargs_pm,
"SubscriptionItem": self.get_list_kwargs_si,
"CountrySpec": self.get_list_kwargs_country_spec,
"TransferReversal": self.get_list_kwargs_trr,
"ApplicationFeeRefund": self.get_list_kwargs_fee_refund,
"TaxId": self.get_list_kwargs_tax_id,
"UsageRecordSummary": self.get_list_kwargs_sis,
}
# get all Stripe Accounts for the given platform account.
# note that we need to fetch from Stripe as we have no way of knowing that the ones in the local db are up to date
# as this can also be the first time the user runs sync.
accs_set = self.get_stripe_account()
default_list_kwargs = self.get_default_list_kwargs(model, accs_set)
handler = list_kwarg_handlers_dict.get(
model.__name__, lambda _: default_list_kwargs
)
return handler(default_list_kwargs)
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs_country_spec(default_list_kwargs)
staticmethod
Returns sequence of kwrags to sync Country Specs for all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_list_kwargs_country_spec(default_list_kwargs):
"""Returns sequence of kwrags to sync Country Specs for
all Stripe Accounts"""
all_list_kwargs = []
for def_kwarg in default_list_kwargs:
all_list_kwargs.append({"limit": 50, **def_kwarg})
return all_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs_fee_refund(default_list_kwargs)
staticmethod
Returns sequence of kwrags to sync Application Fee Refunds for all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_list_kwargs_fee_refund(default_list_kwargs):
"""Returns sequence of kwrags to sync Application Fee Refunds for
all Stripe Accounts"""
all_list_kwargs = []
for def_kwarg in default_list_kwargs:
stripe_account = def_kwarg.get("stripe_account")
for fee in models.ApplicationFee.api_list(stripe_account=stripe_account):
all_list_kwargs.append({"id": fee.id, **def_kwarg})
return all_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs_pm(default_list_kwargs)
staticmethod
Returns sequence of kwrags to sync Payment Methods for all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_list_kwargs_pm(default_list_kwargs):
"""Returns sequence of kwrags to sync Payment Methods for
all Stripe Accounts"""
all_list_kwargs = []
payment_method_types = enums.PaymentMethodType.__members__
for def_kwarg in default_list_kwargs:
stripe_account = def_kwarg.get("stripe_account")
for stripe_customer in models.Customer.api_list(
stripe_account=stripe_account
):
for type in payment_method_types:
all_list_kwargs.append(
{"customer": stripe_customer.id, "type": type, **def_kwarg}
)
return all_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs_si(default_list_kwargs)
staticmethod
Returns sequence of kwrags to sync Subscription Items for all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_list_kwargs_si(default_list_kwargs):
"""Returns sequence of kwrags to sync Subscription Items for
all Stripe Accounts"""
all_list_kwargs = []
for def_kwarg in default_list_kwargs:
stripe_account = def_kwarg.get("stripe_account")
for subscription in models.Subscription.api_list(
stripe_account=stripe_account
):
all_list_kwargs.append({"subscription": subscription.id, **def_kwarg})
return all_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs_sis(default_list_kwargs)
staticmethod
Returns sequence of kwrags to sync Usage Record Summarys for all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_list_kwargs_sis(default_list_kwargs):
"""Returns sequence of kwrags to sync Usage Record Summarys for
all Stripe Accounts"""
all_list_kwargs = []
for def_kwarg in default_list_kwargs:
stripe_account = def_kwarg.get("stripe_account")
for subscription in models.Subscription.api_list(
stripe_account=stripe_account
):
for subscription_item in models.SubscriptionItem.api_list(
subscription=subscription.id, stripe_account=stripe_account
):
all_list_kwargs.append({"id": subscription_item.id, **def_kwarg})
return all_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs_tax_id(default_list_kwargs)
staticmethod
Returns sequence of kwrags to sync Tax Ids for all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_list_kwargs_tax_id(default_list_kwargs):
"""Returns sequence of kwrags to sync Tax Ids for
all Stripe Accounts"""
all_list_kwargs = []
for def_kwarg in default_list_kwargs:
stripe_account = def_kwarg.get("stripe_account")
for customer in models.Customer.api_list(stripe_account=stripe_account):
all_list_kwargs.append({"id": customer.id, **def_kwarg})
return all_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_list_kwargs_trr(default_list_kwargs)
staticmethod
Returns sequence of kwrags to sync Transfer Reversals for all Stripe Accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
@staticmethod
def get_list_kwargs_trr(default_list_kwargs):
"""Returns sequence of kwrags to sync Transfer Reversals for
all Stripe Accounts"""
all_list_kwargs = []
for def_kwarg in default_list_kwargs:
stripe_account = def_kwarg.get("stripe_account")
for transfer in models.Transfer.api_list(stripe_account=stripe_account):
all_list_kwargs.append({"id": transfer.id, **def_kwarg})
return all_list_kwargs
djstripe.management.commands.djstripe_sync_models.Command.get_stripe_account(*args, **kwargs)
classmethod
Get set of all stripe account ids including the Platform Acccount
Source code in djstripe/management/commands/djstripe_sync_models.py
@classmethod
def get_stripe_account(cls, *args, **kwargs):
"""Get set of all stripe account ids including the Platform Acccount"""
accs_set = set()
# special case, since own account isn't returned by Account.api_list
stripe_platform_obj = models.Account.stripe_class.retrieve(
api_key=djstripe_settings.STRIPE_SECRET_KEY
)
accs_set.add(stripe_platform_obj.id)
for stripe_connected_obj in models.Account.api_list(**kwargs):
accs_set.add(stripe_connected_obj.id)
return accs_set
djstripe.management.commands.djstripe_sync_models.Command.handle(self, *args, **options)
The actual logic of the command. Subclasses must implement this method.
Source code in djstripe/management/commands/djstripe_sync_models.py
def handle(self, *args, **options):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
model_list = [] # type: List[models.StripeModel]
if args:
for model_label in args:
try:
model = app_config.get_model(model_label)
except LookupError:
raise CommandError(
"Unknown model: {}.{}".format(app_label, model_label)
)
model_list.append(model)
else:
model_list = app_config.get_models()
for model in model_list:
self.sync_model(model)
djstripe.management.commands.djstripe_sync_models.Command.start_sync(self, items, instance)
Source code in djstripe/management/commands/djstripe_sync_models.py
def start_sync(self, items, instance):
bank_count = 0
card_count = 0
for item in items:
if item.object == "bank_account":
model = models.BankAccount
bank_count += 1
elif item.object == "card":
model = models.Card
card_count += 1
item_obj = model.sync_from_stripe_data(item)
self.stdout.write(
f"\tSyncing {model._meta.verbose_name} ({instance}): id={item_obj.id}, pk={item_obj.pk}"
)
if bank_count + card_count > 0:
self.stdout.write(
f"\tSynced {bank_count} BankAccounts and {card_count} Cards"
)
djstripe.management.commands.djstripe_sync_models.Command.sync_bank_accounts_and_cards(self, instance, *, stripe_account)
Syncs Bank Accounts and Cards for both customers and all external accounts
Source code in djstripe/management/commands/djstripe_sync_models.py
def sync_bank_accounts_and_cards(self, instance, *, stripe_account):
"""
Syncs Bank Accounts and Cards for both customers and all external accounts
"""
type = getattr(instance, "type", None)
kwargs = {
"id": instance.id,
"api_key": djstripe_settings.STRIPE_SECRET_KEY,
"stripe_account": stripe_account,
}
if type in (enums.AccountType.custom, enums.AccountType.express) and isinstance(
instance, models.Account
):
# fetch all Card and BankAccount objects associated with the instance
items = models.Account.stripe_class.list_external_accounts(
**kwargs
).auto_paging_iter()
self.start_sync(items, instance)
elif isinstance(instance, models.Customer):
for object in ("card", "bank_account"):
kwargs["object"] = object
# fetch all Card and BankAccount objects associated with the instance
items = models.Customer.stripe_class.list_sources(
**kwargs
).auto_paging_iter()
self.start_sync(items, instance)
djstripe.management.commands.djstripe_sync_models.Command.sync_model(self, model)
Source code in djstripe/management/commands/djstripe_sync_models.py
def sync_model(self, model): # noqa: C901
model_name = model.__name__
should_sync, reason = self._should_sync_model(model)
if not should_sync:
self.stderr.write(f"Skipping {model}: {reason}")
return
self.stdout.write("Syncing {}:".format(model_name))
count = 0
try:
# todo convert get_list_kwargs into a generator to make the code memory effecient.
for list_kwargs in self.get_list_kwargs(model):
stripe_account = list_kwargs.get("stripe_account", "")
if (
model is models.Account
and stripe_account == models.Account.get_default_account().id
):
# special case, since own account isn't returned by Account.api_list
stripe_obj = models.Account.stripe_class.retrieve(
api_key=djstripe_settings.STRIPE_SECRET_KEY
)
djstripe_obj = model.sync_from_stripe_data(stripe_obj)
self.stdout.write(
f" id={djstripe_obj.id}, pk={djstripe_obj.pk} ({djstripe_obj} on {stripe_account})"
)
# syncing BankAccount and Card objects of Stripe Connected Express and Custom Accounts
self.sync_bank_accounts_and_cards(
djstripe_obj, stripe_account=stripe_account
)
count += 1
try:
for stripe_obj in model.api_list(**list_kwargs):
# Skip model instances that throw an error
try:
djstripe_obj = model.sync_from_stripe_data(stripe_obj)
self.stdout.write(
f" id={djstripe_obj.id}, pk={djstripe_obj.pk} ({djstripe_obj} on {stripe_account})"
)
# syncing BankAccount and Card objects of Stripe Connected Express and Custom Accounts
self.sync_bank_accounts_and_cards(
djstripe_obj, stripe_account=stripe_account
)
count += 1
except Exception as e:
self.stderr.write(f"Skipping {stripe_obj.get('id')}: {e}")
continue
except Exception as e:
self.stderr.write(f"Skipping: {e}")
if count == 0:
self.stdout.write(" (no results)")
else:
self.stdout.write(
" Synced {count} {model_name}".format(
count=count, model_name=model_name
)
)
except Exception as e:
self.stderr.write(str(e))
djstripe.management.commands.djstripe_sync_plans_from_stripe
sync_plans_from_stripe command.
djstripe.management.commands.djstripe_sync_plans_from_stripe.Command
Sync prices (and plans) from stripe.
djstripe.management.commands.djstripe_sync_plans_from_stripe.Command.help
djstripe.management.commands.djstripe_sync_plans_from_stripe.Command.handle(self, *args, **options)
The actual logic of the command. Subclasses must implement this method.
Source code in djstripe/management/commands/djstripe_sync_plans_from_stripe.py
def handle(self, *args, **options):
for price_data in Price.api_list():
price = Price.sync_from_stripe_data(price_data)
self.stdout.write(f"Synchronized price {price.id}")
for plan_data in Plan.api_list():
plan = Plan.sync_from_stripe_data(plan_data)
self.stdout.write(f"Synchronized plan {plan.id}")
djstripe.management.commands.djstripe_update_invoiceitem_ids
djstripe.management.commands.djstripe_update_invoiceitem_ids.no_results_msg
djstripe.management.commands.djstripe_update_invoiceitem_ids.Command
djstripe.management.commands.djstripe_update_invoiceitem_ids.Command.help
djstripe.management.commands.djstripe_update_invoiceitem_ids.Command.add_arguments(self, parser)
Add optional arugments to filter Events by.
Source code in djstripe/management/commands/djstripe_update_invoiceitem_ids.py
def add_arguments(self, parser):
"""Add optional arugments to filter Events by."""
# Use a mutually exclusive group to prevent multiple arguments being
# specified together.
group = parser.add_mutually_exclusive_group()
group.add_argument(
"--i-understand",
action="store_true",
help="Run the command, once you've read the warning and understand it.",
)
djstripe.management.commands.djstripe_update_invoiceitem_ids.Command.handle(self, *args, **options)
The actual logic of the command. Subclasses must implement this method.
Source code in djstripe/management/commands/djstripe_update_invoiceitem_ids.py
def handle(self, *args, **options):
invoice_items = InvoiceItem.objects.filter(id__contains="-il_")
count = invoice_items.count()
if not options["i_understand"]:
self.stderr.write(
"In Stripe API 2019-12-03, the format of invoice line items changed. "
"This means that existing InvoiceItem objects with the old ID format "
"may still be in the database and need to be migrated.\n"
"This is a destructive migration, but this command will attempt to "
"perform it as safely as possible.\n"
"More information: https://stripe.com/docs/upgrades#2019-12-03\n\n"
)
if count:
first_few_ids = invoice_items[:10].values_list("id", flat=True)
self.stdout.write(f"I have found {count} InvoiceItems to migrate:")
self.stdout.write(
" " + ", ".join(first_few_ids) + f", … (and {count-10} more)"
if count > 10
else ""
)
self.stderr.write(
"To perform this migration, run this again with `--i-understand`."
)
else:
self.stdout.write(no_results_msg)
return
if not count:
self.stdout.write(no_results_msg)
return
for ii in invoice_items:
old_id = ii.id
new_id = old_id.partition("-")[2]
if "-" in new_id or not new_id.startswith("il_"):
self.stderr.write(
f"Don't know how to migrate {old_id!r}. This is a bug. "
"Could you report it?\n https://github.com/dj-stripe/dj-stripe"
)
continue
self.stdout.write(f"Migrating {old_id} => {new_id}")
with transaction.atomic():
ii.id = new_id
stripe_data = ii.api_retrieve()
ii.save()
InvoiceItem.sync_from_stripe_data(stripe_data)
djstripe.managers
dj-stripe model managers
Classes
djstripe.managers.ChargeManager
Manager used by models.Charge.
Methods
djstripe.managers.ChargeManager.during(self, year, month)
Return Charges between a certain time range based on created
.
Source code in djstripe/managers.py
def during(self, year, month):
"""Return Charges between a certain time range based on `created`."""
return self.filter(created__year=year, created__month=month)
djstripe.managers.ChargeManager.paid_totals_for(self, year, month)
Return paid Charges during a certain year, month with total amount, fee and refunded annotated.
Source code in djstripe/managers.py
def paid_totals_for(self, year, month):
"""
Return paid Charges during a certain year, month with total amount,
fee and refunded annotated.
"""
return (
self.during(year, month)
.filter(paid=True)
.aggregate(
total_amount=models.Sum("amount"),
total_refunded=models.Sum("amount_refunded"),
)
)
djstripe.managers.StripeModelManager
Manager used in StripeModel.
djstripe.managers.SubscriptionManager
Manager used in models.Subscription.
Methods
djstripe.managers.SubscriptionManager.active(self)
Return active Subscriptions.
Source code in djstripe/managers.py
def active(self):
"""Return active Subscriptions."""
return self.filter(status="active")
djstripe.managers.SubscriptionManager.active_plan_summary(self)
Return active Subscriptions with plan counts annotated.
Source code in djstripe/managers.py
def active_plan_summary(self):
"""Return active Subscriptions with plan counts annotated."""
return (
self.active().values("plan").order_by().annotate(count=models.Count("plan"))
)
djstripe.managers.SubscriptionManager.canceled(self)
Return canceled Subscriptions.
Source code in djstripe/managers.py
def canceled(self):
"""Return canceled Subscriptions."""
return self.filter(status="canceled")
djstripe.managers.SubscriptionManager.canceled_during(self, year, month)
Return Subscriptions canceled during a certain time range.
Source code in djstripe/managers.py
def canceled_during(self, year, month):
"""Return Subscriptions canceled during a certain time range."""
return self.canceled().filter(canceled_at__year=year, canceled_at__month=month)
djstripe.managers.SubscriptionManager.canceled_plan_summary_for(self, year, month)
Return Subscriptions canceled within a time range with plan counts annotated.
Source code in djstripe/managers.py
def canceled_plan_summary_for(self, year, month):
"""
Return Subscriptions canceled within a time range with plan counts annotated.
"""
return (
self.canceled_during(year, month)
.values("plan")
.order_by()
.annotate(count=models.Count("plan"))
)
djstripe.managers.SubscriptionManager.churn(self)
Return number of canceled Subscriptions divided by active Subscriptions.
Source code in djstripe/managers.py
def churn(self):
"""Return number of canceled Subscriptions divided by active Subscriptions."""
canceled = self.canceled().count()
active = self.active().count()
return decimal.Decimal(str(canceled)) / decimal.Decimal(str(active))
djstripe.managers.SubscriptionManager.started_during(self, year, month)
Return Subscriptions not in trial status between a certain time range.
Source code in djstripe/managers.py
def started_during(self, year, month):
"""Return Subscriptions not in trial status between a certain time range."""
return self.exclude(status="trialing").filter(
start_date__year=year, start_date__month=month
)
djstripe.managers.SubscriptionManager.started_plan_summary_for(self, year, month)
Return started_during Subscriptions with plan counts annotated.
Source code in djstripe/managers.py
def started_plan_summary_for(self, year, month):
"""Return started_during Subscriptions with plan counts annotated."""
return (
self.started_during(year, month)
.values("plan")
.order_by()
.annotate(count=models.Count("plan"))
)
djstripe.managers.TransferManager
Manager used by models.Transfer.
Methods
djstripe.managers.TransferManager.during(self, year, month)
Return Transfers between a certain time range.
Source code in djstripe/managers.py
def during(self, year, month):
"""Return Transfers between a certain time range."""
return self.filter(created__year=year, created__month=month)
djstripe.managers.TransferManager.paid_totals_for(self, year, month)
Return paid Transfers during a certain year, month with total amounts annotated.
Source code in djstripe/managers.py
def paid_totals_for(self, year, month):
"""
Return paid Transfers during a certain year, month with total amounts annotated.
"""
return self.during(year, month).aggregate(total_amount=models.Sum("amount"))
djstripe.middleware
dj-stripe middleware
djstripe.middleware.SubscriptionPaymentMiddleware
djstripe.migrations
special
djstripe.migrations.0001_initial
djstripe.migrations.0001_initial.DJSTRIPE_SUBSCRIBER_MODEL
djstripe.migrations.0001_initial.DJSTRIPE_SUBSCRIBER_MODEL_DEPENDENCY
djstripe.migrations.0001_initial.DJSTRIPE_SUBSCRIBER_MODEL_MIGRATION_DEPENDENCY
djstripe.migrations.0001_initial.Migration
djstripe.migrations.0001_initial.Migration.dependencies
djstripe.migrations.0001_initial.Migration.initial
djstripe.migrations.0001_initial.Migration.operations
djstripe.migrations.0006_2_3
djstripe.migrations.0006_2_3.Migration
djstripe.migrations.0006_2_3.Migration.dependencies
djstripe.migrations.0006_2_3.Migration.operations
djstripe.migrations.0007_2_4
djstripe.migrations.0007_2_4.Migration
djstripe.migrations.0007_2_4.Migration.dependencies
djstripe.migrations.0007_2_4.Migration.operations
djstripe.migrations.0008_2_5
djstripe.migrations.0008_2_5.Migration
djstripe.migrations.0008_2_5.Migration.dependencies
djstripe.migrations.0008_2_5.Migration.operations
djstripe.migrations.0010_applicationfee_account
djstripe.migrations.0010_applicationfee_account.Migration
djstripe.migrations.0010_applicationfee_account.Migration.dependencies
djstripe.migrations.0010_applicationfee_account.Migration.operations
djstripe.migrations.0011_auto_20210710_0434
djstripe.migrations.0011_auto_20210710_0434.Migration
djstripe.migrations.0011_auto_20210710_0434.Migration.dependencies
djstripe.migrations.0011_auto_20210710_0434.Migration.operations
djstripe.migrations.0012_alter_transfer_destination_data_1
djstripe.migrations.0012_alter_transfer_destination_data_1.Migration
djstripe.migrations.0012_alter_transfer_destination_data_1.Migration.dependencies
djstripe.migrations.0012_alter_transfer_destination_data_1.Migration.operations
djstripe.migrations.0012_alter_transfer_destination_data_2
djstripe.migrations.0012_alter_transfer_destination_data_2.Migration
djstripe.migrations.0012_alter_transfer_destination_data_2.Migration.dependencies
djstripe.migrations.0012_alter_transfer_destination_data_2.Migration.operations
djstripe.migrations.0012_alter_transfer_schema_change_1
djstripe.migrations.0012_alter_transfer_schema_change_1.Migration
djstripe.migrations.0012_alter_transfer_schema_change_1.Migration.dependencies
djstripe.migrations.0012_alter_transfer_schema_change_1.Migration.operations
djstripe.migrations.0012_alter_transfer_schema_change_2
djstripe.migrations.0012_alter_transfer_schema_change_2.Migration
djstripe.migrations.0012_alter_transfer_schema_change_2.Migration.dependencies
djstripe.migrations.0012_alter_transfer_schema_change_2.Migration.operations
djstripe.migrations.0012_alter_transfer_schema_change_3
djstripe.migrations.0012_alter_transfer_schema_change_3.Migration
djstripe.migrations.0012_alter_transfer_schema_change_3.Migration.dependencies
djstripe.migrations.0012_alter_transfer_schema_change_3.Migration.operations
djstripe.migrations.0013_auto_20210817_0604
djstripe.migrations.0013_auto_20210817_0604.Migration
djstripe.migrations.0013_auto_20210817_0604.Migration.dependencies
djstripe.migrations.0013_auto_20210817_0604.Migration.operations
djstripe.migrations.0014_webhookendpoint
djstripe.migrations.0014_webhookendpoint.Migration
djstripe.migrations.0014_webhookendpoint.Migration.dependencies
djstripe.migrations.0014_webhookendpoint.Migration.operations
djstripe.migrations.0015_alter_customer_delinquent
djstripe.migrations.0015_alter_customer_delinquent.Migration
djstripe.migrations.0015_alter_customer_delinquent.Migration.dependencies
djstripe.migrations.0015_alter_customer_delinquent.Migration.operations
djstripe.mixins
dj-stripe mixins
Classes
djstripe.mixins.PaymentsContextMixin
Adds plan context to a view.
Methods
djstripe.mixins.PaymentsContextMixin.get_context_data(self, **kwargs)
Inject STRIPE_PUBLIC_KEY and plans into context_data.
Source code in djstripe/mixins.py
def get_context_data(self, **kwargs):
"""Inject STRIPE_PUBLIC_KEY and plans into context_data."""
context = super().get_context_data(**kwargs)
context.update(
{
"STRIPE_PUBLIC_KEY": djstripe_settings.STRIPE_PUBLIC_KEY,
"plans": Plan.objects.all(),
}
)
return context
djstripe.mixins.SubscriptionMixin
Adds customer subscription context to a view.
Methods
djstripe.mixins.SubscriptionMixin.get_context_data(self, *args, **kwargs)
Inject is_plans_plural and customer into context_data.
Source code in djstripe/mixins.py
def get_context_data(self, *args, **kwargs):
"""Inject is_plans_plural and customer into context_data."""
context = super().get_context_data(**kwargs)
context["is_plans_plural"] = Plan.objects.count() > 1
context["customer"], _created = Customer.get_or_create(
subscriber=djstripe_settings.subscriber_request_callback(self.request)
)
context["subscription"] = context["customer"].subscription
return context
djstripe.mixins.VerbosityAwareOutputMixin
A mixin class to provide verbosity aware output functions for management commands.
Methods
djstripe.mixins.VerbosityAwareOutputMixin.output(self, arg)
Print if output is not silenced.
Source code in djstripe/mixins.py
def output(self, arg):
"""Print if output is not silenced."""
if self.verbosity > 0:
print(arg)
djstripe.mixins.VerbosityAwareOutputMixin.set_verbosity(self, options)
Set the verbosity based off the passed in options.
Source code in djstripe/mixins.py
def set_verbosity(self, options):
"""Set the verbosity based off the passed in options."""
self.verbosity = options["verbosity"]
djstripe.mixins.VerbosityAwareOutputMixin.verbose_output(self, arg)
Print only if output is verbose.
Source code in djstripe/mixins.py
def verbose_output(self, arg):
"""Print only if output is verbose."""
if self.verbosity > 1:
print(arg)
djstripe.mixins.VerbosityAwareOutputMixin.verbose_traceback(self)
Print out a traceback if the output is verbose.
Source code in djstripe/mixins.py
def verbose_traceback(self):
"""Print out a traceback if the output is verbose."""
if self.verbosity > 1:
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
djstripe.models
special
djstripe.models.__all__
special
Modules
djstripe.models.account
Classes
djstripe.models.account.Account
Stripe documentation: https://stripe.com/docs/api/accounts
djstripe.models.account.Account.branding_icon
property
readonly
djstripe.models.account.Account.branding_logo
property
readonly
djstripe.models.account.Account.business_profile
djstripe.models.account.Account.business_type
djstripe.models.account.Account.business_url: str
property
readonly
The business’s publicly available website.
djstripe.models.account.Account.charges_enabled
djstripe.models.account.Account.company
djstripe.models.account.Account.country
djstripe.models.account.Account.default_api_key: str
property
readonly
djstripe.models.account.Account.default_currency
djstripe.models.account.Account.details_submitted
djstripe.models.account.Account.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.account.Account.email
djstripe.models.account.Account.individual
djstripe.models.account.Account.payouts_enabled
djstripe.models.account.Account.product_description
djstripe.models.account.Account.requirements
djstripe.models.account.Account.settings
djstripe.models.account.Account.tos_acceptance
djstripe.models.account.Account.type
djstripe.models.account.Account.DoesNotExist
djstripe.models.account.Account.MultipleObjectsReturned
djstripe.models.account.Account.stripe_class
djstripe.models.account.Account.stripe_class.OBJECT_NAME
djstripe.models.account.Account.stripe_class.capabilitys_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/account.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.account.Account.stripe_class.capabilitys_url(id, nested_id=None)
classmethod
Source code in djstripe/models/account.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.account.Account.stripe_class.create_external_account(id, **params)
classmethod
Source code in djstripe/models/account.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.account.Account.stripe_class.create_login_link(id, **params)
classmethod
Source code in djstripe/models/account.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.account.Account.stripe_class.create_person(id, **params)
classmethod
Source code in djstripe/models/account.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.account.Account.stripe_class.deauthorize(self, **params)
Source code in djstripe/models/account.py
def deauthorize(self, **params):
params["stripe_user_id"] = self.id
return oauth.OAuth.deauthorize(**params)
djstripe.models.account.Account.stripe_class.delete_external_account(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def delete_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"delete", url, **params
)
djstripe.models.account.Account.stripe_class.delete_person(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def delete_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"delete", url, **params
)
djstripe.models.account.Account.stripe_class.external_accounts_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/account.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.account.Account.stripe_class.external_accounts_url(id, nested_id=None)
classmethod
Source code in djstripe/models/account.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.account.Account.stripe_class.instance_url(self)
Source code in djstripe/models/account.py
def instance_url(self):
return self._build_instance_url(self.get("id"))
djstripe.models.account.Account.stripe_class.list_capabilities(id, **params)
classmethod
Source code in djstripe/models/account.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.account.Account.stripe_class.list_external_accounts(id, **params)
classmethod
Source code in djstripe/models/account.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.account.Account.stripe_class.list_persons(id, **params)
classmethod
Source code in djstripe/models/account.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.account.Account.stripe_class.login_links_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/account.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.account.Account.stripe_class.login_links_url(id, nested_id=None)
classmethod
Source code in djstripe/models/account.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.account.Account.stripe_class.modify(id=None, **params)
classmethod
Source code in djstripe/models/account.py
@classmethod
def modify(cls, id=None, **params):
url = cls._build_instance_url(id)
return cls._static_request("post", url, **params)
djstripe.models.account.Account.stripe_class.modify_capability(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.account.Account.stripe_class.modify_external_account(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.account.Account.stripe_class.modify_person(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.account.Account.stripe_class.persons(self, **params)
Source code in djstripe/models/account.py
def persons(self, **params):
return self.request("get", self.instance_url() + "/persons", params)
djstripe.models.account.Account.stripe_class.persons_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/account.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.account.Account.stripe_class.persons_url(id, nested_id=None)
classmethod
Source code in djstripe/models/account.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.account.Account.stripe_class.reject(self, idempotency_key=None, **params)
Source code in djstripe/models/account.py
def reject(self, idempotency_key=None, **params):
url = self.instance_url() + "/reject"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.account.Account.stripe_class.retrieve(id=None, api_key=None, **params)
classmethod
Source code in djstripe/models/account.py
@classmethod
def retrieve(cls, id=None, api_key=None, **params):
instance = cls(id, api_key, **params)
instance.refresh()
return instance
djstripe.models.account.Account.stripe_class.retrieve_capability(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.account.Account.stripe_class.retrieve_external_account(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.account.Account.stripe_class.retrieve_person(id, nested_id, **params)
classmethod
Source code in djstripe/models/account.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.account.Account.stripe_class.serialize(self, previous)
Source code in djstripe/models/account.py
def serialize(self, previous):
params = super(Account, self).serialize(previous)
previous = previous or self._previous or {}
for k, v in six.iteritems(self):
if (
k == "individual"
and isinstance(v, stripe.api_resources.Person)
and k not in params
):
params[k] = v.serialize(previous.get(k, None))
return params
djstripe.models.account.Account.__str__(self)
special
Source code in djstripe/models/account.py
def __str__(self):
settings = self.settings or {}
business_profile = self.business_profile or {}
return (
settings.get("dashboard", {}).get("display_name")
or business_profile.get("name")
or super().__str__()
)
djstripe.models.account.Account.get_business_type_display(self, *, field=<djstripe.fields.StripeEnumField: business_type>)
Source code in djstripe/models/account.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.account.Account.get_default_account()
classmethod
Source code in djstripe/models/account.py
@classmethod
def get_default_account(cls):
# As of API version 2020-03-02, there is no permission that can allow
# restricted keys to call GET /v1/account
if djstripe_settings.STRIPE_SECRET_KEY.startswith("rk_"):
return None
account_data = cls.stripe_class.retrieve(
api_key=djstripe_settings.STRIPE_SECRET_KEY
)
return cls._get_or_create_from_stripe_object(account_data)[0]
djstripe.models.account.Account.get_default_api_key(self)
Source code in djstripe/models/account.py
def get_default_api_key(self) -> str:
api_key = APIKey.objects.filter(
djstripe_owner_account=self, type=APIKeyType.secret
).first()
if api_key:
return api_key.secret
return djstripe_settings.get_default_api_key(self.livemode)
djstripe.models.account.Account.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/account.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.account.Account.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/account.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.account.Account.get_or_retrieve_for_api_key(api_key)
classmethod
Source code in djstripe/models/account.py
@classmethod
def get_or_retrieve_for_api_key(cls, api_key: str):
with transaction.atomic():
apikey_instance, _ = APIKey.objects.get_or_create_by_api_key(api_key)
if not apikey_instance.djstripe_owner_account:
apikey_instance.refresh_account()
return apikey_instance.djstripe_owner_account
djstripe.models.account.Account.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/account.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.account.Account.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/account.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.account.Account.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/account.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.api
djstripe.models.api.API_KEY_REGEX
Classes
djstripe.models.api.APIKey
APIKey(djstripe_created, djstripe_updated, djstripe_id, djstripe_owner_account, created, id, type, name, secret, livemode)
djstripe.models.api.APIKey.description
djstripe.models.api.APIKey.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.api.APIKey.metadata
djstripe.models.api.APIKey.name
djstripe.models.api.APIKey.object
djstripe.models.api.APIKey.objects
djstripe.models.api.APIKey.secret
djstripe.models.api.APIKey.secret_redacted: str
property
readonly
Returns a redacted version of the secret, suitable for display purposes.
Same algorithm used on the Stripe dashboard.
djstripe.models.api.APIKey.type
djstripe.models.api.APIKey.DoesNotExist
djstripe.models.api.APIKey.MultipleObjectsReturned
djstripe.models.api.APIKey.__str__(self)
special
Source code in djstripe/models/api.py
def __str__(self):
return self.name or self.secret_redacted
djstripe.models.api.APIKey.clean(self)
Hook for doing any extra model-wide validation after clean() has been called on every field by self.clean_fields. Any ValidationError raised by this method will not be associated with a particular field; it will have a special-case association with the field defined by NON_FIELD_ERRORS.
Source code in djstripe/models/api.py
def clean(self):
self._clean_livemode_and_type()
if not self.djstripe_owner_account:
self.refresh_account()
return super().clean()
djstripe.models.api.APIKey.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/api.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.api.APIKey.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/api.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.api.APIKey.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/api.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.api.APIKey.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/api.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.api.APIKey.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/models/api.py
def get_stripe_dashboard_url(self):
return self._get_base_stripe_dashboard_url() + "apikeys"
djstripe.models.api.APIKey.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/api.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.api.APIKey.refresh_account(self, commit=True)
Source code in djstripe/models/api.py
def refresh_account(self, commit=True):
from .account import Account
if self.type != APIKeyType.secret:
return
account_data = Account.stripe_class.retrieve(api_key=self.secret)
# NOTE: Do not immediately use _get_or_create_from_stripe_object() here.
# Account needs to exist for things to work. Make a stub if necessary.
account, created = Account.objects.get_or_create(
id=account_data["id"],
defaults={"charges_enabled": False, "details_submitted": False},
)
if created:
# If it's just been created, now we can sync the account.
Account.sync_from_stripe_data(account_data)
self.djstripe_owner_account = account
if commit:
self.save()
djstripe.models.api.APIKey.save(self, *args, **kwargs)
Save the current instance. Override this in a subclass if you want to control the saving process.
The 'force_insert' and 'force_update' parameters can be used to insist that the "save" must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.
Source code in djstripe/models/api.py
def save(self, *args, **kwargs):
self._clean_livemode_and_type()
if not self.djstripe_owner_account:
self.refresh_account(commit=False)
return super().save(*args, **kwargs)
djstripe.models.api.APIKeyManager
djstripe.models.api.APIKeyManager.get_or_create_by_api_key(self, secret)
Source code in djstripe/models/api.py
def get_or_create_by_api_key(self, secret: str):
key_type, livemode = get_api_key_details_by_prefix(secret)
return super().get_or_create(
secret=secret, defaults={"type": key_type, "livemode": livemode}
)
djstripe.models.api.generate_api_key_id()
Source code in djstripe/models/api.py
def generate_api_key_id() -> str:
b64_id = b64encode(uuid4().bytes).decode()
generated_id = b64_id.rstrip("=").replace("+", "").replace("/", "")
return f"djstripe_mk_{generated_id}"
djstripe.models.api.get_api_key_details_by_prefix(api_key)
Source code in djstripe/models/api.py
def get_api_key_details_by_prefix(api_key: str):
sre = re.match(API_KEY_REGEX, api_key)
if not sre:
raise ValueError(f"Invalid API key: {api_key!r}")
key_type = {
"pk": APIKeyType.publishable,
"sk": APIKeyType.secret,
"rk": APIKeyType.restricted,
}.get(sre.group(1), "")
livemode = {"test": False, "live": True}.get(sre.group(2))
return key_type, livemode
djstripe.models.base
djstripe.models.base.logger
Classes
djstripe.models.base.IdempotencyKey
IdempotencyKey(uuid, action, livemode, created)
djstripe.models.base.IdempotencyKey.action
djstripe.models.base.IdempotencyKey.created
djstripe.models.base.IdempotencyKey.is_expired: bool
property
readonly
djstripe.models.base.IdempotencyKey.livemode
djstripe.models.base.IdempotencyKey.uuid
djstripe.models.base.IdempotencyKey.DoesNotExist
djstripe.models.base.IdempotencyKey.MultipleObjectsReturned
djstripe.models.base.IdempotencyKey.__str__(self)
special
Source code in djstripe/models/base.py
def __str__(self):
return str(self.uuid)
djstripe.models.base.IdempotencyKey.get_next_by_created(self, *, field=<django.db.models.fields.DateTimeField: created>, is_next=True, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.IdempotencyKey.get_previous_by_created(self, *, field=<django.db.models.fields.DateTimeField: created>, is_next=False, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeBaseModel
djstripe.models.base.StripeBaseModel.djstripe_created
djstripe.models.base.StripeBaseModel.djstripe_updated
djstripe.models.base.StripeBaseModel.stripe_class: Optional[stripe.api_resources.abstract.api_resource.APIResource]
djstripe.models.base.StripeBaseModel.Meta
djstripe.models.base.StripeBaseModel.api_list(api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', **kwargs)
classmethod
Call the stripe API's list operation for this model.
:param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string
See Stripe documentation for accepted kwargs for each object.
:returns: an iterator over all items in the query
Source code in djstripe/models/base.py
@classmethod
def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
"""
Call the stripe API's list operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
See Stripe documentation for accepted kwargs for each object.
:returns: an iterator over all items in the query
"""
return cls.stripe_class.list(api_key=api_key, **kwargs).auto_paging_iter()
djstripe.models.base.StripeBaseModel.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeBaseModel.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeBaseModel.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeBaseModel.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeModel
djstripe.models.base.StripeModel.created
djstripe.models.base.StripeModel.default_api_key: str
property
readonly
djstripe.models.base.StripeModel.description
djstripe.models.base.StripeModel.djstripe_id
djstripe.models.base.StripeModel.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.base.StripeModel.expand_fields: List[str]
djstripe.models.base.StripeModel.human_readable_amount: str
property
readonly
djstripe.models.base.StripeModel.id
djstripe.models.base.StripeModel.livemode
djstripe.models.base.StripeModel.metadata
djstripe.models.base.StripeModel.objects
djstripe.models.base.StripeModel.stripe_dashboard_item_name
djstripe.models.base.StripeModel.stripe_objects
djstripe.models.base.StripeModel.Meta
djstripe.models.base.StripeModel.Meta.abstract
djstripe.models.base.StripeModel.Meta.get_latest_by
djstripe.models.base.StripeModel.__str__(self)
special
Source code in djstripe/models/base.py
def __str__(self):
return smart_str("<{list}>".format(list=", ".join(self.str_parts())))
djstripe.models.base.StripeModel.api_retrieve(self, api_key=None, stripe_account=None)
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string :param stripe_account: The optional connected account for which this request is being made. :type stripe_account: string
Source code in djstripe/models/base.py
def api_retrieve(self, api_key=None, stripe_account=None):
"""
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
:param stripe_account: The optional connected account \
for which this request is being made.
:type stripe_account: string
"""
# Prefer passed in stripe_account if set.
if not stripe_account:
stripe_account = self._get_stripe_account_id(api_key)
return self.stripe_class.retrieve(
id=self.id,
api_key=api_key or self.default_api_key,
expand=self.expand_fields,
stripe_account=stripe_account,
)
djstripe.models.base.StripeModel.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeModel.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeModel.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeModel.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/base.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.base.StripeModel.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/models/base.py
def get_stripe_dashboard_url(self) -> str:
"""Get the stripe dashboard url for this object."""
if not self.stripe_dashboard_item_name or not self.id:
return ""
else:
return "{base_url}{item}/{id}".format(
base_url=self._get_base_stripe_dashboard_url(),
item=self.stripe_dashboard_item_name,
id=self.id,
)
djstripe.models.base.StripeModel.is_valid_object(data)
classmethod
Returns whether the data is a valid object for the class
Source code in djstripe/models/base.py
@classmethod
def is_valid_object(cls, data):
"""
Returns whether the data is a valid object for the class
"""
return "object" in data and data["object"] == cls.stripe_class.OBJECT_NAME
djstripe.models.base.StripeModel.str_parts(self)
Extend this to add information to the string representation of the object
Source code in djstripe/models/base.py
def str_parts(self) -> List[str]:
"""
Extend this to add information to the string representation of the object
"""
return ["id={id}".format(id=self.id)]
djstripe.models.base.StripeModel.sync_from_stripe_data(data)
classmethod
Syncs this object from the stripe data provided.
Foreign keys will also be retrieved and synced recursively.
:param data: stripe object :type data: dict :rtype: cls
Source code in djstripe/models/base.py
@classmethod
def sync_from_stripe_data(cls, data):
"""
Syncs this object from the stripe data provided.
Foreign keys will also be retrieved and synced recursively.
:param data: stripe object
:type data: dict
:rtype: cls
"""
current_ids = set()
data_id = data.get("id")
stripe_account = getattr(data, "stripe_account", None)
if data_id:
# stop nested objects from trying to retrieve this object before
# initial sync is complete
current_ids.add(data_id)
instance, created = cls._get_or_create_from_stripe_object(
data,
current_ids=current_ids,
stripe_account=stripe_account,
)
if not created:
record_data = cls._stripe_object_to_record(data)
for attr, value in record_data.items():
setattr(instance, attr, value)
instance._attach_objects_hook(cls, data, current_ids=current_ids)
instance.save()
instance._attach_objects_post_save_hook(cls, data)
for field in instance._meta.concrete_fields:
if isinstance(field, StripePercentField):
# get rid of cached values
delattr(instance, field.name)
return instance
djstripe.models.billing
Classes
djstripe.models.billing.BaseInvoice
The abstract base model shared by Invoice and UpcomingInvoice
Note: Most fields are defined on BaseInvoice so they're available to both models. ManyToManyFields are an exception, since UpcomingInvoice doesn't exist in the db.
djstripe.models.billing.BaseInvoice.account_country
djstripe.models.billing.BaseInvoice.account_name
djstripe.models.billing.BaseInvoice.amount_due
djstripe.models.billing.BaseInvoice.amount_paid
djstripe.models.billing.BaseInvoice.amount_remaining
djstripe.models.billing.BaseInvoice.application_fee_amount
djstripe.models.billing.BaseInvoice.attempt_count
djstripe.models.billing.BaseInvoice.attempted
djstripe.models.billing.BaseInvoice.auto_advance
djstripe.models.billing.BaseInvoice.billing_reason
djstripe.models.billing.BaseInvoice.charge
djstripe.models.billing.BaseInvoice.collection_method
djstripe.models.billing.BaseInvoice.currency
djstripe.models.billing.BaseInvoice.customer
djstripe.models.billing.BaseInvoice.customer_address
djstripe.models.billing.BaseInvoice.customer_email
djstripe.models.billing.BaseInvoice.customer_name
djstripe.models.billing.BaseInvoice.customer_phone
djstripe.models.billing.BaseInvoice.customer_shipping
djstripe.models.billing.BaseInvoice.customer_tax_exempt
djstripe.models.billing.BaseInvoice.default_payment_method
djstripe.models.billing.BaseInvoice.discount
djstripe.models.billing.BaseInvoice.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.BaseInvoice.due_date
djstripe.models.billing.BaseInvoice.ending_balance
djstripe.models.billing.BaseInvoice.footer
djstripe.models.billing.BaseInvoice.hosted_invoice_url
djstripe.models.billing.BaseInvoice.invoice_pdf
djstripe.models.billing.BaseInvoice.next_payment_attempt
djstripe.models.billing.BaseInvoice.number
djstripe.models.billing.BaseInvoice.paid
djstripe.models.billing.BaseInvoice.payment_intent
djstripe.models.billing.BaseInvoice.period_end
djstripe.models.billing.BaseInvoice.period_start
djstripe.models.billing.BaseInvoice.plan: Optional[Plan]
property
readonly
Gets the associated plan for this invoice.
In order to provide a consistent view of invoices, the plan object should be taken from the first invoice item that has one, rather than using the plan associated with the subscription.
Subscriptions (and their associated plan) are updated by the customer and represent what is current, but invoice items are immutable within the invoice and stay static/unchanged.
In other words, a plan retrieved from an invoice item will represent the plan as it was at the time an invoice was issued. The plan retrieved from the subscription will be the currently active plan.
:returns: The associated plan for the invoice.
djstripe.models.billing.BaseInvoice.post_payment_credit_notes_amount
djstripe.models.billing.BaseInvoice.pre_payment_credit_notes_amount
djstripe.models.billing.BaseInvoice.receipt_number
djstripe.models.billing.BaseInvoice.starting_balance
djstripe.models.billing.BaseInvoice.statement_descriptor
djstripe.models.billing.BaseInvoice.status
djstripe.models.billing.BaseInvoice.status_transitions
djstripe.models.billing.BaseInvoice.stripe_dashboard_item_name
djstripe.models.billing.BaseInvoice.subscription
djstripe.models.billing.BaseInvoice.subscription_proration_date
djstripe.models.billing.BaseInvoice.subtotal
djstripe.models.billing.BaseInvoice.tax
djstripe.models.billing.BaseInvoice.tax_percent
djstripe.models.billing.BaseInvoice.threshold_reason
djstripe.models.billing.BaseInvoice.total
djstripe.models.billing.BaseInvoice.webhooks_delivered_at
djstripe.models.billing.BaseInvoice.Meta
djstripe.models.billing.BaseInvoice.Meta.abstract
djstripe.models.billing.BaseInvoice.Meta.ordering
djstripe.models.billing.BaseInvoice.stripe_class
djstripe.models.billing.BaseInvoice.stripe_class.OBJECT_NAME
djstripe.models.billing.BaseInvoice.stripe_class.finalize_invoice(self, idempotency_key=None, **params)
Source code in djstripe/models/billing.py
def finalize_invoice(self, idempotency_key=None, **params):
url = self.instance_url() + "/finalize"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.billing.BaseInvoice.stripe_class.mark_uncollectible(self, idempotency_key=None, **params)
Source code in djstripe/models/billing.py
def mark_uncollectible(self, idempotency_key=None, **params):
url = self.instance_url() + "/mark_uncollectible"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.billing.BaseInvoice.stripe_class.pay(self, idempotency_key=None, **params)
Source code in djstripe/models/billing.py
def pay(self, idempotency_key=None, **params):
url = self.instance_url() + "/pay"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.billing.BaseInvoice.stripe_class.send_invoice(self, idempotency_key=None, **params)
Source code in djstripe/models/billing.py
def send_invoice(self, idempotency_key=None, **params):
url = self.instance_url() + "/send"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.billing.BaseInvoice.stripe_class.upcoming(api_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/billing.py
@classmethod
def upcoming(
cls, api_key=None, stripe_version=None, stripe_account=None, **params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
url = cls.class_url() + "/upcoming"
response, api_key = requestor.request("get", url, params)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.billing.BaseInvoice.stripe_class.void_invoice(self, idempotency_key=None, **params)
Source code in djstripe/models/billing.py
def void_invoice(self, idempotency_key=None, **params):
url = self.instance_url() + "/void"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.billing.BaseInvoice.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
return "Invoice #{number}".format(
number=self.number or self.receipt_number or self.id
)
djstripe.models.billing.BaseInvoice.get_billing_reason_display(self, *, field=<djstripe.fields.StripeEnumField: billing_reason>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_collection_method_display(self, *, field=<djstripe.fields.StripeEnumField: collection_method>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_customer_tax_exempt_display(self, *, field=<djstripe.fields.StripeEnumField: customer_tax_exempt>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_next_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_next_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_previous_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_previous_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.BaseInvoice.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/models/billing.py
def get_stripe_dashboard_url(self):
return self.customer.get_stripe_dashboard_url()
djstripe.models.billing.BaseInvoice.retry(self)
Retry payment on this invoice if it isn't paid or uncollectible.
Source code in djstripe/models/billing.py
def retry(self):
"""Retry payment on this invoice if it isn't paid or uncollectible."""
if (
self.status != enums.InvoiceStatus.paid
and self.status != enums.InvoiceStatus.uncollectible
and self.auto_advance
):
stripe_invoice = self.api_retrieve()
updated_stripe_invoice = (
stripe_invoice.pay()
) # pay() throws an exception if the charge is not successful.
type(self).sync_from_stripe_data(updated_stripe_invoice)
return True
return False
djstripe.models.billing.BaseInvoice.upcoming(api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', customer=None, coupon=None, subscription=None, subscription_plan=None, subscription_prorate=None, subscription_proration_date=None, subscription_quantity=None, subscription_trial_end=None, **kwargs)
classmethod
Gets the upcoming preview invoice (singular) for a customer.
At any time, you can preview the upcoming invoice for a customer. This will show you all the charges that are pending, including subscription renewal charges, invoice item charges, etc. It will also show you any discount that is applicable to the customer. (Source: https://stripe.com/docs/api#upcoming_invoice)
.. important:: Note that when you are viewing an upcoming invoice, you are simply viewing a preview.
:param customer: The identifier of the customer whose upcoming invoice you'd like to retrieve. :type customer: Customer or string (customer ID) :param coupon: The code of the coupon to apply. :type coupon: str :param subscription: The identifier of the subscription to retrieve an invoice for. :type subscription: Subscription or string (subscription ID) :param subscription_plan: If set, the invoice returned will preview updating the subscription given to this plan, or creating a new subscription to this plan if no subscription is given. :type subscription_plan: Plan or string (plan ID) :param subscription_prorate: If previewing an update to a subscription, this decides whether the preview will show the result of applying prorations or not. :type subscription_prorate: bool :param subscription_proration_date: If previewing an update to a subscription, and doing proration, subscription_proration_date forces the proration to be calculated as though the update was done at the specified time. :type subscription_proration_date: datetime :param subscription_quantity: If provided, the invoice returned will preview updating or creating a subscription with that quantity. :type subscription_quantity: int :param subscription_trial_end: If provided, the invoice returned will preview updating or creating a subscription with that trial end. :type subscription_trial_end: datetime :returns: The upcoming preview invoice.
Source code in djstripe/models/billing.py
@classmethod
def upcoming(
cls,
api_key=djstripe_settings.STRIPE_SECRET_KEY,
customer=None,
coupon=None,
subscription=None,
subscription_plan=None,
subscription_prorate=None,
subscription_proration_date=None,
subscription_quantity=None,
subscription_trial_end=None,
**kwargs,
) -> Optional["UpcomingInvoice"]:
"""
Gets the upcoming preview invoice (singular) for a customer.
At any time, you can preview the upcoming
invoice for a customer. This will show you all the charges that are
pending, including subscription renewal charges, invoice item charges,
etc. It will also show you any discount that is applicable to the
customer. (Source: https://stripe.com/docs/api#upcoming_invoice)
.. important:: Note that when you are viewing an upcoming invoice,
you are simply viewing a preview.
:param customer: The identifier of the customer whose upcoming invoice \
you'd like to retrieve.
:type customer: Customer or string (customer ID)
:param coupon: The code of the coupon to apply.
:type coupon: str
:param subscription: The identifier of the subscription to retrieve an \
invoice for.
:type subscription: Subscription or string (subscription ID)
:param subscription_plan: If set, the invoice returned will preview \
updating the subscription given to this plan, or creating a new \
subscription to this plan if no subscription is given.
:type subscription_plan: Plan or string (plan ID)
:param subscription_prorate: If previewing an update to a subscription, \
this decides whether the preview will show the result of applying \
prorations or not.
:type subscription_prorate: bool
:param subscription_proration_date: If previewing an update to a \
subscription, and doing proration, subscription_proration_date forces \
the proration to be calculated as though the update was done at the \
specified time.
:type subscription_proration_date: datetime
:param subscription_quantity: If provided, the invoice returned will \
preview updating or creating a subscription with that quantity.
:type subscription_quantity: int
:param subscription_trial_end: If provided, the invoice returned will \
preview updating or creating a subscription with that trial end.
:type subscription_trial_end: datetime
:returns: The upcoming preview invoice.
"""
# Convert Customer to id
if customer is not None and isinstance(customer, StripeModel):
customer = customer.id
# Convert Subscription to id
if subscription is not None and isinstance(subscription, StripeModel):
subscription = subscription.id
# Convert Plan to id
if subscription_plan is not None and isinstance(subscription_plan, StripeModel):
subscription_plan = subscription_plan.id
try:
upcoming_stripe_invoice = cls.stripe_class.upcoming(
api_key=api_key,
customer=customer,
coupon=coupon,
subscription=subscription,
subscription_plan=subscription_plan,
subscription_prorate=subscription_prorate,
subscription_proration_date=subscription_proration_date,
subscription_quantity=subscription_quantity,
subscription_trial_end=subscription_trial_end,
**kwargs,
)
except InvalidRequestError as exc:
if str(exc) != "Nothing to invoice for customer":
raise
return None
# Workaround for "id" being missing (upcoming invoices don't persist).
upcoming_stripe_invoice["id"] = "upcoming"
return UpcomingInvoice._create_from_stripe_object(
upcoming_stripe_invoice, save=False
)
djstripe.models.billing.Coupon
A coupon contains information about a percent-off or amount-off discount you might want to apply to a customer. Coupons may be applied to invoices or orders. Coupons do not work with conventional one-off charges.
Stripe documentation: https://stripe.com/docs/api/coupons
djstripe.models.billing.Coupon.amount_off
djstripe.models.billing.Coupon.currency
djstripe.models.billing.Coupon.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.Coupon.duration
djstripe.models.billing.Coupon.duration_in_months
djstripe.models.billing.Coupon.human_readable
property
readonly
djstripe.models.billing.Coupon.human_readable_amount
property
readonly
djstripe.models.billing.Coupon.max_redemptions
djstripe.models.billing.Coupon.name
djstripe.models.billing.Coupon.percent_off
djstripe.models.billing.Coupon.redeem_by
djstripe.models.billing.Coupon.stripe_dashboard_item_name
djstripe.models.billing.Coupon.times_redeemed
djstripe.models.billing.Coupon.DoesNotExist
djstripe.models.billing.Coupon.MultipleObjectsReturned
djstripe.models.billing.Coupon.stripe_class
djstripe.models.billing.Coupon.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
if self.name:
return self.name
return self.human_readable
djstripe.models.billing.Coupon.get_duration_display(self, *, field=<djstripe.fields.StripeEnumField: duration>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Coupon.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Coupon.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Coupon.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Coupon.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.DjstripeInvoiceTotalTaxAmount
An internal model that holds the value of elements of Invoice.total_tax_amounts
Note that this is named with the prefix Djstripe to avoid potential collision with a Stripe API object name.
djstripe.models.billing.DjstripeInvoiceTotalTaxAmount.amount
djstripe.models.billing.DjstripeInvoiceTotalTaxAmount.inclusive
djstripe.models.billing.DjstripeInvoiceTotalTaxAmount.invoice
djstripe.models.billing.DjstripeInvoiceTotalTaxAmount.tax_rate
djstripe.models.billing.DjstripeInvoiceTotalTaxAmount.DoesNotExist
djstripe.models.billing.DjstripeInvoiceTotalTaxAmount.MultipleObjectsReturned
djstripe.models.billing.DjstripeUpcomingInvoiceTotalTaxAmount
As per DjstripeInvoiceTotalTaxAmount, except for UpcomingInvoice
djstripe.models.billing.DjstripeUpcomingInvoiceTotalTaxAmount.amount
djstripe.models.billing.DjstripeUpcomingInvoiceTotalTaxAmount.inclusive
djstripe.models.billing.DjstripeUpcomingInvoiceTotalTaxAmount.invoice
djstripe.models.billing.DjstripeUpcomingInvoiceTotalTaxAmount.tax_rate
djstripe.models.billing.DjstripeUpcomingInvoiceTotalTaxAmount.DoesNotExist
djstripe.models.billing.DjstripeUpcomingInvoiceTotalTaxAmount.MultipleObjectsReturned
djstripe.models.billing.Invoice
Invoices are statements of what a customer owes for a particular billing period, including subscriptions, invoice items, and any automatic proration adjustments if necessary.
Once an invoice is created, payment is automatically attempted. Note that the payment, while automatic, does not happen exactly at the time of invoice creation. If you have configured webhooks, the invoice will wait until one hour after the last webhook is successfully sent (or the last webhook times out after failing).
Any customer credit on the account is applied before determining how much is due for that invoice (the amount that will be actually charged). If the amount due for the invoice is less than 50 cents (the minimum for a charge), we add the amount to the customer's running account balance to be added to the next invoice. If this amount is negative, it will act as a credit to offset the next invoice. Note that the customer account balance does not include unpaid invoices; it only includes balances that need to be taken into account when calculating the amount due for the next invoice.
Stripe documentation: https://stripe.com/docs/api?lang=python#invoices
djstripe.models.billing.Invoice.charge
djstripe.models.billing.Invoice.customer
djstripe.models.billing.Invoice.default_payment_method
djstripe.models.billing.Invoice.default_source
djstripe.models.billing.Invoice.default_tax_rates
djstripe.models.billing.Invoice.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.Invoice.payment_intent
djstripe.models.billing.Invoice.subscription
djstripe.models.billing.Invoice.DoesNotExist
djstripe.models.billing.Invoice.MultipleObjectsReturned
djstripe.models.billing.Invoice.get_billing_reason_display(self, *, field=<djstripe.fields.StripeEnumField: billing_reason>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_collection_method_display(self, *, field=<djstripe.fields.StripeEnumField: collection_method>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_customer_tax_exempt_display(self, *, field=<djstripe.fields.StripeEnumField: customer_tax_exempt>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_next_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_next_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_previous_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_previous_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Invoice.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem
Sometimes you want to add a charge or credit to a customer but only actually charge the customer's card at the end of a regular billing cycle. This is useful for combining several charges to minimize per-transaction fees or having Stripe tabulate your usage-based billing totals.
Stripe documentation: https://stripe.com/docs/api?lang=python#invoiceitems
djstripe.models.billing.InvoiceItem.amount
djstripe.models.billing.InvoiceItem.currency
djstripe.models.billing.InvoiceItem.customer
djstripe.models.billing.InvoiceItem.date
djstripe.models.billing.InvoiceItem.discountable
djstripe.models.billing.InvoiceItem.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.InvoiceItem.invoice
djstripe.models.billing.InvoiceItem.period
djstripe.models.billing.InvoiceItem.period_end
djstripe.models.billing.InvoiceItem.period_start
djstripe.models.billing.InvoiceItem.plan
djstripe.models.billing.InvoiceItem.price
djstripe.models.billing.InvoiceItem.proration
djstripe.models.billing.InvoiceItem.quantity
djstripe.models.billing.InvoiceItem.subscription
djstripe.models.billing.InvoiceItem.tax_rates
djstripe.models.billing.InvoiceItem.unit_amount
djstripe.models.billing.InvoiceItem.unit_amount_decimal
djstripe.models.billing.InvoiceItem.DoesNotExist
djstripe.models.billing.InvoiceItem.MultipleObjectsReturned
djstripe.models.billing.InvoiceItem.stripe_class
djstripe.models.billing.InvoiceItem.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
return self.description
djstripe.models.billing.InvoiceItem.api_retrieve(self, *args, **kwargs)
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string :param stripe_account: The optional connected account for which this request is being made. :type stripe_account: string
Source code in djstripe/models/billing.py
def api_retrieve(self, *args, **kwargs):
if "-il_" in self.id:
warnings.warn(
f"Attempting to retrieve InvoiceItem with id={self.id!r}"
" will most likely fail. "
"Run manage.py djstripe_update_invoiceitem_ids if this is a problem."
)
return super().api_retrieve(*args, **kwargs)
djstripe.models.billing.InvoiceItem.get_next_by_date(self, *, field=<djstripe.fields.StripeDateTimeField: date>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_next_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_next_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_previous_by_date(self, *, field=<djstripe.fields.StripeDateTimeField: date>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_previous_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_previous_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.InvoiceItem.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/models/billing.py
def get_stripe_dashboard_url(self):
return self.invoice.get_stripe_dashboard_url()
djstripe.models.billing.InvoiceItem.is_valid_object(data)
classmethod
Returns whether the data is a valid object for the class
Source code in djstripe/models/billing.py
@classmethod
def is_valid_object(cls, data):
return "object" in data and data["object"] in ("invoiceitem", "line_item")
djstripe.models.billing.Plan
A subscription plan contains the pricing information for different products and feature levels on your site.
Stripe documentation: https://stripe.com/docs/api/plans
NOTE: The Stripe Plans API has been deprecated in favor of the Prices API. You may want to upgrade to use the Price model instead of the Plan model.
djstripe.models.billing.Plan.active
djstripe.models.billing.Plan.aggregate_usage
djstripe.models.billing.Plan.amount
djstripe.models.billing.Plan.amount_decimal
djstripe.models.billing.Plan.amount_in_cents
property
readonly
djstripe.models.billing.Plan.billing_scheme
djstripe.models.billing.Plan.currency
djstripe.models.billing.Plan.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.Plan.expand_fields: List[str]
djstripe.models.billing.Plan.human_readable_price
property
readonly
djstripe.models.billing.Plan.interval
djstripe.models.billing.Plan.interval_count
djstripe.models.billing.Plan.nickname
djstripe.models.billing.Plan.product
djstripe.models.billing.Plan.stripe_dashboard_item_name
djstripe.models.billing.Plan.tiers
djstripe.models.billing.Plan.tiers_mode
djstripe.models.billing.Plan.transform_usage
djstripe.models.billing.Plan.trial_period_days
djstripe.models.billing.Plan.usage_type
djstripe.models.billing.Plan.DoesNotExist
djstripe.models.billing.Plan.MultipleObjectsReturned
djstripe.models.billing.Plan.stripe_class
djstripe.models.billing.Plan.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
from .billing import Subscription
subscriptions = Subscription.objects.filter(plan__id=self.id).count()
if self.product and self.product.name:
return f"{self.human_readable_price} for {self.product.name} ({subscriptions} subscriptions)"
return f"{self.human_readable_price} ({subscriptions} subscriptions)"
djstripe.models.billing.Plan.create(**kwargs)
classmethod
Source code in djstripe/models/billing.py
@classmethod
def create(cls, **kwargs):
# A few minor things are changed in the api-version of the create call
api_kwargs = dict(kwargs)
api_kwargs["amount"] = int(api_kwargs["amount"] * 100)
if isinstance(api_kwargs.get("product"), StripeModel):
api_kwargs["product"] = api_kwargs["product"].id
stripe_plan = cls._api_create(**api_kwargs)
plan = cls.sync_from_stripe_data(stripe_plan)
return plan
djstripe.models.billing.Plan.get_aggregate_usage_display(self, *, field=<djstripe.fields.StripeEnumField: aggregate_usage>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_billing_scheme_display(self, *, field=<djstripe.fields.StripeEnumField: billing_scheme>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_interval_display(self, *, field=<djstripe.fields.StripeEnumField: interval>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_or_create(**kwargs)
classmethod
Get or create a Plan.
Source code in djstripe/models/billing.py
@classmethod
def get_or_create(cls, **kwargs):
"""Get or create a Plan."""
try:
return Plan.objects.get(id=kwargs["id"]), False
except Plan.DoesNotExist:
return cls.create(**kwargs), True
djstripe.models.billing.Plan.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_tiers_mode_display(self, *, field=<djstripe.fields.StripeEnumField: tiers_mode>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Plan.get_usage_type_display(self, *, field=<djstripe.fields.StripeEnumField: usage_type>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription
Subscriptions allow you to charge a customer's card on a recurring basis. A subscription ties a customer to a particular plan you've created.
A subscription still in its trial period is trialing
and moves to active
when the trial period is over.
When payment to renew the subscription fails, the subscription becomes past_due
.
After Stripe has exhausted all payment retry attempts, the subscription ends up
with a status of either canceled
or unpaid
depending on your retry settings.
Note that when a subscription has a status of unpaid
, no subsequent invoices
will be attempted (invoices will be created, but then immediately
automatically closed.
Additionally, updating customer card details will not lead to Stripe retrying the latest invoice.). After receiving updated card details from a customer, you may choose to reopen and pay their closed invoices.
Stripe documentation: https://stripe.com/docs/api?lang=python#subscriptions
djstripe.models.billing.Subscription.application_fee_percent
djstripe.models.billing.Subscription.billing_cycle_anchor
djstripe.models.billing.Subscription.billing_thresholds
djstripe.models.billing.Subscription.cancel_at
djstripe.models.billing.Subscription.cancel_at_period_end
djstripe.models.billing.Subscription.canceled_at
djstripe.models.billing.Subscription.collection_method
djstripe.models.billing.Subscription.current_period_end
djstripe.models.billing.Subscription.current_period_start
djstripe.models.billing.Subscription.customer
djstripe.models.billing.Subscription.days_until_due
djstripe.models.billing.Subscription.default_payment_method
djstripe.models.billing.Subscription.default_source
djstripe.models.billing.Subscription.default_tax_rates
djstripe.models.billing.Subscription.discount
djstripe.models.billing.Subscription.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.Subscription.ended_at
djstripe.models.billing.Subscription.latest_invoice
djstripe.models.billing.Subscription.next_pending_invoice_item_invoice
djstripe.models.billing.Subscription.objects
djstripe.models.billing.Subscription.pending_invoice_item_interval
djstripe.models.billing.Subscription.pending_setup_intent
djstripe.models.billing.Subscription.pending_update
djstripe.models.billing.Subscription.plan
djstripe.models.billing.Subscription.quantity
djstripe.models.billing.Subscription.schedule
djstripe.models.billing.Subscription.start_date
djstripe.models.billing.Subscription.status
djstripe.models.billing.Subscription.stripe_dashboard_item_name
djstripe.models.billing.Subscription.trial_end
djstripe.models.billing.Subscription.trial_start
djstripe.models.billing.Subscription.DoesNotExist
djstripe.models.billing.Subscription.MultipleObjectsReturned
djstripe.models.billing.Subscription.stripe_class
djstripe.models.billing.Subscription.stripe_class.OBJECT_NAME
djstripe.models.billing.Subscription.stripe_class.delete_discount(self, **params)
Source code in djstripe/models/billing.py
def delete_discount(self, **params):
requestor = api_requestor.APIRequestor(
self.api_key,
api_version=self.stripe_version,
account=self.stripe_account,
)
url = self.instance_url() + "/discount"
_, api_key = requestor.request("delete", url, params)
self.refresh_from({"discount": None}, api_key, True)
djstripe.models.billing.Subscription.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
subscriptions_lst = self.customer._get_valid_subscriptions()
products_lst = [
subscription.plan.product.name
for subscription in subscriptions_lst
if subscription and subscription.plan
]
return f"{self.customer} on {' and '.join(products_lst)}"
djstripe.models.billing.Subscription.cancel(self, at_period_end=True)
Cancels this subscription. If you set the at_period_end parameter to true, the subscription will remain active until the end of the period, at which point it will be canceled and not renewed. By default, the subscription is terminated immediately. In either case, the customer will not be charged again for the subscription. Note, however, that any pending invoice items that you've created will still be charged for at the end of the period unless manually deleted. If you've set the subscription to cancel at period end, any pending prorations will also be left in place and collected at the end of the period, but if the subscription is set to cancel immediately, pending prorations will be removed.
By default, all unpaid invoices for the customer will be closed upon subscription cancellation. We do this in order to prevent unexpected payment retries once the customer has canceled a subscription. However, you can reopen the invoices manually after subscription cancellation to have us proceed with automatic retries, or you could even re-attempt payment yourself on all unpaid invoices before allowing the customer to cancel the subscription at all.
:param at_period_end: A flag that if set to true will delay the cancellation of the subscription until the end of the current period. Default is False. :type at_period_end: boolean
.. important:: If a subscription is canceled during a trial period, the at_period_end
flag will be overridden to False so that the trial ends immediately and the customer's card isn't charged.
Source code in djstripe/models/billing.py
def cancel(self, at_period_end=djstripe_settings.CANCELLATION_AT_PERIOD_END):
"""
Cancels this subscription. If you set the at_period_end parameter to true,
the subscription will remain active until the end of the period, at which point
it will be canceled and not renewed. By default, the subscription is terminated
immediately. In either case, the customer will not be charged again for
the subscription. Note, however, that any pending invoice items that you've
created will still be charged for at the end of the period unless manually
deleted. If you've set the subscription to cancel at period end,
any pending prorations will also be left in place and collected at the end of
the period, but if the subscription is set to cancel immediately,
pending prorations will be removed.
By default, all unpaid invoices for the customer will be closed upon
subscription cancellation. We do this in order to prevent unexpected payment
retries once the customer has canceled a subscription. However, you can
reopen the invoices manually after subscription cancellation to have us proceed
with automatic retries, or you could even re-attempt payment yourself on all
unpaid invoices before allowing the customer to cancel the
subscription at all.
:param at_period_end: A flag that if set to true will delay the cancellation \
of the subscription until the end of the current period. Default is False.
:type at_period_end: boolean
.. important:: If a subscription is canceled during a trial period, \
the ``at_period_end`` flag will be overridden to False so that the trial ends \
immediately and the customer's card isn't charged.
"""
# If plan has trial days and customer cancels before
# trial period ends, then end subscription now,
# i.e. at_period_end=False
if self.trial_end and self.trial_end > timezone.now():
at_period_end = False
if at_period_end:
stripe_subscription = self._api_update(cancel_at_period_end=True)
else:
try:
stripe_subscription = self._api_delete()
except InvalidRequestError as exc:
if "No such subscription:" in str(exc):
# cancel() works by deleting the subscription. The object still
# exists in Stripe however, and can still be retrieved.
# If the subscription was already canceled (status=canceled),
# that api_retrieve() call will fail with "No such subscription".
# However, this may also happen if the subscription legitimately
# does not exist, in which case the following line will re-raise.
stripe_subscription = self.api_retrieve()
else:
raise
return Subscription.sync_from_stripe_data(stripe_subscription)
djstripe.models.billing.Subscription.extend(self, delta)
Extends this subscription by the provided delta.
:param delta: The timedelta by which to extend this subscription. :type delta: timedelta
Source code in djstripe/models/billing.py
def extend(self, delta):
"""
Extends this subscription by the provided delta.
:param delta: The timedelta by which to extend this subscription.
:type delta: timedelta
"""
if delta.total_seconds() < 0:
raise ValueError("delta must be a positive timedelta.")
if self.trial_end is not None and self.trial_end > timezone.now():
period_end = self.trial_end
else:
period_end = self.current_period_end
period_end += delta
return self.update(proration_behavior="none", trial_end=period_end)
djstripe.models.billing.Subscription.get_collection_method_display(self, *, field=<djstripe.fields.StripeEnumField: collection_method>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_next_by_current_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_end>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_next_by_current_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_start>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_previous_by_current_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_end>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_previous_by_current_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: current_period_start>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.Subscription.is_period_current(self)
Returns True if this subscription's period is current, false otherwise.
Source code in djstripe/models/billing.py
def is_period_current(self):
"""
Returns True if this subscription's period is current, false otherwise.
"""
return self.current_period_end > timezone.now() or (
self.trial_end and self.trial_end > timezone.now()
)
djstripe.models.billing.Subscription.is_status_current(self)
Returns True if this subscription's status is current (active or trialing), false otherwise.
Source code in djstripe/models/billing.py
def is_status_current(self):
"""
Returns True if this subscription's status is current (active or trialing),
false otherwise.
"""
return self.status in ["trialing", "active"]
djstripe.models.billing.Subscription.is_status_temporarily_current(self)
A status is temporarily current when the subscription is canceled with the
at_period_end
flag.
The subscription is still active, but is technically canceled and we're just
waiting for it to run out.
You could use this method to give customers limited service after they've canceled. For example, a video on demand service could only allow customers to download their libraries and do nothing else when their subscription is temporarily current.
Source code in djstripe/models/billing.py
def is_status_temporarily_current(self):
"""
A status is temporarily current when the subscription is canceled with the
``at_period_end`` flag.
The subscription is still active, but is technically canceled and we're just
waiting for it to run out.
You could use this method to give customers limited service after they've
canceled. For example, a video on demand service could only allow customers
to download their libraries and do nothing else when their
subscription is temporarily current.
"""
return (
self.canceled_at
and self.cancel_at_period_end
and timezone.now() < self.current_period_end
)
djstripe.models.billing.Subscription.is_valid(self)
Returns True if this subscription's status and period are current, false otherwise.
Source code in djstripe/models/billing.py
def is_valid(self):
"""
Returns True if this subscription's status and period are current,
false otherwise.
"""
if not self.is_status_current():
return False
if not self.is_period_current():
return False
return True
djstripe.models.billing.Subscription.reactivate(self)
Reactivates this subscription.
If a customer's subscription is canceled with at_period_end
set to True and
it has not yet reached the end of the billing period, it can be reactivated.
Subscriptions canceled immediately cannot be reactivated.
(Source: https://stripe.com/docs/billing/subscriptions/cancel)
.. warning:: Reactivating a fully canceled Subscription will fail silently. Be sure to check the returned Subscription's status.
Source code in djstripe/models/billing.py
def reactivate(self):
"""
Reactivates this subscription.
If a customer's subscription is canceled with ``at_period_end`` set to True and
it has not yet reached the end of the billing period, it can be reactivated.
Subscriptions canceled immediately cannot be reactivated.
(Source: https://stripe.com/docs/billing/subscriptions/cancel)
.. warning:: Reactivating a fully canceled Subscription will fail silently. \
Be sure to check the returned Subscription's status.
"""
stripe_subscription = self.api_retrieve()
stripe_subscription.plan = self.plan.id
stripe_subscription.cancel_at_period_end = False
return Subscription.sync_from_stripe_data(stripe_subscription.save())
djstripe.models.billing.Subscription.update(self, plan=None, prorate=None, **kwargs)
See Customer.subscribe() <#djstripe.models.Customer.subscribe>
__
:param plan: The plan to which to subscribe the customer. :type plan: Plan or string (plan ID)
.. note:: The default value for prorate
is the DJSTRIPE_PRORATION_POLICY setting.
.. important:: Updating a subscription by changing the plan or quantity creates a new Subscription
in Stripe (and dj-stripe).
Source code in djstripe/models/billing.py
def update(
self,
plan: Union[StripeModel, str] = None,
prorate: bool = None,
**kwargs,
):
"""
See `Customer.subscribe() <#djstripe.models.Customer.subscribe>`__
:param plan: The plan to which to subscribe the customer.
:type plan: Plan or string (plan ID)
.. note:: The default value for ``prorate`` is the DJSTRIPE_PRORATION_POLICY \
setting.
.. important:: Updating a subscription by changing the plan or quantity \
creates a new ``Subscription`` in \
Stripe (and dj-stripe).
"""
# Convert Plan to id
if plan is not None and isinstance(plan, StripeModel):
plan = plan.id
if "proration_behavior" not in kwargs:
if prorate is not None:
warnings.warn(
"The `prorate` parameter to Subscription.update() is deprecated "
"by Stripe. Use `proration_behavior` instead.\n"
"Read more: "
"https://stripe.com/docs/billing/subscriptions/prorations"
)
else:
prorate = djstripe_settings.PRORATION_POLICY
if prorate:
kwargs.setdefault("proration_behavior", "create_prorations")
else:
kwargs.setdefault("proration_behavior", "none")
stripe_subscription = self._api_update(plan=plan, **kwargs)
return Subscription.sync_from_stripe_data(stripe_subscription)
djstripe.models.billing.SubscriptionItem
Subscription items allow you to create customer subscriptions with more than one plan, making it easy to represent complex billing relationships.
Stripe documentation: https://stripe.com/docs/api#subscription_items
djstripe.models.billing.SubscriptionItem.billing_thresholds
djstripe.models.billing.SubscriptionItem.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.SubscriptionItem.plan
djstripe.models.billing.SubscriptionItem.price
djstripe.models.billing.SubscriptionItem.quantity
djstripe.models.billing.SubscriptionItem.subscription
djstripe.models.billing.SubscriptionItem.tax_rates
djstripe.models.billing.SubscriptionItem.DoesNotExist
djstripe.models.billing.SubscriptionItem.MultipleObjectsReturned
djstripe.models.billing.SubscriptionItem.stripe_class
djstripe.models.billing.SubscriptionItem.stripe_class.OBJECT_NAME
djstripe.models.billing.SubscriptionItem.stripe_class.create_usage_record(id, **params)
classmethod
Source code in djstripe/models/billing.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.billing.SubscriptionItem.stripe_class.list_usage_record_summaries(id, **params)
classmethod
Source code in djstripe/models/billing.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.billing.SubscriptionItem.stripe_class.usage_record_summaries(self, **params)
usage_record_summaries is deprecated, use SubscriptionItem.list_usage_record_summaries instead.
Source code in djstripe/models/billing.py
def usage_record_summaries(self, **params):
"""usage_record_summaries is deprecated, use SubscriptionItem.list_usage_record_summaries instead."""
return self.request(
"get", self.instance_url() + "/usage_record_summaries", params
)
djstripe.models.billing.SubscriptionItem.stripe_class.usage_record_summarys_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/billing.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.billing.SubscriptionItem.stripe_class.usage_record_summarys_url(id, nested_id=None)
classmethod
Source code in djstripe/models/billing.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.billing.SubscriptionItem.stripe_class.usage_records_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/billing.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.billing.SubscriptionItem.stripe_class.usage_records_url(id, nested_id=None)
classmethod
Source code in djstripe/models/billing.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.billing.SubscriptionItem.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionItem.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionItem.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionItem.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionSchedule
Subscription schedules allow you to create and manage the lifecycle of a subscription by predefining expected changes.
Stripe documentation: https://stripe.com/docs/api/subscription_schedules
djstripe.models.billing.SubscriptionSchedule.billing_thresholds
djstripe.models.billing.SubscriptionSchedule.canceled_at
djstripe.models.billing.SubscriptionSchedule.completed_at
djstripe.models.billing.SubscriptionSchedule.current_phase
djstripe.models.billing.SubscriptionSchedule.customer
djstripe.models.billing.SubscriptionSchedule.default_settings
djstripe.models.billing.SubscriptionSchedule.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.SubscriptionSchedule.end_behavior
djstripe.models.billing.SubscriptionSchedule.phases
djstripe.models.billing.SubscriptionSchedule.released_at
djstripe.models.billing.SubscriptionSchedule.released_subscription
djstripe.models.billing.SubscriptionSchedule.status
djstripe.models.billing.SubscriptionSchedule.DoesNotExist
djstripe.models.billing.SubscriptionSchedule.MultipleObjectsReturned
djstripe.models.billing.SubscriptionSchedule.stripe_class
djstripe.models.billing.SubscriptionSchedule.stripe_class.OBJECT_NAME
djstripe.models.billing.SubscriptionSchedule.stripe_class.cancel(self, idempotency_key=None, **params)
Source code in djstripe/models/billing.py
def cancel(self, idempotency_key=None, **params):
url = self.instance_url() + "/cancel"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.billing.SubscriptionSchedule.stripe_class.release(self, idempotency_key=None, **params)
Source code in djstripe/models/billing.py
def release(self, idempotency_key=None, **params):
url = self.instance_url() + "/release"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.billing.SubscriptionSchedule.get_end_behavior_display(self, *, field=<djstripe.fields.StripeEnumField: end_behavior>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionSchedule.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionSchedule.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionSchedule.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionSchedule.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.SubscriptionSchedule.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxId
Add one or multiple tax IDs to a customer. A customer's tax IDs are displayed on invoices and credit notes issued for the customer.
Stripe documentation: https://stripe.com/docs/api/customer_tax_ids
djstripe.models.billing.TaxId.country
djstripe.models.billing.TaxId.customer
djstripe.models.billing.TaxId.description
djstripe.models.billing.TaxId.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.TaxId.metadata
djstripe.models.billing.TaxId.type
djstripe.models.billing.TaxId.value
djstripe.models.billing.TaxId.verification
djstripe.models.billing.TaxId.DoesNotExist
djstripe.models.billing.TaxId.MultipleObjectsReturned
djstripe.models.billing.TaxId.stripe_class
djstripe.models.billing.TaxId.stripe_class.OBJECT_NAME
djstripe.models.billing.TaxId.stripe_class.instance_url(self)
Source code in djstripe/models/billing.py
def instance_url(self):
token = util.utf8(self.id)
customer = util.utf8(self.customer)
base = Customer.class_url()
cust_extn = quote_plus(customer)
extn = quote_plus(token)
return "%s/%s/tax_ids/%s" % (base, cust_extn, extn)
djstripe.models.billing.TaxId.stripe_class.retrieve(id, api_key=None, **params)
classmethod
Source code in djstripe/models/billing.py
@classmethod
def retrieve(cls, id, api_key=None, **params):
raise NotImplementedError(
"Can't retrieve a tax id without a customer ID. Use customer.retrieve_tax_id('tax_id')"
)
djstripe.models.billing.TaxId.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
return f"{enums.TaxIdType.humanize(self.type)} {self.value} ({self.verification.get('status')})"
djstripe.models.billing.TaxId.api_list(api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', **kwargs)
classmethod
Call the stripe API's list operation for this model. :param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string See Stripe documentation for accepted kwargs for each object. :returns: an iterator over all items in the query
Source code in djstripe/models/billing.py
@classmethod
def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
"""
Call the stripe API's list operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
See Stripe documentation for accepted kwargs for each object.
:returns: an iterator over all items in the query
"""
return stripe.Customer.list_tax_ids(
api_key=api_key, **kwargs
).auto_paging_iter()
djstripe.models.billing.TaxId.api_retrieve(self, api_key=None, stripe_account=None)
Call the stripe API's retrieve operation for this model. :param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string :param stripe_account: The optional connected account for which this request is being made. :type stripe_account: string
Source code in djstripe/models/billing.py
def api_retrieve(self, api_key=None, stripe_account=None):
"""
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
:param stripe_account: The optional connected account \
for which this request is being made.
:type stripe_account: string
"""
nested_id = self.id
id = self.customer.id
# Prefer passed in stripe_account if set.
if not stripe_account:
stripe_account = self._get_stripe_account_id(api_key)
return stripe.Customer.retrieve_tax_id(
id=id,
nested_id=nested_id,
api_key=api_key or self.default_api_key,
expand=self.expand_fields,
stripe_account=stripe_account,
)
djstripe.models.billing.TaxId.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxId.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxId.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxId.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxId.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxRate
Tax rates can be applied to invoices and subscriptions to collect tax.
Stripe documentation: https://stripe.com/docs/api/tax_rates
djstripe.models.billing.TaxRate.active
djstripe.models.billing.TaxRate.display_name
djstripe.models.billing.TaxRate.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.TaxRate.inclusive
djstripe.models.billing.TaxRate.jurisdiction
djstripe.models.billing.TaxRate.percentage
djstripe.models.billing.TaxRate.DoesNotExist
djstripe.models.billing.TaxRate.MultipleObjectsReturned
djstripe.models.billing.TaxRate.stripe_class
djstripe.models.billing.TaxRate.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
return f"{self.display_name} – {self.jurisdiction} at {self.percentage}%"
djstripe.models.billing.TaxRate.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxRate.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxRate.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.TaxRate.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice
The preview of an upcoming invoice - does not exist in the Django database.
See BaseInvoice.upcoming()
Logically it should be set abstract, but that doesn't quite work since we do actually want to instantiate the model and use relations.
djstripe.models.billing.UpcomingInvoice.charge
djstripe.models.billing.UpcomingInvoice.customer
djstripe.models.billing.UpcomingInvoice.default_payment_method
djstripe.models.billing.UpcomingInvoice.default_source
djstripe.models.billing.UpcomingInvoice.default_tax_rates
property
readonly
Gets the default tax rates associated with this upcoming invoice. :return:
djstripe.models.billing.UpcomingInvoice.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.UpcomingInvoice.id
property
writable
djstripe.models.billing.UpcomingInvoice.invoiceitems
property
readonly
Gets the invoice items associated with this upcoming invoice.
This differs from normal (non-upcoming) invoices, in that upcoming invoices are in-memory and do not persist to the database. Therefore, all of the data comes from the Stripe API itself.
Instead of returning a normal queryset for the invoiceitems, this will return a mock of a queryset, but with the data fetched from Stripe - It will act like a normal queryset, but mutation will silently fail.
djstripe.models.billing.UpcomingInvoice.payment_intent
djstripe.models.billing.UpcomingInvoice.subscription
djstripe.models.billing.UpcomingInvoice.total_tax_amounts
property
readonly
Gets the total tax amounts associated with this upcoming invoice. :return:
djstripe.models.billing.UpcomingInvoice.DoesNotExist
djstripe.models.billing.UpcomingInvoice.MultipleObjectsReturned
djstripe.models.billing.UpcomingInvoice.__init__(self, *args, **kwargs)
special
Source code in djstripe/models/billing.py
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._invoiceitems = []
self._default_tax_rates = []
self._total_tax_amounts = []
djstripe.models.billing.UpcomingInvoice.get_billing_reason_display(self, *, field=<djstripe.fields.StripeEnumField: billing_reason>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_collection_method_display(self, *, field=<djstripe.fields.StripeEnumField: collection_method>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_customer_tax_exempt_display(self, *, field=<djstripe.fields.StripeEnumField: customer_tax_exempt>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_next_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_next_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_previous_by_period_end(self, *, field=<djstripe.fields.StripeDateTimeField: period_end>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_previous_by_period_start(self, *, field=<djstripe.fields.StripeDateTimeField: period_start>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UpcomingInvoice.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/models/billing.py
def get_stripe_dashboard_url(self):
return ""
djstripe.models.billing.UpcomingInvoice.save(self, *args, **kwargs)
Save the current instance. Override this in a subclass if you want to control the saving process.
The 'force_insert' and 'force_update' parameters can be used to insist that the "save" must be an SQL insert or update (or equivalent for non-SQL backends), respectively. Normally, they should not be set.
Source code in djstripe/models/billing.py
def save(self, *args, **kwargs):
return # noop
djstripe.models.billing.UsageRecord
Usage records allow you to continually report usage and metrics to Stripe for metered billing of plans.
Stripe documentation: https://stripe.com/docs/api#usage_records
djstripe.models.billing.UsageRecord.action
djstripe.models.billing.UsageRecord.description
djstripe.models.billing.UsageRecord.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.UsageRecord.metadata
djstripe.models.billing.UsageRecord.quantity
djstripe.models.billing.UsageRecord.subscription_item
djstripe.models.billing.UsageRecord.timestamp
djstripe.models.billing.UsageRecord.DoesNotExist
djstripe.models.billing.UsageRecord.MultipleObjectsReturned
djstripe.models.billing.UsageRecord.stripe_class
djstripe.models.billing.UsageRecord.stripe_class.OBJECT_NAME
djstripe.models.billing.UsageRecord.stripe_class.create(api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/billing.py
@classmethod
def create(
cls,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
if "subscription_item" not in params:
raise ValueError("Params must have a subscription_item key")
subscription_item = params.pop("subscription_item")
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
url = "/v1/subscription_items/%s/usage_records" % subscription_item
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request("post", url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.billing.UsageRecord.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
return f"Usage for {self.subscription_item} ({self.action}) is {self.quantity}"
djstripe.models.billing.UsageRecord.create(**kwargs)
classmethod
A wrapper around _api_create() to allow one to create and sync UsageRecord Objects
Source code in djstripe/models/billing.py
@classmethod
def create(cls, **kwargs):
"""
A wrapper around _api_create() to allow one to create and sync UsageRecord Objects
"""
return cls._api_create(**kwargs)
djstripe.models.billing.UsageRecord.get_action_display(self, *, field=<djstripe.fields.StripeEnumField: action>)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecord.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecord.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecord.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecord.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecordSummary
Usage record summaries provides usage information that’s been summarized from multiple usage records and over a subscription billing period (e.g., 15 usage records in the month of September). Since new usage records can still be added, the returned summary information for the subscription item’s ID should be seen as unstable until the subscription billing period ends.
Stripe documentation: https://stripe.com/docs/api/usage_records/subscription_item_summary_list
djstripe.models.billing.UsageRecordSummary.description
djstripe.models.billing.UsageRecordSummary.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.billing.UsageRecordSummary.invoice
djstripe.models.billing.UsageRecordSummary.metadata
djstripe.models.billing.UsageRecordSummary.period
djstripe.models.billing.UsageRecordSummary.period_end
djstripe.models.billing.UsageRecordSummary.period_start
djstripe.models.billing.UsageRecordSummary.subscription_item
djstripe.models.billing.UsageRecordSummary.total_usage
djstripe.models.billing.UsageRecordSummary.DoesNotExist
djstripe.models.billing.UsageRecordSummary.MultipleObjectsReturned
djstripe.models.billing.UsageRecordSummary.stripe_class
djstripe.models.billing.UsageRecordSummary.__str__(self)
special
Source code in djstripe/models/billing.py
def __str__(self):
return f"Usage Summary for {self.subscription_item} ({self.invoice}) is {self.total_usage}"
djstripe.models.billing.UsageRecordSummary.api_list(api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', **kwargs)
classmethod
Call the stripe API's list operation for this model.
:param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string
See Stripe documentation for accepted kwargs for each object.
:returns: an iterator over all items in the query
Source code in djstripe/models/billing.py
@classmethod
def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
"""
Call the stripe API's list operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
See Stripe documentation for accepted kwargs for each object.
:returns: an iterator over all items in the query
"""
if not kwargs.get("id"):
raise KeyError("SubscriptionItem Object ID is missing")
try:
SubscriptionItem.objects.get(id=kwargs["id"])
except SubscriptionItem.DoesNotExist:
raise
return stripe.SubscriptionItem.list_usage_record_summaries(
api_key=api_key, **kwargs
).auto_paging_iter()
djstripe.models.billing.UsageRecordSummary.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecordSummary.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecordSummary.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.billing.UsageRecordSummary.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/billing.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.checkout
Classes
djstripe.models.checkout.Session
A Checkout Session represents your customer's session as they pay for one-time purchases or subscriptions through Checkout.
djstripe.models.checkout.Session.billing_address_collection
djstripe.models.checkout.Session.cancel_url
djstripe.models.checkout.Session.client_reference_id
djstripe.models.checkout.Session.customer
djstripe.models.checkout.Session.customer_email
djstripe.models.checkout.Session.display_items
djstripe.models.checkout.Session.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.checkout.Session.locale
djstripe.models.checkout.Session.mode
djstripe.models.checkout.Session.payment_intent
djstripe.models.checkout.Session.payment_method_types
djstripe.models.checkout.Session.submit_type
djstripe.models.checkout.Session.subscription
djstripe.models.checkout.Session.success_url
djstripe.models.checkout.Session.DoesNotExist
djstripe.models.checkout.Session.MultipleObjectsReturned
djstripe.models.checkout.Session.stripe_class
djstripe.models.checkout.Session.stripe_class.OBJECT_NAME
djstripe.models.checkout.Session.stripe_class.expire(self, idempotency_key=None, **params)
Source code in djstripe/models/checkout.py
def expire(self, idempotency_key=None, **params):
url = self.instance_url() + "/expire"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.checkout.Session.stripe_class.line_items_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/checkout.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.checkout.Session.stripe_class.line_items_url(id, nested_id=None)
classmethod
Source code in djstripe/models/checkout.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.checkout.Session.stripe_class.list_line_items(id, **params)
classmethod
Source code in djstripe/models/checkout.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.checkout.Session.get_billing_address_collection_display(self, *, field=<djstripe.fields.StripeEnumField: billing_address_collection>)
Source code in djstripe/models/checkout.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.checkout.Session.get_mode_display(self, *, field=<djstripe.fields.StripeEnumField: mode>)
Source code in djstripe/models/checkout.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.checkout.Session.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/checkout.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.checkout.Session.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/checkout.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.checkout.Session.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/checkout.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.checkout.Session.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/checkout.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.checkout.Session.get_submit_type_display(self, *, field=<djstripe.fields.StripeEnumField: submit_type>)
Source code in djstripe/models/checkout.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect
Classes
djstripe.models.connect.ApplicationFee
When you collect a transaction fee on top of a charge made for your user (using Connect), an ApplicationFee is created in your account.
Please note the model field charge exists on the Stripe Connected Account while the application_fee modelfield on Charge model exists on the Platform Account!
Stripe documentation: https://stripe.com/docs/api#application_fees
djstripe.models.connect.ApplicationFee.account
djstripe.models.connect.ApplicationFee.amount
djstripe.models.connect.ApplicationFee.amount_refunded
djstripe.models.connect.ApplicationFee.balance_transaction
djstripe.models.connect.ApplicationFee.charge
djstripe.models.connect.ApplicationFee.currency
djstripe.models.connect.ApplicationFee.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.connect.ApplicationFee.refunded
djstripe.models.connect.ApplicationFee.DoesNotExist
djstripe.models.connect.ApplicationFee.MultipleObjectsReturned
djstripe.models.connect.ApplicationFee.stripe_class
djstripe.models.connect.ApplicationFee.stripe_class.OBJECT_NAME
djstripe.models.connect.ApplicationFee.stripe_class.create_refund(id, **params)
classmethod
Source code in djstripe/models/connect.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.connect.ApplicationFee.stripe_class.list_refunds(id, **params)
classmethod
Source code in djstripe/models/connect.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.connect.ApplicationFee.stripe_class.modify_refund(id, nested_id, **params)
classmethod
Source code in djstripe/models/connect.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.connect.ApplicationFee.stripe_class.refund(self, idempotency_key=None, **params)
Source code in djstripe/models/connect.py
def refund(self, idempotency_key=None, **params):
headers = util.populate_headers(idempotency_key)
url = self.instance_url() + "/refund"
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.connect.ApplicationFee.stripe_class.refunds_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/connect.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.connect.ApplicationFee.stripe_class.refunds_url(id, nested_id=None)
classmethod
Source code in djstripe/models/connect.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.connect.ApplicationFee.stripe_class.retrieve_refund(id, nested_id, **params)
classmethod
Source code in djstripe/models/connect.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.connect.ApplicationFee.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.ApplicationFee.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.ApplicationFee.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.ApplicationFee.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.ApplicationFeeRefund
ApplicationFeeRefund objects allow you to refund an ApplicationFee that has previously been created but not yet refunded. Funds will be refunded to the Stripe account from which the fee was originally collected.
Stripe documentation: https://stripe.com/docs/api#fee_refunds
djstripe.models.connect.ApplicationFeeRefund.amount
djstripe.models.connect.ApplicationFeeRefund.balance_transaction
djstripe.models.connect.ApplicationFeeRefund.currency
djstripe.models.connect.ApplicationFeeRefund.description
djstripe.models.connect.ApplicationFeeRefund.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.connect.ApplicationFeeRefund.fee
djstripe.models.connect.ApplicationFeeRefund.DoesNotExist
djstripe.models.connect.ApplicationFeeRefund.MultipleObjectsReturned
djstripe.models.connect.ApplicationFeeRefund.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.ApplicationFeeRefund.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.ApplicationFeeRefund.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.ApplicationFeeRefund.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.CountrySpec
Stripe documentation: https://stripe.com/docs/api#country_specs
djstripe.models.connect.CountrySpec.default_currency
djstripe.models.connect.CountrySpec.id
djstripe.models.connect.CountrySpec.supported_bank_account_currencies
djstripe.models.connect.CountrySpec.supported_payment_currencies
djstripe.models.connect.CountrySpec.supported_payment_methods
djstripe.models.connect.CountrySpec.supported_transfer_countries
djstripe.models.connect.CountrySpec.verification_fields
djstripe.models.connect.CountrySpec.DoesNotExist
djstripe.models.connect.CountrySpec.MultipleObjectsReturned
djstripe.models.connect.CountrySpec.stripe_class
djstripe.models.connect.CountrySpec.api_retrieve(self, api_key=None, stripe_account=None)
Source code in djstripe/models/connect.py
def api_retrieve(self, api_key: str = None, stripe_account=None):
if api_key is None:
api_key = djstripe_settings.get_default_api_key(livemode=None)
return self.stripe_class.retrieve(
id=self.id,
api_key=api_key,
stripe_account=stripe_account,
)
djstripe.models.connect.CountrySpec.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.CountrySpec.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.CountrySpec.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.CountrySpec.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.CountrySpec.sync_from_stripe_data(data)
classmethod
Syncs this object from the stripe data provided.
Foreign keys will also be retrieved and synced recursively.
:param data: stripe object :type data: dict :rtype: cls
Source code in djstripe/models/connect.py
@classmethod
def sync_from_stripe_data(cls, data) -> "CountrySpec":
"""
Syncs this object from the stripe data provided.
Foreign keys will also be retrieved and synced recursively.
:param data: stripe object
:type data: dict
:rtype: cls
"""
data_id = data["id"]
supported_fields = (
"default_currency",
"supported_bank_account_currencies",
"supported_payment_currencies",
"supported_payment_methods",
"supported_transfer_countries",
"verification_fields",
)
instance, created = cls.objects.get_or_create(
id=data_id,
defaults={k: data[k] for k in supported_fields},
)
return instance
djstripe.models.connect.Transfer
When Stripe sends you money or you initiate a transfer to a bank account, debit card, or connected Stripe account, a transfer object will be created.
Stripe documentation: https://stripe.com/docs/api?lang=python#transfers
djstripe.models.connect.Transfer.amount
djstripe.models.connect.Transfer.amount_reversed
djstripe.models.connect.Transfer.balance_transaction
djstripe.models.connect.Transfer.currency
djstripe.models.connect.Transfer.destination
djstripe.models.connect.Transfer.destination_payment
djstripe.models.connect.Transfer.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.connect.Transfer.expand_fields: List[str]
djstripe.models.connect.Transfer.fee
property
readonly
djstripe.models.connect.Transfer.objects
djstripe.models.connect.Transfer.reversed
djstripe.models.connect.Transfer.source_transaction
djstripe.models.connect.Transfer.source_type
djstripe.models.connect.Transfer.stripe_dashboard_item_name
djstripe.models.connect.Transfer.transfer_group
djstripe.models.connect.Transfer.DoesNotExist
djstripe.models.connect.Transfer.MultipleObjectsReturned
djstripe.models.connect.Transfer.stripe_class
djstripe.models.connect.Transfer.stripe_class.OBJECT_NAME
djstripe.models.connect.Transfer.stripe_class.cancel(self, idempotency_key=None, **params)
Source code in djstripe/models/connect.py
def cancel(self, idempotency_key=None, **params):
url = self.instance_url() + "/cancel"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.connect.Transfer.stripe_class.create_reversal(id, **params)
classmethod
Source code in djstripe/models/connect.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.connect.Transfer.stripe_class.list_reversals(id, **params)
classmethod
Source code in djstripe/models/connect.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.connect.Transfer.stripe_class.modify_reversal(id, nested_id, **params)
classmethod
Source code in djstripe/models/connect.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.connect.Transfer.stripe_class.retrieve_reversal(id, nested_id, **params)
classmethod
Source code in djstripe/models/connect.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.connect.Transfer.stripe_class.reversals_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/connect.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.connect.Transfer.stripe_class.reversals_url(id, nested_id=None)
classmethod
Source code in djstripe/models/connect.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.connect.Transfer.__str__(self)
special
Source code in djstripe/models/connect.py
def __str__(self):
if self.reversed:
# Complete Reversal
return f"{self.human_readable_amount} Reversed"
elif self.amount_reversed:
# Partial Reversal
return f"{self.human_readable_amount} Partially Reversed"
# No Reversal
return f"{self.human_readable_amount}"
djstripe.models.connect.Transfer.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.Transfer.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.Transfer.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.Transfer.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.Transfer.get_source_type_display(self, *, field=<djstripe.fields.StripeEnumField: source_type>)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.TransferReversal
Stripe documentation: https://stripe.com/docs/api#transfer_reversals
djstripe.models.connect.TransferReversal.amount
djstripe.models.connect.TransferReversal.balance_transaction
djstripe.models.connect.TransferReversal.currency
djstripe.models.connect.TransferReversal.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.connect.TransferReversal.expand_fields: List[str]
djstripe.models.connect.TransferReversal.transfer
djstripe.models.connect.TransferReversal.DoesNotExist
djstripe.models.connect.TransferReversal.MultipleObjectsReturned
djstripe.models.connect.TransferReversal.stripe_class
djstripe.models.connect.TransferReversal.stripe_class.OBJECT_NAME
djstripe.models.connect.TransferReversal.stripe_class.cancel(self, idempotency_key=None, **params)
Source code in djstripe/models/connect.py
def cancel(self, idempotency_key=None, **params):
url = self.instance_url() + "/cancel"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.connect.TransferReversal.stripe_class.create_reversal(id, **params)
classmethod
Source code in djstripe/models/connect.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.connect.TransferReversal.stripe_class.list_reversals(id, **params)
classmethod
Source code in djstripe/models/connect.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.connect.TransferReversal.stripe_class.modify_reversal(id, nested_id, **params)
classmethod
Source code in djstripe/models/connect.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.connect.TransferReversal.stripe_class.retrieve_reversal(id, nested_id, **params)
classmethod
Source code in djstripe/models/connect.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.connect.TransferReversal.stripe_class.reversals_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/connect.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.connect.TransferReversal.stripe_class.reversals_url(id, nested_id=None)
classmethod
Source code in djstripe/models/connect.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.connect.TransferReversal.__str__(self)
special
Source code in djstripe/models/connect.py
def __str__(self):
return str(self.transfer)
djstripe.models.connect.TransferReversal.api_list(api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', **kwargs)
classmethod
Call the stripe API's list operation for this model. :param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string See Stripe documentation for accepted kwargs for each object. :returns: an iterator over all items in the query
Source code in djstripe/models/connect.py
@classmethod
def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
"""
Call the stripe API's list operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
See Stripe documentation for accepted kwargs for each object.
:returns: an iterator over all items in the query
"""
return stripe.Transfer.list_reversals(
api_key=api_key, **kwargs
).auto_paging_iter()
djstripe.models.connect.TransferReversal.api_retrieve(self, api_key=None, stripe_account=None)
Call the stripe API's retrieve operation for this model. :param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string :param stripe_account: The optional connected account for which this request is being made. :type stripe_account: string
Source code in djstripe/models/connect.py
def api_retrieve(self, api_key=None, stripe_account=None):
"""
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. \
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
:param stripe_account: The optional connected account \
for which this request is being made.
:type stripe_account: string
"""
nested_id = self.id
id = self.transfer.id
# Prefer passed in stripe_account if set.
if not stripe_account:
stripe_account = self._get_stripe_account_id(api_key)
return stripe.Transfer.retrieve_reversal(
id=id,
nested_id=nested_id,
api_key=api_key or self.default_api_key,
expand=self.expand_fields,
stripe_account=stripe_account,
)
djstripe.models.connect.TransferReversal.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.TransferReversal.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.TransferReversal.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.TransferReversal.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/connect.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.connect.TransferReversal.is_valid_object(data)
classmethod
Returns whether the data is a valid object for the class
Source code in djstripe/models/connect.py
@classmethod
def is_valid_object(cls, data):
"""
Returns whether the data is a valid object for the class
"""
return "object" in data and data["object"] == "transfer_reversal"
djstripe.models.core
Classes
djstripe.models.core.BalanceTransaction
A single transaction that updates the Stripe balance.
Stripe documentation: https://stripe.com/docs/api#balance_transaction_object
djstripe.models.core.BalanceTransaction.amount
djstripe.models.core.BalanceTransaction.available_on
djstripe.models.core.BalanceTransaction.currency
djstripe.models.core.BalanceTransaction.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.BalanceTransaction.exchange_rate
djstripe.models.core.BalanceTransaction.fee
djstripe.models.core.BalanceTransaction.fee_details
djstripe.models.core.BalanceTransaction.net
djstripe.models.core.BalanceTransaction.reporting_category
djstripe.models.core.BalanceTransaction.source
djstripe.models.core.BalanceTransaction.status
djstripe.models.core.BalanceTransaction.type
djstripe.models.core.BalanceTransaction.DoesNotExist
djstripe.models.core.BalanceTransaction.MultipleObjectsReturned
djstripe.models.core.BalanceTransaction.stripe_class
djstripe.models.core.BalanceTransaction.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return f"{self.human_readable_amount} ({enums.BalanceTransactionStatus.humanize(self.status)})"
djstripe.models.core.BalanceTransaction.get_next_by_available_on(self, *, field=<djstripe.fields.StripeDateTimeField: available_on>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_previous_by_available_on(self, *, field=<djstripe.fields.StripeDateTimeField: available_on>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_reporting_category_display(self, *, field=<djstripe.fields.StripeEnumField: reporting_category>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_source_class(self)
Source code in djstripe/models/core.py
def get_source_class(self):
try:
return apps.get_model("djstripe", self.type)
except LookupError:
raise
djstripe.models.core.BalanceTransaction.get_source_instance(self)
Source code in djstripe/models/core.py
def get_source_instance(self):
return self.get_source_class().objects.get(id=self.source)
djstripe.models.core.BalanceTransaction.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.BalanceTransaction.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/models/core.py
def get_stripe_dashboard_url(self):
return self.get_source_instance().get_stripe_dashboard_url()
djstripe.models.core.BalanceTransaction.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Charge
To charge a credit or a debit card, you create a charge object. You can retrieve and refund individual charges as well as list all charges. Charges are identified by a unique random ID.
Stripe documentation: https://stripe.com/docs/api?lang=python#charges
djstripe.models.core.Charge.amount
djstripe.models.core.Charge.amount_captured
djstripe.models.core.Charge.amount_refunded
djstripe.models.core.Charge.application
djstripe.models.core.Charge.application_fee
djstripe.models.core.Charge.application_fee_amount
djstripe.models.core.Charge.balance_transaction
djstripe.models.core.Charge.billing_details
djstripe.models.core.Charge.calculated_statement_descriptor
djstripe.models.core.Charge.captured
djstripe.models.core.Charge.currency
djstripe.models.core.Charge.customer
djstripe.models.core.Charge.dispute
djstripe.models.core.Charge.disputed
djstripe.models.core.Charge.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Charge.expand_fields: List[str]
djstripe.models.core.Charge.failure_code
djstripe.models.core.Charge.failure_message
djstripe.models.core.Charge.fee
property
readonly
djstripe.models.core.Charge.fraud_details
djstripe.models.core.Charge.fraudulent: bool
property
readonly
djstripe.models.core.Charge.human_readable_status: str
property
readonly
djstripe.models.core.Charge.invoice
djstripe.models.core.Charge.objects
djstripe.models.core.Charge.on_behalf_of
djstripe.models.core.Charge.outcome
djstripe.models.core.Charge.paid
djstripe.models.core.Charge.payment_intent
djstripe.models.core.Charge.payment_method
djstripe.models.core.Charge.payment_method_details
djstripe.models.core.Charge.receipt_email
djstripe.models.core.Charge.receipt_number
djstripe.models.core.Charge.receipt_url
djstripe.models.core.Charge.refunded
djstripe.models.core.Charge.shipping
djstripe.models.core.Charge.source
djstripe.models.core.Charge.source_transfer
djstripe.models.core.Charge.statement_descriptor
djstripe.models.core.Charge.statement_descriptor_suffix
djstripe.models.core.Charge.status
djstripe.models.core.Charge.stripe_dashboard_item_name
djstripe.models.core.Charge.transfer
djstripe.models.core.Charge.transfer_data
djstripe.models.core.Charge.transfer_group
djstripe.models.core.Charge.DoesNotExist
djstripe.models.core.Charge.MultipleObjectsReturned
djstripe.models.core.Charge.stripe_class
djstripe.models.core.Charge.stripe_class.OBJECT_NAME
djstripe.models.core.Charge.stripe_class.capture(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def capture(self, idempotency_key=None, **params):
url = self.instance_url() + "/capture"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.Charge.stripe_class.close_dispute(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def close_dispute(self, idempotency_key=None, **params):
requestor = api_requestor.APIRequestor(
self.api_key,
api_version=self.stripe_version,
account=self.stripe_account,
)
url = self.instance_url() + "/dispute/close"
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request("post", url, params, headers)
self.refresh_from({"dispute": response}, api_key, True)
return self.dispute
djstripe.models.core.Charge.stripe_class.mark_as_fraudulent(self, idempotency_key=None)
Source code in djstripe/models/core.py
def mark_as_fraudulent(self, idempotency_key=None):
params = {"fraud_details": {"user_report": "fraudulent"}}
url = self.instance_url()
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.Charge.stripe_class.mark_as_safe(self, idempotency_key=None)
Source code in djstripe/models/core.py
def mark_as_safe(self, idempotency_key=None):
params = {"fraud_details": {"user_report": "safe"}}
url = self.instance_url()
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.Charge.stripe_class.refund(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def refund(self, idempotency_key=None, **params):
url = self.instance_url() + "/refund"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.Charge.stripe_class.update_dispute(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def update_dispute(self, idempotency_key=None, **params):
requestor = api_requestor.APIRequestor(
self.api_key,
api_version=self.stripe_version,
account=self.stripe_account,
)
url = self.instance_url() + "/dispute"
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request("post", url, params, headers)
self.refresh_from({"dispute": response}, api_key, True)
return self.dispute
djstripe.models.core.Charge.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
amount = self.human_readable_amount
status = self.human_readable_status
return "{amount} ({status})".format(amount=amount, status=status)
djstripe.models.core.Charge.capture(self, **kwargs)
Capture the payment of an existing, uncaptured, charge. This is the second half of the two-step payment flow, where first you created a charge with the capture option set to False.
See https://stripe.com/docs/api#capture_charge
Source code in djstripe/models/core.py
def capture(self, **kwargs) -> "Charge":
"""
Capture the payment of an existing, uncaptured, charge.
This is the second half of the two-step payment flow, where first you
created a charge with the capture option set to False.
See https://stripe.com/docs/api#capture_charge
"""
captured_charge = self.api_retrieve().capture(**kwargs)
return self.__class__.sync_from_stripe_data(captured_charge)
djstripe.models.core.Charge.get_failure_code_display(self, *, field=<djstripe.fields.StripeEnumField: failure_code>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Charge.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Charge.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Charge.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Charge.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Charge.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Charge.refund(self, amount=None, reason=None)
Initiate a refund. Returns the charge object.
:param amount: A positive decimal amount representing how much of this charge
to refund. If amount is not provided, then this will be a full refund.
Can only refund up to the unrefunded amount remaining of the charge.
:param reason: String indicating the reason for the refund.
If set, possible values are duplicate
, fraudulent
,
and requested_by_customer
. Specifying fraudulent
as the reason
when you believe the charge to be fraudulent will
help Stripe improve their fraud detection algorithms.
Source code in djstripe/models/core.py
def refund(self, amount: Decimal = None, reason: str = None) -> "Charge":
"""
Initiate a refund. Returns the charge object.
:param amount: A positive decimal amount representing how much of this charge
to refund. If amount is not provided, then this will be a full refund.
Can only refund up to the unrefunded amount remaining of the charge.
:param reason: String indicating the reason for the refund.
If set, possible values are ``duplicate``, ``fraudulent``,
and ``requested_by_customer``. Specifying ``fraudulent`` as the reason
when you believe the charge to be fraudulent will
help Stripe improve their fraud detection algorithms.
"""
charge_obj = self.api_retrieve().refund(
amount=self._calculate_refund_amount(amount=amount), reason=reason
)
return self.__class__.sync_from_stripe_data(charge_obj)
djstripe.models.core.Customer
Customer objects allow you to perform recurring charges and track multiple charges that are associated with the same customer.
Stripe documentation: https://stripe.com/docs/api?lang=python#customers
djstripe.models.core.Customer.active_subscriptions
property
readonly
Returns active subscriptions (subscriptions with an active status that end in the future).
djstripe.models.core.Customer.address
djstripe.models.core.Customer.balance
djstripe.models.core.Customer.coupon
djstripe.models.core.Customer.coupon_end
djstripe.models.core.Customer.coupon_start
djstripe.models.core.Customer.credits
property
readonly
The customer is considered to have credits if their balance is below 0.
djstripe.models.core.Customer.currency
djstripe.models.core.Customer.customer_payment_methods
property
readonly
An iterable of all of the customer's payment methods (sources, then legacy cards)
djstripe.models.core.Customer.date_purged
djstripe.models.core.Customer.default_payment_method
djstripe.models.core.Customer.default_source
djstripe.models.core.Customer.deleted
djstripe.models.core.Customer.delinquent
djstripe.models.core.Customer.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Customer.email
djstripe.models.core.Customer.expand_fields: List[str]
djstripe.models.core.Customer.invoice_prefix
djstripe.models.core.Customer.invoice_settings
djstripe.models.core.Customer.name
djstripe.models.core.Customer.pending_charges
property
readonly
The customer is considered to have pending charges if their balance is above 0.
djstripe.models.core.Customer.phone
djstripe.models.core.Customer.preferred_locales
djstripe.models.core.Customer.shipping
djstripe.models.core.Customer.stripe_dashboard_item_name
djstripe.models.core.Customer.subscriber
djstripe.models.core.Customer.subscription
property
readonly
Shortcut to get this customer's subscription.
:returns: None if the customer has no subscriptions, the subscription if
the customer has a subscription.
:raises MultipleSubscriptionException: Raised if the customer has multiple
subscriptions.
In this case, use Customer.subscriptions
instead.
djstripe.models.core.Customer.tax_exempt
djstripe.models.core.Customer.valid_subscriptions
property
readonly
Returns this customer's valid subscriptions (subscriptions that aren't canceled or incomplete_expired).
djstripe.models.core.Customer.DoesNotExist
djstripe.models.core.Customer.MultipleObjectsReturned
djstripe.models.core.Customer.stripe_class
djstripe.models.core.Customer.stripe_class.OBJECT_NAME
djstripe.models.core.Customer.stripe_class.balance_transactions_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/core.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.core.Customer.stripe_class.balance_transactions_url(id, nested_id=None)
classmethod
Source code in djstripe/models/core.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.core.Customer.stripe_class.create_balance_transaction(id, **params)
classmethod
Source code in djstripe/models/core.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.core.Customer.stripe_class.create_source(id, **params)
classmethod
Source code in djstripe/models/core.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.core.Customer.stripe_class.create_tax_id(id, **params)
classmethod
Source code in djstripe/models/core.py
def create_nested_resource(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.core.Customer.stripe_class.delete_discount(self, **params)
Source code in djstripe/models/core.py
def delete_discount(self, **params):
requestor = api_requestor.APIRequestor(
self.api_key,
api_version=self.stripe_version,
account=self.stripe_account,
)
url = self.instance_url() + "/discount"
_, api_key = requestor.request("delete", url, params)
self.refresh_from({"discount": None}, api_key, True)
djstripe.models.core.Customer.stripe_class.delete_source(id, nested_id, **params)
classmethod
Source code in djstripe/models/core.py
def delete_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"delete", url, **params
)
djstripe.models.core.Customer.stripe_class.delete_tax_id(id, nested_id, **params)
classmethod
Source code in djstripe/models/core.py
def delete_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"delete", url, **params
)
djstripe.models.core.Customer.stripe_class.list_balance_transactions(id, **params)
classmethod
Source code in djstripe/models/core.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.core.Customer.stripe_class.list_payment_methods(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def list_payment_methods(self, idempotency_key=None, **params):
url = self.instance_url() + "/payment_methods"
headers = util.populate_headers(idempotency_key)
resp = self.request("get", url, params, headers)
stripe_object = util.convert_to_stripe_object(resp)
stripe_object._retrieve_params = params
return stripe_object
djstripe.models.core.Customer.stripe_class.list_sources(id, **params)
classmethod
Source code in djstripe/models/core.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.core.Customer.stripe_class.list_tax_ids(id, **params)
classmethod
Source code in djstripe/models/core.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.core.Customer.stripe_class.modify_balance_transaction(id, nested_id, **params)
classmethod
Source code in djstripe/models/core.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.core.Customer.stripe_class.modify_source(id, nested_id, **params)
classmethod
Source code in djstripe/models/core.py
def modify_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"post", url, **params
)
djstripe.models.core.Customer.stripe_class.retrieve_balance_transaction(id, nested_id, **params)
classmethod
Source code in djstripe/models/core.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.core.Customer.stripe_class.retrieve_source(id, nested_id, **params)
classmethod
Source code in djstripe/models/core.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.core.Customer.stripe_class.retrieve_tax_id(id, nested_id, **params)
classmethod
Source code in djstripe/models/core.py
def retrieve_nested_resource(cls, id, nested_id, **params):
url = getattr(cls, resource_url_method)(id, nested_id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.core.Customer.stripe_class.sources_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/core.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.core.Customer.stripe_class.sources_url(id, nested_id=None)
classmethod
Source code in djstripe/models/core.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.core.Customer.stripe_class.tax_ids_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/core.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.core.Customer.stripe_class.tax_ids_url(id, nested_id=None)
classmethod
Source code in djstripe/models/core.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.core.Customer.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
if self.subscriber:
return str(self.subscriber)
return self.name or self.description or self.id
djstripe.models.core.Customer.add_card(self, source, set_default=True)
Adds a card to this customer's account.
:param source: Either a token, like the ones returned by our Stripe.js, or a dictionary containing a user's credit card details. Stripe will automatically validate the card. :type source: string, dict :param set_default: Whether or not to set the source as the customer's default source :type set_default: boolean
Source code in djstripe/models/core.py
def add_card(self, source, set_default=True):
"""
Adds a card to this customer's account.
:param source: Either a token, like the ones returned by our Stripe.js, or a
dictionary containing a user's credit card details.
Stripe will automatically validate the card.
:type source: string, dict
:param set_default: Whether or not to set the source as the customer's
default source
:type set_default: boolean
"""
from .payment_methods import DjstripePaymentMethod
stripe_customer = self.api_retrieve()
new_stripe_payment_method = stripe_customer.sources.create(source=source)
if set_default:
stripe_customer.default_source = new_stripe_payment_method["id"]
stripe_customer.save()
new_payment_method = DjstripePaymentMethod.from_stripe_object(
new_stripe_payment_method
)
# Change the default source
if set_default:
self.default_source = new_payment_method
self.save()
return new_payment_method.resolve()
djstripe.models.core.Customer.add_coupon(self, coupon, idempotency_key=None)
Add a coupon to a Customer.
The coupon can be a Coupon object, or a valid Stripe Coupon ID.
Source code in djstripe/models/core.py
def add_coupon(self, coupon, idempotency_key=None):
"""
Add a coupon to a Customer.
The coupon can be a Coupon object, or a valid Stripe Coupon ID.
"""
if isinstance(coupon, StripeModel):
coupon = coupon.id
stripe_customer = self.api_retrieve()
stripe_customer["coupon"] = coupon
stripe_customer.save(idempotency_key=idempotency_key)
return self.__class__.sync_from_stripe_data(stripe_customer)
djstripe.models.core.Customer.add_invoice_item(self, amount, currency, description=None, discountable=None, invoice=None, metadata=None, subscription=None)
Adds an arbitrary charge or credit to the customer's upcoming invoice. Different than creating a charge. Charges are separate bills that get processed immediately. Invoice items are appended to the customer's next invoice. This is extremely useful when adding surcharges to subscriptions.
:param amount: The amount to charge.
:type amount: Decimal. Precision is 2; anything more will be ignored.
:param currency: 3-letter ISO code for currency
:type currency: string
:param description: An arbitrary string.
:type description: string
:param discountable: Controls whether discounts apply to this invoice item.
Defaults to False for prorations or negative invoice items,
and True for all other invoice items.
:type discountable: boolean
:param invoice: An existing invoice to add this invoice item to.
When left blank, the invoice item will be added to the next upcoming scheduled invoice. Use this when adding invoice items in response to an invoice.created
webhook. You cannot add an invoice item to an invoice that has already been paid, attempted or closed.
:type invoice: Invoice or string (invoice ID)
:param metadata: A set of key/value pairs useful for storing
additional information.
:type metadata: dict
:param subscription: A subscription to add this invoice item to.
When left blank, the invoice item will be be added to the next upcoming scheduled invoice. When set, scheduled invoices for subscriptions other than the specified subscription will ignore the invoice item. Use this when you want to express that an invoice item has been accrued within the context of a particular subscription.
:type subscription: Subscription or string (subscription ID)
.. Notes:
.. if you're using Customer.add_invoice_item()
instead of
.. Customer.add_invoice_item()
, invoice
and subscriptions
.. can only be strings
Source code in djstripe/models/core.py
def add_invoice_item(
self,
amount,
currency,
description=None,
discountable=None,
invoice=None,
metadata=None,
subscription=None,
):
"""
Adds an arbitrary charge or credit to the customer's upcoming invoice.
Different than creating a charge. Charges are separate bills that get
processed immediately. Invoice items are appended to the customer's next
invoice. This is extremely useful when adding surcharges to subscriptions.
:param amount: The amount to charge.
:type amount: Decimal. Precision is 2; anything more will be ignored.
:param currency: 3-letter ISO code for currency
:type currency: string
:param description: An arbitrary string.
:type description: string
:param discountable: Controls whether discounts apply to this invoice item.
Defaults to False for prorations or negative invoice items,
and True for all other invoice items.
:type discountable: boolean
:param invoice: An existing invoice to add this invoice item to.
When left blank, the invoice item will be added to the next upcoming \
scheduled invoice. \
Use this when adding invoice items in response to an \
``invoice.created`` webhook. You cannot add an invoice \
item to an invoice that has already been paid, attempted or closed.
:type invoice: Invoice or string (invoice ID)
:param metadata: A set of key/value pairs useful for storing
additional information.
:type metadata: dict
:param subscription: A subscription to add this invoice item to.
When left blank, the invoice item will be be added to the next upcoming \
scheduled invoice. When set, scheduled invoices for subscriptions other \
than the specified subscription will ignore the invoice item. \
Use this when you want to express that an invoice item has been accrued \
within the context of a particular subscription.
:type subscription: Subscription or string (subscription ID)
.. Notes:
.. if you're using ``Customer.add_invoice_item()`` instead of
.. ``Customer.add_invoice_item()``, ``invoice`` and ``subscriptions``
.. can only be strings
"""
from .billing import InvoiceItem
if not isinstance(amount, Decimal):
raise ValueError("You must supply a decimal value representing dollars.")
# Convert Invoice to id
if invoice is not None and isinstance(invoice, StripeModel):
invoice = invoice.id
# Convert Subscription to id
if subscription is not None and isinstance(subscription, StripeModel):
subscription = subscription.id
stripe_invoiceitem = InvoiceItem._api_create(
amount=int(amount * 100), # Convert dollars into cents
currency=currency,
customer=self.id,
description=description,
discountable=discountable,
invoice=invoice,
metadata=metadata,
subscription=subscription,
)
return InvoiceItem.sync_from_stripe_data(stripe_invoiceitem)
djstripe.models.core.Customer.add_payment_method(self, payment_method, set_default=True)
Adds an already existing payment method to this customer's account
:param payment_method: PaymentMethod to be attached to the customer :type payment_method: str, PaymentMethod :param set_default: If true, this will be set as the default_payment_method :type set_default: bool :rtype: PaymentMethod
Source code in djstripe/models/core.py
def add_payment_method(self, payment_method, set_default=True):
"""
Adds an already existing payment method to this customer's account
:param payment_method: PaymentMethod to be attached to the customer
:type payment_method: str, PaymentMethod
:param set_default: If true, this will be set as the default_payment_method
:type set_default: bool
:rtype: PaymentMethod
"""
from .payment_methods import PaymentMethod
stripe_customer = self.api_retrieve()
payment_method = PaymentMethod.attach(payment_method, stripe_customer)
if set_default:
stripe_customer["invoice_settings"][
"default_payment_method"
] = payment_method.id
stripe_customer.save()
# Refresh self from the stripe customer, this should have two effects:
# 1) sets self.default_payment_method (we rely on logic in
# Customer._manipulate_stripe_object_hook to do this)
# 2) updates self.invoice_settings.default_payment_methods
self.sync_from_stripe_data(stripe_customer)
self.refresh_from_db()
return payment_method
djstripe.models.core.Customer.can_charge(self)
Determines if this customer is able to be charged.
Source code in djstripe/models/core.py
def can_charge(self):
"""Determines if this customer is able to be charged."""
return (
self.has_valid_source() or self.default_payment_method is not None
) and self.date_purged is None
djstripe.models.core.Customer.charge(self, amount, *, application_fee=None, source=None, **kwargs)
Creates a charge for this customer.
:param amount: The amount to charge. :type amount: Decimal. Precision is 2; anything more will be ignored. :param source: The source to use for this charge. Must be a source attributed to this customer. If None, the customer's default source is used. Can be either the id of the source or the source object itself. :type source: string, Source
Source code in djstripe/models/core.py
def charge(
self,
amount: Decimal,
*,
application_fee: Decimal = None,
source: Union[str, StripeModel] = None,
**kwargs,
) -> Charge:
"""
Creates a charge for this customer.
:param amount: The amount to charge.
:type amount: Decimal. Precision is 2; anything more will be ignored.
:param source: The source to use for this charge.
Must be a source attributed to this customer. If None, the customer's
default source is used. Can be either the id of the source or
the source object itself.
:type source: string, Source
"""
if not isinstance(amount, Decimal):
raise ValueError("You must supply a decimal value representing dollars.")
# Convert Source to id
if source and isinstance(source, StripeModel):
source = source.id
stripe_charge = Charge._api_create(
customer=self.id,
amount=int(amount * 100), # Convert dollars into cents
application_fee=int(application_fee * 100)
if application_fee
else None, # Convert dollars into cents
source=source,
**kwargs,
)
return Charge.sync_from_stripe_data(stripe_charge)
djstripe.models.core.Customer.create(subscriber, idempotency_key=None, stripe_account=None)
classmethod
Source code in djstripe/models/core.py
@classmethod
def create(cls, subscriber, idempotency_key=None, stripe_account=None):
metadata = {}
subscriber_key = djstripe_settings.SUBSCRIBER_CUSTOMER_KEY
if subscriber_key not in ("", None):
metadata[subscriber_key] = subscriber.pk
stripe_customer = cls._api_create(
email=subscriber.email,
idempotency_key=idempotency_key,
metadata=metadata,
stripe_account=stripe_account,
)
customer, created = Customer.objects.get_or_create(
id=stripe_customer["id"],
defaults={
"subscriber": subscriber,
"livemode": stripe_customer["livemode"],
"balance": stripe_customer.get("balance", 0),
"delinquent": stripe_customer.get("delinquent", False),
},
)
return customer
djstripe.models.core.Customer.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Customer.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Customer.get_or_create(subscriber, livemode=False, stripe_account=None)
classmethod
Get or create a dj-stripe customer.
:param subscriber: The subscriber model instance for which to get or create a customer. :type subscriber: User
:param livemode: Whether to get the subscriber in live or test mode. :type livemode: bool
Source code in djstripe/models/core.py
@classmethod
def get_or_create(
cls,
subscriber,
livemode=djstripe_settings.STRIPE_LIVE_MODE,
stripe_account=None,
):
"""
Get or create a dj-stripe customer.
:param subscriber: The subscriber model instance for which to get or
create a customer.
:type subscriber: User
:param livemode: Whether to get the subscriber in live or test mode.
:type livemode: bool
"""
try:
return Customer.objects.get(subscriber=subscriber, livemode=livemode), False
except Customer.DoesNotExist:
action = "create:{}".format(subscriber.pk)
idempotency_key = djstripe_settings.get_idempotency_key(
"customer", action, livemode
)
return (
cls.create(
subscriber,
idempotency_key=idempotency_key,
stripe_account=stripe_account,
),
True,
)
djstripe.models.core.Customer.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Customer.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Customer.get_tax_exempt_display(self, *, field=<djstripe.fields.StripeEnumField: tax_exempt>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Customer.has_any_active_subscription(self)
Checks to see if this customer has an active subscription to any plan.
:returns: True if there exists an active subscription, False otherwise.
Source code in djstripe/models/core.py
def has_any_active_subscription(self):
"""
Checks to see if this customer has an active subscription to any plan.
:returns: True if there exists an active subscription, False otherwise.
"""
return len(self._get_valid_subscriptions()) != 0
djstripe.models.core.Customer.has_valid_source(self)
Check whether the customer has a valid payment source.
Source code in djstripe/models/core.py
def has_valid_source(self):
"""Check whether the customer has a valid payment source."""
return self.default_source is not None
djstripe.models.core.Customer.is_subscribed_to(self, product)
Checks to see if this customer has an active subscription to the given product.
:param product: The product for which to check for an active subscription. :type product: Product or string (product ID)
:returns: True if there exists an active subscription, False otherwise.
Source code in djstripe/models/core.py
def is_subscribed_to(self, product: Union[Product, str]) -> bool:
"""
Checks to see if this customer has an active subscription to the given product.
:param product: The product for which to check for an active subscription.
:type product: Product or string (product ID)
:returns: True if there exists an active subscription, False otherwise.
"""
if isinstance(product, StripeModel):
product = product.id
for subscription in self._get_valid_subscriptions():
for item in subscription.items.all():
if item.price and item.price.product.id == product:
return True
return False
djstripe.models.core.Customer.purge(self)
Customers are soft deleted as deleted customers are still accessible by the Stripe API and sync for all RelatedModels would fail
Source code in djstripe/models/core.py
def purge(self):
"""Customers are soft deleted as deleted customers are still accessible by the
Stripe API and sync for all RelatedModels would fail"""
try:
self._api_delete()
except InvalidRequestError as exc:
if "No such customer:" in str(exc):
# The exception was thrown because the stripe customer was already
# deleted on the stripe side, ignore the exception
pass
else:
# The exception was raised for another reason, re-raise it
raise
# toggle the deleted flag on Customer to indicate it has been
# deleted upstream in Stripe
self.deleted = True
if self.subscriber:
# Delete the idempotency key used by Customer.create()
# So re-creating a customer for this subscriber before the key expires
# doesn't return the older Customer data
idempotency_key_action = "customer:create:{}".format(self.subscriber.pk)
IdempotencyKey.objects.filter(action=idempotency_key_action).delete()
self.subscriber = None
# Remove sources
self.default_source = None
for source in self.legacy_cards.all():
source.remove()
for source in self.sources.all():
source.detach()
self.date_purged = timezone.now()
self.save()
djstripe.models.core.Customer.retry_unpaid_invoices(self)
Attempt to retry collecting payment on the customer's unpaid invoices.
Source code in djstripe/models/core.py
def retry_unpaid_invoices(self):
"""Attempt to retry collecting payment on the customer's unpaid invoices."""
self._sync_invoices()
for invoice in self.invoices.filter(auto_advance=True).exclude(status="paid"):
try:
invoice.retry() # Always retry unpaid invoices
except InvalidRequestError as exc:
if str(exc) != "Invoice is already paid":
raise
djstripe.models.core.Customer.send_invoice(self)
Pay and send the customer's latest invoice.
:returns: True if an invoice was able to be created and paid, False otherwise (typically if there was nothing to invoice).
Source code in djstripe/models/core.py
def send_invoice(self):
"""
Pay and send the customer's latest invoice.
:returns: True if an invoice was able to be created and paid, False otherwise
(typically if there was nothing to invoice).
"""
from .billing import Invoice
try:
invoice = Invoice._api_create(customer=self.id)
invoice.pay()
return True
except InvalidRequestError: # TODO: Check this for a more
# specific error message.
return False # There was nothing to invoice
djstripe.models.core.Customer.subscribe(self, *, items=None, price=None, plan=None, **kwargs)
Subscribes this customer to all the prices or plans in the items dict (Recommended).
:param items: A list of up to 20 subscription items, each with an attached price :type list: :param items: A dictionary of Plan (or Plan ID) or Price (or Price ID) :type dict: The price or plan to which to subscribe the customer.
:param price: The price to which to subscribe the customer. :type price: Price or string (price ID)
:param plan: The plan to which to subscribe the customer. :type plan: Plan or string (plan ID)
Source code in djstripe/models/core.py
def subscribe(self, *, items=None, price=None, plan=None, **kwargs):
"""
Subscribes this customer to all the prices or plans in the items dict (Recommended).
:param items: A list of up to 20 subscription items, each with an attached price
:type list:
:param items: A dictionary of Plan (or Plan ID) or Price (or Price ID)
:type dict: The price or plan to which to subscribe the customer.
:param price: The price to which to subscribe the customer.
:type price: Price or string (price ID)
:param plan: The plan to which to subscribe the customer.
:type plan: Plan or string (plan ID)
"""
from .billing import Subscription
products_lst = []
if (items and price) or (items and plan) or (price and plan):
raise TypeError("Please define only one of items, price or plan arguments.")
if items:
for item in items:
price = item.get("price", "")
plan = item.get("plan", "")
price, kwargs = self._sanitise_price(price, plan, **kwargs)
# todo override Subscription.sync_from_stripe_data to attach all subscriptions to the customer using bulk updates
stripe_subscription = Subscription._api_create(
items=[item], customer=self.id, **kwargs
)
Subscription.sync_from_stripe_data(stripe_subscription)
# get associated product
product_name = Price.objects.get(id=price).product.name
# keep count of products subscribed to
products_lst.append(product_name)
else:
warnings.warn(
"The Customer.subscribe() method will not be accepting price (or price id)"
" or plan (or plan id) arguments and support will be removed in dj-stripe 2.5+."
" Please default to using the items dictionary which will allow you to subscribe"
" the given customer to one or more than one plan in one go.",
DeprecationWarning,
)
price, kwargs = self._sanitise_price(price, plan, **kwargs)
stripe_subscription = Subscription._api_create(
items=[{"price": price}], customer=self.id, **kwargs
)
Subscription.sync_from_stripe_data(stripe_subscription)
# get associated product
product_name = Price.objects.get(id=price).product.name
# keep count of products subscribed to
products_lst.append(product_name)
return f"Subscribed {self} to {' and '.join(products_lst)}"
djstripe.models.core.Customer.upcoming_invoice(self, **kwargs)
Gets the upcoming preview invoice (singular) for this customer.
See Invoice.upcoming() <#djstripe.Invoice.upcoming>
__.
The customer
argument to the upcoming()
call is automatically set
by this method.
Source code in djstripe/models/core.py
def upcoming_invoice(self, **kwargs):
"""Gets the upcoming preview invoice (singular) for this customer.
See `Invoice.upcoming() <#djstripe.Invoice.upcoming>`__.
The ``customer`` argument to the ``upcoming()`` call is automatically set
by this method.
"""
from .billing import Invoice
kwargs["customer"] = self
return Invoice.upcoming(**kwargs)
djstripe.models.core.Dispute
A dispute occurs when a customer questions your charge with their card issuer. When this happens, you're given the opportunity to respond to the dispute with evidence that shows that the charge is legitimate
Stripe documentation: https://stripe.com/docs/api#disputes
djstripe.models.core.Dispute.amount
djstripe.models.core.Dispute.balance_transaction
djstripe.models.core.Dispute.balance_transactions
djstripe.models.core.Dispute.charge
djstripe.models.core.Dispute.currency
djstripe.models.core.Dispute.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Dispute.evidence
djstripe.models.core.Dispute.evidence_details
djstripe.models.core.Dispute.is_charge_refundable
djstripe.models.core.Dispute.payment_intent
djstripe.models.core.Dispute.reason
djstripe.models.core.Dispute.status
djstripe.models.core.Dispute.stripe_dashboard_item_name
djstripe.models.core.Dispute.DoesNotExist
djstripe.models.core.Dispute.MultipleObjectsReturned
djstripe.models.core.Dispute.stripe_class
djstripe.models.core.Dispute.stripe_class.OBJECT_NAME
djstripe.models.core.Dispute.stripe_class.close(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def close(self, idempotency_key=None, **params):
url = self.instance_url() + "/close"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.Dispute.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return f"{self.human_readable_amount} ({enums.DisputeStatus.humanize(self.status)}) "
djstripe.models.core.Dispute.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Dispute.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Dispute.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Dispute.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Dispute.get_reason_display(self, *, field=<djstripe.fields.StripeEnumField: reason>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Dispute.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Event
Events are Stripe's way of letting you know when something interesting happens in your account. When an interesting event occurs, a new Event object is created and POSTed to the configured webhook URL if the Event type matches.
Stripe documentation: https://stripe.com/docs/api/events
djstripe.models.core.Event.api_version
djstripe.models.core.Event.customer
property
readonly
djstripe.models.core.Event.data
djstripe.models.core.Event.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Event.idempotency_key
djstripe.models.core.Event.request_id
djstripe.models.core.Event.stripe_dashboard_item_name
djstripe.models.core.Event.type
djstripe.models.core.Event.DoesNotExist
djstripe.models.core.Event.MultipleObjectsReturned
djstripe.models.core.Event.stripe_class
djstripe.models.core.Event.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return f"type={self.type}, id={self.id}"
djstripe.models.core.Event.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Event.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Event.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Event.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Event.invoke_webhook_handlers(self)
Invokes any webhook handlers that have been registered for this event based on event type or event sub-type.
See event handlers registered in the djstripe.event_handlers
module
(or handlers registered in djstripe plugins or contrib packages).
Source code in djstripe/models/core.py
def invoke_webhook_handlers(self):
"""
Invokes any webhook handlers that have been registered for this event
based on event type or event sub-type.
See event handlers registered in the ``djstripe.event_handlers`` module
(or handlers registered in djstripe plugins or contrib packages).
"""
webhooks.call_handlers(event=self)
signal = WEBHOOK_SIGNALS.get(self.type)
if signal:
return signal.send(sender=Event, event=self)
djstripe.models.core.Event.process(data)
classmethod
Source code in djstripe/models/core.py
@classmethod
def process(cls, data):
qs = cls.objects.filter(id=data["id"])
if qs.exists():
return qs.first()
# Rollback any DB operations in the case of failure so
# we will retry creating and processing the event the
# next time the webhook fires.
with transaction.atomic():
# process the event and create an Event Object
ret = cls._create_from_stripe_object(data)
ret.invoke_webhook_handlers()
return ret
djstripe.models.core.File
Stripe documentation: https://stripe.com/docs/api/files
djstripe.models.core.File.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.File.filename
djstripe.models.core.File.purpose
djstripe.models.core.File.size
djstripe.models.core.File.type
djstripe.models.core.File.url
djstripe.models.core.File.DoesNotExist
djstripe.models.core.File.MultipleObjectsReturned
djstripe.models.core.File.stripe_class
djstripe.models.core.File.stripe_class.OBJECT_NAME
djstripe.models.core.File.stripe_class.OBJECT_NAME_ALT
djstripe.models.core.File.stripe_class.class_url()
classmethod
Source code in djstripe/models/core.py
@classmethod
def class_url(cls):
return "/v1/files"
djstripe.models.core.File.stripe_class.create(api_key=None, api_version=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/core.py
@classmethod
def create(
# 'api_version' is deprecated, please use 'stripe_version'
cls,
api_key=None,
api_version=None,
stripe_version=None,
stripe_account=None,
**params
):
version = api_version or stripe_version
requestor = api_requestor.APIRequestor(
api_key,
api_base=stripe.upload_api_base,
api_version=version,
account=stripe_account,
)
url = cls.class_url()
supplied_headers = {"Content-Type": "multipart/form-data"}
response, api_key = requestor.request(
"post", url, params=params, headers=supplied_headers
)
return util.convert_to_stripe_object(
response, api_key, version, stripe_account
)
djstripe.models.core.File.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return f"{self.filename}, {enums.FilePurpose.humanize(self.purpose)}"
djstripe.models.core.File.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.File.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.File.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.File.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.File.get_purpose_display(self, *, field=<djstripe.fields.StripeEnumField: purpose>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.File.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.File.is_valid_object(data)
classmethod
Returns whether the data is a valid object for the class
Source code in djstripe/models/core.py
@classmethod
def is_valid_object(cls, data):
return "object" in data and data["object"] in ("file", "file_upload")
djstripe.models.core.FileLink
Stripe documentation: https://stripe.com/docs/api/file_links
djstripe.models.core.FileLink.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.FileLink.expires_at
djstripe.models.core.FileLink.file
djstripe.models.core.FileLink.url
djstripe.models.core.FileLink.DoesNotExist
djstripe.models.core.FileLink.MultipleObjectsReturned
djstripe.models.core.FileLink.stripe_class
djstripe.models.core.FileLink.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return f"{self.file.filename}, {self.url}"
djstripe.models.core.FileLink.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileLink.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileLink.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileLink.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileUpload
Stripe documentation: https://stripe.com/docs/api/files
djstripe.models.core.FileUpload.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.FileUpload.filename
djstripe.models.core.FileUpload.purpose
djstripe.models.core.FileUpload.size
djstripe.models.core.FileUpload.type
djstripe.models.core.FileUpload.url
djstripe.models.core.FileUpload.DoesNotExist
djstripe.models.core.FileUpload.MultipleObjectsReturned
djstripe.models.core.FileUpload.stripe_class
djstripe.models.core.FileUpload.stripe_class.OBJECT_NAME
djstripe.models.core.FileUpload.stripe_class.OBJECT_NAME_ALT
djstripe.models.core.FileUpload.stripe_class.class_url()
classmethod
Source code in djstripe/models/core.py
@classmethod
def class_url(cls):
return "/v1/files"
djstripe.models.core.FileUpload.stripe_class.create(api_key=None, api_version=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/core.py
@classmethod
def create(
# 'api_version' is deprecated, please use 'stripe_version'
cls,
api_key=None,
api_version=None,
stripe_version=None,
stripe_account=None,
**params
):
version = api_version or stripe_version
requestor = api_requestor.APIRequestor(
api_key,
api_base=stripe.upload_api_base,
api_version=version,
account=stripe_account,
)
url = cls.class_url()
supplied_headers = {"Content-Type": "multipart/form-data"}
response, api_key = requestor.request(
"post", url, params=params, headers=supplied_headers
)
return util.convert_to_stripe_object(
response, api_key, version, stripe_account
)
djstripe.models.core.FileUpload.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return f"{self.filename}, {enums.FilePurpose.humanize(self.purpose)}"
djstripe.models.core.FileUpload.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileUpload.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileUpload.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileUpload.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileUpload.get_purpose_display(self, *, field=<djstripe.fields.StripeEnumField: purpose>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileUpload.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.FileUpload.is_valid_object(data)
classmethod
Returns whether the data is a valid object for the class
Source code in djstripe/models/core.py
@classmethod
def is_valid_object(cls, data):
return "object" in data and data["object"] in ("file", "file_upload")
djstripe.models.core.Mandate
https://stripe.com/docs/api/mandates
djstripe.models.core.Mandate.customer_acceptance
djstripe.models.core.Mandate.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Mandate.multi_use
djstripe.models.core.Mandate.payment_method
djstripe.models.core.Mandate.payment_method_details
djstripe.models.core.Mandate.single_use
djstripe.models.core.Mandate.status
djstripe.models.core.Mandate.type
djstripe.models.core.Mandate.DoesNotExist
djstripe.models.core.Mandate.MultipleObjectsReturned
djstripe.models.core.Mandate.stripe_class
djstripe.models.core.Mandate.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Mandate.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Mandate.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Mandate.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Mandate.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Mandate.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent
Stripe documentation: https://stripe.com/docs/api#payment_intents
djstripe.models.core.PaymentIntent.amount
djstripe.models.core.PaymentIntent.amount_capturable
djstripe.models.core.PaymentIntent.amount_received
djstripe.models.core.PaymentIntent.canceled_at
djstripe.models.core.PaymentIntent.cancellation_reason
djstripe.models.core.PaymentIntent.capture_method
djstripe.models.core.PaymentIntent.client_secret
djstripe.models.core.PaymentIntent.confirmation_method
djstripe.models.core.PaymentIntent.currency
djstripe.models.core.PaymentIntent.customer
djstripe.models.core.PaymentIntent.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.PaymentIntent.last_payment_error
djstripe.models.core.PaymentIntent.next_action
djstripe.models.core.PaymentIntent.on_behalf_of
djstripe.models.core.PaymentIntent.payment_method
djstripe.models.core.PaymentIntent.payment_method_types
djstripe.models.core.PaymentIntent.receipt_email
djstripe.models.core.PaymentIntent.setup_future_usage
djstripe.models.core.PaymentIntent.shipping
djstripe.models.core.PaymentIntent.statement_descriptor
djstripe.models.core.PaymentIntent.status
djstripe.models.core.PaymentIntent.stripe_dashboard_item_name
djstripe.models.core.PaymentIntent.transfer_data
djstripe.models.core.PaymentIntent.transfer_group
djstripe.models.core.PaymentIntent.DoesNotExist
djstripe.models.core.PaymentIntent.MultipleObjectsReturned
djstripe.models.core.PaymentIntent.stripe_class
djstripe.models.core.PaymentIntent.stripe_class.OBJECT_NAME
djstripe.models.core.PaymentIntent.stripe_class.cancel(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def cancel(self, idempotency_key=None, **params):
url = self.instance_url() + "/cancel"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.PaymentIntent.stripe_class.capture(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def capture(self, idempotency_key=None, **params):
url = self.instance_url() + "/capture"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.PaymentIntent.stripe_class.confirm(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def confirm(self, idempotency_key=None, **params):
url = self.instance_url() + "/confirm"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.PaymentIntent.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
account = self.on_behalf_of
customer = self.customer
if account and customer:
return (
f"{self.human_readable_amount} ({enums.PaymentIntentStatus.humanize(self.status)}) "
f"for {account} "
f"by {customer}"
)
if account:
return f"{self.human_readable_amount} for {account}. {enums.PaymentIntentStatus.humanize(self.status)}"
if customer:
return f"{self.human_readable_amount} by {customer}. {enums.PaymentIntentStatus.humanize(self.status)}"
return f"{self.human_readable_amount} ({enums.PaymentIntentStatus.humanize(self.status)})"
djstripe.models.core.PaymentIntent.get_cancellation_reason_display(self, *, field=<djstripe.fields.StripeEnumField: cancellation_reason>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_capture_method_display(self, *, field=<djstripe.fields.StripeEnumField: capture_method>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_confirmation_method_display(self, *, field=<djstripe.fields.StripeEnumField: confirmation_method>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_setup_future_usage_display(self, *, field=<djstripe.fields.StripeEnumField: setup_future_usage>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.PaymentIntent.update(self, api_key=None, **kwargs)
Call the stripe API's modify operation for this model
:param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string
Source code in djstripe/models/core.py
def update(self, api_key=None, **kwargs):
"""
Call the stripe API's modify operation for this model
:param api_key: The api key to use for this request.
Defaults to djstripe_settings.STRIPE_SECRET_KEY.
:type api_key: string
"""
api_key = api_key or self.default_api_key
response = self.api_retrieve(api_key=api_key)
return response.modify(response.stripe_id, api_key=api_key, **kwargs)
djstripe.models.core.Payout
A Payout object is created when you receive funds from Stripe, or when you initiate a payout to either a bank account or debit card of a connected Stripe account.
Stripe documentation: https://stripe.com/docs/api#payouts
djstripe.models.core.Payout.amount
djstripe.models.core.Payout.arrival_date
djstripe.models.core.Payout.automatic
djstripe.models.core.Payout.balance_transaction
djstripe.models.core.Payout.currency
djstripe.models.core.Payout.destination
djstripe.models.core.Payout.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Payout.expand_fields: List[str]
djstripe.models.core.Payout.failure_balance_transaction
djstripe.models.core.Payout.failure_code
djstripe.models.core.Payout.failure_message
djstripe.models.core.Payout.method
djstripe.models.core.Payout.source_type
djstripe.models.core.Payout.statement_descriptor
djstripe.models.core.Payout.status
djstripe.models.core.Payout.stripe_dashboard_item_name
djstripe.models.core.Payout.type
djstripe.models.core.Payout.DoesNotExist
djstripe.models.core.Payout.MultipleObjectsReturned
djstripe.models.core.Payout.stripe_class
djstripe.models.core.Payout.stripe_class.OBJECT_NAME
djstripe.models.core.Payout.stripe_class.cancel(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def cancel(self, idempotency_key=None, **params):
url = self.instance_url() + "/cancel"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.Payout.stripe_class.reverse(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def reverse(self, idempotency_key=None, **params):
url = self.instance_url() + "/reverse"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.Payout.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return f"{self.amount} ({enums.PayoutStatus.humanize(self.status)})"
djstripe.models.core.Payout.get_failure_code_display(self, *, field=<djstripe.fields.StripeEnumField: failure_code>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_method_display(self, *, field=<djstripe.fields.StripeEnumField: method>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_next_by_arrival_date(self, *, field=<djstripe.fields.StripeDateTimeField: arrival_date>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_previous_by_arrival_date(self, *, field=<djstripe.fields.StripeDateTimeField: arrival_date>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_source_type_display(self, *, field=<djstripe.fields.StripeEnumField: source_type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Payout.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Price
Prices define the unit cost, currency, and (optional) billing cycle for both recurring and one-time purchases of products.
Price and Plan objects are the same, but use a different representation. Creating a recurring Price in Stripe also makes a Plan available, and vice versa. This is not the case for a Price with interval=one_time.
Price objects are a more recent API representation, support more features and its usage is encouraged instead of Plan objects.
Stripe documentation: - https://stripe.com/docs/api/prices - https://stripe.com/docs/billing/prices-guide
djstripe.models.core.Price.active
djstripe.models.core.Price.billing_scheme
djstripe.models.core.Price.currency
djstripe.models.core.Price.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Price.expand_fields: List[str]
djstripe.models.core.Price.human_readable_price
property
readonly
djstripe.models.core.Price.lookup_key
djstripe.models.core.Price.nickname
djstripe.models.core.Price.product
djstripe.models.core.Price.recurring
djstripe.models.core.Price.stripe_dashboard_item_name
djstripe.models.core.Price.tiers
djstripe.models.core.Price.tiers_mode
djstripe.models.core.Price.transform_quantity
djstripe.models.core.Price.type
djstripe.models.core.Price.unit_amount
djstripe.models.core.Price.unit_amount_decimal
djstripe.models.core.Price.DoesNotExist
djstripe.models.core.Price.MultipleObjectsReturned
djstripe.models.core.Price.stripe_class
djstripe.models.core.Price.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
from .billing import Subscription
subscriptions = Subscription.objects.filter(plan__id=self.id).count()
if self.recurring:
return f"{self.human_readable_price} for {self.product.name} ({subscriptions} subscriptions)"
return f"{self.human_readable_price} for {self.product.name}"
djstripe.models.core.Price.create(**kwargs)
classmethod
Source code in djstripe/models/core.py
@classmethod
def create(cls, **kwargs):
# A few minor things are changed in the api-version of the create call
api_kwargs = dict(kwargs)
api_kwargs["unit_amount"] = int(api_kwargs["unit_amount"] * 100)
if isinstance(api_kwargs.get("product"), StripeModel):
api_kwargs["product"] = api_kwargs["product"].id
stripe_price = cls._api_create(**api_kwargs)
price = cls.sync_from_stripe_data(stripe_price)
return price
djstripe.models.core.Price.get_billing_scheme_display(self, *, field=<djstripe.fields.StripeEnumField: billing_scheme>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Price.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Price.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Price.get_or_create(**kwargs)
classmethod
Get or create a Price.
Source code in djstripe/models/core.py
@classmethod
def get_or_create(cls, **kwargs):
"""Get or create a Price."""
try:
return Price.objects.get(id=kwargs["id"]), False
except Price.DoesNotExist:
return cls.create(**kwargs), True
djstripe.models.core.Price.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Price.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Price.get_tiers_mode_display(self, *, field=<djstripe.fields.StripeEnumField: tiers_mode>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Price.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Product
Stripe documentation: - https://stripe.com/docs/api#products
djstripe.models.core.Product.active
djstripe.models.core.Product.attributes
djstripe.models.core.Product.caption
djstripe.models.core.Product.deactivate_on
djstripe.models.core.Product.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Product.images
djstripe.models.core.Product.name
djstripe.models.core.Product.package_dimensions
djstripe.models.core.Product.shippable
djstripe.models.core.Product.statement_descriptor
djstripe.models.core.Product.stripe_dashboard_item_name
djstripe.models.core.Product.type
djstripe.models.core.Product.unit_label
djstripe.models.core.Product.url
djstripe.models.core.Product.DoesNotExist
djstripe.models.core.Product.MultipleObjectsReturned
djstripe.models.core.Product.stripe_class
djstripe.models.core.Product.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
# 1 product can have 1 or more than 1 related price
price_qs = Price.objects.filter(product__id=self.id)
price_count = price_qs.count()
if price_count > 1:
return f"{self.name} ({price_count} prices)"
elif price_count == 1:
return f"{self.name} ({price_qs[0].human_readable_price})"
else:
return self.name
djstripe.models.core.Product.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Product.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Product.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Product.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Product.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund
Stripe documentation: https://stripe.com/docs/api#refund_object
djstripe.models.core.Refund.amount
djstripe.models.core.Refund.balance_transaction
djstripe.models.core.Refund.charge
djstripe.models.core.Refund.currency
djstripe.models.core.Refund.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.Refund.failure_balance_transaction
djstripe.models.core.Refund.failure_reason
djstripe.models.core.Refund.reason
djstripe.models.core.Refund.receipt_number
djstripe.models.core.Refund.status
djstripe.models.core.Refund.DoesNotExist
djstripe.models.core.Refund.MultipleObjectsReturned
djstripe.models.core.Refund.stripe_class
djstripe.models.core.Refund.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
return (
f"{self.human_readable_amount} ({enums.RefundStatus.humanize(self.status)})"
)
djstripe.models.core.Refund.get_failure_reason_display(self, *, field=<djstripe.fields.StripeEnumField: failure_reason>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund.get_reason_display(self, *, field=<djstripe.fields.StripeEnumField: reason>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.Refund.get_stripe_dashboard_url(self)
Get the stripe dashboard url for this object.
Source code in djstripe/models/core.py
def get_stripe_dashboard_url(self):
return self.charge.get_stripe_dashboard_url()
djstripe.models.core.SetupIntent
A SetupIntent guides you through the process of setting up a customer's payment credentials for future payments. For example, you could use a SetupIntent to set up your customer's card without immediately collecting a payment. Later, you can use PaymentIntents to drive the payment flow.
NOTE: You should not maintain long-lived, unconfirmed SetupIntents. For security purposes, SetupIntents older than 24 hours may no longer be valid.
Stripe documentation: https://stripe.com/docs/api#setup_intents
djstripe.models.core.SetupIntent.application
djstripe.models.core.SetupIntent.cancellation_reason
djstripe.models.core.SetupIntent.client_secret
djstripe.models.core.SetupIntent.customer
djstripe.models.core.SetupIntent.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.core.SetupIntent.last_setup_error
djstripe.models.core.SetupIntent.next_action
djstripe.models.core.SetupIntent.on_behalf_of
djstripe.models.core.SetupIntent.payment_method
djstripe.models.core.SetupIntent.payment_method_types
djstripe.models.core.SetupIntent.status
djstripe.models.core.SetupIntent.usage
djstripe.models.core.SetupIntent.DoesNotExist
djstripe.models.core.SetupIntent.MultipleObjectsReturned
djstripe.models.core.SetupIntent.stripe_class
djstripe.models.core.SetupIntent.stripe_class.OBJECT_NAME
djstripe.models.core.SetupIntent.stripe_class.cancel(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def cancel(self, idempotency_key=None, **params):
url = self.instance_url() + "/cancel"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.SetupIntent.stripe_class.confirm(self, idempotency_key=None, **params)
Source code in djstripe/models/core.py
def confirm(self, idempotency_key=None, **params):
url = self.instance_url() + "/confirm"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.core.SetupIntent.__str__(self)
special
Source code in djstripe/models/core.py
def __str__(self):
account = self.on_behalf_of
customer = self.customer
if account and customer:
return (
f"{self.payment_method} ({enums.SetupIntentStatus.humanize(self.status)}) "
f"for {account} "
f"by {customer}"
)
if account:
return f"{self.payment_method} for {account}. {enums.SetupIntentStatus.humanize(self.status)}"
if customer:
return f"{self.payment_method} by {customer}. {enums.SetupIntentStatus.humanize(self.status)}"
return (
f"{self.payment_method} ({enums.SetupIntentStatus.humanize(self.status)})"
)
djstripe.models.core.SetupIntent.get_cancellation_reason_display(self, *, field=<djstripe.fields.StripeEnumField: cancellation_reason>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.SetupIntent.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.SetupIntent.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.SetupIntent.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.SetupIntent.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.SetupIntent.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.core.SetupIntent.get_usage_display(self, *, field=<djstripe.fields.StripeEnumField: usage>)
Source code in djstripe/models/core.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.fraud
djstripe.models.orders
djstripe.models.payment_methods
Classes
djstripe.models.payment_methods.BankAccount
BankAccount(djstripe_created, djstripe_updated, djstripe_id, id, djstripe_owner_account, livemode, created, metadata, description, account, account_holder_name, account_holder_type, bank_name, country, currency, customer, default_for_currency, fingerprint, last4, routing_number, status)
djstripe.models.payment_methods.BankAccount.account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.BankAccount.account_holder_name
djstripe.models.payment_methods.BankAccount.account_holder_type
djstripe.models.payment_methods.BankAccount.bank_name
djstripe.models.payment_methods.BankAccount.country
djstripe.models.payment_methods.BankAccount.currency
djstripe.models.payment_methods.BankAccount.customer: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.BankAccount.default_for_currency
djstripe.models.payment_methods.BankAccount.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.BankAccount.fingerprint
djstripe.models.payment_methods.BankAccount.human_readable_status
property
readonly
djstripe.models.payment_methods.BankAccount.last4
djstripe.models.payment_methods.BankAccount.routing_number
djstripe.models.payment_methods.BankAccount.status
djstripe.models.payment_methods.BankAccount.DoesNotExist
djstripe.models.payment_methods.BankAccount.MultipleObjectsReturned
djstripe.models.payment_methods.BankAccount.stripe_class
djstripe.models.payment_methods.BankAccount.stripe_class.OBJECT_NAME
djstripe.models.payment_methods.BankAccount.stripe_class.instance_url(self)
Source code in djstripe/models/payment_methods.py
def instance_url(self):
token = util.utf8(self.id)
extn = quote_plus(token)
if hasattr(self, "customer"):
customer = util.utf8(self.customer)
base = Customer.class_url()
owner_extn = quote_plus(customer)
class_base = "sources"
elif hasattr(self, "account"):
account = util.utf8(self.account)
base = Account.class_url()
owner_extn = quote_plus(account)
class_base = "external_accounts"
else:
raise error.InvalidRequestError(
"Could not determine whether bank_account_id %s is "
"attached to a customer or an account." % token,
"id",
)
return "%s/%s/%s/%s" % (base, owner_extn, class_base, extn)
djstripe.models.payment_methods.BankAccount.stripe_class.modify(sid, **params)
classmethod
Source code in djstripe/models/payment_methods.py
@classmethod
def modify(cls, sid, **params):
raise NotImplementedError(
"Can't modify a bank account without a customer or account ID. "
"Call save on customer.sources.retrieve('bank_account_id') or "
"account.external_accounts.retrieve('bank_account_id') instead."
)
djstripe.models.payment_methods.BankAccount.stripe_class.retrieve(id, api_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/payment_methods.py
@classmethod
def retrieve(
cls,
id,
api_key=None,
stripe_version=None,
stripe_account=None,
**params
):
raise NotImplementedError(
"Can't retrieve a bank account without a customer or account ID. "
"Use customer.sources.retrieve('bank_account_id') or "
"account.external_accounts.retrieve('bank_account_id') instead."
)
djstripe.models.payment_methods.BankAccount.__str__(self)
special
Source code in djstripe/models/payment_methods.py
def __str__(self):
default = False
# prefer to show it by customer format if present
if self.customer:
default_source = self.customer.default_source
default_payment_method = self.customer.default_payment_method
if (default_payment_method and self.id == default_payment_method.id) or (
default_source and self.id == default_source.id
):
# current card is the default payment method or source
default = True
customer_template = f"{self.bank_name} {self.routing_number} ({self.human_readable_status}) {'Default' if default else ''} {self.currency}"
return customer_template
elif self.account:
default = getattr(self, "default_for_currency", False)
account_template = f"{self.bank_name} {self.currency} {'Default' if default else ''} {self.routing_number} {self.last4}"
return account_template
djstripe.models.payment_methods.BankAccount.api_retrieve(self, **kwargs)
Call the stripe API's retrieve operation for this model.
:param api_key: The api key to use for this request. Defaults to djstripe_settings.STRIPE_SECRET_KEY. :type api_key: string :param stripe_account: The optional connected account for which this request is being made. :type stripe_account: string
Source code in djstripe/models/payment_methods.py
def api_retrieve(self, **kwargs):
if not self.customer and not self.account:
raise NotImplementedError(
"Can't retrieve a bank account without a customer or account object."
)
return super().api_retrieve(**kwargs)
djstripe.models.payment_methods.BankAccount.get_account_holder_type_display(self, *, field=<djstripe.fields.StripeEnumField: account_holder_type>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.BankAccount.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.BankAccount.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.BankAccount.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.BankAccount.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.BankAccount.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card
You can store multiple cards on a customer in order to charge the customer later.
This is a legacy model which only applies to the "v2" Stripe API (eg. Checkout.js). You should strive to use the Stripe "v3" API (eg. Stripe Elements). Also see: https://stripe.com/docs/stripe-js/elements/migrating When using Elements, you will not be using Card objects. Instead, you will use Source objects. A Source object of type "card" is equivalent to a Card object. However, Card objects cannot be converted into Source objects by Stripe at this time.
Stripe documentation: https://stripe.com/docs/api?lang=python#cards
djstripe.models.payment_methods.Card.account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.Card.address_city
djstripe.models.payment_methods.Card.address_country
djstripe.models.payment_methods.Card.address_line1
djstripe.models.payment_methods.Card.address_line1_check
djstripe.models.payment_methods.Card.address_line2
djstripe.models.payment_methods.Card.address_state
djstripe.models.payment_methods.Card.address_zip
djstripe.models.payment_methods.Card.address_zip_check
djstripe.models.payment_methods.Card.brand
djstripe.models.payment_methods.Card.country
djstripe.models.payment_methods.Card.customer: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.Card.cvc_check
djstripe.models.payment_methods.Card.default_for_currency
djstripe.models.payment_methods.Card.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.Card.dynamic_last4
djstripe.models.payment_methods.Card.exp_month
djstripe.models.payment_methods.Card.exp_year
djstripe.models.payment_methods.Card.fingerprint
djstripe.models.payment_methods.Card.funding
djstripe.models.payment_methods.Card.last4
djstripe.models.payment_methods.Card.name
djstripe.models.payment_methods.Card.tokenization_method
djstripe.models.payment_methods.Card.DoesNotExist
djstripe.models.payment_methods.Card.MultipleObjectsReturned
djstripe.models.payment_methods.Card.stripe_class
djstripe.models.payment_methods.Card.stripe_class.OBJECT_NAME
djstripe.models.payment_methods.Card.stripe_class.instance_url(self)
Source code in djstripe/models/payment_methods.py
def instance_url(self):
token = util.utf8(self.id)
extn = quote_plus(token)
if hasattr(self, "customer"):
customer = util.utf8(self.customer)
base = Customer.class_url()
owner_extn = quote_plus(customer)
class_base = "sources"
elif hasattr(self, "recipient"):
recipient = util.utf8(self.recipient)
base = Recipient.class_url()
owner_extn = quote_plus(recipient)
class_base = "cards"
elif hasattr(self, "account"):
account = util.utf8(self.account)
base = Account.class_url()
owner_extn = quote_plus(account)
class_base = "external_accounts"
else:
raise error.InvalidRequestError(
"Could not determine whether card_id %s is "
"attached to a customer, recipient, or "
"account." % token,
"id",
)
return "%s/%s/%s/%s" % (base, owner_extn, class_base, extn)
djstripe.models.payment_methods.Card.stripe_class.modify(sid, **params)
classmethod
Source code in djstripe/models/payment_methods.py
@classmethod
def modify(cls, sid, **params):
raise NotImplementedError(
"Can't modify a card without a customer, recipient or account "
"ID. Call save on customer.sources.retrieve('card_id'), "
"recipient.cards.retrieve('card_id'), or "
"account.external_accounts.retrieve('card_id') instead."
)
djstripe.models.payment_methods.Card.stripe_class.retrieve(id, api_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/payment_methods.py
@classmethod
def retrieve(
cls,
id,
api_key=None,
stripe_version=None,
stripe_account=None,
**params
):
raise NotImplementedError(
"Can't retrieve a card without a customer, recipient or account "
"ID. Use customer.sources.retrieve('card_id'), "
"recipient.cards.retrieve('card_id'), or "
"account.external_accounts.retrieve('card_id') instead."
)
djstripe.models.payment_methods.Card.__str__(self)
special
Source code in djstripe/models/payment_methods.py
def __str__(self):
default = False
# prefer to show it by customer format if present
if self.customer:
default_source = self.customer.default_source
default_payment_method = self.customer.default_payment_method
if (default_payment_method and self.id == default_payment_method.id) or (
default_source and self.id == default_source.id
):
# current card is the default payment method or source
default = True
customer_template = f"{enums.CardBrand.humanize(self.brand)} {self.last4} {'Default' if default else ''} Expires {self.exp_month} {self.exp_year}"
return customer_template
elif self.account:
default = getattr(self, "default_for_currency", False)
account_template = f"{enums.CardBrand.humanize(self.brand)} {self.account.default_currency} {'Default' if default else ''} {self.last4}"
return account_template
djstripe.models.payment_methods.Card.create_token(number, exp_month, exp_year, cvc, api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', **kwargs)
classmethod
Creates a single use token that wraps the details of a credit card. This token can be used in place of a credit card dictionary with any API method. These tokens can only be used once: by creating a new charge object, or attaching them to a customer. (Source: https://stripe.com/docs/api?lang=python#create_card_token)
:param number: The card number without any separators (no spaces) :param exp_month: The card's expiration month. (two digits) :param exp_year: The card's expiration year. (four digits) :param cvc: Card security code. :param api_key: The API key to use
Source code in djstripe/models/payment_methods.py
@classmethod
def create_token(
cls,
number: str,
exp_month: int,
exp_year: int,
cvc: str,
api_key: str = djstripe_settings.STRIPE_SECRET_KEY,
**kwargs,
) -> stripe.Token:
"""
Creates a single use token that wraps the details of a credit card.
This token can be used in place of a credit card dictionary with any API method.
These tokens can only be used once: by creating a new charge object,
or attaching them to a customer.
(Source: https://stripe.com/docs/api?lang=python#create_card_token)
:param number: The card number without any separators (no spaces)
:param exp_month: The card's expiration month. (two digits)
:param exp_year: The card's expiration year. (four digits)
:param cvc: Card security code.
:param api_key: The API key to use
"""
card = {
"number": number,
"exp_month": exp_month,
"exp_year": exp_year,
"cvc": cvc,
}
card.update(kwargs)
return stripe.Token.create(api_key=api_key, card=card)
djstripe.models.payment_methods.Card.get_address_line1_check_display(self, *, field=<djstripe.fields.StripeEnumField: address_line1_check>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_address_zip_check_display(self, *, field=<djstripe.fields.StripeEnumField: address_zip_check>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_brand_display(self, *, field=<djstripe.fields.StripeEnumField: brand>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_cvc_check_display(self, *, field=<djstripe.fields.StripeEnumField: cvc_check>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_funding_display(self, *, field=<djstripe.fields.StripeEnumField: funding>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Card.get_tokenization_method_display(self, *, field=<djstripe.fields.StripeEnumField: tokenization_method>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.DjstripePaymentMethod
An internal model that abstracts the legacy Card and BankAccount objects with Source objects.
Contains two fields: id
and type
:
- id
is the id of the Stripe object.
- type
can be card
, bank_account
account
or source
.
djstripe.models.payment_methods.DjstripePaymentMethod.id
djstripe.models.payment_methods.DjstripePaymentMethod.object_model
property
readonly
djstripe.models.payment_methods.DjstripePaymentMethod.type
djstripe.models.payment_methods.DjstripePaymentMethod.DoesNotExist
djstripe.models.payment_methods.DjstripePaymentMethod.MultipleObjectsReturned
djstripe.models.payment_methods.DjstripePaymentMethod.from_stripe_object(data)
classmethod
Source code in djstripe/models/payment_methods.py
@classmethod
def from_stripe_object(cls, data):
source_type = data["object"]
model = cls._model_for_type(source_type)
with transaction.atomic():
model.sync_from_stripe_data(data)
instance, _ = cls.objects.get_or_create(
id=data["id"], defaults={"type": source_type}
)
return instance
djstripe.models.payment_methods.DjstripePaymentMethod.resolve(self)
Source code in djstripe/models/payment_methods.py
def resolve(self):
return self.object_model.objects.get(id=self.id)
djstripe.models.payment_methods.LegacySourceMixin
Mixin for functionality shared between the legacy Card & BankAccount sources
djstripe.models.payment_methods.LegacySourceMixin.api_list(api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX', **kwargs)
classmethod
Source code in djstripe/models/payment_methods.py
@classmethod
def api_list(cls, api_key=djstripe_settings.STRIPE_SECRET_KEY, **kwargs):
# OVERRIDING the parent version of this function
# Cards & Bank Accounts must be manipulated through a customer or account.
account, customer, clean_kwargs = cls._get_customer_or_account_from_kwargs(
**kwargs
)
# First we try to retrieve by customer attribute,
# then by account attribute
if customer and account:
try:
# retrieve by customer
return (
customer.api_retrieve(api_key=api_key)
.sources.list(object=cls.stripe_class.OBJECT_NAME, **clean_kwargs)
.auto_paging_iter()
)
except Exception as customer_exc:
try:
# retrieve by account
return (
account.api_retrieve(api_key=api_key)
.external_accounts.list(
object=cls.stripe_class.OBJECT_NAME, **clean_kwargs
)
.auto_paging_iter()
)
except Exception:
raise customer_exc
if customer:
return (
customer.api_retrieve(api_key=api_key)
.sources.list(object=cls.stripe_class.OBJECT_NAME, **clean_kwargs)
.auto_paging_iter()
)
if account:
return (
account.api_retrieve(api_key=api_key)
.external_accounts.list(
object=cls.stripe_class.OBJECT_NAME, **clean_kwargs
)
.auto_paging_iter()
)
djstripe.models.payment_methods.LegacySourceMixin.api_retrieve(self, api_key=None, stripe_account=None)
Source code in djstripe/models/payment_methods.py
def api_retrieve(self, api_key=None, stripe_account=None):
# OVERRIDING the parent version of this function
# Cards & Banks Accounts must be manipulated through a customer or account.
api_key = api_key or self.default_api_key
if self.customer:
return stripe.Customer.retrieve_source(
self.customer.id,
self.id,
expand=self.expand_fields,
stripe_account=stripe_account,
api_key=api_key,
)
# try to retrieve by account attribute if retrieval by customer fails.
if self.account:
return stripe.Account.retrieve_external_account(
self.account.id,
self.id,
expand=self.expand_fields,
stripe_account=stripe_account,
api_key=api_key,
)
djstripe.models.payment_methods.LegacySourceMixin.get_stripe_dashboard_url(self)
Source code in djstripe/models/payment_methods.py
def get_stripe_dashboard_url(self) -> str:
if self.customer:
return self.customer.get_stripe_dashboard_url()
elif self.account:
return self.account.get_stripe_dashboard_url()
else:
return ""
djstripe.models.payment_methods.LegacySourceMixin.remove(self)
Removes a legacy source from this customer's account.
Source code in djstripe/models/payment_methods.py
def remove(self):
"""
Removes a legacy source from this customer's account.
"""
# First, wipe default source on all customers that use this card.
Customer.objects.filter(default_source=self.id).update(default_source=None)
try:
self._api_delete()
except InvalidRequestError as exc:
if "No such source:" in str(exc) or "No such customer:" in str(exc):
# The exception was thrown because the stripe customer or card
# was already deleted on the stripe side, ignore the exception
pass
else:
# The exception was raised for another reason, re-raise it
raise
self.delete()
djstripe.models.payment_methods.PaymentMethod
Stripe documentation: https://stripe.com/docs/api#payment_methods
djstripe.models.payment_methods.PaymentMethod.acss_debit
djstripe.models.payment_methods.PaymentMethod.afterpay_clearpay
djstripe.models.payment_methods.PaymentMethod.alipay
djstripe.models.payment_methods.PaymentMethod.au_becs_debit
djstripe.models.payment_methods.PaymentMethod.bacs_debit
djstripe.models.payment_methods.PaymentMethod.bancontact
djstripe.models.payment_methods.PaymentMethod.billing_details
djstripe.models.payment_methods.PaymentMethod.boleto
djstripe.models.payment_methods.PaymentMethod.card
djstripe.models.payment_methods.PaymentMethod.card_present
djstripe.models.payment_methods.PaymentMethod.customer
djstripe.models.payment_methods.PaymentMethod.description
djstripe.models.payment_methods.PaymentMethod.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.PaymentMethod.eps
djstripe.models.payment_methods.PaymentMethod.fpx
djstripe.models.payment_methods.PaymentMethod.giropay
djstripe.models.payment_methods.PaymentMethod.grabpay
djstripe.models.payment_methods.PaymentMethod.ideal
djstripe.models.payment_methods.PaymentMethod.interac_present
djstripe.models.payment_methods.PaymentMethod.oxxo
djstripe.models.payment_methods.PaymentMethod.p24
djstripe.models.payment_methods.PaymentMethod.sepa_debit
djstripe.models.payment_methods.PaymentMethod.sofort
djstripe.models.payment_methods.PaymentMethod.type
djstripe.models.payment_methods.PaymentMethod.wechat_pay
djstripe.models.payment_methods.PaymentMethod.DoesNotExist
djstripe.models.payment_methods.PaymentMethod.MultipleObjectsReturned
djstripe.models.payment_methods.PaymentMethod.stripe_class
djstripe.models.payment_methods.PaymentMethod.stripe_class.OBJECT_NAME
djstripe.models.payment_methods.PaymentMethod.stripe_class.attach(self, idempotency_key=None, **params)
Source code in djstripe/models/payment_methods.py
def attach(self, idempotency_key=None, **params):
url = self.instance_url() + "/attach"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.payment_methods.PaymentMethod.stripe_class.detach(self, idempotency_key=None, **params)
Source code in djstripe/models/payment_methods.py
def detach(self, idempotency_key=None, **params):
url = self.instance_url() + "/detach"
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("post", url, params, headers))
return self
djstripe.models.payment_methods.PaymentMethod.__str__(self)
special
Source code in djstripe/models/payment_methods.py
def __str__(self):
if self.customer:
return f"{enums.PaymentMethodType.humanize(self.type)} for {self.customer}"
return f"{enums.PaymentMethodType.humanize(self.type)} is not associated with any customer"
djstripe.models.payment_methods.PaymentMethod.attach(payment_method, customer, api_key='sk_test_XXXXXXXXXXXXXXXXXXXXXXXXX')
classmethod
Attach a payment method to a customer
Source code in djstripe/models/payment_methods.py
@classmethod
def attach(
cls,
payment_method: Union[str, "PaymentMethod"],
customer: Union[str, Customer],
api_key: str = djstripe_settings.STRIPE_SECRET_KEY,
) -> "PaymentMethod":
"""
Attach a payment method to a customer
"""
if isinstance(payment_method, StripeModel):
payment_method = payment_method.id
if isinstance(customer, StripeModel):
customer = customer.id
extra_kwargs = {}
if not isinstance(payment_method, stripe.PaymentMethod):
# send api_key if we're not passing in a Stripe object
# avoids "Received unknown parameter: api_key" since api uses the
# key cached in the Stripe object
extra_kwargs = {"api_key": api_key}
stripe_payment_method = stripe.PaymentMethod.attach(
payment_method, customer=customer, **extra_kwargs
)
return cls.sync_from_stripe_data(stripe_payment_method)
djstripe.models.payment_methods.PaymentMethod.detach(self)
Detach the payment method from its customer.
:return: Returns true if the payment method was newly detached, false if it was already detached :rtype: bool
Source code in djstripe/models/payment_methods.py
def detach(self):
"""
Detach the payment method from its customer.
:return: Returns true if the payment method was newly detached, \
false if it was already detached
:rtype: bool
"""
# Find customers that use this
customers = Customer.objects.filter(default_payment_method=self).all()
changed = True
# special handling is needed for legacy "card"-type PaymentMethods,
# since detaching them deletes them within Stripe.
# see https://github.com/dj-stripe/dj-stripe/pull/967
is_legacy_card = self.id.startswith("card_")
try:
self.sync_from_stripe_data(self.api_retrieve().detach())
# resync customer to update .default_payment_method and
# .invoice_settings.default_payment_method
for customer in customers:
Customer.sync_from_stripe_data(customer.api_retrieve())
except (InvalidRequestError,):
# The source was already detached. Resyncing.
if self.pk and not is_legacy_card:
self.sync_from_stripe_data(self.api_retrieve())
changed = False
if self.pk:
if is_legacy_card:
self.delete()
else:
self.refresh_from_db()
return changed
djstripe.models.payment_methods.PaymentMethod.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.PaymentMethod.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.PaymentMethod.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.PaymentMethod.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.PaymentMethod.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source
Stripe documentation: https://stripe.com/docs/api#sources
djstripe.models.payment_methods.Source.amount
djstripe.models.payment_methods.Source.client_secret
djstripe.models.payment_methods.Source.code_verification
djstripe.models.payment_methods.Source.currency
djstripe.models.payment_methods.Source.customer
djstripe.models.payment_methods.Source.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.payment_methods.Source.flow
djstripe.models.payment_methods.Source.owner
djstripe.models.payment_methods.Source.receiver
djstripe.models.payment_methods.Source.redirect
djstripe.models.payment_methods.Source.source_data
djstripe.models.payment_methods.Source.statement_descriptor
djstripe.models.payment_methods.Source.status
djstripe.models.payment_methods.Source.stripe_dashboard_item_name
djstripe.models.payment_methods.Source.type
djstripe.models.payment_methods.Source.usage
djstripe.models.payment_methods.Source.DoesNotExist
djstripe.models.payment_methods.Source.MultipleObjectsReturned
djstripe.models.payment_methods.Source.stripe_class
djstripe.models.payment_methods.Source.stripe_class.OBJECT_NAME
djstripe.models.payment_methods.Source.stripe_class.detach(self, idempotency_key=None, **params)
Source code in djstripe/models/payment_methods.py
def detach(self, idempotency_key=None, **params):
token = util.utf8(self.id)
if hasattr(self, "customer") and self.customer:
extn = quote_plus(token)
customer = util.utf8(self.customer)
base = Customer.class_url()
owner_extn = quote_plus(customer)
url = "%s/%s/sources/%s" % (base, owner_extn, extn)
headers = util.populate_headers(idempotency_key)
self.refresh_from(self.request("delete", url, params, headers))
return self
else:
raise error.InvalidRequestError(
"Source %s does not appear to be currently attached "
"to a customer object." % token,
"id",
)
djstripe.models.payment_methods.Source.stripe_class.list_source_transactions(id, **params)
classmethod
Source code in djstripe/models/payment_methods.py
def list_nested_resources(cls, id, **params):
url = getattr(cls, resource_url_method)(id)
return getattr(cls, resource_request_method)(
"get", url, **params
)
djstripe.models.payment_methods.Source.stripe_class.source_transactions(self, **params)
source_transactions is deprecated, use Source.list_source_transactions instead.
Source code in djstripe/models/payment_methods.py
def source_transactions(self, **params):
"""source_transactions is deprecated, use Source.list_source_transactions instead."""
return self.request(
"get", self.instance_url() + "/source_transactions", params
)
djstripe.models.payment_methods.Source.stripe_class.source_transactions_request(method, url, api_key=None, idempotency_key=None, stripe_version=None, stripe_account=None, **params)
classmethod
Source code in djstripe/models/payment_methods.py
def nested_resource_request(
cls,
method,
url,
api_key=None,
idempotency_key=None,
stripe_version=None,
stripe_account=None,
**params
):
requestor = api_requestor.APIRequestor(
api_key, api_version=stripe_version, account=stripe_account
)
headers = util.populate_headers(idempotency_key)
response, api_key = requestor.request(method, url, params, headers)
return util.convert_to_stripe_object(
response, api_key, stripe_version, stripe_account
)
djstripe.models.payment_methods.Source.stripe_class.source_transactions_url(id, nested_id=None)
classmethod
Source code in djstripe/models/payment_methods.py
def nested_resource_url(cls, id, nested_id=None):
url = "%s/%s/%s" % (
cls.class_url(),
quote_plus(id),
quote_plus(path),
)
if nested_id is not None:
url += "/%s" % quote_plus(nested_id)
return url
djstripe.models.payment_methods.Source.detach(self)
Detach the source from its customer.
Source code in djstripe/models/payment_methods.py
def detach(self) -> bool:
"""
Detach the source from its customer.
"""
# First, wipe default source on all customers that use this.
Customer.objects.filter(default_source=self.id).update(default_source=None)
try:
# TODO - we could use the return value of sync_from_stripe_data
# or call its internals - self._sync/_attach_objects_hook etc here
# to update `self` at this point?
self.sync_from_stripe_data(self.api_retrieve().detach())
return True
except (InvalidRequestError, NotImplementedError):
# The source was already detached. Resyncing.
# NotImplementedError is an artifact of stripe-python<2.0
# https://github.com/stripe/stripe-python/issues/376
self.sync_from_stripe_data(self.api_retrieve())
return False
djstripe.models.payment_methods.Source.get_flow_display(self, *, field=<djstripe.fields.StripeEnumField: flow>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.get_type_display(self, *, field=<djstripe.fields.StripeEnumField: type>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.get_usage_display(self, *, field=<djstripe.fields.StripeEnumField: usage>)
Source code in djstripe/models/payment_methods.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.payment_methods.Source.str_parts(self)
Extend this to add information to the string representation of the object
Source code in djstripe/models/payment_methods.py
def str_parts(self):
return [
f"type={self.type}",
f"status={self.status}",
f"customer={self.customer}",
f"usage={self.usage}",
] + super().str_parts()
djstripe.models.sigma
Classes
djstripe.models.sigma.ScheduledQueryRun
Stripe documentation: https://stripe.com/docs/api#scheduled_queries
djstripe.models.sigma.ScheduledQueryRun.data_load_time
djstripe.models.sigma.ScheduledQueryRun.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.sigma.ScheduledQueryRun.error
djstripe.models.sigma.ScheduledQueryRun.file
djstripe.models.sigma.ScheduledQueryRun.result_available_until
djstripe.models.sigma.ScheduledQueryRun.sql
djstripe.models.sigma.ScheduledQueryRun.status
djstripe.models.sigma.ScheduledQueryRun.title
djstripe.models.sigma.ScheduledQueryRun.DoesNotExist
djstripe.models.sigma.ScheduledQueryRun.MultipleObjectsReturned
djstripe.models.sigma.ScheduledQueryRun.stripe_class
djstripe.models.sigma.ScheduledQueryRun.stripe_class.OBJECT_NAME
djstripe.models.sigma.ScheduledQueryRun.stripe_class.class_url()
classmethod
Source code in djstripe/models/sigma.py
@classmethod
def class_url(cls):
return "/v1/sigma/scheduled_query_runs"
djstripe.models.sigma.ScheduledQueryRun.__str__(self)
special
Source code in djstripe/models/sigma.py
def __str__(self):
return f"{self.title or self.id} ({self.status})"
djstripe.models.sigma.ScheduledQueryRun.get_next_by_data_load_time(self, *, field=<djstripe.fields.StripeDateTimeField: data_load_time>, is_next=True, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_next_by_result_available_until(self, *, field=<djstripe.fields.StripeDateTimeField: result_available_until>, is_next=True, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_previous_by_data_load_time(self, *, field=<djstripe.fields.StripeDateTimeField: data_load_time>, is_next=False, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_previous_by_result_available_until(self, *, field=<djstripe.fields.StripeDateTimeField: result_available_until>, is_next=False, **kwargs)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.sigma.ScheduledQueryRun.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/sigma.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks
Module for dj-stripe Webhook models
Classes
djstripe.models.webhooks.WebhookEndpoint
WebhookEndpoint(djstripe_created, djstripe_updated, djstripe_id, id, djstripe_owner_account, livemode, created, metadata, description, api_version, enabled_events, secret, status, url, application, djstripe_uuid)
djstripe.models.webhooks.WebhookEndpoint.api_version
djstripe.models.webhooks.WebhookEndpoint.application
djstripe.models.webhooks.WebhookEndpoint.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
djstripe.models.webhooks.WebhookEndpoint.djstripe_uuid
djstripe.models.webhooks.WebhookEndpoint.enabled_events
djstripe.models.webhooks.WebhookEndpoint.secret
djstripe.models.webhooks.WebhookEndpoint.status
djstripe.models.webhooks.WebhookEndpoint.url
djstripe.models.webhooks.WebhookEndpoint.DoesNotExist
djstripe.models.webhooks.WebhookEndpoint.MultipleObjectsReturned
djstripe.models.webhooks.WebhookEndpoint.stripe_class
djstripe.models.webhooks.WebhookEndpoint.__str__(self)
special
Source code in djstripe/models/webhooks.py
def __str__(self):
return self.url or str(self.djstripe_uuid)
djstripe.models.webhooks.WebhookEndpoint.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEndpoint.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEndpoint.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEndpoint.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEndpoint.get_status_display(self, *, field=<djstripe.fields.StripeEnumField: status>)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEventTrigger
An instance of a request that reached the server endpoint for Stripe webhooks.
Webhook Events are initially UNTRUSTED, as it is possible for any web entity to post any data to our webhook url. Data posted may be valid Stripe information, garbage, or even malicious. The 'valid' flag in this model monitors this.
djstripe.models.webhooks.WebhookEventTrigger.body
djstripe.models.webhooks.WebhookEventTrigger.created
djstripe.models.webhooks.WebhookEventTrigger.djstripe_version
djstripe.models.webhooks.WebhookEventTrigger.event
djstripe.models.webhooks.WebhookEventTrigger.exception
djstripe.models.webhooks.WebhookEventTrigger.headers
djstripe.models.webhooks.WebhookEventTrigger.id
djstripe.models.webhooks.WebhookEventTrigger.is_test_event
property
readonly
djstripe.models.webhooks.WebhookEventTrigger.processed
djstripe.models.webhooks.WebhookEventTrigger.remote_ip
djstripe.models.webhooks.WebhookEventTrigger.stripe_trigger_account
djstripe.models.webhooks.WebhookEventTrigger.traceback
djstripe.models.webhooks.WebhookEventTrigger.updated
djstripe.models.webhooks.WebhookEventTrigger.valid
djstripe.models.webhooks.WebhookEventTrigger.DoesNotExist
djstripe.models.webhooks.WebhookEventTrigger.MultipleObjectsReturned
djstripe.models.webhooks.WebhookEventTrigger.__str__(self)
special
Source code in djstripe/models/webhooks.py
def __str__(self):
return f"id={self.id}, valid={self.valid}, processed={self.processed}"
djstripe.models.webhooks.WebhookEventTrigger.from_request(request)
classmethod
Create, validate and process a WebhookEventTrigger given a Django request object.
The process is three-fold: 1. Create a WebhookEventTrigger object from a Django request. 2. Validate the WebhookEventTrigger as a Stripe event using the API. 3. If valid, process it into an Event object (and child resource).
Source code in djstripe/models/webhooks.py
@classmethod
def from_request(cls, request):
"""
Create, validate and process a WebhookEventTrigger given a Django
request object.
The process is three-fold:
1. Create a WebhookEventTrigger object from a Django request.
2. Validate the WebhookEventTrigger as a Stripe event using the API.
3. If valid, process it into an Event object (and child resource).
"""
try:
body = request.body.decode(request.encoding or "utf-8")
except Exception:
body = "(error decoding body)"
ip = get_remote_ip(request)
try:
data = json.loads(body)
except ValueError:
data = {}
obj = cls.objects.create(
headers=dict(request.headers),
body=body,
remote_ip=ip,
stripe_trigger_account=StripeModel._find_owner_account(data=data),
)
try:
obj.valid = obj.validate()
if obj.valid:
if djstripe_settings.WEBHOOK_EVENT_CALLBACK:
# If WEBHOOK_EVENT_CALLBACK, pass it for processing
djstripe_settings.WEBHOOK_EVENT_CALLBACK(obj)
else:
# Process the item (do not save it, it'll get saved below)
obj.process(save=False)
except Exception as e:
max_length = WebhookEventTrigger._meta.get_field("exception").max_length
obj.exception = str(e)[:max_length]
obj.traceback = format_exc()
# Send the exception as the webhook_processing_error signal
webhook_processing_error.send(
sender=WebhookEventTrigger,
exception=e,
data=getattr(e, "http_body", ""),
)
# re-raise the exception so Django sees it
raise e
finally:
obj.save()
return obj
djstripe.models.webhooks.WebhookEventTrigger.get_next_by_created(self, *, field=<django.db.models.fields.DateTimeField: created>, is_next=True, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEventTrigger.get_next_by_updated(self, *, field=<django.db.models.fields.DateTimeField: updated>, is_next=True, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEventTrigger.get_previous_by_created(self, *, field=<django.db.models.fields.DateTimeField: created>, is_next=False, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEventTrigger.get_previous_by_updated(self, *, field=<django.db.models.fields.DateTimeField: updated>, is_next=False, **kwargs)
Source code in djstripe/models/webhooks.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
djstripe.models.webhooks.WebhookEventTrigger.process(self, save=True)
Source code in djstripe/models/webhooks.py
def process(self, save=True):
# Reset traceback and exception in case of reprocessing
self.exception = ""
self.traceback = ""
self.event = Event.process(self.json_body)
self.processed = True
if save:
self.save()
return self.event
djstripe.models.webhooks.WebhookEventTrigger.validate(self, api_key=None)
The original contents of the Event message must be confirmed by refetching it and comparing the fetched data with the original data.
This function makes an API call to Stripe to redownload the Event data and returns whether or not it matches the WebhookEventTrigger data.
Source code in djstripe/models/webhooks.py
def validate(self, api_key=None):
"""
The original contents of the Event message must be confirmed by
refetching it and comparing the fetched data with the original data.
This function makes an API call to Stripe to redownload the Event data
and returns whether or not it matches the WebhookEventTrigger data.
"""
local_data = self.json_body
if "id" not in local_data or "livemode" not in local_data:
logger.error(
'"id" not in json body or "livemode" not in json body(%s)', local_data
)
return False
if self.is_test_event:
logger.info("Test webhook received and discarded: {}".format(local_data))
return False
if djstripe_settings.WEBHOOK_VALIDATION is None:
# validation disabled
warnings.warn("WEBHOOK VALIDATION is disabled.")
return True
elif (
djstripe_settings.WEBHOOK_VALIDATION == "verify_signature"
and djstripe_settings.WEBHOOK_SECRET
):
# HTTP headers are case-insensitive, but we store them as a dict.
headers = CaseInsensitiveMapping(self.headers)
try:
stripe.WebhookSignature.verify_header(
self.body,
headers.get("stripe-signature"),
djstripe_settings.WEBHOOK_SECRET,
djstripe_settings.WEBHOOK_TOLERANCE,
)
except stripe.error.SignatureVerificationError:
logger.exception("Failed to verify header")
return False
else:
return True
livemode = local_data["livemode"]
api_key = api_key or djstripe_settings.get_default_api_key(livemode)
# Retrieve the event using the api_version specified in itself
with stripe_temporary_api_version(local_data["api_version"], validate=False):
remote_data = Event.stripe_class.retrieve(
id=local_data["id"], api_key=api_key
)
return local_data["data"] == remote_data["data"]
Functions
djstripe.models.webhooks.get_remote_ip(request)
Given the HTTPRequest object return the IP Address of the client
:param request: client request :type request: HTTPRequest
:Returns: the client ip address
Source code in djstripe/models/webhooks.py
def get_remote_ip(request):
"""Given the HTTPRequest object return the IP Address of the client
:param request: client request
:type request: HTTPRequest
:Returns: the client ip address
"""
# HTTP_X_FORWARDED_FOR is relevant for django running behind a proxy
x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR")
if x_forwarded_for:
ip = x_forwarded_for.split(",")[0]
else:
ip = request.META.get("REMOTE_ADDR")
if not ip:
warnings.warn(
"Could not determine remote IP (missing REMOTE_ADDR). "
"This is likely an issue with your wsgi/server setup."
)
ip = "0.0.0.0"
return ip
djstripe.settings
dj-stripe settings
djstripe.settings.djstripe_settings
Classes
djstripe.settings.DjstripeSettings
Container for Dj-stripe settings
:return: Initialised settings for Dj-stripe. :rtype: object
Attributes
djstripe.settings.DjstripeSettings.CANCELLATION_AT_PERIOD_END
property
readonly
djstripe.settings.DjstripeSettings.DEFAULT_STRIPE_API_VERSION
djstripe.settings.DjstripeSettings.DJSTRIPE_WEBHOOK_URL
property
readonly
djstripe.settings.DjstripeSettings.LIVE_API_KEY
property
readonly
djstripe.settings.DjstripeSettings.PRORATION_POLICY
property
readonly
djstripe.settings.DjstripeSettings.STRIPE_API_VERSION
property
readonly
Get the desired API version to use for Stripe requests.
djstripe.settings.DjstripeSettings.STRIPE_LIVE_MODE
property
readonly
djstripe.settings.DjstripeSettings.STRIPE_PUBLIC_KEY
property
readonly
djstripe.settings.DjstripeSettings.STRIPE_SECRET_KEY
property
readonly
djstripe.settings.DjstripeSettings.SUBSCRIBER_CUSTOMER_KEY
property
readonly
djstripe.settings.DjstripeSettings.SUBSCRIPTION_REDIRECT
property
readonly
djstripe.settings.DjstripeSettings.SUBSCRIPTION_REQUIRED_EXCEPTION_URLS
property
readonly
djstripe.settings.DjstripeSettings.TEST_API_KEY
property
readonly
djstripe.settings.DjstripeSettings.USE_NATIVE_JSONFIELD
property
readonly
djstripe.settings.DjstripeSettings.WEBHOOK_EVENT_CALLBACK
property
readonly
djstripe.settings.DjstripeSettings.WEBHOOK_SECRET
property
readonly
djstripe.settings.DjstripeSettings.WEBHOOK_TOLERANCE
property
readonly
djstripe.settings.DjstripeSettings.WEBHOOK_VALIDATION
property
readonly
djstripe.settings.DjstripeSettings.ZERO_DECIMAL_CURRENCIES
djstripe.settings.DjstripeSettings.get_idempotency_key
property
readonly
djstripe.settings.DjstripeSettings.subscriber_request_callback
property
readonly
Methods
djstripe.settings.DjstripeSettings.__delattr__(self, name)
special
Source code in djstripe/settings.py
def __delattr__(self, name):
del self.__dict__[name]
djstripe.settings.DjstripeSettings.__init__(self)
special
Source code in djstripe/settings.py
def __init__(self):
# Set STRIPE_API_HOST if you want to use a different Stripe API server
# Example: https://github.com/stripe/stripe-mock
if hasattr(settings, "STRIPE_API_HOST"):
stripe.api_base = getattr(settings, "STRIPE_API_HOST")
djstripe.settings.DjstripeSettings.__setattr__(self, name, value)
special
Source code in djstripe/settings.py
def __setattr__(self, name, value):
self.__dict__[name] = value
djstripe.settings.DjstripeSettings.get_callback_function(self, setting_name, default=None)
Resolve a callback function based on a setting name.
If the setting value isn't set, default is returned. If the setting value is already a callable function, that value is used - If the setting value is a string, an attempt is made to import it. Anything else will result in a failed import causing ImportError to be raised.
:param setting_name: The name of the setting to resolve a callback from.
:type setting_name: string (str
/unicode
)
:param default: The default to return if setting isn't populated.
:type default: bool
:returns: The resolved callback function (if any).
:type: callable
Source code in djstripe/settings.py
def get_callback_function(self, setting_name, default=None):
"""
Resolve a callback function based on a setting name.
If the setting value isn't set, default is returned. If the setting value
is already a callable function, that value is used - If the setting value
is a string, an attempt is made to import it. Anything else will result in
a failed import causing ImportError to be raised.
:param setting_name: The name of the setting to resolve a callback from.
:type setting_name: string (``str``/``unicode``)
:param default: The default to return if setting isn't populated.
:type default: ``bool``
:returns: The resolved callback function (if any).
:type: ``callable``
"""
func = getattr(settings, setting_name, None)
if not func:
return default
if callable(func):
return func
if isinstance(func, str):
func = import_string(func)
if not callable(func):
raise ImproperlyConfigured(
"{name} must be callable.".format(name=setting_name)
)
return func
djstripe.settings.DjstripeSettings.get_default_api_key(self, livemode)
Returns the default API key for a value of livemode
.
Source code in djstripe/settings.py
def get_default_api_key(self, livemode):
"""
Returns the default API key for a value of `livemode`.
"""
if livemode is None:
# Livemode is unknown. Use the default secret key.
return self.STRIPE_SECRET_KEY
elif livemode:
# Livemode is true, use the live secret key
return self.LIVE_API_KEY or self.STRIPE_SECRET_KEY
else:
# Livemode is false, use the test secret key
return self.TEST_API_KEY or self.STRIPE_SECRET_KEY
djstripe.settings.DjstripeSettings.get_subscriber_model(self)
Attempt to pull settings.DJSTRIPE_SUBSCRIBER_MODEL.
Users have the option of specifying a custom subscriber model via the DJSTRIPE_SUBSCRIBER_MODEL setting.
This methods falls back to AUTH_USER_MODEL if DJSTRIPE_SUBSCRIBER_MODEL is not set.
Returns the subscriber model that is active in this project.
Source code in djstripe/settings.py
def get_subscriber_model(self):
"""
Attempt to pull settings.DJSTRIPE_SUBSCRIBER_MODEL.
Users have the option of specifying a custom subscriber model via the
DJSTRIPE_SUBSCRIBER_MODEL setting.
This methods falls back to AUTH_USER_MODEL if DJSTRIPE_SUBSCRIBER_MODEL is not set.
Returns the subscriber model that is active in this project.
"""
model_name = self.get_subscriber_model_string()
# Attempt a Django 1.7 app lookup
try:
subscriber_model = django_apps.get_model(model_name)
except ValueError:
raise ImproperlyConfigured(
"DJSTRIPE_SUBSCRIBER_MODEL must be of the form 'app_label.model_name'."
)
except LookupError:
raise ImproperlyConfigured(
"DJSTRIPE_SUBSCRIBER_MODEL refers to model '{model}' "
"that has not been installed.".format(model=model_name)
)
if (
"email"
not in [field_.name for field_ in subscriber_model._meta.get_fields()]
) and not hasattr(subscriber_model, "email"):
raise ImproperlyConfigured(
"DJSTRIPE_SUBSCRIBER_MODEL must have an email attribute."
)
if model_name != settings.AUTH_USER_MODEL:
# Custom user model detected. Make sure the callback is configured.
func = self.get_callback_function(
"DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK"
)
if not func:
raise ImproperlyConfigured(
"DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK must be implemented "
"if a DJSTRIPE_SUBSCRIBER_MODEL is defined."
)
return subscriber_model
djstripe.settings.DjstripeSettings.get_subscriber_model_string(self)
Get the configured subscriber model as a module path string.
Source code in djstripe/settings.py
def get_subscriber_model_string(self):
"""Get the configured subscriber model as a module path string."""
return getattr(settings, "DJSTRIPE_SUBSCRIBER_MODEL", settings.AUTH_USER_MODEL)
djstripe.settings.DjstripeSettings.set_stripe_api_version(self, version=None, validate=True)
Set the desired API version to use for Stripe requests.
:param version: The version to set for the Stripe API.
:type version: str
:param validate: If True validate the value for the specified version).
:type validate: bool
Source code in djstripe/settings.py
def set_stripe_api_version(self, version=None, validate=True):
"""
Set the desired API version to use for Stripe requests.
:param version: The version to set for the Stripe API.
:type version: ``str``
:param validate: If True validate the value for the specified version).
:type validate: ``bool``
"""
version = version or self.STRIPE_API_VERSION
if validate:
valid = validate_stripe_api_version(version)
if not valid:
raise ValueError("Bad stripe API version: {}".format(version))
stripe.api_version = version
djstripe.signals
signals are sent for each event Stripe sends to the app
Stripe docs for Webhooks: https://stripe.com/docs/webhooks
djstripe.signals.WEBHOOK_SIGNALS
djstripe.signals.webhook_processing_error
djstripe.sync
Utility functions used for syncing data.
Functions
djstripe.sync.sync_subscriber(subscriber)
Sync a Customer with Stripe api data.
Source code in djstripe/sync.py
def sync_subscriber(subscriber):
"""Sync a Customer with Stripe api data."""
customer, _created = Customer.get_or_create(subscriber=subscriber)
try:
customer.sync_from_stripe_data(customer.api_retrieve())
customer._sync_subscriptions()
customer._sync_invoices()
customer._sync_cards()
customer._sync_charges()
except InvalidRequestError as e:
print("ERROR: " + str(e))
return customer
djstripe.urls
Urls related to the djstripe app.
Wire this into the root URLConf this way::
path("stripe/", include("djstripe.urls", namespace="djstripe")),
# url can be changed
# Call to 'djstripe.urls' and 'namespace' must stay as is
djstripe.urls.app_name
djstripe.urls.urlpatterns
djstripe.utils
Utility functions related to the djstripe app.
djstripe.utils.CURRENCY_SIGILS
Classes
djstripe.utils.QuerySetMock
A mocked QuerySet class that does not handle updates. Used by UpcomingInvoice.invoiceitems.
Methods
djstripe.utils.QuerySetMock.delete(self)
Delete the records in the current QuerySet.
Source code in djstripe/utils.py
def delete(self):
return 0
djstripe.utils.QuerySetMock.from_iterable(model, iterable)
classmethod
Source code in djstripe/utils.py
@classmethod
def from_iterable(cls, model, iterable):
instance = cls(model)
instance._result_cache = list(iterable)
instance._prefetch_done = True
return instance
djstripe.utils.QuerySetMock.update(self)
Update all elements in the current QuerySet, setting all the given fields to the appropriate values.
Source code in djstripe/utils.py
def update(self):
return 0
Functions
djstripe.utils.clear_expired_idempotency_keys()
Source code in djstripe/utils.py
def clear_expired_idempotency_keys():
from .models import IdempotencyKey
threshold = timezone.now() - datetime.timedelta(hours=24)
IdempotencyKey.objects.filter(created__lt=threshold).delete()
djstripe.utils.convert_tstamp(response)
Convert a Stripe API timestamp response (unix epoch) to a native datetime.
Source code in djstripe/utils.py
def convert_tstamp(response) -> Optional[datetime.datetime]:
"""
Convert a Stripe API timestamp response (unix epoch) to a native datetime.
"""
if response is None:
# Allow passing None to convert_tstamp()
return response
# Overrides the set timezone to UTC - I think...
tz = timezone.utc if settings.USE_TZ else None
return datetime.datetime.fromtimestamp(response, tz)
djstripe.utils.get_friendly_currency_amount(amount, currency)
Source code in djstripe/utils.py
def get_friendly_currency_amount(amount, currency: str) -> str:
currency = currency.upper()
sigil = CURRENCY_SIGILS.get(currency, "")
return "{sigil}{amount:.2f} {currency}".format(
sigil=sigil, amount=amount, currency=currency
)
djstripe.utils.get_supported_currency_choices(api_key)
Pull a stripe account's supported currencies and returns a choices tuple of those supported currencies.
:param api_key: The api key associated with the account from which to pull data. :type api_key: str
Source code in djstripe/utils.py
def get_supported_currency_choices(api_key):
"""
Pull a stripe account's supported currencies and returns a choices tuple of those
supported currencies.
:param api_key: The api key associated with the account from which to pull data.
:type api_key: str
"""
import stripe
stripe.api_key = api_key
account = stripe.Account.retrieve()
supported_payment_currencies = stripe.CountrySpec.retrieve(account["country"])[
"supported_payment_currencies"
]
return [(currency, currency.upper()) for currency in supported_payment_currencies]
djstripe.views
dj-stripe - Views related to the djstripe app.
djstripe.views.logger
Classes
djstripe.views.ProcessWebhookView
A Stripe Webhook handler view.
This will create a WebhookEventTrigger instance, verify it, then attempt to process it.
If the webhook cannot be verified, returns HTTP 400.
If an exception happens during processing, returns HTTP 500.
djstripe.views.ProcessWebhookView.dispatch(self, request, *args, **kwargs)
Source code in djstripe/views.py
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
djstripe.views.ProcessWebhookView.post(self, request)
Source code in djstripe/views.py
def post(self, request):
if "HTTP_STRIPE_SIGNATURE" not in request.META:
# Do not even attempt to process/store the event if there is
# no signature in the headers so we avoid overfilling the db.
logger.error("HTTP_STRIPE_SIGNATURE is missing")
return HttpResponseBadRequest()
trigger = WebhookEventTrigger.from_request(request)
if trigger.is_test_event:
# Since we don't do signature verification, we have to skip trigger.valid
return HttpResponse("Test webhook successfully received and discarded!")
if not trigger.valid:
# Webhook Event did not validate, return 400
logger.error("Trigger object did not validate")
return HttpResponseBadRequest()
return HttpResponse(str(trigger.id))
djstripe.webhooks
Utils related to processing or registering for webhooks
A model registers itself here if it wants to be in the list of processing functions for a particular webhook. Each processor will have the ability to modify the event object, access event data, and do what it needs to do
registrations are keyed by top-level event type (e.g. "invoice", "customer", etc)
Each registration entry is a list of processors
Each processor in these lists is a function to be called
The function signature is:
There is also a "global registry" which is just a list of processors (as defined above)
NOTE: global processors are called before other processors.
djstripe.webhooks.TEST_EVENT_ID
djstripe.webhooks.__all__
special
djstripe.webhooks.registrations
djstripe.webhooks.registrations_global
Functions
djstripe.webhooks.call_handlers(event)
Invoke all handlers for the provided event type/sub-type.
The handlers are invoked in the following order:
- Global handlers
- Event type handlers
- Event sub-type handlers
Handlers within each group are invoked in order of registration.
:param event: The event model object.
:type event: djstripe.models.Event
Source code in djstripe/webhooks.py
def call_handlers(event):
"""
Invoke all handlers for the provided event type/sub-type.
The handlers are invoked in the following order:
1. Global handlers
2. Event type handlers
3. Event sub-type handlers
Handlers within each group are invoked in order of registration.
:param event: The event model object.
:type event: ``djstripe.models.Event``
"""
chain = [registrations_global]
# Build up a list of handlers with each qualified part of the event
# category and verb. For example, "customer.subscription.created" creates:
# 1. "customer"
# 2. "customer.subscription"
# 3. "customer.subscription.created"
for index, _ in enumerate(event.parts):
qualified_event_type = ".".join(event.parts[: (index + 1)])
chain.append(registrations[qualified_event_type])
for handler_func in itertools.chain(*chain):
handler_func(event=event)
djstripe.webhooks.handler(*event_types)
Decorator that registers a function as a webhook handler.
Functions can be registered for event types (e.g. 'customer') or fully qualified event sub-types (e.g. 'customer.subscription.deleted').
If an event type is specified, the handler will receive callbacks for ALL webhook events of that type. For example, if 'customer' is specified, the handler will receive events for 'customer.subscription.created', 'customer.subscription.updated', etc.
:param event_types: The event type(s) that should be handled. :type event_types: str.
Source code in djstripe/webhooks.py
def handler(*event_types):
"""
Decorator that registers a function as a webhook handler.
Functions can be registered for event types (e.g. 'customer') or
fully qualified event sub-types (e.g. 'customer.subscription.deleted').
If an event type is specified, the handler will receive callbacks for
ALL webhook events of that type. For example, if 'customer' is specified,
the handler will receive events for 'customer.subscription.created',
'customer.subscription.updated', etc.
:param event_types: The event type(s) that should be handled.
:type event_types: str.
"""
def decorator(func):
for event_type in event_types:
registrations[event_type].append(func)
return func
return decorator
djstripe.webhooks.handler_all(func=None)
Decorator that registers a function as a webhook handler for ALL webhook events.
Handles all webhooks regardless of event type or sub-type.
Source code in djstripe/webhooks.py
def handler_all(func=None):
"""
Decorator that registers a function as a webhook handler for ALL webhook events.
Handles all webhooks regardless of event type or sub-type.
"""
if not func:
return functools.partial(handler_all)
registrations_global.append(func)
return func
A Fake or multiple fakes for each stripe object.
Originally collected using API VERSION 2015-07-28. Updated to API VERSION 2016-03-07 with bogus fields.
tests.FAKE_ACCOUNT
tests.FAKE_BALANCE_TRANSACTION
tests.FAKE_BALANCE_TRANSACTION_II
tests.FAKE_BALANCE_TRANSACTION_III
tests.FAKE_BALANCE_TRANSACTION_IV
tests.FAKE_BALANCE_TRANSACTION_REFUND
tests.FAKE_BANK_ACCOUNT
tests.FAKE_BANK_ACCOUNT_II
tests.FAKE_BANK_ACCOUNT_IV
tests.FAKE_BANK_ACCOUNT_SOURCE
tests.FAKE_CARD
tests.FAKE_CARD_AS_PAYMENT_METHOD
tests.FAKE_CARD_II
tests.FAKE_CARD_III
tests.FAKE_CARD_IV
tests.FAKE_CHARGE
tests.FAKE_CHARGE_II
tests.FAKE_CHARGE_REFUNDED
tests.FAKE_COUPON
tests.FAKE_CUSTOMER
tests.FAKE_CUSTOMER_II
tests.FAKE_CUSTOMER_III
tests.FAKE_CUSTOMER_IV
tests.FAKE_CUSTOM_ACCOUNT
tests.FAKE_DISCOUNT_CUSTOMER
tests.FAKE_DISPUTE_BALANCE_TRANSACTION
tests.FAKE_DISPUTE_BALANCE_TRANSACTION_REFUND_FULL
tests.FAKE_DISPUTE_BALANCE_TRANSACTION_REFUND_PARTIAL
tests.FAKE_DISPUTE_CHARGE
tests.FAKE_DISPUTE_I
tests.FAKE_DISPUTE_II
tests.FAKE_DISPUTE_III
tests.FAKE_DISPUTE_IV
tests.FAKE_DISPUTE_PAYMENT_INTENT
tests.FAKE_DISPUTE_PAYMENT_METHOD
tests.FAKE_DISPUTE_V_FULL
tests.FAKE_DISPUTE_V_PARTIAL
tests.FAKE_EVENT_ACCOUNT_APPLICATION_AUTHORIZED
tests.FAKE_EVENT_ACCOUNT_APPLICATION_DEAUTHORIZED
tests.FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_CREATED
tests.FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_DELETED
tests.FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_UPDATED
tests.FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_CREATED
tests.FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_DELETED
tests.FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_UPDATED
tests.FAKE_EVENT_CARD_PAYMENT_METHOD_ATTACHED
tests.FAKE_EVENT_CARD_PAYMENT_METHOD_DETACHED
tests.FAKE_EVENT_CHARGE_SUCCEEDED
tests.FAKE_EVENT_CUSTOMER_CREATED
tests.FAKE_EVENT_CUSTOMER_DELETED
tests.FAKE_EVENT_CUSTOMER_DISCOUNT_CREATED
tests.FAKE_EVENT_CUSTOMER_DISCOUNT_DELETED
tests.FAKE_EVENT_CUSTOMER_SOURCE_CREATED
tests.FAKE_EVENT_CUSTOMER_SOURCE_DELETED
tests.FAKE_EVENT_CUSTOMER_SOURCE_DELETED_DUPE
tests.FAKE_EVENT_CUSTOMER_SUBSCRIPTION_CREATED
tests.FAKE_EVENT_CUSTOMER_SUBSCRIPTION_DELETED
tests.FAKE_EVENT_CUSTOMER_UPDATED
tests.FAKE_EVENT_CUSTOM_ACCOUNT_UPDATED
tests.FAKE_EVENT_DISPUTE_CLOSED
tests.FAKE_EVENT_DISPUTE_CREATED
tests.FAKE_EVENT_DISPUTE_FUNDS_REINSTATED_FULL
tests.FAKE_EVENT_DISPUTE_FUNDS_REINSTATED_PARTIAL
tests.FAKE_EVENT_DISPUTE_FUNDS_WITHDRAWN
tests.FAKE_EVENT_DISPUTE_UPDATED
tests.FAKE_EVENT_EXPRESS_ACCOUNT_UPDATED
tests.FAKE_EVENT_FILE_CREATED
tests.FAKE_EVENT_INVOICEITEM_CREATED
tests.FAKE_EVENT_INVOICEITEM_DELETED
tests.FAKE_EVENT_INVOICE_CREATED
tests.FAKE_EVENT_INVOICE_DELETED
tests.FAKE_EVENT_INVOICE_UPCOMING
tests.FAKE_EVENT_PAYMENT_INTENT_SUCCEEDED_DESTINATION_CHARGE
tests.FAKE_EVENT_PAYMENT_METHOD_ATTACHED
tests.FAKE_EVENT_PAYMENT_METHOD_DETACHED
tests.FAKE_EVENT_PLAN_CREATED
tests.FAKE_EVENT_PLAN_DELETED
tests.FAKE_EVENT_PLAN_REQUEST_IS_OBJECT
tests.FAKE_EVENT_PRICE_CREATED
tests.FAKE_EVENT_PRICE_DELETED
tests.FAKE_EVENT_PRICE_UPDATED
tests.FAKE_EVENT_SESSION_COMPLETED
tests.FAKE_EVENT_STANDARD_ACCOUNT_UPDATED
tests.FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CANCELED
tests.FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CREATED
tests.FAKE_EVENT_SUBSCRIPTION_SCHEDULE_RELEASED
tests.FAKE_EVENT_SUBSCRIPTION_SCHEDULE_UPDATED
tests.FAKE_EVENT_TAX_ID_CREATED
tests.FAKE_EVENT_TAX_ID_DELETED
tests.FAKE_EVENT_TAX_ID_UPDATED
tests.FAKE_EVENT_TEST_CHARGE_SUCCEEDED
tests.FAKE_EVENT_TRANSFER_CREATED
tests.FAKE_EVENT_TRANSFER_DELETED
tests.FAKE_EXPRESS_ACCOUNT
tests.FAKE_FILEUPLOAD_ICON
tests.FAKE_FILEUPLOAD_LOGO
tests.FAKE_INVOICE
tests.FAKE_INVOICEITEM
tests.FAKE_INVOICEITEM_II
tests.FAKE_INVOICEITEM_III
tests.FAKE_INVOICE_II
tests.FAKE_INVOICE_III
tests.FAKE_INVOICE_IV
tests.FAKE_INVOICE_METERED_SUBSCRIPTION
tests.FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE
tests.FAKE_PAYMENT_INTENT_DESTINATION_CHARGE
tests.FAKE_PAYMENT_INTENT_I
tests.FAKE_PAYMENT_INTENT_II
tests.FAKE_PAYMENT_METHOD_I
tests.FAKE_PAYMENT_METHOD_II
tests.FAKE_PLAN
tests.FAKE_PLAN_II
tests.FAKE_PLAN_METERED
tests.FAKE_PLATFORM_ACCOUNT
tests.FAKE_PRICE
tests.FAKE_PRICE_II
tests.FAKE_PRICE_METERED
tests.FAKE_PRICE_ONETIME
tests.FAKE_PRICE_TIER
tests.FAKE_PRODUCT
tests.FAKE_REFUND
tests.FAKE_SESSION_I
tests.FAKE_SETUP_INTENT_DESTINATION_CHARGE
tests.FAKE_SETUP_INTENT_I
tests.FAKE_SETUP_INTENT_II
tests.FAKE_SOURCE
tests.FAKE_SOURCE_II
tests.FAKE_STANDARD_ACCOUNT
tests.FAKE_SUBSCRIPTION
tests.FAKE_SUBSCRIPTION_CANCELED
tests.FAKE_SUBSCRIPTION_CANCELED_AT_PERIOD_END
tests.FAKE_SUBSCRIPTION_II
tests.FAKE_SUBSCRIPTION_III
tests.FAKE_SUBSCRIPTION_ITEM
tests.FAKE_SUBSCRIPTION_ITEM_METERED
tests.FAKE_SUBSCRIPTION_ITEM_MULTI_PLAN
tests.FAKE_SUBSCRIPTION_ITEM_TAX_RATES
tests.FAKE_SUBSCRIPTION_METERED
tests.FAKE_SUBSCRIPTION_MULTI_PLAN
tests.FAKE_SUBSCRIPTION_NOT_PERIOD_CURRENT
tests.FAKE_SUBSCRIPTION_SCHEDULE
tests.FAKE_TAX_ID
tests.FAKE_TAX_ID_UPDATED
tests.FAKE_TAX_RATE_EXAMPLE_1_VAT
tests.FAKE_TAX_RATE_EXAMPLE_2_SALES
tests.FAKE_TIER_PLAN
tests.FAKE_TOKEN
tests.FAKE_TRANSFER
tests.FAKE_TRANSFER_WITH_1_REVERSAL
tests.FAKE_UPCOMING_INVOICE
tests.FAKE_USAGE_RECORD
tests.FAKE_USAGE_RECORD_SUMMARY
tests.FIXTURE_DIR_PATH
tests.FUTURE_DATE
tests.IS_STATICMETHOD_AUTOSPEC_SUPPORTED
tests.logger
Classes
tests.AccountDict
tests.AccountDict.external_accounts
property
readonly
tests.AccountDict.create(self)
Source code in tests/__init__.py
def create(self):
from djstripe.models import Account
return Account.sync_from_stripe_data(self)
tests.AccountDict.save(self, idempotency_key=None)
Source code in tests/__init__.py
def save(self, idempotency_key=None):
return self
tests.AssertStripeFksMixin
Methods
tests.AssertStripeFksMixin.assert_fks(self, obj, expected_blank_fks, processed_stripe_ids=None)
Recursively walk through fks on obj, asserting they're not-none :param obj: :param expected_blank_fks: fields that are expected to be None :param processed_stripe_ids: set of objects ids already processed :return:
Source code in tests/__init__.py
def assert_fks(self, obj, expected_blank_fks, processed_stripe_ids=None):
"""
Recursively walk through fks on obj, asserting they're not-none
:param obj:
:param expected_blank_fks: fields that are expected to be None
:param processed_stripe_ids: set of objects ids already processed
:return:
"""
if processed_stripe_ids is None:
processed_stripe_ids = set()
processed_stripe_ids.add(obj.id)
for field in obj._meta.get_fields():
field_str = self._get_field_str(field)
if not field_str or field_str.endswith(".djstripe_owner_account"):
continue
try:
field_value = getattr(obj, field.name)
except ObjectDoesNotExist:
field_value = None
if field_str in expected_blank_fks:
self.assertIsNone(field_value, field_str)
else:
self.assertIsNotNone(field_value, field_str)
if field_value.id not in processed_stripe_ids:
# recurse into the object if it's not already been checked
self.assert_fks(
field_value, expected_blank_fks, processed_stripe_ids
)
logger.warning("checked {}".format(field_str))
tests.BankAccountDict
tests.CardDict
tests.ChargeDict
Methods
tests.ChargeDict.__init__(self, *args, **kwargs)
special
Match Stripe's behavior: return a stripe iterable on charge.refunds
.
Source code in tests/__init__.py
def __init__(self, *args, **kwargs):
"""Match Stripe's behavior: return a stripe iterable on `charge.refunds`."""
super().__init__(*args, **kwargs)
self.refunds = StripeList(self.refunds)
tests.ChargeDict.capture(self)
Source code in tests/__init__.py
def capture(self):
self.update({"captured": True})
return self
tests.ChargeDict.refund(self, amount=None, reason=None)
Source code in tests/__init__.py
def refund(self, amount=None, reason=None):
self.update({"refunded": True, "amount_refunded": amount})
return self
tests.CustomerDict
tests.CustomerDict.sources
property
readonly
tests.CustomerDict.__init__(self, *args, **kwargs)
special
Source code in tests/__init__.py
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self["default_source"] = convert_source_dict(self["default_source"])
for n, d in enumerate(self["sources"].get("data", [])):
self["sources"]["data"][n] = convert_source_dict(d)
tests.CustomerDict.create_for_user(self, user)
Source code in tests/__init__.py
def create_for_user(self, user):
from djstripe.models import Customer
stripe_customer = Customer.sync_from_stripe_data(self)
stripe_customer.subscriber = user
stripe_customer.save()
return stripe_customer
tests.CustomerDict.delete(self)
Source code in tests/__init__.py
def delete(self):
return self
tests.CustomerDict.save(self, idempotency_key=None)
Source code in tests/__init__.py
def save(self, idempotency_key=None):
return self
tests.ExternalAccounts
tests.ExternalAccounts.__init__(self, external_account_fakes)
special
Source code in tests/__init__.py
def __init__(self, external_account_fakes):
self.external_account_fakes = external_account_fakes
tests.ExternalAccounts.create(self, source, api_key=None)
Source code in tests/__init__.py
def create(self, source, api_key=None):
for fake_external_account in self.external_account_fakes:
if fake_external_account["id"] == source:
return fake_external_account
tests.ExternalAccounts.list(self, **kwargs)
Source code in tests/__init__.py
def list(self, **kwargs):
return StripeList(data=self.external_account_fakes)
tests.ExternalAccounts.retrieve(self, id, expand=None)
Source code in tests/__init__.py
def retrieve(self, id, expand=None): # noqa
for fake_external_account in self.external_account_fakes:
if fake_external_account["id"] == id:
return fake_external_account
tests.InvoiceDict
Methods
tests.InvoiceDict.__init__(self, *args, **kwargs)
special
Match Stripe's behavior: return a stripe iterable on invoice.lines
.
Source code in tests/__init__.py
def __init__(self, *args, **kwargs):
"""Match Stripe's behavior: return a stripe iterable on `invoice.lines`."""
super().__init__(*args, **kwargs)
self.lines = StripeList(self.lines)
tests.InvoiceDict.pay(self)
Source code in tests/__init__.py
def pay(self):
return self
tests.LegacySourceDict
tests.LegacySourceDict.delete(self)
Source code in tests/__init__.py
def delete(self):
return self
tests.PaymentMethodDict
tests.PaymentMethodDict.detach(self)
Source code in tests/__init__.py
def detach(self):
self.pop("customer")
return self
tests.SourceDict
tests.SourceDict.detach(self)
Source code in tests/__init__.py
def detach(self):
self.pop("customer")
self.update({"status": "consumed"})
return self
tests.Sources
tests.Sources.__init__(self, card_fakes)
special
Source code in tests/__init__.py
def __init__(self, card_fakes):
self.card_fakes = card_fakes
tests.Sources.create(self, source, api_key=None)
Source code in tests/__init__.py
def create(self, source, api_key=None):
for fake_card in self.card_fakes:
if fake_card["id"] == source:
return fake_card
tests.Sources.list(self, **kwargs)
Source code in tests/__init__.py
def list(self, **kwargs):
return StripeList(data=self.card_fakes)
tests.Sources.retrieve(self, id, expand=None)
Source code in tests/__init__.py
def retrieve(self, id, expand=None): # noqa
for fake_card in self.card_fakes:
if fake_card["id"] == id:
return fake_card
tests.StripeItem
Flexible class built to mock any generic Stripe object.
Implements object access + deletion methods to match the behavior of Stripe's library, which allows both object + dictionary access.
Has a delete method since (most) Stripe objects can be deleted.
Methods
tests.StripeItem.__delattr__(self, name)
special
Source code in tests/__init__.py
def __delattr__(self, name):
if name in self:
del self[name]
else:
raise AttributeError("No such attribute: " + name)
tests.StripeItem.__getattr__(self, name)
special
Give StripeItem normal object access to match Stripe behavior.
Source code in tests/__init__.py
def __getattr__(self, name):
"""Give StripeItem normal object access to match Stripe behavior."""
if name in self:
return self[name]
else:
raise AttributeError("No such attribute: " + name)
tests.StripeItem.__setattr__(self, name, value)
special
Source code in tests/__init__.py
def __setattr__(self, name, value):
self[name] = value
tests.StripeItem.class_url()
classmethod
Source code in tests/__init__.py
@classmethod
def class_url(cls):
return "/v1/test-items/"
tests.StripeItem.delete(self)
Superficial mock that adds a deleted attribute.
Source code in tests/__init__.py
def delete(self) -> bool:
"""Superficial mock that adds a deleted attribute."""
self.deleted = True
return self.deleted
tests.StripeItem.instance_url(self)
Superficial mock that emulates instance_url.
Source code in tests/__init__.py
def instance_url(self):
"""Superficial mock that emulates instance_url."""
id = self.get("id")
base = self.class_url()
return "%s/%s" % (base, id)
tests.StripeItem.request(self, method, url, params)
Superficial mock that emulates request method.
Source code in tests/__init__.py
def request(self, method, url, params) -> dict:
"""Superficial mock that emulates request method."""
assert method == "post"
for key, value in params.items():
self.__setattr__(key, value)
return self
tests.StripeList
Mock a generic Stripe Iterable.
It has the relevant attributes of a stripe iterable (has_more, data).
This mock is important so we can use stripe's list
method in our testing.
StripeList.list() will return the StripeList.
Additionally, iterating over instances of MockStripeIterable will iterate over the data attribute, just like Stripe iterables.
Attributes:
Name | Type | Description |
---|---|---|
has_more |
mock has_more flag. Default False. |
|
**kwargs |
all of the fields of the stripe object, generally as a dictionary. |
tests.StripeList.has_more
tests.StripeList.object
tests.StripeList.total_count
property
readonly
tests.StripeList.url
Methods
tests.StripeList.__delattr__(self, name)
special
Source code in tests/__init__.py
def __delattr__(self, name):
if name in self:
del self[name]
else:
raise AttributeError("No such attribute: " + name)
tests.StripeList.__getattr__(self, name)
special
Give StripeItem normal object access to match Stripe behavior.
Source code in tests/__init__.py
def __getattr__(self, name):
"""Give StripeItem normal object access to match Stripe behavior."""
if name in self:
return self[name]
else:
raise AttributeError("No such attribute: " + name)
tests.StripeList.__iter__(self)
special
Make StripeList an iterable, to match the Stripe iterable behavior.
Source code in tests/__init__.py
def __iter__(self) -> Any:
"""Make StripeList an iterable, to match the Stripe iterable behavior."""
self.iter_copy = self.data.copy()
return self
tests.StripeList.__next__(self)
special
Define iteration for StripeList.
Source code in tests/__init__.py
def __next__(self) -> StripeItem:
"""Define iteration for StripeList."""
if len(self.iter_copy) > 0:
return self.iter_copy.pop(0)
else:
raise StopIteration()
tests.StripeList.__setattr__(self, name, value)
special
Source code in tests/__init__.py
def __setattr__(self, name, value):
self[name] = value
tests.StripeList.auto_paging_iter(self)
Add an auto_paging_iter method to the StripeList which returns itself.
The StripeList is an iterable, so this mimics the real behavior.
Source code in tests/__init__.py
def auto_paging_iter(self) -> "StripeList":
"""Add an auto_paging_iter method to the StripeList which returns itself.
The StripeList is an iterable, so this mimics the real behavior.
"""
return self
tests.StripeList.list(self, **kwargs)
Add a list method to the StripeList which returns itself.
list() accepts arbitrary kwargs, be careful is you expect the argument-accepting functionality of Stripe's list() method.
Source code in tests/__init__.py
def list(self, **kwargs: Any) -> "StripeList":
"""Add a list method to the StripeList which returns itself.
list() accepts arbitrary kwargs, be careful is you expect the
argument-accepting functionality of Stripe's list() method.
"""
return self
tests.SubscriptionDict
Methods
tests.SubscriptionDict.__init__(self, *args, **kwargs)
special
Match Stripe's behavior: return a stripe iterable on subscription.items
.
Source code in tests/__init__.py
def __init__(self, *args, **kwargs):
"""Match Stripe's behavior: return a stripe iterable on `subscription.items`."""
super().__init__(*args, **kwargs)
self["items"] = StripeList(self["items"])
tests.SubscriptionDict.__setattr__(self, name, value)
special
Source code in tests/__init__.py
def __setattr__(self, name, value):
if type(value) == datetime:
value = datetime_to_unix(value)
# Special case for price and plan
if name == "price":
for price in [
FAKE_PRICE,
FAKE_PRICE_II,
FAKE_PRICE_TIER,
FAKE_PRICE_METERED,
]:
if value == price["id"]:
value = price
elif name == "plan":
for plan in [FAKE_PLAN, FAKE_PLAN_II, FAKE_TIER_PLAN, FAKE_PLAN_METERED]:
if value == plan["id"]:
value = plan
self[name] = value
tests.SubscriptionDict.delete(self, **kwargs)
Superficial mock that adds a deleted attribute.
Source code in tests/__init__.py
def delete(self, **kwargs):
if "at_period_end" in kwargs:
self["cancel_at_period_end"] = kwargs["at_period_end"]
return self
tests.SubscriptionDict.save(self, idempotency_key=None)
Source code in tests/__init__.py
def save(self, idempotency_key=None):
return self
tests.UsageRecordSummaryDict
Methods
tests.UsageRecordSummaryDict.__init__(self, *args, **kwargs)
special
Match Stripe's behavior: return a stripe iterable on invoice.lines
.
Source code in tests/__init__.py
def __init__(self, *args, **kwargs):
"""Match Stripe's behavior: return a stripe iterable on `invoice.lines`."""
super().__init__(*args, **kwargs)
tests.convert_source_dict(data)
Source code in tests/__init__.py
def convert_source_dict(data):
if data:
source_type = data["object"]
if source_type == "card":
data = CardDict(data)
elif source_type == "bank_account":
data = BankAccountDict(data)
elif source_type == "source":
data = SourceDict(data)
else:
raise ValueError("Unknown source type: {}".format(source_type))
return data
tests.datetime_to_unix(datetime_)
Source code in tests/__init__.py
def datetime_to_unix(datetime_):
return int(dateformat.format(datetime_, "U"))
tests.load_fixture(filename)
Source code in tests/__init__.py
def load_fixture(filename):
with FIXTURE_DIR_PATH.joinpath(filename).open("r") as f:
return json.load(f)
Modules
tests.apps
special
Modules
tests.apps.example
special
Modules
tests.apps.example.forms
tests.apps.example.forms.PaymentIntentForm
tests.apps.example.forms.PaymentIntentForm.media
property
readonly
tests.apps.example.forms.PurchaseSubscriptionForm
tests.apps.example.forms.PurchaseSubscriptionForm.media
property
readonly
tests.apps.example.management
special
tests.apps.example.management.commands
special
tests.apps.example.management.commands.regenerate_test_fixtures
tests.apps.example.management.commands.regenerate_test_fixtures.FAKE_ID_METADATA_KEY
tests.apps.example.management.commands.regenerate_test_fixtures.Command
This does the following:
1) Load existing fixtures from JSON files 2) Attempts to read the corresponding objects from Stripe 3) If found, for types Stripe doesn't allow us to choose ids for, we build a map between the fake ids in the fixtures and real Stripe ids 3) If not found, creates objects in Stripe from the fixtures 4) Save objects back as fixtures, using fake ids if available
The rationale for this is so that the fixtures can automatically be updated with Stripe schema changes running this command.
This should make keeping our tests and model schema compatible with Stripe schema changes less pain-staking and simplify the process of upgrading the targeted Stripe API version.
tests.apps.example.management.commands.regenerate_test_fixtures.Command.fake_data_map
tests.apps.example.management.commands.regenerate_test_fixtures.Command.fake_id_map
tests.apps.example.management.commands.regenerate_test_fixtures.Command.help
tests.apps.example.management.commands.regenerate_test_fixtures.Command.add_arguments(self, parser)
Entry point for subclassed commands to add custom arguments.
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def add_arguments(self, parser):
parser.add_argument(
"--delete-stale",
action="store_true",
help="Delete any untouched fixtures in the directory",
)
parser.add_argument(
"--update-sideeffect-fields",
action="store_true",
help="Don't preserve sideeffect fields such as 'created'",
)
tests.apps.example.management.commands.regenerate_test_fixtures.Command.fake_json_ids(self, json_str)
Replace real ids with fakes ones in the JSON fixture
Do this on the serialized JSON string since it's a simple string replace :param json_str: :return:
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def fake_json_ids(self, json_str):
"""
Replace real ids with fakes ones in the JSON fixture
Do this on the serialized JSON string since it's a simple string replace
:param json_str:
:return:
"""
for fake_id, actual_id in self.fake_id_map.items():
json_str = json_str.replace(actual_id, fake_id)
return json_str
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_fake_id(self, obj)
Get a stable fake id from a real Stripe object, we use this so that fixtures are stable :param obj: :return:
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_fake_id(self, obj):
"""
Get a stable fake id from a real Stripe object, we use this so that fixtures
are stable
:param obj:
:return:
"""
fake_id = None
if isinstance(obj, str):
real_id = obj
real_id_map = {v: k for k, v in self.fake_id_map.items()}
fake_id = real_id_map.get(real_id)
elif "metadata" in obj:
# Note: not all objects have a metadata dict
# (eg Account, BalanceTransaction don't)
fake_id = obj.get("metadata", {}).get(FAKE_ID_METADATA_KEY)
elif obj.get("object") == "balance_transaction":
# assume for purposes of fixture generation that 1 balance_transaction per
# source charge (etc)
fake_source_id = self.get_fake_id(obj["source"])
fake_id = "txn_fake_{}".format(fake_source_id)
return fake_id
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_account(self, old_obj, readonly_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_account(self, old_obj, readonly_fields):
obj = djstripe.models.Account().api_retrieve()
return True, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_balance_transaction(self, old_obj)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_balance_transaction(self, old_obj):
source = old_obj["source"]
if source.startswith("ch_"):
charge = djstripe.models.Charge(id=source).api_retrieve()
id_ = djstripe.models.StripeModel._id_from_data(
charge["balance_transaction"]
)
try:
obj = djstripe.models.BalanceTransaction(id=id_).api_retrieve()
created = False
self.stdout.write(f" found {id_}")
except InvalidRequestError:
assert False, "Expected to find balance transaction via source"
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_bank_account(self, old_obj, readonly_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_bank_account(self, old_obj, readonly_fields):
customer_id = old_obj["customer"]
try:
obj = stripe.Customer.retrieve_source(customer_id, old_obj["id"])
created = False
self.stdout.write(" found")
except InvalidRequestError:
self.stdout.write(" creating")
create_obj = deepcopy(old_obj)
# create in Stripe
for k in readonly_fields:
create_obj.pop(k, None)
# see https://stripe.com/docs/connect/testing#account-numbers
# we've stash the account number in the metadata
# so we can regenerate the fixture
create_obj["account_number"] = old_obj["metadata"][
"djstripe_test_fixture_account_number"
]
create_obj["object"] = "bank_account"
obj = stripe.Customer.create_source(customer_id, source=create_obj)
created = True
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_card(self, old_obj, readonly_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_card(self, old_obj, readonly_fields):
customer_id = old_obj["customer"]
try:
obj = stripe.Customer.retrieve_source(customer_id, old_obj["id"])
created = False
self.stdout.write(" found")
except InvalidRequestError:
self.stdout.write(" creating")
create_obj = deepcopy(old_obj)
# create in Stripe
for k in readonly_fields:
create_obj.pop(k, None)
obj = stripe.Customer.create_source(**{"source": "tok_visa"})
for k, v in create_obj.items():
setattr(obj, k, v)
obj.save()
created = True
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_charge(self, old_obj, writable_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_charge(self, old_obj, writable_fields):
invoice = djstripe.models.Invoice(id=old_obj["invoice"]).api_retrieve()
id_ = invoice["charge"]
try:
obj = djstripe.models.Charge(id=id_).api_retrieve()
created = False
self.stdout.write(f" found {id_}")
except InvalidRequestError:
assert False, "Expected to find charge via invoice"
for k in writable_fields:
if isinstance(obj.get(k), dict):
# merge dicts (eg metadata)
obj[k].update(old_obj.get(k, {}))
else:
obj[k] = old_obj[k]
obj.save()
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_invoice(self, old_obj, writable_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_invoice(self, old_obj, writable_fields):
subscription = djstripe.models.Subscription(
id=old_obj["subscription"]
).api_retrieve()
id_ = subscription["latest_invoice"]
try:
obj = djstripe.models.Invoice(id=id_).api_retrieve()
created = False
self.stdout.write(f" found {id_}")
except InvalidRequestError:
assert False, "Expected to find invoice via subscription"
for k in writable_fields:
if isinstance(obj.get(k), dict):
# merge dicts (eg metadata)
obj[k].update(old_obj.get(k, {}))
else:
obj[k] = old_obj[k]
obj.save()
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_payment_intent(self, old_obj, writable_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_payment_intent(self, old_obj, writable_fields):
invoice = djstripe.models.Invoice(id=old_obj["invoice"]).api_retrieve()
id_ = invoice["payment_intent"]
try:
obj = djstripe.models.PaymentIntent(id=id_).api_retrieve()
created = False
self.stdout.write(f" found {id_}")
except InvalidRequestError:
assert False, "Expected to find payment_intent via invoice"
for k in writable_fields:
if isinstance(obj.get(k), dict):
# merge dicts (eg metadata)
obj[k].update(old_obj.get(k, {}))
else:
obj[k] = old_obj[k]
obj.save()
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_payment_method(self, old_obj, writable_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_payment_method(self, old_obj, writable_fields):
id_ = old_obj["id"]
customer_id = old_obj["customer"]
type_ = old_obj["type"]
try:
obj = djstripe.models.PaymentMethod(id=id_).api_retrieve()
created = False
self.stdout.write(" found")
except InvalidRequestError:
self.stdout.write(" creating")
obj = djstripe.models.PaymentMethod()._api_create(
type=type_, card={"token": "tok_visa"}
)
stripe.PaymentMethod.attach(
obj["id"],
customer=customer_id,
api_key=djstripe_settings.djstripe_settings.STRIPE_SECRET_KEY,
)
for k in writable_fields:
if isinstance(obj.get(k), dict):
# merge dicts (eg metadata)
obj[k].update(old_obj.get(k, {}))
else:
obj[k] = old_obj[k]
obj.save()
created = True
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.get_or_create_stripe_source(self, old_obj, readonly_fields)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def get_or_create_stripe_source(self, old_obj, readonly_fields):
customer_id = old_obj["customer"]
try:
obj = stripe.Customer.retrieve_source(customer_id, old_obj["id"])
created = False
self.stdout.write(" found")
except InvalidRequestError:
self.stdout.write(" creating")
create_obj = deepcopy(old_obj)
# create in Stripe
for k in readonly_fields:
create_obj.pop(k, None)
source_obj = djstripe.models.Source._api_create(
**{"token": "tok_visa", "type": "card"}
)
obj = stripe.Customer.create_source(**{"source": source_obj.id})
for k, v in create_obj.items():
setattr(obj, k, v)
obj.save()
created = True
return created, obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.handle(self, *args, **options)
The actual logic of the command. Subclasses must implement this method.
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def handle(self, *args, **options):
do_delete_stale_fixtures = options["delete_stale"]
do_preserve_sideeffect_fields = not options["update_sideeffect_fields"]
common_readonly_fields = ["object", "created", "updated", "livemode"]
common_sideeffect_fields = ["created"]
# TODO - is it be possible to get a list of which fields are writable from
# the API? maybe using https://github.com/stripe/openapi ?
# (though that's only for current version)
"""
Fields that we treat as read-only.
Most of these will cause an error if sent to the Stripe API.
"""
model_extra_readonly_fields = {
djstripe.models.Account: ["id"],
djstripe.models.Customer: [
"account_balance",
"currency",
"default_source",
"delinquent",
"invoice_prefix",
"subscriptions",
"sources",
],
djstripe.models.BankAccount: [
"id",
"bank_name",
"customer",
"last4",
"fingerprint",
"status",
],
djstripe.models.Card: [
"id",
"address_line1_check",
"address_zip_check",
"brand",
"country",
"customer",
"cvc_check",
"dynamic_last4",
"exp_month",
"exp_year",
"fingerprint",
"funding",
"last4",
"tokenization_method",
],
djstripe.models.PaymentIntent: ["id"],
djstripe.models.PaymentMethod: ["id"],
djstripe.models.Plan: [
# Can only specify one of amount and amount_decimal
"amount_decimal"
],
djstripe.models.Source: [
"id",
"amount",
"card",
"client_secret",
"currency",
"customer",
"flow",
"owner",
"statement_descriptor",
"status",
"type",
"usage",
],
djstripe.models.Subscription: [
"id",
# not actually read-only
"billing_cycle_anchor",
"billing",
"current_period_end",
"current_period_start",
# workaround for "the
# `invoice_customer_balance_settings[consume_applied_balance_on_void]`
# parameter is only supported in API version 2019-11-05 and below.
# See
# https://stripe.com/docs/api#versioning and
# https://stripe.com/docs/upgrades#2019-12-03 for more detail.
"invoice_customer_balance_settings",
"latest_invoice",
"start",
"start_date",
"status",
],
djstripe.models.TaxRate: ["id"],
} # type: Dict[Type[djstripe.models.StripeModel], List[str]]
"""
Fields that we don't care about the value of, and that preserving
allows us to avoid churn in the fixtures
"""
model_sideeffect_fields = {
djstripe.models.BalanceTransaction: ["available_on"],
djstripe.models.Source: ["client_secret"],
djstripe.models.Charge: ["receipt_url"],
djstripe.models.Subscription: [
"billing_cycle_anchor",
"current_period_start",
"current_period_end",
"start",
"start_date",
],
djstripe.models.SubscriptionItem: [
# we don't currently track separate fixtures for SubscriptionItems
"id"
],
djstripe.models.Product: ["updated"],
djstripe.models.Invoice: [
"date",
"finalized_at",
"hosted_invoice_url",
"invoice_pdf",
"webhooks_delivered_at",
"period_start",
"period_end",
# we don't currently track separate fixtures for SubscriptionItems
"subscription_item",
],
} # type: Dict[Type[djstripe.models.StripeModel], List[str]]
object_sideeffect_fields = {
model.stripe_class.OBJECT_NAME: set(v)
for model, v in model_sideeffect_fields.items()
} # type: Dict[str, Set[str]]
self.fake_data_map = {
# djstripe.models.Account: [tests.FAKE_ACCOUNT],
djstripe.models.Customer: [
tests.FAKE_CUSTOMER,
tests.FAKE_CUSTOMER_II,
tests.FAKE_CUSTOMER_III,
tests.FAKE_CUSTOMER_IV,
],
djstripe.models.BankAccount: [tests.FAKE_BANK_ACCOUNT_SOURCE],
djstripe.models.Card: [
tests.FAKE_CARD,
tests.FAKE_CARD_II,
tests.FAKE_CARD_III,
],
djstripe.models.Source: [tests.FAKE_SOURCE],
djstripe.models.Plan: [tests.FAKE_PLAN, tests.FAKE_PLAN_II],
djstripe.models.Price: [tests.FAKE_PRICE, tests.FAKE_PRICE_II],
djstripe.models.Product: [tests.FAKE_PRODUCT],
djstripe.models.TaxRate: [
tests.FAKE_TAX_RATE_EXAMPLE_1_VAT,
tests.FAKE_TAX_RATE_EXAMPLE_2_SALES,
],
djstripe.models.Subscription: [
tests.FAKE_SUBSCRIPTION,
tests.FAKE_SUBSCRIPTION_II,
tests.FAKE_SUBSCRIPTION_III,
tests.FAKE_SUBSCRIPTION_MULTI_PLAN,
],
djstripe.models.SubscriptionSchedule: [
tests.FAKE_SUBSCRIPTION_SCHEDULE,
],
djstripe.models.Invoice: [tests.FAKE_INVOICE, tests.FAKE_INVOICE_IV],
djstripe.models.Charge: [tests.FAKE_CHARGE],
djstripe.models.PaymentIntent: [tests.FAKE_PAYMENT_INTENT_I],
djstripe.models.PaymentMethod: [
tests.FAKE_PAYMENT_METHOD_I,
tests.FAKE_CARD_AS_PAYMENT_METHOD,
],
djstripe.models.BalanceTransaction: [tests.FAKE_BALANCE_TRANSACTION],
}
self.init_fake_id_map()
objs = []
# Regenerate each of the fixture objects via Stripe
# We re-fetch objects in a second pass if they were created during
# the first pass, to ensure nested objects are up to date
# (eg Customer.subscriptions),
for n in range(2):
any_created = False
self.stdout.write(f"Updating fixture objects, pass {n}")
# reset the objects list since we don't want to keep those from
# the first pass
objs.clear()
for model_class, old_objs in self.fake_data_map.items():
readonly_fields = (
common_readonly_fields
+ model_extra_readonly_fields.get(model_class, [])
)
for old_obj in old_objs:
created, obj = self.update_fixture_obj(
old_obj=deepcopy(old_obj),
model_class=model_class,
readonly_fields=readonly_fields,
do_preserve_sideeffect_fields=do_preserve_sideeffect_fields,
object_sideeffect_fields=object_sideeffect_fields,
common_sideeffect_fields=common_sideeffect_fields,
)
objs.append(obj)
any_created = created or any_created
if not any_created:
# nothing created on this pass, no need to continue
break
else:
self.stderr.write(
"Warning, unexpected behaviour - some fixtures still being created "
"in second pass?"
)
# Now the fake_id_map should be complete and the objs should be up to date,
# save all the fixtures
paths = set()
for obj in objs:
path = self.save_fixture(obj)
paths.add(path)
if do_delete_stale_fixtures:
for path in tests.FIXTURE_DIR_PATH.glob("*.json"):
if path in paths:
continue
else:
self.stdout.write("deleting {}".format(path))
path.unlink()
tests.apps.example.management.commands.regenerate_test_fixtures.Command.init_fake_id_map(self)
Build a mapping between fake ids stored in Stripe metadata and those obj's actual ids
We do this so we can have fixtures with stable ids for objects Stripe doesn't allow us to specify an id for (eg Card).
Fixtures and tests will use the fake ids, when we talk to stripe we use the real ids :return:
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def init_fake_id_map(self):
"""
Build a mapping between fake ids stored in Stripe metadata and those obj's
actual ids
We do this so we can have fixtures with stable ids for objects Stripe doesn't
allow us to specify an id for (eg Card).
Fixtures and tests will use the fake ids, when we talk to stripe we use the
real ids
:return:
"""
for fake_customer in self.fake_data_map[djstripe.models.Customer]:
try:
# can only access Cards via the customer
customer = djstripe.models.Customer(
id=fake_customer["id"]
).api_retrieve()
except InvalidRequestError:
self.stdout.write(
f"Fake customer {fake_customer['id']} doesn't exist in Stripe yet"
)
return
# assume that test customers don't have more than 100 cards...
for card in customer.sources.list(limit=100):
self.update_fake_id_map(card)
for payment_method in djstripe.models.PaymentMethod.api_list(
customer=customer.id, type="card"
):
self.update_fake_id_map(payment_method)
for subscription in customer["subscriptions"]["data"]:
self.update_fake_id_map(subscription)
for tax_rate in djstripe.models.TaxRate.api_list():
self.update_fake_id_map(tax_rate)
tests.apps.example.management.commands.regenerate_test_fixtures.Command.pre_process_subscription(self, create_obj)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def pre_process_subscription(self, create_obj):
# flatten plan/items/tax rates on create
items = create_obj.get("items", {}).get("data", [])
if len(items):
# don't try and create with both plan and item (list of plans)
create_obj.pop("plan", None)
create_obj.pop("quantity", None)
# TODO - move this to SubscriptionItem handling?
subscription_item_create_fields = {
"plan",
"billing_thresholds",
"metadata",
"quantity",
"tax_rates",
}
create_items = []
for item in items:
create_item = {
k: v
for k, v in item.items()
if k in subscription_item_create_fields
}
create_item["plan"] = djstripe.models.StripeModel._id_from_data(
create_item["plan"]
)
if create_item.get("tax_rates", []):
create_item["tax_rates"] = [
djstripe.models.StripeModel._id_from_data(t)
for t in create_item["tax_rates"]
]
create_items.append(create_item)
create_obj["items"] = create_items
else:
# don't try and send empty items list
create_obj.pop("items", None)
create_obj["plan"] = djstripe.models.StripeModel._id_from_data(
create_obj["plan"]
)
if create_obj.get("default_tax_rates", []):
create_obj["default_tax_rates"] = [
djstripe.models.StripeModel._id_from_data(t)
for t in create_obj["default_tax_rates"]
]
# don't send both default_tax_rates and tax_percent
create_obj.pop("tax_percent", None)
return create_obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.preserve_old_sideeffect_values(self, old_obj, new_obj, object_sideeffect_fields, common_sideeffect_fields)
Try to preserve values of side-effect fields from old_obj, to reduce churn in fixtures
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def preserve_old_sideeffect_values(
self, old_obj, new_obj, object_sideeffect_fields, common_sideeffect_fields
):
"""
Try to preserve values of side-effect fields from old_obj,
to reduce churn in fixtures
"""
object_name = new_obj.get("object")
sideeffect_fields = object_sideeffect_fields.get(object_name, set()).union(
set(common_sideeffect_fields)
)
old_obj = old_obj or {}
for f, old_val in old_obj.items():
try:
new_val = new_obj[f]
except KeyError:
continue
if isinstance(new_val, stripe.api_resources.ListObject):
# recursively process nested lists
for n, (old_val_item, new_val_item) in enumerate(
zip(old_val.get("data", []), new_val.data)
):
new_val.data[n] = self.preserve_old_sideeffect_values(
old_obj=old_val_item,
new_obj=new_val_item,
object_sideeffect_fields=object_sideeffect_fields,
common_sideeffect_fields=common_sideeffect_fields,
)
elif isinstance(new_val, stripe.stripe_object.StripeObject):
# recursively process nested objects
new_obj[f] = self.preserve_old_sideeffect_values(
old_obj=old_val,
new_obj=new_val,
object_sideeffect_fields=object_sideeffect_fields,
common_sideeffect_fields=common_sideeffect_fields,
)
elif (
f in sideeffect_fields
and type(old_val) == type(new_val)
and old_val != new_val
):
# only preserve old values if the type is the same
new_obj[f] = old_val
return new_obj
tests.apps.example.management.commands.regenerate_test_fixtures.Command.save_fixture(self, obj)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def save_fixture(self, obj):
type_name = obj["object"]
id_ = self.update_fake_id_map(obj)
fixture_path = tests.FIXTURE_DIR_PATH.joinpath(f"{type_name}_{id_}.json")
with fixture_path.open("w") as f:
json_str = self.fake_json_ids(json.dumps(obj, indent=4))
f.write(json_str)
return fixture_path
tests.apps.example.management.commands.regenerate_test_fixtures.Command.unfake_json_ids(self, json_str)
Replace fake ids with actual ones in the JSON fixture
Do this on the serialized JSON string since it's a simple string replace :param json_str: :return:
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def unfake_json_ids(self, json_str):
"""
Replace fake ids with actual ones in the JSON fixture
Do this on the serialized JSON string since it's a simple string replace
:param json_str:
:return:
"""
for fake_id, actual_id in self.fake_id_map.items():
json_str = json_str.replace(fake_id, actual_id)
# special-case: undo the replace for the djstripe_test_fake_id in metadata
json_str = json_str.replace(
f'"{FAKE_ID_METADATA_KEY}": "{actual_id}"',
f'"{FAKE_ID_METADATA_KEY}": "{fake_id}"',
)
return json_str
tests.apps.example.management.commands.regenerate_test_fixtures.Command.update_fake_id_map(self, obj)
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def update_fake_id_map(self, obj):
fake_id = self.get_fake_id(obj)
actual_id = obj["id"]
if fake_id:
if fake_id in self.fake_id_map:
assert self.fake_id_map[fake_id] == actual_id, (
f"Duplicate fake_id {fake_id} - reset your test Stripe data at "
f"https://dashboard.stripe.com/account/data"
)
self.fake_id_map[fake_id] = actual_id
return fake_id
else:
return actual_id
tests.apps.example.management.commands.regenerate_test_fixtures.Command.update_fixture_obj(self, old_obj, model_class, readonly_fields, do_preserve_sideeffect_fields, object_sideeffect_fields, common_sideeffect_fields)
Given a fixture object, update it via stripe :param model_class: :param old_obj: :param readonly_fields: :return:
Source code in tests/apps/example/management/commands/regenerate_test_fixtures.py
def update_fixture_obj( # noqa: C901
self,
old_obj,
model_class,
readonly_fields,
do_preserve_sideeffect_fields,
object_sideeffect_fields,
common_sideeffect_fields,
):
"""
Given a fixture object, update it via stripe
:param model_class:
:param old_obj:
:param readonly_fields:
:return:
"""
# restore real ids from Stripe
old_obj = json.loads(self.unfake_json_ids(json.dumps(old_obj)))
id_ = old_obj["id"]
self.stdout.write(f"{model_class.__name__} {id_}", ending="")
# For objects that we can't directly choose the ids of
# (and that will thus vary between stripe accounts)
# we fetch the id from a related object
if issubclass(model_class, djstripe.models.Account):
created, obj = self.get_or_create_stripe_account(
old_obj=old_obj, readonly_fields=readonly_fields
)
elif issubclass(model_class, djstripe.models.BankAccount):
created, obj = self.get_or_create_stripe_bank_account(
old_obj=old_obj, readonly_fields=readonly_fields
)
elif issubclass(model_class, djstripe.models.Card):
created, obj = self.get_or_create_stripe_card(
old_obj=old_obj, readonly_fields=readonly_fields
)
elif issubclass(model_class, djstripe.models.Source):
created, obj = self.get_or_create_stripe_source(
old_obj=old_obj, readonly_fields=readonly_fields
)
elif issubclass(model_class, djstripe.models.Invoice):
created, obj = self.get_or_create_stripe_invoice(
old_obj=old_obj, writable_fields=["metadata"]
)
elif issubclass(model_class, djstripe.models.Charge):
created, obj = self.get_or_create_stripe_charge(
old_obj=old_obj, writable_fields=["metadata"]
)
elif issubclass(model_class, djstripe.models.PaymentIntent):
created, obj = self.get_or_create_stripe_payment_intent(
old_obj=old_obj, writable_fields=["metadata"]
)
elif issubclass(model_class, djstripe.models.PaymentMethod):
created, obj = self.get_or_create_stripe_payment_method(
old_obj=old_obj, writable_fields=["metadata"]
)
elif issubclass(model_class, djstripe.models.BalanceTransaction):
created, obj = self.get_or_create_stripe_balance_transaction(
old_obj=old_obj
)
else:
try:
# fetch from Stripe, using the active API version
# this allows us regenerate the fixtures from Stripe
# and hopefully, automatically get schema changes
obj = model_class(id=id_).api_retrieve()
created = False
self.stdout.write(" found")
except InvalidRequestError:
self.stdout.write(" creating")
create_obj = deepcopy(old_obj)
# create in Stripe
for k in readonly_fields:
create_obj.pop(k, None)
if issubclass(model_class, djstripe.models.Subscription):
create_obj = self.pre_process_subscription(create_obj=create_obj)
obj = model_class._api_create(**create_obj)
created = True
self.update_fake_id_map(obj)
if do_preserve_sideeffect_fields:
obj = self.preserve_old_sideeffect_values(
old_obj=old_obj,
new_obj=obj,
object_sideeffect_fields=object_sideeffect_fields,
common_sideeffect_fields=common_sideeffect_fields,
)
return created, obj
tests.apps.example.urls
tests.apps.example.urls.app_name
tests.apps.example.urls.urlpatterns
tests.apps.example.views
tests.apps.example.views.User
tests.apps.example.views.logger
tests.apps.example.views.CheckoutSessionSuccessView
Template View for showing Checkout Payment Success
tests.apps.example.views.CheckoutSessionSuccessView.template_name
tests.apps.example.views.CreateCheckoutSessionView
Example View to demonstrate how to use dj-stripe to:
- Create a Stripe Checkout Session (for a new and a returning customer)
- Add SUBSCRIBER_CUSTOMER_KEY to metadata to populate customer.subscriber model field
- Fill out Payment Form and Complete Payment
Redirects the User to Stripe Checkout Session. This does a logged in purchase for a new and a returning customer using Stripe Checkout
tests.apps.example.views.CreateCheckoutSessionView.template_name
tests.apps.example.views.CreateCheckoutSessionView.get_context_data(self, **kwargs)
Creates and returns a Stripe Checkout Session
Source code in tests/apps/example/views.py
def get_context_data(self, **kwargs):
"""
Creates and returns a Stripe Checkout Session
"""
# Get Parent Context
context = super().get_context_data(**kwargs)
# to initialise Stripe.js on the front end
context[
"STRIPE_PUBLIC_KEY"
] = djstripe_settings.djstripe_settings.STRIPE_PUBLIC_KEY
success_url = self.request.build_absolute_uri(
reverse("djstripe_example:success")
)
cancel_url = self.request.build_absolute_uri(reverse("home"))
# get the id of the Model instance of djstripe_settings.djstripe_settings.get_subscriber_model()
# here we have assumed it is the Django User model. It could be a Team, Company model too.
# note that it needs to have an email field.
id = self.request.user.id
# example of how to insert the SUBSCRIBER_CUSTOMER_KEY: id in the metadata
# to add customer.subscriber to the newly created/updated customer.
metadata = {
f"{djstripe_settings.djstripe_settings.SUBSCRIBER_CUSTOMER_KEY}": id
}
try:
# retreive the Stripe Customer.
customer = models.Customer.objects.get(subscriber=self.request.user)
print("Customer Object in DB.")
# ! Note that Stripe will always create a new Customer Object if customer id not provided
# ! even if customer_email is provided!
session = stripe.checkout.Session.create(
payment_method_types=["card"],
customer=customer.id,
# payment_method_types=["bacs_debit"], # for bacs_debit
payment_intent_data={
"setup_future_usage": "off_session",
# so that the metadata gets copied to the associated Payment Intent and Charge Objects
"metadata": metadata,
},
line_items=[
{
"price_data": {
"currency": "usd",
# "currency": "gbp", # for bacs_debit
"unit_amount": 2000,
"product_data": {
"name": "Sample Product Name",
"images": ["https://i.imgur.com/EHyR2nP.png"],
"description": "Sample Description",
},
},
"quantity": 1,
},
],
mode="payment",
success_url=success_url,
cancel_url=cancel_url,
metadata=metadata,
)
except models.Customer.DoesNotExist:
print("Customer Object not in DB.")
session = stripe.checkout.Session.create(
payment_method_types=["card"],
# payment_method_types=["bacs_debit"], # for bacs_debit
payment_intent_data={
"setup_future_usage": "off_session",
# so that the metadata gets copied to the associated Payment Intent and Charge Objects
"metadata": metadata,
},
line_items=[
{
"price_data": {
"currency": "usd",
# "currency": "gbp", # for bacs_debit
"unit_amount": 2000,
"product_data": {
"name": "Sample Product Name",
"images": ["https://i.imgur.com/EHyR2nP.png"],
"description": "Sample Description",
},
},
"quantity": 1,
},
],
mode="payment",
success_url=success_url,
cancel_url=cancel_url,
metadata=metadata,
)
context["CHECKOUT_SESSION_ID"] = session.id
return context
tests.apps.example.views.PurchaseSubscriptionSuccessView
tests.apps.example.views.PurchaseSubscriptionSuccessView.context_object_name
tests.apps.example.views.PurchaseSubscriptionSuccessView.queryset
tests.apps.example.views.PurchaseSubscriptionSuccessView.slug_field
tests.apps.example.views.PurchaseSubscriptionSuccessView.slug_url_kwarg
tests.apps.example.views.PurchaseSubscriptionSuccessView.template_name
tests.apps.example.views.PurchaseSubscriptionView
Example view to demonstrate how to use dj-stripe to:
- create a Customer
- add a card to the Customer
- create a Subscription using that card
This does a non-logged in purchase for the user of the provided email
tests.apps.example.views.PurchaseSubscriptionView.template_name
tests.apps.example.views.PurchaseSubscriptionView.form_class
tests.apps.example.views.PurchaseSubscriptionView.form_class.media
property
readonly
tests.apps.example.views.PurchaseSubscriptionView.form_valid(self, form)
If the form is valid, redirect to the supplied URL.
Source code in tests/apps/example/views.py
def form_valid(self, form):
stripe_source = form.cleaned_data["stripe_source"]
email = form.cleaned_data["email"]
plan = form.cleaned_data["plan"]
# Guest checkout with the provided email
try:
user = User.objects.get(email=email)
except User.DoesNotExist:
user = User.objects.create(username=email, email=email)
# Create the stripe Customer, by default subscriber Model is User,
# this can be overridden with djstripe_settings.djstripe_settings.DJSTRIPE_SUBSCRIBER_MODEL
customer, created = models.Customer.get_or_create(subscriber=user)
# Add the source as the customer's default card
customer.add_card(stripe_source)
# Using the Stripe API, create a subscription for this customer,
# using the customer's default payment source
stripe_subscription = stripe.Subscription.create(
customer=customer.id,
items=[{"plan": plan.id}],
collection_method="charge_automatically",
# tax_percent=15,
api_key=djstripe_settings.djstripe_settings.STRIPE_SECRET_KEY,
)
# Sync the Stripe API return data to the database,
# this way we don't need to wait for a webhook-triggered sync
subscription = models.Subscription.sync_from_stripe_data(stripe_subscription)
self.request.subscription = subscription
return super().form_valid(form)
tests.apps.example.views.PurchaseSubscriptionView.get_context_data(self, **kwargs)
Insert the form into the context dict.
Source code in tests/apps/example/views.py
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if models.Plan.objects.count() == 0:
raise Exception(
"No Product Plans in the dj-stripe database - create some in your "
"stripe account and then "
"run `./manage.py djstripe_sync_plans_from_stripe` "
"(or use the dj-stripe webhooks)"
)
context[
"STRIPE_PUBLIC_KEY"
] = djstripe_settings.djstripe_settings.STRIPE_PUBLIC_KEY
return context
tests.apps.example.views.PurchaseSubscriptionView.get_success_url(self)
Return the URL to redirect to after processing a valid form.
Source code in tests/apps/example/views.py
def get_success_url(self):
return reverse(
"djstripe_example:purchase_subscription_success",
kwargs={"id": self.request.subscription.id},
)
tests.apps.example.views.create_payment_intent(request)
Source code in tests/apps/example/views.py
def create_payment_intent(request):
if request.method == "POST":
intent = None
data = json.loads(request.body)
try:
if "payment_method_id" in data:
# Create the PaymentIntent
intent = stripe.PaymentIntent.create(
payment_method=data["payment_method_id"],
amount=1099,
currency="usd",
confirmation_method="manual",
confirm=True,
api_key=djstripe_settings.djstripe_settings.STRIPE_SECRET_KEY,
)
elif "payment_intent_id" in data:
intent = stripe.PaymentIntent.confirm(
data["payment_intent_id"],
api_key=djstripe_settings.djstripe_settings.STRIPE_SECRET_KEY,
)
except stripe.error.CardError as e:
# Display error on client
return_data = json.dumps({"error": e.user_message}), 200
return HttpResponse(
return_data[0], content_type="application/json", status=return_data[1]
)
if (
intent.status == "requires_action"
and intent.next_action.type == "use_stripe_sdk"
):
# Tell the client to handle the action
return_data = (
json.dumps(
{
"requires_action": True,
"payment_intent_client_secret": intent.client_secret,
}
),
200,
)
elif intent.status == "succeeded":
# The payment did not need any additional actions and completed!
# Handle post-payment fulfillment
return_data = json.dumps({"success": True}), 200
else:
# Invalid status
return_data = json.dumps({"error": "Invalid PaymentIntent status"}), 500
return HttpResponse(
return_data[0], content_type="application/json", status=return_data[1]
)
else:
context = {
"STRIPE_PUBLIC_KEY": djstripe_settings.djstripe_settings.STRIPE_PUBLIC_KEY
}
return TemplateResponse(request, "payment_intent.html", context)
tests.apps.testapp
special
Modules
tests.apps.testapp.models
tests.apps.testapp.models.NoEmailOrganization
Model used to test the new custom model setting.
tests.apps.testapp.models.NoEmailOrganization.name
tests.apps.testapp.models.NoEmailOrganization.DoesNotExist
tests.apps.testapp.models.NoEmailOrganization.MultipleObjectsReturned
tests.apps.testapp.models.Organization
Model used to test the new custom model setting.
tests.apps.testapp.models.Organization.email
tests.apps.testapp.models.Organization.DoesNotExist
tests.apps.testapp.models.Organization.MultipleObjectsReturned
tests.apps.testapp.models.StaticEmailOrganization
Model used to test the new custom model setting.
tests.apps.testapp.models.StaticEmailOrganization.email
property
readonly
tests.apps.testapp.models.StaticEmailOrganization.name
tests.apps.testapp.models.StaticEmailOrganization.DoesNotExist
tests.apps.testapp.models.StaticEmailOrganization.MultipleObjectsReturned
tests.apps.testapp.urls
tests.apps.testapp.urls.urlpatterns
tests.apps.testapp.urls.empty_view(request)
Source code in tests/apps/testapp/urls.py
def empty_view(request):
return HttpResponse()
tests.apps.testapp_content
special
Modules
tests.apps.testapp_content.models
tests.apps.testapp_content.urls
Represents protected content
tests.apps.testapp_content.urls.urlpatterns
tests.apps.testapp_content.urls.testview(request)
Source code in tests/apps/testapp_content/urls.py
def testview(request):
return HttpResponse()
tests.apps.testapp_namespaced
special
tests.apps.testapp_namespaced.models
tests.apps.testapp_namespaced.urls
tests.apps.testapp_namespaced.urls.app_name
tests.apps.testapp_namespaced.urls.urlpatterns
tests.apps.testapp_namespaced.urls.testview(request)
Source code in tests/apps/testapp_namespaced/urls.py
def testview(request):
return HttpResponse()
tests.conftest
Module for creating re-usable fixtures to be used across the test suite
tests.conftest.pytestmark
Functions
tests.conftest.create_account_and_stripe_apikeys(settings)
Fixture to automatically create and assign the default testing keys to the Platform Account
Source code in tests/conftest.py
@pytest.fixture(autouse=True)
def create_account_and_stripe_apikeys(settings):
"""
Fixture to automatically create and assign the default testing keys to the Platform Account
"""
# create a Stripe Platform Account
djstripe_platform_account = FAKE_PLATFORM_ACCOUNT.create()
# create and assign APIKey instances to the djstripe Platform Account
APIKey.objects.get_or_create(
type=APIKeyType.secret,
name="Test Secret Key",
secret=settings.STRIPE_TEST_SECRET_KEY,
livemode=False,
djstripe_owner_account=djstripe_platform_account,
)
tests.conftest.fake_customer(fake_user)
Source code in tests/conftest.py
@pytest.fixture
def fake_customer(fake_user):
customer = FAKE_CUSTOMER.create_for_user(fake_user)
return customer
tests.conftest.fake_user()
Source code in tests/conftest.py
@pytest.fixture
def fake_user():
user = get_user_model().objects.create_user(
username="arnav", email="arnav13@gmail.com"
)
return user
tests.settings
tests.settings.ALLOWED_HOSTS
tests.settings.BASE_DIR
tests.settings.DEBUG
tests.settings.DEFAULT_AUTO_FIELD
tests.settings.DJSTRIPE_FOREIGN_KEY_TO_FIELD
tests.settings.DJSTRIPE_SUBSCRIPTION_REDIRECT
tests.settings.DJSTRIPE_SUBSCRIPTION_REQUIRED_EXCEPTION_URLS
tests.settings.DJSTRIPE_USE_NATIVE_JSONFIELD
tests.settings.DJSTRIPE_WEBHOOK_SECRET
tests.settings.DJSTRIPE_WEBHOOK_VALIDATION
tests.settings.INSTALLED_APPS
tests.settings.MIDDLEWARE
tests.settings.PROJECT_DIR
tests.settings.ROOT_URLCONF
tests.settings.SECRET_KEY
tests.settings.SITE_ID
tests.settings.STATIC_URL
tests.settings.STRIPE_LIVE_PUBLIC_KEY
tests.settings.STRIPE_LIVE_SECRET_KEY
tests.settings.STRIPE_TEST_PUBLIC_KEY
tests.settings.STRIPE_TEST_SECRET_KEY
tests.settings.TEMPLATES
tests.settings.TIME_ZONE
tests.settings.USE_TZ
tests.settings.test_db_name
tests.settings.test_db_pass
tests.settings.test_db_port
tests.settings.test_db_user
tests.settings.test_db_vendor
tests.test_account
dj-stripe Account Tests.
tests.test_account.pytestmark
Classes
tests.test_account.TestAccount
tests.test_account.TestAccount.test__attach_objects_post_save_hook(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch("stripe.Account.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_LOGO),
autospec=True,
)
def test__attach_objects_post_save_hook(
self, fileupload_retrieve_mock, account_retrieve_mock
):
fake_account = deepcopy(FAKE_ACCOUNT)
fake_account["settings"]["branding"]["icon"] = None
account_retrieve_mock.return_value = fake_account
Account.sync_from_stripe_data(fake_account)
fileupload_retrieve_mock.assert_called_with(
id=fake_account["settings"]["branding"]["logo"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
stripe_account=fake_account["id"],
)
tests.test_account.TestAccount.test__find_owner_account(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch(
"stripe.Account.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_ACCOUNT),
)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test__find_owner_account(self, fileupload_retrieve_mock, account_retrieve_mock):
fake_account = deepcopy(FAKE_ACCOUNT)
account = Account.sync_from_stripe_data(fake_account)
self.assertEqual(None, Account._find_owner_account(account))
tests.test_account.TestAccount.test_branding_icon(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch(
"stripe.Account.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_ACCOUNT),
)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test_branding_icon(self, fileupload_retrieve_mock, account_retrieve_mock):
fake_account = deepcopy(FAKE_ACCOUNT)
account = Account.sync_from_stripe_data(fake_account)
self.assertEqual(
fake_account["settings"]["branding"]["icon"], account.branding_icon.id
)
tests.test_account.TestAccount.test_branding_logo(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch(
"stripe.Account.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_ACCOUNT),
)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test_branding_logo(self, fileupload_retrieve_mock, account_retrieve_mock):
fake_account = deepcopy(FAKE_ACCOUNT)
account = Account.sync_from_stripe_data(fake_account)
self.assertEqual(
fake_account["settings"]["branding"]["logo"], account.branding_logo.id
)
tests.test_account.TestAccount.test_business_url(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch(
"stripe.Account.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_ACCOUNT),
)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test_business_url(self, fileupload_retrieve_mock, account_retrieve_mock):
fake_account = deepcopy(FAKE_ACCOUNT)
account = Account.sync_from_stripe_data(fake_account)
self.assertEqual(fake_account["business_profile"]["url"], account.business_url)
tests.test_account.TestAccount.test_get_default_account(self, file_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch("stripe.Account.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test_get_default_account(self, file_retrieve_mock, account_retrieve_mock):
account_retrieve_mock.return_value = deepcopy(FAKE_ACCOUNT)
account = Account.get_default_account()
account_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY
)
self.assertGreater(len(account.business_profile), 0)
self.assertGreater(len(account.settings), 0)
self.assertEqual(account.branding_icon.id, FAKE_FILEUPLOAD_ICON["id"])
self.assertEqual(account.branding_logo.id, FAKE_FILEUPLOAD_LOGO["id"])
self.assertEqual(account.settings["branding"]["icon"], account.branding_icon.id)
self.assertEqual(account.settings["branding"]["logo"], account.branding_logo.id)
self.assertNotEqual(account.branding_logo.id, account.branding_icon.id)
self.assert_fks(account, expected_blank_fks={})
self.assertEqual(account.business_url, "https://djstripe.com")
account.business_profile = None
self.assertEqual(account.business_url, "")
tests.test_account.TestAccount.test_get_default_account_null_logo(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch("stripe.Account.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_LOGO),
autospec=True,
)
def test_get_default_account_null_logo(
self, fileupload_retrieve_mock, account_retrieve_mock
):
fake_account = deepcopy(FAKE_ACCOUNT)
fake_account["settings"]["branding"]["icon"] = None
fake_account["settings"]["branding"]["logo"] = None
account_retrieve_mock.return_value = fake_account
account = Account.get_default_account()
account_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY
)
self.assert_fks(
account,
expected_blank_fks={
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
},
)
tests.test_account.TestAccount.test_sync_from_stripe_data(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_account.py
@patch(
"stripe.Account.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_ACCOUNT),
)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test_sync_from_stripe_data(
self, fileupload_retrieve_mock, account_retrieve_mock
):
fake_account = deepcopy(FAKE_ACCOUNT)
account = Account.sync_from_stripe_data(fake_account)
self.assertGreater(len(account.business_profile), 0)
self.assertGreater(len(account.settings), 0)
self.assertEqual(account.branding_icon.id, FAKE_FILEUPLOAD_ICON["id"])
self.assertEqual(account.branding_logo.id, FAKE_FILEUPLOAD_LOGO["id"])
self.assertEqual(account.settings["branding"]["icon"], account.branding_icon.id)
self.assertEqual(account.settings["branding"]["logo"], account.branding_logo.id)
self.assertNotEqual(account.branding_logo.id, account.branding_icon.id)
self.assert_fks(account, expected_blank_fks={})
self.assertEqual(account.business_url, "https://djstripe.com")
tests.test_account.TestAccountRestrictedKeys
Methods
tests.test_account.TestAccountRestrictedKeys.test_account_str_restricted_key(self, account_retrieve_mock)
Test that we do not attempt to retrieve account ID with restricted keys.
Source code in tests/test_account.py
@override_settings(
STRIPE_TEST_SECRET_KEY="rk_test_blah",
STRIPE_TEST_PUBLIC_KEY="pk_test_foo",
STRIPE_LIVE_MODE=False,
)
@patch("stripe.Account.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
def test_account_str_restricted_key(self, account_retrieve_mock):
"""
Test that we do not attempt to retrieve account ID with restricted keys.
"""
assert djstripe_settings.STRIPE_SECRET_KEY == "rk_test_blah"
account = Account.get_default_account()
assert account is None
account_retrieve_mock.assert_not_called()
tests.test_account.TestAccountStr
Methods
tests.test_account.TestAccountStr.test__str__null_settings_null_business_profile(self, fileupload_retrieve_mock, account_retrieve_mock)
Test that str doesn't crash when settings and business_profile are NULL.
Source code in tests/test_account.py
@patch("stripe.Account.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_LOGO),
autospec=True,
)
def test__str__null_settings_null_business_profile(
self,
fileupload_retrieve_mock,
account_retrieve_mock,
):
"""Test that __str__ doesn't crash when settings and business_profile are NULL."""
fake_account = deepcopy(FAKE_ACCOUNT)
fake_account["settings"] = None
fake_account["business_profile"] = None
account_retrieve_mock.return_value = fake_account
account = Account.sync_from_stripe_data(fake_account)
assert str(account) == "<id=acct_1032D82eZvKYlo2C>"
tests.test_account.TestAccountStr.test_account_str(self, fileupload_retrieve_mock, account_retrieve_mock, business_profile_update, settings_dashboard_update, expected_account_str)
Source code in tests/test_account.py
@pytest.mark.parametrize(
(
"business_profile_update",
"settings_dashboard_update",
"expected_account_str",
),
(
({}, {}, "dj-stripe"),
({}, {"display_name": "some display name"}, "some display name"),
(
{"name": "some business name"},
{"display_name": ""},
"some business name",
),
({"name": ""}, {"display_name": ""}, "<id=acct_1032D82eZvKYlo2C>"),
),
)
@patch("stripe.Account.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_LOGO),
autospec=True,
)
def test_account_str(
self,
fileupload_retrieve_mock,
account_retrieve_mock,
business_profile_update,
settings_dashboard_update,
expected_account_str,
):
fake_account = deepcopy(FAKE_ACCOUNT)
fake_account["business_profile"].update(business_profile_update)
fake_account["settings"]["dashboard"].update(settings_dashboard_update)
account_retrieve_mock.return_value = fake_account
account = Account.get_default_account()
assert str(account) == expected_account_str
Functions
tests.test_account.test_account__create_from_stripe_object(mock_super__create_from_stripe_object, mock_account_id, other_mock_account_id, expected_stripe_account)
Ensure that we are setting the ID value correctly.
Source code in tests/test_account.py
@pytest.mark.parametrize(
"mock_account_id, other_mock_account_id, expected_stripe_account",
(
("acct_fakefakefakefake001", None, "acct_fakefakefakefake001"),
(
"acct_fakefakefakefake001",
"acct_fakefakefakefake002",
"acct_fakefakefakefake002",
),
),
)
@patch(
target="djstripe.models.connect.StripeModel._create_from_stripe_object",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_account__create_from_stripe_object(
mock_super__create_from_stripe_object,
mock_account_id,
other_mock_account_id,
expected_stripe_account,
):
"""Ensure that we are setting the ID value correctly."""
mock_data = {"id": mock_account_id}
Account._create_from_stripe_object(
data=mock_data, stripe_account=other_mock_account_id
)
mock_super__create_from_stripe_object.assert_called_once_with(
data=mock_data,
current_ids=None,
pending_relations=None,
save=True,
stripe_account=expected_stripe_account,
)
tests.test_admin
dj-stripe Admin Tests.
tests.test_admin.pytestmark
Classes
tests.test_admin.TestAdminInlineModels
Methods
tests.test_admin.TestAdminInlineModels.test_readonly_fields_exist(self)
Ensure all fields in BaseModelAdmin.readonly_fields exist on the model
Source code in tests/test_admin.py
def test_readonly_fields_exist(self):
"""
Ensure all fields in BaseModelAdmin.readonly_fields exist on the model
"""
for model, model_admin in site._registry.items():
for inline_admin in model_admin.inlines:
fields = getattr(inline_admin, "readonly_fields", [])
try:
# need to force the returned queryset to get evaluated
list(inline_admin.model.objects.select_related(*fields))
except FieldError as error:
if "Non-relational field given in select_related" not in str(error):
self.fail(error)
tests.test_admin.TestAdminRegisteredModels
Methods
tests.test_admin.TestAdminRegisteredModels.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_admin.py
def setUp(self):
self.admin = get_user_model().objects.create_superuser(
username="admin", email="admin@djstripe.com", password="xxx"
)
self.factory = RequestFactory()
# the 2 models that do not inherit from StripeModel and hence
# do not inherit from StripeModelAdmin
self.ignore_models = ["WebhookEventTrigger", "IdempotencyKey"]
tests.test_admin.TestAdminRegisteredModels.test_get_fields_add(self)
Source code in tests/test_admin.py
def test_get_fields_add(self):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard add url
add_url = reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_add"
)
# add the admin user to the mocked request
request = self.factory.get(add_url)
request.user = self.admin
# skip model if model doesn't have "has_add_permission"
if not model_admin.has_add_permission(request):
continue
response = model_admin.add_view(request)
fields = model_admin.get_fields(request)
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.context_data["adminform"].model_admin.get_fields(request),
list(fields),
)
# ensure all the fields in fields are valid
for field in model_admin.get_fields(request):
model_admin.get_changelist_instance(request).get_ordering_field(
field
)
tests.test_admin.TestAdminRegisteredModels.test_get_fieldsets_add(self)
Source code in tests/test_admin.py
def test_get_fieldsets_add(self):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard add url
add_url = reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_add"
)
# add the admin user to the mocked request
request = self.factory.get(add_url)
request.user = self.admin
# skip model if model doesn't have "has_add_permission"
if not model_admin.has_add_permission(request):
continue
response = model_admin.add_view(request)
fieldsets = model_admin.get_fieldsets(request)
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.context_data["adminform"].fieldsets,
[*fieldsets],
)
# for models inheriting from StripeModelAdmin verify:
if model.__name__ not in self.ignore_models:
self.assertTrue(
all(
[
1
for i in [
"created",
"livemode",
"djstripe_owner_account",
"id",
]
if i in fieldsets
]
)
)
tests.test_admin.TestAdminRegisteredModels.test_get_list_display(self)
Source code in tests/test_admin.py
def test_get_list_display(self):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard changelist_view url
url = reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_changelist"
)
# add the admin user to the mocked request
request = self.factory.get(url)
request.user = self.admin
response = model_admin.changelist_view(request)
# get_changelist_instance to get an instance of the ChangelistView for logged in admin user
list_display = model_admin.get_changelist_instance(request).list_display
self.assertEqual(response.status_code, 200)
self.assertEqual(
list(response.context_data["cl"].list_display),
list(list_display),
)
# ensure all the fields in list_display are valid
for field in model_admin.get_list_display(request):
model_admin.get_changelist_instance(request).get_ordering_field(
field
)
# for models inheriting from StripeModelAdmin verify:
if model.__name__ not in self.ignore_models:
self.assertTrue(
all(
[
1
for i in [
"__str__",
"id",
"djstripe_owner_account",
"created",
"livemode",
]
if i in list_display
]
)
)
tests.test_admin.TestAdminRegisteredModels.test_get_list_display_links(self)
Source code in tests/test_admin.py
def test_get_list_display_links(self):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard changelist_view url
url = reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_changelist"
)
# add the admin user to the mocked request
request = self.factory.get(url)
request.user = self.admin
response = model_admin.changelist_view(request)
list_display = model_admin.get_changelist_instance(request).list_display
# get_changelist_instance to get an instance of the ChangelistView for logged in admin user
self.assertEqual(response.status_code, 200)
self.assertEqual(
list(response.context_data["cl"].list_display_links),
list(
model_admin.get_changelist_instance(request).list_display_links
),
)
# ensure all the fields in list_display_links are valid
for field in model_admin.get_list_display_links(request, list_display):
model_admin.get_changelist_instance(request).get_ordering_field(
field
)
tests.test_admin.TestAdminRegisteredModels.test_get_list_filter(self)
Source code in tests/test_admin.py
def test_get_list_filter(self):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard changelist_view url
url = reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_changelist"
)
# add the admin user to the mocked request
request = self.factory.get(url)
request.user = self.admin
response = model_admin.changelist_view(request)
# get_changelist_instance to get an instance of the ChangelistView for logged in admin user
list_filter = model_admin.get_changelist_instance(request).list_filter
self.assertEqual(response.status_code, 200)
self.assertEqual(
list(response.context_data["cl"].list_filter),
list(list_filter),
)
# ensure all the fields in list_filter are valid
for field in model_admin.get_list_filter(request):
model_admin.get_changelist_instance(request).get_ordering_field(
field
)
# for models inheriting from StripeModelAdmin verify:
if model.__name__ not in self.ignore_models:
self.assertTrue(
all([1 for i in ["created", "livemode"] if i in list_filter])
)
tests.test_admin.TestAdminRegisteredModels.test_get_list_select_related(self)
Source code in tests/test_admin.py
def test_get_list_select_related(self):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard changelist_view url
url = reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_changelist"
)
# add the admin user to the mocked request
request = self.factory.get(url)
request.user = self.admin
response = model_admin.changelist_view(request)
# get_changelist_instance to get an instance of the ChangelistView for logged in admin user
list_select_related = model_admin.get_changelist_instance(
request
).list_select_related
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.context_data["cl"].list_select_related,
list_select_related,
)
# ensure all the fields in list_select_related are valid
list_select_related_fields = model_admin.get_list_select_related(
request
)
if isinstance(list_select_related_fields, Sequence):
# need to force the returned queryset to get evaluated
list(model.objects.select_related(*list_select_related_fields))
tests.test_admin.TestAdminRegisteredModels.test_get_readonly_fields(self)
Source code in tests/test_admin.py
def test_get_readonly_fields(self):
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard changelist_view url
url = reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_changelist"
)
# add the admin user to the mocked request
request = self.factory.get(url)
request.user = self.admin
response = model_admin.changelist_view(request)
# get_changelist_instance to get an instance of the ChangelistView for logged in admin user
readonly_fields = model_admin.get_changelist_instance(
request
).model_admin.readonly_fields
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.context_data["cl"].model_admin.readonly_fields,
readonly_fields,
)
# ensure all the fields in readonly_fields are valid
for field in model_admin.get_readonly_fields(request):
model_admin.get_changelist_instance(request).get_ordering_field(
field
)
# for models inheriting from StripeModelAdmin verify:
if model.__name__ not in self.ignore_models:
self.assertTrue(
all(
[
1
for i in ["created", "djstripe_owner_account", "id"]
if i in readonly_fields
]
)
)
tests.test_admin.TestAdminRegisteredModels.test_get_search_fields(self)
Ensure all fields in model_admin.get_search_fields exist on the model or the related model
Source code in tests/test_admin.py
def test_get_search_fields(self):
"""
Ensure all fields in model_admin.get_search_fields exist on the model or the related model
"""
app_label = "djstripe"
app_config = apps.get_app_config(app_label)
all_models_lst = app_config.get_models()
for model in all_models_lst:
if model in site._registry.keys():
model_admin = site._registry.get(model)
# get the standard changelist_view url and make a sample query to trigger search
url = (
reverse(
f"admin:{model._meta.app_label}_{model.__name__.lower()}_changelist"
)
+ "?q=bar"
)
# add the admin user to the mocked request
request = self.factory.get(url)
request.user = self.admin
response = model_admin.changelist_view(request)
search_fields = model_admin.get_changelist_instance(
request
).search_fields
self.assertEqual(response.status_code, 200)
self.assertEqual(
response.context_data["cl"].search_fields,
search_fields,
)
try:
# ensure all the fields in search_fields are valid
# need to force the returned queryset to get evaluated
list(model.objects.select_related(*search_fields))
except FieldError as error:
if "Non-relational field given in select_related" not in str(error):
self.fail(error)
# for models inheriting from StripeModelAdmin verify:
if model.__name__ not in self.ignore_models:
self.assertTrue("id" in search_fields)
tests.test_admin.TestAdminSite
Methods
tests.test_admin.TestAdminSite.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_admin.py
def setUp(self):
self.empty_value = "-empty-"
tests.test_admin.TestAdminSite.test_custom_display_for_JSONfield(self)
Source code in tests/test_admin.py
def test_custom_display_for_JSONfield(self):
json_tests = [
({"a": {"b": None}}, '{"a": {"b": null}}'),
(["a", False], '["a", false]'),
("a", '"a"'),
({("a", "b"): "c"}, "{('a', 'b'): 'c'}"), # Invalid JSON.
]
for value, display_value in json_tests:
with self.subTest(value=value):
self.assertEqual(
djstripe_admin.custom_display_for_JSONfield(
value, JSONField(), self.empty_value
),
display_value,
)
tests.test_admin.TestAdminSite.test_list_select_related_fields_exist(self)
Ensure all fields in model_admin.list_select_related exist on the model or the related model
Source code in tests/test_admin.py
def test_list_select_related_fields_exist(self):
"""
Ensure all fields in model_admin.list_select_related exist on the model or the related model
"""
for model, model_admin in site._registry.items():
fields = getattr(model_admin, "list_select_related", False)
if isinstance(fields, Sequence):
try:
# need to force the returned queryset to get evaluated
list(model.objects.select_related(*fields))
except FieldError as error:
self.fail(error)
tests.test_admin.TestAdminSite.test_search_fields(self)
Search for errors like this:
Bad search field
Source code in tests/test_admin.py
def test_search_fields(self):
"""
Search for errors like this:
Bad search field <customer__user__username> for Customer model.
"""
for _model, model_admin in site._registry.items():
for search_field in getattr(model_admin, "search_fields", []):
model_name = model_admin.model.__name__
self.assertFalse(
search_field.startswith(
"{table_name}__".format(table_name=model_name.lower())
),
"Bad search field <{search_field}> for {model_name} model.".format(
search_field=search_field, model_name=model_name
),
)
tests.test_admin.TestAdminSite.test_search_fields_exist(self)
Ensure all fields in model_admin.search_fields exist on the model or the related model
Source code in tests/test_admin.py
def test_search_fields_exist(self):
"""
Ensure all fields in model_admin.search_fields exist on the model or the related model
"""
for model, model_admin in site._registry.items():
fields = getattr(model_admin, "search_fields", [])
try:
# need to force the returned queryset to get evaluated
list(model.objects.select_related(*fields))
except FieldError as error:
if "Non-relational field given in select_related" not in str(error):
self.fail(error)
tests.test_admin.test_get_forward_relation_fields_for_model(output, input)
Source code in tests/test_admin.py
@pytest.mark.parametrize(
"output,input",
[
(["event", "stripe_trigger_account"], models.WebhookEventTrigger),
(
[
"djstripe_owner_account",
"customer",
"default_payment_method",
"default_source",
"latest_invoice",
"pending_setup_intent",
"plan",
"schedule",
"default_tax_rates",
],
models.Subscription,
),
(
[
"djstripe_owner_account",
"default_source",
"coupon",
"default_payment_method",
"subscriber",
],
models.Customer,
),
],
)
def test_get_forward_relation_fields_for_model(output, input):
assert output == djstripe_admin.get_forward_relation_fields_for_model(input)
tests.test_api_keys
tests.test_api_keys.TestCheckApiKeySettings
tests.test_api_keys.TestCheckApiKeySettings.test_api_key_live_mode(self)
Source code in tests/test_api_keys.py
@override_settings(
STRIPE_TEST_SECRET_KEY="sk_test_foo",
STRIPE_LIVE_SECRET_KEY="sk_live_foo",
STRIPE_TEST_PUBLIC_KEY="pk_test_foo",
STRIPE_LIVE_PUBLIC_KEY="pk_live_foo",
STRIPE_LIVE_MODE=True,
)
def test_api_key_live_mode(self):
del settings.STRIPE_SECRET_KEY, settings.STRIPE_TEST_SECRET_KEY
del settings.STRIPE_PUBLIC_KEY, settings.STRIPE_TEST_PUBLIC_KEY
self.assertEqual(djstripe_settings.STRIPE_LIVE_MODE, True)
self.assertEqual(djstripe_settings.STRIPE_SECRET_KEY, "sk_live_foo")
self.assertEqual(djstripe_settings.STRIPE_PUBLIC_KEY, "pk_live_foo")
self.assertEqual(djstripe_settings.LIVE_API_KEY, "sk_live_foo")
self.assertEqual(models.Account(livemode=True).default_api_key, "sk_live_foo")
tests.test_api_keys.TestCheckApiKeySettings.test_global_api_keys_live_mode(self)
Source code in tests/test_api_keys.py
@override_settings(
STRIPE_LIVE_SECRET_KEY="sk_live_foo",
STRIPE_LIVE_PUBLIC_KEY="sk_live_foo",
STRIPE_LIVE_MODE=True,
)
def test_global_api_keys_live_mode(self):
self.assertEqual(djstripe_settings.STRIPE_LIVE_MODE, True)
self.assertEqual(djstripe_settings.STRIPE_SECRET_KEY, "sk_live_foo")
self.assertEqual(djstripe_settings.LIVE_API_KEY, "sk_live_foo")
self.assertEqual(models.Account(livemode=True).default_api_key, "sk_live_foo")
tests.test_api_keys.TestCheckApiKeySettings.test_global_api_keys_test_mode(self)
Source code in tests/test_api_keys.py
@override_settings(
STRIPE_TEST_SECRET_KEY="sk_test_foo",
STRIPE_TEST_PUBLIC_KEY="pk_test_foo",
STRIPE_LIVE_MODE=False,
)
def test_global_api_keys_test_mode(self):
self.assertEqual(djstripe_settings.STRIPE_LIVE_MODE, False)
self.assertEqual(djstripe_settings.STRIPE_SECRET_KEY, "sk_test_foo")
self.assertEqual(djstripe_settings.TEST_API_KEY, "sk_test_foo")
self.assertEqual(models.Account(livemode=False).default_api_key, "sk_test_foo")
tests.test_api_keys.TestCheckApiKeySettings.test_secret_key_test_mode(self)
Source code in tests/test_api_keys.py
@override_settings(
STRIPE_TEST_SECRET_KEY="sk_test_foo",
STRIPE_LIVE_SECRET_KEY="sk_live_foo",
STRIPE_TEST_PUBLIC_KEY="pk_test_foo",
STRIPE_LIVE_PUBLIC_KEY="pk_live_foo",
STRIPE_LIVE_MODE=False,
)
def test_secret_key_test_mode(self):
del settings.STRIPE_SECRET_KEY
del settings.STRIPE_PUBLIC_KEY
self.assertEqual(djstripe_settings.STRIPE_LIVE_MODE, False)
self.assertEqual(djstripe_settings.STRIPE_SECRET_KEY, "sk_test_foo")
self.assertEqual(djstripe_settings.STRIPE_PUBLIC_KEY, "pk_test_foo")
self.assertEqual(djstripe_settings.TEST_API_KEY, "sk_test_foo")
self.assertEqual(models.Account(livemode=False).default_api_key, "sk_test_foo")
tests.test_apikey
dj-stripe APIKey model tests
tests.test_apikey.PK_LIVE
tests.test_apikey.PK_TEST
tests.test_apikey.RK_LIVE
tests.test_apikey.RK_TEST
tests.test_apikey.SK_LIVE
tests.test_apikey.SK_TEST
tests.test_apikey.pytestmark
Classes
tests.test_apikey.APIKeyTest
Methods
tests.test_apikey.APIKeyTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_apikey.py
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
self.apikey_test = APIKey.objects.create(
type=APIKeyType.secret,
name="Test Secret Key",
secret=SK_TEST,
livemode=False,
djstripe_owner_account=self.account,
)
self.apikey_live = APIKey.objects.create(
type=APIKeyType.secret,
name="Live Secret Key",
secret=SK_LIVE,
livemode=True,
djstripe_owner_account=self.account,
)
tests.test_apikey.APIKeyTest.test_get_account_by_api_key(self)
Source code in tests/test_apikey.py
def test_get_account_by_api_key(self):
account = Account.get_or_retrieve_for_api_key(self.apikey_test.secret)
assert account == self.account
tests.test_apikey.APIKeyTest.test_get_stripe_dashboard_url(self)
Source code in tests/test_apikey.py
def test_get_stripe_dashboard_url(self):
self.assertEqual(
self.apikey_test.get_stripe_dashboard_url(),
"https://dashboard.stripe.com/acct_1Fg9jUA3kq9o1aTc/test/apikeys",
)
self.assertEqual(
self.apikey_live.get_stripe_dashboard_url(),
"https://dashboard.stripe.com/acct_1Fg9jUA3kq9o1aTc/apikeys",
)
tests.test_apikey.APIKeyTest.test_refresh_account(self, fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_apikey.py
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test_refresh_account(self, fileupload_retrieve_mock, account_retrieve_mock):
self.apikey_test.djstripe_owner_account = None
self.apikey_test.save()
self.apikey_test.clean()
assert self.apikey_test.djstripe_owner_account.id == FAKE_PLATFORM_ACCOUNT["id"]
tests.test_apikey.APIKeyTest.test_secret_not_in_str(self)
Source code in tests/test_apikey.py
def test_secret_not_in_str(self):
assert self.apikey_test.secret not in str(self.apikey_test)
assert self.apikey_live.secret not in str(self.apikey_live)
tests.test_apikey.APIKeyTest.test_secret_redacted(self)
Source code in tests/test_apikey.py
def test_secret_redacted(self):
self.assertEqual(self.apikey_test.secret_redacted, "sk_test_...1234")
self.assertEqual(self.apikey_live.secret_redacted, "sk_live_...5678")
tests.test_apikey.test_apikey_detect_livemode_and_type(fileupload_retrieve_mock, account_retrieve_mock)
Source code in tests/test_apikey.py
@pytest.mark.django_db
@patch("stripe.Account.retrieve", return_value=deepcopy(FAKE_PLATFORM_ACCOUNT))
@patch("stripe.File.retrieve", return_value=deepcopy(FAKE_FILEUPLOAD_ICON))
def test_apikey_detect_livemode_and_type(
fileupload_retrieve_mock, account_retrieve_mock
):
keys_and_values = (
(PK_TEST, False, APIKeyType.publishable),
(RK_TEST, False, APIKeyType.restricted),
(SK_TEST, False, APIKeyType.secret),
(PK_LIVE, True, APIKeyType.publishable),
(RK_LIVE, True, APIKeyType.restricted),
(SK_LIVE, True, APIKeyType.secret),
)
for secret, livemode, type in keys_and_values:
key = APIKey.objects.create(secret=secret)
assert key.livemode is livemode
assert key.type is type
key.clean()
assert key.livemode is livemode
assert key.type is type
tests.test_apikey.test_clean_public_apikey()
Source code in tests/test_apikey.py
def test_clean_public_apikey():
key = APIKey(type=APIKeyType.publishable, livemode=False, secret=PK_TEST)
assert not key.djstripe_owner_account
key.clean()
assert not key.djstripe_owner_account
tests.test_apikey.test_get_api_key_details_by_prefix()
Source code in tests/test_apikey.py
def test_get_api_key_details_by_prefix():
assert get_api_key_details_by_prefix(SK_TEST) == (APIKeyType.secret, False)
assert get_api_key_details_by_prefix(SK_LIVE) == (APIKeyType.secret, True)
assert get_api_key_details_by_prefix(RK_TEST) == (APIKeyType.restricted, False)
assert get_api_key_details_by_prefix(RK_LIVE) == (APIKeyType.restricted, True)
assert get_api_key_details_by_prefix(PK_TEST) == (APIKeyType.publishable, False)
assert get_api_key_details_by_prefix(PK_LIVE) == (APIKeyType.publishable, True)
tests.test_apikey.test_get_api_key_details_by_prefix_bad_values()
Source code in tests/test_apikey.py
def test_get_api_key_details_by_prefix_bad_values():
with pytest.raises(ValueError):
get_api_key_details_by_prefix("pk_a")
with pytest.raises(ValueError):
get_api_key_details_by_prefix("sk_a")
with pytest.raises(ValueError):
get_api_key_details_by_prefix("rk_nope_1234")
tests.test_balance_transaction
dj-stripe BalanceTransaction model tests
tests.test_balance_transaction.pytestmark
tests.test_balance_transaction.TestBalanceTransaction
tests.test_balance_transaction.TestBalanceTransaction.test_get_source_instance(self, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, charge_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, balance_transaction_retrieve_mock, customer_retrieve_mock, invoice_retrieve_mock)
Source code in tests/test_balance_transaction.py
@patch(
"stripe.Invoice.retrieve",
return_value=deepcopy(FAKE_INVOICE),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
autospec=True,
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_CHARGE),
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_get_source_instance(
self,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
charge_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
balance_transaction_retrieve_mock,
customer_retrieve_mock,
invoice_retrieve_mock,
):
balance_transaction = models.BalanceTransaction.sync_from_stripe_data(
deepcopy(FAKE_BALANCE_TRANSACTION)
)
charge = models.Charge.sync_from_stripe_data(deepcopy(FAKE_CHARGE))
assert balance_transaction.get_source_instance() == charge
tests.test_balance_transaction.TestBalanceTransaction.test_get_stripe_dashboard_url(self, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, charge_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, balance_transaction_retrieve_mock, customer_retrieve_mock, invoice_retrieve_mock)
Source code in tests/test_balance_transaction.py
@patch(
"stripe.Invoice.retrieve",
return_value=deepcopy(FAKE_INVOICE),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
autospec=True,
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_CHARGE),
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_get_stripe_dashboard_url(
self,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
charge_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
balance_transaction_retrieve_mock,
customer_retrieve_mock,
invoice_retrieve_mock,
):
balance_transaction = models.BalanceTransaction.sync_from_stripe_data(
deepcopy(FAKE_BALANCE_TRANSACTION)
)
charge = models.Charge.sync_from_stripe_data(deepcopy(FAKE_CHARGE))
assert (
balance_transaction.get_stripe_dashboard_url()
== charge.get_stripe_dashboard_url()
)
tests.test_balance_transaction.TestBalanceTransaction.test_sync_from_stripe_data(self, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, charge_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, balance_transaction_retrieve_mock, customer_retrieve_mock, invoice_retrieve_mock)
Source code in tests/test_balance_transaction.py
@patch(
"stripe.Invoice.retrieve",
return_value=deepcopy(FAKE_INVOICE),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
autospec=True,
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_CHARGE),
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_sync_from_stripe_data(
self,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
charge_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
balance_transaction_retrieve_mock,
customer_retrieve_mock,
invoice_retrieve_mock,
):
balance_transaction = models.BalanceTransaction.sync_from_stripe_data(
deepcopy(FAKE_BALANCE_TRANSACTION)
)
balance_transaction_retrieve_mock.assert_not_called()
assert balance_transaction.type == FAKE_BALANCE_TRANSACTION["type"]
assert balance_transaction.amount == FAKE_BALANCE_TRANSACTION["amount"]
assert balance_transaction.status == FAKE_BALANCE_TRANSACTION["status"]
tests.test_balance_transaction.TestBalanceTransactionSourceClass
tests.test_balance_transaction.TestBalanceTransactionSourceClass.test_get_source_class_failure(self, transaction_type)
Source code in tests/test_balance_transaction.py
@pytest.mark.parametrize("transaction_type", ["network_cost", "payment_refund"])
def test_get_source_class_failure(self, transaction_type):
modified_balance_transaction = deepcopy(FAKE_BALANCE_TRANSACTION)
modified_balance_transaction["type"] = transaction_type
balance_transaction = models.BalanceTransaction.sync_from_stripe_data(
modified_balance_transaction
)
with pytest.raises(LookupError):
balance_transaction.get_source_class()
tests.test_balance_transaction.TestBalanceTransactionSourceClass.test_get_source_class_success(self, transaction_type)
Source code in tests/test_balance_transaction.py
@pytest.mark.parametrize("transaction_type", ["card", "payout", "refund"])
def test_get_source_class_success(self, transaction_type):
modified_balance_transaction = deepcopy(FAKE_BALANCE_TRANSACTION)
modified_balance_transaction["type"] = transaction_type
balance_transaction = models.BalanceTransaction.sync_from_stripe_data(
modified_balance_transaction
)
assert balance_transaction.get_source_class() is getattr(
models, transaction_type.capitalize(), None
)
tests.test_balance_transaction.TestBalanceTransactionStr
tests.test_balance_transaction.TestBalanceTransactionStr.test___str__(self, transaction_status)
Source code in tests/test_balance_transaction.py
@pytest.mark.parametrize("transaction_status", BalanceTransactionStatus.__members__)
def test___str__(self, transaction_status):
modified_balance_transaction = deepcopy(FAKE_BALANCE_TRANSACTION)
modified_balance_transaction["status"] = transaction_status
balance_transaction = models.BalanceTransaction.sync_from_stripe_data(
modified_balance_transaction
)
assert (
f"{get_friendly_currency_amount(modified_balance_transaction['amount'], modified_balance_transaction['currency'])}"
f" ({BalanceTransactionStatus.humanize(modified_balance_transaction['status'])})"
) == str(balance_transaction)
tests.test_bank_account
dj-stripe Bank Account Model Tests.
tests.test_bank_account.pytestmark
Classes
tests.test_bank_account.BankAccountTest
Methods
tests.test_bank_account.BankAccountTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_bank_account.py
def setUp(self):
# create a Standard Stripe Account
self.standard_account = FAKE_STANDARD_ACCOUNT.create()
# create a Custom Stripe Account
self.custom_account = FAKE_CUSTOM_ACCOUNT.create()
user = get_user_model().objects.create_user(
username="testuser", email="djstripe@example.com"
)
fake_empty_customer = deepcopy(FAKE_CUSTOMER_IV)
fake_empty_customer["default_source"] = None
fake_empty_customer["sources"] = []
self.customer = fake_empty_customer.create_for_user(user)
tests.test_bank_account.BankAccountTest.test__api_create_with_account_absent(self, customer_retrieve_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_IV),
autospec=True,
)
def test__api_create_with_account_absent(self, customer_retrieve_mock):
stripe_bank_account = BankAccount._api_create(
customer=self.customer, source=FAKE_BANK_ACCOUNT_SOURCE["id"]
)
self.assertEqual(FAKE_BANK_ACCOUNT_SOURCE, stripe_bank_account)
tests.test_bank_account.BankAccountTest.test__api_create_with_customer_absent(self, account_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test__api_create_with_customer_absent(
self, account_retrieve_mock, customer_retrieve_mock
):
stripe_bank_account = BankAccount._api_create(
account=self.custom_account, source=FAKE_BANK_ACCOUNT_IV["id"]
)
self.assertEqual(FAKE_BANK_ACCOUNT_IV, stripe_bank_account)
tests.test_bank_account.BankAccountTest.test__api_create_with_customer_and_account(self, account_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_IV),
autospec=True,
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test__api_create_with_customer_and_account(
self, account_retrieve_mock, customer_retrieve_mock
):
FAKE_BANK_ACCOUNT_DICT = deepcopy(FAKE_BANK_ACCOUNT_SOURCE)
FAKE_BANK_ACCOUNT_DICT["account"] = FAKE_CUSTOM_ACCOUNT["id"]
stripe_bank_account = BankAccount._api_create(
account=self.custom_account,
customer=self.customer,
source=FAKE_BANK_ACCOUNT_DICT["id"],
)
self.assertEqual(FAKE_BANK_ACCOUNT_SOURCE, stripe_bank_account)
tests.test_bank_account.BankAccountTest.test_api_call_bad_account(self)
Source code in tests/test_bank_account.py
def test_api_call_bad_account(self):
exception_message = (
"BankAccounts must be manipulated through a Stripe Connected Account. "
"Pass an Account object into this call."
)
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
BankAccount._api_create(account="fish")
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
BankAccount.api_list(account="fish")
tests.test_bank_account.BankAccountTest.test_api_call_bad_customer(self)
Source code in tests/test_bank_account.py
def test_api_call_bad_customer(self):
exception_message = (
"BankAccounts must be manipulated through a Customer. "
"Pass a Customer object into this call."
)
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
BankAccount._api_create(customer="fish")
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
BankAccount.api_list(customer="fish")
tests.test_bank_account.BankAccountTest.test_api_call_no_customer_and_no_account(self)
Source code in tests/test_bank_account.py
def test_api_call_no_customer_and_no_account(self):
exception_message = (
"BankAccounts must be manipulated through either a Stripe Connected Account or a customer. "
"Pass a Customer or an Account object into this call."
)
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
BankAccount._api_create()
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
BankAccount.api_list()
tests.test_bank_account.BankAccountTest.test_api_list(self, customer_retrieve_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_IV),
autospec=True,
)
def test_api_list(self, customer_retrieve_mock):
bank_account_list = BankAccount.api_list(customer=self.customer)
self.assertCountEqual(
[FAKE_BANK_ACCOUNT_SOURCE], [i for i in bank_account_list]
)
tests.test_bank_account.BankAccountTest.test_api_retrieve_by_customer_equals_retrieval_by_account(self, account_retrieve_external_account_mock, customer_retrieve_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_BANK_ACCOUNT_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_api_retrieve_by_customer_equals_retrieval_by_account(
self, account_retrieve_external_account_mock, customer_retrieve_mock
):
# deepcopy the BankAccount object
FAKE_BANK_ACCOUNT_DICT = deepcopy(FAKE_BANK_ACCOUNT_IV)
bankaccount = BankAccount.sync_from_stripe_data(FAKE_BANK_ACCOUNT_DICT)
bankaccount_by_customer = bankaccount.api_retrieve()
# Add account
FAKE_BANK_ACCOUNT_DICT["account"] = FAKE_CUSTOM_ACCOUNT["id"]
FAKE_BANK_ACCOUNT_DICT["customer"] = None
bankaccount = BankAccount.sync_from_stripe_data(FAKE_BANK_ACCOUNT_DICT)
bankaccount_by_account = bankaccount.api_retrieve()
# assert the same bankaccount object gets retrieved
self.assertCountEqual(bankaccount_by_customer, bankaccount_by_account)
tests.test_bank_account.BankAccountTest.test_attach_objects_hook_without_account(self)
Source code in tests/test_bank_account.py
def test_attach_objects_hook_without_account(self):
bank_account = BankAccount.sync_from_stripe_data(FAKE_BANK_ACCOUNT_SOURCE)
self.assertEqual(bank_account.account, None)
tests.test_bank_account.BankAccountTest.test_attach_objects_hook_without_customer(self)
Source code in tests/test_bank_account.py
def test_attach_objects_hook_without_customer(self):
FAKE_BANK_ACCOUNT_DICT = deepcopy(FAKE_BANK_ACCOUNT_SOURCE)
FAKE_BANK_ACCOUNT_DICT["customer"] = None
bank_account = BankAccount.sync_from_stripe_data(FAKE_BANK_ACCOUNT_DICT)
self.assertEqual(bank_account.customer, None)
tests.test_bank_account.BankAccountTest.test_create_bank_account_finds_account_with_customer_absent(self)
Source code in tests/test_bank_account.py
def test_create_bank_account_finds_account_with_customer_absent(self):
FAKE_BANK_ACCOUNT_DICT = deepcopy(FAKE_BANK_ACCOUNT_SOURCE)
FAKE_BANK_ACCOUNT_DICT["account"] = self.standard_account.id
FAKE_BANK_ACCOUNT_DICT["customer"] = None
bank_account = BankAccount.sync_from_stripe_data(FAKE_BANK_ACCOUNT_DICT)
self.assertEqual(self.standard_account, bank_account.account)
self.assertEqual(
bank_account.get_stripe_dashboard_url(),
self.standard_account.get_stripe_dashboard_url(),
)
self.assert_fks(
bank_account,
expected_blank_fks={
"djstripe.BankAccount.customer",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
"djstripe.Customer.coupon",
},
)
tests.test_bank_account.BankAccountTest.test_create_bank_account_finds_customer_with_account_absent(self)
Source code in tests/test_bank_account.py
def test_create_bank_account_finds_customer_with_account_absent(self):
bank_account = BankAccount.sync_from_stripe_data(FAKE_BANK_ACCOUNT_SOURCE)
self.assertEqual(self.customer, bank_account.customer)
self.assertEqual(
bank_account.get_stripe_dashboard_url(),
self.customer.get_stripe_dashboard_url(),
)
self.assert_fks(
bank_account,
expected_blank_fks={
"djstripe.BankAccount.account",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
"djstripe.Customer.coupon",
},
)
tests.test_bank_account.BankAccountTest.test_create_bank_account_finds_customer_with_account_present(self)
Source code in tests/test_bank_account.py
def test_create_bank_account_finds_customer_with_account_present(self):
FAKE_BANK_ACCOUNT_DICT = deepcopy(FAKE_BANK_ACCOUNT_SOURCE)
FAKE_BANK_ACCOUNT_DICT["account"] = self.standard_account.id
bank_account = BankAccount.sync_from_stripe_data(FAKE_BANK_ACCOUNT_DICT)
self.assertEqual(self.customer, bank_account.customer)
self.assertEqual(self.standard_account, bank_account.account)
self.assertEqual(
bank_account.get_stripe_dashboard_url(),
self.customer.get_stripe_dashboard_url(),
)
self.assert_fks(
bank_account,
expected_blank_fks={
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
"djstripe.Customer.coupon",
},
)
tests.test_bank_account.BankAccountTest.test_remove_already_deleted_bank_account(self, customer_retrieve_source_mock, customer_retrieve_mock, bank_account_delete_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Customer.delete_source",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_IV),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_source",
return_value=deepcopy(FAKE_BANK_ACCOUNT_SOURCE),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_already_deleted_bank_account(
self,
customer_retrieve_source_mock,
customer_retrieve_mock,
bank_account_delete_mock,
):
stripe_bank_account = BankAccount._api_create(
customer=self.customer, source=FAKE_BANK_ACCOUNT_SOURCE["id"]
)
BankAccount.sync_from_stripe_data(stripe_bank_account)
self.assertEqual(self.customer.bank_account.count(), 1)
bank_account_object = self.customer.bank_account.first()
BankAccount.objects.filter(id=stripe_bank_account["id"]).delete()
self.assertEqual(self.customer.bank_account.count(), 0)
bank_account_object.remove()
self.assertEqual(self.customer.bank_account.count(), 0)
tests.test_bank_account.BankAccountTest.test_remove_already_deleted_bankaccount_by_account(self, account_retrieve_mock, bank_account_delete_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Account.delete_external_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_already_deleted_bankaccount_by_account(
self,
account_retrieve_mock,
bank_account_delete_mock,
):
stripe_bank_account = BankAccount._api_create(
account=self.custom_account, source=FAKE_BANK_ACCOUNT_IV["id"]
)
bank_account = BankAccount.sync_from_stripe_data(stripe_bank_account)
self.assertEqual(
1, BankAccount.objects.filter(id=stripe_bank_account["id"]).count()
)
api_key = bank_account.default_api_key
stripe_account = bank_account._get_stripe_account_id(api_key)
assert bank_account.customer is None
assert bank_account.account is not None
# remove BankAccount
bank_account.remove()
self.assertEqual(
0, BankAccount.objects.filter(id=stripe_bank_account["id"]).count()
)
bank_account_delete_mock.assert_called_once_with(
self.custom_account.id,
bank_account.id,
api_key=api_key,
stripe_account=stripe_account,
)
# remove BankAccount again
count, _ = BankAccount.objects.filter(id=stripe_bank_account["id"]).delete()
self.assertEqual(0, count)
tests.test_bank_account.BankAccountTest.test_remove_bankaccount_by_account(self, account_retrieve_mock, bank_account_delete_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Account.delete_external_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_bankaccount_by_account(
self,
account_retrieve_mock,
bank_account_delete_mock,
):
stripe_bank_account = BankAccount._api_create(
account=self.custom_account, source=FAKE_BANK_ACCOUNT_IV["id"]
)
bank_account = BankAccount.sync_from_stripe_data(stripe_bank_account)
self.assertEqual(
1, BankAccount.objects.filter(id=stripe_bank_account["id"]).count()
)
api_key = bank_account.default_api_key
stripe_account = bank_account._get_stripe_account_id(api_key)
assert bank_account.customer is None
assert bank_account.account is not None
# remove BankAccount
bank_account.remove()
bank_account_delete_mock.assert_called_once_with(
self.custom_account.id,
bank_account.id,
api_key=api_key,
stripe_account=stripe_account,
)
self.assertEqual(
0, BankAccount.objects.filter(id=stripe_bank_account["id"]).count()
)
tests.test_bank_account.BankAccountTest.test_remove_bankaccount_by_customer(self, customer_retrieve_source_mock, customer_retrieve_mock, bank_account_retrieve_mock, bank_account_delete_mock)
Source code in tests/test_bank_account.py
@patch(
"stripe.Customer.delete_source",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BankAccount.retrieve",
return_value=deepcopy(FAKE_BANK_ACCOUNT_SOURCE),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_IV),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_source",
return_value=deepcopy(FAKE_BANK_ACCOUNT_SOURCE),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_bankaccount_by_customer(
self,
customer_retrieve_source_mock,
customer_retrieve_mock,
bank_account_retrieve_mock,
bank_account_delete_mock,
):
stripe_bank_account = BankAccount._api_create(
customer=self.customer, source=FAKE_BANK_ACCOUNT_SOURCE["id"]
)
BankAccount.sync_from_stripe_data(stripe_bank_account)
self.assertEqual(
1, BankAccount.objects.filter(id=stripe_bank_account["id"]).count()
)
bank_account = self.customer.bank_account.all()[0]
bank_account.remove()
self.assertEqual(
0, BankAccount.objects.filter(id=stripe_bank_account["id"]).count()
)
api_key = bank_account.default_api_key
stripe_account = bank_account._get_stripe_account_id(api_key)
bank_account_delete_mock.assert_called_once_with(
self.customer.id,
bank_account.id,
api_key=api_key,
stripe_account=stripe_account,
)
tests.test_bank_account.TestStrBankAccount
tests.test_bank_account.TestStrBankAccount.test__str__(self, fake_stripe_data, has_account, has_customer, monkeypatch)
Source code in tests/test_bank_account.py
@pytest.mark.parametrize(
"fake_stripe_data, has_account, has_customer",
[
(deepcopy(FAKE_BANK_ACCOUNT_IV), True, False),
(deepcopy(FAKE_BANK_ACCOUNT_SOURCE), False, True),
],
)
def test__str__(self, fake_stripe_data, has_account, has_customer, monkeypatch):
def mock_customer_get(*args, **kwargs):
data = deepcopy(FAKE_CUSTOMER_IV)
data["default_source"] = None
data["sources"] = []
return data
def mock_account_get(*args, **kwargs):
return deepcopy(FAKE_CUSTOM_ACCOUNT)
# monkeypatch stripe.Account.retrieve and stripe.Customer.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Account, "retrieve", mock_account_get)
monkeypatch.setattr(stripe.Customer, "retrieve", mock_customer_get)
bankaccount = BankAccount.sync_from_stripe_data(fake_stripe_data)
default = False
if has_account:
default = fake_stripe_data["default_for_currency"]
assert (
f"{fake_stripe_data['bank_name']} {fake_stripe_data['currency']} {'Default' if default else ''} {fake_stripe_data['routing_number']} {fake_stripe_data['last4']}"
== str(bankaccount)
)
if has_customer:
customer = Customer.objects.filter(id=fake_stripe_data["customer"]).first()
default_source = customer.default_source
default_payment_method = customer.default_payment_method
if (
default_payment_method
and fake_stripe_data["id"] == default_payment_method.id
) or (default_source and fake_stripe_data["id"] == default_source.id):
# current bankaccount is the default payment method or source
default = True
assert (
f"{fake_stripe_data['bank_name']} {fake_stripe_data['routing_number']} ({bankaccount.human_readable_status}) {'Default' if default else ''} {fake_stripe_data['currency']}"
== str(bankaccount)
)
tests.test_bank_account.TestStrBankAccount.test_human_readable_status(self, fake_stripe_data, monkeypatch)
Source code in tests/test_bank_account.py
@pytest.mark.parametrize(
"fake_stripe_data",
[
deepcopy(FAKE_BANK_ACCOUNT_IV),
deepcopy(FAKE_BANK_ACCOUNT_SOURCE),
],
)
def test_human_readable_status(self, fake_stripe_data, monkeypatch):
def mock_customer_get(*args, **kwargs):
data = deepcopy(FAKE_CUSTOMER_IV)
data["default_source"] = None
data["sources"] = []
return data
def mock_account_get(*args, **kwargs):
return deepcopy(FAKE_CUSTOM_ACCOUNT)
# monkeypatch stripe.Account.retrieve and stripe.Customer.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Account, "retrieve", mock_account_get)
monkeypatch.setattr(stripe.Customer, "retrieve", mock_customer_get)
bankaccount = BankAccount.sync_from_stripe_data(fake_stripe_data)
if fake_stripe_data["status"] == "new":
assert bankaccount.human_readable_status == "Pending Verification"
else:
assert (
bankaccount.human_readable_status
== enums.BankAccountStatus.humanize(fake_stripe_data["status"])
)
tests.test_card
dj-stripe Card Model Tests.
tests.test_card.pytestmark
Classes
tests.test_card.CardTest
Methods
tests.test_card.CardTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_card.py
def setUp(self):
# create a Standard Stripe Account
self.standard_account = FAKE_STANDARD_ACCOUNT.create()
# create a Custom Stripe Account
self.custom_account = FAKE_CUSTOM_ACCOUNT.create()
user = get_user_model().objects.create_user(
username="testuser", email="djstripe@example.com"
)
fake_empty_customer = deepcopy(FAKE_CUSTOMER)
fake_empty_customer["default_source"] = None
fake_empty_customer["sources"] = []
self.customer = fake_empty_customer.create_for_user(user)
tests.test_card.CardTest.test__api_create_with_account_absent(self, customer_retrieve_mock)
Source code in tests/test_card.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test__api_create_with_account_absent(self, customer_retrieve_mock):
stripe_card = Card._api_create(customer=self.customer, source=FAKE_CARD["id"])
self.assertEqual(FAKE_CARD, stripe_card)
tests.test_card.CardTest.test__api_create_with_customer_absent(self, account_retrieve_mock)
Source code in tests/test_card.py
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test__api_create_with_customer_absent(self, account_retrieve_mock):
stripe_card = Card._api_create(
account=self.custom_account, source=FAKE_CARD_IV["id"]
)
self.assertEqual(FAKE_CARD_IV, stripe_card)
tests.test_card.CardTest.test__api_create_with_customer_and_account(self, account_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_card.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test__api_create_with_customer_and_account(
self, account_retrieve_mock, customer_retrieve_mock
):
FAKE_CARD_DICT = deepcopy(FAKE_CARD)
FAKE_CARD_DICT["account"] = FAKE_CUSTOM_ACCOUNT["id"]
stripe_card = Card._api_create(
account=self.custom_account,
customer=self.customer,
source=FAKE_CARD_DICT["id"],
)
self.assertEqual(FAKE_CARD, stripe_card)
tests.test_card.CardTest.test_api_call_bad_account(self)
Source code in tests/test_card.py
def test_api_call_bad_account(self):
exception_message = (
"Cards must be manipulated through a Stripe Connected Account. "
"Pass an Account object into this call."
)
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
Card._api_create(account="fish")
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
Card.api_list(account="fish")
tests.test_card.CardTest.test_api_call_bad_customer(self)
Source code in tests/test_card.py
def test_api_call_bad_customer(self):
exception_message = (
"Cards must be manipulated through a Customer. "
"Pass a Customer object into this call."
)
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
Card._api_create(customer="fish")
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
Card.api_list(customer="fish")
tests.test_card.CardTest.test_api_call_no_customer_and_no_account(self)
Source code in tests/test_card.py
def test_api_call_no_customer_and_no_account(self):
exception_message = (
"Cards must be manipulated through either a Stripe Connected Account or a customer. "
"Pass a Customer or an Account object into this call."
)
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
Card._api_create()
with self.assertRaisesMessage(
StripeObjectManipulationException, exception_message
):
Card.api_list()
tests.test_card.CardTest.test_api_list(self, customer_retrieve_mock)
Source code in tests/test_card.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_api_list(self, customer_retrieve_mock):
card_list = Card.api_list(customer=self.customer)
self.assertCountEqual([FAKE_CARD, FAKE_CARD_III], [i for i in card_list])
tests.test_card.CardTest.test_api_retrieve_by_customer_equals_retrieval_by_account(self, customer_retrieve_source_mock, account_retrieve_external_account_mock, customer_retrieve_mock)
Source code in tests/test_card.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_CARD),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Customer.retrieve_source",
return_value=deepcopy(FAKE_CARD),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_api_retrieve_by_customer_equals_retrieval_by_account(
self,
customer_retrieve_source_mock,
account_retrieve_external_account_mock,
customer_retrieve_mock,
):
# deepcopy the CardDict object
FAKE_CARD_DICT = deepcopy(FAKE_CARD)
card = Card.sync_from_stripe_data(deepcopy(FAKE_CARD_DICT))
card_by_customer = card.api_retrieve()
# Add account
FAKE_CARD_DICT["account"] = FAKE_CUSTOM_ACCOUNT["id"]
FAKE_CARD_DICT["customer"] = None
card = Card.sync_from_stripe_data(FAKE_CARD_DICT)
card_by_account = card.api_retrieve()
# assert the same card object gets retrieved
self.assertCountEqual(card_by_customer, card_by_account)
tests.test_card.CardTest.test_attach_objects_hook_without_account(self)
Source code in tests/test_card.py
def test_attach_objects_hook_without_account(self):
card = Card.sync_from_stripe_data(FAKE_CARD)
self.assertEqual(card.account, None)
tests.test_card.CardTest.test_attach_objects_hook_without_customer(self)
Source code in tests/test_card.py
def test_attach_objects_hook_without_customer(self):
FAKE_CARD_DICT = deepcopy(FAKE_CARD)
FAKE_CARD_DICT["customer"] = None
card = Card.sync_from_stripe_data(FAKE_CARD_DICT)
self.assertEqual(card.customer, None)
tests.test_card.CardTest.test_card_create_token(self, token_create_mock)
Source code in tests/test_card.py
@patch("stripe.Token.create", autospec=True)
def test_card_create_token(self, token_create_mock):
card = {"number": "4242", "exp_month": 5, "exp_year": 2012, "cvc": 445}
Card.create_token(**card)
token_create_mock.assert_called_with(api_key=ANY, card=card)
tests.test_card.CardTest.test_create_card_finds_account_with_customer_absent(self)
Source code in tests/test_card.py
def test_create_card_finds_account_with_customer_absent(self):
# deepcopy the CardDict object
FAKE_CARD_DICT = deepcopy(FAKE_CARD)
# Add account and remove customer
FAKE_CARD_DICT["account"] = self.standard_account.id
FAKE_CARD_DICT["customer"] = None
card = Card.sync_from_stripe_data(FAKE_CARD_DICT)
self.assertEqual(self.standard_account, card.account)
self.assertEqual(
card.get_stripe_dashboard_url(),
self.standard_account.get_stripe_dashboard_url(),
)
self.assert_fks(
card,
expected_blank_fks={
"djstripe.Card.customer",
"djstripe.BankAccount.account",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
},
)
tests.test_card.CardTest.test_create_card_finds_customer_with_account_absent(self)
Source code in tests/test_card.py
def test_create_card_finds_customer_with_account_absent(self):
card = Card.sync_from_stripe_data(FAKE_CARD)
self.assertEqual(self.customer, card.customer)
self.assertEqual(
card.get_stripe_dashboard_url(), self.customer.get_stripe_dashboard_url()
)
self.assert_fks(
card,
expected_blank_fks={
"djstripe.Card.account",
"djstripe.BankAccount.account",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
},
)
tests.test_card.CardTest.test_create_card_finds_customer_with_account_present(self)
Source code in tests/test_card.py
def test_create_card_finds_customer_with_account_present(self):
# deepcopy the CardDict object
FAKE_CARD_DICT = deepcopy(FAKE_CARD)
# Add account
FAKE_CARD_DICT["account"] = self.standard_account.id
card = Card.sync_from_stripe_data(FAKE_CARD_DICT)
self.assertEqual(self.customer, card.customer)
self.assertEqual(self.standard_account, card.account)
self.assertEqual(
card.get_stripe_dashboard_url(),
self.customer.get_stripe_dashboard_url(),
)
self.assert_fks(
card,
expected_blank_fks={
"djstripe.BankAccount.account",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
},
)
tests.test_card.CardTest.test_remove_already_deleted_card(self, customer_retrieve_source_mock, customer_retrieve_mock, card_delete_mock)
Source code in tests/test_card.py
@patch(
"stripe.Customer.delete_source",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Customer.retrieve_source",
return_value=deepcopy(FAKE_CARD),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_already_deleted_card(
self,
customer_retrieve_source_mock,
customer_retrieve_mock,
card_delete_mock,
):
stripe_card = Card._api_create(customer=self.customer, source=FAKE_CARD["id"])
Card.sync_from_stripe_data(stripe_card)
self.assertEqual(self.customer.legacy_cards.count(), 1)
card_object = self.customer.legacy_cards.first()
Card.objects.filter(id=stripe_card["id"]).delete()
self.assertEqual(self.customer.legacy_cards.count(), 0)
card_object.remove()
self.assertEqual(self.customer.legacy_cards.count(), 0)
tests.test_card.CardTest.test_remove_already_deleted_card_by_account(self, account_retrieve_mock, card_delete_mock)
Source code in tests/test_card.py
@patch(
"stripe.Account.delete_external_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_already_deleted_card_by_account(
self, account_retrieve_mock, card_delete_mock
):
stripe_card = Card._api_create(
account=self.custom_account, source=FAKE_CARD_IV["id"]
)
card = Card.sync_from_stripe_data(stripe_card)
self.assertEqual(1, Card.objects.filter(id=stripe_card["id"]).count())
# remove card
card.remove()
self.assertEqual(0, Card.objects.filter(id=stripe_card["id"]).count())
# remove card again
count, _ = Card.objects.filter(id=stripe_card["id"]).delete()
self.assertEqual(0, count)
api_key = card.default_api_key
stripe_account = card._get_stripe_account_id(api_key)
card_delete_mock.assert_called_once_with(
self.custom_account.id,
card.id,
api_key=api_key,
stripe_account=stripe_account,
)
tests.test_card.CardTest.test_remove_card_by_account(self, account_retrieve_mock, card_delete_mock)
Source code in tests/test_card.py
@patch(
"stripe.Account.delete_external_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_card_by_account(self, account_retrieve_mock, card_delete_mock):
stripe_card = Card._api_create(
account=self.custom_account, source=FAKE_CARD_IV["id"]
)
card = Card.sync_from_stripe_data(stripe_card)
self.assertEqual(1, Card.objects.filter(id=stripe_card["id"]).count())
# remove card
card.remove()
self.assertEqual(0, Card.objects.filter(id=stripe_card["id"]).count())
api_key = card.default_api_key
stripe_account = card._get_stripe_account_id(api_key)
card_delete_mock.assert_called_once_with(
self.custom_account.id,
card.id,
api_key=api_key,
stripe_account=stripe_account,
)
tests.test_card.CardTest.test_remove_card_by_customer(self, customer_retrieve_source_mock, customer_retrieve_mock, card_retrieve_mock, card_delete_mock)
Source code in tests/test_card.py
@patch(
"stripe.Customer.delete_source",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Card.retrieve", return_value=deepcopy(FAKE_CARD), autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Customer.retrieve_source",
return_value=deepcopy(FAKE_CARD),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_remove_card_by_customer(
self,
customer_retrieve_source_mock,
customer_retrieve_mock,
card_retrieve_mock,
card_delete_mock,
):
stripe_card = Card._api_create(customer=self.customer, source=FAKE_CARD["id"])
Card.sync_from_stripe_data(stripe_card)
self.assertEqual(1, self.customer.legacy_cards.count())
# remove card
card = self.customer.legacy_cards.all()[0]
card.remove()
self.assertEqual(0, self.customer.legacy_cards.count())
api_key = card.default_api_key
stripe_account = card._get_stripe_account_id(api_key)
card_delete_mock.assert_called_once_with(
self.customer.id, card.id, api_key=api_key, stripe_account=stripe_account
)
tests.test_card.CardTest.test_remove_no_such_customer(self, customer_retrieve_mock, card_delete_mock)
Source code in tests/test_card.py
@patch("djstripe.models.Card._api_delete", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_remove_no_such_customer(self, customer_retrieve_mock, card_delete_mock):
stripe_card = Card._api_create(customer=self.customer, source=FAKE_CARD["id"])
Card.sync_from_stripe_data(stripe_card)
card_delete_mock.side_effect = InvalidRequestError("No such customer:", "blah")
self.assertEqual(1, self.customer.legacy_cards.count())
card = self.customer.legacy_cards.all()[0]
card.remove()
self.assertEqual(0, self.customer.legacy_cards.count())
self.assertTrue(card_delete_mock.called)
tests.test_card.CardTest.test_remove_no_such_source(self, customer_retrieve_mock, card_delete_mock)
Source code in tests/test_card.py
@patch("djstripe.models.Card._api_delete", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_remove_no_such_source(self, customer_retrieve_mock, card_delete_mock):
stripe_card = Card._api_create(customer=self.customer, source=FAKE_CARD["id"])
Card.sync_from_stripe_data(stripe_card)
card_delete_mock.side_effect = InvalidRequestError("No such source:", "blah")
self.assertEqual(1, self.customer.legacy_cards.count())
card = self.customer.legacy_cards.all()[0]
card.remove()
self.assertEqual(0, self.customer.legacy_cards.count())
self.assertTrue(card_delete_mock.called)
tests.test_card.CardTest.test_remove_unexpected_exception(self, customer_retrieve_mock, card_delete_mock)
Source code in tests/test_card.py
@patch("djstripe.models.Card._api_delete", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_remove_unexpected_exception(
self, customer_retrieve_mock, card_delete_mock
):
stripe_card = Card._api_create(customer=self.customer, source=FAKE_CARD["id"])
Card.sync_from_stripe_data(stripe_card)
card_delete_mock.side_effect = InvalidRequestError(
"Unexpected Exception", "blah"
)
self.assertEqual(1, self.customer.legacy_cards.count())
card = self.customer.legacy_cards.all()[0]
with self.assertRaisesMessage(InvalidRequestError, "Unexpected Exception"):
card.remove()
tests.test_card.TestStrCard
tests.test_card.TestStrCard.test__str__(self, fake_stripe_data, has_account, has_customer, monkeypatch)
Source code in tests/test_card.py
@pytest.mark.parametrize(
"fake_stripe_data, has_account, has_customer",
[
(deepcopy(FAKE_CARD), False, True),
(deepcopy(FAKE_CARD_IV), True, False),
],
)
def test__str__(self, fake_stripe_data, has_account, has_customer, monkeypatch):
def mock_customer_get(*args, **kwargs):
data = deepcopy(FAKE_CUSTOMER)
data["default_source"] = None
data["sources"] = []
return data
def mock_account_get(*args, **kwargs):
return deepcopy(FAKE_CUSTOM_ACCOUNT)
# monkeypatch stripe.Account.retrieve and stripe.Customer.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Account, "retrieve", mock_account_get)
monkeypatch.setattr(stripe.Customer, "retrieve", mock_customer_get)
card = Card.sync_from_stripe_data(fake_stripe_data)
default = False
if has_account:
account = Account.objects.filter(id=fake_stripe_data["account"]).first()
default = fake_stripe_data["default_for_currency"]
assert (
f"{enums.CardBrand.humanize(fake_stripe_data['brand'])} {account.default_currency} {'Default' if default else ''} {fake_stripe_data['last4']}"
== str(card)
)
if has_customer:
customer = Customer.objects.filter(id=fake_stripe_data["customer"]).first()
default_source = customer.default_source
default_payment_method = customer.default_payment_method
if (
default_payment_method
and fake_stripe_data["id"] == default_payment_method.id
) or (default_source and fake_stripe_data["id"] == default_source.id):
# current card is the default payment method or source
default = True
assert (
f"{enums.CardBrand.humanize(fake_stripe_data['brand'])} {fake_stripe_data['last4']} {'Default' if default else ''} Expires {fake_stripe_data['exp_month']} {fake_stripe_data['exp_year']}"
== str(card)
)
tests.test_charge
dj-stripe Charge Model Tests.
Classes
tests.test_charge.ChargeTest
Methods
tests.test_charge.ChargeTest.setUp()
classmethod
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_charge.py
@classmethod
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
user = get_user_model().objects.create_user(
username="testuser", email="djstripe@example.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(user)
self.default_expected_blank_fks = {
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
}
tests.test_charge.ChargeTest.test___str__(self)
Source code in tests/test_charge.py
def test___str__(self):
charge = Charge(
amount=50,
currency="usd",
id="ch_test",
status=ChargeStatus.failed,
captured=False,
paid=False,
)
self.assertEqual(str(charge), "$50.00 USD (Uncaptured)")
charge.captured = True
self.assertEqual(str(charge), "$50.00 USD (Failed)")
charge.status = ChargeStatus.succeeded
charge.disputed = True
self.assertEqual(str(charge), "$50.00 USD (Disputed)")
charge.disputed = False
charge.refunded = True
charge.amount_refunded = 50
self.assertEqual(str(charge), "$50.00 USD (Refunded)")
charge.refunded = False
charge.amount_refunded = 0
self.assertEqual(str(charge), "$50.00 USD (Succeeded)")
charge.status = ChargeStatus.pending
self.assertEqual(str(charge), "$50.00 USD (Pending)")
tests.test_charge.ChargeTest.test__attach_objects_hook_missing_source_data(self, mock_account, mock_payment_method, mock_charge_source)
Make sure we handle the case where the source data is empty or insufficient.
Source code in tests/test_charge.py
@patch.object(target=Charge, attribute="source", autospec=True)
@patch(
target="djstripe.models.payment_methods.DjstripePaymentMethod", autospec=True
)
@patch(target="djstripe.models.account.Account", autospec=True)
def test__attach_objects_hook_missing_source_data(
self, mock_account, mock_payment_method, mock_charge_source
):
"""
Make sure we handle the case where the source data is empty or insufficient.
"""
charge = Charge(
amount=50,
currency="usd",
id="ch_test",
status=ChargeStatus.failed,
captured=False,
paid=False,
)
mock_cls = create_autospec(spec=Charge, spec_set=True)
# Empty data dict works for this test since we only look up the source key and
# everything else is mocked.
mock_data = {}
starting_source = charge.source
charge._attach_objects_hook(cls=mock_cls, data=mock_data)
# source shouldn't be touched
self.assertEqual(starting_source, charge.source)
mock_payment_method._get_or_create_source.assert_not_called()
# try again with a source key, but no object sub key.
mock_data = {"source": {"foo": "bar"}}
charge._attach_objects_hook(cls=mock_cls, data=mock_data)
# source shouldn't be touched
self.assertEqual(starting_source, charge.source)
mock_payment_method._get_or_create_source.assert_not_called()
tests.test_charge.ChargeTest.test_capture_charge(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, default_account_mock)
Source code in tests/test_charge.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_capture_charge(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_no_invoice = deepcopy(FAKE_CHARGE)
fake_charge_no_invoice.update({"invoice": None})
charge_retrieve_mock.return_value = fake_charge_no_invoice
# TODO - I think this is needed in line with above?
fake_payment_intent_no_invoice = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent_no_invoice.update({"invoice": None})
payment_intent_retrieve_mock.return_value = fake_payment_intent_no_invoice
charge, created = Charge._get_or_create_from_stripe_object(
fake_charge_no_invoice
)
self.assertTrue(created)
captured_charge = charge.capture()
self.assertTrue(captured_charge.captured)
self.assertFalse(captured_charge.fraudulent)
self.assert_fks(
charge,
expected_blank_fks=self.default_expected_blank_fks
| {
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.latest_invoice (related name)",
"djstripe.Charge.invoice",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.Plan.product",
},
)
tests.test_charge.ChargeTest.test_max_size_large_charge_on_decimal_amount(self, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
By contacting stripe support, some accounts will have their limit raised to 11 digits
Source code in tests/test_charge.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED
and IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.BalanceTransaction.retrieve", autospec=True)
@patch("stripe.Charge.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_max_size_large_charge_on_decimal_amount(
self,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
invoice_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
"""
By contacting stripe support, some accounts will have their limit raised to 11
digits
"""
amount = 99999999999
assert len(str(amount)) == 11
fake_transaction = deepcopy(FAKE_BALANCE_TRANSACTION)
fake_transaction.update({"amount": amount})
default_account_mock.return_value = self.account
balance_transaction_retrieve_mock.return_value = fake_transaction
fake_charge = deepcopy(FAKE_CHARGE)
fake_charge.update({"amount": amount})
charge = Charge.sync_from_stripe_data(fake_charge)
charge_retrieve_mock.assert_not_called()
self.assertTrue(bool(charge.pk))
self.assertEqual(charge.amount, Decimal("999999999.99"))
self.assertEqual(charge.balance_transaction.amount, 99999999999)
tests.test_charge.ChargeTest.test_sync_from_stripe_data(self, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_charge.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED
and IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_sync_from_stripe_data(
self,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
invoice_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
charge = Charge.sync_from_stripe_data(fake_charge_copy)
self.assertEqual(Decimal("20"), charge.amount)
self.assertEqual(True, charge.paid)
self.assertEqual(False, charge.refunded)
self.assertEqual(True, charge.captured)
self.assertEqual(False, charge.disputed)
self.assertEqual("Subscription creation", charge.description)
self.assertEqual(0, charge.amount_refunded)
self.assertEqual(self.customer.default_source.id, charge.source_id)
self.assertEqual(charge.source.type, LegacySourceType.card)
self.assertGreater(len(charge.receipt_url), 1)
self.assertTrue(charge.payment_method_details["type"])
charge_retrieve_mock.assert_not_called()
balance_transaction_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION["id"],
stripe_account=None,
)
self.assert_fks(
charge,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.Account.branding_logo", "djstripe.Account.branding_icon"},
)
tests.test_charge.ChargeTest.test_sync_from_stripe_data_max_amount(self, default_account_mock, subscription_retrieve_mock, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_charge.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_sync_from_stripe_data_max_amount(
self,
default_account_mock,
subscription_retrieve_mock,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
invoice_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
# https://support.stripe.com/questions/what-is-the-maximum-amount-i-can-charge-with-stripe
fake_charge_copy.update({"amount": 99999999})
charge = Charge.sync_from_stripe_data(fake_charge_copy)
self.assertEqual(Decimal("999999.99"), charge.amount)
self.assertEqual(True, charge.paid)
self.assertEqual(False, charge.refunded)
self.assertEqual(True, charge.captured)
self.assertEqual(False, charge.disputed)
self.assertEqual(0, charge.amount_refunded)
charge_retrieve_mock.assert_not_called()
self.assert_fks(
charge,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.Account.branding_logo", "djstripe.Account.branding_icon"},
)
tests.test_charge.ChargeTest.test_sync_from_stripe_data_no_customer(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_charge.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_sync_from_stripe_data_no_customer(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.pop("customer", None)
# remove invoice since it requires a customer
fake_charge_copy.pop("invoice", None)
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent["invoice"] = None
payment_intent_retrieve_mock.return_value = fake_payment_intent
Charge.sync_from_stripe_data(fake_charge_copy)
assert Charge.objects.count() == 1
charge = Charge.objects.get()
assert charge.customer is None
charge_retrieve_mock.assert_not_called()
balance_transaction_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION["id"],
stripe_account=None,
)
self.assert_fks(
charge,
expected_blank_fks=self.default_expected_blank_fks
| {
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.customer",
"djstripe.Charge.latest_invoice (related name)",
"djstripe.Charge.invoice",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.Plan.product",
},
)
tests.test_charge.ChargeTest.test_sync_from_stripe_data_refunded(self, subscription_retrieve_mock, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_charge.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
side_effect=[
deepcopy(FAKE_BALANCE_TRANSACTION),
deepcopy(FAKE_BALANCE_TRANSACTION_REFUND),
],
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_sync_from_stripe_data_refunded(
self,
subscription_retrieve_mock,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
invoice_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE_REFUNDED)
charge = Charge.sync_from_stripe_data(fake_charge_copy)
self.assertEqual(Decimal("20"), charge.amount)
self.assertEqual(True, charge.paid)
self.assertEqual(True, charge.refunded)
self.assertEqual(True, charge.captured)
self.assertEqual(False, charge.disputed)
self.assertEqual("Subscription creation", charge.description)
self.assertEqual(charge.amount, charge.amount_refunded)
charge_retrieve_mock.assert_not_called()
# We expect two calls - for charge and then for charge.refunds
balance_transaction_retrieve_mock.assert_has_calls(
[
call(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION["id"],
stripe_account=None,
),
call(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION_REFUND["id"],
stripe_account=None,
),
]
)
refunds = list(charge.refunds.all())
self.assertEqual(len(refunds), 1)
refund = refunds[0]
self.assertEqual(refund.id, FAKE_REFUND["id"])
self.assertNotEqual(
charge.balance_transaction.id, refund.balance_transaction.id
)
self.assertEqual(charge.balance_transaction.id, FAKE_BALANCE_TRANSACTION["id"])
self.assertEqual(
refund.balance_transaction.id, FAKE_BALANCE_TRANSACTION_REFUND["id"]
)
self.assert_fks(
charge,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.Account.branding_logo", "djstripe.Account.branding_icon"},
)
tests.test_charge.ChargeTest.test_sync_from_stripe_data_refunded_on_update(self, subscription_retrieve_mock, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, default_account_mock)
Source code in tests/test_charge.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_sync_from_stripe_data_refunded_on_update(
self,
subscription_retrieve_mock,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
invoice_retrieve_mock,
charge_retrieve_mock,
default_account_mock,
):
# first sync charge (as per test_sync_from_stripe_data)
# then sync refunded version, to hit the update code-path instead of insert
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
with patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
):
charge = Charge.sync_from_stripe_data(fake_charge_copy)
self.assertEqual(Decimal("20"), charge.amount)
self.assertEqual(True, charge.paid)
self.assertEqual(False, charge.refunded)
self.assertEqual(True, charge.captured)
self.assertEqual(False, charge.disputed)
self.assertEqual(len(charge.refunds.all()), 0)
fake_charge_refunded_copy = deepcopy(FAKE_CHARGE_REFUNDED)
with patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION_REFUND),
) as balance_transaction_retrieve_mock:
charge_refunded = Charge.sync_from_stripe_data(fake_charge_refunded_copy)
self.assertEqual(charge.id, charge_refunded.id)
self.assertEqual(Decimal("20"), charge_refunded.amount)
self.assertEqual(True, charge_refunded.paid)
self.assertEqual(True, charge_refunded.refunded)
self.assertEqual(True, charge_refunded.captured)
self.assertEqual(False, charge_refunded.disputed)
self.assertEqual("Subscription creation", charge_refunded.description)
self.assertEqual(charge_refunded.amount, charge_refunded.amount_refunded)
charge_retrieve_mock.assert_not_called()
balance_transaction_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION_REFUND["id"],
stripe_account=None,
)
refunds = list(charge_refunded.refunds.all())
self.assertEqual(len(refunds), 1)
refund = refunds[0]
self.assertEqual(refund.id, FAKE_REFUND["id"])
self.assertNotEqual(
charge_refunded.balance_transaction.id, refund.balance_transaction.id
)
self.assertEqual(
charge_refunded.balance_transaction.id, FAKE_BALANCE_TRANSACTION["id"]
)
self.assertEqual(
refund.balance_transaction.id, FAKE_BALANCE_TRANSACTION_REFUND["id"]
)
self.assert_fks(
charge_refunded,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.Account.branding_logo", "djstripe.Account.branding_icon"},
)
tests.test_charge.ChargeTest.test_sync_from_stripe_data_unsupported_source(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_charge.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_sync_from_stripe_data_unsupported_source(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
invoice_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update({"source": {"id": "test_id", "object": "unsupported"}})
charge = Charge.sync_from_stripe_data(fake_charge_copy)
self.assertEqual("test_id", charge.source_id)
self.assertEqual("UNSUPPORTED_test_id", charge.source.type)
self.assertEqual(charge.source, DjstripePaymentMethod.objects.get(id="test_id"))
charge_retrieve_mock.assert_not_called()
balance_transaction_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION["id"],
stripe_account=None,
)
self.assert_fks(
charge,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.Account.branding_logo", "djstripe.Account.branding_icon"},
)
tests.test_charge.ChargeTest.test_sync_from_stripe_data_with_destination(self, file_retrieve_mock, invoice_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, charge_retrieve_mock)
Source code in tests/test_charge.py
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.Account.retrieve", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.File.retrieve",
side_effect=[deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)],
autospec=True,
)
def test_sync_from_stripe_data_with_destination(
self,
file_retrieve_mock,
invoice_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
balance_transaction_retrieve_mock,
account_retrieve_mock,
charge_retrieve_mock,
):
account_retrieve_mock.return_value = FAKE_STANDARD_ACCOUNT
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update({"destination": FAKE_STANDARD_ACCOUNT["id"]})
charge, created = Charge._get_or_create_from_stripe_object(
fake_charge_copy, current_ids={fake_charge_copy["id"]}
)
self.assertTrue(created)
charge_retrieve_mock.assert_not_called()
balance_transaction_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION["id"],
stripe_account=None,
)
self.assert_fks(charge, expected_blank_fks=self.default_expected_blank_fks)
tests.test_charge.ChargeTest.test_sync_from_stripe_data_with_transfer(self, default_account_mock, subscription_retrieve_mock, product_retrieve_mock, transfer_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, invoice_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_charge.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch("stripe.Transfer.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_sync_from_stripe_data_with_transfer(
self,
default_account_mock,
subscription_retrieve_mock,
product_retrieve_mock,
transfer_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
invoice_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
default_account_mock.return_value = self.account
fake_transfer = deepcopy(FAKE_TRANSFER)
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update({"transfer": fake_transfer["id"]})
transfer_retrieve_mock.return_value = fake_transfer
charge_retrieve_mock.return_value = fake_charge_copy
charge, created = Charge._get_or_create_from_stripe_object(
fake_charge_copy, current_ids={fake_charge_copy["id"]}
)
self.assertTrue(created)
self.assertNotEqual(None, charge.transfer)
self.assertEqual(fake_transfer["id"], charge.transfer.id)
charge_retrieve_mock.assert_not_called()
balance_transaction_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_BALANCE_TRANSACTION["id"],
stripe_account=None,
)
self.assert_fks(
charge,
expected_blank_fks=(
self.default_expected_blank_fks
| {"djstripe.Account.branding_logo", "djstripe.Account.branding_icon"}
)
- {"djstripe.Charge.transfer"},
)
tests.test_context_managers
dj-stripe Context Manager Tests.
tests.test_context_managers.TestTemporaryVersion
tests.test_context_managers.TestTemporaryVersion.test_basic_with_exception(self)
Source code in tests/test_context_managers.py
def test_basic_with_exception(self):
version = stripe.api_version
with self.assertRaises(ValueError):
with stripe_temporary_api_version("2016-03-07"):
self.assertEqual(stripe.api_version, "2016-03-07")
raise ValueError("Something happened")
self.assertEqual(stripe.api_version, version)
tests.test_context_managers.TestTemporaryVersion.test_basic_without_validation(self)
Source code in tests/test_context_managers.py
def test_basic_without_validation(self):
version = stripe.api_version
with stripe_temporary_api_version("newversion", validate=False):
self.assertEqual(stripe.api_version, "newversion")
self.assertEqual(stripe.api_version, version)
tests.test_coupon
tests.test_coupon.pytestmark
tests.test_coupon.HumanReadableCouponTest
tests.test_coupon.HumanReadableCouponTest.test___str__(self)
Source code in tests/test_coupon.py
def test___str__(self):
coupon = Coupon.objects.create(
id="coupon-test-amount-off-forever",
amount_off=10,
currency="usd",
duration="forever",
name="Test coupon",
)
self.assertEqual(str(coupon), "Test coupon")
tests.test_coupon.HumanReadableCouponTest.test_human_readable_eur_off_forever(self)
Source code in tests/test_coupon.py
def test_human_readable_eur_off_forever(self):
coupon = Coupon.objects.create(
id="coupon-test-amount-off-forever",
amount_off=10,
currency="eur",
duration="forever",
)
self.assertEqual(coupon.human_readable, "€10.00 EUR off forever")
self.assertEqual(str(coupon), coupon.human_readable)
tests.test_coupon.HumanReadableCouponTest.test_human_readable_integer_percent_off_forever(self)
Source code in tests/test_coupon.py
def test_human_readable_integer_percent_off_forever(self):
coupon = Coupon.objects.create(
id="coupon-test-percent-off-forever",
percent_off=10,
currency="usd",
duration="forever",
)
self.assertEqual(coupon.human_readable, "10% off forever")
self.assertEqual(str(coupon), coupon.human_readable)
tests.test_coupon.HumanReadableCouponTest.test_human_readable_percent_off_forever(self)
Source code in tests/test_coupon.py
def test_human_readable_percent_off_forever(self):
coupon = Coupon.objects.create(
id="coupon-test-percent-off-forever",
percent_off=10.25,
currency="usd",
duration="forever",
)
self.assertEqual(coupon.human_readable, "10.25% off forever")
self.assertEqual(str(coupon), coupon.human_readable)
tests.test_coupon.HumanReadableCouponTest.test_human_readable_percent_off_once(self)
Source code in tests/test_coupon.py
def test_human_readable_percent_off_once(self):
coupon = Coupon.objects.create(
id="coupon-test-percent-off-once",
percent_off=10.25,
currency="usd",
duration="once",
)
self.assertEqual(coupon.human_readable, "10.25% off once")
self.assertEqual(str(coupon), coupon.human_readable)
tests.test_coupon.HumanReadableCouponTest.test_human_readable_percent_off_one_month(self)
Source code in tests/test_coupon.py
def test_human_readable_percent_off_one_month(self):
coupon = Coupon.objects.create(
id="coupon-test-percent-off-1month",
percent_off=10.25,
currency="usd",
duration="repeating",
duration_in_months=1,
)
self.assertEqual(coupon.human_readable, "10.25% off for 1 month")
self.assertEqual(str(coupon), coupon.human_readable)
tests.test_coupon.HumanReadableCouponTest.test_human_readable_percent_off_three_months(self)
Source code in tests/test_coupon.py
def test_human_readable_percent_off_three_months(self):
coupon = Coupon.objects.create(
id="coupon-test-percent-off-3month",
percent_off=10.25,
currency="usd",
duration="repeating",
duration_in_months=3,
)
self.assertEqual(coupon.human_readable, "10.25% off for 3 months")
self.assertEqual(str(coupon), coupon.human_readable)
tests.test_coupon.HumanReadableCouponTest.test_human_readable_usd_off_forever(self)
Source code in tests/test_coupon.py
def test_human_readable_usd_off_forever(self):
coupon = Coupon.objects.create(
id="coupon-test-amount-off-forever",
amount_off=10,
currency="usd",
duration="forever",
)
self.assertEqual(coupon.human_readable, "$10.00 USD off forever")
self.assertEqual(str(coupon), coupon.human_readable)
tests.test_coupon.TestCouponDecimal
tests.test_coupon.TestCouponDecimal.test_decimal_percent_off_coupon(self, inputted, expected)
Source code in tests/test_coupon.py
@pytest.mark.parametrize(
"inputted,expected",
[
(Decimal("1"), Decimal("1.00")),
(Decimal("1.5234567"), Decimal("1.52")),
(Decimal("0"), Decimal("0.00")),
(Decimal("23.2345678"), Decimal("23.23")),
("1", Decimal("1.00")),
("1.5234567", Decimal("1.52")),
("0", Decimal("0.00")),
("23.2345678", Decimal("23.23")),
(1, Decimal("1.00")),
(1.5234567, Decimal("1.52")),
(0, Decimal("0.00")),
(23.2345678, Decimal("23.24")),
],
)
def test_decimal_percent_off_coupon(self, inputted, expected):
fake_coupon = deepcopy(FAKE_COUPON)
fake_coupon["percent_off"] = inputted
coupon = Coupon.sync_from_stripe_data(fake_coupon)
field_data = coupon.percent_off
assert isinstance(field_data, Decimal)
assert field_data == expected
tests.test_coupon.TestCouponStr
tests.test_coupon.TestCouponStr.test_blank_coupon_str(self)
Source code in tests/test_coupon.py
def test_blank_coupon_str(self):
coupon = Coupon()
self.assertEqual(str(coupon).strip(), "(invalid amount) off")
tests.test_coupon.TransferTest
tests.test_coupon.TransferTest.test_retrieve_coupon(self)
Source code in tests/test_coupon.py
def test_retrieve_coupon(self):
coupon_data = deepcopy(FAKE_COUPON)
coupon = Coupon.sync_from_stripe_data(coupon_data)
self.assertEqual(coupon.id, FAKE_COUPON["id"])
tests.test_customer
Customer Model Tests.
Classes
tests.test_customer.TestCustomer
Methods
tests.test_customer.TestCustomer.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_customer.py
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
self.payment_method, _ = DjstripePaymentMethod._get_or_create_source(
FAKE_CARD, "card"
)
self.card = self.payment_method.resolve()
self.customer.default_source = self.payment_method
self.customer.save()
tests.test_customer.TestCustomer.test___str__(self)
Source code in tests/test_customer.py
def test___str__(self):
self.assertEqual(str(self.customer), str(self.user))
self.customer.subscriber = None
self.assertEqual(str(self.customer), self.customer.description)
tests.test_customer.TestCustomer.test_add_card_set_default_false(self, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_add_card_set_default_false(self, customer_retrieve_mock):
# self.customer already has FAKE_CARD as its default payment method
self.customer.add_card(FAKE_CARD_III["id"], set_default=False)
self.assertEqual(2, Card.objects.count())
self.assertEqual(FAKE_CARD["id"], self.customer.default_source.id)
tests.test_customer.TestCustomer.test_add_card_set_default_false_with_single_card_still_becomes_default(self, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_add_card_set_default_false_with_single_card_still_becomes_default(
self, customer_retrieve_mock
):
# delete all already added cards to self.customer
Card.objects.all().delete()
# assert self.customer has no cards
self.assertEqual(0, self.customer.legacy_cards.count())
self.assertEqual(0, self.customer.sources.count())
self.customer.add_card(FAKE_CARD["id"], set_default=False)
# assert new card got added to self.customer
self.assertEqual(1, Card.objects.count())
# self.customer already has FAKE_CARD as its default payment method
self.assertEqual(FAKE_CARD["id"], self.customer.default_source.id)
tests.test_customer.TestCustomer.test_add_card_set_default_true(self, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_add_card_set_default_true(self, customer_retrieve_mock):
self.customer.add_card(FAKE_CARD["id"])
self.customer.add_card(FAKE_CARD_III["id"])
self.assertEqual(2, Card.objects.count())
self.assertEqual(FAKE_CARD_III["id"], self.customer.default_source.id)
tests.test_customer.TestCustomer.test_add_coupon_by_id(self, customer_retrieve_mock, coupon_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Coupon.retrieve", return_value=deepcopy(FAKE_COUPON), autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_add_coupon_by_id(self, customer_retrieve_mock, coupon_retrieve_mock):
self.assertEqual(self.customer.coupon, None)
self.customer.add_coupon(FAKE_COUPON["id"])
customer_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=ANY,
id=FAKE_CUSTOMER["id"],
stripe_account=self.customer.djstripe_owner_account.id,
)
tests.test_customer.TestCustomer.test_add_coupon_by_object(self, customer_retrieve_mock, coupon_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Coupon.retrieve", return_value=deepcopy(FAKE_COUPON), autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_add_coupon_by_object(self, customer_retrieve_mock, coupon_retrieve_mock):
self.assertEqual(self.customer.coupon, None)
coupon = Coupon.sync_from_stripe_data(FAKE_COUPON)
fake_discount = deepcopy(FAKE_DISCOUNT_CUSTOMER)
def fake_customer_save(self, *args, **kwargs):
# fake the api coupon update behaviour
coupon = self.pop("coupon", None)
if coupon:
self["discount"] = fake_discount
else:
self["discount"] = None
return self
with patch("tests.CustomerDict.save", new=fake_customer_save):
self.customer.add_coupon(coupon)
customer_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=ANY,
id=FAKE_CUSTOMER["id"],
stripe_account=self.customer.djstripe_owner_account.id,
)
self.customer.refresh_from_db()
self.assert_fks(
self.customer,
expected_blank_fks={"djstripe.Customer.default_payment_method"},
)
tests.test_customer.TestCustomer.test_add_invoice_item(self, invoiceitem_create_mock, invoiceitem_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.InvoiceItem.sync_from_stripe_data",
return_value="pancakes",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.InvoiceItem.create",
return_value=deepcopy(FAKE_INVOICEITEM),
autospec=True,
)
def test_add_invoice_item(self, invoiceitem_create_mock, invoiceitem_sync_mock):
invoiceitem = self.customer.add_invoice_item(
amount=decimal.Decimal("50.00"),
currency="eur",
description="test",
invoice=77,
subscription=25,
)
self.assertEqual("pancakes", invoiceitem)
invoiceitem_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
amount=5000,
customer=self.customer.id,
currency="eur",
description="test",
discountable=None,
invoice=77,
metadata=None,
subscription=25,
)
tests.test_customer.TestCustomer.test_add_invoice_item_bad_decimal(self)
Source code in tests/test_customer.py
def test_add_invoice_item_bad_decimal(self):
with self.assertRaisesMessage(
ValueError, "You must supply a decimal value representing dollars."
):
self.customer.add_invoice_item(amount=5000, currency="usd")
tests.test_customer.TestCustomer.test_add_invoice_item_djstripe_objects(self, invoiceitem_create_mock, invoiceitem_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.InvoiceItem.sync_from_stripe_data",
return_value="pancakes",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.InvoiceItem.create",
return_value=deepcopy(FAKE_INVOICEITEM),
autospec=True,
)
def test_add_invoice_item_djstripe_objects(
self, invoiceitem_create_mock, invoiceitem_sync_mock
):
invoiceitem = self.customer.add_invoice_item(
amount=decimal.Decimal("50.00"),
currency="eur",
description="test",
invoice=Invoice(id=77),
subscription=Subscription(id=25),
)
self.assertEqual("pancakes", invoiceitem)
invoiceitem_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
amount=5000,
customer=self.customer.id,
currency="eur",
description="test",
discountable=None,
invoice=77,
metadata=None,
subscription=25,
)
tests.test_customer.TestCustomer.test_add_payment_method_obj(self, attach_mock, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch("stripe.PaymentMethod.attach", return_value=deepcopy(FAKE_PAYMENT_METHOD_I))
def test_add_payment_method_obj(self, attach_mock, customer_retrieve_mock):
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).count(),
0,
)
payment_method = PaymentMethod.sync_from_stripe_data(FAKE_PAYMENT_METHOD_I)
payment_method = self.customer.add_payment_method(payment_method)
self.assertEqual(payment_method.customer.id, self.customer.id)
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).count(),
1,
)
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).first(),
self.customer.default_payment_method,
)
self.assertEqual(
self.customer.default_payment_method.id,
self.customer.invoice_settings["default_payment_method"],
)
self.assert_fks(self.customer, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_customer.TestCustomer.test_add_payment_method_set_default_false(self, attach_mock, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Customer.retrieve", autospec=True)
@patch("stripe.PaymentMethod.attach", return_value=deepcopy(FAKE_PAYMENT_METHOD_I))
def test_add_payment_method_set_default_false(
self, attach_mock, customer_retrieve_mock
):
# clear default source so we can check can_charge()
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["default_source"] = None
customer_retrieve_mock.return_value = fake_customer
self.customer.default_source = None
self.customer.save()
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).count(),
0,
)
payment_method = self.customer.add_payment_method(
FAKE_PAYMENT_METHOD_I["id"], set_default=False
)
self.assertEqual(payment_method.customer.id, self.customer.id)
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).count(),
1,
)
self.assertFalse(
self.customer.can_charge(),
"Expect not to be able to charge since we've not set a "
"default_payment_method",
)
self.assert_fks(
self.customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
},
)
tests.test_customer.TestCustomer.test_add_payment_method_set_default_true(self, attach_mock, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Customer.retrieve", autospec=True)
@patch("stripe.PaymentMethod.attach", return_value=deepcopy(FAKE_PAYMENT_METHOD_I))
def test_add_payment_method_set_default_true(
self, attach_mock, customer_retrieve_mock
):
# clear default source so we can check can_charge()
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["default_source"] = None
customer_retrieve_mock.return_value = fake_customer
self.customer.default_source = None
self.customer.save()
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).count(),
0,
)
payment_method = self.customer.add_payment_method(FAKE_PAYMENT_METHOD_I["id"])
self.assertEqual(payment_method.customer.id, self.customer.id)
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).count(),
1,
)
self.assertEqual(
self.customer.payment_methods.filter(
id=FAKE_PAYMENT_METHOD_I["id"]
).first(),
self.customer.default_payment_method,
)
self.assertEqual(
self.customer.default_payment_method.id,
self.customer.invoice_settings["default_payment_method"],
)
self.assertTrue(
self.customer.can_charge(),
"Expect to be able to charge since we've set a default_payment_method",
)
self.assert_fks(
self.customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_source",
},
)
tests.test_customer.TestCustomer.test_balance(self)
Source code in tests/test_customer.py
def test_balance(self):
self.assertEqual(self.customer.balance, 0)
self.assertEqual(self.customer.credits, 0)
self.customer.balance = 1000
self.assertEqual(self.customer.balance, 1000)
self.assertEqual(self.customer.credits, 0)
self.assertEqual(self.customer.pending_charges, 1000)
self.customer.balance = -1000
self.assertEqual(self.customer.balance, -1000)
self.assertEqual(self.customer.credits, 1000)
self.assertEqual(self.customer.pending_charges, 0)
tests.test_customer.TestCustomer.test_calculate_refund_above_max_refund(self)
Source code in tests/test_customer.py
def test_calculate_refund_above_max_refund(self):
charge = Charge(
id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")
)
self.assertEqual(
charge._calculate_refund_amount(amount=decimal.Decimal("600.00")), 50000
)
tests.test_customer.TestCustomer.test_calculate_refund_amount_partial_refund(self)
Source code in tests/test_customer.py
def test_calculate_refund_amount_partial_refund(self):
charge = Charge(
id="ch_111111", customer=self.customer, amount=decimal.Decimal("500.00")
)
self.assertEqual(
charge._calculate_refund_amount(amount=decimal.Decimal("300.00")), 30000
)
tests.test_customer.TestCustomer.test_can_charge(self)
Source code in tests/test_customer.py
def test_can_charge(self):
self.assertTrue(self.customer.can_charge())
tests.test_customer.TestCustomer.test_cannot_charge(self, customer_retrieve_fake)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_cannot_charge(self, customer_retrieve_fake):
self.customer.date_purged = timezone.now()
self.assertFalse(self.customer.can_charge())
tests.test_customer.TestCustomer.test_charge_accepts_only_decimals(self)
Source code in tests/test_customer.py
def test_charge_accepts_only_decimals(self):
with self.assertRaises(ValueError):
self.customer.charge(10)
tests.test_customer.TestCustomer.test_charge_card_source(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_create_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.Charge.create", autospec=True)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_charge_card_source(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_create_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update({"invoice": None})
charge_create_mock.return_value = fake_charge_copy
charge_retrieve_mock.return_value = fake_charge_copy
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent.update({"invoice": None})
payment_intent_retrieve_mock.return_value = fake_payment_intent
self.customer.charge(amount=decimal.Decimal("10.00"), source=self.card)
tests.test_customer.TestCustomer.test_charge_converts_dollars_into_cents(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_create_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.Charge.create", autospec=True)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_charge_converts_dollars_into_cents(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_create_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update({"invoice": None, "amount": 1000})
charge_create_mock.return_value = fake_charge_copy
charge_retrieve_mock.return_value = fake_charge_copy
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent.update({"invoice": None})
payment_intent_retrieve_mock.return_value = fake_payment_intent
self.customer.charge(amount=decimal.Decimal("10.00"))
_, kwargs = charge_create_mock.call_args
self.assertEqual(kwargs["amount"], 1000)
tests.test_customer.TestCustomer.test_charge_doesnt_require_invoice(self, subscription_retrieve_mock, product_retrieve_mock, invoice_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_create_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.Charge.create", autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch("stripe.Invoice.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_charge_doesnt_require_invoice(
self,
subscription_retrieve_mock,
product_retrieve_mock,
invoice_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_create_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update(
{"invoice": FAKE_INVOICE["id"], "amount": FAKE_INVOICE["amount_due"]}
)
fake_invoice_copy = deepcopy(FAKE_INVOICE)
charge_create_mock.return_value = fake_charge_copy
charge_retrieve_mock.return_value = fake_charge_copy
invoice_retrieve_mock.return_value = fake_invoice_copy
try:
self.customer.charge(amount=decimal.Decimal("20.00"))
except Invoice.DoesNotExist:
self.fail(msg="Stripe Charge shouldn't throw Invoice DoesNotExist.")
tests.test_customer.TestCustomer.test_charge_passes_extra_arguments(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_create_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.Charge.create", autospec=True)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_charge_passes_extra_arguments(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_create_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update({"invoice": None})
charge_create_mock.return_value = fake_charge_copy
charge_retrieve_mock.return_value = fake_charge_copy
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent.update({"invoice": None})
payment_intent_retrieve_mock.return_value = fake_payment_intent
self.customer.charge(
amount=decimal.Decimal("10.00"),
capture=True,
destination=FAKE_PLATFORM_ACCOUNT["id"],
)
_, kwargs = charge_create_mock.call_args
self.assertEqual(kwargs["capture"], True)
self.assertEqual(kwargs["destination"], FAKE_PLATFORM_ACCOUNT["id"])
tests.test_customer.TestCustomer.test_charge_string_source(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_create_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.Charge.create", autospec=True)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_charge_string_source(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_create_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_copy = deepcopy(FAKE_CHARGE)
fake_charge_copy.update({"invoice": None})
charge_create_mock.return_value = fake_charge_copy
charge_retrieve_mock.return_value = fake_charge_copy
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent.update({"invoice": None})
payment_intent_retrieve_mock.return_value = fake_payment_intent
self.customer.charge(amount=decimal.Decimal("10.00"), source=self.card.id)
tests.test_customer.TestCustomer.test_customer_create_metadata_disabled(self, customer_mock)
Source code in tests/test_customer.py
@override_settings(DJSTRIPE_SUBSCRIBER_CUSTOMER_KEY="")
@patch("stripe.Customer.create", autospec=True)
def test_customer_create_metadata_disabled(self, customer_mock):
user = get_user_model().objects.create_user(
username="test_user_create_metadata_disabled"
)
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["id"] = "cus_test_create_metadata_disabled"
customer_mock.return_value = fake_customer
customer = Customer.create(user)
customer_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
email="",
idempotency_key=None,
metadata={},
stripe_account=None,
)
self.assertEqual(customer.metadata, None)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
},
)
tests.test_customer.TestCustomer.test_customer_dashboard_url(self)
Source code in tests/test_customer.py
def test_customer_dashboard_url(self):
expected_url = f"https://dashboard.stripe.com/{self.customer.djstripe_owner_account.id}/test/customers/{self.customer.id}"
self.assertEqual(self.customer.get_stripe_dashboard_url(), expected_url)
self.customer.livemode = True
expected_url = f"https://dashboard.stripe.com/{self.customer.djstripe_owner_account.id}/customers/{self.customer.id}"
self.assertEqual(self.customer.get_stripe_dashboard_url(), expected_url)
unsaved_customer = Customer()
self.assertEqual(unsaved_customer.get_stripe_dashboard_url(), "")
tests.test_customer.TestCustomer.test_customer_delete_raises_unexpected_exception(self, customer_retrieve_source_mock, customer_retrieve_mock, customer_delete_mock, customer_source_delete_mock)
Source code in tests/test_customer.py
@patch("stripe.Customer.delete_source", autospec=True)
@patch("stripe.Customer.delete", autospec=True)
@patch("stripe.Customer.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve_source",
return_value=deepcopy(FAKE_CARD),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_customer_delete_raises_unexpected_exception(
self,
customer_retrieve_source_mock,
customer_retrieve_mock,
customer_delete_mock,
customer_source_delete_mock,
):
customer_delete_mock.side_effect = InvalidRequestError(
"Unexpected Exception", "blah"
)
with self.assertRaisesMessage(InvalidRequestError, "Unexpected Exception"):
self.customer.purge()
customer_delete_mock.assert_called_once_with(
self.customer.id,
api_key=djstripe_settings.STRIPE_SECRET_KEY,
stripe_account=self.customer.djstripe_owner_account.id,
)
tests.test_customer.TestCustomer.test_customer_purge_deletes_idempotency_key(self, customer_api_create_fake)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.create", return_value=deepcopy(FAKE_CUSTOMER_II), autospec=True
)
def test_customer_purge_deletes_idempotency_key(self, customer_api_create_fake):
# We need to call Customer.get_or_create (which setUp doesn't)
# to get an idempotency key
user = get_user_model().objects.create_user(
username="blah", email=FAKE_CUSTOMER_II["email"]
)
idempotency_key_action = "customer:create:{}".format(user.pk)
self.assertFalse(
IdempotencyKey.objects.filter(action=idempotency_key_action).exists()
)
customer, created = Customer.get_or_create(user)
self.assertTrue(
IdempotencyKey.objects.filter(action=idempotency_key_action).exists()
)
with patch("stripe.Customer.delete", autospec=True):
customer.purge()
self.assertFalse(
IdempotencyKey.objects.filter(action=idempotency_key_action).exists()
)
tests.test_customer.TestCustomer.test_customer_purge_detaches_sources(self, customer_api_create_fake)
Source code in tests/test_customer.py
@patch("stripe.Customer.create", autospec=True)
def test_customer_purge_detaches_sources(
self,
customer_api_create_fake,
):
fake_customer = deepcopy(FAKE_CUSTOMER_III)
customer_api_create_fake.return_value = fake_customer
user = get_user_model().objects.create_user(
username="blah", email=FAKE_CUSTOMER_III["email"]
)
Customer.get_or_create(user)
customer = Customer.sync_from_stripe_data(deepcopy(FAKE_CUSTOMER_III))
self.assertIsNotNone(customer.default_source)
self.assertNotEqual(customer.sources.count(), 0)
with patch("stripe.Customer.delete", autospec=True), patch(
"stripe.Source.retrieve", return_value=deepcopy(FAKE_SOURCE), autospec=True
):
customer.purge()
self.assertIsNone(customer.default_source)
self.assertEqual(customer.sources.count(), 0)
tests.test_customer.TestCustomer.test_customer_purge_leaves_customer_record(self, customer_retrieve_source_mock, customer_retrieve_fake, customer_delete_mock, customer_source_delete_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.delete_source",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Customer.delete", autospec=True)
@patch("stripe.Customer.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve_source",
side_effect=[deepcopy(FAKE_CARD), deepcopy(FAKE_CARD_III)],
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_customer_purge_leaves_customer_record(
self,
customer_retrieve_source_mock,
customer_retrieve_fake,
customer_delete_mock,
customer_source_delete_mock,
):
self.customer.purge()
customer = Customer.objects.get(id=self.customer.id)
self.assertTrue(customer.subscriber is None)
self.assertTrue(customer.default_source is None)
self.assertTrue(customer.deleted is True)
self.assertTrue(not customer.legacy_cards.all())
self.assertTrue(not customer.sources.all())
self.assertTrue(get_user_model().objects.filter(pk=self.user.pk).exists())
tests.test_customer.TestCustomer.test_customer_purge_raises_customer_exception(self, customer_retrieve_mock, customer_delete_mock, customer_source_delete_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.delete_source",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Customer.delete", autospec=True)
@patch(
"stripe.Customer.retrieve",
side_effect=InvalidRequestError("No such customer:", "blah"),
autospec=True,
)
def test_customer_purge_raises_customer_exception(
self, customer_retrieve_mock, customer_delete_mock, customer_source_delete_mock
):
self.customer.purge()
customer = Customer.objects.get(id=self.customer.id)
self.assertTrue(customer.subscriber is None)
self.assertTrue(customer.default_source is None)
self.assertTrue(not customer.legacy_cards.all())
self.assertTrue(not customer.sources.all())
self.assertTrue(get_user_model().objects.filter(pk=self.user.pk).exists())
customer_delete_mock.assert_called_once_with(
self.customer.id,
api_key=djstripe_settings.STRIPE_SECRET_KEY,
stripe_account=self.customer.djstripe_owner_account.id,
)
self.assertEqual(0, customer_retrieve_mock.call_count)
self.assertEqual(2, customer_source_delete_mock.call_count)
tests.test_customer.TestCustomer.test_customer_sync_bank_account_source(self, bank_account_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.BankAccount.retrieve",
return_value=FAKE_CUSTOMER_IV["default_source"],
autospec=True,
)
def test_customer_sync_bank_account_source(self, bank_account_retrieve_mock):
fake_customer = deepcopy(FAKE_CUSTOMER_IV)
user = get_user_model().objects.create_user(
username="test_user_sync_bank_account_source"
)
customer = fake_customer.create_for_user(user)
self.assertEqual(customer.deleted, False)
self.assertEqual(customer.sources.count(), 0)
self.assertEqual(customer.legacy_cards.count(), 0)
self.assertEqual(customer.bank_account.count(), 1)
self.assertEqual(
customer.default_source.id, fake_customer["default_source"]["id"]
)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_customer.TestCustomer.test_customer_sync_default_payment_method_string(self, attach_mock, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Customer.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve", return_value=deepcopy(FAKE_PAYMENT_METHOD_I)
)
def test_customer_sync_default_payment_method_string(
self, attach_mock, customer_retrieve_mock
):
Customer.objects.all().delete()
PaymentMethod.objects.all().delete()
customer_fake = deepcopy(FAKE_CUSTOMER)
customer_fake["invoice_settings"][
"default_payment_method"
] = FAKE_PAYMENT_METHOD_I["id"]
customer_retrieve_mock.return_value = customer_fake
customer = Customer.sync_from_stripe_data(customer_fake)
self.assertEqual(
customer.default_payment_method.id,
customer_fake["invoice_settings"]["default_payment_method"],
)
self.assertEqual(customer.payment_methods.count(), 1)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.subscriber",
},
)
tests.test_customer.TestCustomer.test_customer_sync_default_source_string(self)
Source code in tests/test_customer.py
def test_customer_sync_default_source_string(self):
Customer.objects.all().delete()
Card.objects.all().delete()
customer_fake = deepcopy(FAKE_CUSTOMER)
customer = Customer.sync_from_stripe_data(customer_fake)
self.assertEqual(
customer.default_source.id, customer_fake["default_source"]["id"]
)
self.assertEqual(customer.legacy_cards.count(), 2)
self.assertEqual(len(list(customer.customer_payment_methods)), 2)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
},
)
tests.test_customer.TestCustomer.test_customer_sync_has_bad_subscriber_metadata(self)
Source code in tests/test_customer.py
def test_customer_sync_has_bad_subscriber_metadata(self):
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["id"] = "cus_sync_has_bad_subscriber_metadata"
fake_customer["metadata"] = {"djstripe_subscriber": "does_not_exist"}
customer = Customer.sync_from_stripe_data(fake_customer)
self.assertEqual(customer.subscriber, None)
self.assertEqual(customer.metadata, {"djstripe_subscriber": "does_not_exist"})
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
},
)
tests.test_customer.TestCustomer.test_customer_sync_has_subscriber_metadata(self)
Source code in tests/test_customer.py
def test_customer_sync_has_subscriber_metadata(self):
user = get_user_model().objects.create(username="test_metadata", id=12345)
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["id"] = "cus_sync_has_subscriber_metadata"
fake_customer["metadata"] = {"djstripe_subscriber": "12345"}
customer = Customer.sync_from_stripe_data(fake_customer)
self.assertEqual(customer.subscriber, user)
self.assertEqual(customer.metadata, {"djstripe_subscriber": "12345"})
tests.test_customer.TestCustomer.test_customer_sync_has_subscriber_metadata_disabled(self)
Source code in tests/test_customer.py
@override_settings(DJSTRIPE_SUBSCRIBER_CUSTOMER_KEY="")
def test_customer_sync_has_subscriber_metadata_disabled(self):
user = get_user_model().objects.create(
username="test_metadata_disabled", id=98765
)
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["id"] = "cus_test_metadata_disabled"
fake_customer["metadata"] = {"djstripe_subscriber": "98765"}
customer = Customer.sync_from_stripe_data(fake_customer)
self.assertNotEqual(customer.subscriber, user)
self.assertNotEqual(customer.subscriber_id, 98765)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
},
)
tests.test_customer.TestCustomer.test_customer_sync_no_sources(self, customer_mock)
Source code in tests/test_customer.py
@patch("stripe.Customer.create", autospec=True)
def test_customer_sync_no_sources(self, customer_mock):
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["id"] = "cus_test_sync_no_sources"
fake_customer["default_source"] = None
fake_customer["sources"] = None
customer_mock.return_value = fake_customer
user = get_user_model().objects.create_user(
username="test_user_sync_non_local_card"
)
customer = Customer.create(user)
self.assertEqual(
customer_mock.call_args_list[0][1].get("metadata"),
{"djstripe_subscriber": user.pk},
)
self.assertEqual(customer.sources.count(), 0)
self.assertEqual(customer.legacy_cards.count(), 0)
self.assertEqual(customer.default_source, None)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.default_source",
},
)
tests.test_customer.TestCustomer.test_customer_sync_non_local_card(self, card_retrieve_mock, customer_retrieve_mock, card_get_or_create_mock)
Source code in tests/test_customer.py
@patch.object(Card, "_get_or_create_from_stripe_object")
@patch("stripe.Customer.retrieve", autospec=True)
@patch(
"stripe.Card.retrieve",
autospec=True,
)
def test_customer_sync_non_local_card(
self, card_retrieve_mock, customer_retrieve_mock, card_get_or_create_mock
):
fake_customer = deepcopy(FAKE_CUSTOMER_II)
fake_customer["id"] = fake_customer["sources"]["data"][0][
"customer"
] = "cus_test_sync_non_local_card"
fake_customer["default_source"]["id"] = fake_customer["sources"]["data"][0][
"id"
] = "card_cus_test_sync_non_local_card"
customer_retrieve_mock.return_value = fake_customer
fake_card = deepcopy(fake_customer["default_source"])
fake_card["customer"] = "cus_test_sync_non_local_card"
card_retrieve_mock.return_value = fake_card
card_get_or_create_mock.return_value = fake_card
user = get_user_model().objects.create_user(
username="test_user_sync_non_local_card"
)
# create a source object so that FAKE_CUSTOMER_III with a default source
# can be created correctly.
fake_source_data = deepcopy(FAKE_SOURCE_II)
fake_source_data["card"] = deepcopy(fake_card)
fake_source_data["customer"] = fake_customer
Source.sync_from_stripe_data(fake_source_data)
customer = fake_customer.create_for_user(user)
self.assertEqual(customer.sources.count(), 1)
self.assertEqual(customer.legacy_cards.count(), 0)
self.assertEqual(
customer.default_source.id, fake_customer["default_source"]["id"]
)
tests.test_customer.TestCustomer.test_customer_sync_null_default_payment_method(self, attach_mock, customer_retrieve_mock)
Test to make sure a custom'er default_payment_method gets updated to None if they remove their only attached payment method
Source code in tests/test_customer.py
@patch("stripe.Customer.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve", return_value=deepcopy(FAKE_PAYMENT_METHOD_I)
)
def test_customer_sync_null_default_payment_method(
self, attach_mock, customer_retrieve_mock
):
"""Test to make sure a custom'er default_payment_method gets updated to None
if they remove their only attached payment method"""
Customer.objects.all().delete()
PaymentMethod.objects.all().delete()
customer_fake = deepcopy(FAKE_CUSTOMER)
customer_fake["invoice_settings"][
"default_payment_method"
] = FAKE_PAYMENT_METHOD_I["id"]
customer_retrieve_mock.return_value = customer_fake
customer = Customer.sync_from_stripe_data(customer_fake)
self.assertEqual(
customer.default_payment_method.id,
customer_fake["invoice_settings"]["default_payment_method"],
)
self.assertEqual(customer.payment_methods.count(), 1)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.subscriber",
},
)
# update customer_retrieve_mock return value
customer_fake = deepcopy(FAKE_CUSTOMER)
customer_fake["invoice_settings"]["default_payment_method"] = None
customer_retrieve_mock.return_value = customer_fake
# now detach the payment method from customer
is_detached = customer.default_payment_method.detach()
assert is_detached is True
# refresh customer from db
customer.refresh_from_db()
self.assertEqual(
customer.default_payment_method,
None,
)
self.assertEqual(customer.payment_methods.count(), 0)
self.assert_fks(
customer,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.subscriber",
"djstripe.Customer.default_payment_method",
},
)
tests.test_customer.TestCustomer.test_customer_sync_unsupported_source(self)
Source code in tests/test_customer.py
def test_customer_sync_unsupported_source(self):
fake_customer = deepcopy(FAKE_CUSTOMER_II)
fake_customer["default_source"]["object"] = fake_customer["sources"]["data"][0][
"object"
] = "fish"
user = get_user_model().objects.create_user(
username="test_user_sync_unsupported_source"
)
self.assertRaisesRegexp(
ValueError,
"Trying to fit a 'fish' into 'Card'. Aborting.",
fake_customer.create_for_user,
user,
)
tests.test_customer.TestCustomer.test_delete_subscriber_without_customer_is_noop(self, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Customer.retrieve", autospec=True)
def test_delete_subscriber_without_customer_is_noop(self, customer_retrieve_mock):
self.user.delete()
for customer in self.user.djstripe_customers.all():
self.assertIsNone(customer.date_purged)
tests.test_customer.TestCustomer.test_is_subscribed_to_with_product_new_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_is_subscribed_to_with_product_new_style(
self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock
):
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake["current_period_end"] = datetime_to_unix(
timezone.now() + timezone.timedelta(days=7)
)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
subscription_fake["latest_invoice"] = None
subscription_create_mock.return_value = subscription_fake
self.customer.subscribe(items=[{"price": price}])
assert self.customer.is_subscribed_to(product)
tests.test_customer.TestCustomer.test_is_subscribed_to_with_product_old_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_is_subscribed_to_with_product_old_style(
self,
product_retrieve_mock,
customer_retrieve_mock,
subscription_create_mock,
):
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake["current_period_end"] = datetime_to_unix(
timezone.now() + timezone.timedelta(days=7)
)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
subscription_fake["latest_invoice"] = None
subscription_create_mock.return_value = subscription_fake
self.customer.subscribe(items=[{"price": price}])
assert self.customer.is_subscribed_to(product)
tests.test_customer.TestCustomer.test_is_subscribed_to_with_product_string_new_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_is_subscribed_to_with_product_string_new_style(
self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock
):
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake["current_period_end"] = datetime_to_unix(
timezone.now() + timezone.timedelta(days=7)
)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
subscription_fake["latest_invoice"] = None
subscription_create_mock.return_value = subscription_fake
self.customer.subscribe(items=[{"price": price}])
assert self.customer.is_subscribed_to(product.id)
tests.test_customer.TestCustomer.test_is_subscribed_to_with_product_string_old_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_is_subscribed_to_with_product_string_old_style(
self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock
):
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake["current_period_end"] = datetime_to_unix(
timezone.now() + timezone.timedelta(days=7)
)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
subscription_fake["latest_invoice"] = None
subscription_create_mock.return_value = subscription_fake
# ensure DeprecationWarning is triggered
with pytest.warns(DeprecationWarning) as recorded_warning:
self.customer.subscribe(price=price)
assert len(recorded_warning) == 1
assert (
"not be accepting price (or price id)"
in recorded_warning[0].message.args[0]
)
assert self.customer.is_subscribed_to(product.id)
tests.test_customer.TestCustomer.test_refund_charge(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_refund_charge(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_no_invoice = deepcopy(FAKE_CHARGE)
fake_charge_no_invoice.update({"invoice": None})
charge_retrieve_mock.return_value = fake_charge_no_invoice
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent.update({"invoice": None})
payment_intent_retrieve_mock.return_value = fake_payment_intent
charge, created = Charge._get_or_create_from_stripe_object(
fake_charge_no_invoice
)
self.assertTrue(created)
self.assert_fks(
charge,
expected_blank_fks={
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_invoice (related name)",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.invoice",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
},
)
charge.refund()
refunded_charge, created2 = Charge._get_or_create_from_stripe_object(
fake_charge_no_invoice
)
self.assertFalse(created2)
self.assertEqual(refunded_charge.refunded, True)
self.assertEqual(refunded_charge.amount_refunded, decimal.Decimal("20.00"))
self.assert_fks(
refunded_charge,
expected_blank_fks={
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_invoice (related name)",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.invoice",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
},
)
tests.test_customer.TestCustomer.test_refund_charge_object_returned(self, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch("stripe.PaymentIntent.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
def test_refund_charge_object_returned(
self,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_charge_no_invoice = deepcopy(FAKE_CHARGE)
fake_charge_no_invoice.update({"invoice": None})
charge_retrieve_mock.return_value = fake_charge_no_invoice
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent.update({"invoice": None})
payment_intent_retrieve_mock.return_value = fake_payment_intent
charge, created = Charge._get_or_create_from_stripe_object(
fake_charge_no_invoice
)
self.assertTrue(created)
self.assert_fks(
charge,
expected_blank_fks={
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_invoice (related name)",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.invoice",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
},
)
refunded_charge = charge.refund()
self.assertEqual(refunded_charge.refunded, True)
self.assertEqual(refunded_charge.amount_refunded, decimal.Decimal("20.00"))
self.assert_fks(
refunded_charge,
expected_blank_fks={
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_invoice (related name)",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.invoice",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
},
)
tests.test_customer.TestCustomer.test_retry_unpaid_invoices(self, invoice_retry_mock, invoice_list_mock, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Invoice.list",
return_value=StripeList(
data=[deepcopy(FAKE_INVOICE), deepcopy(FAKE_INVOICE_III)]
),
autospec=True,
)
@patch("djstripe.models.Invoice.retry", autospec=True)
def test_retry_unpaid_invoices(
self,
invoice_retry_mock,
invoice_list_mock,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
self.customer.retry_unpaid_invoices()
invoice = Invoice.objects.get(id=FAKE_INVOICE_III["id"])
invoice_retry_mock.assert_called_once_with(invoice)
tests.test_customer.TestCustomer.test_retry_unpaid_invoices_expected_exception(self, invoice_retry_mock, invoice_list_mock, product_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Invoice.list",
return_value=StripeList(data=[deepcopy(FAKE_INVOICE_III)]),
)
@patch("djstripe.models.Invoice.retry", autospec=True)
def test_retry_unpaid_invoices_expected_exception(
self,
invoice_retry_mock,
invoice_list_mock,
product_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest invoice should be the unpaid one
fake_subscription["latest_invoice"] = FAKE_INVOICE_III
subscription_retrieve_mock.return_value = fake_subscription
invoice_retry_mock.side_effect = InvalidRequestError(
"Invoice is already paid", "blah"
)
try:
self.customer.retry_unpaid_invoices()
except Exception:
self.fail("Exception was unexpectedly raised.")
tests.test_customer.TestCustomer.test_retry_unpaid_invoices_none_unpaid(self, invoice_retry_mock, invoice_list_mock, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Invoice.list",
return_value=StripeList(data=[deepcopy(FAKE_INVOICE)]),
autospec=True,
)
@patch("djstripe.models.Invoice.retry", autospec=True)
def test_retry_unpaid_invoices_none_unpaid(
self,
invoice_retry_mock,
invoice_list_mock,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
self.customer.retry_unpaid_invoices()
self.assertFalse(invoice_retry_mock.called)
tests.test_customer.TestCustomer.test_retry_unpaid_invoices_unexpected_exception(self, invoice_retry_mock, invoice_list_mock, product_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, default_account_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Invoice.list",
return_value=StripeList(data=[deepcopy(FAKE_INVOICE_III)]),
)
@patch("djstripe.models.Invoice.retry", autospec=True)
def test_retry_unpaid_invoices_unexpected_exception(
self,
invoice_retry_mock,
invoice_list_mock,
product_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest invoice should be the unpaid one
fake_subscription["latest_invoice"] = FAKE_INVOICE_III
subscription_retrieve_mock.return_value = fake_subscription
invoice_retry_mock.side_effect = InvalidRequestError(
"This should fail!", "blah"
)
with self.assertRaisesMessage(InvalidRequestError, "This should fail!"):
self.customer.retry_unpaid_invoices()
tests.test_customer.TestCustomer.test_send_invoice_failure(self, invoice_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Invoice.create", autospec=True)
def test_send_invoice_failure(self, invoice_create_mock):
invoice_create_mock.side_effect = InvalidRequestError(
"Invoice creation failed.", "blah"
)
return_status = self.customer.send_invoice()
self.assertFalse(return_status)
invoice_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, customer=self.customer.id
)
tests.test_customer.TestCustomer.test_send_invoice_success(self, invoice_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Invoice.create", autospec=True)
def test_send_invoice_success(self, invoice_create_mock):
return_status = self.customer.send_invoice()
self.assertTrue(return_status)
invoice_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, customer=self.customer.id
)
tests.test_customer.TestCustomer.test_subscribe_price_string_new_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscribe_price_string_new_style(
self,
product_retrieve_mock,
customer_retrieve_mock,
subscription_create_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription["latest_invoice"] = None
subscription_create_mock.return_value = fake_subscription
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
self.assert_fks(price, expected_blank_fks={})
self.customer.subscribe(items=[{"price": price.id}])
tests.test_customer.TestCustomer.test_subscribe_price_string_old_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscribe_price_string_old_style(
self,
product_retrieve_mock,
customer_retrieve_mock,
subscription_create_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription["latest_invoice"] = None
subscription_create_mock.return_value = fake_subscription
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
self.assert_fks(price, expected_blank_fks={})
# ensure DeprecationWarning is triggered
with pytest.warns(DeprecationWarning) as recorded_warning:
self.customer.subscribe(price=price.id)
assert len(recorded_warning) == 1
assert (
"not be accepting price (or price id)"
in recorded_warning[0].message.args[0]
)
tests.test_customer.TestCustomer.test_subscription_shortcut_with_invalid_subscriptions(self, product_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscription_shortcut_with_invalid_subscriptions(
self, product_retrieve_mock, customer_retrieve_mock
):
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
self.assert_fks(price, expected_blank_fks={})
fake_subscription_upd = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription_upd["latest_invoice"] = None
fake_subscriptions = [
deepcopy(fake_subscription_upd),
deepcopy(fake_subscription_upd),
deepcopy(fake_subscription_upd),
]
# update the status of all but one to be invalid,
# we need to also change the id for sync to work
fake_subscriptions[1]["status"] = "canceled"
fake_subscriptions[1]["id"] = fake_subscriptions[1]["id"] + "foo1"
fake_subscriptions[2]["status"] = "incomplete_expired"
fake_subscriptions[2]["id"] = fake_subscriptions[2]["id"] + "foo2"
for _fake_subscription in fake_subscriptions:
with patch(
"stripe.Subscription.create",
autospec=True,
side_effect=[_fake_subscription],
):
self.customer.subscribe(items=[{"price": price}])
self.assertEqual(3, self.customer.subscriptions.count())
self.assertEqual(1, len(self.customer.valid_subscriptions))
self.assertEqual(
self.customer.valid_subscriptions[0], self.customer.subscription
)
self.assertEqual(fake_subscriptions[0]["id"], self.customer.subscription.id)
tests.test_customer.TestCustomer.test_subscription_shortcut_with_multiple_subscriptions_new_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscription_shortcut_with_multiple_subscriptions_new_style(
self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock
):
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
self.assert_fks(price, expected_blank_fks={})
subscription_fake_duplicate = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake_duplicate["id"] = "sub_6lsC8pt7IcF8jd"
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
subscription_fake_duplicate["latest_invoice"] = None
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription["latest_invoice"] = None
subscription_create_mock.side_effect = [
fake_subscription,
subscription_fake_duplicate,
]
self.customer.subscribe(items=[{"price": price}, {"price": price}])
self.assertEqual(2, self.customer.subscriptions.count())
self.assertEqual(2, len(self.customer.valid_subscriptions))
with self.assertRaises(MultipleSubscriptionException):
self.customer.subscription
tests.test_customer.TestCustomer.test_subscription_shortcut_with_multiple_subscriptions_old_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscription_shortcut_with_multiple_subscriptions_old_style(
self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock
):
price = Price.sync_from_stripe_data(deepcopy(FAKE_PRICE))
self.assert_fks(price, expected_blank_fks={})
subscription_fake_duplicate = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake_duplicate["id"] = "sub_6lsC8pt7IcF8jd"
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
subscription_fake_duplicate["latest_invoice"] = None
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription["latest_invoice"] = None
subscription_create_mock.side_effect = [
fake_subscription,
subscription_fake_duplicate,
]
self.customer.subscribe(price=price)
# ensure DeprecationWarning is triggered
with pytest.warns(DeprecationWarning) as recorded_warning:
self.customer.subscribe(price=price)
assert len(recorded_warning) == 1
assert (
"not be accepting price (or price id)"
in recorded_warning[0].message.args[0]
)
self.assertEqual(2, self.customer.subscriptions.count())
self.assertEqual(2, len(self.customer.valid_subscriptions))
with self.assertRaises(MultipleSubscriptionException):
self.customer.subscription
tests.test_customer.TestCustomer.test_sync_charges(self, customer_retrieve_mock, charge_list_mock, charge_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Charge.sync_from_stripe_data",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Charge.list",
return_value=StripeList(data=[deepcopy(FAKE_CHARGE)]),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_charges(
self, customer_retrieve_mock, charge_list_mock, charge_sync_mock
):
self.customer._sync_charges()
self.assertEqual(1, charge_sync_mock.call_count)
tests.test_customer.TestCustomer.test_sync_charges_none(self, customer_retrieve_mock, charge_list_mock, charge_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Charge.sync_from_stripe_data",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Charge.list", return_value=StripeList(data=[]), autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_charges_none(
self, customer_retrieve_mock, charge_list_mock, charge_sync_mock
):
self.customer._sync_charges()
self.assertEqual(0, charge_sync_mock.call_count)
tests.test_customer.TestCustomer.test_sync_customer_delete_discount(self)
Source code in tests/test_customer.py
def test_sync_customer_delete_discount(self):
test_coupon = Coupon.sync_from_stripe_data(FAKE_COUPON)
self.customer.coupon = test_coupon
self.customer.save()
self.assertEqual(self.customer.coupon.id, FAKE_COUPON["id"])
customer = Customer.sync_from_stripe_data(FAKE_CUSTOMER)
self.assertEqual(customer.coupon, None)
tests.test_customer.TestCustomer.test_sync_customer_discount_already_present(self, coupon_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Coupon.retrieve", return_value=deepcopy(FAKE_COUPON), autospec=True)
def test_sync_customer_discount_already_present(self, coupon_retrieve_mock):
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["discount"] = deepcopy(FAKE_DISCOUNT_CUSTOMER)
# Set the customer's coupon to be what we'll sync
customer = Customer.objects.get(id=FAKE_CUSTOMER["id"])
customer.coupon = Coupon.sync_from_stripe_data(FAKE_COUPON)
customer.save()
customer = Customer.sync_from_stripe_data(fake_customer)
self.assertEqual(customer.coupon.id, FAKE_COUPON["id"])
tests.test_customer.TestCustomer.test_sync_customer_with_discount(self, coupon_retrieve_mock)
Source code in tests/test_customer.py
@patch("stripe.Coupon.retrieve", return_value=deepcopy(FAKE_COUPON), autospec=True)
def test_sync_customer_with_discount(self, coupon_retrieve_mock):
self.assertIsNone(self.customer.coupon)
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["discount"] = deepcopy(FAKE_DISCOUNT_CUSTOMER)
customer = Customer.sync_from_stripe_data(fake_customer)
self.assertEqual(customer.coupon.id, FAKE_COUPON["id"])
self.assertIsNotNone(customer.coupon_start)
self.assertIsNone(customer.coupon_end)
tests.test_customer.TestCustomer.test_sync_invoices(self, customer_retrieve_mock, invoice_list_mock, invoice_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Invoice.sync_from_stripe_data",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Invoice.list",
return_value=StripeList(
data=[deepcopy(FAKE_INVOICE), deepcopy(FAKE_INVOICE_III)]
),
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_invoices(
self, customer_retrieve_mock, invoice_list_mock, invoice_sync_mock
):
self.customer._sync_invoices()
self.assertEqual(2, invoice_sync_mock.call_count)
tests.test_customer.TestCustomer.test_sync_invoices_none(self, customer_retrieve_mock, invoice_list_mock, invoice_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Invoice.sync_from_stripe_data",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Invoice.list", return_value=StripeList(data=[]), autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_invoices_none(
self, customer_retrieve_mock, invoice_list_mock, invoice_sync_mock
):
self.customer._sync_invoices()
self.assertEqual(0, invoice_sync_mock.call_count)
tests.test_customer.TestCustomer.test_sync_subscriptions(self, customer_retrieve_mock, subscription_list_mock, subscription_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Subscription.sync_from_stripe_data",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Subscription.list",
return_value=StripeList(
data=[deepcopy(FAKE_SUBSCRIPTION), deepcopy(FAKE_SUBSCRIPTION_II)]
),
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_subscriptions(
self, customer_retrieve_mock, subscription_list_mock, subscription_sync_mock
):
self.customer._sync_subscriptions()
self.assertEqual(2, subscription_sync_mock.call_count)
tests.test_customer.TestCustomer.test_sync_subscriptions_none(self, customer_retrieve_mock, subscription_list_mock, subscription_sync_mock)
Source code in tests/test_customer.py
@patch(
"djstripe.models.Subscription.sync_from_stripe_data",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Subscription.list", return_value=StripeList(data=[]), autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_subscriptions_none(
self, customer_retrieve_mock, subscription_list_mock, subscription_sync_mock
):
self.customer._sync_subscriptions()
self.assertEqual(0, subscription_sync_mock.call_count)
tests.test_customer.TestCustomer.test_upcoming_invoice_plan(self, invoice_upcoming_mock, invoice_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Plan.retrieve",
return_value=deepcopy(FAKE_PLAN),
autospec=True,
)
@patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", autospec=True, return_value=deepcopy(FAKE_INVOICE)
)
@patch(
"stripe.Invoice.upcoming",
return_value=deepcopy(FAKE_UPCOMING_INVOICE),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_upcoming_invoice_plan(
self,
invoice_upcoming_mock,
invoice_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
# create invoice for latest_invoice in subscription to work.
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
invoice = self.customer.upcoming_invoice()
self.assertIsNotNone(invoice)
self.assertIsNone(invoice.id)
self.assertIsNone(invoice.save())
subscription_retrieve_mock.assert_called_once_with(
api_key=ANY, expand=ANY, id=FAKE_SUBSCRIPTION["id"], stripe_account=None
)
plan_retrieve_mock.assert_not_called()
items = invoice.invoiceitems.all()
self.assertEqual(1, len(items))
self.assertEqual(FAKE_SUBSCRIPTION["id"], items[0].id)
self.assertIsNotNone(invoice.plan)
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
invoice._invoiceitems = []
items = invoice.invoiceitems.all()
self.assertEqual(0, len(items))
self.assertIsNotNone(invoice.plan)
tests.test_customer.TestCustomerLegacy
Methods
tests.test_customer.TestCustomerLegacy.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_customer.py
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
self.payment_method, _ = DjstripePaymentMethod._get_or_create_source(
FAKE_CARD, "card"
)
self.card = self.payment_method.resolve()
self.customer.default_source = self.payment_method
self.customer.save()
tests.test_customer.TestCustomerLegacy.test_subscribe_plan_string_new_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Subscription.create",
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscribe_plan_string_new_style(
self,
product_retrieve_mock,
customer_retrieve_mock,
subscription_create_mock,
):
plan = Plan.sync_from_stripe_data(deepcopy(FAKE_PLAN))
self.assert_fks(plan, expected_blank_fks={})
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription["latest_invoice"] = None
subscription_create_mock.return_value = fake_subscription
self.customer.subscribe(items=[{"plan": plan.id}])
tests.test_customer.TestCustomerLegacy.test_subscribe_plan_string_old_style(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Subscription.create",
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscribe_plan_string_old_style(
self,
product_retrieve_mock,
customer_retrieve_mock,
subscription_create_mock,
):
plan = Plan.sync_from_stripe_data(deepcopy(FAKE_PLAN))
self.assert_fks(plan, expected_blank_fks={})
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription["latest_invoice"] = None
subscription_create_mock.return_value = fake_subscription
# ensure DeprecationWarning is triggered
with pytest.warns(DeprecationWarning) as recorded_warning:
self.customer.subscribe(plan=plan.id)
assert len(recorded_warning) == 1
assert (
"not be accepting price (or price id)"
in recorded_warning[0].message.args[0]
)
tests.test_customer.TestCustomerLegacy.test_subscription_shortcut_with_invalid_subscriptions(self, product_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscription_shortcut_with_invalid_subscriptions(
self, product_retrieve_mock, customer_retrieve_mock
):
plan = Plan.sync_from_stripe_data(deepcopy(FAKE_PLAN))
self.assert_fks(plan, expected_blank_fks={})
fake_subscription_upd = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription_upd["latest_invoice"] = None
fake_subscriptions = [
deepcopy(fake_subscription_upd),
deepcopy(fake_subscription_upd),
deepcopy(fake_subscription_upd),
]
# update the status of all but one to be invalid,
# we need to also change the id for sync to work
fake_subscriptions[1]["status"] = "canceled"
fake_subscriptions[1]["id"] = fake_subscriptions[1]["id"] + "foo1"
fake_subscriptions[2]["status"] = "incomplete_expired"
fake_subscriptions[2]["id"] = fake_subscriptions[2]["id"] + "foo2"
for _fake_subscription in fake_subscriptions:
with patch(
"stripe.Subscription.create",
autospec=True,
side_effect=[_fake_subscription],
):
self.customer.subscribe(items=[{"plan": plan}])
self.assertEqual(3, self.customer.subscriptions.count())
self.assertEqual(1, len(self.customer.valid_subscriptions))
self.assertEqual(
self.customer.valid_subscriptions[0], self.customer.subscription
)
self.assertEqual(fake_subscriptions[0]["id"], self.customer.subscription.id)
tests.test_customer.TestCustomerLegacy.test_subscription_shortcut_with_multiple_subscriptions(self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock)
Source code in tests/test_customer.py
@patch("stripe.Subscription.create", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_subscription_shortcut_with_multiple_subscriptions(
self, product_retrieve_mock, customer_retrieve_mock, subscription_create_mock
):
plan = Plan.sync_from_stripe_data(deepcopy(FAKE_PLAN))
self.assert_fks(plan, expected_blank_fks={})
subscription_fake_duplicate = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake_duplicate["id"] = "sub_6lsC8pt7IcF8jd"
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
subscription_fake_duplicate["latest_invoice"] = None
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for an invoice that doesn't exist yet
# and hence cannot have been billed yet
fake_subscription["latest_invoice"] = None
subscription_create_mock.side_effect = [
fake_subscription,
subscription_fake_duplicate,
]
self.customer.subscribe(items=[{"plan": plan}, {"plan": plan}])
self.assertEqual(2, self.customer.subscriptions.count())
self.assertEqual(2, len(self.customer.valid_subscriptions))
with self.assertRaises(MultipleSubscriptionException):
self.customer.subscription
tests.test_customer.TestCustomerLegacy.test_upcoming_invoice(self, invoice_upcoming_mock, invoice_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_customer.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Plan.retrieve",
return_value=deepcopy(FAKE_PLAN),
autospec=True,
)
@patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", autospec=True, return_value=deepcopy(FAKE_INVOICE)
)
@patch(
"stripe.Invoice.upcoming",
return_value=deepcopy(FAKE_UPCOMING_INVOICE),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_upcoming_invoice(
self,
invoice_upcoming_mock,
invoice_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
# create invoice for latest_invoice in subscription to work.
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
invoice = self.customer.upcoming_invoice()
self.assertIsNotNone(invoice)
self.assertIsNone(invoice.id)
self.assertIsNone(invoice.save())
subscription_retrieve_mock.assert_called_once_with(
api_key=ANY, expand=ANY, id=FAKE_SUBSCRIPTION["id"], stripe_account=None
)
plan_retrieve_mock.assert_not_called()
items = invoice.invoiceitems.all()
self.assertEqual(1, len(items))
self.assertEqual(FAKE_SUBSCRIPTION["id"], items[0].id)
self.assertIsNotNone(invoice.plan)
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
invoice._invoiceitems = []
items = invoice.invoiceitems.all()
self.assertEqual(0, len(items))
self.assertIsNotNone(invoice.plan)
tests.test_dispute
dj-stripe Dispute model tests
tests.test_dispute.pytestmark
Classes
tests.test_dispute.TestDispute
Methods
tests.test_dispute.TestDispute.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_dispute.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="fake_customer_1", email=FAKE_CUSTOMER["email"]
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
tests.test_dispute.TestDispute.test___str__(self, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_dispute.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_DISPUTE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve", return_value=deepcopy(FAKE_DISPUTE_I), autospec=True
)
def test___str__(
self,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
dispute = Dispute.sync_from_stripe_data(FAKE_DISPUTE_I)
self.assertEqual(
str(dispute),
f"{dispute.human_readable_amount} ({enums.DisputeStatus.humanize(FAKE_DISPUTE_I['status'])}) ",
)
tests.test_dispute.TestDispute.test__attach_objects_post_save_hook(self, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_dispute.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_DISPUTE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve",
return_value=deepcopy(FAKE_DISPUTE_III),
autospec=True,
)
def test__attach_objects_post_save_hook(
self,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
dispute = Dispute.sync_from_stripe_data(FAKE_DISPUTE_III)
assert dispute.id == FAKE_DISPUTE_III["id"]
# assert File was retrieved correctly
file_retrieve_mock.assert_called_once_with(
id=FAKE_DISPUTE_III["evidence"]["receipt"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
stripe_account=None,
)
# assert Balance Transactions were retrieved correctly
balance_transaction_retrieve_mock.assert_called_once_with(
id=FAKE_DISPUTE_BALANCE_TRANSACTION["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
stripe_account=None,
)
tests.test_dispute.TestDispute.test_sync_from_stripe_data(self, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_dispute.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_DISPUTE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve", return_value=deepcopy(FAKE_DISPUTE_I), autospec=True
)
def test_sync_from_stripe_data(
self,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
dispute = Dispute.sync_from_stripe_data(FAKE_DISPUTE_I)
assert dispute.id == FAKE_DISPUTE_I["id"]
tests.test_django
tests.test_django.TestRunManagePyCheck
tests.test_django.TestRunManagePyCheck.test_manage_py_check(self)
Source code in tests/test_django.py
@override_settings(
STRIPE_TEST_SECRET_KEY="sk_test_foo",
STRIPE_LIVE_SECRET_KEY="sk_live_foo",
STRIPE_TEST_PUBLIC_KEY="pk_test_foo",
STRIPE_LIVE_PUBLIC_KEY="pk_live_foo",
STRIPE_LIVE_MODE=True,
)
def test_manage_py_check(self):
call_command("check")
tests.test_enums
tests.test_enums.TestEnumHumanize
tests.test_enums.TestEnumHumanize.test_humanize(self)
Source code in tests/test_enums.py
def test_humanize(self):
class TestEnum(Enum):
red = _("Red")
blue = _("Blue")
self.assertEqual(TestEnum.humanize("red"), _("Red"))
tests.test_enums.TestEnumMetaClass
tests.test_enums.TestEnumMetaClass.test_python2_prepare(self)
Source code in tests/test_enums.py
def test_python2_prepare(self):
# Python 2 hack to ensure __prepare__ is called...
self.assertEqual(EnumMetaClass.__prepare__(None, None), OrderedDict())
tests.test_event
dj-stripe Event Model Tests.
Classes
tests.test_event.EventRaceConditionTest
tests.test_event.EventRaceConditionTest.test_process_event_race_condition(self, transfer_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_event.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
def test_process_event_race_condition(
self,
transfer_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
transfer = Transfer.sync_from_stripe_data(deepcopy(FAKE_TRANSFER))
transfer_retrieve_mock.reset_mock()
event_data = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
# emulate the race condition in _get_or_create_from_stripe_object where
# an object is created by a different request during the call
#
# Sequence of events:
# 1) first Transfer.stripe_objects.get fails with DoesNotExist
# (due to it not existing in reality, but due to our side_effect in the test)
# 2) object is really created by a different request in reality
# 3) Transfer._create_from_stripe_object fails with IntegrityError due to
# duplicate id
# 4) second Transfer.stripe_objects.get succeeds
# (due to being created by step 2 in reality, due to side effect in the test)
side_effect = [Transfer.DoesNotExist(), transfer]
with patch(
"djstripe.models.Transfer.stripe_objects.get",
side_effect=side_effect,
autospec=True,
) as transfer_objects_get_mock:
Event.process(event_data)
self.assertEqual(transfer_objects_get_mock.call_count, 2)
self.assertEqual(transfer_retrieve_mock.call_count, 1)
tests.test_event.EventTest
Methods
tests.test_event.EventTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
patcher = patch.object(webhooks, "call_handlers")
self.addCleanup(patcher.stop)
self.call_handlers = patcher.start()
tests.test_event.EventTest.test___str__(self)
Source code in tests/test_event.py
def test___str__(self):
event = self._create_event(FAKE_EVENT_TRANSFER_CREATED)
self.assertEqual(
f"type={FAKE_EVENT_TRANSFER_CREATED['type']}, id={FAKE_EVENT_TRANSFER_CREATED['id']}",
str(event),
)
tests.test_event.EventTest.test_invoke_webhook_handlers_event_when_invalid(self)
Source code in tests/test_event.py
def test_invoke_webhook_handlers_event_when_invalid(self):
event = self._create_event(FAKE_EVENT_TRANSFER_CREATED)
event.valid = False
event.invoke_webhook_handlers()
tests.test_event.EventTest.test_invoke_webhook_handlers_event_with_log_stripe_error(self)
Source code in tests/test_event.py
def test_invoke_webhook_handlers_event_with_log_stripe_error(self):
event = self._create_event(FAKE_EVENT_TRANSFER_CREATED)
self.call_handlers.side_effect = StripeError("Boom!")
with self.assertRaises(StripeError):
event.invoke_webhook_handlers()
tests.test_event.EventTest.test_invoke_webhook_handlers_event_with_raise_stripe_error(self)
Source code in tests/test_event.py
def test_invoke_webhook_handlers_event_with_raise_stripe_error(self):
event = self._create_event(FAKE_EVENT_TRANSFER_CREATED)
self.call_handlers.side_effect = StripeError("Boom!")
with self.assertRaises(StripeError):
event.invoke_webhook_handlers()
tests.test_event.EventTest.test_process_event(self, mock_objects, mock__create_from_stripe_object, mock_atomic)
Test that process event creates a new event and invokes webhooks when the event doesn't already exist.
Source code in tests/test_event.py
@patch(target="djstripe.models.core.transaction.atomic", autospec=True)
@patch.object(target=Event, attribute="_create_from_stripe_object", autospec=True)
@patch.object(target=Event, attribute="objects", autospec=True)
def test_process_event(
self, mock_objects, mock__create_from_stripe_object, mock_atomic
):
"""Test that process event creates a new event and invokes webhooks
when the event doesn't already exist.
"""
# Set up mocks
mock_objects.filter.return_value.exists.return_value = False
mock_data = {"id": "foo_id", "other_stuff": "more_things"}
result = Event.process(data=mock_data)
# Check that all the expected work was performed
mock_objects.filter.assert_called_once_with(id=mock_data["id"])
mock_objects.filter.return_value.exists.assert_called_once_with()
mock_atomic.return_value.__enter__.assert_called_once_with()
mock__create_from_stripe_object.assert_called_once_with(mock_data)
(
mock__create_from_stripe_object.return_value.invoke_webhook_handlers
).assert_called_once_with()
# Make sure the event was returned.
self.assertEqual(mock__create_from_stripe_object.return_value, result)
tests.test_event.EventTest.test_process_event_exists(self, mock_objects, mock__create_from_stripe_object, mock_atomic)
Test that process event returns the existing event and skips webhook processing when the event already exists.
Source code in tests/test_event.py
@patch(target="djstripe.models.core.transaction.atomic", autospec=True)
@patch.object(target=Event, attribute="_create_from_stripe_object", autospec=True)
@patch.object(target=Event, attribute="objects", autospec=True)
def test_process_event_exists(
self, mock_objects, mock__create_from_stripe_object, mock_atomic
):
"""
Test that process event returns the existing event and skips webhook processing
when the event already exists.
"""
# Set up mocks
mock_objects.filter.return_value.exists.return_value = True
mock_data = {"id": "foo_id", "other_stuff": "more_things"}
result = Event.process(data=mock_data)
# Make sure that the db was queried and the existing results used.
mock_objects.filter.assert_called_once_with(id=mock_data["id"])
mock_objects.filter.return_value.exists.assert_called_once_with()
mock_objects.filter.return_value.first.assert_called_once_with()
# Make sure the webhook actions and event object creation were not performed.
mock_atomic.return_value.__enter__.assert_not_called()
mock__create_from_stripe_object.assert_not_called()
(
mock__create_from_stripe_object.return_value.invoke_webhook_handlers
).assert_not_called()
# Make sure the existing event was returned.
self.assertEqual(mock_objects.filter.return_value.first.return_value, result)
tests.test_event.EventTest.test_process_event_failure_rolls_back(self, invoke_webhook_handlers_mock)
Test that process event rolls back event creation on error
Source code in tests/test_event.py
@patch("djstripe.models.Event.invoke_webhook_handlers", autospec=True)
def test_process_event_failure_rolls_back(self, invoke_webhook_handlers_mock):
"""Test that process event rolls back event creation on error"""
class HandlerException(Exception):
pass
invoke_webhook_handlers_mock.side_effect = HandlerException
real_create_from_stripe_object = Event._create_from_stripe_object
def side_effect(*args, **kwargs):
return real_create_from_stripe_object(*args, **kwargs)
event_data = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
self.assertFalse(
Event.objects.filter(id=FAKE_EVENT_TRANSFER_CREATED["id"]).exists()
)
with self.assertRaises(HandlerException), patch(
"djstripe.models.Event._create_from_stripe_object",
side_effect=side_effect,
autospec=True,
) as create_from_stripe_object_mock:
Event.process(data=event_data)
create_from_stripe_object_mock.assert_called_once_with(event_data)
self.assertFalse(
Event.objects.filter(id=FAKE_EVENT_TRANSFER_CREATED["id"]).exists()
)
tests.test_event_handlers
dj-stripe Event Handler tests
Classes
tests.test_event_handlers.EventTestCase
tests.test_event_handlers.TestAccountEvents
Methods
tests.test_event_handlers.TestAccountEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
# create a Custom Stripe Account
self.custom_account = FAKE_CUSTOM_ACCOUNT.create()
# create a Standard Stripe Account
self.standard_account = FAKE_STANDARD_ACCOUNT.create()
# create an Express Stripe Account
self.express_account = FAKE_EXPRESS_ACCOUNT.create()
tests.test_event_handlers.TestAccountEvents.test_account_authorized_event(self, event_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Event.retrieve", autospec=True)
def test_account_authorized_event(self, event_retrieve_mock):
fake_stripe_event = deepcopy(FAKE_EVENT_ACCOUNT_APPLICATION_AUTHORIZED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
tests.test_event_handlers.TestAccountEvents.test_account_deauthorized_event(self, event_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Event.retrieve", autospec=True)
def test_account_deauthorized_event(self, event_retrieve_mock):
fake_stripe_event = deepcopy(FAKE_EVENT_ACCOUNT_APPLICATION_DEAUTHORIZED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
tests.test_event_handlers.TestAccountEvents.test_custom_account_external_account_created_bank_account_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_BANK_ACCOUNT_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_custom_account_external_account_created_bank_account_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
# fetch the newly created BankAccount object
bankaccount = BankAccount.objects.get(account=self.custom_account)
# assert the ids of the Bank Account and the Accounts were synced correctly.
self.assertEqual(
bankaccount.id,
fake_stripe_event["data"]["object"]["id"],
)
self.assertEqual(
self.custom_account.id,
fake_stripe_event["data"]["object"]["account"],
)
tests.test_event_handlers.TestAccountEvents.test_custom_account_external_account_created_card_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_CARD_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_custom_account_external_account_created_card_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_CREATED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
# fetch the newly created Card object
card = Card.objects.get(account=self.custom_account)
# assert the ids of the Card and the Accounts were synced correctly.
self.assertEqual(
card.id,
fake_stripe_event["data"]["object"]["id"],
)
self.assertEqual(
self.custom_account.id,
fake_stripe_event["data"]["object"]["account"],
)
tests.test_event_handlers.TestAccountEvents.test_custom_account_external_account_deleted_bank_account_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_BANK_ACCOUNT_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_custom_account_external_account_deleted_bank_account_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_delete_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_DELETED
)
event = Event.sync_from_stripe_data(fake_stripe_delete_event)
event.invoke_webhook_handlers()
# assert the BankAccount object no longer exists
self.assertFalse(
BankAccount.objects.filter(
id=fake_stripe_create_event["data"]["object"]["id"]
).exists()
)
tests.test_event_handlers.TestAccountEvents.test_custom_account_external_account_deleted_card_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_CARD_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_custom_account_external_account_deleted_card_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_delete_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_DELETED
)
event = Event.sync_from_stripe_data(fake_stripe_delete_event)
event.invoke_webhook_handlers()
# assert Card Object no longer exists
self.assertFalse(
Card.objects.filter(
id=fake_stripe_create_event["data"]["object"]["id"]
).exists()
)
tests.test_event_handlers.TestAccountEvents.test_custom_account_external_account_updated_bank_account_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_BANK_ACCOUNT_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_custom_account_external_account_updated_bank_account_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_update_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_UPDATED
)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
# fetch the updated BankAccount object
bankaccount = BankAccount.objects.get(account=self.custom_account)
# assert we are updating the account_holder_name
self.assertNotEqual(
fake_stripe_update_event["data"]["object"]["account_holder_name"],
fake_stripe_create_event["data"]["object"]["account_holder_name"],
)
# assert the account_holder_name got updated
self.assertNotEqual(
bankaccount.account_holder_name,
fake_stripe_update_event["data"]["object"]["account_holder_name"],
)
# assert the expected BankAccount object got updated
self.assertEqual(
bankaccount.id, fake_stripe_create_event["data"]["object"]["id"]
)
tests.test_event_handlers.TestAccountEvents.test_custom_account_external_account_updated_card_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_CARD_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_custom_account_external_account_updated_card_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_update_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_UPDATED
)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
# fetch the updated Card object
card = Card.objects.get(account=self.custom_account)
# assert we are updating the name
self.assertNotEqual(
fake_stripe_update_event["data"]["object"]["name"],
fake_stripe_create_event["data"]["object"]["name"],
)
# assert the name got updated
self.assertNotEqual(
card.name, fake_stripe_update_event["data"]["object"]["name"]
)
# assert the expected Card object got updated
self.assertEqual(card.id, fake_stripe_create_event["data"]["object"]["id"])
tests.test_event_handlers.TestAccountEvents.test_custom_account_updated_event(self, event_retrieve_mock, account_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_EVENT_CUSTOM_ACCOUNT_UPDATED["data"]["object"]),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_custom_account_updated_event(
self, event_retrieve_mock, account_retrieve_mock
):
# fetch the Stripe Account
custom_account = self.custom_account
# assert metadata is empty
self.assertEqual(custom_account.metadata, {})
fake_stripe_update_event = deepcopy(FAKE_EVENT_CUSTOM_ACCOUNT_UPDATED)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
# fetch the updated Account object
updated_custom_account = Account.objects.get(id=custom_account.id)
# assert we are updating the metadata
self.assertNotEqual(
updated_custom_account.metadata,
custom_account.metadata,
)
# assert the meta got updated
self.assertEqual(
updated_custom_account.metadata,
fake_stripe_update_event["data"]["object"]["metadata"],
)
tests.test_event_handlers.TestAccountEvents.test_express_account_external_account_created_bank_account_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_BANK_ACCOUNT_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_express_account_external_account_created_bank_account_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
# fetch the newly created BankAccount object
bankaccount = BankAccount.objects.get(account=self.express_account)
# assert the ids of the Bank Account and the Accounts were synced correctly.
self.assertEqual(
bankaccount.id,
fake_stripe_event["data"]["object"]["id"],
)
self.assertEqual(
self.express_account.id,
fake_stripe_event["data"]["object"]["account"],
)
tests.test_event_handlers.TestAccountEvents.test_express_account_external_account_created_card_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_CARD_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_express_account_external_account_created_card_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_CREATED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
# fetch the newly created Card object
card = Card.objects.get(account=self.express_account)
# assert the ids of the Card and the Accounts were synced correctly.
self.assertEqual(
card.id,
fake_stripe_event["data"]["object"]["id"],
)
self.assertEqual(
self.express_account.id,
fake_stripe_event["data"]["object"]["account"],
)
tests.test_event_handlers.TestAccountEvents.test_express_account_external_account_deleted_bank_account_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_BANK_ACCOUNT_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_express_account_external_account_deleted_bank_account_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_delete_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_DELETED
)
event = Event.sync_from_stripe_data(fake_stripe_delete_event)
event.invoke_webhook_handlers()
# assert the BankAccount object no longer exists
self.assertFalse(
BankAccount.objects.filter(
id=fake_stripe_create_event["data"]["object"]["id"]
).exists()
)
tests.test_event_handlers.TestAccountEvents.test_express_account_external_account_deleted_card_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_CARD_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_express_account_external_account_deleted_card_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_delete_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_DELETED
)
event = Event.sync_from_stripe_data(fake_stripe_delete_event)
event.invoke_webhook_handlers()
# assert Card Object no longer exists
self.assertFalse(
Card.objects.filter(
id=fake_stripe_create_event["data"]["object"]["id"]
).exists()
)
tests.test_event_handlers.TestAccountEvents.test_express_account_external_account_updated_bank_account_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_BANK_ACCOUNT_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_express_account_external_account_updated_bank_account_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_update_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_BANK_ACCOUNT_UPDATED
)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
# fetch the updated BankAccount object
bankaccount = BankAccount.objects.get(account=self.express_account)
# assert we are updating the account_holder_name
self.assertNotEqual(
fake_stripe_update_event["data"]["object"]["account_holder_name"],
fake_stripe_create_event["data"]["object"]["account_holder_name"],
)
# assert the account_holder_name got updated
self.assertNotEqual(
bankaccount.account_holder_name,
fake_stripe_update_event["data"]["object"]["account_holder_name"],
)
# assert the expected BankAccount object got updated
self.assertEqual(
bankaccount.id, fake_stripe_create_event["data"]["object"]["id"]
)
tests.test_event_handlers.TestAccountEvents.test_express_account_external_account_updated_card_event(self, event_retrieve_mock, account_retrieve_external_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve_external_account",
return_value=deepcopy(FAKE_CARD_IV),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_express_account_external_account_updated_card_event(
self, event_retrieve_mock, account_retrieve_external_account_mock
):
fake_stripe_create_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_CREATED
)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
fake_stripe_update_event = deepcopy(
FAKE_EVENT_ACCOUNT_EXTERNAL_ACCOUNT_CARD_UPDATED
)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
# fetch the updated Card object
card = Card.objects.get(account=self.express_account)
# assert we are updating the name
self.assertNotEqual(
fake_stripe_update_event["data"]["object"]["name"],
fake_stripe_create_event["data"]["object"]["name"],
)
# assert the name got updated
self.assertNotEqual(
card.name, fake_stripe_update_event["data"]["object"]["name"]
)
# assert the expected Card object got updated
self.assertEqual(card.id, fake_stripe_create_event["data"]["object"]["id"])
tests.test_event_handlers.TestAccountEvents.test_express_account_updated_event(self, event_retrieve_mock, account_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_EVENT_EXPRESS_ACCOUNT_UPDATED["data"]["object"]),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_express_account_updated_event(
self, event_retrieve_mock, account_retrieve_mock
):
# fetch the Stripe Account
express_account = self.express_account
# assert metadata is empty
self.assertEqual(express_account.metadata, {})
fake_stripe_update_event = deepcopy(FAKE_EVENT_EXPRESS_ACCOUNT_UPDATED)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
# fetch the updated Account object
updated_express_account = Account.objects.get(id=express_account.id)
# assert we are updating the metadata
self.assertNotEqual(
updated_express_account.metadata,
express_account.metadata,
)
# assert the meta got updated
self.assertEqual(
updated_express_account.metadata,
fake_stripe_update_event["data"]["object"]["metadata"],
)
tests.test_event_handlers.TestAccountEvents.test_standard_account_updated_event(self, event_retrieve_mock, account_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_EVENT_STANDARD_ACCOUNT_UPDATED["data"]["object"]),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_standard_account_updated_event(
self, event_retrieve_mock, account_retrieve_mock
):
# fetch the Stripe Account
standard_account = self.standard_account
# assert metadata is empty
self.assertEqual(standard_account.metadata, {})
fake_stripe_update_event = deepcopy(FAKE_EVENT_STANDARD_ACCOUNT_UPDATED)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
# fetch the updated Account object
updated_standard_account = Account.objects.get(id=standard_account.id)
# assert we are updating the metadata
self.assertNotEqual(
updated_standard_account.metadata,
standard_account.metadata,
)
# assert the meta got updated
self.assertEqual(
updated_standard_account.metadata,
fake_stripe_update_event["data"]["object"]["metadata"],
)
tests.test_event_handlers.TestChargeEvents
Methods
tests.test_event_handlers.TestChargeEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
tests.test_event_handlers.TestChargeEvents.test_charge_created(self, subscription_retrieve_mock, product_retrieve_mock, invoice_retrieve_mock, event_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock, account_mock)
Source code in tests/test_event_handlers.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
)
@patch("stripe.Charge.retrieve", autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch("stripe.Event.retrieve", autospec=True)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
def test_charge_created(
self,
subscription_retrieve_mock,
product_retrieve_mock,
invoice_retrieve_mock,
event_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
account_mock,
):
FAKE_CUSTOMER.create_for_user(self.user)
fake_stripe_event = deepcopy(FAKE_EVENT_CHARGE_SUCCEEDED)
event_retrieve_mock.return_value = fake_stripe_event
charge_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
account_mock.return_value = self.account
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
charge = Charge.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(
charge.amount,
fake_stripe_event["data"]["object"]["amount"] / Decimal("100"),
)
self.assertEqual(charge.status, fake_stripe_event["data"]["object"]["status"])
tests.test_event_handlers.TestCheckoutEvents
Methods
tests.test_event_handlers.TestCheckoutEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
tests.test_event_handlers.TestCheckoutEvents.test_checkout_session_async_payment_failed(self, event_retrieve_mock, payment_intent_retrieve_mock, customer_retrieve_mock, session_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.checkout.Session.retrieve", return_value=FAKE_SESSION_I, autospec=True
)
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=FAKE_PAYMENT_INTENT_I,
autospec=True,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_checkout_session_async_payment_failed(
self,
event_retrieve_mock,
payment_intent_retrieve_mock,
customer_retrieve_mock,
session_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_SESSION_COMPLETED)
fake_stripe_event["type"] = "checkout.session.async_payment_failed"
event_retrieve_mock.return_value = fake_stripe_event
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
session = Session.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(session.customer.id, self.customer.id)
tests.test_event_handlers.TestCheckoutEvents.test_checkout_session_async_payment_succeeded(self, event_retrieve_mock, payment_intent_retrieve_mock, customer_retrieve_mock, session_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.checkout.Session.retrieve", return_value=FAKE_SESSION_I, autospec=True
)
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=FAKE_PAYMENT_INTENT_I,
autospec=True,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_checkout_session_async_payment_succeeded(
self,
event_retrieve_mock,
payment_intent_retrieve_mock,
customer_retrieve_mock,
session_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_SESSION_COMPLETED)
fake_stripe_event["type"] = "checkout.session.async_payment_succeeded"
event_retrieve_mock.return_value = fake_stripe_event
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
session = Session.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(session.customer.id, self.customer.id)
tests.test_event_handlers.TestCheckoutEvents.test_checkout_session_completed(self, event_retrieve_mock, payment_intent_retrieve_mock, customer_retrieve_mock, session_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.checkout.Session.retrieve", return_value=FAKE_SESSION_I, autospec=True
)
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=FAKE_PAYMENT_INTENT_I,
autospec=True,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_checkout_session_completed(
self,
event_retrieve_mock,
payment_intent_retrieve_mock,
customer_retrieve_mock,
session_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_SESSION_COMPLETED)
event_retrieve_mock.return_value = fake_stripe_event
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
session = Session.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(session.customer.id, self.customer.id)
tests.test_event_handlers.TestCheckoutEvents.test_checkout_session_completed_customer_subscriber_added(self, event_retrieve_mock, payment_intent_retrieve_mock, customer_modify_mock, session_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.checkout.Session.retrieve", autospec=True)
@patch(
"stripe.Customer.modify",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=FAKE_PAYMENT_INTENT_I,
autospec=True,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_checkout_session_completed_customer_subscriber_added(
self,
event_retrieve_mock,
payment_intent_retrieve_mock,
customer_modify_mock,
session_retrieve_mock,
):
# because create_for_user method adds subscriber
self.customer.subcriber = None
self.customer.save()
# update metadata in deepcopied FAKE_SEESION_1 Object
fake_stripe_event = deepcopy(FAKE_EVENT_SESSION_COMPLETED)
fake_stripe_event["data"]["object"]["metadata"] = {
"djstripe_subscriber": self.user.id
}
event_retrieve_mock.return_value = fake_stripe_event
# update metadata in FAKE_SEESION_1 Object
fake_stripe_session = deepcopy(FAKE_SESSION_I)
fake_stripe_session["metadata"] = {"djstripe_subscriber": self.user.id}
session_retrieve_mock.return_value = fake_stripe_session
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
# refresh self.customer from db
self.customer.refresh_from_db()
session = Session.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(session.customer.id, self.customer.id)
self.assertEqual(self.customer.subscriber, self.user)
self.assertEqual(self.customer.metadata, {"djstripe_subscriber": self.user.id})
tests.test_event_handlers.TestCustomerEvents
Methods
tests.test_event_handlers.TestCustomerEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
tests.test_event_handlers.TestCustomerEvents.test_customer_bogus_event_type(self, event_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Customer.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_customer_bogus_event_type(
self, event_retrieve_mock, customer_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_CREATED)
fake_stripe_event["data"]["object"]["customer"] = fake_stripe_event["data"][
"object"
]["id"]
fake_stripe_event["type"] = "customer.praised"
event_retrieve_mock.return_value = fake_stripe_event
customer_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
tests.test_event_handlers.TestCustomerEvents.test_customer_card_created(self, customer_retrieve_source_mock, event_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve_source",
return_value=deepcopy(FAKE_CARD),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_customer_card_created(
self, customer_retrieve_source_mock, event_retrieve_mock, customer_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_SOURCE_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
card = Card.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertIn(card, self.customer.legacy_cards.all())
self.assertEqual(card.brand, fake_stripe_event["data"]["object"]["brand"])
self.assertEqual(card.last4, fake_stripe_event["data"]["object"]["last4"])
tests.test_event_handlers.TestCustomerEvents.test_customer_created(self, event_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_customer_created(self, event_retrieve_mock, customer_retrieve_mock):
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
customer = Customer.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(
customer.balance, fake_stripe_event["data"]["object"]["balance"]
)
self.assertEqual(
customer.currency, fake_stripe_event["data"]["object"]["currency"]
)
tests.test_event_handlers.TestCustomerEvents.test_customer_default_source_deleted(self, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
def test_customer_default_source_deleted(self, customer_retrieve_mock):
self.customer.default_source = DjstripePaymentMethod.objects.get(
id=FAKE_CARD["id"]
)
self.customer.save()
self.assertIsNotNone(self.customer.default_source)
self.assertTrue(self.customer.has_valid_source())
event = self._create_event(FAKE_EVENT_CUSTOMER_SOURCE_DELETED)
event.invoke_webhook_handlers()
# fetch the customer. Doubles up as a check that the customer didn't get
# deleted
customer = Customer.objects.get(id=FAKE_CUSTOMER["id"])
self.assertIsNone(customer.default_source)
self.assertFalse(customer.has_valid_source())
tests.test_event_handlers.TestCustomerEvents.test_customer_deleted(self, customer_retrieve_mock, customer_retrieve_source_mock, customer_delete_mock, customer_source_delete_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Customer.delete_source",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Customer.delete", autospec=True)
@patch(
"stripe.Customer.retrieve_source",
side_effect=[deepcopy(FAKE_CARD), deepcopy(FAKE_CARD_III)],
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
def test_customer_deleted(
self,
customer_retrieve_mock,
customer_retrieve_source_mock,
customer_delete_mock,
customer_source_delete_mock,
):
FAKE_CUSTOMER.create_for_user(self.user)
event = self._create_event(FAKE_EVENT_CUSTOMER_CREATED)
event.invoke_webhook_handlers()
event = self._create_event(FAKE_EVENT_CUSTOMER_DELETED)
event.invoke_webhook_handlers()
customer = Customer.objects.get(id=FAKE_CUSTOMER["id"])
self.assertIsNotNone(customer.date_purged)
tests.test_event_handlers.TestCustomerEvents.test_customer_discount_created(self, event_retrieve_mock, coupon_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Coupon.retrieve", return_value=FAKE_COUPON, autospec=True)
@patch(
"stripe.Event.retrieve",
return_value=FAKE_EVENT_CUSTOMER_DISCOUNT_CREATED,
autospec=True,
)
def test_customer_discount_created(self, event_retrieve_mock, coupon_retrieve_mock):
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_DISCOUNT_CREATED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
self.assertIsNotNone(event.customer)
self.assertEqual(event.customer.id, FAKE_CUSTOMER["id"])
self.assertIsNotNone(event.customer.coupon)
tests.test_event_handlers.TestCustomerEvents.test_customer_discount_deleted(self, event_retrieve_mock, coupon_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Coupon.retrieve", return_value=FAKE_COUPON, autospec=True)
@patch(
"stripe.Event.retrieve",
return_value=FAKE_EVENT_CUSTOMER_DISCOUNT_DELETED,
autospec=True,
)
def test_customer_discount_deleted(self, event_retrieve_mock, coupon_retrieve_mock):
coupon = Coupon.sync_from_stripe_data(FAKE_COUPON)
self.customer.coupon = coupon
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_DISCOUNT_DELETED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
self.assertIsNotNone(event.customer)
self.assertEqual(event.customer.id, FAKE_CUSTOMER["id"])
self.assertIsNone(event.customer.coupon)
tests.test_event_handlers.TestCustomerEvents.test_customer_metadata_created(self, event_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Customer.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_customer_metadata_created(
self, event_retrieve_mock, customer_retrieve_mock
):
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["metadata"] = {"djstripe_subscriber": self.user.id}
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_CREATED)
fake_stripe_event["data"]["object"] = fake_customer
event_retrieve_mock.return_value = fake_stripe_event
customer_retrieve_mock.return_value = fake_customer
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
customer = Customer.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(
customer.balance, fake_stripe_event["data"]["object"]["balance"]
)
self.assertEqual(
customer.currency, fake_stripe_event["data"]["object"]["currency"]
)
self.assertEqual(customer.subscriber, self.user)
self.assertEqual(customer.metadata, {"djstripe_subscriber": self.user.id})
tests.test_event_handlers.TestCustomerEvents.test_customer_metadata_updated(self, event_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Customer.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_customer_metadata_updated(
self, event_retrieve_mock, customer_retrieve_mock
):
fake_customer = deepcopy(FAKE_CUSTOMER)
fake_customer["metadata"] = {"djstripe_subscriber": self.user.id}
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_UPDATED)
fake_stripe_event["data"]["object"] = fake_customer
event_retrieve_mock.return_value = fake_stripe_event
customer_retrieve_mock.return_value = fake_customer
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
customer = Customer.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(
customer.balance, fake_stripe_event["data"]["object"]["balance"]
)
self.assertEqual(
customer.currency, fake_stripe_event["data"]["object"]["currency"]
)
self.assertEqual(customer.subscriber, self.user)
self.assertEqual(customer.metadata, {"djstripe_subscriber": self.user.id})
tests.test_event_handlers.TestCustomerEvents.test_customer_source_double_delete(self, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
def test_customer_source_double_delete(self, customer_retrieve_mock):
event = self._create_event(FAKE_EVENT_CUSTOMER_SOURCE_DELETED)
event.invoke_webhook_handlers()
event = self._create_event(FAKE_EVENT_CUSTOMER_SOURCE_DELETED_DUPE)
event.invoke_webhook_handlers()
# fetch the customer. Doubles up as a check that the customer didn't get
# deleted
customer = Customer.objects.get(id=FAKE_CUSTOMER["id"])
self.assertIsNone(customer.default_source)
self.assertFalse(customer.has_valid_source())
tests.test_event_handlers.TestCustomerEvents.test_customer_subscription_created(self, customer_retrieve_mock, event_retrieve_mock, product_retrieve_mock, subscription_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch("stripe.Subscription.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Event.retrieve", autospec=True)
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
def test_customer_subscription_created(
self,
customer_retrieve_mock,
event_retrieve_mock,
product_retrieve_mock,
subscription_retrieve_mock,
plan_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_SUBSCRIPTION_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# latest_invoice has to be None for a Subscription that has not been created yet.
fake_subscription["latest_invoice"] = None
subscription_retrieve_mock.return_value = fake_subscription
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
subscription = Subscription.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
self.assertIn(subscription, self.customer.subscriptions.all())
self.assertEqual(
subscription.status, fake_stripe_event["data"]["object"]["status"]
)
self.assertEqual(
subscription.quantity, fake_stripe_event["data"]["object"]["quantity"]
)
tests.test_event_handlers.TestCustomerEvents.test_customer_subscription_deleted(self, customer_retrieve_mock, product_retrieve_mock, subscription_retrieve_mock, plan_retrieve_mock, invoice_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_customer_subscription_deleted(
self,
customer_retrieve_mock,
product_retrieve_mock,
subscription_retrieve_mock,
plan_retrieve_mock,
invoice_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
# A just created Subscription cannot have latest_invoice
fake_subscription["latest_invoice"] = None
subscription_retrieve_mock.return_value = fake_subscription
fake_event = deepcopy(FAKE_EVENT_CUSTOMER_SUBSCRIPTION_CREATED)
fake_event["data"]["object"] = fake_subscription
event = self._create_event(fake_event)
event.invoke_webhook_handlers()
sub = Subscription.objects.get(id=fake_subscription["id"])
self.assertEqual(sub.status, SubscriptionStatus.active)
# create invoice for latest_invoice in subscription to work.
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
subscription_retrieve_mock.return_value = deepcopy(FAKE_SUBSCRIPTION_CANCELED)
event = self._create_event(FAKE_EVENT_CUSTOMER_SUBSCRIPTION_DELETED)
event.invoke_webhook_handlers()
sub = Subscription.objects.get(id=FAKE_SUBSCRIPTION["id"])
# Check that Subscription is canceled and not deleted
self.assertEqual(sub.status, SubscriptionStatus.canceled)
self.assertIsNotNone(sub.canceled_at)
tests.test_event_handlers.TestCustomerEvents.test_customer_unknown_source_created(self, customer_retrieve_mock, event_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Event.retrieve", autospec=True)
@patch("stripe.Customer.retrieve", return_value=FAKE_CUSTOMER, autospec=True)
def test_customer_unknown_source_created(
self, customer_retrieve_mock, event_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_CUSTOMER_SOURCE_CREATED)
fake_stripe_event["data"]["object"]["object"] = "unknown"
fake_stripe_event["data"]["object"][
"id"
] = "card_xxx_test_customer_unk_source_created"
event_retrieve_mock.return_value = fake_stripe_event
FAKE_CUSTOMER.create_for_user(self.user)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
self.assertFalse(
Card.objects.filter(id=fake_stripe_event["data"]["object"]["id"]).exists()
)
tests.test_event_handlers.TestDisputeEvents
Methods
tests.test_event_handlers.TestDisputeEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="fake_customer_1", email=FAKE_CUSTOMER["email"]
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
tests.test_event_handlers.TestDisputeEvents.test_dispute_closed(self, event_retrieve_mock, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_DISPUTE_BALANCE_TRANSACTION),
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve",
return_value=deepcopy(FAKE_DISPUTE_III),
autospec=True,
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_DISPUTE_CLOSED),
autospec=True,
)
def test_dispute_closed(
self,
event_retrieve_mock,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_DISPUTE_CLOSED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
dispute = Dispute.objects.get()
self.assertEqual(dispute.id, FAKE_DISPUTE_III["id"])
tests.test_event_handlers.TestDisputeEvents.test_dispute_created(self, event_retrieve_mock, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_DISPUTE_BALANCE_TRANSACTION),
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve", return_value=deepcopy(FAKE_DISPUTE_I), autospec=True
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_DISPUTE_CREATED),
autospec=True,
)
def test_dispute_created(
self,
event_retrieve_mock,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_DISPUTE_CREATED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
dispute = Dispute.objects.get()
self.assertEqual(dispute.id, FAKE_DISPUTE_I["id"])
tests.test_event_handlers.TestDisputeEvents.test_dispute_funds_reinstated_full(self, event_retrieve_mock, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
side_effect=[
FAKE_DISPUTE_BALANCE_TRANSACTION,
FAKE_DISPUTE_BALANCE_TRANSACTION_REFUND_FULL,
],
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve",
return_value=deepcopy(FAKE_DISPUTE_V_FULL),
autospec=True,
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_DISPUTE_FUNDS_REINSTATED_FULL),
autospec=True,
)
def test_dispute_funds_reinstated_full(
self,
event_retrieve_mock,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_DISPUTE_FUNDS_REINSTATED_FULL)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
dispute = Dispute.objects.get()
self.assertEqual(dispute.id, FAKE_DISPUTE_V_FULL["id"])
tests.test_event_handlers.TestDisputeEvents.test_dispute_funds_reinstated_partial(self, event_retrieve_mock, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
side_effect=[
FAKE_DISPUTE_BALANCE_TRANSACTION,
FAKE_DISPUTE_BALANCE_TRANSACTION_REFUND_PARTIAL,
],
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve",
return_value=deepcopy(FAKE_DISPUTE_V_PARTIAL),
autospec=True,
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_DISPUTE_FUNDS_REINSTATED_PARTIAL),
autospec=True,
)
def test_dispute_funds_reinstated_partial(
self,
event_retrieve_mock,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_DISPUTE_FUNDS_REINSTATED_PARTIAL)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
dispute = Dispute.objects.get()
self.assertGreaterEqual(len(dispute.balance_transactions), 2)
self.assertEqual(dispute.id, FAKE_DISPUTE_V_PARTIAL["id"])
tests.test_event_handlers.TestDisputeEvents.test_dispute_funds_withdrawn(self, event_retrieve_mock, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_DISPUTE_BALANCE_TRANSACTION),
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve", return_value=deepcopy(FAKE_DISPUTE_II), autospec=True
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_DISPUTE_FUNDS_WITHDRAWN),
autospec=True,
)
def test_dispute_funds_withdrawn(
self,
event_retrieve_mock,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_DISPUTE_FUNDS_WITHDRAWN)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
dispute = Dispute.objects.get()
self.assertEqual(dispute.id, FAKE_DISPUTE_II["id"])
tests.test_event_handlers.TestDisputeEvents.test_dispute_updated(self, event_retrieve_mock, dispute_retrieve_mock, file_retrieve_mock, balance_transaction_retrieve_mock, charge_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_DISPUTE_PAYMENT_INTENT),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_DISPUTE_CHARGE),
autospec=True,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_DISPUTE_BALANCE_TRANSACTION),
)
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Dispute.retrieve",
return_value=deepcopy(FAKE_DISPUTE_III),
autospec=True,
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_DISPUTE_UPDATED),
autospec=True,
)
def test_dispute_updated(
self,
event_retrieve_mock,
dispute_retrieve_mock,
file_retrieve_mock,
balance_transaction_retrieve_mock,
charge_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_DISPUTE_UPDATED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
dispute = Dispute.objects.get()
self.assertEqual(dispute.id, FAKE_DISPUTE_III["id"])
tests.test_event_handlers.TestFileEvents
Methods
tests.test_event_handlers.TestFileEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
tests.test_event_handlers.TestFileEvents.test_file_created(self, event_retrieve_mock, file_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.File.retrieve",
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
autospec=True,
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_FILE_CREATED),
autospec=True,
)
def test_file_created(self, event_retrieve_mock, file_retrieve_mock):
fake_stripe_event = deepcopy(FAKE_EVENT_FILE_CREATED)
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
file = File.objects.get()
self.assertEqual(file.id, FAKE_FILEUPLOAD_ICON["id"])
tests.test_event_handlers.TestInvoiceEvents
Methods
tests.test_event_handlers.TestInvoiceEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
tests.test_event_handlers.TestInvoiceEvents.test_invoice_created(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, event_retrieve_mock, invoice_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"djstripe.models.Account.get_default_account",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch("stripe.Invoice.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_created(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
event_retrieve_mock,
invoice_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
FAKE_CUSTOMER.create_for_user(self.user)
fake_stripe_event = deepcopy(FAKE_EVENT_INVOICE_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
invoice_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
invoice = Invoice.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(
invoice.amount_due,
fake_stripe_event["data"]["object"]["amount_due"] / Decimal("100"),
)
self.assertEqual(invoice.paid, fake_stripe_event["data"]["object"]["paid"])
tests.test_event_handlers.TestInvoiceEvents.test_invoice_created_no_existing_customer(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, event_retrieve_mock, invoice_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"djstripe.models.Account.get_default_account",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch("stripe.Event.retrieve", autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_created_no_existing_customer(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
event_retrieve_mock,
invoice_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_INVOICE_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
invoice_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
self.assertEqual(Customer.objects.count(), 1)
customer = Customer.objects.get()
self.assertEqual(customer.subscriber, None)
tests.test_event_handlers.TestInvoiceEvents.test_invoice_deleted(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, invoice_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"djstripe.models.Account.get_default_account",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE), autospec=True
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_deleted(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
invoice_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
FAKE_CUSTOMER.create_for_user(self.user)
event = self._create_event(FAKE_EVENT_INVOICE_CREATED)
event.invoke_webhook_handlers()
Invoice.objects.get(id=FAKE_INVOICE["id"])
event = self._create_event(FAKE_EVENT_INVOICE_DELETED)
event.invoke_webhook_handlers()
with self.assertRaises(Invoice.DoesNotExist):
Invoice.objects.get(id=FAKE_INVOICE["id"])
tests.test_event_handlers.TestInvoiceEvents.test_invoice_upcoming(self)
Source code in tests/test_event_handlers.py
def test_invoice_upcoming(self):
# Ensure that invoice upcoming events are processed - No actual
# process occurs so the operation is an effective no-op.
event = self._create_event(FAKE_EVENT_INVOICE_UPCOMING)
event.invoke_webhook_handlers()
tests.test_event_handlers.TestInvoiceItemEvents
Methods
tests.test_event_handlers.TestInvoiceItemEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
tests.test_event_handlers.TestInvoiceItemEvents.test_invoiceitem_created(self, customer_retrieve_mock, product_retrieve_mock, event_retrieve_mock, invoiceitem_retrieve_mock, invoice_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"djstripe.models.Account.get_default_account",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE_II), autospec=True
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_II),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_II),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE_II), autospec=True
)
@patch("stripe.InvoiceItem.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test_invoiceitem_created(
self,
customer_retrieve_mock,
product_retrieve_mock,
event_retrieve_mock,
invoiceitem_retrieve_mock,
invoice_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_III)
fake_subscription["latest_invoice"] = FAKE_INVOICE_II["id"]
subscription_retrieve_mock.return_value = fake_subscription
fake_card = deepcopy(FAKE_CARD_II)
fake_card["customer"] = None
# create Card for FAKE_CUSTOMER_III
Card.sync_from_stripe_data(fake_card)
# create invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE_II))
FAKE_CUSTOMER_II.create_for_user(self.user)
fake_stripe_event = deepcopy(FAKE_EVENT_INVOICEITEM_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
invoiceitem_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
invoiceitem = InvoiceItem.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
self.assertEqual(
invoiceitem.amount,
fake_stripe_event["data"]["object"]["amount"] / Decimal("100"),
)
tests.test_event_handlers.TestInvoiceItemEvents.test_invoiceitem_deleted(self, customer_retrieve_mock, product_retrieve_mock, invoiceitem_retrieve_mock, invoice_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_event_handlers.py
@patch(
"djstripe.models.Account.get_default_account",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE_II), autospec=True
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_II),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_II),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE_II), autospec=True
)
@patch(
"stripe.InvoiceItem.retrieve",
return_value=deepcopy(FAKE_INVOICEITEM),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test_invoiceitem_deleted(
self,
customer_retrieve_mock,
product_retrieve_mock,
invoiceitem_retrieve_mock,
invoice_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_III)
fake_subscription["latest_invoice"] = FAKE_INVOICE_II["id"]
subscription_retrieve_mock.return_value = fake_subscription
fake_card = deepcopy(FAKE_CARD_II)
fake_card["customer"] = None
# create Card for FAKE_CUSTOMER_III
Card.sync_from_stripe_data(fake_card)
# create invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE_II))
FAKE_CUSTOMER_II.create_for_user(self.user)
event = self._create_event(FAKE_EVENT_INVOICEITEM_CREATED)
event.invoke_webhook_handlers()
InvoiceItem.objects.get(id=FAKE_INVOICEITEM["id"])
event = self._create_event(FAKE_EVENT_INVOICEITEM_DELETED)
event.invoke_webhook_handlers()
with self.assertRaises(InvoiceItem.DoesNotExist):
InvoiceItem.objects.get(id=FAKE_INVOICEITEM["id"])
tests.test_event_handlers.TestPaymentIntentEvents
Test case for payment intent event handling.
Methods
tests.test_event_handlers.TestPaymentIntentEvents.test_payment_intent_succeeded_with_destination_charge(self, customer_retrieve_mock, account_retrieve_mock, file_upload_retrieve_mock, payment_intent_retrieve_mock, payment_method_retrieve_mock)
Test that the payment intent succeeded event can create all related objects.
This should exercise the machinery to set stripe_account
when recursing into
objects related to a connect Account
.
Source code in tests/test_event_handlers.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.File.retrieve",
side_effect=(deepcopy(FAKE_FILEUPLOAD_ICON), deepcopy(FAKE_FILEUPLOAD_LOGO)),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_DESTINATION_CHARGE),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_I),
autospec=True,
)
def test_payment_intent_succeeded_with_destination_charge(
self,
customer_retrieve_mock,
account_retrieve_mock,
file_upload_retrieve_mock,
payment_intent_retrieve_mock,
payment_method_retrieve_mock,
):
"""Test that the payment intent succeeded event can create all related objects.
This should exercise the machinery to set `stripe_account` when recursing into
objects related to a connect `Account`.
"""
event = self._create_event(
FAKE_EVENT_PAYMENT_INTENT_SUCCEEDED_DESTINATION_CHARGE
)
event.invoke_webhook_handlers()
# Make sure the file uploads were retrieved using the account ID.
file_upload_retrieve_mock.assert_has_calls(
(
call(
id=FAKE_FILEUPLOAD_ICON["id"],
api_key=ANY,
expand=ANY,
stripe_account=FAKE_ACCOUNT["id"],
),
call(
id=FAKE_FILEUPLOAD_LOGO["id"],
api_key=ANY,
expand=ANY,
stripe_account=FAKE_ACCOUNT["id"],
),
)
)
tests.test_event_handlers.TestPaymentMethodEvents
Methods
tests.test_event_handlers.TestPaymentMethodEvents.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_event_handlers.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="fake_customer_1", email=FAKE_CUSTOMER["email"]
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
tests.test_event_handlers.TestPaymentMethodEvents.test_card_payment_method_attached(self, event_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.PaymentMethod.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_card_payment_method_attached(
self, event_retrieve_mock, payment_method_retrieve_mock
):
# Attach of a legacy id="card_xxx" payment method should behave exactly
# as per a normal "native" id="pm_yyy" payment_method.
fake_stripe_event = deepcopy(FAKE_EVENT_CARD_PAYMENT_METHOD_ATTACHED)
event_retrieve_mock.return_value = fake_stripe_event
payment_method_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
payment_method = PaymentMethod.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
self.assert_fks(
payment_method,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_event_handlers.TestPaymentMethodEvents.test_card_payment_method_detached(self, event_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.PaymentMethod.retrieve",
side_effect=InvalidRequestError(
message="No such payment_method: card_xxxx",
param="payment_method",
code="resource_missing",
),
autospec=True,
)
@patch("stripe.Event.retrieve", autospec=True)
def test_card_payment_method_detached(
self, event_retrieve_mock, payment_method_retrieve_mock
):
# Detach of a legacy id="card_xxx" payment method is handled specially,
# since the card is deleted by Stripe and therefore PaymetMethod.retrieve fails
fake_stripe_event = deepcopy(FAKE_EVENT_CARD_PAYMENT_METHOD_DETACHED)
event_retrieve_mock.return_value = fake_stripe_event
payment_method_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
self.assertEqual(
PaymentMethod.objects.filter(
id=fake_stripe_event["data"]["object"]["id"]
).count(),
0,
"Detach of a 'card_' payment_method should delete it",
)
tests.test_event_handlers.TestPaymentMethodEvents.test_payment_method_attached(self, event_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.PaymentMethod.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_payment_method_attached(
self, event_retrieve_mock, payment_method_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_PAYMENT_METHOD_ATTACHED)
event_retrieve_mock.return_value = fake_stripe_event
payment_method_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
payment_method = PaymentMethod.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
self.assert_fks(
payment_method,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_event_handlers.TestPaymentMethodEvents.test_payment_method_detached(self, event_retrieve_mock, payment_method_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.PaymentMethod.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_payment_method_detached(
self, event_retrieve_mock, payment_method_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_PAYMENT_METHOD_DETACHED)
event_retrieve_mock.return_value = fake_stripe_event
payment_method_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
payment_method = PaymentMethod.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
self.assertIsNone(
payment_method.customer,
"Detach of a payment_method should set customer to null",
)
self.assert_fks(
payment_method, expected_blank_fks={"djstripe.PaymentMethod.customer"}
)
tests.test_event_handlers.TestPlanEvents
tests.test_event_handlers.TestPlanEvents.test_plan_created(self, product_retrieve_mock, event_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Plan.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_plan_created(
self, product_retrieve_mock, event_retrieve_mock, plan_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_PLAN_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
plan_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
plan = Plan.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(plan.nickname, fake_stripe_event["data"]["object"]["nickname"])
tests.test_event_handlers.TestPlanEvents.test_plan_deleted(self, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Plan.retrieve", return_value=FAKE_PLAN, autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_plan_deleted(self, product_retrieve_mock, plan_retrieve_mock):
event = self._create_event(FAKE_EVENT_PLAN_CREATED)
event.invoke_webhook_handlers()
Plan.objects.get(id=FAKE_PLAN["id"])
event = self._create_event(FAKE_EVENT_PLAN_DELETED)
event.invoke_webhook_handlers()
with self.assertRaises(Plan.DoesNotExist):
Plan.objects.get(id=FAKE_PLAN["id"])
tests.test_event_handlers.TestPlanEvents.test_plan_updated_request_object(self, product_retrieve_mock, event_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Plan.retrieve", return_value=FAKE_PLAN, autospec=True)
@patch(
"stripe.Event.retrieve",
return_value=FAKE_EVENT_PLAN_REQUEST_IS_OBJECT,
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_plan_updated_request_object(
self, product_retrieve_mock, event_retrieve_mock, plan_retrieve_mock
):
plan_retrieve_mock.return_value = FAKE_EVENT_PLAN_REQUEST_IS_OBJECT["data"][
"object"
]
event = Event.sync_from_stripe_data(FAKE_EVENT_PLAN_REQUEST_IS_OBJECT)
event.invoke_webhook_handlers()
plan = Plan.objects.get(
id=FAKE_EVENT_PLAN_REQUEST_IS_OBJECT["data"]["object"]["id"]
)
self.assertEqual(
plan.nickname,
FAKE_EVENT_PLAN_REQUEST_IS_OBJECT["data"]["object"]["nickname"],
)
tests.test_event_handlers.TestPriceEvents
tests.test_event_handlers.TestPriceEvents.test_price_created(self, product_retrieve_mock, event_retrieve_mock, price_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Price.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_price_created(
self, product_retrieve_mock, event_retrieve_mock, price_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_PRICE_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
price_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
price = Price.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(
price.nickname, fake_stripe_event["data"]["object"]["nickname"]
)
tests.test_event_handlers.TestPriceEvents.test_price_deleted(self, product_retrieve_mock, price_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Price.retrieve", return_value=FAKE_PRICE, autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_price_deleted(self, product_retrieve_mock, price_retrieve_mock):
event = self._create_event(FAKE_EVENT_PRICE_CREATED)
event.invoke_webhook_handlers()
Price.objects.get(id=FAKE_PRICE["id"])
event = self._create_event(FAKE_EVENT_PRICE_DELETED)
event.invoke_webhook_handlers()
with self.assertRaises(Price.DoesNotExist):
Price.objects.get(id=FAKE_PRICE["id"])
tests.test_event_handlers.TestPriceEvents.test_price_updated(self, product_retrieve_mock, event_retrieve_mock, price_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.Price.retrieve", return_value=FAKE_PRICE, autospec=True)
@patch(
"stripe.Event.retrieve", return_value=FAKE_EVENT_PRICE_UPDATED, autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_price_updated(
self, product_retrieve_mock, event_retrieve_mock, price_retrieve_mock
):
price_retrieve_mock.return_value = FAKE_EVENT_PRICE_UPDATED["data"]["object"]
event = Event.sync_from_stripe_data(FAKE_EVENT_PRICE_UPDATED)
event.invoke_webhook_handlers()
price = Price.objects.get(id=FAKE_EVENT_PRICE_UPDATED["data"]["object"]["id"])
self.assertEqual(
price.unit_amount,
FAKE_EVENT_PRICE_UPDATED["data"]["object"]["unit_amount"],
)
self.assertEqual(
price.unit_amount_decimal,
Decimal(FAKE_EVENT_PRICE_UPDATED["data"]["object"]["unit_amount_decimal"]),
)
tests.test_event_handlers.TestSubscriptionScheduleEvents
tests.test_event_handlers.TestSubscriptionScheduleEvents.test_subscription_schedule_canceled(self, customer_retrieve_mock, schedule_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.SubscriptionSchedule.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test_subscription_schedule_canceled(
self, customer_retrieve_mock, schedule_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_SUBSCRIPTION_SCHEDULE_UPDATED)
fake_stripe_event["data"]["object"]["canceled_at"] = 1605058030
fake_stripe_event["data"]["object"]["status"] = "canceled"
fake_stripe_event["data"]["previous_attributes"] = {
"canceled_at": None,
"status": "not_started",
}
schedule_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
schedule = SubscriptionSchedule.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
assert schedule.status == "canceled"
assert schedule.canceled_at is not None
schedule_retrieve_mock.return_value = FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CANCELED[
"data"
]["object"]
event = Event.sync_from_stripe_data(FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CANCELED)
event.invoke_webhook_handlers()
schedule.refresh_from_db()
assert schedule.status == "canceled"
assert schedule.canceled_at is not None
tests.test_event_handlers.TestSubscriptionScheduleEvents.test_subscription_schedule_created(self, customer_retrieve_mock, schedule_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.SubscriptionSchedule.retrieve",
return_value=FAKE_SUBSCRIPTION_SCHEDULE,
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test_subscription_schedule_created(
self, customer_retrieve_mock, schedule_retrieve_mock
):
event = Event.sync_from_stripe_data(FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CREATED)
event.invoke_webhook_handlers()
schedule = SubscriptionSchedule.objects.get(
id=FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CREATED["data"]["object"]["id"]
)
assert (
schedule.id
== FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CREATED["data"]["object"]["id"]
)
assert schedule.status == "not_started"
tests.test_event_handlers.TestSubscriptionScheduleEvents.test_subscription_schedule_released(self, customer_retrieve_mock, schedule_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.SubscriptionSchedule.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test_subscription_schedule_released(
self, customer_retrieve_mock, schedule_retrieve_mock
):
fake_stripe_event = deepcopy(FAKE_EVENT_SUBSCRIPTION_SCHEDULE_UPDATED)
fake_stripe_event["data"]["object"]["released_at"] = 1605058030
fake_stripe_event["data"]["object"]["status"] = "released"
fake_stripe_event["data"]["previous_attributes"] = {
"released_at": None,
"status": "not_started",
}
schedule_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
schedule = SubscriptionSchedule.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
assert schedule.status == "released"
assert schedule.released_at is not None
schedule_retrieve_mock.return_value = FAKE_EVENT_SUBSCRIPTION_SCHEDULE_RELEASED[
"data"
]["object"]
event = Event.sync_from_stripe_data(FAKE_EVENT_SUBSCRIPTION_SCHEDULE_RELEASED)
event.invoke_webhook_handlers()
schedule.refresh_from_db()
assert schedule.status == "released"
assert schedule.released_at is not None
tests.test_event_handlers.TestSubscriptionScheduleEvents.test_subscription_schedule_updated(self, customer_retrieve_mock, schedule_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch("stripe.SubscriptionSchedule.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test_subscription_schedule_updated(
self, customer_retrieve_mock, schedule_retrieve_mock
):
schedule_retrieve_mock.return_value = FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CREATED[
"data"
]["object"]
event = Event.sync_from_stripe_data(FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CREATED)
event.invoke_webhook_handlers()
schedule = SubscriptionSchedule.objects.get(
id=FAKE_EVENT_SUBSCRIPTION_SCHEDULE_CREATED["data"]["object"]["id"]
)
assert schedule.status == "not_started"
assert schedule.released_at is None
fake_stripe_event = deepcopy(FAKE_EVENT_SUBSCRIPTION_SCHEDULE_UPDATED)
fake_stripe_event["data"]["object"]["released_at"] = 1605058030
fake_stripe_event["data"]["object"]["status"] = "released"
fake_stripe_event["data"]["previous_attributes"] = {
"released_at": None,
"status": "not_started",
}
schedule_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
schedule = SubscriptionSchedule.objects.get(
id=fake_stripe_event["data"]["object"]["id"]
)
assert schedule.status == "released"
assert schedule.released_at is not None
tests.test_event_handlers.TestTaxIdEvents
tests.test_event_handlers.TestTaxIdEvents.test_tax_id_created(self, event_retrieve_mock, tax_id_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_tax_id",
return_value=deepcopy(FAKE_TAX_ID),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_TAX_ID_CREATED),
autospec=True,
)
def test_tax_id_created(
self, event_retrieve_mock, tax_id_retrieve_mock, customer_retrieve_mock
):
event = Event.sync_from_stripe_data(FAKE_EVENT_TAX_ID_CREATED)
event.invoke_webhook_handlers()
tax_id = TaxId.objects.get()
self.assertEqual(tax_id.id, FAKE_TAX_ID["id"])
tests.test_event_handlers.TestTaxIdEvents.test_tax_id_deleted(self, event_retrieve_mock, tax_id_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_tax_id",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Event.retrieve",
autospec=True,
)
def test_tax_id_deleted(
self, event_retrieve_mock, tax_id_retrieve_mock, customer_retrieve_mock
):
tax_id_retrieve_mock.return_value = FAKE_TAX_ID
fake_stripe_create_event = deepcopy(FAKE_EVENT_TAX_ID_CREATED)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
tax_id_retrieve_mock.return_value = FAKE_EVENT_TAX_ID_DELETED
fake_stripe_delete_event = deepcopy(FAKE_EVENT_TAX_ID_DELETED)
event = Event.sync_from_stripe_data(fake_stripe_delete_event)
event.invoke_webhook_handlers()
self.assertFalse(TaxId.objects.filter(id=FAKE_TAX_ID["id"]).exists())
tests.test_event_handlers.TestTaxIdEvents.test_tax_id_updated(self, event_retrieve_mock, tax_id_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_event_handlers.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_tax_id",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Event.retrieve",
autospec=True,
)
def test_tax_id_updated(
self, event_retrieve_mock, tax_id_retrieve_mock, customer_retrieve_mock
):
tax_id_retrieve_mock.return_value = FAKE_TAX_ID
fake_stripe_create_event = deepcopy(FAKE_EVENT_TAX_ID_CREATED)
event = Event.sync_from_stripe_data(fake_stripe_create_event)
event.invoke_webhook_handlers()
tax_id_retrieve_mock.return_value = FAKE_TAX_ID_UPDATED
fake_stripe_update_event = deepcopy(FAKE_EVENT_TAX_ID_UPDATED)
event = Event.sync_from_stripe_data(fake_stripe_update_event)
event.invoke_webhook_handlers()
tax_id = TaxId.objects.get()
self.assertEqual(tax_id.id, FAKE_TAX_ID["id"])
self.assertEqual(tax_id.verification.get("status"), "verified")
self.assertEqual(tax_id.verification.get("verified_name"), "Test")
tests.test_event_handlers.TestTransferEvents
tests.test_event_handlers.TestTransferEvents.test_transfer_created(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_event_handlers.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Transfer.retrieve", autospec=True)
@patch("stripe.Event.retrieve", autospec=True)
def test_transfer_created(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
fake_stripe_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
event_retrieve_mock.return_value = fake_stripe_event
transfer_retrieve_mock.return_value = fake_stripe_event["data"]["object"]
event = Event.sync_from_stripe_data(fake_stripe_event)
event.invoke_webhook_handlers()
transfer = Transfer.objects.get(id=fake_stripe_event["data"]["object"]["id"])
self.assertEqual(
transfer.amount,
fake_stripe_event["data"]["object"]["amount"] / Decimal("100"),
)
tests.test_event_handlers.TestTransferEvents.test_transfer_deleted(self, transfer_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_event_handlers.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Transfer.retrieve", return_value=FAKE_TRANSFER, autospec=True)
def test_transfer_deleted(
self,
transfer_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
event = self._create_event(FAKE_EVENT_TRANSFER_CREATED)
event.invoke_webhook_handlers()
Transfer.objects.get(id=FAKE_TRANSFER["id"])
event = self._create_event(FAKE_EVENT_TRANSFER_DELETED)
event.invoke_webhook_handlers()
with self.assertRaises(Transfer.DoesNotExist):
Transfer.objects.get(id=FAKE_TRANSFER["id"])
event = self._create_event(FAKE_EVENT_TRANSFER_DELETED)
event.invoke_webhook_handlers()
tests.test_fields
dj-stripe Custom Field Tests.
tests.test_fields.pytestmark
tests.test_fields.TestStripeDateTimeField
tests.test_fields.TestStripeDateTimeField.noval
tests.test_fields.TestStripeDateTimeField.test_stripe_to_db_datetime_val(self)
Source code in tests/test_fields.py
def test_stripe_to_db_datetime_val(self):
self.assertEqual(
datetime(1997, 9, 18, 7, 48, 35, tzinfo=timezone.utc),
self.noval.stripe_to_db({"noval": 874568915}),
)
tests.test_fields.TestStripeDateTimeField.test_stripe_to_db_none_val(self)
Source code in tests/test_fields.py
def test_stripe_to_db_none_val(self):
self.assertEqual(None, self.noval.stripe_to_db({"noval": None}))
tests.test_fields.TestStripeDecimalCurrencyAmountField
tests.test_fields.TestStripeDecimalCurrencyAmountField.noval
tests.test_fields.TestStripeDecimalCurrencyAmountField.test_stripe_to_db_decimal_val(self, expected, inputted)
Source code in tests/test_fields.py
@pytest.mark.parametrize(
"expected,inputted",
[
(Decimal("1"), Decimal("100")),
(Decimal("1.5"), Decimal("150")),
(Decimal("0"), Decimal("0")),
],
)
def test_stripe_to_db_decimal_val(self, expected, inputted):
assert expected == self.noval.stripe_to_db({"noval": inputted})
tests.test_fields.TestStripeDecimalCurrencyAmountField.test_stripe_to_db_none_val(self)
Source code in tests/test_fields.py
def test_stripe_to_db_none_val(self):
assert self.noval.stripe_to_db({"noval": None}) is None
tests.test_fields.TestStripePercentField
tests.test_fields.TestStripePercentField.test_stripe_percent_field(self, inputted, expected)
Source code in tests/test_fields.py
@pytest.mark.parametrize(
"inputted,expected",
[
(Decimal("1"), Decimal("1.00")),
(Decimal("1.5234567"), Decimal("1.52")),
(Decimal("0"), Decimal("0.00")),
(Decimal("23.2345678"), Decimal("23.23")),
("1", Decimal("1.00")),
("1.5234567", Decimal("1.52")),
("0", Decimal("0.00")),
("23.2345678", Decimal("23.23")),
(1, Decimal("1.00")),
(1.5234567, Decimal("1.52")),
(0, Decimal("0.00")),
(23.2345678, Decimal("23.24")),
],
)
def test_stripe_percent_field(self, inputted, expected):
# create a model with the StripePercentField
model_field = TestDecimalModel(noval=inputted)
model_field.save()
# get the field data
field_data = TestDecimalModel.objects.get(pk=model_field.pk).noval
assert isinstance(field_data, Decimal)
assert field_data == expected
tests.test_file_link
dj-stripe FileLink model tests
tests.test_file_link.pytestmark
tests.test_file_link.TestFileLink
tests.test_file_link.TestFileLink.test___str__(self, mock_file_link_retrieve, mock_file_upload_retrieve)
Source code in tests/test_file_link.py
@patch(
target="stripe.File.retrieve",
autospec=True,
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
)
@patch(
target="stripe.FileLink.retrieve",
autospec=True,
return_value=deepcopy(FAKE_FILEUPLOAD_ICON["links"]["data"][0]),
)
def test___str__(self, mock_file_link_retrieve, mock_file_upload_retrieve):
file_link_data = deepcopy(FAKE_FILEUPLOAD_ICON["links"]["data"][0])
file_link = FileLink.sync_from_stripe_data(file_link_data)
assert (f"{FAKE_FILEUPLOAD_ICON['filename']}, {file_link_data['url']}") == str(
file_link
)
tests.test_file_link.TestFileLink.test_sync_from_stripe_data(self, mock_file_link_retrieve, mock_file_upload_retrieve)
Source code in tests/test_file_link.py
@patch(
target="stripe.File.retrieve",
autospec=True,
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
)
@patch(
target="stripe.FileLink.retrieve",
autospec=True,
return_value=deepcopy(FAKE_FILEUPLOAD_ICON["links"]["data"][0]),
)
def test_sync_from_stripe_data(
self, mock_file_link_retrieve, mock_file_upload_retrieve
):
file_link_data = deepcopy(FAKE_FILEUPLOAD_ICON["links"]["data"][0])
file_link = FileLink.sync_from_stripe_data(file_link_data)
mock_file_link_retrieve.assert_not_called()
mock_file_upload_retrieve.assert_called_once_with(
id=file_link_data["file"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
stripe_account=None,
)
assert file_link.file == File.objects.get(id=file_link_data["file"])
assert file_link.url == file_link_data["url"]
tests.test_file_upload
dj-stripe File model tests
tests.test_file_upload.pytestmark
Classes
tests.test_file_upload.TestFileLink
Methods
tests.test_file_upload.TestFileLink.test_file_upload_api_retrieve(self, mock_file_upload_retrieve)
Expect file_upload to use the ID of the account referring to it to retrieve itself.
Source code in tests/test_file_upload.py
@patch(
target="stripe.File.retrieve",
autospec=True,
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
)
def test_file_upload_api_retrieve(self, mock_file_upload_retrieve):
"""Expect file_upload to use the ID of the account referring
to it to retrieve itself.
"""
# Create files
icon_file = File._get_or_create_from_stripe_object(data=FAKE_FILEUPLOAD_ICON)[0]
logo_file = File._get_or_create_from_stripe_object(data=FAKE_FILEUPLOAD_LOGO)[0]
# Create account to associate the files to it
account = Account._get_or_create_from_stripe_object(data=FAKE_ACCOUNT)[0]
# Call the API retrieve methods.
icon_file.api_retrieve()
logo_file.api_retrieve()
# Ensure the correct Account ID was used in retrieval
mock_file_upload_retrieve.assert_has_calls(
(
call(
id=icon_file.id, api_key=ANY, expand=ANY, stripe_account=account.id
),
call(
id=logo_file.id, api_key=ANY, expand=ANY, stripe_account=account.id
),
)
)
tests.test_file_upload.TestFileLink.test_sync_from_stripe_data(self, mock_file_upload_retrieve)
Source code in tests/test_file_upload.py
@patch(
target="stripe.File.retrieve",
autospec=True,
return_value=deepcopy(FAKE_FILEUPLOAD_ICON),
)
def test_sync_from_stripe_data(self, mock_file_upload_retrieve):
file = File.sync_from_stripe_data(deepcopy(FAKE_FILEUPLOAD_ICON))
mock_file_upload_retrieve.assert_not_called()
assert file.id == FAKE_FILEUPLOAD_ICON["id"]
assert file.purpose == FAKE_FILEUPLOAD_ICON["purpose"]
assert file.type == FAKE_FILEUPLOAD_ICON["type"]
tests.test_file_upload.TestFileUploadStr
tests.test_file_upload.TestFileUploadStr.test___str__(self, file_purpose)
Source code in tests/test_file_upload.py
@pytest.mark.parametrize("file_purpose", FilePurpose.__members__)
def test___str__(self, file_purpose):
modified_file_data = deepcopy(FAKE_FILEUPLOAD_ICON)
modified_file_data["purpose"] = file_purpose
file = File.sync_from_stripe_data(modified_file_data)
assert (
f"{modified_file_data['filename']}, {FilePurpose.humanize(modified_file_data['purpose'])}"
) == str(file)
tests.test_idempotency_keys
tests.test_idempotency_keys.IdempotencyKeyTest
tests.test_idempotency_keys.IdempotencyKeyTest.test_clear_expired_idempotency_keys(self)
Source code in tests/test_idempotency_keys.py
def test_clear_expired_idempotency_keys(self):
expired_key = djstripe_settings.get_idempotency_key(
"customer", "create:1", False
)
expired_key_obj = IdempotencyKey.objects.get(uuid=expired_key)
expired_key_obj.created = now() - timedelta(hours=25)
expired_key_obj.save()
valid_key = djstripe_settings.get_idempotency_key("customer", "create:2", False)
self.assertEqual(IdempotencyKey.objects.count(), 2)
clear_expired_idempotency_keys()
self.assertEqual(IdempotencyKey.objects.count(), 1)
self.assertEqual(str(IdempotencyKey.objects.get().uuid), valid_key)
tests.test_idempotency_keys.IdempotencyKeyTest.test_generate_idempotency_key(self)
Source code in tests/test_idempotency_keys.py
def test_generate_idempotency_key(self):
key1 = djstripe_settings.get_idempotency_key("customer", "create:1", False)
key2 = djstripe_settings.get_idempotency_key("customer", "create:1", False)
self.assertTrue(key1 == key2)
key3 = djstripe_settings.get_idempotency_key("customer", "create:2", False)
self.assertTrue(key1 != key3)
key4 = djstripe_settings.get_idempotency_key("charge", "create:1", False)
self.assertTrue(key1 != key4)
self.assertEqual(IdempotencyKey.objects.count(), 3)
key1_obj = IdempotencyKey.objects.get(
action="customer:create:1", livemode=False
)
self.assertFalse(key1_obj.is_expired)
self.assertEqual(str(key1_obj), str(key1_obj.uuid))
tests.test_integrations
special
tests.test_invoice
dj-stripe Invoice Model Tests.
tests.test_invoice.pytestmark
Classes
tests.test_invoice.InvoiceTest
Methods
tests.test_invoice.InvoiceTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_invoice.py
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(user)
self.default_expected_blank_fks = {
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
}
tests.test_invoice.InvoiceTest.test_billing_reason_enum(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_billing_reason_enum(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_invoice = deepcopy(FAKE_INVOICE)
for billing_reason in (
"subscription_cycle",
"subscription_create",
"subscription_update",
"subscription",
"manual",
"upcoming",
"subscription_threshold",
):
fake_invoice["billing_reason"] = billing_reason
invoice = Invoice.sync_from_stripe_data(fake_invoice)
self.assertEqual(invoice.billing_reason, billing_reason)
# trigger model field validation (including enum value choices check)
invoice.full_clean()
tests.test_invoice.InvoiceTest.test_invoice_plan_from_invoice_items(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_plan_from_invoice_items(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertIsNotNone(invoice.plan) # retrieved from invoice item
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_invoice_plan_from_subscription(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_plan_from_subscription(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data["lines"]["data"][0]["plan"] = None
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertIsNotNone(invoice.plan) # retrieved from subscription
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_invoice_status_enum(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_status_enum(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_invoice = deepcopy(FAKE_INVOICE)
for status in (
"draft",
"open",
"paid",
"uncollectible",
"void",
):
fake_invoice["status"] = status
invoice = Invoice.sync_from_stripe_data(fake_invoice)
self.assertEqual(invoice.status, status)
# trigger model field validation (including enum value choices check)
invoice.full_clean()
tests.test_invoice.InvoiceTest.test_invoice_with_no_invoice_items(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_with_no_invoice_items(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data["lines"] = []
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertIsNotNone(invoice.plan) # retrieved from invoice item
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_invoice_with_non_subscription_invoice_items(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_with_non_subscription_invoice_items(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data["lines"]["data"].append(deepcopy(FAKE_INVOICEITEM_II))
invoice_data["lines"]["total_count"] += 1
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertIsNotNone(invoice)
self.assertEqual(2, len(invoice.invoiceitems.all()))
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_invoice_with_subscription_invoice_items(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_with_subscription_invoice_items(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice = Invoice.sync_from_stripe_data(invoice_data)
items = invoice.invoiceitems.all()
self.assertEqual(1, len(items))
# Previously the test asserted item_id="{invoice_id}-{subscription_id}",
# but this doesn't match what I'm seeing from Stripe
# I'm not sure if it's possible to predict the whole item id now,
# sli seems to not reference anything
item_id_prefix = "{invoice_id}-il_".format(invoice_id=invoice.id)
self.assertTrue(items[0].id.startswith(item_id_prefix))
self.assertEqual(items[0].subscription.id, FAKE_SUBSCRIPTION["id"])
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_invoice_without_plan(self, product_retrieve_mock, charge_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Subscription.retrieve", autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_invoice_without_plan(
self,
product_retrieve_mock,
charge_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data["lines"]["data"][0]["plan"] = None
invoice_data["lines"]["data"][0]["subscription"] = None
invoice_data["subscription"] = None
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertIsNone(invoice.plan)
self.assert_fks(
invoice,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.Invoice.subscription"},
)
tests.test_invoice.InvoiceTest.test_no_upcoming_invoices(self, invoice_upcoming_mock)
Source code in tests/test_invoice.py
@patch(
"stripe.Invoice.upcoming",
side_effect=InvalidRequestError("Nothing to invoice for customer", None),
)
def test_no_upcoming_invoices(self, invoice_upcoming_mock):
invoice = Invoice.upcoming()
self.assertIsNone(invoice)
tests.test_invoice.InvoiceTest.test_retry_false(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock, invoice_retrieve_mock)
Source code in tests/test_invoice.py
@patch("stripe.Invoice.retrieve", autospec=True)
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_retry_false(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
invoice_retrieve_mock,
):
default_account_mock.return_value = self.account
fake_invoice = deepcopy(FAKE_INVOICE)
invoice_retrieve_mock.return_value = fake_invoice
invoice = Invoice.sync_from_stripe_data(fake_invoice)
return_value = invoice.retry()
self.assertFalse(invoice_retrieve_mock.called)
self.assertFalse(return_value)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_retry_true(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock, invoice_retrieve_mock)
Source code in tests/test_invoice.py
@patch("stripe.Invoice.retrieve", autospec=True)
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_retry_true(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
invoice_retrieve_mock,
):
default_account_mock.return_value = self.account
fake_invoice = deepcopy(FAKE_INVOICE)
fake_invoice.update({"paid": False, "status": "open"})
fake_invoice.update({"auto_advance": True})
invoice_retrieve_mock.return_value = fake_invoice
invoice = Invoice.sync_from_stripe_data(fake_invoice)
return_value = invoice.retry()
invoice_retrieve_mock.assert_called_once_with(
id=invoice.id,
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
stripe_account=invoice.djstripe_owner_account.id,
)
self.assertTrue(return_value)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_status_draft(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_status_draft(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data.update({"paid": False, "status": "draft"})
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertEqual(InvoiceStatus.draft, invoice.status)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_status_open(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_status_open(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data.update({"paid": False, "status": "open"})
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertEqual(InvoiceStatus.open, invoice.status)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_status_paid(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_status_paid(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice = Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
self.assertEqual(InvoiceStatus.paid, invoice.status)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_status_uncollectible(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_status_uncollectible(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data.update({"paid": False, "status": "uncollectible"})
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertEqual(InvoiceStatus.uncollectible, invoice.status)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_status_void(self, product_retrieve_mock, paymentmethod_card_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_status_void(
self,
product_retrieve_mock,
paymentmethod_card_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data.update({"paid": False, "status": "void"})
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertEqual(InvoiceStatus.void, invoice.status)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_sync_from_stripe_data(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_sync_from_stripe_data(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice = Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
self.assertEqual(
invoice.get_stripe_dashboard_url(), self.customer.get_stripe_dashboard_url()
)
self.assertEqual(str(invoice), "Invoice #{}".format(FAKE_INVOICE["number"]))
self.assertGreater(len(invoice.status_transitions.keys()), 1)
self.assertTrue(bool(invoice.account_country))
self.assertTrue(bool(invoice.account_name))
self.assertTrue(bool(invoice.collection_method))
self.assertEqual(invoice.default_tax_rates.count(), 1)
self.assertEqual(
invoice.default_tax_rates.first().id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
self.assertEqual(invoice.total_tax_amounts.count(), 1)
first_tax_amount = invoice.total_tax_amounts.first()
self.assertEqual(
first_tax_amount.tax_rate.id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
self.assertEqual(
first_tax_amount.inclusive, FAKE_TAX_RATE_EXAMPLE_1_VAT["inclusive"]
)
self.assertEqual(first_tax_amount.amount, 261)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
tests.test_invoice.InvoiceTest.test_sync_from_stripe_data_default_payment_method(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_sync_from_stripe_data_default_payment_method(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
fake_invoice = deepcopy(FAKE_INVOICE)
fake_invoice["default_payment_method"] = deepcopy(FAKE_CARD_AS_PAYMENT_METHOD)
invoice = Invoice.sync_from_stripe_data(fake_invoice)
self.assertEqual(
invoice.default_payment_method.id, FAKE_CARD_AS_PAYMENT_METHOD["id"]
)
self.assert_fks(
invoice,
expected_blank_fks=self.default_expected_blank_fks
- {"djstripe.Invoice.default_payment_method"},
)
tests.test_invoice.InvoiceTest.test_sync_from_stripe_data_update_total_tax_amounts(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_sync_from_stripe_data_update_total_tax_amounts(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice = Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
# as per basic sync test
self.assertEqual(invoice.default_tax_rates.count(), 1)
self.assertEqual(
invoice.default_tax_rates.first().id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
self.assertEqual(invoice.total_tax_amounts.count(), 1)
first_tax_amount = invoice.total_tax_amounts.first()
self.assertEqual(
first_tax_amount.tax_rate.id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
self.assertEqual(
first_tax_amount.inclusive, FAKE_TAX_RATE_EXAMPLE_1_VAT["inclusive"]
)
self.assertEqual(first_tax_amount.amount, 261)
self.assert_fks(invoice, expected_blank_fks=self.default_expected_blank_fks)
# Now update with a different tax rate
# TODO - should update tax rate in invoice items etc as well,
# but here we're mainly testing that invoice.total_tax_rates is
# correctly updated
fake_updated_invoice = deepcopy(FAKE_INVOICE)
fake_tax_rate_2 = deepcopy(FAKE_TAX_RATE_EXAMPLE_2_SALES)
new_tax_amount = int(
fake_updated_invoice["total"] * fake_tax_rate_2["percentage"] / 100
)
fake_updated_invoice.update(
{
"default_tax_rates": [fake_tax_rate_2],
"tax": new_tax_amount,
"total": fake_updated_invoice["total"] + new_tax_amount,
"total_tax_amounts": [
{
"amount": new_tax_amount,
"inclusive": False,
"tax_rate": fake_tax_rate_2["id"],
}
],
}
)
invoice_updated = Invoice.sync_from_stripe_data(fake_updated_invoice)
self.assertEqual(invoice_updated.default_tax_rates.count(), 1)
self.assertEqual(
invoice_updated.default_tax_rates.first().id, fake_tax_rate_2["id"]
)
self.assertEqual(invoice_updated.total_tax_amounts.count(), 1)
first_tax_amount = invoice_updated.total_tax_amounts.first()
self.assertEqual(first_tax_amount.tax_rate.id, fake_tax_rate_2["id"])
self.assertEqual(first_tax_amount.inclusive, fake_tax_rate_2["inclusive"])
self.assertEqual(first_tax_amount.amount, new_tax_amount)
self.assert_fks(
invoice_updated, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_invoice.InvoiceTest.test_sync_no_subscription(self, product_retrieve_mock, payment_intent_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, plan_retrieve_mock, paymentmethod_card_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoice.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.Plan.retrieve",
return_value=deepcopy(FAKE_PLAN),
autospec=True,
)
@patch("stripe.Subscription.retrieve", autospec=True)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_sync_no_subscription(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
plan_retrieve_mock,
paymentmethod_card_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoice_data = deepcopy(FAKE_INVOICE)
invoice_data.update({"subscription": None})
invoice_data["lines"]["data"][0]["subscription"] = None
invoice = Invoice.sync_from_stripe_data(invoice_data)
self.assertEqual(None, invoice.subscription)
self.assertEqual(FAKE_CHARGE["id"], invoice.charge.id)
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
# charge_retrieve_mock.assert_not_called()
plan_retrieve_mock.assert_not_called()
subscription_retrieve_mock.assert_not_called()
self.assert_fks(
invoice,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.Invoice.subscription"},
)
tests.test_invoice.InvoiceTest.test_upcoming_invoice(self, product_retrieve_mock, invoice_upcoming_mock, subscription_retrieve_mock, plan_retrieve_mock, invoice_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_invoice.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", autospec=True, return_value=deepcopy(FAKE_INVOICE)
)
@patch(
"stripe.Plan.retrieve",
return_value=deepcopy(FAKE_PLAN),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Invoice.upcoming",
return_value=deepcopy(FAKE_UPCOMING_INVOICE),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_upcoming_invoice(
self,
product_retrieve_mock,
invoice_upcoming_mock,
subscription_retrieve_mock,
plan_retrieve_mock,
invoice_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
# create invoice for latest_invoice in subscription to work.
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
invoice = UpcomingInvoice.upcoming()
self.assertIsNotNone(invoice)
self.assertIsNone(invoice.id)
self.assertIsNone(invoice.save())
self.assertEqual(invoice.get_stripe_dashboard_url(), "")
invoice.id = "foo"
self.assertIsNone(invoice.id)
subscription_retrieve_mock.assert_called_once_with(
api_key=ANY, expand=ANY, id=FAKE_SUBSCRIPTION["id"], stripe_account=None
)
plan_retrieve_mock.assert_not_called()
items = invoice.invoiceitems.all()
self.assertEqual(1, len(items))
self.assertEqual(FAKE_SUBSCRIPTION["id"], items[0].id)
# delete/update should do nothing
self.assertEqual(invoice.invoiceitems.update(), 0)
self.assertEqual(invoice.invoiceitems.delete(), 0)
self.assertIsNotNone(invoice.plan)
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
invoice._invoiceitems = []
items = invoice.invoiceitems.all()
self.assertEqual(0, len(items))
self.assertIsNotNone(invoice.plan)
self.assertEqual(invoice.default_tax_rates.count(), 1)
self.assertEqual(
invoice.default_tax_rates.first().id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
self.assertEqual(invoice.total_tax_amounts.count(), 1)
first_tax_amount = invoice.total_tax_amounts.first()
self.assertEqual(
first_tax_amount.tax_rate.id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
self.assertEqual(
first_tax_amount.inclusive, FAKE_TAX_RATE_EXAMPLE_1_VAT["inclusive"]
)
self.assertEqual(first_tax_amount.amount, 261)
tests.test_invoice.InvoiceTest.test_upcoming_invoice_error(self, invoice_upcoming_mock)
Source code in tests/test_invoice.py
@patch(
"stripe.Invoice.upcoming",
side_effect=InvalidRequestError("Some other error", None),
)
def test_upcoming_invoice_error(self, invoice_upcoming_mock):
with self.assertRaises(InvalidRequestError):
Invoice.upcoming()
tests.test_invoice.InvoiceTest.test_upcoming_invoice_with_subscription(self, invoice_upcoming_mock, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, invoice_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_invoice.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", autospec=True, return_value=deepcopy(FAKE_INVOICE)
)
@patch("stripe.Plan.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Invoice.upcoming",
return_value=deepcopy(FAKE_UPCOMING_INVOICE),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_upcoming_invoice_with_subscription(
self,
invoice_upcoming_mock,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
invoice_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
# create invoice for latest_invoice in subscription to work.
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
invoice = Invoice.upcoming(
subscription=Subscription(id=FAKE_SUBSCRIPTION["id"])
)
self.assertIsNotNone(invoice)
self.assertIsNone(invoice.id)
self.assertIsNone(invoice.save())
subscription_retrieve_mock.assert_called_once_with(
api_key=ANY, expand=ANY, id=FAKE_SUBSCRIPTION["id"], stripe_account=None
)
plan_retrieve_mock.assert_not_called()
self.assertIsNotNone(invoice.plan)
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
tests.test_invoice.InvoiceTest.test_upcoming_invoice_with_subscription_plan(self, product_retrieve_mock, invoice_upcoming_mock, subscription_retrieve_mock, plan_retrieve_mock, invoice_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_invoice.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", autospec=True, return_value=deepcopy(FAKE_INVOICE)
)
@patch("stripe.Plan.retrieve", autospec=True)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Invoice.upcoming",
return_value=deepcopy(FAKE_UPCOMING_INVOICE),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_upcoming_invoice_with_subscription_plan(
self,
product_retrieve_mock,
invoice_upcoming_mock,
subscription_retrieve_mock,
plan_retrieve_mock,
invoice_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
# create invoice for latest_invoice in subscription to work.
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
invoice = Invoice.upcoming(subscription_plan=Plan(id=FAKE_PLAN["id"]))
self.assertIsNotNone(invoice)
self.assertIsNone(invoice.id)
self.assertIsNone(invoice.save())
subscription_retrieve_mock.assert_called_once_with(
api_key=ANY, expand=ANY, id=FAKE_SUBSCRIPTION["id"], stripe_account=None
)
plan_retrieve_mock.assert_not_called()
self.assertIsNotNone(invoice.plan)
self.assertEqual(FAKE_PLAN["id"], invoice.plan.id)
tests.test_invoice.TestInvoiceDecimal
tests.test_invoice.TestInvoiceDecimal.test_decimal_tax_percent(self, inputted, expected, monkeypatch)
Source code in tests/test_invoice.py
@pytest.mark.parametrize(
"inputted,expected",
[
(Decimal("1"), Decimal("1.00")),
(Decimal("1.5234567"), Decimal("1.52")),
(Decimal("0"), Decimal("0.00")),
(Decimal("23.2345678"), Decimal("23.23")),
("1", Decimal("1.00")),
("1.5234567", Decimal("1.52")),
("0", Decimal("0.00")),
("23.2345678", Decimal("23.23")),
(1, Decimal("1.00")),
(1.5234567, Decimal("1.52")),
(0, Decimal("0.00")),
(23.2345678, Decimal("23.24")),
],
)
def test_decimal_tax_percent(self, inputted, expected, monkeypatch):
fake_invoice = deepcopy(FAKE_INVOICE)
fake_invoice["tax_percent"] = inputted
def mock_invoice_get(*args, **kwargs):
return fake_invoice
def mock_customer_get(*args, **kwargs):
return FAKE_CUSTOMER
def mock_charge_get(*args, **kwargs):
return FAKE_CHARGE
def mock_payment_method_get(*args, **kwargs):
return FAKE_CARD_AS_PAYMENT_METHOD
def mock_payment_intent_get(*args, **kwargs):
return FAKE_PAYMENT_INTENT_I
def mock_subscription_get(*args, **kwargs):
return FAKE_SUBSCRIPTION
def mock_balance_transaction_get(*args, **kwargs):
return FAKE_BALANCE_TRANSACTION
def mock_product_get(*args, **kwargs):
return FAKE_PRODUCT
# monkeypatch stripe retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Invoice, "retrieve", mock_invoice_get)
monkeypatch.setattr(stripe.Customer, "retrieve", mock_customer_get)
monkeypatch.setattr(
stripe.BalanceTransaction, "retrieve", mock_balance_transaction_get
)
monkeypatch.setattr(stripe.Subscription, "retrieve", mock_subscription_get)
monkeypatch.setattr(stripe.Charge, "retrieve", mock_charge_get)
monkeypatch.setattr(stripe.PaymentMethod, "retrieve", mock_payment_method_get)
monkeypatch.setattr(stripe.PaymentIntent, "retrieve", mock_payment_intent_get)
monkeypatch.setattr(stripe.Product, "retrieve", mock_product_get)
invoice = Invoice.sync_from_stripe_data(fake_invoice)
field_data = invoice.tax_percent
assert isinstance(field_data, Decimal)
assert field_data == expected
tests.test_invoiceitem
dj-stripe InvoiceItem Model Tests.
Classes
tests.test_invoiceitem.InvoiceItemTest
Methods
tests.test_invoiceitem.InvoiceItemTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_invoiceitem.py
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
self.default_expected_blank_fks = {
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.Invoice.payment_intent",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
}
tests.test_invoiceitem.InvoiceItemTest.test___str__(self, invoice_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoiceitem.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
side_effect=[
deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
deepcopy(FAKE_PAYMENT_METHOD_II),
],
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
side_effect=[deepcopy(FAKE_PAYMENT_INTENT_I), deepcopy(FAKE_PAYMENT_INTENT_II)],
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
side_effect=[deepcopy(FAKE_CHARGE), deepcopy(FAKE_CHARGE_II)],
autospec=True,
)
@patch(
"stripe.Invoice.retrieve",
side_effect=[deepcopy(FAKE_INVOICE), deepcopy(FAKE_INVOICE_II)],
autospec=True,
)
def test___str__(
self,
invoice_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_III)
fake_subscription["latest_invoice"] = FAKE_INVOICE["id"]
subscription_retrieve_mock.side_effect = [
deepcopy(FAKE_SUBSCRIPTION),
fake_subscription,
]
fake_customer = deepcopy(FAKE_CUSTOMER_II)
customer_retrieve_mock.side_effect = [deepcopy(FAKE_CUSTOMER), fake_customer]
fake_card = deepcopy(FAKE_CARD_II)
fake_card["customer"] = None
# create Card for FAKE_CUSTOMER_III
Card.sync_from_stripe_data(fake_card)
# create invoice for latest_invoice in subscription to work.
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
# create invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE_II))
default_account_mock.return_value = self.account
invoiceitem_data = deepcopy(FAKE_INVOICEITEM)
invoiceitem_data["plan"] = FAKE_PLAN_II
invoiceitem_data["price"] = FAKE_PRICE_II
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
self.assertEqual(
invoiceitem.get_stripe_dashboard_url(),
invoiceitem.invoice.get_stripe_dashboard_url(),
)
assert str(invoiceitem) == invoiceitem.description
tests.test_invoiceitem.InvoiceItemTest.test_sync_expanded_invoice_with_subscription(self, invoice_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoiceitem.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_II),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_II),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE_II), autospec=True
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE_II), autospec=True
)
def test_sync_expanded_invoice_with_subscription(
self,
invoice_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_III)
fake_subscription["latest_invoice"] = FAKE_INVOICE_II["id"]
subscription_retrieve_mock.return_value = fake_subscription
fake_card = deepcopy(FAKE_CARD_II)
fake_card["customer"] = None
# create Card for FAKE_CUSTOMER_III
Card.sync_from_stripe_data(fake_card)
# create invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE_II))
default_account_mock.return_value = self.account
invoiceitem_data = deepcopy(FAKE_INVOICEITEM)
# Expand the Invoice data
invoiceitem_data.update(
{
"subscription": FAKE_SUBSCRIPTION_III["id"],
"invoice": deepcopy(dict(FAKE_INVOICE_II)),
}
)
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
expected_blank_fks = self.default_expected_blank_fks | {
"djstripe.InvoiceItem.plan",
"djstripe.InvoiceItem.price",
}
self.assert_fks(invoiceitem, expected_blank_fks=expected_blank_fks)
# Coverage of sync of existing data
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
self.assert_fks(invoiceitem, expected_blank_fks=expected_blank_fks)
tests.test_invoiceitem.InvoiceItemTest.test_sync_null_invoice(self, invoice_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, price_retrieve_mock, default_account_mock)
Source code in tests/test_invoiceitem.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch("stripe.Price.retrieve", return_value=deepcopy(FAKE_PRICE_II), autospec=True)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_II), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_III),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE_II), autospec=True
)
@patch("stripe.Invoice.retrieve", autospec=True)
def test_sync_null_invoice(
self,
invoice_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
price_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
invoiceitem_data = deepcopy(FAKE_INVOICEITEM)
invoiceitem_data.update(
{
"proration": True,
"plan": FAKE_PLAN_II["id"],
"price": FAKE_PRICE_II["id"],
"invoice": None,
}
)
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
self.assertEqual(FAKE_PLAN_II["id"], invoiceitem.plan.id)
self.assertEqual(FAKE_PRICE_II["id"], invoiceitem.price.id)
self.assert_fks(
invoiceitem,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.InvoiceItem.invoice", "djstripe.InvoiceItem.subscription"},
)
tests.test_invoiceitem.InvoiceItemTest.test_sync_proration(self, invoice_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, price_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoiceitem.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch("stripe.Price.retrieve", return_value=deepcopy(FAKE_PRICE_II), autospec=True)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_II), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_II),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_II),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE_II), autospec=True
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE_II), autospec=True
)
def test_sync_proration(
self,
invoice_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
price_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_III)
fake_subscription["latest_invoice"] = FAKE_INVOICE_II["id"]
subscription_retrieve_mock.return_value = fake_subscription
fake_card = deepcopy(FAKE_CARD_II)
fake_card["customer"] = None
# create Card for FAKE_CUSTOMER_III
Card.sync_from_stripe_data(fake_card)
# create invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE_II))
default_account_mock.return_value = self.account
invoiceitem_data = deepcopy(FAKE_INVOICEITEM)
invoiceitem_data.update(
{
"proration": True,
"plan": FAKE_PLAN_II["id"],
"price": FAKE_PRICE_II["id"],
}
)
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
self.assertEqual(FAKE_PLAN_II["id"], invoiceitem.plan.id)
self.assertEqual(FAKE_PRICE_II["id"], invoiceitem.price.id)
self.assert_fks(
invoiceitem,
expected_blank_fks=self.default_expected_blank_fks
| {"djstripe.InvoiceItem.subscription"},
)
tests.test_invoiceitem.InvoiceItemTest.test_sync_with_subscription(self, invoice_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoiceitem.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_II),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_II),
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
return_value=deepcopy(FAKE_CHARGE_II),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve",
return_value=deepcopy(FAKE_INVOICE_II),
autospec=True,
)
def test_sync_with_subscription(
self,
invoice_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_III)
fake_subscription["latest_invoice"] = FAKE_INVOICE_II["id"]
subscription_retrieve_mock.return_value = fake_subscription
fake_customer = deepcopy(FAKE_CUSTOMER_II)
customer_retrieve_mock.return_value = fake_customer
fake_card = deepcopy(FAKE_CARD_II)
fake_card["customer"] = None
# create Card for FAKE_CUSTOMER_III
Card.sync_from_stripe_data(fake_card)
default_account_mock.return_value = self.account
invoiceitem_data = deepcopy(FAKE_INVOICEITEM)
invoiceitem_data.update({"subscription": fake_subscription["id"]})
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
expected_blank_fks = self.default_expected_blank_fks | {
"djstripe.InvoiceItem.plan",
"djstripe.InvoiceItem.price",
}
self.assert_fks(invoiceitem, expected_blank_fks=expected_blank_fks)
# Coverage of sync of existing data
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
self.assert_fks(invoiceitem, expected_blank_fks=expected_blank_fks)
invoice_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
id=FAKE_INVOICE_II["id"],
stripe_account=None,
)
tests.test_invoiceitem.InvoiceItemTest.test_sync_with_taxes(self, invoice_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, charge_retrieve_mock, customer_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_invoiceitem.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE_II), autospec=True
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_II),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_II),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE_II), autospec=True
)
def test_sync_with_taxes(
self,
invoice_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
charge_retrieve_mock,
customer_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_III)
fake_subscription["latest_invoice"] = FAKE_INVOICE_II["id"]
subscription_retrieve_mock.return_value = fake_subscription
fake_card = deepcopy(FAKE_CARD_II)
fake_card["customer"] = None
# create Card for FAKE_CUSTOMER_III
Card.sync_from_stripe_data(fake_card)
# create invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE_II))
default_account_mock.return_value = self.account
invoiceitem_data = deepcopy(FAKE_INVOICEITEM_III)
invoiceitem_data["plan"] = FAKE_PLAN_II
invoiceitem_data["price"] = FAKE_PRICE_II
invoiceitem = InvoiceItem.sync_from_stripe_data(invoiceitem_data)
self.assertEqual(invoiceitem.tax_rates.count(), 1)
self.assertEqual(
invoiceitem.tax_rates.first().id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
tests.test_managers
dj-stripe Model Manager Tests.
Classes
tests.test_managers.ChargeManagerTest
Methods
tests.test_managers.ChargeManagerTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_managers.py
def setUp(self):
customer = Customer.objects.create(
id="cus_XXXXXXX", livemode=False, balance=0, delinquent=False
)
self.march_charge = Charge.objects.create(
id="ch_XXXXMAR1",
customer=customer,
created=datetime.datetime(2015, 3, 31, tzinfo=timezone.utc),
amount=0,
amount_refunded=0,
currency="usd",
status="pending",
)
self.april_charge_1 = Charge.objects.create(
id="ch_XXXXAPR1",
customer=customer,
created=datetime.datetime(2015, 4, 1, tzinfo=timezone.utc),
amount=decimal.Decimal("20.15"),
amount_refunded=0,
currency="usd",
status="succeeded",
paid=True,
)
self.april_charge_2 = Charge.objects.create(
id="ch_XXXXAPR2",
customer=customer,
created=datetime.datetime(2015, 4, 18, tzinfo=timezone.utc),
amount=decimal.Decimal("10.35"),
amount_refunded=decimal.Decimal("5.35"),
currency="usd",
status="succeeded",
paid=True,
)
self.april_charge_3 = Charge.objects.create(
id="ch_XXXXAPR3",
customer=customer,
created=datetime.datetime(2015, 4, 30, tzinfo=timezone.utc),
amount=decimal.Decimal("100.00"),
amount_refunded=decimal.Decimal("80.00"),
currency="usd",
status="pending",
paid=False,
)
self.may_charge = Charge.objects.create(
id="ch_XXXXMAY1",
customer=customer,
created=datetime.datetime(2015, 5, 1, tzinfo=timezone.utc),
amount=0,
amount_refunded=0,
currency="usd",
status="pending",
)
self.november_charge = Charge.objects.create(
id="ch_XXXXNOV1",
customer=customer,
created=datetime.datetime(2015, 11, 16, tzinfo=timezone.utc),
amount=0,
amount_refunded=0,
currency="usd",
status="pending",
)
self.charge_2014 = Charge.objects.create(
id="ch_XXXX20141",
customer=customer,
created=datetime.datetime(2014, 12, 31, tzinfo=timezone.utc),
amount=0,
amount_refunded=0,
currency="usd",
status="pending",
)
self.charge_2016 = Charge.objects.create(
id="ch_XXXX20161",
customer=customer,
created=datetime.datetime(2016, 1, 1, tzinfo=timezone.utc),
amount=0,
amount_refunded=0,
currency="usd",
status="pending",
)
tests.test_managers.ChargeManagerTest.test_get_paid_totals_for_april_2015(self)
Source code in tests/test_managers.py
def test_get_paid_totals_for_april_2015(self):
paid_totals = Charge.objects.paid_totals_for(year=2015, month=4)
self.assertEqual(
decimal.Decimal("30.50"),
paid_totals["total_amount"],
"Total amount is not correct.",
)
self.assertEqual(
decimal.Decimal("5.35"),
paid_totals["total_refunded"],
"Total amount refunded is not correct.",
)
tests.test_managers.ChargeManagerTest.test_is_during_april_2015(self)
Source code in tests/test_managers.py
def test_is_during_april_2015(self):
raw_charges = Charge.objects.during(year=2015, month=4)
charges = [charge.id for charge in raw_charges]
self.assertIn(self.april_charge_1.id, charges, "April charge 1 not in charges.")
self.assertIn(self.april_charge_2.id, charges, "April charge 2 not in charges.")
self.assertIn(self.april_charge_3.id, charges, "April charge 3 not in charges.")
self.assertNotIn(
self.march_charge.id, charges, "March charge unexpectedly in charges."
)
self.assertNotIn(
self.may_charge.id, charges, "May charge unexpectedly in charges."
)
self.assertNotIn(
self.november_charge.id, charges, "November charge unexpectedly in charges."
)
self.assertNotIn(
self.charge_2014.id, charges, "2014 charge unexpectedly in charges."
)
self.assertNotIn(
self.charge_2016.id, charges, "2016 charge unexpectedly in charges."
)
tests.test_managers.SubscriptionManagerTest
Methods
tests.test_managers.SubscriptionManagerTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_managers.py
def setUp(self):
# create customers and current subscription records
period_start = datetime.datetime(2013, 4, 1, tzinfo=timezone.utc)
period_end = datetime.datetime(2013, 4, 30, tzinfo=timezone.utc)
start = datetime.datetime(
2013, 1, 1, 0, 0, 1, tzinfo=timezone.utc
) # more realistic start
with patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
):
self.plan = Plan.sync_from_stripe_data(FAKE_PLAN)
self.plan2 = Plan.sync_from_stripe_data(FAKE_PLAN_II)
for i in range(10):
user = get_user_model().objects.create_user(
username="patrick{0}".format(i),
email="patrick{0}@example.com".format(i),
)
customer = Customer.objects.create(
subscriber=user,
id="cus_xxxxxxxxxxxxxx{0}".format(i),
livemode=False,
balance=0,
delinquent=False,
)
Subscription.objects.create(
id="sub_xxxxxxxxxxxxxx{0}".format(i),
customer=customer,
plan=self.plan,
current_period_start=period_start,
current_period_end=period_end,
status="active",
start_date=start,
quantity=1,
)
user = get_user_model().objects.create_user(
username="patrick{0}".format(11), email="patrick{0}@example.com".format(11)
)
customer = Customer.objects.create(
subscriber=user,
id="cus_xxxxxxxxxxxxxx{0}".format(11),
livemode=False,
balance=0,
delinquent=False,
)
Subscription.objects.create(
id="sub_xxxxxxxxxxxxxx{0}".format(11),
customer=customer,
plan=self.plan,
current_period_start=period_start,
current_period_end=period_end,
status="canceled",
canceled_at=period_end,
start_date=start,
quantity=1,
)
user = get_user_model().objects.create_user(
username="patrick{0}".format(12), email="patrick{0}@example.com".format(12)
)
customer = Customer.objects.create(
subscriber=user,
id="cus_xxxxxxxxxxxxxx{0}".format(12),
livemode=False,
balance=0,
delinquent=False,
)
Subscription.objects.create(
id="sub_xxxxxxxxxxxxxx{0}".format(12),
customer=customer,
plan=self.plan2,
current_period_start=period_start,
current_period_end=period_end,
status="active",
start_date=start,
quantity=1,
)
tests.test_managers.SubscriptionManagerTest.test_active_all(self)
Source code in tests/test_managers.py
def test_active_all(self):
self.assertEqual(Subscription.objects.active().count(), 11)
tests.test_managers.SubscriptionManagerTest.test_active_plan_summary(self)
Source code in tests/test_managers.py
def test_active_plan_summary(self):
for plan in Subscription.objects.active_plan_summary():
if plan["plan"] == self.plan:
self.assertEqual(plan["count"], 10)
if plan["plan"] == self.plan2:
self.assertEqual(plan["count"], 1)
tests.test_managers.SubscriptionManagerTest.test_canceled_all(self)
Source code in tests/test_managers.py
def test_canceled_all(self):
self.assertEqual(Subscription.objects.canceled().count(), 1)
tests.test_managers.SubscriptionManagerTest.test_canceled_during(self)
Source code in tests/test_managers.py
def test_canceled_during(self):
self.assertEqual(Subscription.objects.canceled_during(2013, 4).count(), 1)
tests.test_managers.SubscriptionManagerTest.test_canceled_plan_summary(self)
Source code in tests/test_managers.py
def test_canceled_plan_summary(self):
for plan in Subscription.objects.canceled_plan_summary_for(2013, 1):
if plan["plan"] == self.plan:
self.assertEqual(plan["count"], 1)
if plan["plan"] == self.plan2:
self.assertEqual(plan["count"], 0)
tests.test_managers.SubscriptionManagerTest.test_churn(self)
Source code in tests/test_managers.py
def test_churn(self):
self.assertEqual(
Subscription.objects.churn(), decimal.Decimal("1") / decimal.Decimal("11")
)
tests.test_managers.SubscriptionManagerTest.test_started_during_has_records(self)
Source code in tests/test_managers.py
def test_started_during_has_records(self):
self.assertEqual(Subscription.objects.started_during(2013, 1).count(), 12)
tests.test_managers.SubscriptionManagerTest.test_started_during_no_records(self)
Source code in tests/test_managers.py
def test_started_during_no_records(self):
self.assertEqual(Subscription.objects.started_during(2013, 4).count(), 0)
tests.test_managers.SubscriptionManagerTest.test_started_plan_summary(self)
Source code in tests/test_managers.py
def test_started_plan_summary(self):
for plan in Subscription.objects.started_plan_summary_for(2013, 1):
if plan["plan"] == self.plan:
self.assertEqual(plan["count"], 11)
if plan["plan"] == self.plan2:
self.assertEqual(plan["count"], 1)
tests.test_managers.TransferManagerTest
tests.test_managers.TransferManagerTest.test_transfer_summary(self, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_managers.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_transfer_summary(
self, account_retrieve_mock, transfer__attach_object_post_save_hook_mock
):
def FAKE_TRANSFER_III():
data = deepcopy(FAKE_TRANSFER)
data["id"] = "tr_17O4U52eZvKYlo2CmyYbDAEy"
data["amount"] = 19010
data["created"] = 1451560845
return data
def FAKE_TRANSFER_II():
data = deepcopy(FAKE_TRANSFER)
data["id"] = "tr_16hTzv2eZvKYlo2CWuyMmuvV"
data["amount"] = 2000
data["created"] = 1440420000
return data
Transfer.sync_from_stripe_data(deepcopy(FAKE_TRANSFER))
Transfer.sync_from_stripe_data(FAKE_TRANSFER_II())
Transfer.sync_from_stripe_data(FAKE_TRANSFER_III())
self.assertEqual(Transfer.objects.during(2015, 8).count(), 2)
totals = Transfer.objects.paid_totals_for(2015, 12)
self.assertEqual(totals["total_amount"], decimal.Decimal("190.10"))
tests.test_migrations
dj-stripe Migrations Tests
Classes
tests.test_migrations.TestCustomerSubscriberFK
Methods
tests.test_migrations.TestCustomerSubscriberFK.setUp(self)
Source code in tests/test_migrations.py
@override_settings(
DJSTRIPE_SUBSCRIBER_MODEL="testapp.Organization",
DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK=(lambda request: request.org),
)
def setUp(self):
return super().setUp()
tests.test_migrations.TestCustomerSubscriberFK.test_customer_subscriber_fk_fallback_to_auth_user_model(self)
Test to ensure customer.subscriber fk points to the fallback AUTH_USER_MODEL when DJSTRIPE_SUBSCRIBER_MODEL is not set
Source code in tests/test_migrations.py
def test_customer_subscriber_fk_fallback_to_auth_user_model(self):
"""
Test to ensure customer.subscriber fk points to the fallback AUTH_USER_MODEL
when DJSTRIPE_SUBSCRIBER_MODEL is not set
"""
# assert DJSTRIPE_SUBSCRIBER_MODEL has not been set
with pytest.raises(AttributeError):
settings.DJSTRIPE_SUBSCRIBER_MODEL
field = Customer._meta.get_field("subscriber")
self.assertEqual(field.related_model, get_user_model())
tests.test_migrations.TestCustomerSubscriberFK.test_customer_subscriber_fk_to_subscriber_model(self)
Test to ensure customer.subscriber fk points to the configured model set by DJSTRIPE_SUBSCRIBER_MODEL
Source code in tests/test_migrations.py
def test_customer_subscriber_fk_to_subscriber_model(self):
"""
Test to ensure customer.subscriber fk points to the configured model
set by DJSTRIPE_SUBSCRIBER_MODEL
"""
field = Customer._meta.get_field("subscriber")
self.assertEqual(field.related_model, djstripe_settings.get_subscriber_model())
self.assertNotEqual(field.related_model, settings.AUTH_USER_MODEL)
tests.test_mixins
dj-stripe Mixin Tests.
Classes
tests.test_mixins.TestPaymentsContextMixin
tests.test_mixins.TestPaymentsContextMixin.test_get_context_data(self)
Source code in tests/test_mixins.py
def test_get_context_data(self):
class TestSuperView(object):
def get_context_data(self):
return {}
class TestView(PaymentsContextMixin, TestSuperView):
pass
context = TestView().get_context_data()
self.assertIn(
"STRIPE_PUBLIC_KEY", context, "STRIPE_PUBLIC_KEY missing from context."
)
self.assertEqual(
context["STRIPE_PUBLIC_KEY"],
djstripe_settings.STRIPE_PUBLIC_KEY,
"Incorrect STRIPE_PUBLIC_KEY.",
)
self.assertIn("plans", context, "pans missing from context.")
self.assertEqual(
list(Plan.objects.all()), list(context["plans"]), "Incorrect plans."
)
tests.test_mixins.TestSubscriptionMixin
Methods
tests.test_mixins.TestSubscriptionMixin.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_mixins.py
def setUp(self):
with patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
):
Plan.sync_from_stripe_data(deepcopy(FAKE_PLAN))
Plan.sync_from_stripe_data(deepcopy(FAKE_PLAN_II))
tests.test_mixins.TestSubscriptionMixin.test_get_context_data(self, stripe_create_customer_mock)
Source code in tests/test_mixins.py
@patch(
"stripe.Customer.create", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_get_context_data(self, stripe_create_customer_mock):
class TestSuperView(object):
def get_context_data(self):
return {}
class TestView(SubscriptionMixin, TestSuperView):
pass
test_view = TestView()
test_view.request = RequestFactory()
test_view.request.user = get_user_model().objects.create(
username="x", email="user@test.com"
)
context = test_view.get_context_data()
self.assertIn(
"is_plans_plural", context, "is_plans_plural missing from context."
)
self.assertTrue(context["is_plans_plural"], "Incorrect is_plans_plural.")
self.assertIn("customer", context, "customer missing from context.")
tests.test_payment_intent
dj-stripe PaymentIntent Model Tests.
tests.test_payment_intent.pytestmark
tests.test_payment_intent.PaymentIntentTest
tests.test_payment_intent.PaymentIntentTest.test_canceled_intent(self, customer_retrieve_mock)
Source code in tests/test_payment_intent.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_canceled_intent(self, customer_retrieve_mock):
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
fake_payment_intent["status"] = "canceled"
fake_payment_intent["canceled_at"] = 1567524169
for reason in (
None,
"duplicate",
"fraudulent",
"requested_by_customer",
"abandoned",
"failed_invoice",
"void_invoice",
"automatic",
):
fake_payment_intent["cancellation_reason"] = reason
payment_intent = PaymentIntent.sync_from_stripe_data(fake_payment_intent)
if reason is None:
# enums nulls are coerced to "" by StripeModel._stripe_object_to_record
self.assertEqual(payment_intent.cancellation_reason, "")
else:
self.assertEqual(payment_intent.cancellation_reason, reason)
# trigger model field validation (including enum value choices check)
payment_intent.full_clean()
tests.test_payment_intent.PaymentIntentTest.test_status_enum(self, customer_retrieve_mock)
Source code in tests/test_payment_intent.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_status_enum(self, customer_retrieve_mock):
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
for status in (
"requires_payment_method",
"requires_confirmation",
"requires_action",
"processing",
"requires_capture",
"canceled",
"succeeded",
):
fake_payment_intent["status"] = status
payment_intent = PaymentIntent.sync_from_stripe_data(fake_payment_intent)
# trigger model field validation (including enum value choices check)
payment_intent.full_clean()
tests.test_payment_intent.PaymentIntentTest.test_sync_from_stripe_data(self, customer_retrieve_mock)
Source code in tests/test_payment_intent.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_from_stripe_data(self, customer_retrieve_mock):
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
payment_intent = PaymentIntent.sync_from_stripe_data(fake_payment_intent)
self.assert_fks(
payment_intent,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
},
)
# TODO - PaymentIntent should probably sync invoice (reverse OneToOneField)
# self.assertIsNotNone(payment_intent.invoice)
tests.test_payment_intent.TestStrPaymentIntent
tests.test_payment_intent.TestStrPaymentIntent.get_fake_payment_intent_destination_charge_no_customer()
Source code in tests/test_payment_intent.py
def get_fake_payment_intent_destination_charge_no_customer():
FAKE_PAYMENT_INTENT_DESTINATION_CHARGE_NO_CUSTOMER = deepcopy(
FAKE_PAYMENT_INTENT_DESTINATION_CHARGE
)
FAKE_PAYMENT_INTENT_DESTINATION_CHARGE_NO_CUSTOMER["customer"] = None
return FAKE_PAYMENT_INTENT_DESTINATION_CHARGE_NO_CUSTOMER
tests.test_payment_intent.TestStrPaymentIntent.get_fake_payment_intent_i_no_customer()
Source code in tests/test_payment_intent.py
def get_fake_payment_intent_i_no_customer():
FAKE_PAYMENT_INTENT_I_NO_CUSTOMER = deepcopy(FAKE_PAYMENT_INTENT_I)
FAKE_PAYMENT_INTENT_I_NO_CUSTOMER["customer"] = None
return FAKE_PAYMENT_INTENT_I_NO_CUSTOMER
tests.test_payment_intent.TestStrPaymentIntent.test___str__(self, fake_intent_data, has_account, has_customer, monkeypatch)
Source code in tests/test_payment_intent.py
@pytest.mark.parametrize(
"fake_intent_data, has_account, has_customer",
[
(FAKE_PAYMENT_INTENT_I, False, True),
(FAKE_PAYMENT_INTENT_DESTINATION_CHARGE, True, True),
(get_fake_payment_intent_destination_charge_no_customer(), True, False),
(get_fake_payment_intent_i_no_customer(), False, False),
],
)
def test___str__(self, fake_intent_data, has_account, has_customer, monkeypatch):
def mock_customer_get(*args, **kwargs):
return deepcopy(FAKE_CUSTOMER)
def mock_account_get(*args, **kwargs):
data = deepcopy(FAKE_ACCOUNT)
# Otherwise Account.api_retrieve will invoke File.api_retrieve...
data["settings"]["branding"] = {}
return data
def mock_payment_method_get(*args, **kwargs):
return deepcopy(FAKE_PAYMENT_METHOD_I)
# monkeypatch stripe.Product.retrieve, stripe.Price.retrieve, and stripe.PaymentMethod.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Account, "retrieve", mock_account_get)
monkeypatch.setattr(stripe.Customer, "retrieve", mock_customer_get)
monkeypatch.setattr(stripe.PaymentMethod, "retrieve", mock_payment_method_get)
pi = PaymentIntent.sync_from_stripe_data(fake_intent_data)
account = Account.objects.filter(id=fake_intent_data["on_behalf_of"]).first()
customer = Customer.objects.filter(id=fake_intent_data["customer"]).first()
if has_account and has_customer:
assert (
f"{pi.human_readable_amount} ({PaymentIntentStatus.humanize(fake_intent_data['status'])}) "
f"for {account} "
f"by {customer}"
) == str(pi)
elif has_account and not has_customer:
assert (
f"{pi.human_readable_amount} for {account}. {PaymentIntentStatus.humanize(fake_intent_data['status'])}"
) == str(pi)
elif has_customer and not has_account:
assert (
f"{pi.human_readable_amount} by {customer}. {PaymentIntentStatus.humanize(fake_intent_data['status'])}"
) == str(pi)
elif not has_customer and not has_account:
f"{pi.human_readable_amount} ({PaymentIntentStatus.humanize(fake_intent_data['status'])})" == str(
pi
)
tests.test_payment_method
dj-stripe PaymenthMethod Model Tests.
tests.test_payment_method.pytestmark
Classes
tests.test_payment_method.PaymentMethodTest
Methods
tests.test_payment_method.PaymentMethodTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_payment_method.py
def setUp(self):
user = get_user_model().objects.create_user(
username="testuser", email="djstripe@example.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(user)
tests.test_payment_method.PaymentMethodTest.test_attach(self, attach_mock)
Source code in tests/test_payment_method.py
@patch(
"stripe.PaymentMethod._cls_attach",
return_value=deepcopy(FAKE_PAYMENT_METHOD_I),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_attach(self, attach_mock):
payment_method = models.PaymentMethod.attach(
FAKE_PAYMENT_METHOD_I["id"], customer=FAKE_CUSTOMER["id"]
)
self.assert_fks(
payment_method,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_payment_method.PaymentMethodTest.test_attach_obj(self, attach_mock)
Source code in tests/test_payment_method.py
@patch(
"stripe.PaymentMethod._cls_attach",
return_value=deepcopy(FAKE_PAYMENT_METHOD_I),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_attach_obj(self, attach_mock):
pm = models.PaymentMethod.sync_from_stripe_data(FAKE_PAYMENT_METHOD_I)
payment_method = models.PaymentMethod.attach(pm, customer=self.customer)
self.assert_fks(
payment_method,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_payment_method.PaymentMethodTest.test_attach_synced(self, attach_mock)
Source code in tests/test_payment_method.py
@patch(
"stripe.PaymentMethod._cls_attach",
return_value=deepcopy(FAKE_PAYMENT_METHOD_I),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_attach_synced(self, attach_mock):
fake_payment_method = deepcopy(FAKE_PAYMENT_METHOD_I)
fake_payment_method["customer"] = None
payment_method = models.PaymentMethod.sync_from_stripe_data(fake_payment_method)
self.assert_fks(
payment_method, expected_blank_fks={"djstripe.PaymentMethod.customer"}
)
payment_method = models.PaymentMethod.attach(
payment_method.id, customer=FAKE_CUSTOMER["id"]
)
self.assert_fks(
payment_method,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_payment_method.PaymentMethodTest.test_detach(self)
Source code in tests/test_payment_method.py
def test_detach(self):
original_detach = PaymentMethodDict.detach
def mocked_detach(*args, **kwargs):
return original_detach(*args, **kwargs)
with patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_I),
autospec=True,
):
models.PaymentMethod.sync_from_stripe_data(deepcopy(FAKE_PAYMENT_METHOD_I))
self.assertEqual(1, self.customer.payment_methods.count())
payment_method = self.customer.payment_methods.first()
with patch(
"tests.PaymentMethodDict.detach", side_effect=mocked_detach, autospec=True
) as mock_detach, patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_I),
autospec=True,
):
self.assertTrue(payment_method.detach())
self.assertEqual(0, self.customer.payment_methods.count())
self.assertIsNone(self.customer.default_payment_method)
self.assertIsNone(payment_method.customer)
if sys.version_info >= (3, 6):
# this mock isn't working on py34, py35, but it's not strictly necessary
# for the test
mock_detach.assert_called()
self.assert_fks(
payment_method, expected_blank_fks={"djstripe.PaymentMethod.customer"}
)
with patch(
"tests.PaymentMethodDict.detach",
side_effect=InvalidRequestError(
message="A source must be attached to a customer to be used "
"as a `payment_method`",
param="payment_method",
),
autospec=True,
) as mock_detach, patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_I),
autospec=True,
) as payment_method_retrieve_mock:
payment_method_retrieve_mock.return_value["customer"] = None
self.assertFalse(
payment_method.detach(), "Second call to detach should return false"
)
tests.test_payment_method.PaymentMethodTest.test_detach_card(self)
Source code in tests/test_payment_method.py
def test_detach_card(self):
original_detach = PaymentMethodDict.detach
# "card_" payment methods are deleted after detach
deleted_card_exception = InvalidRequestError(
message="No such payment_method: card_xxxx",
param="payment_method",
code="resource_missing",
)
def mocked_detach(*args, **kwargs):
return original_detach(*args, **kwargs)
with patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
):
models.PaymentMethod.sync_from_stripe_data(
deepcopy(FAKE_CARD_AS_PAYMENT_METHOD)
)
self.assertEqual(1, self.customer.payment_methods.count())
payment_method = self.customer.payment_methods.first()
self.assertTrue(
payment_method.id.startswith("card_"), "We expect this to be a 'card_'"
)
with patch(
"tests.PaymentMethodDict.detach", side_effect=mocked_detach, autospec=True
) as mock_detach, patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
):
self.assertTrue(payment_method.detach())
self.assertEqual(0, self.customer.payment_methods.count())
self.assertIsNone(self.customer.default_payment_method)
self.assertEqual(
models.PaymentMethod.objects.filter(id=payment_method.id).count(),
0,
"We expect PaymentMethod id = card_* to be deleted",
)
if sys.version_info >= (3, 6):
# this mock isn't working on py34, py35, but it's not strictly necessary
# for the test
mock_detach.assert_called()
with patch(
"tests.PaymentMethodDict.detach",
side_effect=InvalidRequestError(
message="A source must be attached to a customer to be used "
"as a `payment_method`",
param="payment_method",
),
autospec=True,
) as mock_detach, patch(
"stripe.PaymentMethod.retrieve",
side_effect=deleted_card_exception,
autospec=True,
) as payment_method_retrieve_mock:
payment_method_retrieve_mock.return_value["customer"] = None
self.assertFalse(
payment_method.detach(), "Second call to detach should return false"
)
tests.test_payment_method.PaymentMethodTest.test_sync_null_customer(self)
Source code in tests/test_payment_method.py
def test_sync_null_customer(self):
payment_method = models.PaymentMethod.sync_from_stripe_data(
deepcopy(FAKE_PAYMENT_METHOD_I)
)
self.assertIsNotNone(payment_method.customer)
# simulate remote detach
fake_payment_method_no_customer = deepcopy(FAKE_PAYMENT_METHOD_I)
fake_payment_method_no_customer["customer"] = None
payment_method = models.PaymentMethod.sync_from_stripe_data(
fake_payment_method_no_customer
)
self.assertIsNone(payment_method.customer)
self.assert_fks(
payment_method, expected_blank_fks={"djstripe.PaymentMethod.customer"}
)
tests.test_payment_method.TestPaymentMethodStr
tests.test_payment_method.TestPaymentMethodStr.mock_customer_get(*args, **kwargs)
Source code in tests/test_payment_method.py
def mock_customer_get(*args, **kwargs):
return deepcopy(FAKE_CUSTOMER)
tests.test_payment_method.TestPaymentMethodStr.test___str__(self, monkeypatch, customer_exists)
Source code in tests/test_payment_method.py
@pytest.mark.parametrize("customer_exists", [True, False])
def test___str__(self, monkeypatch, customer_exists):
# monkeypatch stripe.Customer.retrieve call to return
# the desired json response.
monkeypatch.setattr(stripe.Customer, "retrieve", self.mock_customer_get)
fake_payment_method_data = deepcopy(FAKE_PAYMENT_METHOD_I)
if not customer_exists:
fake_payment_method_data["customer"] = None
pm = models.PaymentMethod.sync_from_stripe_data(fake_payment_method_data)
customer = None
assert (
f"{enums.PaymentMethodType.humanize(fake_payment_method_data['type'])} is not associated with any customer"
) == str(pm)
else:
pm = models.PaymentMethod.sync_from_stripe_data(fake_payment_method_data)
customer = models.Customer.objects.get(
id=fake_payment_method_data["customer"]
)
assert (
f"{enums.PaymentMethodType.humanize(fake_payment_method_data['type'])} for {customer}"
) == str(pm)
tests.test_plan
dj-stripe Plan Model Tests.
tests.test_plan.pytestmark
Classes
tests.test_plan.PlanCreateTest
Methods
tests.test_plan.PlanCreateTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_plan.py
def setUp(self):
with patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
):
self.stripe_product = Product(id=FAKE_PRODUCT["id"]).api_retrieve()
tests.test_plan.PlanCreateTest.test_create_from_djstripe_product(self, plan_create_mock, product_retrieve_mock)
Source code in tests/test_plan.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Plan.create", return_value=deepcopy(FAKE_PLAN), autospec=True)
def test_create_from_djstripe_product(
self, plan_create_mock, product_retrieve_mock
):
fake_plan = deepcopy(FAKE_PLAN)
fake_plan["product"] = Product.sync_from_stripe_data(self.stripe_product)
fake_plan["amount"] = fake_plan["amount"] / 100
self.assertIsInstance(fake_plan["product"], Product)
plan = Plan.create(**fake_plan)
plan_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, **FAKE_PLAN
)
self.assert_fks(plan, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_plan.PlanCreateTest.test_create_from_product_id(self, plan_create_mock, product_retrieve_mock)
Source code in tests/test_plan.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Plan.create", return_value=deepcopy(FAKE_PLAN), autospec=True)
def test_create_from_product_id(self, plan_create_mock, product_retrieve_mock):
fake_plan = deepcopy(FAKE_PLAN)
fake_plan["amount"] = fake_plan["amount"] / 100
self.assertIsInstance(fake_plan["product"], str)
plan = Plan.create(**fake_plan)
expected_create_kwargs = deepcopy(FAKE_PLAN)
expected_create_kwargs["api_key"] = djstripe_settings.STRIPE_SECRET_KEY
plan_create_mock.assert_called_once_with(**expected_create_kwargs)
self.assert_fks(plan, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_plan.PlanCreateTest.test_create_from_stripe_product(self, plan_create_mock, product_retrieve_mock)
Source code in tests/test_plan.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Plan.create", return_value=deepcopy(FAKE_PLAN), autospec=True)
def test_create_from_stripe_product(self, plan_create_mock, product_retrieve_mock):
fake_plan = deepcopy(FAKE_PLAN)
fake_plan["product"] = self.stripe_product
fake_plan["amount"] = fake_plan["amount"] / 100
self.assertIsInstance(fake_plan["product"], dict)
plan = Plan.create(**fake_plan)
expected_create_kwargs = deepcopy(FAKE_PLAN)
expected_create_kwargs["product"] = self.stripe_product
plan_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, **expected_create_kwargs
)
self.assert_fks(plan, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_plan.PlanCreateTest.test_create_with_metadata(self, plan_create_mock, product_retrieve_mock)
Source code in tests/test_plan.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Plan.create", return_value=deepcopy(FAKE_PLAN), autospec=True)
def test_create_with_metadata(self, plan_create_mock, product_retrieve_mock):
metadata = {"other_data": "more_data"}
fake_plan = deepcopy(FAKE_PLAN)
fake_plan["amount"] = fake_plan["amount"] / 100
fake_plan["metadata"] = metadata
self.assertIsInstance(fake_plan["product"], str)
plan = Plan.create(**fake_plan)
expected_create_kwargs = deepcopy(FAKE_PLAN)
expected_create_kwargs["metadata"] = metadata
plan_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, **expected_create_kwargs
)
self.assert_fks(plan, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_plan.PlanTest
Methods
tests.test_plan.PlanTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_plan.py
def setUp(self):
self.plan_data = deepcopy(FAKE_PLAN)
with patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
):
self.plan = Plan.sync_from_stripe_data(self.plan_data)
tests.test_plan.PlanTest.test___str__(self)
Source code in tests/test_plan.py
def test___str__(self):
subscriptions = Subscription.objects.filter(plan__id=self.plan.id).count()
self.assertEqual(
f"{self.plan.human_readable_price} for {FAKE_PRODUCT['name']} ({subscriptions} subscriptions)",
str(self.plan),
)
tests.test_plan.PlanTest.test___str__null_product(self)
Source code in tests/test_plan.py
def test___str__null_product(self):
plan_data = deepcopy(FAKE_PLAN_II)
del plan_data["product"]
plan = Plan.sync_from_stripe_data(plan_data)
self.assertIsNone(plan.product)
subscriptions = Subscription.objects.filter(plan__id=plan.id).count()
self.assertEqual(
f"{plan.human_readable_price} ({subscriptions} subscriptions)",
str(plan),
)
tests.test_plan.PlanTest.test_stripe_metered_plan(self)
Source code in tests/test_plan.py
def test_stripe_metered_plan(self):
plan_data = deepcopy(FAKE_PLAN_METERED)
plan = Plan.sync_from_stripe_data(plan_data)
self.assertEqual(plan.id, plan_data["id"])
self.assertEqual(plan.usage_type, PriceUsageType.metered)
self.assertIsNotNone(plan.amount, plan.product)
self.assert_fks(plan, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_plan.PlanTest.test_stripe_plan(self, plan_retrieve_mock)
Source code in tests/test_plan.py
@patch("stripe.Plan.retrieve", return_value=FAKE_PLAN, autospec=True)
def test_stripe_plan(self, plan_retrieve_mock):
stripe_plan = self.plan.api_retrieve()
plan_retrieve_mock.assert_called_once_with(
id=self.plan_data["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=["tiers"],
stripe_account=self.plan.djstripe_owner_account.id,
)
plan = Plan.sync_from_stripe_data(stripe_plan)
assert plan.amount_in_cents == plan.amount * 100
assert isinstance(plan.amount_in_cents, int)
self.assert_fks(plan, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_plan.PlanTest.test_stripe_plan_null_product(self)
assert that plan.Product can be null for backwards compatibility though note that it is a Stripe required field
Source code in tests/test_plan.py
def test_stripe_plan_null_product(self):
"""
assert that plan.Product can be null for backwards compatibility
though note that it is a Stripe required field
"""
plan_data = deepcopy(FAKE_PLAN_II)
del plan_data["product"]
plan = Plan.sync_from_stripe_data(plan_data)
self.assert_fks(
plan,
expected_blank_fks={"djstripe.Customer.coupon", "djstripe.Plan.product"},
)
tests.test_plan.PlanTest.test_stripe_tier_plan(self)
Source code in tests/test_plan.py
def test_stripe_tier_plan(self):
tier_plan_data = deepcopy(FAKE_TIER_PLAN)
plan = Plan.sync_from_stripe_data(tier_plan_data)
self.assertEqual(plan.id, tier_plan_data["id"])
self.assertIsNone(plan.amount)
self.assertIsNotNone(plan.tiers, plan.product)
self.assert_fks(plan, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_plan.TestHumanReadablePlan
tests.test_plan.TestHumanReadablePlan.get_fake_price_0_amount()
Source code in tests/test_plan.py
def get_fake_price_0_amount():
FAKE_PRICE_TIER_0_AMOUNT = deepcopy(FAKE_PLAN)
FAKE_PRICE_TIER_0_AMOUNT["amount"] = 0
FAKE_PRICE_TIER_0_AMOUNT["amount_decimal"] = 0
return FAKE_PRICE_TIER_0_AMOUNT
tests.test_plan.TestHumanReadablePlan.get_fake_price_0_flat_amount()
Source code in tests/test_plan.py
def get_fake_price_0_flat_amount():
FAKE_PRICE_TIER_0_FLAT_AMOUNT = deepcopy(FAKE_TIER_PLAN)
FAKE_PRICE_TIER_0_FLAT_AMOUNT["tiers"][0]["flat_amount"] = 0
FAKE_PRICE_TIER_0_FLAT_AMOUNT["tiers"][0]["flat_amount_decimal"] = 0
return FAKE_PRICE_TIER_0_FLAT_AMOUNT
tests.test_plan.TestHumanReadablePlan.get_fake_price_NONE_flat_amount()
Source code in tests/test_plan.py
def get_fake_price_NONE_flat_amount():
FAKE_PRICE_TIER_NONE_FLAT_AMOUNT = deepcopy(FAKE_TIER_PLAN)
FAKE_PRICE_TIER_NONE_FLAT_AMOUNT["tiers"][0]["flat_amount"] = None
FAKE_PRICE_TIER_NONE_FLAT_AMOUNT["tiers"][0]["flat_amount_decimal"] = None
return FAKE_PRICE_TIER_NONE_FLAT_AMOUNT
tests.test_plan.TestHumanReadablePlan.test_human_readable(self, fake_plan_data, expected_str, monkeypatch)
Source code in tests/test_plan.py
@pytest.mark.parametrize(
"fake_plan_data, expected_str",
[
(deepcopy(FAKE_PLAN), "$20.00 USD/month"),
(get_fake_price_0_amount(), "$0.00 USD/month"),
(
deepcopy(FAKE_TIER_PLAN),
"Starts at $10.00 USD per unit + $49.00 USD/month",
),
(
get_fake_price_0_flat_amount(),
"Starts at $10.00 USD per unit + $0.00 USD/month",
),
(
get_fake_price_NONE_flat_amount(),
"Starts at $10.00 USD per unit/month",
),
(deepcopy(FAKE_PLAN_METERED), "$2.00 USD/month"),
],
)
def test_human_readable(self, fake_plan_data, expected_str, monkeypatch):
def mock_product_get(*args, **kwargs):
return deepcopy(FAKE_PRODUCT)
def mock_price_get(*args, **kwargs):
return fake_plan_data
# monkeypatch stripe.Product.retrieve and stripe.Plan.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Product, "retrieve", mock_product_get)
monkeypatch.setattr(stripe.Plan, "retrieve", mock_price_get)
plan = Plan.sync_from_stripe_data(fake_plan_data)
assert plan.human_readable_price == expected_str
tests.test_price
dj-stripe Price model tests
tests.test_price.pytestmark
Classes
tests.test_price.PriceCreateTest
Methods
tests.test_price.PriceCreateTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_price.py
def setUp(self):
with patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
):
self.stripe_product = Product(id=FAKE_PRODUCT["id"]).api_retrieve()
tests.test_price.PriceCreateTest.test_create_from_djstripe_product(self, price_create_mock, product_retrieve_mock)
Source code in tests/test_price.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Price.create", return_value=deepcopy(FAKE_PRICE), autospec=True)
def test_create_from_djstripe_product(
self, price_create_mock, product_retrieve_mock
):
fake_price = deepcopy(FAKE_PRICE)
fake_price["product"] = Product.sync_from_stripe_data(self.stripe_product)
fake_price["unit_amount"] /= 100
assert isinstance(fake_price["product"], Product)
price = Price.create(**fake_price)
price_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, **FAKE_PRICE
)
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_price.PriceCreateTest.test_create_from_product_id(self, price_create_mock, product_retrieve_mock)
Source code in tests/test_price.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Price.create", return_value=deepcopy(FAKE_PRICE), autospec=True)
def test_create_from_product_id(self, price_create_mock, product_retrieve_mock):
fake_price = deepcopy(FAKE_PRICE)
fake_price["unit_amount"] /= 100
assert isinstance(fake_price["product"], str)
price = Price.create(**fake_price)
expected_create_kwargs = deepcopy(FAKE_PRICE)
expected_create_kwargs["api_key"] = djstripe_settings.STRIPE_SECRET_KEY
price_create_mock.assert_called_once_with(**expected_create_kwargs)
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_price.PriceCreateTest.test_create_from_stripe_product(self, price_create_mock, product_retrieve_mock)
Source code in tests/test_price.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Price.create", return_value=deepcopy(FAKE_PRICE), autospec=True)
def test_create_from_stripe_product(self, price_create_mock, product_retrieve_mock):
fake_price = deepcopy(FAKE_PRICE)
fake_price["product"] = self.stripe_product
fake_price["unit_amount"] /= 100
assert isinstance(fake_price["product"], dict)
price = Price.create(**fake_price)
expected_create_kwargs = deepcopy(FAKE_PRICE)
expected_create_kwargs["product"] = self.stripe_product
price_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, **expected_create_kwargs
)
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_price.PriceCreateTest.test_create_with_metadata(self, price_create_mock, product_retrieve_mock)
Source code in tests/test_price.py
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Price.create", return_value=deepcopy(FAKE_PRICE), autospec=True)
def test_create_with_metadata(self, price_create_mock, product_retrieve_mock):
metadata = {"other_data": "more_data"}
fake_price = deepcopy(FAKE_PRICE)
fake_price["unit_amount"] /= 100
fake_price["metadata"] = metadata
assert isinstance(fake_price["product"], str)
price = Price.create(**fake_price)
expected_create_kwargs = deepcopy(FAKE_PRICE)
expected_create_kwargs["metadata"] = metadata
price_create_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY, **expected_create_kwargs
)
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_price.PriceTest
Methods
tests.test_price.PriceTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_price.py
def setUp(self):
self.price_data = deepcopy(FAKE_PRICE)
with patch(
"stripe.Product.retrieve",
return_value=deepcopy(FAKE_PRODUCT),
autospec=True,
):
self.price = Price.sync_from_stripe_data(self.price_data)
tests.test_price.PriceTest.test_stripe_metered_price(self, price_retrieve_mock)
Source code in tests/test_price.py
@patch("stripe.Price.retrieve", autospec=True)
def test_stripe_metered_price(self, price_retrieve_mock):
price_data = deepcopy(FAKE_PRICE_METERED)
price = Price.sync_from_stripe_data(price_data)
assert price.id == price_data["id"]
assert price.recurring["usage_type"] == PriceUsageType.metered
assert price.unit_amount is not None
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_price.PriceTest.test_stripe_onetime_price(self, price_retrieve_mock)
Source code in tests/test_price.py
@patch("stripe.Price.retrieve", autospec=True)
def test_stripe_onetime_price(self, price_retrieve_mock):
price_data = deepcopy(FAKE_PRICE_ONETIME)
price = Price.sync_from_stripe_data(price_data)
assert price.id == price_data["id"]
assert price.unit_amount is not None
assert not price.recurring
assert price.type == PriceType.one_time
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_price.PriceTest.test_stripe_price(self, price_retrieve_mock)
Source code in tests/test_price.py
@patch("stripe.Price.retrieve", return_value=FAKE_PRICE, autospec=True)
def test_stripe_price(self, price_retrieve_mock):
stripe_price = self.price.api_retrieve()
price_retrieve_mock.assert_called_once_with(
id=self.price_data["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=["tiers"],
stripe_account=self.price.djstripe_owner_account.id,
)
price = Price.sync_from_stripe_data(stripe_price)
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
assert price.human_readable_price == "$20.00 USD/month"
tests.test_price.PriceTest.test_stripe_tier_price(self, price_retrieve_mock)
Source code in tests/test_price.py
@patch("stripe.Price.retrieve", autospec=True)
def test_stripe_tier_price(self, price_retrieve_mock):
price_data = deepcopy(FAKE_PRICE_TIER)
price = Price.sync_from_stripe_data(price_data)
assert price.id == price_data["id"]
assert price.unit_amount is None
assert price.tiers is not None
self.assert_fks(price, expected_blank_fks={"djstripe.Customer.coupon"})
tests.test_price.TestHumanReadablePrice
tests.test_price.TestHumanReadablePrice.get_fake_price_0_amount()
Source code in tests/test_price.py
def get_fake_price_0_amount():
FAKE_PRICE_TIER_0_AMOUNT = deepcopy(FAKE_PRICE)
FAKE_PRICE_TIER_0_AMOUNT["unit_amount"] = 0
FAKE_PRICE_TIER_0_AMOUNT["unit_amount_decimal"] = 0
return FAKE_PRICE_TIER_0_AMOUNT
tests.test_price.TestHumanReadablePrice.get_fake_price_0_flat_amount()
Source code in tests/test_price.py
def get_fake_price_0_flat_amount():
FAKE_PRICE_TIER_0_FLAT_AMOUNT = deepcopy(FAKE_PRICE_TIER)
FAKE_PRICE_TIER_0_FLAT_AMOUNT["tiers"][0]["flat_amount"] = 0
FAKE_PRICE_TIER_0_FLAT_AMOUNT["tiers"][0]["flat_amount_decimal"] = 0
return FAKE_PRICE_TIER_0_FLAT_AMOUNT
tests.test_price.TestHumanReadablePrice.get_fake_price_NONE_flat_amount()
Source code in tests/test_price.py
def get_fake_price_NONE_flat_amount():
FAKE_PRICE_TIER_NONE_FLAT_AMOUNT = deepcopy(FAKE_PRICE_TIER)
FAKE_PRICE_TIER_NONE_FLAT_AMOUNT["tiers"][0]["flat_amount"] = None
FAKE_PRICE_TIER_NONE_FLAT_AMOUNT["tiers"][0]["flat_amount_decimal"] = None
return FAKE_PRICE_TIER_NONE_FLAT_AMOUNT
tests.test_price.TestHumanReadablePrice.test_human_readable(self, fake_price_data, expected_str, monkeypatch)
Source code in tests/test_price.py
@pytest.mark.parametrize(
"fake_price_data, expected_str",
[
(deepcopy(FAKE_PRICE), "$20.00 USD/month"),
(get_fake_price_0_amount(), "$0.00 USD/month"),
(deepcopy(FAKE_PRICE_ONETIME), "$20.00 USD (one time)"),
(
deepcopy(FAKE_PRICE_TIER),
"Starts at $10.00 USD per unit + $49.00 USD/month",
),
(
get_fake_price_0_flat_amount(),
"Starts at $10.00 USD per unit + $0.00 USD/month",
),
(
get_fake_price_NONE_flat_amount(),
"Starts at $10.00 USD per unit/month",
),
(deepcopy(FAKE_PRICE_METERED), "$2.00 USD/month"),
],
)
def test_human_readable(self, fake_price_data, expected_str, monkeypatch):
def mock_product_get(*args, **kwargs):
return deepcopy(FAKE_PRODUCT)
def mock_price_get(*args, **kwargs):
return fake_price_data
# monkeypatch stripe.Product.retrieve and stripe.Price.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Product, "retrieve", mock_product_get)
monkeypatch.setattr(stripe.Price, "retrieve", mock_price_get)
price = Price.sync_from_stripe_data(fake_price_data)
assert price.human_readable_price == expected_str
tests.test_price.TestStrPrice
tests.test_price.TestStrPrice.test___str__(self, fake_price_data, monkeypatch)
Source code in tests/test_price.py
@pytest.mark.parametrize(
"fake_price_data",
[
deepcopy(FAKE_PRICE),
deepcopy(FAKE_PRICE_ONETIME),
deepcopy(FAKE_PRICE_TIER),
deepcopy(FAKE_PRICE_METERED),
],
)
def test___str__(self, fake_price_data, monkeypatch):
def mock_product_get(*args, **kwargs):
return deepcopy(FAKE_PRODUCT)
def mock_price_get(*args, **kwargs):
return fake_price_data
# monkeypatch stripe.Product.retrieve and stripe.Price.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Product, "retrieve", mock_product_get)
monkeypatch.setattr(stripe.Price, "retrieve", mock_price_get)
if not fake_price_data["recurring"]:
price = Price.sync_from_stripe_data(fake_price_data)
assert (f"{price.human_readable_price} for {FAKE_PRODUCT['name']}") == str(
price
)
else:
price = Price.sync_from_stripe_data(fake_price_data)
subscriptions = Subscription.objects.filter(plan__id=price.id).count()
assert (
f"{price.human_readable_price} for {FAKE_PRODUCT['name']} ({subscriptions} subscriptions)"
) == str(price)
tests.test_product
dj-stripe Product model tests
tests.test_product.pytestmark
tests.test_product.TestProduct
tests.test_product.TestProduct.mock_account_retrieve(*args, **kwargs)
Source code in tests/test_product.py
def mock_account_retrieve(*args, **kwargs):
return deepcopy(FAKE_PLATFORM_ACCOUNT)
tests.test_product.TestProduct.mock_file_retrieve(*args, **kwargs)
Source code in tests/test_product.py
def mock_file_retrieve(*args, **kwargs):
return deepcopy(FAKE_FILEUPLOAD_ICON)
tests.test_product.TestProduct.mock_product_get(self, *args, **kwargs)
Source code in tests/test_product.py
def mock_product_get(self, *args, **kwargs):
return deepcopy(FAKE_PRODUCT)
tests.test_product.TestProduct.test___str__(self, count, monkeypatch)
Source code in tests/test_product.py
@pytest.mark.parametrize("count", [1, 2, 3])
def test___str__(self, count, monkeypatch):
def mock_price_get(*args, **kwargs):
return random_price_data
# monkeypatch stripe.Product.retrieve and stripe.Price.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Product, "retrieve", self.mock_product_get)
monkeypatch.setattr(stripe.Price, "retrieve", mock_price_get)
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
PRICE_DATA_OPTIONS = [
deepcopy(FAKE_PRICE),
deepcopy(FAKE_PRICE_TIER),
deepcopy(FAKE_PRICE_METERED),
deepcopy(FAKE_PRICE_ONETIME),
]
for _ in range(count):
random_price_data = PRICE_DATA_OPTIONS.pop()
price = Price.sync_from_stripe_data(random_price_data)
if count > 1:
assert f"{FAKE_PRODUCT['name']} ({count} prices)" == str(product)
else:
assert f"{FAKE_PRODUCT['name']} ({price.human_readable_price})" == str(
product
)
tests.test_product.TestProduct.test_sync_from_stripe_data(self, monkeypatch)
Source code in tests/test_product.py
def test_sync_from_stripe_data(self, monkeypatch):
# monkeypatch stripe.Product.retrieve call to return
# the desired json response.
monkeypatch.setattr(stripe.Product, "retrieve", self.mock_product_get)
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
assert product.id == FAKE_PRODUCT["id"]
assert product.name == FAKE_PRODUCT["name"]
assert product.type == FAKE_PRODUCT["type"]
tests.test_refund
dj-stripe Charge Model Tests.
Classes
tests.test_refund.RefundTest
Methods
tests.test_refund.RefundTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_refund.py
def setUp(self):
# create a Stripe Platform Account
self.account = FAKE_PLATFORM_ACCOUNT.create()
user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(user)
self.default_expected_blank_fks = {
"djstripe.Account.branding_logo",
"djstripe.Account.branding_icon",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.refund",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
"djstripe.Refund.failure_balance_transaction",
}
tests.test_refund.RefundTest.test___str__(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_refund.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test___str__(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
# TODO - remove invoice sync
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
fake_refund = deepcopy(FAKE_REFUND)
fake_refund["reason"] = enums.RefundReason.requested_by_customer
balance_transaction_retrieve_mock.return_value = deepcopy(
FAKE_BALANCE_TRANSACTION_REFUND
)
refund = Refund.sync_from_stripe_data(fake_refund)
self.assertEqual(
f"{refund.human_readable_amount} ({enums.RefundStatus.humanize(fake_refund['status'])})",
str(refund),
)
self.assert_fks(refund, expected_blank_fks=self.default_expected_blank_fks)
tests.test_refund.RefundTest.test_reason_enum(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_refund.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_reason_enum(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
# TODO - remove invoice sync
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
balance_transaction_retrieve_mock.return_value = deepcopy(
FAKE_BALANCE_TRANSACTION_REFUND
)
fake_refund = deepcopy(FAKE_REFUND)
for reason in (
"duplicate",
"fraudulent",
"requested_by_customer",
"expired_uncaptured_charge",
):
fake_refund["reason"] = reason
refund = Refund.sync_from_stripe_data(fake_refund)
self.assertEqual(refund.reason, reason)
# trigger model field validation (including enum value choices check)
refund.full_clean()
self.assert_fks(refund, expected_blank_fks=self.default_expected_blank_fks)
tests.test_refund.RefundTest.test_status_enum(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_refund.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_status_enum(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
# TODO - remove invoice sync
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
balance_transaction_retrieve_mock.return_value = deepcopy(
FAKE_BALANCE_TRANSACTION_REFUND
)
fake_refund = deepcopy(FAKE_REFUND)
for status in (
"pending",
"succeeded",
"failed",
"canceled",
):
fake_refund["status"] = status
refund = Refund.sync_from_stripe_data(fake_refund)
self.assertEqual(refund.status, status)
# trigger model field validation (including enum value choices check)
refund.full_clean()
self.assert_fks(refund, expected_blank_fks=self.default_expected_blank_fks)
tests.test_refund.RefundTest.test_sync_from_stripe_data(self, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock, default_account_mock)
Source code in tests/test_refund.py
@patch(
"djstripe.models.Account.get_default_account",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_sync_from_stripe_data(
self,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
default_account_mock,
):
default_account_mock.return_value = self.account
# TODO - remove invoice sync
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
fake_refund = deepcopy(FAKE_REFUND)
balance_transaction_retrieve_mock.return_value = deepcopy(
FAKE_BALANCE_TRANSACTION_REFUND
)
refund = Refund.sync_from_stripe_data(fake_refund)
self.assert_fks(refund, expected_blank_fks=self.default_expected_blank_fks)
tests.test_session
dj-stripe Session Model Tests.
tests.test_session.pytestmark
Classes
tests.test_session.SessionTest
tests.test_session.SessionTest.test___str__(self, payment_intent_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_session.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
def test___str__(self, payment_intent_retrieve_mock, customer_retrieve_mock):
fake_payment_intent = deepcopy(FAKE_SESSION_I)
session = Session.sync_from_stripe_data(fake_payment_intent)
self.assertEqual(f"<id={FAKE_SESSION_I['id']}>", str(session))
self.assert_fks(
session,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.Session.subscription",
},
)
tests.test_session.SessionTest.test_sync_from_stripe_data(self, payment_intent_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_session.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
def test_sync_from_stripe_data(
self, payment_intent_retrieve_mock, customer_retrieve_mock
):
fake_payment_intent = deepcopy(FAKE_SESSION_I)
session = Session.sync_from_stripe_data(fake_payment_intent)
self.assert_fks(
session,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.Session.subscription",
},
)
tests.test_session.TestSession
tests.test_session.TestSession.key
Methods
tests.test_session.TestSession.test__attach_objects_post_save_hook(self, monkeypatch, fake_user, fake_customer, metadata)
Test for Checkout Session _attach_objects_post_save_hook
Source code in tests/test_session.py
@pytest.mark.parametrize(
"metadata",
[
{},
{"key1": "val1", key: "random"},
],
)
def test__attach_objects_post_save_hook(
self, monkeypatch, fake_user, fake_customer, metadata
):
"""
Test for Checkout Session _attach_objects_post_save_hook
"""
user = fake_user
customer = fake_customer
# because create_for_user method adds subscriber
customer.subcriber = None
customer.save()
# update metadata
if metadata.get(self.key, ""):
metadata[self.key] = user.id
fake_stripe_session = deepcopy(FAKE_SESSION_I)
fake_stripe_session["metadata"] = metadata
def patched_checkout_session(*args, **kwargs):
"""Monkeypatched stripe.Session.retrieve"""
return fake_stripe_session
def patched_customer(*args, **kwargs):
"""Monkeypatched stripe.Customer.retrieve"""
fake_customer = deepcopy(FAKE_CUSTOMER)
return fake_customer
def patched_payment_intent(*args, **kwargs):
"""Monkeypatched stripe.PaymentIntent.retrieve"""
fake_payment_intent = deepcopy(FAKE_PAYMENT_INTENT_I)
return fake_payment_intent
# monkeypatch stripe.checkout.Session.retrieve, stripe.Customer.retrieve, stripe.PaymentIntent.retrieve
monkeypatch.setattr(
stripe.checkout.Session, "retrieve", patched_checkout_session
)
monkeypatch.setattr(stripe.Customer, "modify", patched_customer)
monkeypatch.setattr(stripe.PaymentIntent, "retrieve", patched_payment_intent)
# Invoke the sync to invoke _attach_objects_post_save_hook()
session = Session.sync_from_stripe_data(fake_stripe_session)
# refresh self.customer from db
customer.refresh_from_db()
assert session.customer.id == customer.id
assert customer.subscriber == user
if metadata.get(self.key, ""):
assert customer.metadata == {self.key: metadata.get(self.key)}
else:
assert customer.metadata == {}
tests.test_settings
dj-stripe Settings Tests.
tests.test_settings.TestGetStripeApiVersion
tests.test_settings.TestGetStripeApiVersion.test_with_default(self)
Source code in tests/test_settings.py
def test_with_default(self):
self.assertEqual(
settings.djstripe_settings.DEFAULT_STRIPE_API_VERSION,
settings.djstripe_settings.STRIPE_API_VERSION,
)
tests.test_settings.TestGetStripeApiVersion.test_with_override(self)
Source code in tests/test_settings.py
@override_settings(STRIPE_API_VERSION="2016-03-07")
def test_with_override(self):
self.assertEqual(
"2016-03-07",
settings.djstripe_settings.STRIPE_API_VERSION,
)
tests.test_settings.TestObjectPatching
tests.test_settings.TestObjectPatching.test_object_patching(self, mock)
Source code in tests/test_settings.py
@patch.object(
settings.djstripe_settings,
"DJSTRIPE_WEBHOOK_URL",
return_value=r"^webhook/sample/$",
)
def test_object_patching(self, mock):
webhook_url = settings.djstripe_settings.DJSTRIPE_WEBHOOK_URL
self.assertTrue(webhook_url, r"^webhook/sample/$")
tests.test_settings.TestSetStripeApiVersion
tests.test_settings.TestSetStripeApiVersion.test_with_default(self)
Source code in tests/test_settings.py
def test_with_default(self):
settings.djstripe_settings.set_stripe_api_version()
self.assertEqual(
settings.djstripe_settings.DEFAULT_STRIPE_API_VERSION, stripe.api_version
)
tests.test_settings.TestSetStripeApiVersion.test_with_invalid_date(self)
Source code in tests/test_settings.py
def test_with_invalid_date(self):
with self.assertRaises(ValueError):
settings.djstripe_settings.set_stripe_api_version(version="foobar")
tests.test_settings.TestSetStripeApiVersion.test_with_invalid_date_and_no_validation(self)
Source code in tests/test_settings.py
def test_with_invalid_date_and_no_validation(self):
settings.djstripe_settings.set_stripe_api_version(
version="foobar", validate=False
)
self.assertEqual("foobar", stripe.api_version)
tests.test_settings.TestSetStripeApiVersion.test_with_valid_date(self)
Source code in tests/test_settings.py
def test_with_valid_date(self):
settings.djstripe_settings.set_stripe_api_version(version="2016-03-07")
self.assertEqual("2016-03-07", stripe.api_version)
tests.test_settings.TestSubscriberModelRetrievalMethod
tests.test_settings.TestSubscriberModelRetrievalMethod.test_bad_callback(self)
Source code in tests/test_settings.py
@override_settings(
DJSTRIPE_SUBSCRIBER_MODEL="testapp.Organization",
DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK=5,
)
def test_bad_callback(self):
self.assertRaisesMessage(
ImproperlyConfigured,
"DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK must be callable.",
settings.djstripe_settings.get_subscriber_model,
)
tests.test_settings.TestSubscriberModelRetrievalMethod.test_bad_model_name(self)
Source code in tests/test_settings.py
@override_settings(
DJSTRIPE_SUBSCRIBER_MODEL="testappStaticEmailOrganization",
DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK=(lambda request: request.org),
)
def test_bad_model_name(self):
self.assertRaisesMessage(
ImproperlyConfigured,
"DJSTRIPE_SUBSCRIBER_MODEL must be of the form 'app_label.model_name'.",
settings.djstripe_settings.get_subscriber_model,
)
tests.test_settings.TestSubscriberModelRetrievalMethod.test_get_callback_function_(self)
Source code in tests/test_settings.py
@override_settings(DJSTRIPE_TEST_CALLBACK="foo.non_existant_callback")
def test_get_callback_function_(self):
with self.assertRaises(ImportError):
settings.djstripe_settings.get_callback_function("DJSTRIPE_TEST_CALLBACK")
tests.test_settings.TestSubscriberModelRetrievalMethod.test_get_callback_function_import_error(self)
Source code in tests/test_settings.py
@override_settings(DJSTRIPE_TEST_CALLBACK="foo.non_existant_callback")
def test_get_callback_function_import_error(self):
with self.assertRaises(ImportError):
settings.djstripe_settings.get_callback_function("DJSTRIPE_TEST_CALLBACK")
tests.test_settings.TestSubscriberModelRetrievalMethod.test_get_callback_function_with_non_callable_string(self, import_string_mock)
Source code in tests/test_settings.py
@override_settings(DJSTRIPE_TEST_CALLBACK="foo.invalid_callback")
@patch.object(settings, "import_string", return_value="not_callable")
def test_get_callback_function_with_non_callable_string(self, import_string_mock):
with self.assertRaises(ImproperlyConfigured):
settings.djstripe_settings.get_callback_function("DJSTRIPE_TEST_CALLBACK")
import_string_mock.assert_called_with("foo.invalid_callback")
tests.test_settings.TestSubscriberModelRetrievalMethod.test_get_callback_function_with_valid_func_callable(self)
Source code in tests/test_settings.py
@override_settings(DJSTRIPE_TEST_CALLBACK=(lambda: "ok"))
def test_get_callback_function_with_valid_func_callable(self):
func = settings.djstripe_settings.get_callback_function(
"DJSTRIPE_TEST_CALLBACK"
)
self.assertEqual("ok", func())
tests.test_settings.TestSubscriberModelRetrievalMethod.test_get_callback_function_with_valid_string_callable(self, import_string_mock)
Source code in tests/test_settings.py
@override_settings(DJSTRIPE_TEST_CALLBACK="foo.valid_callback")
@patch.object(settings, "import_string", return_value=(lambda: "ok"))
def test_get_callback_function_with_valid_string_callable(self, import_string_mock):
func = settings.djstripe_settings.get_callback_function(
"DJSTRIPE_TEST_CALLBACK"
)
self.assertEqual("ok", func())
import_string_mock.assert_called_with("foo.valid_callback")
tests.test_settings.TestSubscriberModelRetrievalMethod.test_no_callback(self)
Source code in tests/test_settings.py
@override_settings(DJSTRIPE_SUBSCRIBER_MODEL="testapp.Organization")
def test_no_callback(self):
self.assertRaisesMessage(
ImproperlyConfigured,
"DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK must be implemented "
"if a DJSTRIPE_SUBSCRIBER_MODEL is defined.",
settings.djstripe_settings.get_subscriber_model,
)
tests.test_settings.TestSubscriberModelRetrievalMethod.test_no_email_model(self)
Source code in tests/test_settings.py
@override_settings(
DJSTRIPE_SUBSCRIBER_MODEL="testapp.NoEmailOrganization",
DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK=(lambda request: request.org),
)
def test_no_email_model(self):
self.assertRaisesMessage(
ImproperlyConfigured,
"DJSTRIPE_SUBSCRIBER_MODEL must have an email attribute.",
settings.djstripe_settings.get_subscriber_model,
)
tests.test_settings.TestSubscriberModelRetrievalMethod.test_unknown_model(self)
Source code in tests/test_settings.py
@override_settings(
DJSTRIPE_SUBSCRIBER_MODEL="testapp.UnknownModel",
DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK=(lambda request: request.org),
)
def test_unknown_model(self):
self.assertRaisesMessage(
ImproperlyConfigured,
"DJSTRIPE_SUBSCRIBER_MODEL refers to model 'testapp.UnknownModel' "
"that has not been installed.",
settings.djstripe_settings.get_subscriber_model,
)
tests.test_settings.TestSubscriberModelRetrievalMethod.test_with_org(self)
Source code in tests/test_settings.py
@override_settings(
DJSTRIPE_SUBSCRIBER_MODEL="testapp.Organization",
DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK=(lambda request: request.org),
)
def test_with_org(self):
org_model = settings.djstripe_settings.get_subscriber_model()
self.assertTrue(isinstance(org_model, ModelBase))
tests.test_settings.TestSubscriberModelRetrievalMethod.test_with_org_static(self)
Source code in tests/test_settings.py
@override_settings(
DJSTRIPE_SUBSCRIBER_MODEL="testapp.StaticEmailOrganization",
DJSTRIPE_SUBSCRIBER_MODEL_REQUEST_CALLBACK=(lambda request: request.org),
)
def test_with_org_static(self):
org_model = settings.djstripe_settings.get_subscriber_model()
self.assertTrue(isinstance(org_model, ModelBase))
tests.test_settings.TestSubscriberModelRetrievalMethod.test_with_user(self)
Source code in tests/test_settings.py
def test_with_user(self):
user_model = settings.djstripe_settings.get_subscriber_model()
self.assertTrue(isinstance(user_model, ModelBase))
tests.test_setup_intent
dj-stripe SetupIntent Model Tests.
tests.test_setup_intent.pytestmark
tests.test_setup_intent.SetupIntentTest
tests.test_setup_intent.SetupIntentTest.test_canceled_intent(self, customer_retrieve_mock)
Source code in tests/test_setup_intent.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_canceled_intent(self, customer_retrieve_mock):
fake_setup_intent = deepcopy(FAKE_SETUP_INTENT_I)
fake_setup_intent["status"] = "canceled"
fake_setup_intent["canceled_at"] = 1567524169
for reason in (None, "abandoned", "requested_by_customer", "duplicate"):
fake_setup_intent["cancellation_reason"] = reason
setup_intent = SetupIntent.sync_from_stripe_data(fake_setup_intent)
if reason is None:
# enums nulls are coerced to "" by StripeModel._stripe_object_to_record
self.assertEqual(setup_intent.cancellation_reason, "")
else:
self.assertEqual(setup_intent.cancellation_reason, reason)
# trigger model field validation (including enum value choices check)
setup_intent.full_clean()
tests.test_setup_intent.SetupIntentTest.test_status_enum(self, customer_retrieve_mock)
Source code in tests/test_setup_intent.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_status_enum(self, customer_retrieve_mock):
fake_setup_intent = deepcopy(FAKE_SETUP_INTENT_I)
for status in (
"requires_payment_method",
"requires_confirmation",
"requires_action",
"processing",
"canceled",
"succeeded",
):
fake_setup_intent["status"] = status
setup_intent = SetupIntent.sync_from_stripe_data(fake_setup_intent)
# trigger model field validation (including enum value choices check)
setup_intent.full_clean()
tests.test_setup_intent.SetupIntentTest.test_sync_from_stripe_data(self, customer_retrieve_mock)
Source code in tests/test_setup_intent.py
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_from_stripe_data(self, customer_retrieve_mock):
fake_payment_intent = deepcopy(FAKE_SETUP_INTENT_I)
setup_intent = SetupIntent.sync_from_stripe_data(fake_payment_intent)
self.assertEqual(setup_intent.payment_method_types, ["card"])
self.assert_fks(
setup_intent,
expected_blank_fks={
"djstripe.SetupIntent.customer",
"djstripe.SetupIntent.on_behalf_of",
"djstripe.SetupIntent.payment_method",
},
)
tests.test_setup_intent.TestStrSetupIntent
tests.test_setup_intent.TestStrSetupIntent.get_fake_setup_intent_destination_charge_no_customer()
Source code in tests/test_setup_intent.py
def get_fake_setup_intent_destination_charge_no_customer():
FAKE_SETUP_INTENT_DESTINATION_CHARGE_NO_CUSTOMER = deepcopy(
FAKE_SETUP_INTENT_DESTINATION_CHARGE
)
FAKE_SETUP_INTENT_DESTINATION_CHARGE_NO_CUSTOMER["customer"] = None
return FAKE_SETUP_INTENT_DESTINATION_CHARGE_NO_CUSTOMER
tests.test_setup_intent.TestStrSetupIntent.test___str__(self, fake_intent_data, has_account, has_customer, monkeypatch)
Source code in tests/test_setup_intent.py
@pytest.mark.parametrize(
"fake_intent_data, has_account, has_customer",
[
(FAKE_SETUP_INTENT_I, False, False),
(FAKE_SETUP_INTENT_DESTINATION_CHARGE, True, True),
(get_fake_setup_intent_destination_charge_no_customer(), True, False),
(FAKE_SETUP_INTENT_II, False, True),
],
)
def test___str__(self, fake_intent_data, has_account, has_customer, monkeypatch):
def mock_customer_get(*args, **kwargs):
return deepcopy(FAKE_CUSTOMER)
def mock_account_get(*args, **kwargs):
return deepcopy(FAKE_STANDARD_ACCOUNT)
def mock_payment_method_get(*args, **kwargs):
return deepcopy(FAKE_PAYMENT_METHOD_I)
# monkeypatch stripe.Account.retrieve, stripe.Customer.retrieve, and stripe.PaymentMethod.retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Account, "retrieve", mock_account_get)
monkeypatch.setattr(stripe.Customer, "retrieve", mock_customer_get)
monkeypatch.setattr(stripe.PaymentMethod, "retrieve", mock_payment_method_get)
si = SetupIntent.sync_from_stripe_data(fake_intent_data)
pm = PaymentMethod.objects.filter(id=fake_intent_data["payment_method"]).first()
account = Account.objects.filter(id=fake_intent_data["on_behalf_of"]).first()
customer = Customer.objects.filter(id=fake_intent_data["customer"]).first()
if has_account and has_customer:
assert (
f"{pm} ({SetupIntentStatus.humanize(fake_intent_data['status'])}) "
f"for {account} "
f"by {customer}"
) == str(si)
elif has_account and not has_customer:
assert (
f"{pm} for {account}. {SetupIntentStatus.humanize(fake_intent_data['status'])}"
) == str(si)
elif has_customer and not has_account:
assert (
f"{pm} by {customer}. {SetupIntentStatus.humanize(fake_intent_data['status'])}"
) == str(si)
elif not has_customer and not has_account:
f"{pm} ({SetupIntentStatus.humanize(fake_intent_data['status'])})" == str(
si
)
tests.test_source
dj-stripe Card Model Tests.
Classes
tests.test_source.SourceTest
Methods
tests.test_source.SourceTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_source.py
def setUp(self):
user = get_user_model().objects.create_user(
username="testuser", email="djstripe@example.com"
)
# create a source object so that FAKE_CUSTOMER_III with a default source
# can be created correctly.
fake_source_data = deepcopy(FAKE_SOURCE)
fake_source_data["customer"] = None
self.source = Source.sync_from_stripe_data(fake_source_data)
self.customer = FAKE_CUSTOMER_III.create_for_user(user)
self.customer.sources.all().delete()
self.customer.legacy_cards.all().delete()
tests.test_source.SourceTest.test___str__(self)
Source code in tests/test_source.py
def test___str__(self):
fake_source = deepcopy(FAKE_SOURCE)
source = Source.sync_from_stripe_data(fake_source)
customer = Customer.objects.get(id=fake_source["customer"])
self.assertEqual(
f"<type={fake_source['type']}, "
f"status={fake_source['status']}, "
f"customer={customer}, "
f"usage={fake_source['usage']}, "
f"id={fake_source['id']}>",
str(source),
)
self.assert_fks(
source,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_source.SourceTest.test_attach_objects_hook_without_customer(self)
Source code in tests/test_source.py
def test_attach_objects_hook_without_customer(self):
source = Source.sync_from_stripe_data(deepcopy(FAKE_SOURCE_II))
self.assertEqual(source.customer, None)
self.assert_fks(
source,
expected_blank_fks={
"djstripe.Source.customer",
"djstripe.Customer.default_payment_method",
},
)
tests.test_source.SourceTest.test_detach(self, source_retrieve_mock)
Source code in tests/test_source.py
@patch("stripe.Source.retrieve", return_value=deepcopy(FAKE_SOURCE), autospec=True)
def test_detach(self, source_retrieve_mock):
original_detach = SourceDict.detach
def mocked_detach(self):
return original_detach(self)
Source.sync_from_stripe_data(deepcopy(FAKE_SOURCE))
self.assertEqual(0, self.customer.legacy_cards.count())
self.assertEqual(1, self.customer.sources.count())
source = self.customer.sources.first()
with patch(
"tests.SourceDict.detach", side_effect=mocked_detach, autospec=True
) as mock_detach:
source.detach()
self.assertEqual(0, self.customer.sources.count())
# need to refresh_from_db since default_source was cleared with a query
self.customer.refresh_from_db()
self.assertIsNone(self.customer.default_source)
# need to refresh_from_db due to the implementation of Source.detach() -
# see TODO in method
source.refresh_from_db()
self.assertIsNone(source.customer)
self.assertEqual(source.status, "consumed")
if sys.version_info >= (3, 6):
# this mock isn't working on py34, py35, but it's not strictly necessary
# for the test
mock_detach.assert_called()
self.assert_fks(
source,
expected_blank_fks={
"djstripe.Source.customer",
"djstripe.Customer.default_payment_method",
},
)
tests.test_source.SourceTest.test_sync_source_finds_customer(self)
Source code in tests/test_source.py
def test_sync_source_finds_customer(self):
source = Source.sync_from_stripe_data(deepcopy(FAKE_SOURCE))
self.assertEqual(self.customer, source.customer)
self.assert_fks(
source,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
},
)
tests.test_stripe_model
dj-stripe StripeModel Model Tests.
tests.test_stripe_model.pytestmark
Classes
tests.test_stripe_model.TestStripeModel
TestStripeModel(djstripe_created, djstripe_updated, djstripe_id, id, djstripe_owner_account, livemode, created, metadata, description)
tests.test_stripe_model.TestStripeModel.djstripe_owner_account: Optional[djstripe.fields.StripeForeignKey]
tests.test_stripe_model.TestStripeModel.DoesNotExist
tests.test_stripe_model.TestStripeModel.MultipleObjectsReturned
tests.test_stripe_model.TestStripeModel.get_next_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=True, **kwargs)
Source code in tests/test_stripe_model.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
tests.test_stripe_model.TestStripeModel.get_next_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=True, **kwargs)
Source code in tests/test_stripe_model.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
tests.test_stripe_model.TestStripeModel.get_previous_by_djstripe_created(self, *, field=<django.db.models.fields.DateTimeField: djstripe_created>, is_next=False, **kwargs)
Source code in tests/test_stripe_model.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
tests.test_stripe_model.TestStripeModel.get_previous_by_djstripe_updated(self, *, field=<django.db.models.fields.DateTimeField: djstripe_updated>, is_next=False, **kwargs)
Source code in tests/test_stripe_model.py
def _method(cls_or_self, /, *args, **keywords):
keywords = {**self.keywords, **keywords}
return self.func(cls_or_self, *self.args, *args, **keywords)
tests.test_stripe_model.TestStripeModelExceptions
tests.test_stripe_model.TestStripeModelExceptions.test_bad_object_value(self)
Source code in tests/test_stripe_model.py
def test_bad_object_value(self):
with self.assertRaises(ValueError):
# Errors because the object is not correct
Customer._stripe_object_to_record(
{"id": "test_XXXXXXXX", "livemode": False, "object": "not_a_customer"}
)
tests.test_stripe_model.TestStripeModelExceptions.test_no_object_value(self)
Source code in tests/test_stripe_model.py
def test_no_object_value(self):
# Instantiate a stripeobject model class
class BasicModel(StripeModel):
pass
with self.assertRaises(ValueError):
# Errors because there's no object value
BasicModel._stripe_object_to_record(
{"id": "test_XXXXXXXX", "livemode": False}
)
Functions
tests.test_stripe_model.test__api_delete(mock_stripe_class, stripe_account, api_key, expected_api_key, extra_kwargs)
Test that API delete properly uses the passed in parameters.
Source code in tests/test_stripe_model.py
@pytest.mark.parametrize("stripe_account", (None, "acct_fakefakefakefake001"))
@pytest.mark.parametrize(
"api_key, expected_api_key",
(
(None, djstripe_settings.STRIPE_SECRET_KEY),
("sk_fakefakefake01", "sk_fakefakefake01"),
),
)
@pytest.mark.parametrize("extra_kwargs", ({}, {"foo": "bar"}))
@patch.object(target=StripeModel, attribute="stripe_class")
def test__api_delete(
mock_stripe_class, stripe_account, api_key, expected_api_key, extra_kwargs
):
"""Test that API delete properly uses the passed in parameters."""
test_model = TestStripeModel()
mock_id = "id_fakefakefakefake01"
test_model.id = mock_id
# invoke _api_delete()
test_model._api_delete(
api_key=api_key, stripe_account=stripe_account, **extra_kwargs
)
mock_stripe_class.delete.assert_called_once_with(
mock_id, api_key=expected_api_key, stripe_account=stripe_account, **extra_kwargs
)
tests.test_stripe_model.test__find_owner_account(mock__get_or_retrieve, mock_get_or_retrieve_for_api_key, api_key, stripe_account, has_stripe_account_attr, monkeypatch)
Test that the correct classmethod is invoked with the correct arguments to get the owner account
Source code in tests/test_stripe_model.py
@pytest.mark.parametrize(
"has_stripe_account_attr,stripe_account",
((False, None), (True, ""), (True, "acct_fakefakefakefake001")),
)
@pytest.mark.parametrize("api_key", (None, "sk_fakefakefake01"))
@patch.object(target=Account, attribute="get_or_retrieve_for_api_key")
@patch.object(target=Account, attribute="_get_or_retrieve")
def test__find_owner_account(
mock__get_or_retrieve,
mock_get_or_retrieve_for_api_key,
api_key,
stripe_account,
has_stripe_account_attr,
monkeypatch,
):
"""
Test that the correct classmethod is invoked with the correct arguments
to get the owner account
"""
# fake_data_class used to invoke _find_owner_account classmethod
class fake_data_class:
@property
def stripe_account(self):
return stripe_account
def get(*args, **kwargs):
return "customer"
fake_data = fake_data_class()
if api_key is None:
# invoke _find_owner_account without the api_key parameter
StripeModel._find_owner_account(fake_data)
else:
# invoke _find_owner_account with the api_key parameter
StripeModel._find_owner_account(fake_data, api_key=api_key)
if has_stripe_account_attr and stripe_account:
mock__get_or_retrieve.assert_called_once_with(id=stripe_account)
else:
if api_key:
mock_get_or_retrieve_for_api_key.assert_called_once_with(api_key)
else:
mock_get_or_retrieve_for_api_key.assert_called_once_with(
djstripe_settings.STRIPE_SECRET_KEY
)
tests.test_stripe_model.test__find_owner_account_for_empty_data(mock_get_or_retrieve_for_api_key, api_key)
Test that the correct classmethod is invoked with the correct arguments to get the owner account
Source code in tests/test_stripe_model.py
@pytest.mark.parametrize("api_key", (None, "sk_fakefakefake01"))
@patch.object(target=Account, attribute="get_or_retrieve_for_api_key")
def test__find_owner_account_for_empty_data(
mock_get_or_retrieve_for_api_key,
api_key,
):
"""
Test that the correct classmethod is invoked with the correct arguments
to get the owner account
"""
fake_data = {}
if api_key is None:
# invoke _find_owner_account without the api_key parameter
StripeModel._find_owner_account(fake_data)
else:
# invoke _find_owner_account with the api_key parameter
StripeModel._find_owner_account(fake_data, api_key=api_key)
if api_key:
mock_get_or_retrieve_for_api_key.assert_called_once_with(api_key)
else:
mock_get_or_retrieve_for_api_key.assert_called_once_with(
djstripe_settings.STRIPE_SECRET_KEY
)
tests.test_stripe_model.test__find_owner_account_for_webhook_event_trigger(mock__get_or_retrieve, mock_get_or_retrieve_for_api_key, api_key, stripe_account, has_account_key)
Test that the correct classmethod is invoked with the correct arguments to get the owner account
Source code in tests/test_stripe_model.py
@pytest.mark.parametrize(
"has_account_key,stripe_account",
((False, None), (True, ""), (True, "acct_fakefakefakefake001")),
)
@pytest.mark.parametrize("api_key", (None, "sk_fakefakefake01"))
@patch.object(target=Account, attribute="get_or_retrieve_for_api_key")
@patch.object(target=Account, attribute="_get_or_retrieve")
def test__find_owner_account_for_webhook_event_trigger(
mock__get_or_retrieve,
mock_get_or_retrieve_for_api_key,
api_key,
stripe_account,
has_account_key,
):
"""
Test that the correct classmethod is invoked with the correct arguments
to get the owner account
"""
# should fake_data have the account key
if has_account_key:
# fake_data used to invoke _find_owner_account classmethod
fake_data = {
"id": "test_XXXXXXXX",
"livemode": False,
"object": "event",
"account": stripe_account,
}
else:
# fake_data used to invoke _find_owner_account classmethod
fake_data = {
"id": "test_XXXXXXXX",
"livemode": False,
"object": "event",
}
if api_key is None:
# invoke _find_owner_account without the api_key parameter
StripeModel._find_owner_account(fake_data)
else:
# invoke _find_owner_account with the api_key parameter
StripeModel._find_owner_account(fake_data, api_key=api_key)
if has_account_key and stripe_account:
mock__get_or_retrieve.assert_called_once_with(id=stripe_account)
else:
if api_key:
mock_get_or_retrieve_for_api_key.assert_called_once_with(api_key)
else:
mock_get_or_retrieve_for_api_key.assert_called_once_with(
djstripe_settings.STRIPE_SECRET_KEY
)
tests.test_stripe_model.test_api_retrieve(mock_stripe_class, stripe_account, api_key, expected_api_key, expand_fields)
Test that API delete properly uses the passed in parameters.
Source code in tests/test_stripe_model.py
@pytest.mark.parametrize("stripe_account", (None, "acct_fakefakefakefake001"))
@pytest.mark.parametrize(
"api_key, expected_api_key",
(
(None, djstripe_settings.STRIPE_SECRET_KEY),
("sk_fakefakefake01", "sk_fakefakefake01"),
),
)
@pytest.mark.parametrize("expand_fields", ([], ["foo", "bar"]))
@patch.object(target=StripeModel, attribute="stripe_class")
def test_api_retrieve(
mock_stripe_class, stripe_account, api_key, expected_api_key, expand_fields
):
"""Test that API delete properly uses the passed in parameters."""
test_model = TestStripeModel()
mock_id = "id_fakefakefakefake01"
test_model.id = mock_id
test_model.expand_fields = expand_fields
test_model.api_retrieve(api_key=api_key, stripe_account=stripe_account)
mock_stripe_class.retrieve.assert_called_once_with(
id=mock_id,
api_key=expected_api_key,
stripe_account=stripe_account,
expand=expand_fields,
)
tests.test_stripe_model.test_api_retrieve_reverse_foreign_key_lookup(mock_stripe_class)
Test that the reverse foreign key lookup finds the correct fields.
Source code in tests/test_stripe_model.py
@patch.object(target=StripeModel, attribute="stripe_class")
def test_api_retrieve_reverse_foreign_key_lookup(mock_stripe_class):
"""Test that the reverse foreign key lookup finds the correct fields."""
# Set up some mock fields that shouldn't be used for reverse lookups
mock_field_1 = MagicMock()
mock_field_1.is_relation = False
mock_field_2 = MagicMock()
mock_field_2.is_relation = True
mock_field_2.one_to_many = False
# Set up a mock reverse foreign key field
mock_reverse_foreign_key = MagicMock()
mock_reverse_foreign_key.is_relation = True
mock_reverse_foreign_key.one_to_many = True
mock_reverse_foreign_key.related_model = Account
mock_reverse_foreign_key.get_accessor_name.return_value = "foo_account_reverse_attr"
# Set up a mock account for the reverse foreign key query to return.
mock_account = MagicMock()
mock_account_reverse_manager = MagicMock()
# Make first return the mock account.
mock_account_reverse_manager.first.return_value = mock_account
test_model = TestStripeModel()
mock_id = "id_fakefakefakefake01"
test_model.id = mock_id
# Set mock reverse manager on the model.
test_model.foo_account_reverse_attr = mock_account_reverse_manager
# Set the mocked _meta.get_fields to return some mock fields, including the mock
# reverse foreign key above.
test_model._meta = MagicMock()
test_model._meta.get_fields.return_value = (
mock_field_1,
mock_field_2,
mock_reverse_foreign_key,
)
# Call the function with API key set because we mocked _meta
mock_api_key = "sk_fakefakefakefake01"
test_model.api_retrieve(api_key=mock_api_key)
# Expect the retrieve to be done with the reverse look up of the Account ID.
mock_stripe_class.retrieve.assert_called_once_with(
id=mock_id, api_key=mock_api_key, stripe_account=mock_account.id, expand=[]
)
mock_reverse_foreign_key.get_accessor_name.assert_called_once_with()
mock_account_reverse_manager.first.assert_called_once_with()
tests.test_subscription
dj-stripe Subscription Model Tests.
tests.test_subscription.pytestmark
Classes
tests.test_subscription.SubscriptionStrTest
Methods
tests.test_subscription.SubscriptionStrTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_subscription.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER_II.create_for_user(self.user)
tests.test_subscription.SubscriptionStrTest.test___str__(self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, subscription_creation_mock)
Source code in tests/test_subscription.py
@patch("djstripe.models.billing.Subscription._api_create", autospec=True)
@patch(
"stripe.Plan.retrieve",
side_effect=[deepcopy(FAKE_PLAN), deepcopy(FAKE_PLAN_II)],
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test___str__(
self,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
subscription_creation_mock,
):
subscription_fake_1 = deepcopy(FAKE_SUBSCRIPTION_III)
subscription_fake_1["current_period_end"] += int(
datetime.timestamp(timezone.now())
)
subscription_fake_1["latest_invoice"] = None
subscription_fake_2 = deepcopy(FAKE_SUBSCRIPTION_II)
subscription_fake_2["current_period_end"] += int(
datetime.timestamp(timezone.now())
)
subscription_fake_2["customer"] = self.customer.id
subscription_fake_2["latest_invoice"] = None
subscription_creation_mock.side_effect = [
subscription_fake_1,
subscription_fake_2,
]
# sync subscriptions (to update the changes just made)
Subscription.sync_from_stripe_data(subscription_fake_1)
Subscription.sync_from_stripe_data(subscription_fake_2)
# refresh self.customer from db
self.customer.refresh_from_db()
# subscribe the customer to 2 plans
self.customer.subscribe(plan=FAKE_PLAN["id"])
self.customer.subscribe(plan=FAKE_PLAN_II["id"])
subscriptions_lst = self.customer._get_valid_subscriptions()
products_lst = [
subscription.plan.product.name
for subscription in subscriptions_lst
if subscription and subscription.plan
]
self.assertEqual(
str(Subscription.objects.get(id=subscription_fake_2["id"])),
f"{self.customer} on {' and '.join(products_lst)}",
)
tests.test_subscription.SubscriptionTest
tests.test_subscription.SubscriptionTest.setUp(self, invoice_retrieve_mock, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_subscription.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Invoice.retrieve", autospec=True, return_value=deepcopy(FAKE_INVOICE)
)
def setUp(
self,
invoice_retrieve_mock,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
self.default_expected_blank_fks = {
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
}
# create latest invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
tests.test_subscription.SubscriptionTest.test_cancel_already_canceled(self, subscription_retrieve_mock, product_retrieve_mock, subscription_delete_mock)
Source code in tests/test_subscription.py
@patch("djstripe.models.Subscription._api_delete", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_CANCELED),
)
def test_cancel_already_canceled(
self,
subscription_retrieve_mock,
product_retrieve_mock,
subscription_delete_mock,
):
subscription_delete_mock.side_effect = InvalidRequestError(
"No such subscription: sub_xxxx", "blah"
)
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assertEqual(Subscription.objects.filter(status="canceled").count(), 0)
subscription.cancel(at_period_end=False)
self.assertEqual(Subscription.objects.filter(status="canceled").count(), 1)
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_cancel_and_reactivate(self, customer_retrieve_mock, subscription_retrieve_mock, subscription_modify_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.modify",
autospec=True,
)
@patch("stripe.Subscription.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_cancel_and_reactivate(
self,
customer_retrieve_mock,
subscription_retrieve_mock,
subscription_modify_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
current_period_end = timezone.now() + timezone.timedelta(days=7)
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.current_period_end = current_period_end
subscription.save()
canceled_subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
canceled_subscription_fake["current_period_end"] = datetime_to_unix(
current_period_end
)
canceled_subscription_fake["canceled_at"] = datetime_to_unix(timezone.now())
subscription_retrieve_mock.return_value = canceled_subscription_fake
self.assertTrue(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertTrue(self.customer.has_any_active_subscription())
# Update the Subscription by cancelling it at the end of the period
subscription_updated = deepcopy(canceled_subscription_fake)
subscription_updated["cancel_at_period_end"] = True
subscription_modify_mock.return_value = subscription_updated
new_subscription = subscription.cancel(at_period_end=True)
self.assertEqual(new_subscription.cancel_at_period_end, True)
new_subscription.reactivate()
subscription_reactivate_fake = deepcopy(FAKE_SUBSCRIPTION)
reactivated_subscription = Subscription.sync_from_stripe_data(
subscription_reactivate_fake
)
self.assertEqual(reactivated_subscription.cancel_at_period_end, False)
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_cancel_at_period_end(self, customer_retrieve_mock, subscription_delete_mock, subscription_modify_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.modify",
autospec=True,
)
@patch("stripe.Subscription.delete", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_cancel_at_period_end(
self,
customer_retrieve_mock,
subscription_delete_mock,
subscription_modify_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
current_period_end = timezone.now() + timezone.timedelta(days=7)
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.current_period_end = current_period_end
subscription.save()
canceled_subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
canceled_subscription_fake["current_period_end"] = datetime_to_unix(
current_period_end
)
canceled_subscription_fake["canceled_at"] = datetime_to_unix(timezone.now())
subscription_delete_mock.return_value = (
canceled_subscription_fake # retrieve().delete()
)
self.assertTrue(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertTrue(self.customer.has_any_active_subscription())
self.assertEqual(self.customer.active_subscriptions.count(), 1)
self.assertTrue(subscription in self.customer.active_subscriptions)
# Update the Subscription by cancelling it at the end of the period
subscription_updated = deepcopy(canceled_subscription_fake)
subscription_updated["cancel_at_period_end"] = True
subscription_modify_mock.return_value = subscription_updated
new_subscription = subscription.cancel(at_period_end=True)
self.assertEqual(self.customer.active_subscriptions.count(), 1)
self.assertTrue(new_subscription in self.customer.active_subscriptions)
self.assertEqual(SubscriptionStatus.active, new_subscription.status)
self.assertEqual(True, new_subscription.cancel_at_period_end)
self.assertNotEqual(new_subscription.canceled_at, new_subscription.ended_at)
self.assertTrue(new_subscription.is_valid())
self.assertTrue(new_subscription.is_status_temporarily_current())
self.assertTrue(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertTrue(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_cancel_during_trial_sets_at_period_end(self, customer_retrieve_mock, subscription_delete_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Subscription.delete", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_cancel_during_trial_sets_at_period_end(
self,
customer_retrieve_mock,
subscription_delete_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.trial_end = timezone.now() + timezone.timedelta(days=7)
subscription.save()
cancel_timestamp = datetime_to_unix(timezone.now())
canceled_subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
canceled_subscription_fake["status"] = SubscriptionStatus.canceled
canceled_subscription_fake["canceled_at"] = cancel_timestamp
canceled_subscription_fake["ended_at"] = cancel_timestamp
subscription_delete_mock.return_value = canceled_subscription_fake
self.assertTrue(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertTrue(self.customer.has_any_active_subscription())
new_subscription = subscription.cancel(at_period_end=False)
self.assertEqual(SubscriptionStatus.canceled, new_subscription.status)
self.assertEqual(False, new_subscription.cancel_at_period_end)
self.assertEqual(new_subscription.canceled_at, new_subscription.ended_at)
self.assertFalse(new_subscription.is_valid())
self.assertFalse(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertFalse(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_cancel_error_in_cancel(self, product_retrieve_mock, subscription_delete_mock)
Source code in tests/test_subscription.py
@patch("djstripe.models.Subscription._api_delete", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
def test_cancel_error_in_cancel(
self, product_retrieve_mock, subscription_delete_mock
):
subscription_delete_mock.side_effect = InvalidRequestError(
"Unexpected error", "blah"
)
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
with self.assertRaises(InvalidRequestError):
subscription.cancel(at_period_end=False)
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_cancel_now(self, customer_retrieve_mock, subscription_delete_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch("stripe.Subscription.delete", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_cancel_now(
self,
customer_retrieve_mock,
subscription_delete_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.current_period_end = timezone.now() + timezone.timedelta(days=7)
subscription.save()
cancel_timestamp = datetime_to_unix(timezone.now())
canceled_subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
canceled_subscription_fake["status"] = SubscriptionStatus.canceled
canceled_subscription_fake["canceled_at"] = cancel_timestamp
canceled_subscription_fake["ended_at"] = cancel_timestamp
subscription_delete_mock.return_value = canceled_subscription_fake
self.assertTrue(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertEqual(self.customer.active_subscriptions.count(), 1)
self.assertTrue(self.customer.has_any_active_subscription())
new_subscription = subscription.cancel(at_period_end=False)
self.assertEqual(SubscriptionStatus.canceled, new_subscription.status)
self.assertEqual(False, new_subscription.cancel_at_period_end)
self.assertEqual(new_subscription.canceled_at, new_subscription.ended_at)
self.assertFalse(new_subscription.is_valid())
self.assertFalse(new_subscription.is_status_temporarily_current())
self.assertFalse(new_subscription in self.customer.active_subscriptions)
self.assertFalse(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertFalse(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_extend(self, customer_retrieve_mock, subscription_retrieve_mock, subscription_modify_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.modify",
autospec=True,
)
@patch("stripe.Subscription.retrieve", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_extend(
self,
customer_retrieve_mock,
subscription_retrieve_mock,
subscription_modify_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
current_period_end = timezone.now() - timezone.timedelta(days=20)
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake["current_period_end"] = int(current_period_end.timestamp())
subscription_retrieve_mock.return_value = subscription_fake
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assertFalse(subscription in self.customer.active_subscriptions)
self.assertEqual(self.customer.active_subscriptions.count(), 0)
# Extend the Subscription by 30 days
delta = timezone.timedelta(days=30)
subscription_updated = deepcopy(subscription_fake)
subscription_updated["trial_end"] = int(
(current_period_end + delta).timestamp()
)
subscription_modify_mock.return_value = subscription_updated
extended_subscription = subscription.extend(delta)
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
self.assertNotEqual(None, extended_subscription.trial_end)
self.assertTrue(self.customer.is_subscribed_to(product))
self.assertTrue(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_extend_negative_delta(self, customer_retrieve_mock, subscription_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_extend_negative_delta(
self,
customer_retrieve_mock,
subscription_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION_NOT_PERIOD_CURRENT)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
with self.assertRaises(ValueError):
subscription.extend(timezone.timedelta(days=-30))
self.assertFalse(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertFalse(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_extend_with_trial(self, customer_retrieve_mock, subscription_retrieve_mock, subscription_modify_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.modify",
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_extend_with_trial(
self,
customer_retrieve_mock,
subscription_retrieve_mock,
subscription_modify_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
trial_end = timezone.now() + timezone.timedelta(days=5)
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.trial_end = trial_end
subscription.save()
# Extend the Subscription by 30 days
delta = timezone.timedelta(days=30)
subscription_updated = deepcopy(subscription_fake)
subscription_updated["trial_end"] = int((trial_end + delta).timestamp())
subscription_modify_mock.return_value = subscription_updated
extended_subscription = subscription.extend(delta)
new_trial_end = subscription.trial_end + delta
self.assertEqual(
new_trial_end.replace(microsecond=0), extended_subscription.trial_end
)
self.assertTrue(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertTrue(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_is_status_temporarily_current(self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_is_status_temporarily_current(
self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock
):
product = Product.sync_from_stripe_data(deepcopy(FAKE_PRODUCT))
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.canceled_at = timezone.now() + timezone.timedelta(days=7)
subscription.current_period_end = timezone.now() + timezone.timedelta(days=7)
subscription.cancel_at_period_end = True
subscription.save()
self.assertTrue(subscription.is_status_current())
self.assertTrue(subscription.is_status_temporarily_current())
self.assertTrue(subscription.is_valid())
self.assertTrue(subscription in self.customer.active_subscriptions)
self.assertTrue(self.customer.is_subscribed_to(product))
self.assertTrue(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_is_status_temporarily_current_false(self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_is_status_temporarily_current_false(
self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.current_period_end = timezone.now() + timezone.timedelta(days=7)
subscription.save()
self.assertTrue(subscription.is_status_current())
self.assertFalse(subscription.is_status_temporarily_current())
self.assertTrue(subscription.is_valid())
self.assertTrue(subscription in self.customer.active_subscriptions)
self.assertTrue(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertTrue(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_is_status_temporarily_current_false_and_canceled(self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_is_status_temporarily_current_false_and_canceled(
self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
subscription.status = SubscriptionStatus.canceled
subscription.current_period_end = timezone.now() + timezone.timedelta(days=7)
subscription.save()
self.assertFalse(subscription.is_status_current())
self.assertFalse(subscription.is_status_temporarily_current())
self.assertFalse(subscription.is_valid())
self.assertFalse(subscription in self.customer.active_subscriptions)
self.assertFalse(self.customer.is_subscribed_to(FAKE_PRODUCT["id"]))
self.assertFalse(self.customer.has_any_active_subscription())
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_remove_all_multi_plan(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, invoice_retrieve_mock, paymentintent_retrieve_mock, paymentmethod_retrieve_mock, charge_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_subscription.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Charge.retrieve",
autospec=True,
)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_PAYMENT_METHOD_II),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_II),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve", return_value=deepcopy(FAKE_INVOICE_II), autospec=True
)
@patch("stripe.Plan.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
def test_remove_all_multi_plan(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
invoice_retrieve_mock,
paymentintent_retrieve_mock,
paymentmethod_retrieve_mock,
charge_retrieve_mock,
balance_transaction_retrieve_mock,
):
# delete pydanny customer as that causes issues with Invoice and Latest_invoice FKs
self.customer.delete()
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_MULTI_PLAN)
fake_subscription["latest_invoice"] = FAKE_INVOICE_II["id"]
subscription_retrieve_mock.return_value = fake_subscription
fake_charge = deepcopy(FAKE_CHARGE_II)
fake_charge["payment_method"] = FAKE_PAYMENT_METHOD_II["id"]
charge_retrieve_mock.return_value = fake_charge
# create invoice
fake_invoice = deepcopy(FAKE_INVOICE_II)
Invoice.sync_from_stripe_data(fake_invoice)
subscription = Subscription.sync_from_stripe_data(fake_subscription)
self.assertIsNone(subscription.plan)
self.assertIsNone(subscription.quantity)
items = subscription.items.all()
self.assertEqual(2, len(items))
# Simulate a webhook received with no more plan
del fake_subscription["items"]["data"][1]
del fake_subscription["items"]["data"][0]
fake_subscription["items"]["total_count"] = 0
subscription = Subscription.sync_from_stripe_data(fake_subscription)
items = subscription.items.all()
self.assertEqual(0, len(items))
self.assert_fks(
subscription,
expected_blank_fks=self.default_expected_blank_fks
| {
"djstripe.Customer.subscriber",
"djstripe.Subscription.plan",
"djstripe.PaymentIntent.invoice (related name)",
"djstripe.Invoice.payment_intent",
},
)
tests.test_subscription.SubscriptionTest.test_sync_from_stripe_data(self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_from_stripe_data(
self,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake["cancel_at"] = 1624553655
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assertEqual(subscription.default_tax_rates.count(), 1)
self.assertEqual(
subscription.default_tax_rates.first().id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
self.assertEqual(datetime_to_unix(subscription.cancel_at), 1624553655)
tests.test_subscription.SubscriptionTest.test_sync_from_stripe_data_default_source_string(self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_from_stripe_data_default_source_string(
self, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription_fake["default_source"] = FAKE_CARD["id"]
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assertEqual(subscription.default_source.id, FAKE_CARD["id"])
# pop out "djstripe.Subscription.default_source" from self.assert_fks
expected_blank_fks = deepcopy(self.default_expected_blank_fks)
expected_blank_fks.remove("djstripe.Subscription.default_source")
self.assert_fks(subscription, expected_blank_fks=expected_blank_fks)
tests.test_subscription.SubscriptionTest.test_sync_items_with_tax_rates(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_II), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
def test_sync_items_with_tax_rates(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION_II)
subscription_fake["latest_invoice"] = FAKE_INVOICE["id"]
subscription_retrieve_mock.return_value = subscription_fake
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
self.assertEqual(subscription.default_tax_rates.count(), 0)
first_item = subscription.items.first()
self.assertEqual(first_item.tax_rates.count(), 1)
self.assertEqual(
first_item.tax_rates.first().id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
tests.test_subscription.SubscriptionTest.test_sync_metered_plan(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve", return_value=deepcopy(FAKE_SUBSCRIPTION_METERED)
)
def test_sync_metered_plan(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION_METERED)
self.assertNotIn(
"quantity",
subscription_fake["items"]["data"],
"Expect Metered plan SubscriptionItem to have no quantity",
)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
items = subscription.items.all()
self.assertEqual(1, len(items))
item = items[0]
self.assertEqual(subscription.quantity, 1)
# Note that subscription.quantity is 1,
# but item.quantity isn't set on metered plans
self.assertIsNone(item.quantity)
self.assertEqual(item.plan.id, FAKE_PLAN_METERED["id"])
self.assert_fks(
subscription,
expected_blank_fks=(
self.default_expected_blank_fks
| {"djstripe.Subscription.latest_invoice"}
),
)
tests.test_subscription.SubscriptionTest.test_sync_multi_plan(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
def test_sync_multi_plan(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION_MULTI_PLAN)
subscription_fake["latest_invoice"] = FAKE_INVOICE["id"]
subscription_retrieve_mock.return_value = subscription_fake
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assertIsNone(subscription.plan)
self.assertIsNone(subscription.quantity)
items = subscription.items.all()
self.assertEqual(2, len(items))
# delete pydanny customer as that causes issues with Invoice and Latest_invoice FKs
self.customer.delete()
self.assert_fks(
subscription,
expected_blank_fks=(
self.default_expected_blank_fks
| {
"djstripe.Customer.subscriber",
"djstripe.Subscription.plan",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.Invoice.charge",
"djstripe.Invoice.customer",
"djstripe.Invoice.payment_intent",
"djstripe.Invoice.subscription",
}
),
)
tests.test_subscription.SubscriptionTest.test_update(self, customer_retrieve_mock, subscription_retrieve_mock, subscription_modify_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.modify",
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_update(
self,
customer_retrieve_mock,
subscription_retrieve_mock,
subscription_modify_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assertEqual(1, subscription.quantity)
# Update the quantity of the Subscription
subscription_updated = deepcopy(FAKE_SUBSCRIPTION)
subscription_updated["quantity"] = 4
subscription_modify_mock.return_value = subscription_updated
new_subscription = subscription.update(quantity=4)
self.assertEqual(4, new_subscription.quantity)
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
tests.test_subscription.SubscriptionTest.test_update_multi_plan(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
def test_update_multi_plan(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION_MULTI_PLAN)
subscription_fake["latest_invoice"] = FAKE_INVOICE["id"]
subscription_retrieve_mock.return_value = subscription_fake
subscription = Subscription.sync_from_stripe_data(subscription_fake)
self.assertIsNone(subscription.plan)
self.assertIsNone(subscription.quantity)
items = subscription.items.all()
self.assertEqual(2, len(items))
# Simulate a webhook received with one plan that has been removed
del subscription_fake["items"]["data"][1]
subscription_fake["items"]["total_count"] = 1
subscription = Subscription.sync_from_stripe_data(subscription_fake)
items = subscription.items.all()
self.assertEqual(1, len(items))
# delete pydanny customer as that causes issues with Invoice and Latest_invoice FKs
self.customer.delete()
self.assert_fks(
subscription,
expected_blank_fks=(
self.default_expected_blank_fks
| {
"djstripe.Customer.subscriber",
"djstripe.Subscription.plan",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.Invoice.charge",
"djstripe.Invoice.customer",
"djstripe.Invoice.payment_intent",
"djstripe.Invoice.subscription",
}
),
)
tests.test_subscription.SubscriptionTest.test_update_with_plan_model(self, customer_retrieve_mock, subscription_retrieve_mock, subscription_modify_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_subscription.py
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Subscription.modify",
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_update_with_plan_model(
self,
customer_retrieve_mock,
subscription_retrieve_mock,
subscription_modify_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
subscription_fake = deepcopy(FAKE_SUBSCRIPTION)
subscription = Subscription.sync_from_stripe_data(subscription_fake)
new_plan = Plan.sync_from_stripe_data(deepcopy(FAKE_PLAN_II))
self.assertEqual(FAKE_PLAN["id"], subscription.plan.id)
# Update the Subscription's plan
subscription_updated = deepcopy(FAKE_SUBSCRIPTION)
subscription_updated["plan"] = deepcopy(FAKE_PLAN_II)
subscription_modify_mock.return_value = subscription_updated
new_subscription = subscription.update(plan=new_plan)
self.assertEqual(FAKE_PLAN_II["id"], new_subscription.plan.id)
self.assert_fks(
subscription, expected_blank_fks=self.default_expected_blank_fks
)
self.assert_fks(new_plan, expected_blank_fks={})
tests.test_subscription.TestSubscriptionDecimal
tests.test_subscription.TestSubscriptionDecimal.test_decimal_application_fee_percent(self, inputted, expected, monkeypatch)
Source code in tests/test_subscription.py
@pytest.mark.parametrize(
"inputted,expected",
[
(Decimal("1"), Decimal("1.00")),
(Decimal("1.5234567"), Decimal("1.52")),
(Decimal("0"), Decimal("0.00")),
(Decimal("23.2345678"), Decimal("23.23")),
("1", Decimal("1.00")),
("1.5234567", Decimal("1.52")),
("0", Decimal("0.00")),
("23.2345678", Decimal("23.23")),
(1, Decimal("1.00")),
(1.5234567, Decimal("1.52")),
(0, Decimal("0.00")),
(23.2345678, Decimal("23.24")),
],
)
def test_decimal_application_fee_percent(self, inputted, expected, monkeypatch):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION)
fake_subscription["application_fee_percent"] = inputted
def mock_invoice_get(*args, **kwargs):
return FAKE_INVOICE
def mock_customer_get(*args, **kwargs):
return FAKE_CUSTOMER
def mock_charge_get(*args, **kwargs):
return FAKE_CHARGE
def mock_payment_method_get(*args, **kwargs):
return FAKE_CARD_AS_PAYMENT_METHOD
def mock_payment_intent_get(*args, **kwargs):
return FAKE_PAYMENT_INTENT_I
def mock_subscription_get(*args, **kwargs):
return fake_subscription
def mock_balance_transaction_get(*args, **kwargs):
return FAKE_BALANCE_TRANSACTION
def mock_product_get(*args, **kwargs):
return FAKE_PRODUCT
def mock_plan_get(*args, **kwargs):
return FAKE_PLAN
# monkeypatch stripe retrieve calls to return
# the desired json response.
monkeypatch.setattr(stripe.Invoice, "retrieve", mock_invoice_get)
monkeypatch.setattr(stripe.Customer, "retrieve", mock_customer_get)
monkeypatch.setattr(
stripe.BalanceTransaction, "retrieve", mock_balance_transaction_get
)
monkeypatch.setattr(stripe.Subscription, "retrieve", mock_subscription_get)
monkeypatch.setattr(stripe.Charge, "retrieve", mock_charge_get)
monkeypatch.setattr(stripe.PaymentMethod, "retrieve", mock_payment_method_get)
monkeypatch.setattr(stripe.PaymentIntent, "retrieve", mock_payment_intent_get)
monkeypatch.setattr(stripe.Product, "retrieve", mock_product_get)
monkeypatch.setattr(stripe.Plan, "retrieve", mock_plan_get)
# Create Latest Invoice
Invoice.sync_from_stripe_data(FAKE_INVOICE)
subscription = Subscription.sync_from_stripe_data(fake_subscription)
field_data = subscription.application_fee_percent
assert isinstance(field_data, Decimal)
assert field_data == expected
tests.test_subscription_item
dj-stripe SubscriptionItem model tests
tests.test_subscription_item.SubscriptionItemTest
tests.test_subscription_item.SubscriptionItemTest.setUp(self, invoice_retrieve_mock, product_retrieve_mock, payment_intent_retrieve_mock, paymentmethod_card_retrieve_mock, charge_retrieve_mock, subscription_retrieve_mock, balance_transaction_retrieve_mock)
Source code in tests/test_subscription_item.py
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION),
autospec=True,
)
@patch("stripe.Charge.retrieve", return_value=deepcopy(FAKE_CHARGE), autospec=True)
@patch(
"stripe.PaymentMethod.retrieve",
return_value=deepcopy(FAKE_CARD_AS_PAYMENT_METHOD),
autospec=True,
)
@patch(
"stripe.PaymentIntent.retrieve",
return_value=deepcopy(FAKE_PAYMENT_INTENT_I),
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Invoice.retrieve", autospec=True, return_value=deepcopy(FAKE_INVOICE)
)
def setUp(
self,
invoice_retrieve_mock,
product_retrieve_mock,
payment_intent_retrieve_mock,
paymentmethod_card_retrieve_mock,
charge_retrieve_mock,
subscription_retrieve_mock,
balance_transaction_retrieve_mock,
):
self.user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER.create_for_user(self.user)
self.default_expected_blank_fks = {
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
}
# create latest invoice
Invoice.sync_from_stripe_data(deepcopy(FAKE_INVOICE))
tests.test_subscription_item.SubscriptionItemTest.test_sync_from_stripe_data_metered_subscription(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, price_retrieve_mock)
Source code in tests/test_subscription_item.py
@patch(
"stripe.Price.retrieve",
return_value=deepcopy(FAKE_PRICE_METERED),
autospec=True,
)
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_METERED),
autospec=True,
)
def test_sync_from_stripe_data_metered_subscription(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
price_retrieve_mock,
):
subscription_item_fake = deepcopy(FAKE_SUBSCRIPTION_ITEM_METERED)
subscription_item = SubscriptionItem.sync_from_stripe_data(
subscription_item_fake
)
self.assertEqual(subscription_item.id, FAKE_SUBSCRIPTION_ITEM_METERED["id"])
self.assertEqual(
subscription_item.plan.id, FAKE_SUBSCRIPTION_ITEM_METERED["plan"]["id"]
)
self.assertEqual(
subscription_item.price.id, FAKE_SUBSCRIPTION_ITEM_METERED["price"]["id"]
)
self.assertEqual(
subscription_item.subscription.id,
FAKE_SUBSCRIPTION_ITEM_METERED["subscription"],
)
self.assert_fks(
subscription_item,
expected_blank_fks=(
self.default_expected_blank_fks
| {"djstripe.Subscription.latest_invoice"}
),
)
tests.test_subscription_item.SubscriptionItemTest.test_sync_items_with_tax_rates(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, price_retrieve_mock)
Source code in tests/test_subscription_item.py
@patch(
"stripe.Price.retrieve",
return_value=deepcopy(FAKE_PRICE_II),
autospec=True,
)
@patch("stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_II), autospec=True)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
def test_sync_items_with_tax_rates(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
price_retrieve_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_II)
fake_subscription["latest_invoice"] = FAKE_INVOICE["id"]
subscription_retrieve_mock.return_value = fake_subscription
subscription_item_fake = deepcopy(FAKE_SUBSCRIPTION_ITEM_TAX_RATES)
subscription_item = SubscriptionItem.sync_from_stripe_data(
subscription_item_fake
)
self.assertEqual(subscription_item.id, FAKE_SUBSCRIPTION_ITEM_TAX_RATES["id"])
self.assertEqual(
subscription_item.plan.id, FAKE_SUBSCRIPTION_ITEM_TAX_RATES["plan"]["id"]
)
self.assertEqual(
subscription_item.price.id, FAKE_SUBSCRIPTION_ITEM_TAX_RATES["price"]["id"]
)
self.assertEqual(
subscription_item.subscription.id,
FAKE_SUBSCRIPTION_ITEM_TAX_RATES["subscription"],
)
self.assert_fks(
subscription_item,
expected_blank_fks=(
self.default_expected_blank_fks
| {
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
}
),
)
self.assertEqual(subscription_item.tax_rates.count(), 1)
self.assertEqual(
subscription_item.tax_rates.first().id, FAKE_TAX_RATE_EXAMPLE_1_VAT["id"]
)
tests.test_subscription_item.SubscriptionItemTest.test_sync_multi_plan_subscription(self, subscription_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, price_retrieve_mock)
Source code in tests/test_subscription_item.py
@patch(
"stripe.Price.retrieve",
side_effect=[deepcopy(FAKE_PRICE), deepcopy(FAKE_PRICE_II)],
autospec=True,
)
@patch(
"stripe.Plan.retrieve",
side_effect=[deepcopy(FAKE_PLAN), deepcopy(FAKE_PLAN_II)],
autospec=True,
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
autospec=True,
)
def test_sync_multi_plan_subscription(
self,
subscription_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
price_retrieve_mock,
):
fake_subscription = deepcopy(FAKE_SUBSCRIPTION_MULTI_PLAN)
fake_subscription["latest_invoice"] = FAKE_INVOICE["id"]
subscription_retrieve_mock.return_value = fake_subscription
subscription_item_fake = deepcopy(FAKE_SUBSCRIPTION_ITEM_MULTI_PLAN)
subscription_item = SubscriptionItem.sync_from_stripe_data(
subscription_item_fake
)
self.assertEqual(subscription_item.id, FAKE_SUBSCRIPTION_ITEM_MULTI_PLAN["id"])
self.assertEqual(
subscription_item.plan.id, FAKE_SUBSCRIPTION_ITEM_MULTI_PLAN["plan"]["id"]
)
self.assertEqual(
subscription_item.price.id, FAKE_SUBSCRIPTION_ITEM_MULTI_PLAN["price"]["id"]
)
self.assertEqual(
subscription_item.subscription.id,
FAKE_SUBSCRIPTION_ITEM_MULTI_PLAN["subscription"],
)
# delete pydanny customer as that causes issues with Invoice and Latest_invoice FKs
self.customer.delete()
self.assert_fks(
subscription_item,
expected_blank_fks=(
self.default_expected_blank_fks
| {
"djstripe.Customer.subscriber",
"djstripe.Subscription.plan",
"djstripe.Charge.latest_upcominginvoice (related name)",
"djstripe.Charge.application_fee",
"djstripe.Charge.dispute",
"djstripe.Charge.on_behalf_of",
"djstripe.Charge.source_transfer",
"djstripe.Charge.transfer",
"djstripe.PaymentIntent.upcominginvoice (related name)",
"djstripe.PaymentIntent.on_behalf_of",
"djstripe.PaymentIntent.payment_method",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.Invoice.charge",
"djstripe.Invoice.customer",
"djstripe.Invoice.payment_intent",
"djstripe.Invoice.subscription",
}
),
)
tests.test_subscription_schedule
dj-stripe SubscriptionSchedule model tests.
Classes
tests.test_subscription_schedule.SubscriptionScheduleTest
Methods
tests.test_subscription_schedule.SubscriptionScheduleTest.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_subscription_schedule.py
def setUp(self):
user = get_user_model().objects.create_user(
username="pydanny", email="pydanny@gmail.com"
)
self.customer = FAKE_CUSTOMER_II.create_for_user(user)
self.default_expected_blank_fks = {
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.SubscriptionSchedule.released_subscription",
}
tests.test_subscription_schedule.SubscriptionScheduleTest.test___str__(self, customer_retrieve_mock)
Source code in tests/test_subscription_schedule.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test___str__(self, customer_retrieve_mock):
schedule = SubscriptionSchedule.sync_from_stripe_data(
deepcopy(FAKE_SUBSCRIPTION_SCHEDULE)
)
self.assertEqual(f"<id={FAKE_SUBSCRIPTION_SCHEDULE['id']}>", str(schedule))
self.assert_fks(schedule, expected_blank_fks=self.default_expected_blank_fks)
tests.test_subscription_schedule.SubscriptionScheduleTest.test_sync_from_stripe_data(self, customer_retrieve_mock)
Source code in tests/test_subscription_schedule.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
def test_sync_from_stripe_data(self, customer_retrieve_mock):
canceled_schedule_fake = deepcopy(FAKE_SUBSCRIPTION_SCHEDULE)
canceled_schedule_fake["canceled_at"] = 1624553655
canceled_schedule_fake["status"] = SubscriptionScheduleStatus.canceled
schedule = SubscriptionSchedule.sync_from_stripe_data(canceled_schedule_fake)
self.assert_fks(schedule, expected_blank_fks=self.default_expected_blank_fks)
self.assertEqual(datetime_to_unix(schedule.canceled_at), 1624553655)
tests.test_sync
dj-stripe Sync Method Tests.
Classes
tests.test_sync.TestSyncSubscriber
Methods
tests.test_sync.TestSyncSubscriber.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_sync.py
def setUp(self):
self.user = get_user_model().objects.create_user(
username="testuser", email="test@example.com", password="123"
)
tests.test_sync.TestSyncSubscriber.test_sync_fail(self, stripe_customer_create_mock, api_retrieve_mock)
Source code in tests/test_sync.py
@patch(
"djstripe.models.Customer.api_retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.create", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_fail(self, stripe_customer_create_mock, api_retrieve_mock):
api_retrieve_mock.side_effect = InvalidRequestError("No such customer:", "blah")
with capture_stdout() as stdout:
sync_subscriber(self.user)
self.assertEqual("ERROR: No such customer:", stdout.getvalue().strip())
tests.test_sync.TestSyncSubscriber.test_sync_success(self, stripe_customer_create_mock, api_retrieve_mock, _sync_subscriptions_mock, _sync_invoices_mock, _sync_charges_mock)
Source code in tests/test_sync.py
@patch("djstripe.models.Customer._sync_charges", autospec=True)
@patch("djstripe.models.Customer._sync_invoices", autospec=True)
@patch("djstripe.models.Customer._sync_subscriptions", autospec=True)
@patch(
"stripe.Customer.retrieve", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
@patch(
"stripe.Customer.create", return_value=deepcopy(FAKE_CUSTOMER), autospec=True
)
def test_sync_success(
self,
stripe_customer_create_mock,
api_retrieve_mock,
_sync_subscriptions_mock,
_sync_invoices_mock,
_sync_charges_mock,
):
sync_subscriber(self.user)
self.assertEqual(1, Customer.objects.count())
self.assertEqual(
FAKE_CUSTOMER["id"],
Customer.objects.get(subscriber=self.user).api_retrieve()["id"],
)
_sync_subscriptions_mock.assert_called_once_with(Customer.objects.first())
_sync_invoices_mock.assert_called_once_with(Customer.objects.first())
_sync_charges_mock.assert_called_once_with(Customer.objects.first())
tests.test_sync.capture_stdout()
Source code in tests/test_sync.py
@contextlib.contextmanager
def capture_stdout():
import sys
from io import StringIO
old_stdout = sys.stdout
sys.stdout = StringIO()
try:
yield sys.stdout
finally:
sys.stdout = old_stdout
tests.test_tax_id
dj-stripe TaxId model tests
tests.test_tax_id.pytestmark
tests.test_tax_id.TestTaxIdStr
tests.test_tax_id.TestTaxIdStr.test___str__(self, tax_id_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_tax_id.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_tax_id",
return_value=deepcopy(FAKE_TAX_ID),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test___str__(
self,
tax_id_retrieve_mock,
customer_retrieve_mock,
):
tax_id = TaxId.sync_from_stripe_data(FAKE_TAX_ID)
self.assertEqual(
str(tax_id),
f"{enums.TaxIdType.humanize(FAKE_TAX_ID['type'])} {FAKE_TAX_ID['value']} ({FAKE_TAX_ID['verification']['status']})",
)
tests.test_tax_id.TestTransfer
tests.test_tax_id.TestTransfer.test__api_create(self, tax_id_create_mock, customer_get_mock)
Source code in tests/test_tax_id.py
@patch(
"djstripe.models.core.Customer.objects.get",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.create_tax_id",
return_value=deepcopy(FAKE_TAX_ID),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test__api_create(
self,
tax_id_create_mock,
customer_get_mock,
):
STRIPE_DATA = TaxId._api_create(
id=FAKE_CUSTOMER["id"], type=FAKE_TAX_ID["type"], value=FAKE_TAX_ID["value"]
)
assert STRIPE_DATA == FAKE_TAX_ID
tax_id_create_mock.assert_called_once_with(
id=FAKE_CUSTOMER["id"],
type=FAKE_TAX_ID["type"],
value=FAKE_TAX_ID["value"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
)
tests.test_tax_id.TestTransfer.test__api_create_no_customer(self, tax_id_create_mock)
Source code in tests/test_tax_id.py
@patch(
"stripe.Customer.create_tax_id",
return_value=deepcopy(FAKE_TAX_ID),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test__api_create_no_customer(
self,
tax_id_create_mock,
):
with pytest.raises(Customer.DoesNotExist):
TaxId._api_create(
id=FAKE_CUSTOMER["id"],
type=FAKE_TAX_ID["type"],
value=FAKE_TAX_ID["value"],
)
tests.test_tax_id.TestTransfer.test__api_create_no_id_kwarg(self, tax_id_create_mock, customer_get_mock)
Source code in tests/test_tax_id.py
@patch(
"djstripe.models.core.Customer.objects.get",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.create_tax_id",
return_value=deepcopy(FAKE_TAX_ID),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test__api_create_no_id_kwarg(
self,
tax_id_create_mock,
customer_get_mock,
):
with pytest.raises(KeyError) as exc:
TaxId._api_create(
FAKE_CUSTOMER["id"],
type=FAKE_TAX_ID["type"],
value=FAKE_TAX_ID["value"],
)
assert "Customer Object ID is missing" in str(exc.value)
tests.test_tax_id.TestTransfer.test_api_list(self, tax_id_list_mock)
Source code in tests/test_tax_id.py
@patch(
"stripe.Customer.list_tax_ids",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_api_list(
self,
tax_id_list_mock,
):
p = PropertyMock(return_value=deepcopy(FAKE_TAX_ID))
type(tax_id_list_mock).auto_paging_iter = p
TaxId.api_list(id=FAKE_CUSTOMER["id"])
tax_id_list_mock.assert_called_once_with(
id=FAKE_CUSTOMER["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
)
tests.test_tax_id.TestTransfer.test_api_retrieve(self, tax_id_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_tax_id.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_tax_id",
return_value=deepcopy(FAKE_TAX_ID),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_api_retrieve(
self,
tax_id_retrieve_mock,
customer_retrieve_mock,
):
tax_id = TaxId.sync_from_stripe_data(FAKE_TAX_ID)
tax_id.api_retrieve()
tax_id_retrieve_mock.assert_called_once_with(
id=FAKE_CUSTOMER["id"],
nested_id=FAKE_TAX_ID["id"],
expand=[],
stripe_account=tax_id.djstripe_owner_account.id,
api_key=djstripe_settings.STRIPE_SECRET_KEY,
)
tests.test_tax_id.TestTransfer.test_sync_from_stripe_data(self, tax_id_retrieve_mock, customer_retrieve_mock)
Source code in tests/test_tax_id.py
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER),
autospec=True,
)
@patch(
"stripe.Customer.retrieve_tax_id",
return_value=deepcopy(FAKE_TAX_ID),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_sync_from_stripe_data(
self,
tax_id_retrieve_mock,
customer_retrieve_mock,
):
tax_id = TaxId.sync_from_stripe_data(FAKE_TAX_ID)
assert tax_id.id == FAKE_TAX_ID["id"]
assert tax_id.customer.id == FAKE_CUSTOMER["id"]
self.assert_fks(
tax_id,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
},
)
tests.test_tax_rates
dj-stripe SetupIntent Model Tests.
tests.test_tax_rates.pytestmark
tests.test_tax_rates.TaxRateTest
tests.test_tax_rates.TaxRateTest.test___str__(self)
Source code in tests/test_tax_rates.py
def test___str__(self):
tax_rate = TaxRate.sync_from_stripe_data(deepcopy(FAKE_TAX_RATE_EXAMPLE_1_VAT))
# need to refresh to load percentage as decimal
tax_rate.refresh_from_db()
self.assertEqual(
f"{FAKE_TAX_RATE_EXAMPLE_1_VAT['display_name']} – {FAKE_TAX_RATE_EXAMPLE_1_VAT['jurisdiction']} at {FAKE_TAX_RATE_EXAMPLE_1_VAT['percentage']:.2f}%",
str(tax_rate),
)
tests.test_tax_rates.TestTaxRateDecimal
tests.test_tax_rates.TestTaxRateDecimal.test_decimal_tax_percent(self, inputted, expected)
Source code in tests/test_tax_rates.py
@pytest.mark.parametrize(
"inputted,expected",
[
(Decimal("1"), Decimal("1.00")),
(Decimal("1.5234567"), Decimal("1.52")),
(Decimal("0"), Decimal("0.00")),
(Decimal("23.2345678"), Decimal("23.23")),
("1", Decimal("1.00")),
("1.5234567", Decimal("1.52")),
("0", Decimal("0.00")),
("23.2345678", Decimal("23.23")),
(1, Decimal("1.00")),
(1.5234567, Decimal("1.52")),
(0, Decimal("0.00")),
(23.2345678, Decimal("23.24")),
],
)
def test_decimal_tax_percent(self, inputted, expected):
fake_tax_rate = deepcopy(FAKE_TAX_RATE_EXAMPLE_1_VAT)
fake_tax_rate["percentage"] = inputted
tax_rate = TaxRate.sync_from_stripe_data(fake_tax_rate)
field_data = tax_rate.percentage
assert isinstance(field_data, Decimal)
assert field_data == expected
tests.test_transfer
dj-stripe Transfer model tests
tests.test_transfer.pytestmark
tests.test_transfer.TestTransfer
tests.test_transfer.TestTransfer.test_fee(self, transfer_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_transfer.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION_II),
autospec=True,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
def test_fee(
self,
transfer_retrieve_mock,
balance_transaction_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
transfer = Transfer.sync_from_stripe_data(deepcopy(FAKE_TRANSFER))
assert transfer.fee == FAKE_BALANCE_TRANSACTION_II["fee"]
assert transfer.fee == transfer.balance_transaction.fee
tests.test_transfer.TestTransfer.test_sync_from_stripe_data(self, transfer_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_transfer.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION_II),
autospec=True,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
def test_sync_from_stripe_data(
self,
transfer_retrieve_mock,
balance_transaction_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
transfer = Transfer.sync_from_stripe_data(deepcopy(FAKE_TRANSFER))
balance_transaction_retrieve_mock.assert_not_called()
transfer_retrieve_mock.assert_not_called()
assert (
transfer.balance_transaction.id
== FAKE_TRANSFER["balance_transaction"]["id"]
)
assert transfer.destination.id == FAKE_TRANSFER["destination"]
self.assert_fks(transfer, expected_blank_fks="")
tests.test_transfer.TestTransferStr
tests.test_transfer.TestTransferStr.FAKE_TRANSFER_COMPLETE_REVERSAL()
Source code in tests/test_transfer.py
def FAKE_TRANSFER_COMPLETE_REVERSAL():
data = deepcopy(FAKE_TRANSFER)
data["reversed"] = True
data["amount_reversed"] = data["amount"]
return data
tests.test_transfer.TestTransferStr.FAKE_TRANSFER_PARTIAL_REVERSAL()
Source code in tests/test_transfer.py
def FAKE_TRANSFER_PARTIAL_REVERSAL():
data = deepcopy(FAKE_TRANSFER)
assert data["amount"] > 1
data["amount_reversed"] = data["amount"] - 1
return data
tests.test_transfer.TestTransferStr.test___str__(self, transfer_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock, fake_transfer_data)
Source code in tests/test_transfer.py
@pytest.mark.parametrize(
"fake_transfer_data",
[
deepcopy(FAKE_TRANSFER),
FAKE_TRANSFER_COMPLETE_REVERSAL(),
FAKE_TRANSFER_PARTIAL_REVERSAL(),
],
)
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION_II),
autospec=True,
)
@patch("stripe.Transfer.retrieve", autospec=True)
def test___str__(
self,
transfer_retrieve_mock,
balance_transaction_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
fake_transfer_data,
):
transfer_retrieve_mock.return_value = fake_transfer_data
transfer = Transfer.sync_from_stripe_data(fake_transfer_data)
if fake_transfer_data["reversed"]:
assert f"{transfer.human_readable_amount} Reversed" == str(transfer)
elif fake_transfer_data["amount_reversed"]:
assert f"{transfer.human_readable_amount} Partially Reversed" == str(
transfer
)
else:
assert f"{transfer.human_readable_amount}" == str(transfer)
tests.test_transfer_reversal
dj-stripe TransferReversal model tests
tests.test_transfer_reversal.pytestmark
tests.test_transfer_reversal.TestTransfer
tests.test_transfer_reversal.TestTransfer.test__api_create(self, transfer_reversal_create_mock, transfer_get_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_transfer_reversal.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
# we are returning any value for the Transfer.objects.get as we only need to avoid the Transfer.DoesNotExist error
@patch(
"djstripe.models.connect.Transfer.objects.get",
return_value=deepcopy(FAKE_TRANSFER),
)
@patch(
"stripe.Transfer.create_reversal",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL),
)
def test__api_create(
self,
transfer_reversal_create_mock,
transfer_get_mock,
transfer__attach_object_post_save_hook_mock,
):
TransferReversal._api_create(
id=FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0]["transfer"]["id"]
)
transfer_reversal_create_mock.assert_called_once_with(
id=FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0]["transfer"]["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
)
tests.test_transfer_reversal.TestTransfer.test_api_list(self, transfer_reversal_list_mock)
Source code in tests/test_transfer_reversal.py
@patch(
"stripe.Transfer.list_reversals", autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED
)
def test_api_list(self, transfer_reversal_list_mock):
p = PropertyMock(return_value=deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL))
type(transfer_reversal_list_mock).auto_paging_iter = p
TransferReversal.api_list(
id=FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0]["transfer"]["id"]
)
transfer_reversal_list_mock.assert_called_once_with(
id=FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0]["transfer"]["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
)
tests.test_transfer_reversal.TestTransfer.test_api_retrieve(self, transfer_reversal_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_transfer_reversal.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION_II),
autospec=True,
)
@patch(
"stripe.Transfer.retrieve_reversal",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL),
)
def test_api_retrieve(
self,
transfer_reversal_retrieve_mock,
balance_transaction_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
transfer_reversal = TransferReversal.sync_from_stripe_data(
deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0])
)
transfer_reversal.api_retrieve()
transfer_reversal_retrieve_mock.assert_called_once_with(
id=FAKE_TRANSFER_WITH_1_REVERSAL["id"],
nested_id=FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0]["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=["balance_transaction", "transfer"],
stripe_account=transfer_reversal.djstripe_owner_account.id,
)
tests.test_transfer_reversal.TestTransfer.test_is_valid_object(self)
Source code in tests/test_transfer_reversal.py
def test_is_valid_object(self):
assert TransferReversal.is_valid_object(
deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0])
)
tests.test_transfer_reversal.TestTransfer.test_sync_from_stripe_data(self, transfer_reversal_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_transfer_reversal.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION_II),
autospec=True,
)
@patch(
"stripe.Transfer.retrieve_reversal",
autospec=True,
return_value=deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0]),
)
def test_sync_from_stripe_data(
self,
transfer_reversal_retrieve_mock,
balance_transaction_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
transfer_reversal = TransferReversal.sync_from_stripe_data(
deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0])
)
balance_transaction_retrieve_mock.assert_not_called()
transfer_reversal_retrieve_mock.assert_not_called()
assert (
transfer_reversal.balance_transaction.id
== FAKE_TRANSFER["balance_transaction"]["id"]
)
assert (
transfer_reversal.transfer.id
== FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0]["transfer"]["id"]
)
self.assert_fks(transfer_reversal, expected_blank_fks="")
tests.test_transfer_reversal.TestTransferReversalStr
tests.test_transfer_reversal.TestTransferReversalStr.test___str__(self, transfer_reversal_retrieve_mock, balance_transaction_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_transfer_reversal.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_PLATFORM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.BalanceTransaction.retrieve",
return_value=deepcopy(FAKE_BALANCE_TRANSACTION_II),
autospec=True,
)
@patch(
"stripe.Transfer.retrieve_reversal",
autospec=True,
return_value=deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL),
)
def test___str__(
self,
transfer_reversal_retrieve_mock,
balance_transaction_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
transfer_reversal = TransferReversal.sync_from_stripe_data(
deepcopy(FAKE_TRANSFER_WITH_1_REVERSAL["reversals"]["data"][0])
)
self.assertEqual(str(f"{transfer_reversal.transfer}"), str(transfer_reversal))
tests.test_usage_record
dj-stripe UsageRecord model tests
tests.test_usage_record.pytestmark
tests.test_usage_record.TestUsageRecord
tests.test_usage_record.TestUsageRecord.test___str__(self, subscription_retrieve_mock, subscription_item_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_usage_record.py
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.SubscriptionItem.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE),
autospec=True,
)
def test___str__(
self,
subscription_retrieve_mock,
subscription_item_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
fake_usage_data = deepcopy(FAKE_USAGE_RECORD)
usage_record = UsageRecord.sync_from_stripe_data(fake_usage_data)
self.assertEqual(
str(usage_record),
f"Usage for {str(usage_record.subscription_item)} ({fake_usage_data['action']}) is {fake_usage_data['quantity']}",
)
tests.test_usage_record.TestUsageRecord.test__api_create(self, subscription_retrieve_mock, subscription_item_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, subcription_item_get_mock, sync_from_stripe_data_mock, usage_record_creation_mock)
Source code in tests/test_usage_record.py
@patch(
"stripe.SubscriptionItem.create_usage_record",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
return_value=deepcopy(FAKE_USAGE_RECORD),
)
@patch(
"djstripe.models.billing.UsageRecord.sync_from_stripe_data",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
)
@patch(
"djstripe.models.billing.SubscriptionItem.objects.get",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
)
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.SubscriptionItem.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE),
autospec=True,
)
def test__api_create(
self,
subscription_retrieve_mock,
subscription_item_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
subcription_item_get_mock,
sync_from_stripe_data_mock,
usage_record_creation_mock,
):
fake_usage_data = deepcopy(FAKE_USAGE_RECORD)
UsageRecord._api_create(id=fake_usage_data["subscription_item"])
# assert usage_record_creation_mock was called as expected
usage_record_creation_mock.assert_called_once_with(
id=fake_usage_data["subscription_item"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
)
# assert usage_record_creation_mock was called as expected
sync_from_stripe_data_mock.assert_called_once_with(fake_usage_data)
tests.test_usage_record.TestUsageRecord.test_sync_from_stripe_data(self, subscription_retrieve_mock, subscription_item_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_usage_record.py
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.SubscriptionItem.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE),
autospec=True,
)
def test_sync_from_stripe_data(
self,
subscription_retrieve_mock,
subscription_item_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
fake_usage_data = deepcopy(FAKE_USAGE_RECORD)
usage_record = UsageRecord.sync_from_stripe_data(fake_usage_data)
self.assertEqual(usage_record.id, fake_usage_data["id"])
self.assertEqual(
usage_record.subscription_item.id, fake_usage_data["subscription_item"]
)
self.assert_fks(
usage_record,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
"djstripe.Subscription.latest_invoice",
},
)
tests.test_usage_record_summary
dj-stripe UsageRecordSummary model tests
tests.test_usage_record_summary.pytestmark
tests.test_usage_record_summary.TestUsageRecordSummary
tests.test_usage_record_summary.TestUsageRecordSummary.test___str__(self, invoice_retrieve_mock, subscription_retrieve_mock, subscription_item_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_usage_record_summary.py
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.SubscriptionItem.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION),
autospec=True,
)
def test___str__(
self,
invoice_retrieve_mock,
subscription_retrieve_mock,
subscription_item_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
fake_usage_data = deepcopy(FAKE_USAGE_RECORD_SUMMARY)
usage_record_summary = UsageRecordSummary.sync_from_stripe_data(
fake_usage_data["data"][1]
)
self.assertEqual(
str(usage_record_summary),
f"Usage Summary for {str(usage_record_summary.subscription_item)} ({str(usage_record_summary.invoice)}) is {fake_usage_data['data'][1]['total_usage']}",
)
tests.test_usage_record_summary.TestUsageRecordSummary.test_api_list(self, invoice_retrieve_mock, subscription_retrieve_mock, subscription_item_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock, subcription_item_get_mock, usage_record_list_mock)
Source code in tests/test_usage_record_summary.py
@patch(
"stripe.SubscriptionItem.list_usage_record_summaries",
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"djstripe.models.billing.SubscriptionItem.objects.get",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
)
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.SubscriptionItem.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION),
autospec=True,
)
def test_api_list(
self,
invoice_retrieve_mock,
subscription_retrieve_mock,
subscription_item_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
subcription_item_get_mock,
usage_record_list_mock,
):
p = PropertyMock(return_value=deepcopy(FAKE_USAGE_RECORD_SUMMARY))
type(usage_record_list_mock).auto_paging_iter = p
fake_usage_data = deepcopy(FAKE_USAGE_RECORD_SUMMARY)
UsageRecordSummary.api_list(id=fake_usage_data["data"][1]["subscription_item"])
# assert usage_record_list_mock was called as expected
usage_record_list_mock.assert_called_once_with(
id=fake_usage_data["data"][1]["subscription_item"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
)
tests.test_usage_record_summary.TestUsageRecordSummary.test_sync_from_stripe_data(self, invoice_retrieve_mock, subscription_retrieve_mock, subscription_item_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_usage_record_summary.py
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.SubscriptionItem.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE),
autospec=True,
)
@patch(
"stripe.Invoice.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION),
autospec=True,
)
def test_sync_from_stripe_data(
self,
invoice_retrieve_mock,
subscription_retrieve_mock,
subscription_item_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
fake_usage_data = deepcopy(FAKE_USAGE_RECORD_SUMMARY)
usage_record_summary = UsageRecordSummary.sync_from_stripe_data(
fake_usage_data["data"][1]
)
self.assertEqual(usage_record_summary.id, fake_usage_data["data"][1]["id"])
self.assertEqual(
usage_record_summary.subscription_item.id,
fake_usage_data["data"][1]["subscription_item"],
)
self.assert_fks(
usage_record_summary,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
"djstripe.Subscription.latest_invoice",
"djstripe.Invoice.default_payment_method",
"djstripe.Invoice.default_source",
"djstripe.Invoice.payment_intent",
"djstripe.Invoice.charge",
},
)
# assert invoice_retrieve_mock was called once
invoice_retrieve_mock.assert_called_once_with(
id=FAKE_INVOICE_METERED_SUBSCRIPTION["id"],
api_key=djstripe_settings.STRIPE_SECRET_KEY,
expand=[],
stripe_account=None,
)
tests.test_usage_record_summary.TestUsageRecordSummary.test_sync_from_stripe_data_with_null_invoice(self, subscription_retrieve_mock, subscription_item_retrieve_mock, customer_retrieve_mock, product_retrieve_mock, plan_retrieve_mock)
Source code in tests/test_usage_record_summary.py
@patch(
"stripe.Plan.retrieve", return_value=deepcopy(FAKE_PLAN_METERED), autospec=True
)
@patch(
"stripe.Product.retrieve", return_value=deepcopy(FAKE_PRODUCT), autospec=True
)
@patch(
"stripe.Customer.retrieve",
return_value=deepcopy(FAKE_CUSTOMER_II),
autospec=True,
)
@patch(
"stripe.SubscriptionItem.retrieve",
return_value=deepcopy(FAKE_SUBSCRIPTION_ITEM),
autospec=True,
)
@patch(
"stripe.Subscription.retrieve",
return_value=deepcopy(FAKE_INVOICE_METERED_SUBSCRIPTION_USAGE),
autospec=True,
)
def test_sync_from_stripe_data_with_null_invoice(
self,
subscription_retrieve_mock,
subscription_item_retrieve_mock,
customer_retrieve_mock,
product_retrieve_mock,
plan_retrieve_mock,
):
fake_usage_data = deepcopy(FAKE_USAGE_RECORD_SUMMARY)
usage_record_summary = UsageRecordSummary.sync_from_stripe_data(
fake_usage_data["data"][0]
)
self.assertEqual(usage_record_summary.id, fake_usage_data["data"][0]["id"])
self.assertEqual(
usage_record_summary.subscription_item.id,
fake_usage_data["data"][0]["subscription_item"],
)
self.assert_fks(
usage_record_summary,
expected_blank_fks={
"djstripe.Customer.coupon",
"djstripe.Customer.default_payment_method",
"djstripe.Customer.subscriber",
"djstripe.Subscription.default_payment_method",
"djstripe.Subscription.default_source",
"djstripe.Subscription.pending_setup_intent",
"djstripe.Subscription.schedule",
"djstripe.Subscription.latest_invoice",
"djstripe.UsageRecordSummary.invoice",
},
)
tests.test_utils
dj-stripe Utilities Tests.
tests.test_utils.TZ_IS_UTC
tests.test_utils.TestGetSupportedCurrencyChoices
tests.test_utils.TestGetSupportedCurrencyChoices.test_get_choices(self, stripe_account_retrieve_mock, stripe_countryspec_retrieve_mock)
Source code in tests/test_utils.py
@patch(
"stripe.CountrySpec.retrieve",
return_value={"supported_payment_currencies": ["usd", "cad", "eur"]},
)
@patch(
"stripe.Account.retrieve",
return_value={"country": "US"},
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
def test_get_choices(
self, stripe_account_retrieve_mock, stripe_countryspec_retrieve_mock
):
# Simple test to test sure that at least one currency choice tuple is returned.
currency_choices = get_supported_currency_choices(None)
stripe_account_retrieve_mock.assert_called_once_with()
stripe_countryspec_retrieve_mock.assert_called_once_with("US")
self.assertGreaterEqual(
len(currency_choices), 1, "Currency choices pull returned an empty list."
)
self.assertEqual(
tuple, type(currency_choices[0]), "Currency choices are not tuples."
)
self.assertIn(("usd", "USD"), currency_choices, "USD not in currency choices.")
tests.test_utils.TestTimestampConversion
tests.test_utils.TestTimestampConversion.test_conversion(self)
Source code in tests/test_utils.py
def test_conversion(self):
stamp = convert_tstamp(1365567407)
self.assertEqual(stamp, datetime(2013, 4, 10, 4, 16, 47, tzinfo=timezone.utc))
tests.test_utils.TestTimestampConversion.test_conversion_no_tz(self)
Source code in tests/test_utils.py
@skipIf(not TZ_IS_UTC, "Skipped because timezone is not UTC.")
@override_settings(USE_TZ=False)
def test_conversion_no_tz(self):
stamp = convert_tstamp(1365567407)
self.assertEqual(stamp, datetime(2013, 4, 10, 4, 16, 47))
tests.test_utils.TestUtils
tests.test_utils.TestUtils.test_get_friendly_currency_amount(self)
Source code in tests/test_utils.py
def test_get_friendly_currency_amount(self):
self.assertEqual(
get_friendly_currency_amount(Decimal("1.001"), "usd"), "$1.00 USD"
)
self.assertEqual(
get_friendly_currency_amount(Decimal("10"), "usd"), "$10.00 USD"
)
self.assertEqual(
get_friendly_currency_amount(Decimal("10.50"), "usd"), "$10.50 USD"
)
self.assertEqual(
get_friendly_currency_amount(Decimal("10.51"), "cad"), "$10.51 CAD"
)
self.assertEqual(
get_friendly_currency_amount(Decimal("9.99"), "eur"), "€9.99 EUR"
)
tests.test_webhooks
dj-stripe Webhook Tests.
tests.test_webhooks.pytestmark
Classes
tests.test_webhooks.TestGetRemoteIp
tests.test_webhooks.TestGetRemoteIp.RequestClass
tests.test_webhooks.TestGetRemoteIp.RequestClass.META
property
readonly
tests.test_webhooks.TestGetRemoteIp.RequestClass.__init__(self, data)
special
Source code in tests/test_webhooks.py
def __init__(self, data):
self.data = data
tests.test_webhooks.TestGetRemoteIp.test_get_remote_ip(self, data)
Source code in tests/test_webhooks.py
@pytest.mark.parametrize(
"data",
[
{"HTTP_X_FORWARDED_FOR": "127.0.0.1,345.5.5.3,451.1.1.2"},
{
"REMOTE_ADDR": "422.0.0.1",
"HTTP_X_FORWARDED_FOR": "127.0.0.1,345.5.5.3,451.1.1.2",
},
{
"REMOTE_ADDR": "127.0.0.1",
},
],
)
def test_get_remote_ip(self, data):
request = self.RequestClass(data)
assert get_remote_ip(request) == "127.0.0.1"
tests.test_webhooks.TestGetRemoteIp.test_get_remote_ip_remote_addr_is_none(self, data)
Source code in tests/test_webhooks.py
@pytest.mark.parametrize(
"data",
[
{
"REMOTE_ADDR": "",
},
{
"pqwwe": "127.0.0.1",
},
],
)
def test_get_remote_ip_remote_addr_is_none(self, data):
request = self.RequestClass(data)
# ensure warning is raised
with pytest.warns(None) as recorded_warning:
assert get_remote_ip(request) == "0.0.0.0"
assert len(recorded_warning) == 1
assert (
"Could not determine remote IP (missing REMOTE_ADDR)."
in recorded_warning[0].message.args[0]
)
tests.test_webhooks.TestWebhookEventTrigger
Test class to test WebhookEventTrigger model and its methods
Methods
tests.test_webhooks.TestWebhookEventTrigger.test___str__(self)
Source code in tests/test_webhooks.py
def test___str__(self):
self.assertEqual(WebhookEventTrigger.objects.count(), 0)
resp = self._send_event(FAKE_EVENT_TEST_CHARGE_SUCCEEDED)
self.assertEqual(resp.status_code, 200)
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
webhookeventtrigger = WebhookEventTrigger.objects.first()
self.assertEqual(
f"id={webhookeventtrigger.id}, valid={webhookeventtrigger.valid}, processed={webhookeventtrigger.processed}",
str(webhookeventtrigger),
)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_error(self, event_retrieve_mock, transfer_retrieve_mock, mock_invoke_webhook_handlers)
Test the case where webhook processing fails to ensure we rollback and do not commit the Event object to the database.
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_SECRET="")
@patch.object(target=Event, attribute="invoke_webhook_handlers", autospec=True)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch("stripe.Event.retrieve", autospec=True)
def test_webhook_error(
self, event_retrieve_mock, transfer_retrieve_mock, mock_invoke_webhook_handlers
):
"""Test the case where webhook processing fails to ensure we rollback
and do not commit the Event object to the database.
"""
mock_invoke_webhook_handlers.side_effect = KeyError("Test error")
fake_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
event_retrieve_mock.return_value = fake_event
with self.assertRaises(KeyError):
self._send_event(fake_event)
self.assertEqual(Event.objects.count(), 0)
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
event_trigger = WebhookEventTrigger.objects.first()
self.assertEqual(event_trigger.is_test_event, False)
self.assertEqual(event_trigger.exception, "'Test error'")
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_good_connect_account(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_SECRET="")
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_CUSTOM_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch("stripe.Event.retrieve", autospec=True)
def test_webhook_good_connect_account(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
fake_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
fake_event["account"] = FAKE_CUSTOM_ACCOUNT["id"]
event_retrieve_mock.return_value = fake_event
resp = self._send_event(fake_event)
self.assertEqual(resp.status_code, 200)
self.assertEqual(Event.objects.count(), 1)
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
event_trigger = WebhookEventTrigger.objects.first()
self.assertEqual(event_trigger.is_test_event, False)
self.assertEqual(
event_trigger.stripe_trigger_account.id, FAKE_CUSTOM_ACCOUNT["id"]
)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_good_platform_account(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_SECRET="")
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch("stripe.Event.retrieve", autospec=True)
def test_webhook_good_platform_account(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
fake_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
event_retrieve_mock.return_value = fake_event
resp = self._send_event(fake_event)
self.assertEqual(resp.status_code, 200)
self.assertEqual(Event.objects.count(), 1)
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
event_trigger = WebhookEventTrigger.objects.first()
self.assertEqual(event_trigger.is_test_event, False)
self.assertEqual(
event_trigger.stripe_trigger_account.id, FAKE_STANDARD_ACCOUNT["id"]
)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_invalid_verify_signature_fail(self, event_retrieve_mock, transfer_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(
DJSTRIPE_WEBHOOK_VALIDATION="verify_signature",
DJSTRIPE_WEBHOOK_SECRET="whsec_XXXXX",
)
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_TRANSFER_CREATED),
autospec=True,
)
def test_webhook_invalid_verify_signature_fail(
self,
event_retrieve_mock,
transfer_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
invalid_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
invalid_event["id"] = "evt_invalid"
invalid_event["data"]["valid"] = "not really"
resp = self._send_event(invalid_event)
self.assertEqual(resp.status_code, 400)
self.assertFalse(Event.objects.filter(id="evt_invalid").exists())
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_no_signature(self)
Source code in tests/test_webhooks.py
def test_webhook_no_signature(self):
self.assertEqual(WebhookEventTrigger.objects.count(), 0)
resp = Client().post(
reverse("djstripe:webhook"), "{}", content_type="application/json"
)
self.assertEqual(resp.status_code, 400)
self.assertEqual(WebhookEventTrigger.objects.count(), 0)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_no_validation_pass(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, verify_header_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_VALIDATION=None)
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch("stripe.WebhookSignature.verify_header", autospec=True)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_TRANSFER_CREATED),
autospec=True,
)
def test_webhook_no_validation_pass(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
verify_header_mock,
transfer__attach_object_post_save_hook_mock,
):
invalid_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
invalid_event["id"] = "evt_invalid"
invalid_event["data"]["valid"] = "not really"
resp = self._send_event(invalid_event)
self.assertEqual(resp.status_code, 200)
self.assertTrue(Event.objects.filter(id="evt_invalid").exists())
event_retrieve_mock.assert_not_called()
verify_header_mock.assert_not_called()
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_remote_addr_is_empty_string(self)
Source code in tests/test_webhooks.py
def test_webhook_remote_addr_is_empty_string(self):
self.assertEqual(WebhookEventTrigger.objects.count(), 0)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
Client().post(
reverse("djstripe:webhook"),
"{}",
content_type="application/json",
HTTP_STRIPE_SIGNATURE="PLACEHOLDER",
REMOTE_ADDR="",
)
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
event_trigger = WebhookEventTrigger.objects.first()
self.assertEqual(event_trigger.remote_ip, "0.0.0.0")
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_remote_addr_is_none(self)
Source code in tests/test_webhooks.py
def test_webhook_remote_addr_is_none(self):
self.assertEqual(WebhookEventTrigger.objects.count(), 0)
with warnings.catch_warnings():
warnings.simplefilter("ignore")
Client().post(
reverse("djstripe:webhook"),
"{}",
content_type="application/json",
HTTP_STRIPE_SIGNATURE="PLACEHOLDER",
REMOTE_ADDR=None,
)
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
event_trigger = WebhookEventTrigger.objects.first()
self.assertEqual(event_trigger.remote_ip, "0.0.0.0")
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_reraise_exception(self, webhook_event_process_mock, webhook_event_validate_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"djstripe.models.WebhookEventTrigger.validate", return_value=True, autospec=True
)
@patch("djstripe.models.WebhookEventTrigger.process", autospec=True)
def test_webhook_reraise_exception(
self,
webhook_event_process_mock,
webhook_event_validate_mock,
transfer__attach_object_post_save_hook_mock,
):
class ProcessException(Exception):
pass
exception_message = "process fail"
webhook_event_process_mock.side_effect = ProcessException(exception_message)
self.assertEqual(WebhookEventTrigger.objects.count(), 0)
fake_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
with self.assertRaisesMessage(ProcessException, exception_message):
self._send_event(fake_event)
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
event_trigger = WebhookEventTrigger.objects.first()
self.assertEqual(event_trigger.exception, exception_message)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_retrieve_event_fail(self, event_retrieve_mock, transfer_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_VALIDATION="retrieve_event")
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_TRANSFER_CREATED),
autospec=True,
)
def test_webhook_retrieve_event_fail(
self,
event_retrieve_mock,
transfer_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
invalid_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
invalid_event["id"] = "evt_invalid"
invalid_event["data"]["valid"] = "not really"
resp = self._send_event(invalid_event)
self.assertEqual(resp.status_code, 400)
self.assertFalse(Event.objects.filter(id="evt_invalid").exists())
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_retrieve_event_pass(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_VALIDATION="retrieve_event")
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_TRANSFER_CREATED),
autospec=True,
)
def test_webhook_retrieve_event_pass(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
resp = self._send_event(FAKE_EVENT_TRANSFER_CREATED)
self.assertEqual(resp.status_code, 200)
event_retrieve_mock.assert_called_once_with(
api_key=djstripe_settings.STRIPE_SECRET_KEY,
id=FAKE_EVENT_TRANSFER_CREATED["id"],
)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_test_event(self)
Source code in tests/test_webhooks.py
def test_webhook_test_event(self):
self.assertEqual(WebhookEventTrigger.objects.count(), 0)
resp = self._send_event(FAKE_EVENT_TEST_CHARGE_SUCCEEDED)
self.assertEqual(resp.status_code, 200)
self.assertFalse(Event.objects.filter(id=TEST_EVENT_ID).exists())
self.assertEqual(WebhookEventTrigger.objects.count(), 1)
event_trigger = WebhookEventTrigger.objects.first()
self.assertTrue(event_trigger.is_test_event)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_verify_signature_pass(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, verify_header_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(
DJSTRIPE_WEBHOOK_VALIDATION="verify_signature",
DJSTRIPE_WEBHOOK_SECRET="whsec_XXXXX",
)
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.WebhookSignature.verify_header",
return_value=True,
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch(
"stripe.Event.retrieve",
return_value=deepcopy(FAKE_EVENT_TRANSFER_CREATED),
autospec=True,
)
def test_webhook_verify_signature_pass(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
verify_header_mock,
transfer__attach_object_post_save_hook_mock,
):
resp = self._send_event(FAKE_EVENT_TRANSFER_CREATED)
self.assertEqual(resp.status_code, 200)
self.assertFalse(Event.objects.filter(id="evt_invalid").exists())
verify_header_mock.assert_called_once_with(
json.dumps(FAKE_EVENT_TRANSFER_CREATED),
"PLACEHOLDER",
djstripe_settings.WEBHOOK_SECRET,
djstripe_settings.WEBHOOK_TOLERANCE,
)
event_retrieve_mock.assert_not_called()
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_with_custom_callback(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, webhook_event_callback_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_SECRET="")
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch.object(
djstripe_settings, "WEBHOOK_EVENT_CALLBACK", return_value=mock_webhook_handler
)
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch("stripe.Event.retrieve", autospec=True)
def test_webhook_with_custom_callback(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
webhook_event_callback_mock,
transfer__attach_object_post_save_hook_mock,
):
fake_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
event_retrieve_mock.return_value = fake_event
resp = self._send_event(fake_event)
self.assertEqual(resp.status_code, 200)
webhook_event_trigger = WebhookEventTrigger.objects.get()
webhook_event_callback_mock.called_once_with(webhook_event_trigger)
tests.test_webhooks.TestWebhookEventTrigger.test_webhook_with_transfer_event_duplicate(self, event_retrieve_mock, transfer_retrieve_mock, account_retrieve_mock, transfer__attach_object_post_save_hook_mock)
Source code in tests/test_webhooks.py
@override_settings(DJSTRIPE_WEBHOOK_SECRET="")
@patch.object(Transfer, "_attach_objects_post_save_hook")
@patch(
"stripe.Account.retrieve",
return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)
@patch(
"stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
)
@patch("stripe.Event.retrieve", autospec=True)
def test_webhook_with_transfer_event_duplicate(
self,
event_retrieve_mock,
transfer_retrieve_mock,
account_retrieve_mock,
transfer__attach_object_post_save_hook_mock,
):
fake_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
event_retrieve_mock.return_value = fake_event
resp = self._send_event(fake_event)
self.assertEqual(resp.status_code, 200)
self.assertTrue(Event.objects.filter(type="transfer.created").exists())
self.assertEqual(1, Event.objects.filter(type="transfer.created").count())
# Duplication
resp = self._send_event(fake_event)
self.assertEqual(resp.status_code, 200)
self.assertEqual(1, Event.objects.filter(type="transfer.created").count())
tests.test_webhooks.TestWebhookHandlers
Methods
tests.test_webhooks.TestWebhookHandlers.setUp(self)
Hook method for setting up the test fixture before exercising it.
Source code in tests/test_webhooks.py
def setUp(self):
# Reset state of registrations per test
patcher = patch.object(
webhooks, "registrations", new_callable=(lambda: defaultdict(list))
)
self.addCleanup(patcher.stop)
self.registrations = patcher.start()
patcher = patch.object(webhooks, "registrations_global", new_callable=list)
self.addCleanup(patcher.stop)
self.registrations_global = patcher.start()
tests.test_webhooks.TestWebhookHandlers.test_event_handle_registation_with_list_of_strings(self)
Source code in tests/test_webhooks.py
def test_event_handle_registation_with_list_of_strings(self):
func_mock = Mock()
handler("foo", "bar")(func_mock)
event1 = self._call_handlers("foo.bar", {"data": "foo"}) # handled
event2 = self._call_handlers("bar.foo", {"data": "bar"}) # handled
self.assertEqual(2, func_mock.call_count)
func_mock.assert_has_calls([call(event=event1), call(event=event2)])
tests.test_webhooks.TestWebhookHandlers.test_event_handle_registation_with_string(self)
Source code in tests/test_webhooks.py
def test_event_handle_registation_with_string(self):
func_mock = Mock()
handler("foo")(func_mock)
event = self._call_handlers("foo.bar", {"data": "foo"}) # handled
self.assertEqual(1, func_mock.call_count)
func_mock.assert_called_with(event=event)
tests.test_webhooks.TestWebhookHandlers.test_event_handler_registration(self)
Source code in tests/test_webhooks.py
def test_event_handler_registration(self):
global_func_mock = Mock()
handler_all()(global_func_mock)
func_mock = Mock()
handler("foo")(func_mock)
event = self._call_handlers("foo.bar", {"data": "foo"}) # handled
self._call_handlers("bar.foo", {"data": "foo"}) # not handled
self.assertEqual(2, global_func_mock.call_count) # called each time
self.assertEqual(1, func_mock.call_count)
func_mock.assert_called_with(event=event)
tests.test_webhooks.TestWebhookHandlers.test_event_subtype_handler_registration(self)
Source code in tests/test_webhooks.py
def test_event_subtype_handler_registration(self):
global_func_mock = Mock()
handler_all()(global_func_mock)
func_mock = Mock()
handler("foo.bar")(func_mock)
event1 = self._call_handlers("foo.bar", {"data": "foo"}) # handled
event2 = self._call_handlers("foo.bar.wib", {"data": "foo"}) # handled
self._call_handlers("foo.baz", {"data": "foo"}) # not handled
self.assertEqual(3, global_func_mock.call_count) # called each time
self.assertEqual(2, func_mock.call_count)
func_mock.assert_has_calls([call(event=event1), call(event=event2)])
tests.test_webhooks.TestWebhookHandlers.test_global_handler_registration(self)
Source code in tests/test_webhooks.py
def test_global_handler_registration(self):
func_mock = Mock()
handler_all()(func_mock)
event = self._call_handlers("wib.ble", {"data": "foo"}) # handled
self.assertEqual(1, func_mock.call_count)
func_mock.assert_called_with(event=event)
tests.test_webhooks.TestWebhookHandlers.test_global_handler_registration_with_function(self)
Source code in tests/test_webhooks.py
def test_global_handler_registration_with_function(self):
func_mock = Mock()
handler_all(func_mock)
event = self._call_handlers("wib.ble", {"data": "foo"}) # handled
self.assertEqual(1, func_mock.call_count)
func_mock.assert_called_with(event=event)
tests.test_webhooks.TestWebhookHandlers.test_webhook_event_trigger_invalid_body(self)
Source code in tests/test_webhooks.py
def test_webhook_event_trigger_invalid_body(self):
trigger = WebhookEventTrigger(remote_ip="127.0.0.1", body="invalid json")
assert not trigger.json_body
tests.test_webhooks.mock_webhook_handler(webhook_event_trigger)
Source code in tests/test_webhooks.py
def mock_webhook_handler(webhook_event_trigger):
webhook_event_trigger.process()
tests.test_zz_jsonfield
Tests for JSONField
Due to their nature messing with subclassing, these tests must be run last.
tests.test_zz_jsonfield.TestFallbackJSONField
tests.test_zz_jsonfield.TestFallbackJSONField.test_jsonfield_inheritance(self)
Source code in tests/test_zz_jsonfield.py
def test_jsonfield_inheritance(self):
self.assertTrue(issubclass(import_jsonfield(), UglyJSONField))
tests.test_zz_jsonfield.TestNativeJSONField
tests.test_zz_jsonfield.TestNativeJSONField.test_jsonfield_inheritance(self)
Source code in tests/test_zz_jsonfield.py
def test_jsonfield_inheritance(self):
self.assertTrue(issubclass(import_jsonfield(), DjangoJSONField))
tests.urls
tests.urls.urlpatterns
tests.urls.empty_view(request)
Source code in tests/urls.py
def empty_view(request):
return HttpResponse()