mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-07-17 11:08:47 +02:00
Migrate all 29 money columns from float to NUMERIC/Decimal (BE-02)
Models use Money = Annotated[Decimal, PlainSerializer(float)] so storage is exact NUMERIC(15,2) (rates 15,6) while JSON keeps emitting plain numbers — the frontend contract is unchanged, pinned by test_models_serialization.py. Service layers coerce to float at their boundaries (projection math, rate multipliers, agent tool output, the savings constants become Decimal) so no naive Decimal/float mixing can raise. Migration 7f567c8bafdb applied to dev: per-row values and the table sum byte-identical before/after; endpoints verified live on the new schema. 59/59 tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,263 @@
|
||||
"""money columns to numeric
|
||||
|
||||
Revision ID: 7f567c8bafdb
|
||||
Revises: c3da001a0eb3
|
||||
Create Date: 2026-06-10 13:37:26.281634
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '7f567c8bafdb'
|
||||
down_revision: Union[str, Sequence[str], None] = 'c3da001a0eb3'
|
||||
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('account', 'balance',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('account', 'next_payment',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=True)
|
||||
op.alter_column('balanceoverride', 'override_balance',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('exchangerate', 'buy_rate',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=6),
|
||||
existing_nullable=False)
|
||||
op.alter_column('exchangerate', 'sell_rate',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=6),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'subtotal',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'interests',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'iva',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'total',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'saldo_anterior',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'aportes',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'rendimientos',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'retiros',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'traslados',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'comision',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'correccion',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'bonificacion',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'saldo_final',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('recurringitem', 'amount',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('savingsaccrual', 'memp_amount',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('savingsaccrual', 'mpat_amount',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('transaction', 'amount',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'reading_previous',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'reading_current',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'consumption_m3',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'agua_potable',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'serv_ambientales',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'alcant_sanitario',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'iva',
|
||||
existing_type=sa.DOUBLE_PRECISION(precision=53),
|
||||
type_=sa.Numeric(precision=15, scale=2),
|
||||
existing_nullable=False)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.alter_column('watermeterreading', 'iva',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'alcant_sanitario',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'serv_ambientales',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'agua_potable',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'consumption_m3',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'reading_current',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('watermeterreading', 'reading_previous',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('transaction', 'amount',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('savingsaccrual', 'mpat_amount',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('savingsaccrual', 'memp_amount',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('recurringitem', 'amount',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'saldo_final',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'bonificacion',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'correccion',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'comision',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'traslados',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'retiros',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'rendimientos',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'aportes',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('pensionsnapshot', 'saldo_anterior',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'total',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'iva',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'interests',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('municipalreceipt', 'subtotal',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('exchangerate', 'sell_rate',
|
||||
existing_type=sa.Numeric(precision=15, scale=6),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('exchangerate', 'buy_rate',
|
||||
existing_type=sa.Numeric(precision=15, scale=6),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('balanceoverride', 'override_balance',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
op.alter_column('account', 'next_payment',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=True)
|
||||
op.alter_column('account', 'balance',
|
||||
existing_type=sa.Numeric(precision=15, scale=2),
|
||||
type_=sa.DOUBLE_PRECISION(precision=53),
|
||||
existing_nullable=False)
|
||||
# ### end Alembic commands ###
|
||||
Reference in New Issue
Block a user