From 37927e7fcdaced5d9a3504c153f4c7b9b0b6fd56 Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Mon, 31 Aug 2026 22:48:41 -0400 Subject: [PATCH 1/9] feat: transfer service --- bank-app/backend/services.py | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/bank-app/backend/services.py b/bank-app/backend/services.py index 3d100ba..b9f2884 100644 --- a/bank-app/backend/services.py +++ b/bank-app/backend/services.py @@ -78,3 +78,64 @@ def withdrawal(db: Session, account_id: UUID, amount: Decimal, idempotency_key: db.commit() return transaction + + +def transfer( + db: Session, + from_account: UUID, + to_account: UUID, + amount: Decimal, + idempotency_key: str, +): + f_acc = db.query(Account).filter(Account.id == from_account).first() + t_acc = db.query(Account).filter(Account.id == to_account).first() + + if from_account == to_account: + raise ValueError("Cannot fund same account") + + existing_transaction = ( + db.query(Transaction) + .filter(Transaction.idempotency_key == idempotency_key) + .all() + ) + + if existing_transaction: + return existing_transaction + + f_acc_balance_before = f_acc.balance + t_acc_balance_before = t_acc.balance + + if f_acc_balance_before < amount: + raise ValueError("Insufficient funds") + + f_acc_balance_after = f_acc_balance_before - amount + t_acc_balance_after = t_acc_balance_before + amount + + f_acc.balance = f_acc_balance_after + t_acc.balance = t_acc_balance_after + + transaction_sent = Transaction( + account_id=f_acc.id, + transaction_type="transfer", + amount=amount, + balance_before=f_acc_balance_before, + balance_after=f_acc_balance_after, + status="completed", + idempotency_key=idempotency_key, + ) + + transaction_received = Transaction( + account_id=t_acc.id, + transaction_type="transfer", + amount=amount, + balance_before=t_acc_balance_before, + balance_after=t_acc_balance_after, + status="completed", + idempotency_key=idempotency_key, + ) + + db.add(transaction_sent) + db.add(transaction_received) + db.commit() + + return [transaction_sent, transaction_received] From 019b24297a5c1addc00083cc4345f106af4f7700 Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Mon, 31 Aug 2026 22:49:12 -0400 Subject: [PATCH 2/9] feat: TransferRequest schema --- bank-app/backend/schemas.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bank-app/backend/schemas.py b/bank-app/backend/schemas.py index e46d88d..8f80dc1 100644 --- a/bank-app/backend/schemas.py +++ b/bank-app/backend/schemas.py @@ -58,6 +58,13 @@ class WithdrawalRequest(BaseModel): idempotency_key: str +class TransferRequest(BaseModel): + from_account: UUID + to_account: UUID + amount: Decimal + idempotency_key: str + + class TransactionResponse(BaseModel): id: UUID account_id: UUID From aeb34b628d1fba215ae74406eabfe80dc064b36b Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Mon, 31 Aug 2026 22:49:34 -0400 Subject: [PATCH 3/9] feat: transfer feat --- bank-app/backend/main.py | 64 ++++++---------------------------------- 1 file changed, 9 insertions(+), 55 deletions(-) diff --git a/bank-app/backend/main.py b/bank-app/backend/main.py index 628a803..29e86f1 100644 --- a/bank-app/backend/main.py +++ b/bank-app/backend/main.py @@ -20,12 +20,13 @@ TransactionResponse, DepositRequest, WithdrawalRequest, + TransferRequest, UserCreate, UserResponse, ) from tasks import send_transaction_notification, send_registration_notification -from services import deposit, withdrawal +from services import deposit, withdrawal, transfer from slowapi.errors import RateLimitExceeded from limiter import limiter @@ -322,68 +323,21 @@ def withdrawal_transaction( return withdrawal(db, account.id, transaction.amount, transaction.idempotency_key) -@app.patch("/accounts/{id}/transaction", response_model=TransactionResponse) +@app.patch("/accounts/{id}/transfer", response_model=list[TransactionResponse]) @limiter.limit("100/minute") -def transaction( +def transfer_transaction( request: Request, - id: UUID, - transaction: AccountTransaction, + transaction: TransferRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user), - idempotency_key: str = Header(...), ): - account = get_account(id, db, current_user) - - existing_transaction = ( - db.query(Transaction) - .filter(Transaction.idempotency_key == idempotency_key) - .first() - ) - - if ( - existing_transaction - ): # if that transaction was already complete return IMMEDIATELY - return existing_transaction - - balance_before = account.balance - - if account.frozen: - raise HTTPException(status_code=400, detail="Account is currently frozen") - - if transaction.transaction_type == "deposit": - account.balance += transaction.amount + from_account = get_account(transaction.from_account, db, current_user) + to_account = db.query(Account).filter(Account.id == transaction.to_account).first() - elif transaction.transaction_type == "withdrawal": - if transaction.amount > account.balance: - raise HTTPException(status_code=400, detail="Insufficient funds") - - account.balance -= transaction.amount - - else: - raise HTTPException(status_code=400, detail="Invalid transaction type") - - new_transaction = Transaction( - account_id=account.id, - transaction_type=transaction.transaction_type, - amount=transaction.amount, - balance_before=balance_before, - balance_after=account.balance, - status="completed", - idempotency_key=idempotency_key, - ) - - db.add(new_transaction) - db.commit() - db.refresh(new_transaction) - - send_transaction_notification.delay( - current_user.id, transaction.amount, transaction.transaction_type + return transfer( + db, from_account, to_account, transaction.amount, transaction.idempotency_key ) - delete_cache(f"accounts:user:{current_user.id}") - - return new_transaction - @app.get("/accounts/{id}/transaction", response_model=list[TransactionResponse]) def get_transactions( From 8db005f9dd9b06a8fd69e0181cbc072973f2fdb0 Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Tue, 1 Sep 2026 00:10:50 -0400 Subject: [PATCH 4/9] feat: remodel & Transfer table --- bank-app/backend/models.py | 41 ++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/bank-app/backend/models.py b/bank-app/backend/models.py index 7e298e9..6463ab4 100644 --- a/bank-app/backend/models.py +++ b/bank-app/backend/models.py @@ -86,6 +86,10 @@ class Transaction(Base): UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 ) + transfer_id: Mapped[uuid.UUID | None] = mapped_column( + UUID(as_uuid=True), ForeignKey("transfers.id"), nullable=True + ) + account_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("accounts.id"), nullable=False, index=True ) @@ -100,16 +104,45 @@ class Transaction(Base): status: Mapped[str] = mapped_column(String(12), nullable=False, default="pending") - idempotency_key: Mapped[str] = mapped_column( - String(255), unique=True, nullable=False, index=True - ) - created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), nullable=False ) + idempotency_key: Mapped[str | None] = mapped_column(String(255), unique=True, nullable=True, index=True) #temporary until we add Operations/Payment table + account: Mapped["Account"] = relationship(back_populates="transactions") + transfer: Mapped["Transfer | None"] = relationship(back_populates="transactions") __table_args__ = ( CheckConstraint("amount > 0", name="check_transaction_amount_positive"), ) + + +class Transfer(Base): + __tablename__ = "transfers" + + id: Mapped[uuid.UUID] = mapped_column( + UUID(as_uuid=True), primary_key=True, default=uuid.uuid4 + ) + + idempotency_key: Mapped[str] = mapped_column( + String(255), unique=True, nullable=False, index=True + ) + + from_account_id: Mapped[uuid.UUID] = mapped_column( + UUID(as_uuid=True), ForeignKey("accounts.id"), nullable=False + ) + + to_account_id: Mapped[uuid.UUID] = mapped_column( + UUID(as_uuid=True), ForeignKey("accounts.id"), nullable=False + ) + + amount: Mapped[Decimal] = mapped_column(Numeric(12, 2), nullable=False) + + status: Mapped[str] = mapped_column(String(12), nullable=False, default="pending") + + from_account: Mapped["Account"] = relationship(foreign_keys=[from_account_id]) + + to_account: Mapped["Account"] = relationship(foreign_keys=[to_account_id]) + + transactions: Mapped[list["Transaction"]] = relationship(back_populates="transfer") From a41e90d2559d647690167fbb817651f06728805c Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Tue, 1 Sep 2026 00:11:13 -0400 Subject: [PATCH 5/9] feat: services updated with Transfer table --- bank-app/backend/services.py | 45 +++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/bank-app/backend/services.py b/bank-app/backend/services.py index b9f2884..deb567f 100644 --- a/bank-app/backend/services.py +++ b/bank-app/backend/services.py @@ -2,7 +2,7 @@ from uuid import UUID from sqlalchemy.orm import Session -from models import Account, Transaction +from models import Account, Transaction, Transfer def deposit(db: Session, account_id: UUID, amount: Decimal, idempotency_key: str): @@ -87,55 +87,72 @@ def transfer( amount: Decimal, idempotency_key: str, ): + existing_transfer = ( + db.query(Transfer).filter(Transfer.idempotency_key == idempotency_key).first() + ) + + if existing_transfer: + return existing_transfer + f_acc = db.query(Account).filter(Account.id == from_account).first() t_acc = db.query(Account).filter(Account.id == to_account).first() + if not f_acc or not t_acc: + raise ValueError("Account not found") + if from_account == to_account: raise ValueError("Cannot fund same account") - existing_transaction = ( - db.query(Transaction) - .filter(Transaction.idempotency_key == idempotency_key) - .all() - ) - - if existing_transaction: - return existing_transaction + if f_acc.balance < amount: + raise ValueError("Insufficient funds") f_acc_balance_before = f_acc.balance t_acc_balance_before = t_acc.balance - if f_acc_balance_before < amount: - raise ValueError("Insufficient funds") - f_acc_balance_after = f_acc_balance_before - amount t_acc_balance_after = t_acc_balance_before + amount f_acc.balance = f_acc_balance_after t_acc.balance = t_acc_balance_after + transfer_record = Transfer( + idempotency_key=idempotency_key, + from_account_id=f_acc.id, + to_account_id=t_acc.id, + amount=amount, + status="completed", + ) + + db.add(transfer_record) + db.flush() # generates the uuid + transaction_sent = Transaction( account_id=f_acc.id, + transfer=transfer_record, transaction_type="transfer", amount=amount, balance_before=f_acc_balance_before, balance_after=f_acc_balance_after, status="completed", - idempotency_key=idempotency_key, ) transaction_received = Transaction( account_id=t_acc.id, + transfer=transfer_record, transaction_type="transfer", amount=amount, balance_before=t_acc_balance_before, balance_after=t_acc_balance_after, status="completed", - idempotency_key=idempotency_key, ) db.add(transaction_sent) db.add(transaction_received) + db.commit() + db.refresh(transfer_record) + db.refresh(transaction_sent) + db.refresh(transaction_received) + return [transaction_sent, transaction_received] From 1717126f001a5ffa751bd39aecdaaa6ef084816c Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Tue, 1 Sep 2026 00:11:47 -0400 Subject: [PATCH 6/9] tests: transfer service test passed --- .../backend/test/test_services_transfer.py | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 bank-app/backend/test/test_services_transfer.py diff --git a/bank-app/backend/test/test_services_transfer.py b/bank-app/backend/test/test_services_transfer.py new file mode 100644 index 0000000..98d70d6 --- /dev/null +++ b/bank-app/backend/test/test_services_transfer.py @@ -0,0 +1,65 @@ +from decimal import Decimal +from uuid import uuid4 +from models import Account, Transfer +from datetime import datetime +from services import transfer +import pytest + + +def test_services_transfer(db, create_account, create_user): + from_account = create_account + + to_account = Account( + id=uuid4(), + owner_name="test_user_2", + account_type="chequing", + balance=Decimal("100.00"), + created_at=datetime.utcnow(), + frozen=False, + owner_id=create_user.id, + ) + + db.add(to_account) + db.commit() + db.refresh(to_account) + + e_transfer = transfer( + db=db, + from_account=from_account.id, + to_account=to_account.id, + amount=Decimal("100.00"), + idempotency_key="test_transfer_001", + ) + + assert len(e_transfer) == 2 + + sent_transaction = e_transfer[0] + received_transaction = e_transfer[1] + + assert sent_transaction.transaction_type == "transfer" + assert sent_transaction.amount == Decimal("100.00") + assert sent_transaction.balance_before == Decimal("100.00") + assert sent_transaction.balance_after == Decimal("0.00") + assert sent_transaction.status == "completed" + + assert received_transaction.transaction_type == "transfer" + assert received_transaction.amount == Decimal("100.00") + assert received_transaction.balance_before == Decimal("100.00") + assert received_transaction.balance_after == Decimal("200.00") + assert received_transaction.status == "completed" + + assert sent_transaction.transfer_id == received_transaction.transfer_id + + transfer_record = ( + db.query(Transfer).filter(Transfer.id == sent_transaction.transfer_id).first() + ) + + assert transfer_record is not None + assert transfer_record.idempotency_key == "test_transfer_001" + assert transfer_record.from_account_id == from_account.id + assert transfer_record.to_account_id == to_account.id + assert transfer_record.amount == Decimal("100.00") + assert transfer_record.status == "completed" + + assert to_account.balance == Decimal("200.00") + assert from_account.balance == Decimal("0.00") From babba5647b5e4013ba91c72f2d1d357b50a6ae1a Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Tue, 1 Sep 2026 00:12:08 -0400 Subject: [PATCH 7/9] removed test_transaction --- bank-app/backend/test/test_transactions.py | 96 ---------------------- 1 file changed, 96 deletions(-) delete mode 100644 bank-app/backend/test/test_transactions.py diff --git a/bank-app/backend/test/test_transactions.py b/bank-app/backend/test/test_transactions.py deleted file mode 100644 index a5b25a9..0000000 --- a/bank-app/backend/test/test_transactions.py +++ /dev/null @@ -1,96 +0,0 @@ -import pytest - - -@pytest.mark.asyncio -async def test_get_transactions(client, authenticated_user): - headers = authenticated_user["headers"] - - created_response = await client.post( - "/accounts", - json={ - "owner_name": "test_user", - "balance": 1000.00, - "account_type": "chequing", - }, - headers=headers, - ) - - assert created_response.status_code == 200 - - account_id = created_response.json()["id"] - - transaction1_headers = { - **headers, - "Idempotency-Key": "test-deposit-001", - } - - transaction1 = await client.patch( - f"/accounts/{account_id}/transaction", - json={"amount": 1000.00, "transaction_type": "deposit"}, - headers=transaction1_headers, - ) - - assert transaction1.status_code == 200 - - transaction2_headers = { - **headers, - "Idempotency-Key": "test-deposit-002", - } - - transaction2 = await client.patch( - f"/accounts/{account_id}/transaction", - json={"amount": 100.00, "transaction_type": "withdrawal"}, - headers=transaction2_headers, - ) - - assert transaction2.status_code == 200 - - response = await client.get(f"/accounts/{account_id}/transaction", headers=headers) - - transactions = response.json() - - assert len(transactions) == 2 - assert transactions[0]["amount"] == "1000.00" - assert transactions[0]["transaction_type"] == "deposit" - assert transactions[0]["account_id"] == account_id - assert transactions[0]["balance_before"] == "1000.00" - assert transactions[0]["balance_after"] == "2000.00" - - assert transactions[1]["amount"] == "100.00" - assert transactions[1]["transaction_type"] == "withdrawal" - assert transactions[1]["account_id"] == account_id - assert transactions[1]["balance_before"] == "2000.00" - assert transactions[1]["balance_after"] == "1900.00" - - -@pytest.mark.asyncio -async def test_transactions_with_frozen_account(client, authenticated_user): - headers = authenticated_user["headers"] - - created_response = await client.post( - "/accounts", - json={"owner_name": "test_user", "balance": 1000.0, "account_type": "checking"}, - headers=headers, - ) - - assert created_response.status_code == 200 - - account_id = created_response.json()["id"] - - frozen = await client.patch( - f"/accounts/{account_id}/set_freeze", json={"freeze": True}, headers=headers - ) - - assert frozen.status_code == 200 - assert frozen.json()["frozen"] is True - - transaction_header = {**headers, "Idempotency-Key": "test-deposit-001"} - - transaction = await client.patch( - f"/accounts/{account_id}/transaction", - json={"amount": 1000.0, "transaction_type": "deposit"}, - headers=transaction_header, - ) - - assert transaction.status_code == 400 - assert transaction.json()["detail"] == "Account is currently frozen" From 5e1c4ff3b629f8cfc58a21dc3e32f4e7943b6638 Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Tue, 1 Sep 2026 00:12:25 -0400 Subject: [PATCH 8/9] alembic: new versions --- .../4e8e514ff17a_add_transfer_table.py | 78 +++++++++++++++++++ ...d8c18bf5b_temporary_idempotency_key_in_.py | 34 ++++++++ 2 files changed, 112 insertions(+) create mode 100644 bank-app/backend/alembic/versions/4e8e514ff17a_add_transfer_table.py create mode 100644 bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py diff --git a/bank-app/backend/alembic/versions/4e8e514ff17a_add_transfer_table.py b/bank-app/backend/alembic/versions/4e8e514ff17a_add_transfer_table.py new file mode 100644 index 0000000..8d6c6b2 --- /dev/null +++ b/bank-app/backend/alembic/versions/4e8e514ff17a_add_transfer_table.py @@ -0,0 +1,78 @@ +"""add transfer table + +Revision ID: 4e8e514ff17a +Revises: e9713222ea96 +Create Date: 2026-08-31 23:37:05.883395 + +""" + +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = "4e8e514ff17a" +down_revision: Union[str, Sequence[str], None] = "e9713222ea96" +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.create_table( + "transfers", + sa.Column("id", sa.UUID(), nullable=False), + sa.Column("idempotency_key", sa.String(length=255), nullable=False), + sa.Column("from_account_id", sa.UUID(), nullable=False), + sa.Column("to_account_id", sa.UUID(), nullable=False), + sa.Column("amount", sa.Numeric(precision=12, scale=2), nullable=False), + sa.Column("status", sa.String(length=12), nullable=False), + sa.ForeignKeyConstraint( + ["from_account_id"], + ["accounts.id"], + ), + sa.ForeignKeyConstraint( + ["to_account_id"], + ["accounts.id"], + ), + sa.PrimaryKeyConstraint("id"), + ) + op.create_index( + op.f("ix_transfers_idempotency_key"), + "transfers", + ["idempotency_key"], + unique=True, + ) + op.add_column("transactions", sa.Column("transfer_id", sa.UUID(), nullable=True)) + op.drop_index(op.f("ix_transactions_idempotency_key"), table_name="transactions") + op.create_foreign_key(None, "transactions", "transfers", ["transfer_id"], ["id"]) + op.drop_column("transactions", "idempotency_key") + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "transactions", + sa.Column( + "idempotency_key", + sa.VARCHAR(length=255), + autoincrement=False, + nullable=False, + ), + ) + op.drop_constraint(None, "transactions", type_="foreignkey") + op.create_index( + op.f("ix_transactions_idempotency_key"), + "transactions", + ["idempotency_key"], + unique=True, + ) + op.drop_column("transactions", "transfer_id") + op.drop_index(op.f("ix_transfers_idempotency_key"), table_name="transfers") + op.drop_table("transfers") + # ### end Alembic commands ### diff --git a/bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py b/bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py new file mode 100644 index 0000000..d9fe3ce --- /dev/null +++ b/bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py @@ -0,0 +1,34 @@ +"""temporary idempotency_key in transactions table + +Revision ID: c00d8c18bf5b +Revises: 4e8e514ff17a +Create Date: 2026-09-01 00:06:21.314328 + +""" +from typing import Sequence, Union + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision: str = 'c00d8c18bf5b' +down_revision: Union[str, Sequence[str], None] = '4e8e514ff17a' +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.add_column('transactions', sa.Column('idempotency_key', sa.String(length=255), nullable=True)) + op.create_index(op.f('ix_transactions_idempotency_key'), 'transactions', ['idempotency_key'], unique=True) + # ### end Alembic commands ### + + +def downgrade() -> None: + """Downgrade schema.""" + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_transactions_idempotency_key'), table_name='transactions') + op.drop_column('transactions', 'idempotency_key') + # ### end Alembic commands ### From e5986546039f166fd1cdc7f41fc571213c97d5f7 Mon Sep 17 00:00:00 2001 From: Jonathan Zhao Date: Tue, 1 Sep 2026 00:17:38 -0400 Subject: [PATCH 9/9] chore: fixed flake8 formatting --- ...d8c18bf5b_temporary_idempotency_key_in_.py | 21 +++++++++++++------ bank-app/backend/models.py | 4 +++- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py b/bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py index d9fe3ce..6d15624 100644 --- a/bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py +++ b/bank-app/backend/alembic/versions/c00d8c18bf5b_temporary_idempotency_key_in_.py @@ -5,6 +5,7 @@ Create Date: 2026-09-01 00:06:21.314328 """ + from typing import Sequence, Union from alembic import op @@ -12,8 +13,8 @@ # revision identifiers, used by Alembic. -revision: str = 'c00d8c18bf5b' -down_revision: Union[str, Sequence[str], None] = '4e8e514ff17a' +revision: str = "c00d8c18bf5b" +down_revision: Union[str, Sequence[str], None] = "4e8e514ff17a" branch_labels: Union[str, Sequence[str], None] = None depends_on: Union[str, Sequence[str], None] = None @@ -21,14 +22,22 @@ def upgrade() -> None: """Upgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### - op.add_column('transactions', sa.Column('idempotency_key', sa.String(length=255), nullable=True)) - op.create_index(op.f('ix_transactions_idempotency_key'), 'transactions', ['idempotency_key'], unique=True) + op.add_column( + "transactions", + sa.Column("idempotency_key", sa.String(length=255), nullable=True), + ) + op.create_index( + op.f("ix_transactions_idempotency_key"), + "transactions", + ["idempotency_key"], + unique=True, + ) # ### end Alembic commands ### def downgrade() -> None: """Downgrade schema.""" # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_transactions_idempotency_key'), table_name='transactions') - op.drop_column('transactions', 'idempotency_key') + op.drop_index(op.f("ix_transactions_idempotency_key"), table_name="transactions") + op.drop_column("transactions", "idempotency_key") # ### end Alembic commands ### diff --git a/bank-app/backend/models.py b/bank-app/backend/models.py index 6463ab4..ae5be16 100644 --- a/bank-app/backend/models.py +++ b/bank-app/backend/models.py @@ -108,7 +108,9 @@ class Transaction(Base): DateTime(timezone=True), server_default=func.now(), nullable=False ) - idempotency_key: Mapped[str | None] = mapped_column(String(255), unique=True, nullable=True, index=True) #temporary until we add Operations/Payment table + idempotency_key: Mapped[str | None] = mapped_column( + String(255), unique=True, nullable=True, index=True + ) # temporary until we add Operations/Payment table account: Mapped["Account"] = relationship(back_populates="transactions") transfer: Mapped["Transfer | None"] = relationship(back_populates="transactions")