"""Add external_meta_deposits for ActualBudget payroll reconciliation. Daily sync pulls Meta payroll deposits from ActualBudget (the jhonderson/actual-http-api sidecar) so the dashboard can overlay bank- deposit reality with `payslip.net_pay`. If the delta exceeds a tolerance threshold, the payslip parser likely got the net_pay wrong — useful for catching parser regressions without manual audit. Idempotent on `actualbudget_tx_id` — rerunning the sync only inserts new transactions. Deletions in ActualBudget are NOT propagated here (append- only — the audit trail matters more than a live mirror). """ import sqlalchemy as sa from alembic import op revision = "0007" down_revision = "0006" branch_labels = None depends_on = None SCHEMA = "payslip_ingest" def upgrade() -> None: op.create_table( "external_meta_deposits", sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True), sa.Column("actualbudget_tx_id", sa.String(), nullable=False, unique=True), sa.Column("deposit_date", sa.Date(), nullable=False), sa.Column("amount", sa.Numeric(12, 2), nullable=False), sa.Column("payee", sa.String(), nullable=True), sa.Column("memo", sa.String(), nullable=True), sa.Column("synced_at", sa.TIMESTAMP(timezone=True), server_default=sa.text("now()"), nullable=False), schema=SCHEMA, ) op.create_index( "ix_external_meta_deposits_deposit_date", "external_meta_deposits", ["deposit_date"], schema=SCHEMA, ) def downgrade() -> None: op.drop_index("ix_external_meta_deposits_deposit_date", table_name="external_meta_deposits", schema=SCHEMA) op.drop_table("external_meta_deposits", schema=SCHEMA)