mirror of
https://github.com/we-promise/sure.git
synced 2026-04-17 19:14:11 +00:00
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>
This commit is contained in:
@@ -18,6 +18,16 @@ class LunchflowEntry::Processor
|
||||
return nil
|
||||
end
|
||||
|
||||
# If this is a pending transaction with a temporary ID, check if a posted version already exists
|
||||
# This prevents duplicate entries when posted transactions arrive before pending ones
|
||||
if is_pending? && external_id.start_with?("lunchflow_pending_")
|
||||
existing_posted = find_existing_posted_version
|
||||
if existing_posted
|
||||
Rails.logger.info "LunchflowEntry::Processor - Skipping pending transaction (posted version already exists): pending=#{external_id}, posted=#{existing_posted.external_id}"
|
||||
return existing_posted
|
||||
end
|
||||
end
|
||||
|
||||
# Wrap import in error handling to catch validation and save errors
|
||||
begin
|
||||
import_adapter.import_transaction(
|
||||
@@ -63,6 +73,10 @@ class LunchflowEntry::Processor
|
||||
end
|
||||
|
||||
def external_id
|
||||
@external_id ||= calculate_external_id
|
||||
end
|
||||
|
||||
def calculate_external_id
|
||||
id = data[:id].presence
|
||||
|
||||
# For pending transactions, Lunchflow may return blank/nil IDs
|
||||
@@ -101,10 +115,10 @@ class LunchflowEntry::Processor
|
||||
Rails.logger.debug "Lunchflow: Generated temporary ID #{final_id} for pending transaction: #{data[:merchant]} #{data[:amount]} #{data[:currency]}"
|
||||
end
|
||||
|
||||
return final_id
|
||||
final_id
|
||||
else
|
||||
"lunchflow_#{id}"
|
||||
end
|
||||
|
||||
"lunchflow_#{id}"
|
||||
end
|
||||
|
||||
def entry_exists_with_external_id?(external_id)
|
||||
@@ -203,4 +217,35 @@ class LunchflowEntry::Processor
|
||||
|
||||
metadata
|
||||
end
|
||||
|
||||
# Check if this transaction is marked as pending
|
||||
def is_pending?
|
||||
ActiveModel::Type::Boolean.new.cast(data[:isPending])
|
||||
end
|
||||
|
||||
# Find an existing posted version of this pending transaction
|
||||
# Matches by: exact amount, currency, merchant name (if present), and date window
|
||||
# Uses same 8-day window as Account::ProviderImportAdapter reconciliation logic
|
||||
# Note: Lunchflow never provides real IDs for pending transactions (they're always blank),
|
||||
# so filtering by external_id NOT LIKE 'lunchflow_pending_%' is sufficient to exclude pending entries
|
||||
def find_existing_posted_version
|
||||
return nil unless account.present?
|
||||
|
||||
query = account.entries
|
||||
.where(source: "lunchflow")
|
||||
.where(amount: amount)
|
||||
.where(currency: currency)
|
||||
.where("date BETWEEN ? AND ?", date, date + 8)
|
||||
.where("external_id NOT LIKE 'lunchflow_pending_%'")
|
||||
.where("external_id IS NOT NULL")
|
||||
.order(date: :asc) # Closest date first (prefer same-day posted, then next day, etc.)
|
||||
|
||||
# Add merchant name matching for better precision
|
||||
# Only if merchant name is present in the transaction data
|
||||
if data[:merchant].present?
|
||||
query = query.where(name: name)
|
||||
end
|
||||
|
||||
query.first
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user