# Generated by Django 5.2.17 on 2026-09-06 19:02 import django.core.validators import django.db.models.deletion import uuid from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Account', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('name', models.CharField(max_length=255, unique=True)), ('kind', models.CharField(choices=[('BANK', 'Bank'), ('CREDIT_CARD', 'Credit card')], max_length=16)), ('currency', models.CharField(default='BRL', max_length=3, validators=[django.core.validators.RegexValidator('\\A[A-Z]{3}\\Z', 'Use three uppercase ASCII letters.')])), ('archived', models.BooleanField(default=False)), ], options={ 'constraints': [models.CheckConstraint(condition=models.Q(('kind__in', ['BANK', 'CREDIT_CARD'])), name='account_valid_kind'), models.CheckConstraint(condition=models.Q(('currency__regex', '^[A-Z]{3}$')), name='account_valid_currency'), models.CheckConstraint(condition=models.Q(('name__regex', '\\S')), name='account_nonblank_name')], }, ), migrations.CreateModel( name='AuditEvent', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('actor_kind', models.CharField(choices=[('HUMAN', 'Human'), ('APPLICATION', 'Application'), ('AGENT', 'Agent')], max_length=16)), ('actor_identifier', models.CharField(max_length=255)), ('operation', models.CharField(max_length=128)), ('target_id', models.UUIDField(blank=True, null=True)), ('outcome', models.CharField(choices=[('SUCCESS', 'Success'), ('FAILURE', 'Failure')], max_length=16)), ('changed_fields', models.JSONField(blank=True, default=list)), ('error_code', models.CharField(blank=True, max_length=128)), ], options={ 'constraints': [models.CheckConstraint(condition=models.Q(('actor_kind__in', ['HUMAN', 'APPLICATION', 'AGENT'])), name='audit_valid_actor'), models.CheckConstraint(condition=models.Q(('outcome__in', ['SUCCESS', 'FAILURE'])), name='audit_valid_outcome'), models.CheckConstraint(condition=models.Q(('actor_identifier__regex', '\\S')), name='audit_nonblank_actor'), models.CheckConstraint(condition=models.Q(('operation__regex', '\\S')), name='audit_nonblank_operation')], }, ), migrations.CreateModel( name='CardStatement', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('period_start', models.DateField()), ('period_end', models.DateField()), ('due_date', models.DateField()), ('statement_balance', models.DecimalField(blank=True, decimal_places=2, max_digits=18, null=True)), ('account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='statements', to='finance.account')), ], ), migrations.CreateModel( name='Category', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('name', models.CharField(max_length=255, unique=True)), ('kind', models.CharField(choices=[('INCOME', 'Income'), ('EXPENSE', 'Expense')], max_length=16)), ('archived', models.BooleanField(default=False)), ], options={ 'constraints': [models.CheckConstraint(condition=models.Q(('kind__in', ['INCOME', 'EXPENSE'])), name='category_valid_kind'), models.CheckConstraint(condition=models.Q(('name__regex', '\\S')), name='category_nonblank_name')], }, ), migrations.CreateModel( name='InstallmentPlan', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('description', models.TextField(blank=True)), ('total_installments', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(1)])), ('account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='installment_plans', to='finance.account')), ], ), migrations.CreateModel( name='Payee', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('name', models.CharField(max_length=255, unique=True)), ('archived', models.BooleanField(default=False)), ], options={ 'constraints': [models.CheckConstraint(condition=models.Q(('name__regex', '\\S')), name='payee_nonblank_name')], }, ), migrations.CreateModel( name='Transaction', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('amount', models.DecimalField(decimal_places=2, max_digits=18)), ('posting_date', models.DateField()), ('occurrence_date', models.DateField(blank=True, null=True)), ('description', models.TextField(blank=True)), ('kind', models.CharField(choices=[('INCOME', 'Income'), ('EXPENSE', 'Expense'), ('TRANSFER', 'Transfer'), ('REFUND', 'Refund'), ('OPENING', 'Opening')], max_length=16)), ('installment_number', models.PositiveIntegerField(blank=True, null=True, validators=[django.core.validators.MinValueValidator(1)])), ('account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='transactions', to='finance.account')), ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='transactions', to='finance.category')), ('installment_plan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='transactions', to='finance.installmentplan')), ('payee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='transactions', to='finance.payee')), ('refund_of', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='refunds', to='finance.transaction')), ('statement', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='transactions', to='finance.cardstatement')), ], ), migrations.CreateModel( name='SourceRecord', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('document_hash', models.CharField(max_length=64, validators=[django.core.validators.RegexValidator('\\A[0-9a-f]{64}\\Z', 'Use a lowercase SHA-256 hexadecimal digest.')])), ('source_format', models.CharField(choices=[('BANK_CSV', 'Bank CSV'), ('OUROCARD_TXT', 'Ourocard TXT')], max_length=16)), ('parser_version', models.CharField(max_length=128)), ('item_locator', models.CharField(max_length=255)), ('transaction', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='source_records', to='finance.transaction')), ], ), migrations.CreateModel( name='Transfer', fields=[ ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), ('created_at', models.DateTimeField(auto_now_add=True)), ('updated_at', models.DateTimeField(auto_now=True)), ('incoming', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='incoming_transfer', to='finance.transaction')), ('outgoing', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='outgoing_transfer', to='finance.transaction')), ], ), migrations.AddConstraint( model_name='cardstatement', constraint=models.CheckConstraint(condition=models.Q(('period_end__gte', models.F('period_start'))), name='statement_period_order'), ), migrations.AddConstraint( model_name='cardstatement', constraint=models.CheckConstraint(condition=models.Q(('due_date__gte', models.F('period_end'))), name='statement_due_order'), ), migrations.AddConstraint( model_name='cardstatement', constraint=models.UniqueConstraint(fields=('account', 'period_end'), name='statement_account_period_unique'), ), migrations.AddConstraint( model_name='installmentplan', constraint=models.CheckConstraint(condition=models.Q(('total_installments__gt', 0)), name='plan_positive_total'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(('kind__in', ['INCOME', 'EXPENSE', 'TRANSFER', 'REFUND', 'OPENING'])), name='transaction_valid_kind'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(('amount', 0), _negated=True), name='transaction_nonzero_amount'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(models.Q(('amount__gt', 0), ('kind__in', ['INCOME', 'REFUND'])), models.Q(('amount__lt', 0), ('kind', 'EXPENSE')), ('kind__in', ['TRANSFER', 'OPENING']), _connector='OR'), name='transaction_kind_sign'), ), migrations.AddConstraint( model_name='transaction', constraint=models.UniqueConstraint(condition=models.Q(('kind', 'OPENING')), fields=('account',), name='transaction_one_opening'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(models.Q(('kind', 'OPENING'), _negated=True), models.Q(('category__isnull', True), ('installment_number__isnull', True), ('installment_plan__isnull', True), ('payee__isnull', True), ('refund_of__isnull', True), ('statement__isnull', True)), _connector='OR'), name='transaction_opening_unassociated'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(models.Q(('kind', 'TRANSFER'), _negated=True), models.Q(('category__isnull', True), ('installment_number__isnull', True), ('installment_plan__isnull', True), ('refund_of__isnull', True)), _connector='OR'), name='transaction_transfer_unclassified'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(('refund_of__isnull', True), ('kind', 'REFUND'), _connector='OR'), name='transaction_refund_link_kind'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(('refund_of__isnull', True), models.Q(('refund_of', models.F('id')), _negated=True), _connector='OR'), name='transaction_refund_not_self'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(models.Q(('installment_number__isnull', True), ('installment_plan__isnull', True)), models.Q(('installment_number__isnull', False), ('installment_plan__isnull', False)), _connector='OR'), name='transaction_installment_pair'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(('installment_number__isnull', True), ('installment_number__gt', 0), _connector='OR'), name='transaction_installment_positive'), ), migrations.AddConstraint( model_name='transaction', constraint=models.CheckConstraint(condition=models.Q(('installment_plan__isnull', True), ('kind', 'EXPENSE'), _connector='OR'), name='transaction_installment_expense'), ), migrations.AddConstraint( model_name='transaction', constraint=models.UniqueConstraint(condition=models.Q(('installment_plan__isnull', False)), fields=('installment_plan', 'installment_number'), name='transaction_installment_unique'), ), migrations.AddConstraint( model_name='sourcerecord', constraint=models.CheckConstraint(condition=models.Q(('source_format__in', ['BANK_CSV', 'OUROCARD_TXT'])), name='source_valid_format'), ), migrations.AddConstraint( model_name='sourcerecord', constraint=models.CheckConstraint(condition=models.Q(('document_hash__regex', '^[0-9a-f]{64}$')), name='source_valid_hash'), ), migrations.AddConstraint( model_name='sourcerecord', constraint=models.CheckConstraint(condition=models.Q(('parser_version__regex', '\\S')), name='source_nonblank_parser'), ), migrations.AddConstraint( model_name='sourcerecord', constraint=models.CheckConstraint(condition=models.Q(('item_locator__regex', '\\S')), name='source_nonblank_locator'), ), migrations.AddConstraint( model_name='sourcerecord', constraint=models.UniqueConstraint(fields=('document_hash', 'item_locator'), name='source_document_item_unique'), ), migrations.AddConstraint( model_name='transfer', constraint=models.CheckConstraint(condition=models.Q(('outgoing', models.F('incoming')), _negated=True), name='transfer_distinct_legs'), ), ]