Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,64 @@ Add ``STRIPE_USER_MODEL`` if it is different than settings.AUTH_USER_MODEL. In e
Add ``aa_stripe.api_urls`` into your url conf.


Development
===========

This is not a full Django app, but a library.
To take advantage of Django’s toolset, you need to temporarily:
- configure `aa_stripe/settings.py` to include all the required modules
- create a `manage.py` file at the root of this project to run Django commands


Here are the changes required in the `app_stripe/settings.py`:
```
INSTALLED_APPS = [
"django.contrib.contenttypes",
"django.contrib.auth",
"aa_stripe",
]
```


And here is an example of a minimalistic `manage.py` file:
```
#!/usr/bin/env python
import os
import sys

def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'aa_stripe.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable?"
) from exc
execute_from_command_line(sys.argv)

if __name__ == '__main__':
main()
```
Remember to make it executable by `chmod +x manage.py`.


Then, after activating your `virtual env` you can run the `./manage.py` command like in regular Django project.
For example, you will be able to create migrations automatically:

```bash
./manage.py makemigrations aa_stripe
```


Running Tests
=============
This project relies on `tox`, so in your shell please use the following command:

```bash
tox
```


Usage
=====

Expand Down
80 changes: 80 additions & 0 deletions aa_stripe/migrations/0023_alter_stripecharge_customer_and_more.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Generated by Django 4.2.20 on 2025-04-29 05:03

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models

remove_indexes = [
"DROP INDEX CONCURRENTLY IF EXISTS aa_stripe_stripecharge_user_id_6f76c244",
"DROP INDEX CONCURRENTLY IF EXISTS aa_stripe_stripecharge_stripe_refund_id_78d16b7f_like",
"DROP INDEX CONCURRENTLY IF EXISTS aa_stripe_stripecharge_stripe_refund_id_78d16b7f",
"DROP INDEX CONCURRENTLY IF EXISTS aa_stripe_stripecharge_stripe_charge_id_86aca19a",
"DROP INDEX CONCURRENTLY IF EXISTS aa_stripe_stripecharge_stripe_charge_id_86aca19a_like",
"DROP INDEX CONCURRENTLY IF EXISTS aa_stripe_stripecharge_customer_id_a6cd951b",
]


def drop_indexes_postgresql(apps, schema_editor):
"""
This function drops indexes for PostgreSQL database.
It will NOT run on SQLite during testing as it does NOT support:
- DROP INDEX CONCURRENTLY
- IF EXISTS
"""
if schema_editor.connection.vendor != "postgresql":
return # Skip for SQLite or other DBs

for sql in remove_indexes:
schema_editor.execute(sql)


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("aa_stripe", "0022_stripecharge_amount_refunded"),
]
atomic = False # CONCURRENTLY cannot run inside a transaction block

operations = [
migrations.SeparateDatabaseAndState(
database_operations=[
migrations.RunPython(
drop_indexes_postgresql,
reverse_code=migrations.RunPython.noop,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why no reverse?

),
],
state_operations=[
migrations.AlterField(
model_name="stripecharge",
name="customer",
field=models.ForeignKey(
db_index=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="aa_stripe.stripecustomer",
),
),
migrations.AlterField(
model_name="stripecharge",
name="stripe_charge_id",
field=models.CharField(blank=True, max_length=255),
),
migrations.AlterField(
model_name="stripecharge",
name="stripe_refund_id",
field=models.CharField(blank=True, max_length=255),
),
migrations.AlterField(
model_name="stripecharge",
name="user",
field=models.ForeignKey(
db_index=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="stripe_charges",
to=settings.AUTH_USER_MODEL,
),
),
],
)
]
18 changes: 14 additions & 4 deletions aa_stripe/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,17 +378,27 @@ def delete(self, *args, **kwargs):


class StripeCharge(StripeBasicModel):
user = models.ForeignKey(USER_MODEL, on_delete=models.CASCADE, related_name="stripe_charges")
customer = models.ForeignKey(StripeCustomer, on_delete=models.SET_NULL, null=True)
user = models.ForeignKey(
USER_MODEL,
on_delete=models.CASCADE,
related_name="stripe_charges",
db_index=False,
)
customer = models.ForeignKey(
StripeCustomer,
on_delete=models.SET_NULL,
null=True,
db_index=False,
)
amount = models.IntegerField(null=True, help_text=_("in cents"))
amount_refunded = models.IntegerField(null=True, help_text=_("in cents"), default=0)
is_charged = models.BooleanField(default=False)
is_refunded = models.BooleanField(default=False)
# if True, it will not be triggered through stripe_charge command
is_manual_charge = models.BooleanField(default=False)
charge_attempt_failed = models.BooleanField(default=False)
stripe_charge_id = models.CharField(max_length=255, blank=True, db_index=True)
stripe_refund_id = models.CharField(max_length=255, blank=True, db_index=True)
stripe_charge_id = models.CharField(max_length=255, blank=True, db_index=False)
stripe_refund_id = models.CharField(max_length=255, blank=True, db_index=False)
description = models.CharField(max_length=255, help_text=_("Description sent to Stripe"))
comment = models.CharField(max_length=255, help_text=_("Comment for internal information"))
content_type = models.ForeignKey(ContentType, null=True, on_delete=models.CASCADE)
Expand Down