Worth the migration, and it is a small one. Two booleans encode four states of which one is nonsense, and the database has no way to refuse it.
One column with a constraint instead:
alter table expenses add column status text not null default 'submitted'
check (status in ('submitted','approved','paid','rejected'));Backfill from the booleans, then drop them. Now 'paid but not approved' is unrepresentable rather than merely discouraged.
For the second half of your question, add an expense_events table with expense_id, from_status, to_status, actor_id, created_at and write a row on every transition. Approvals are exactly the kind of thing someone asks about a year later, and a status column alone cannot answer it.