1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-21 22:29:38 +02:00
Maybe/test/interfaces/import_interface_test.rb
Daniel Esteves 077694bbde
Some checks are pending
Publish Docker image / ci (push) Waiting to run
Publish Docker image / Build docker image (push) Blocked by required conditions
feat(import): add currency and number format support for CSV imports (#1819)
* feat(import): add currency and number format support for CSV imports

* feat(import): add currency and format for mint and trade

* fix(imports): remove currency field in favor of currency csv col

* fix(imports): remove validate column from import model

* test(import): add some tests for imports

* test(import): add some tests for generate_rows_from_csv

* fix: change method name for import model

* fix: change before validation

---------

Co-authored-by: danestves <danestves@users.noreply.github.com>
2025-02-10 15:31:28 -05:00

286 lines
8.1 KiB
Ruby

require "test_helper"
module ImportInterfaceTest
extend ActiveSupport::Testing::Declarative
test "import interface" do
assert_respond_to @subject, :publish
assert_respond_to @subject, :publish_later
assert_respond_to @subject, :generate_rows_from_csv
assert_respond_to @subject, :csv_rows
assert_respond_to @subject, :csv_headers
assert_respond_to @subject, :csv_sample
assert_respond_to @subject, :uploaded?
assert_respond_to @subject, :configured?
assert_respond_to @subject, :cleaned?
assert_respond_to @subject, :publishable?
assert_respond_to @subject, :importing?
assert_respond_to @subject, :complete?
assert_respond_to @subject, :failed?
end
test "publishes later" do
import = imports(:transaction)
import.stubs(:publishable?).returns(true)
assert_enqueued_with job: ImportJob, args: [ import ] do
import.publish_later
end
assert_equal "importing", import.reload.status
end
test "raises if not publishable" do
import = imports(:transaction)
import.stubs(:publishable?).returns(false)
assert_raises(RuntimeError, "Import is not publishable") do
import.publish_later
end
end
test "handles publish errors" do
import = imports(:transaction)
import.stubs(:publishable?).returns(true)
import.stubs(:import!).raises(StandardError, "Failed to publish")
assert_nil import.error
import.publish
assert_equal "Failed to publish", import.error
assert_equal "failed", import.status
end
test "parses US/UK number format correctly" do
import = imports(:transaction)
import.update!(
number_format: "1,234.56",
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
date_format: "%m/%d/%Y"
)
csv_data = "date,amount,name\n01/01/2024,\"1,234.56\",Test"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "1234.56", row.amount
end
test "parses European number format correctly" do
import = imports(:transaction)
import.update!(
number_format: "1.234,56",
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
date_format: "%m/%d/%Y"
)
csv_data = "date,amount,name\n01/01/2024,\"1.234,56\",Test"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "1234.56", row.amount
end
test "parses French/Scandinavian number format correctly" do
import = imports(:transaction)
import.update!(
number_format: "1 234,56",
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
date_format: "%m/%d/%Y"
)
# Quote the amount field to ensure proper CSV parsing
csv_data = "date,amount,name\n01/01/2024,\"1 234,56\",Test"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "1234.56", row.amount
end
test "parses zero-decimal currency format correctly" do
import = imports(:transaction)
import.update!(
number_format: "1,234",
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
date_format: "%m/%d/%Y"
)
csv_data = "date,amount,name\n01/01/2024,1234,Test"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "1234", row.amount
end
test "currency from CSV takes precedence over default" do
import = imports(:transaction)
import.update!(
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
currency_col_label: "currency",
number_format: "1,234.56",
date_format: "%m/%d/%Y"
)
import.family.update!(currency: "USD")
csv_data = "date,amount,name,currency\n01/01/2024,123.45,Test,EUR"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "EUR", row.currency
end
test "uses default currency when CSV currency column is empty" do
import = imports(:transaction)
import.update!(
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
currency_col_label: "currency",
number_format: "1,234.56",
date_format: "%m/%d/%Y"
)
import.family.update!(currency: "USD")
csv_data = "date,amount,name,currency\n01/01/2024,123.45,Test,"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "USD", row.currency
end
test "uses default currency when CSV has no currency column" do
import = imports(:transaction)
import.update!(
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
number_format: "1,234.56",
date_format: "%m/%d/%Y"
)
import.family.update!(currency: "USD")
csv_data = "date,amount,name\n01/01/2024,123.45,Test"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "USD", row.currency
end
test "generates rows with all optional fields" do
import = imports(:transaction)
import.update!(
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
account_col_label: "account",
category_col_label: "category",
tags_col_label: "tags",
notes_col_label: "notes",
currency_col_label: "currency",
number_format: "1,234.56",
date_format: "%m/%d/%Y"
)
csv_data = "date,amount,name,account,category,tags,notes,currency\n" \
"01/01/2024,1234.56,Salary,Bank Account,Income,\"monthly,salary\",Salary payment,EUR"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "01/01/2024", row.date
assert_equal "1234.56", row.amount
assert_equal "Salary", row.name
assert_equal "Bank Account", row.account
assert_equal "Income", row.category
assert_equal "monthly,salary", row.tags
assert_equal "Salary payment", row.notes
assert_equal "EUR", row.currency
end
test "generates rows with minimal required fields" do
import = imports(:transaction)
import.update!(
amount_col_label: "amount",
date_col_label: "date",
number_format: "1,234.56",
date_format: "%m/%d/%Y"
)
csv_data = "date,amount\n01/01/2024,1234.56"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "01/01/2024", row.date
assert_equal "1234.56", row.amount
assert_equal "Imported item", row.name # Default name
assert_equal import.family.currency, row.currency # Default currency
end
test "handles empty values in optional fields" do
import = imports(:transaction)
import.update!(
amount_col_label: "amount",
date_col_label: "date",
name_col_label: "name",
category_col_label: "category",
tags_col_label: "tags",
number_format: "1,234.56",
date_format: "%m/%d/%Y"
)
csv_data = "date,amount,name,category,tags\n01/01/2024,1234.56,,,"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "01/01/2024", row.date
assert_equal "1234.56", row.amount
assert_equal "Imported item", row.name # Falls back to default
assert_equal "", row.category
assert_equal "", row.tags
end
test "handles trade-specific fields" do
import = imports(:transaction)
import.update!(
amount_col_label: "amount",
date_col_label: "date",
qty_col_label: "quantity",
ticker_col_label: "symbol",
price_col_label: "price",
number_format: "1,234.56",
date_format: "%m/%d/%Y"
)
csv_data = "date,amount,quantity,symbol,price\n01/01/2024,1234.56,10,AAPL,123.456"
import.update!(raw_file_str: csv_data)
import.generate_rows_from_csv
row = import.rows.first
assert_equal "10", row.qty
assert_equal "AAPL", row.ticker
assert_equal "123.456", row.price
end
end