From 49d3c484642cb1ecaf0364259fa59785b9936e51 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 6 Feb 2023 15:56:10 +0000 Subject: [PATCH] feat: Add django simple history ent-6730 --- .annotation_safe_list.yml | 6 ++ .gitignore | 1 + default.db | 0 openedx_ledger/__init__.py | 2 +- openedx_ledger/admin.py | 7 +- ...istoricalreversal_historicaltransaction.py | 92 +++++++++++++++++++ openedx_ledger/models.py | 4 + test_settings.py | 2 + 8 files changed, 110 insertions(+), 4 deletions(-) delete mode 100644 default.db create mode 100644 openedx_ledger/migrations/0002_historicalledger_historicalreversal_historicaltransaction.py diff --git a/.annotation_safe_list.yml b/.annotation_safe_list.yml index 62eaaa7..7c52648 100644 --- a/.annotation_safe_list.yml +++ b/.annotation_safe_list.yml @@ -19,6 +19,12 @@ auth.User: ".. pii_retirement": "consumer_api" contenttypes.ContentType: ".. no_pii:": "This model has no PII" +openedx_ledger.HistoricalLedger: + ".. no_pii:": "This model has no PII" +openedx_ledger.HistoricalReversal: + ".. no_pii:": "This model has no PII" +openedx_ledger.HistoricalTransaction: + ".. no_pii:": "This model has no PII" sessions.Session: ".. no_pii:": "This model has no PII" social_django.Association: diff --git a/.gitignore b/.gitignore index 96b4e67..cfd58cc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.py[cod] __pycache__ .pytest_cache +default.db # C extensions *.so diff --git a/default.db b/default.db deleted file mode 100644 index e69de29..0000000 diff --git a/openedx_ledger/__init__.py b/openedx_ledger/__init__.py index 3b6f0cf..688f206 100644 --- a/openedx_ledger/__init__.py +++ b/openedx_ledger/__init__.py @@ -1,6 +1,6 @@ """ A library that records transactions against a ledger, denominated in units of value. """ -__version__ = "0.1.1" +__version__ = "0.1.2" default_app_config = "openedx_ledger.apps.EdxLedgerConfig" diff --git a/openedx_ledger/admin.py b/openedx_ledger/admin.py index 536638e..0e760ba 100644 --- a/openedx_ledger/admin.py +++ b/openedx_ledger/admin.py @@ -2,12 +2,13 @@ Admin configuration for openedx_ledger models. """ from django.contrib import admin +from simple_history.admin import SimpleHistoryAdmin from openedx_ledger import models @admin.register(models.Ledger) -class LedgerAdmin(admin.ModelAdmin): +class LedgerAdmin(SimpleHistoryAdmin): """ Admin configuration for the Ledger model. """ @@ -39,7 +40,7 @@ def balance(self, obj): @admin.register(models.Transaction) -class TransactionAdmin(admin.ModelAdmin): +class TransactionAdmin(SimpleHistoryAdmin): """ Admin configuration for the Transaction model. """ @@ -54,7 +55,7 @@ class Meta: @admin.register(models.Reversal) -class ReversalAdmin(admin.ModelAdmin): +class ReversalAdmin(SimpleHistoryAdmin): """ Admin configuration for the Reversal model. """ diff --git a/openedx_ledger/migrations/0002_historicalledger_historicalreversal_historicaltransaction.py b/openedx_ledger/migrations/0002_historicalledger_historicalreversal_historicaltransaction.py new file mode 100644 index 0000000..56ffbdc --- /dev/null +++ b/openedx_ledger/migrations/0002_historicalledger_historicalreversal_historicaltransaction.py @@ -0,0 +1,92 @@ +# Generated by Django 3.2.16 on 2023-02-14 12:49 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import jsonfield.fields +import model_utils.fields +import simple_history.models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('openedx_ledger', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='HistoricalTransaction', + fields=[ + ('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')), + ('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ('idempotency_key', models.CharField(db_index=True, max_length=255)), + ('quantity', models.BigIntegerField()), + ('metadata', jsonfield.fields.JSONField(blank=True, null=True)), + ('lms_user_id', models.IntegerField(blank=True, db_index=True, null=True)), + ('content_uuid', models.UUIDField(blank=True, db_index=True, null=True)), + ('reference_id', models.CharField(blank=True, db_index=True, help_text='The identifier of the item acquired via the transaction.e.g. a course enrollment ID, an entitlement ID, a subscription license ID.', max_length=255, null=True)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField()), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ('ledger', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='openedx_ledger.ledger')), + ], + options={ + 'verbose_name': 'historical transaction', + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': 'history_date', + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + migrations.CreateModel( + name='HistoricalReversal', + fields=[ + ('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')), + ('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ('idempotency_key', models.CharField(db_index=True, max_length=255)), + ('quantity', models.BigIntegerField()), + ('metadata', jsonfield.fields.JSONField(blank=True, null=True)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField()), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ('transaction', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='openedx_ledger.transaction')), + ], + options={ + 'verbose_name': 'historical reversal', + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': 'history_date', + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + migrations.CreateModel( + name='HistoricalLedger', + fields=[ + ('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')), + ('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False)), + ('idempotency_key', models.CharField(db_index=True, max_length=255)), + ('unit', models.CharField(choices=[('usd_cents', 'U.S. Dollar (Cents)'), ('seats', 'Seats in a course'), ('jpy', 'Japanese Yen')], db_index=True, default='usd_cents', max_length=255)), + ('metadata', jsonfield.fields.JSONField(blank=True, null=True)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField()), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'historical ledger', + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': 'history_date', + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + ] diff --git a/openedx_ledger/models.py b/openedx_ledger/models.py index c040264..2cacdde 100644 --- a/openedx_ledger/models.py +++ b/openedx_ledger/models.py @@ -8,6 +8,7 @@ from django.db.transaction import atomic from jsonfield.fields import JSONField from model_utils.models import TimeStampedModel +from simple_history.models import HistoricalRecords # Units on the ledger model - probably yes. TODO: say why # Unit conversion - price/seat is captured somewhere, is it in here? @@ -80,6 +81,7 @@ class Ledger(TimeStampedModelWithUuid): blank=True, null=True, ) + history = HistoricalRecords() def balance(self): """ @@ -170,6 +172,7 @@ class Meta: "e.g. a course enrollment ID, an entitlement ID, a subscription license ID." ), ) + history = HistoricalRecords() class Reversal(BaseTransaction): @@ -192,5 +195,6 @@ class Meta: null=True, on_delete=models.SET_NULL, ) + history = HistoricalRecords() # Reversal quantities should always have the opposite sign of the transaction (i.e. negative) # We have to enforce this somehow... diff --git a/test_settings.py b/test_settings.py index 7a8e4d1..e292ca0 100644 --- a/test_settings.py +++ b/test_settings.py @@ -33,6 +33,7 @@ def root(*args): 'django.contrib.messages', 'django.contrib.sessions', 'openedx_ledger', + 'simple_history', ) LOCALE_PATHS = [ @@ -47,6 +48,7 @@ def root(*args): 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', + 'simple_history.middleware.HistoryRequestMiddleware', ) TEMPLATES = [{