Skip to content

Commit d79d86d

Browse files
authored
PDF ai import (#1006)
Add support to review transactions for AI pdf import
1 parent 16aca78 commit d79d86d

6 files changed

Lines changed: 26 additions & 18 deletions

File tree

app/controllers/import/cleans_controller.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ class Import::CleansController < ApplicationController
44
before_action :set_import
55

66
def show
7-
redirect_to import_configuration_path(@import), alert: "Please configure your import before proceeding." unless @import.configured?
7+
unless @import.configured?
8+
redirect_path = @import.is_a?(PdfImport) ? import_path(@import) : import_configuration_path(@import)
9+
return redirect_to redirect_path, alert: "Please configure your import before proceeding."
10+
end
811

912
rows = @import.rows.ordered
1013

app/jobs/process_pdf_job.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ def perform(pdf_import)
55
return unless pdf_import.is_a?(PdfImport)
66
return unless pdf_import.pdf_uploaded?
77
return if pdf_import.status == "complete"
8-
return if pdf_import.ai_processed? && (!pdf_import.bank_statement? || pdf_import.rows_count > 0)
8+
return if pdf_import.ai_processed? && (!pdf_import.statement_with_transactions? || pdf_import.rows_count > 0)
99

1010
pdf_import.update!(status: :importing)
1111

@@ -14,9 +14,9 @@ def perform(pdf_import)
1414
document_type = resolve_document_type(pdf_import, process_result)
1515
upload_to_vector_store(pdf_import, document_type: document_type)
1616

17-
# For bank statements, extract transactions and generate import rows
18-
if bank_statement_document?(document_type)
19-
Rails.logger.info("ProcessPdfJob: Extracting transactions for bank statement import #{pdf_import.id}")
17+
# For statements with transactions (bank/credit card), extract and generate import rows
18+
if statement_with_transactions?(document_type)
19+
Rails.logger.info("ProcessPdfJob: Extracting transactions for #{document_type} import #{pdf_import.id}")
2020
pdf_import.extract_transactions
2121
Rails.logger.info("ProcessPdfJob: Extracted #{pdf_import.extracted_transactions.size} transactions")
2222

@@ -32,9 +32,9 @@ def perform(pdf_import)
3232
pdf_import.send_next_steps_email(user)
3333
end
3434

35-
# Bank statements with rows go to pending for user review/publish
36-
# Non-bank statements are marked complete (no further action needed)
37-
final_status = bank_statement_document?(document_type) && pdf_import.rows_count > 0 ? :pending : :complete
35+
# Statements with extracted rows go to pending for user review/publish
36+
# Other document types are marked complete (no further action needed)
37+
final_status = statement_with_transactions?(document_type) && pdf_import.rows_count > 0 ? :pending : :complete
3838
pdf_import.update!(status: final_status)
3939
rescue StandardError => e
4040
sanitized_error = sanitize_error_message(e)
@@ -82,7 +82,7 @@ def resolve_document_type(pdf_import, process_result)
8282
pdf_import.reload.document_type
8383
end
8484

85-
def bank_statement_document?(document_type)
86-
document_type == "bank_statement"
85+
def statement_with_transactions?(document_type)
86+
document_type.in?(%w[bank_statement credit_card_statement])
8787
end
8888
end

app/models/pdf_import.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def process_with_ai
6868
end
6969

7070
def extract_transactions
71-
return unless bank_statement?
71+
return unless statement_with_transactions?
7272

7373
provider = Provider::Registry.get_provider(:openai)
7474
raise "AI provider not configured" unless provider
@@ -91,6 +91,10 @@ def bank_statement?
9191
document_type == "bank_statement"
9292
end
9393

94+
def statement_with_transactions?
95+
document_type.in?(%w[bank_statement credit_card_statement])
96+
end
97+
9498
def has_extracted_transactions?
9599
extracted_data.present? && extracted_data["transactions"].present?
96100
end
@@ -147,7 +151,7 @@ def cleaned?
147151
end
148152

149153
def publishable?
150-
account.present? && bank_statement? && cleaned? && mappings.all?(&:valid?)
154+
account.present? && statement_with_transactions? && cleaned? && mappings.all?(&:valid?)
151155
end
152156

153157
def column_keys

app/views/import/cleans/show.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<%= render "imports/nav", import: @import %>
33
<% end %>
44

5-
<%= content_for :previous_path, import_configuration_path(@import) %>
5+
<%= content_for :previous_path, @import.is_a?(PdfImport) ? import_path(@import) : import_configuration_path(@import) %>
66

77
<div class="space-y-4 mx-auto max-w-5xl">
88
<div class="text-center space-y-2 max-w-[400px] mx-auto mb-4">
@@ -20,7 +20,7 @@
2020
<%= render DS::Link.new(
2121
text: "Next step",
2222
variant: "primary",
23-
href: import_confirm_path(@import),
23+
href: @import.is_a?(PdfImport) ? import_path(@import) : import_confirm_path(@import),
2424
frame: :_top,
2525
class: "w-full md:w-auto"
2626
) %>

app/views/imports/_nav.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
[
77
{ name: t("imports.steps.upload", default: "Upload"), path: nil, is_complete: import.pdf_uploaded?, step_number: 1 },
88
{ name: t("imports.steps.configure", default: "Configure"), path: nil, is_complete: import.configured?, step_number: 2 },
9-
{ name: t("imports.steps.clean", default: "Clean"), path: nil, is_complete: import.cleaned?, step_number: 3 },
9+
{ name: t("imports.steps.clean", default: "Clean"), path: import.configured? ? import_clean_path(import) : nil, is_complete: import.cleaned?, step_number: 3 },
1010
{ name: t("imports.steps.confirm", default: "Confirm"), path: import_path(import), is_complete: import.complete?, step_number: 4 }
1111
]
1212
else

app/views/imports/_pdf_import.html.erb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
<div class="h-full flex flex-col justify-center items-center">
44
<div class="space-y-6 max-w-lg w-full">
55
<% if import.pending? && import.rows_count > 0 %>
6-
<%# Bank statement with rows ready for review %>
6+
<%# Statement with rows ready for review %>
77
<div class="mx-auto bg-success/10 h-8 w-8 rounded-full flex items-center justify-center">
88
<%= icon "check", class: "text-success" %>
99
</div>
1010

1111
<div class="text-center space-y-2">
1212
<h1 class="font-medium text-primary text-center text-3xl"><%= t("imports.pdf_import.ready_for_review_title", default: "Ready for Review") %></h1>
13-
<p class="text-sm text-secondary"><%= t("imports.pdf_import.ready_for_review_description", default: "We extracted %{count} transactions from your bank statement. Review and publish them to add to your account.", count: import.rows_count) %></p>
13+
<p class="text-sm text-secondary"><%= t("imports.pdf_import.ready_for_review_description", default: "We extracted %{count} transactions from your statement. Review and publish them to add to your account.", count: import.rows_count) %></p>
1414
</div>
1515

1616
<div class="bg-container border border-primary rounded-xl p-4 space-y-4">
@@ -53,8 +53,9 @@
5353
<div class="space-y-2 flex flex-col">
5454
<% if import.publishable? %>
5555
<%= button_to t("imports.pdf_import.publish_transactions", default: "Publish %{count} Transactions", count: import.rows_count), publish_import_path(import), method: :post, class: "w-full font-medium text-sm px-3 py-2 rounded-lg text-inverse bg-inverse hover:bg-inverse-hover" %>
56+
<%= render DS::Link.new(text: t("imports.pdf_import.review_transactions", default: "Review Transactions"), href: import_clean_path(import), variant: "secondary", full_width: true) %>
5657
<% elsif import.account.present? %>
57-
<%= render DS::Link.new(text: t("imports.pdf_import.review_transactions", default: "Review Transactions"), href: import_confirm_path(import), variant: "primary", full_width: true) %>
58+
<%= render DS::Link.new(text: t("imports.pdf_import.review_transactions", default: "Review Transactions"), href: import_clean_path(import), variant: "primary", full_width: true) %>
5859
<% else %>
5960
<p class="text-center text-sm text-secondary"><%= t("imports.pdf_import.select_account_to_continue", default: "Please select an account above to continue.") %></p>
6061
<% end %>

0 commit comments

Comments
 (0)