True when any of the listings has a paid line for this attendee — a gross
sale leg in the row's ledger_event_group (a sale leg's amount is always > 0,
so its existence is exactly a non-zero projected price_paid; a refund keeps the
gross leg, so a refunded line still reads as paid). One query over all the IDs,
read from the live ledger rather than the edit form's submitted key (a
stale/missing key can leave it null), so a recorded payment is never dropped
onto a fresh quantity-0 row. Callers pass a non-empty list.
Usage
import { hasPaidLine } from "doc.ts";