
- Introduced a new `RecurrencePattern` model to manage recurrence details for expenses, allowing for daily, weekly, monthly, and yearly patterns. - Updated the `Expense` model to include fields for recurrence management, such as `is_recurring`, `recurrence_pattern_id`, and `next_occurrence`. - Modified the database schema to reflect these changes, including alterations to existing columns and the removal of obsolete fields. - Enhanced the expense creation logic to accommodate recurring expenses and updated related CRUD operations accordingly. - Implemented necessary migrations to ensure database integrity and support for the new features.
91 lines
4.8 KiB
Python
91 lines
4.8 KiB
Python
"""add_recurrence_pattern
|
|
|
|
Revision ID: 295cb070f266
|
|
Revises: 7cc1484074eb
|
|
Create Date: 2025-05-22 19:55:24.650524
|
|
|
|
"""
|
|
from typing import Sequence, Union
|
|
|
|
from alembic import op
|
|
import sqlalchemy as sa
|
|
from sqlalchemy.dialects import postgresql
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision: str = '295cb070f266'
|
|
down_revision: Union[str, None] = '7cc1484074eb'
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
def upgrade() -> None:
|
|
"""Upgrade schema."""
|
|
# ### commands auto generated by Alembic - please adjust! ###
|
|
op.alter_column('expenses', 'next_occurrence',
|
|
existing_type=postgresql.TIMESTAMP(),
|
|
type_=sa.DateTime(timezone=True),
|
|
existing_nullable=True)
|
|
op.drop_index('ix_expenses_recurring_next_occurrence', table_name='expenses', postgresql_where='(is_recurring = true)')
|
|
op.drop_constraint('fk_expenses_recurrence_pattern_id', 'expenses', type_='foreignkey')
|
|
op.drop_constraint('fk_expenses_parent_expense_id', 'expenses', type_='foreignkey')
|
|
op.drop_column('expenses', 'recurrence_pattern_id')
|
|
op.drop_column('expenses', 'last_occurrence')
|
|
op.drop_column('expenses', 'parent_expense_id')
|
|
op.alter_column('recurrence_patterns', 'days_of_week',
|
|
existing_type=postgresql.JSON(astext_type=sa.Text()),
|
|
type_=sa.String(),
|
|
existing_nullable=True)
|
|
op.alter_column('recurrence_patterns', 'end_date',
|
|
existing_type=postgresql.TIMESTAMP(),
|
|
type_=sa.DateTime(timezone=True),
|
|
existing_nullable=True)
|
|
op.alter_column('recurrence_patterns', 'created_at',
|
|
existing_type=postgresql.TIMESTAMP(),
|
|
type_=sa.DateTime(timezone=True),
|
|
existing_nullable=False)
|
|
op.alter_column('recurrence_patterns', 'updated_at',
|
|
existing_type=postgresql.TIMESTAMP(),
|
|
type_=sa.DateTime(timezone=True),
|
|
existing_nullable=False)
|
|
op.create_index(op.f('ix_settlement_activities_created_by_user_id'), 'settlement_activities', ['created_by_user_id'], unique=False)
|
|
op.create_index(op.f('ix_settlement_activities_expense_split_id'), 'settlement_activities', ['expense_split_id'], unique=False)
|
|
op.create_index(op.f('ix_settlement_activities_id'), 'settlement_activities', ['id'], unique=False)
|
|
op.create_index(op.f('ix_settlement_activities_paid_by_user_id'), 'settlement_activities', ['paid_by_user_id'], unique=False)
|
|
# ### end Alembic commands ###
|
|
|
|
|
|
def downgrade() -> None:
|
|
"""Downgrade schema."""
|
|
# ### commands auto generated by Alembic - please adjust! ###
|
|
op.drop_index(op.f('ix_settlement_activities_paid_by_user_id'), table_name='settlement_activities')
|
|
op.drop_index(op.f('ix_settlement_activities_id'), table_name='settlement_activities')
|
|
op.drop_index(op.f('ix_settlement_activities_expense_split_id'), table_name='settlement_activities')
|
|
op.drop_index(op.f('ix_settlement_activities_created_by_user_id'), table_name='settlement_activities')
|
|
op.alter_column('recurrence_patterns', 'updated_at',
|
|
existing_type=sa.DateTime(timezone=True),
|
|
type_=postgresql.TIMESTAMP(),
|
|
existing_nullable=False)
|
|
op.alter_column('recurrence_patterns', 'created_at',
|
|
existing_type=sa.DateTime(timezone=True),
|
|
type_=postgresql.TIMESTAMP(),
|
|
existing_nullable=False)
|
|
op.alter_column('recurrence_patterns', 'end_date',
|
|
existing_type=sa.DateTime(timezone=True),
|
|
type_=postgresql.TIMESTAMP(),
|
|
existing_nullable=True)
|
|
op.alter_column('recurrence_patterns', 'days_of_week',
|
|
existing_type=sa.String(),
|
|
type_=postgresql.JSON(astext_type=sa.Text()),
|
|
existing_nullable=True)
|
|
op.add_column('expenses', sa.Column('parent_expense_id', sa.INTEGER(), autoincrement=False, nullable=True))
|
|
op.add_column('expenses', sa.Column('last_occurrence', postgresql.TIMESTAMP(), autoincrement=False, nullable=True))
|
|
op.add_column('expenses', sa.Column('recurrence_pattern_id', sa.INTEGER(), autoincrement=False, nullable=True))
|
|
op.create_foreign_key('fk_expenses_parent_expense_id', 'expenses', 'expenses', ['parent_expense_id'], ['id'], ondelete='SET NULL')
|
|
op.create_foreign_key('fk_expenses_recurrence_pattern_id', 'expenses', 'recurrence_patterns', ['recurrence_pattern_id'], ['id'], ondelete='SET NULL')
|
|
op.create_index('ix_expenses_recurring_next_occurrence', 'expenses', ['is_recurring', 'next_occurrence'], unique=False, postgresql_where='(is_recurring = true)')
|
|
op.alter_column('expenses', 'next_occurrence',
|
|
existing_type=sa.DateTime(timezone=True),
|
|
type_=postgresql.TIMESTAMP(),
|
|
existing_nullable=True)
|
|
# ### end Alembic commands ###
|