Files
sure/lib/tasks/cleanup_stuck_pending_lunchflow.rake
AdamWHY2K 356d9ebf3a fix: add logic to skip future pending transactions and add cleanup ta… (#1011)
* fix: add logic to skip future pending transactions and add cleanup task for stuck entries

* Update lib/tasks/cleanup_stuck_pending_lunchflow.rake

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: AdamWHY2K <adamgm.email@gmail.com>

* Update app/models/lunchflow_entry/processor.rb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: AdamWHY2K <adamgm.email@gmail.com>

* fix(coderabbit): assertions use entryable instead of transaction for pending state checks

* chore(codex): add comments to clarify handling of pending transactions, exclude self in cleanup task

* fix(coderabbit): memoize external_id

---------

Signed-off-by: AdamWHY2K <adamgm.email@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-02-19 18:58:01 +01:00

62 lines
2.4 KiB
Ruby

namespace :lunchflow do
desc "Cleanup stuck pending Lunchflow transactions that have posted duplicates"
task cleanup_stuck_pending: :environment do
puts "Finding stuck pending Lunchflow transactions..."
stuck_pending = Transaction
.pending
.where("transactions.extra -> 'lunchflow' ->> 'pending' = 'true'")
.includes(:entry)
.where(entries: { source: "lunchflow" })
puts "Found #{stuck_pending.count} pending Lunchflow transactions"
puts ""
deleted_count = 0
kept_count = 0
stuck_pending.each do |transaction|
pending_entry = transaction.entry
# Search for a posted version with same merchant name, amount, and date window
# Note: Lunchflow never provides real IDs for pending transactions, so external_id pattern
# matching is sufficient. We still exclude self (pending_entry.id) for extra safety.
posted_match = Entry
.where(source: "lunchflow")
.where(account_id: pending_entry.account_id)
.where(name: pending_entry.name)
.where(amount: pending_entry.amount)
.where(currency: pending_entry.currency)
.where("date BETWEEN ? AND ?", pending_entry.date, pending_entry.date + 8)
.where("external_id NOT LIKE 'lunchflow_pending_%'")
.where("external_id IS NOT NULL")
.where.not(id: pending_entry.id)
.order(date: :asc) # Prefer closest date match
.first
if posted_match
puts "DELETING duplicate pending entry:"
puts " Pending: #{pending_entry.date} | #{pending_entry.name} | #{pending_entry.amount} | #{pending_entry.external_id}"
puts " Posted: #{posted_match.date} | #{posted_match.name} | #{posted_match.amount} | #{posted_match.external_id}"
# Delete the pending entry (this will also delete the transaction via cascade)
pending_entry.destroy!
deleted_count += 1
puts " ✓ Deleted"
puts ""
else
puts "KEEPING (no posted duplicate found):"
puts " #{pending_entry.date} | #{pending_entry.name} | #{pending_entry.amount} | #{pending_entry.external_id}"
puts " This may be legitimately still pending, or posted with different details"
puts ""
kept_count += 1
end
end
puts "="*80
puts "Cleanup complete!"
puts " Deleted: #{deleted_count} duplicate pending entries"
puts " Kept: #{kept_count} entries (no posted version found)"
end
end