mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 20:14:08 +00:00
Mercury integration (#723)
* Initial mercury impl * FIX both mercury and generator class * Finish mercury integration and provider generator * Fix schema * Fix linter and tags * Update routes.rb * Avoid schema drift --------- Signed-off-by: soky srm <sokysrm@gmail.com> Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
This commit is contained in:
@@ -318,11 +318,11 @@ class Provider::FamilyGenerator < Rails::Generators::NamedBase
|
||||
# Add section before the last closing div (at end of file)
|
||||
section_content = <<~ERB
|
||||
|
||||
<%%= settings_section title: "#{class_name}", collapsible: true, open: false do %>
|
||||
<%= settings_section title: "#{class_name}", collapsible: true, open: false do %>
|
||||
<turbo-frame id="#{file_name}-providers-panel">
|
||||
<%%= render "settings/providers/#{file_name}_panel" %>
|
||||
<%= render "settings/providers/#{file_name}_panel" %>
|
||||
</turbo-frame>
|
||||
<%% end %>
|
||||
<% end %>
|
||||
ERB
|
||||
|
||||
# Insert before the final </div> at the end of file
|
||||
@@ -331,6 +331,99 @@ class Provider::FamilyGenerator < Rails::Generators::NamedBase
|
||||
end
|
||||
end
|
||||
|
||||
def update_accounts_controller
|
||||
controller_path = "app/controllers/accounts_controller.rb"
|
||||
return unless File.exist?(controller_path)
|
||||
|
||||
content = File.read(controller_path)
|
||||
items_var = "@#{file_name}_items"
|
||||
|
||||
# Check if already added
|
||||
if content.include?(items_var)
|
||||
say "Accounts controller already has #{items_var}", :skip
|
||||
return
|
||||
end
|
||||
|
||||
# Add to index action - find the last @*_items line and insert after it
|
||||
lines = content.lines
|
||||
last_items_index = nil
|
||||
lines.each_with_index do |line, index|
|
||||
if line =~ /@\w+_items = family\.\w+_items\.ordered/
|
||||
last_items_index = index
|
||||
end
|
||||
end
|
||||
|
||||
if last_items_index
|
||||
indentation = lines[last_items_index][/^\s*/]
|
||||
new_line = "#{indentation}#{items_var} = family.#{file_name}_items.ordered.includes(:syncs, :#{file_name}_accounts)\n"
|
||||
lines.insert(last_items_index + 1, new_line)
|
||||
File.write(controller_path, lines.join)
|
||||
say "Added #{items_var} to accounts controller index", :green
|
||||
else
|
||||
say "Could not find @*_items assignments in accounts controller", :yellow
|
||||
end
|
||||
|
||||
# Add sync stats map
|
||||
add_accounts_controller_sync_stats_map(controller_path)
|
||||
end
|
||||
|
||||
def update_accounts_index_view
|
||||
view_path = "app/views/accounts/index.html.erb"
|
||||
return unless File.exist?(view_path)
|
||||
|
||||
content = File.read(view_path)
|
||||
items_var = "@#{file_name}_items"
|
||||
|
||||
if content.include?(items_var)
|
||||
say "Accounts index view already has #{class_name} section", :skip
|
||||
return
|
||||
end
|
||||
|
||||
# Add to empty check - find the existing pattern and append our check
|
||||
content = content.gsub(
|
||||
/@coinstats_items\.empty\? %>/,
|
||||
"@coinstats_items.empty? && #{items_var}.empty? %>"
|
||||
)
|
||||
|
||||
# Add provider section before manual_accounts
|
||||
section = <<~ERB
|
||||
|
||||
<% if #{items_var}.any? %>
|
||||
<%= render #{items_var}.sort_by(&:created_at) %>
|
||||
<% end %>
|
||||
|
||||
ERB
|
||||
|
||||
content = content.gsub(
|
||||
/<% if @manual_accounts\.any\? %>/,
|
||||
"#{section.strip}\n\n <% if @manual_accounts.any? %>"
|
||||
)
|
||||
|
||||
File.write(view_path, content)
|
||||
say "Added #{class_name} section to accounts index view", :green
|
||||
end
|
||||
|
||||
def create_locale_file
|
||||
locale_dir = "config/locales/views/#{file_name}_items"
|
||||
locale_path = "#{locale_dir}/en.yml"
|
||||
|
||||
if File.exist?(locale_path)
|
||||
say "Locale file already exists: #{locale_path}", :skip
|
||||
return
|
||||
end
|
||||
|
||||
FileUtils.mkdir_p(locale_dir)
|
||||
template "locale.en.yml.tt", locale_path
|
||||
say "Created locale file: #{locale_path}", :green
|
||||
end
|
||||
|
||||
def update_source_enums
|
||||
# Add the new provider to the source enum in ProviderMerchant and DataEnrichment
|
||||
# These enums track which provider created a merchant or enrichment record
|
||||
update_source_enum("app/models/provider_merchant.rb")
|
||||
update_source_enum("app/models/data_enrichment.rb")
|
||||
end
|
||||
|
||||
def show_summary
|
||||
say "\n" + "=" * 80, :green
|
||||
say "Successfully generated per-family provider: #{class_name}", :green
|
||||
@@ -395,6 +488,77 @@ class Provider::FamilyGenerator < Rails::Generators::NamedBase
|
||||
|
||||
private
|
||||
|
||||
def update_source_enum(model_path)
|
||||
return unless File.exist?(model_path)
|
||||
|
||||
content = File.read(model_path)
|
||||
model_name = File.basename(model_path, ".rb").camelize
|
||||
|
||||
# Check if provider is already in the enum
|
||||
if content.include?("#{file_name}: \"#{file_name}\"")
|
||||
say "#{model_name} source enum already includes #{file_name}", :skip
|
||||
return
|
||||
end
|
||||
|
||||
# Find the enum :source line and add the new provider
|
||||
# Pattern: enum :source, { key: "value", ... }
|
||||
if content =~ /(enum :source, \{[^}]+)(})/
|
||||
# Insert the new provider before the closing brace
|
||||
updated_content = content.sub(
|
||||
/(enum :source, \{[^}]+)(})/,
|
||||
"\\1, #{file_name}: \"#{file_name}\"\\2"
|
||||
)
|
||||
File.write(model_path, updated_content)
|
||||
say "Added #{file_name} to #{model_name} source enum", :green
|
||||
else
|
||||
say "Could not find source enum in #{model_name}", :yellow
|
||||
end
|
||||
end
|
||||
|
||||
def add_accounts_controller_sync_stats_map(controller_path)
|
||||
content = File.read(controller_path)
|
||||
stats_var = "@#{file_name}_sync_stats_map"
|
||||
|
||||
if content.include?(stats_var)
|
||||
say "Accounts controller already has #{stats_var}", :skip
|
||||
return
|
||||
end
|
||||
|
||||
# Find the build_sync_stats_maps method and add our stats map before the closing 'end'
|
||||
sync_stats_block = <<~RUBY
|
||||
|
||||
# #{class_name} sync stats
|
||||
#{stats_var} = {}
|
||||
@#{file_name}_items.each do |item|
|
||||
latest_sync = item.syncs.ordered.first
|
||||
#{stats_var}[item.id] = latest_sync&.sync_stats || {}
|
||||
end
|
||||
RUBY
|
||||
|
||||
lines = content.lines
|
||||
method_start = nil
|
||||
method_end = nil
|
||||
indent_level = 0
|
||||
|
||||
lines.each_with_index do |line, index|
|
||||
if line.include?("def build_sync_stats_maps")
|
||||
method_start = index
|
||||
indent_level = line[/^\s*/].length
|
||||
elsif method_start && line =~ /^#{' ' * indent_level}end\s*$/
|
||||
method_end = index
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if method_end
|
||||
lines.insert(method_end, sync_stats_block)
|
||||
File.write(controller_path, lines.join)
|
||||
say "Added #{stats_var} to build_sync_stats_maps", :green
|
||||
else
|
||||
say "Could not find build_sync_stats_maps method end", :yellow
|
||||
end
|
||||
end
|
||||
|
||||
def table_name
|
||||
"#{file_name}_items"
|
||||
end
|
||||
|
||||
147
lib/generators/provider/family/templates/locale.en.yml.tt
Normal file
147
lib/generators/provider/family/templates/locale.en.yml.tt
Normal file
@@ -0,0 +1,147 @@
|
||||
---
|
||||
en:
|
||||
<%= file_name %>_items:
|
||||
create:
|
||||
success: <%= class_name %> connection created successfully
|
||||
destroy:
|
||||
success: <%= class_name %> connection removed
|
||||
index:
|
||||
title: <%= class_name %> Connections
|
||||
loading:
|
||||
loading_message: Loading <%= class_name %> accounts...
|
||||
loading_title: Loading
|
||||
link_accounts:
|
||||
all_already_linked:
|
||||
one: "The selected account (%%{names}) is already linked"
|
||||
other: "All %%{count} selected accounts are already linked: %%{names}"
|
||||
api_error: "API error: %%{message}"
|
||||
invalid_account_names:
|
||||
one: "Cannot link account with blank name"
|
||||
other: "Cannot link %%{count} accounts with blank names"
|
||||
link_failed: Failed to link accounts
|
||||
no_accounts_selected: Please select at least one account
|
||||
no_api_key: <%= class_name %> API key not found. Please configure it in Provider Settings.
|
||||
partial_invalid: "Successfully linked %%{created_count} account(s), %%{already_linked_count} were already linked, %%{invalid_count} account(s) had invalid names"
|
||||
partial_success: "Successfully linked %%{created_count} account(s). %%{already_linked_count} account(s) were already linked: %%{already_linked_names}"
|
||||
success:
|
||||
one: "Successfully linked %%{count} account"
|
||||
other: "Successfully linked %%{count} accounts"
|
||||
<%= file_name %>_item:
|
||||
accounts_need_setup: Accounts need setup
|
||||
delete: Delete connection
|
||||
deletion_in_progress: deletion in progress...
|
||||
error: Error
|
||||
no_accounts_description: This connection has no linked accounts yet.
|
||||
no_accounts_title: No accounts
|
||||
setup_action: Set Up New Accounts
|
||||
setup_description: "%%{linked} of %%{total} accounts linked. Choose account types for your newly imported <%= class_name %> accounts."
|
||||
setup_needed: New accounts ready to set up
|
||||
status: "Synced %%{timestamp} ago"
|
||||
status_never: Never synced
|
||||
status_with_summary: "Last synced %%{timestamp} ago - %%{summary}"
|
||||
syncing: Syncing...
|
||||
total: Total
|
||||
unlinked: Unlinked
|
||||
select_accounts:
|
||||
accounts_selected: accounts selected
|
||||
api_error: "API error: %%{message}"
|
||||
cancel: Cancel
|
||||
configure_name_in_provider: Cannot import - please configure account name in <%= class_name %>
|
||||
description: Select the accounts you want to link to your %%{product_name} account.
|
||||
link_accounts: Link selected accounts
|
||||
no_accounts_found: No accounts found. Please check your API key configuration.
|
||||
no_api_key: <%= class_name %> API key is not configured. Please configure it in Settings.
|
||||
no_credentials_configured: Please configure your <%= class_name %> credentials first in Provider Settings.
|
||||
no_name_placeholder: "(No name)"
|
||||
title: Select <%= class_name %> Accounts
|
||||
select_existing_account:
|
||||
account_already_linked: This account is already linked to a provider
|
||||
all_accounts_already_linked: All <%= class_name %> accounts are already linked
|
||||
api_error: "API error: %%{message}"
|
||||
cancel: Cancel
|
||||
configure_name_in_provider: Cannot import - please configure account name in <%= class_name %>
|
||||
description: Select a <%= class_name %> account to link with this account. Transactions will be synced and deduplicated automatically.
|
||||
link_account: Link account
|
||||
no_account_specified: No account specified
|
||||
no_accounts_found: No <%= class_name %> accounts found. Please check your API key configuration.
|
||||
no_api_key: <%= class_name %> API key is not configured. Please configure it in Settings.
|
||||
no_credentials_configured: Please configure your <%= class_name %> credentials first in Provider Settings.
|
||||
no_name_placeholder: "(No name)"
|
||||
title: "Link %%{account_name} with <%= class_name %>"
|
||||
link_existing_account:
|
||||
account_already_linked: This account is already linked to a provider
|
||||
api_error: "API error: %%{message}"
|
||||
invalid_account_name: Cannot link account with blank name
|
||||
provider_account_already_linked: This <%= class_name %> account is already linked to another account
|
||||
provider_account_not_found: <%= class_name %> account not found
|
||||
missing_parameters: Missing required parameters
|
||||
no_api_key: <%= class_name %> API key not found. Please configure it in Provider Settings.
|
||||
success: "Successfully linked %%{account_name} with <%= class_name %>"
|
||||
setup_accounts:
|
||||
account_type_label: "Account Type:"
|
||||
all_accounts_linked: "All your <%= class_name %> accounts have already been set up."
|
||||
api_error: "API error: %%{message}"
|
||||
fetch_failed: "Failed to Fetch Accounts"
|
||||
no_accounts_to_setup: "No Accounts to Set Up"
|
||||
no_api_key: "<%= class_name %> API key is not configured. Please check your connection settings."
|
||||
account_types:
|
||||
skip: Skip this account
|
||||
depository: Checking or Savings Account
|
||||
credit_card: Credit Card
|
||||
investment: Investment Account
|
||||
loan: Loan or Mortgage
|
||||
other_asset: Other Asset
|
||||
subtype_labels:
|
||||
depository: "Account Subtype:"
|
||||
credit_card: ""
|
||||
investment: "Investment Type:"
|
||||
loan: "Loan Type:"
|
||||
other_asset: ""
|
||||
subtype_messages:
|
||||
credit_card: "Credit cards will be automatically set up as credit card accounts."
|
||||
other_asset: "No additional options needed for Other Assets."
|
||||
subtypes:
|
||||
depository:
|
||||
checking: Checking
|
||||
savings: Savings
|
||||
hsa: Health Savings Account
|
||||
cd: Certificate of Deposit
|
||||
money_market: Money Market
|
||||
investment:
|
||||
brokerage: Brokerage
|
||||
pension: Pension
|
||||
retirement: Retirement
|
||||
"401k": "401(k)"
|
||||
roth_401k: "Roth 401(k)"
|
||||
"403b": "403(b)"
|
||||
tsp: Thrift Savings Plan
|
||||
"529_plan": "529 Plan"
|
||||
hsa: Health Savings Account
|
||||
mutual_fund: Mutual Fund
|
||||
ira: Traditional IRA
|
||||
roth_ira: Roth IRA
|
||||
angel: Angel
|
||||
loan:
|
||||
mortgage: Mortgage
|
||||
student: Student Loan
|
||||
auto: Auto Loan
|
||||
other: Other Loan
|
||||
balance: Balance
|
||||
cancel: Cancel
|
||||
choose_account_type: "Choose the correct account type for each <%= class_name %> account:"
|
||||
create_accounts: Create Accounts
|
||||
creating_accounts: Creating Accounts...
|
||||
historical_data_range: "Historical Data Range:"
|
||||
subtitle: Choose the correct account types for your imported accounts
|
||||
sync_start_date_help: Select how far back you want to sync transaction history.
|
||||
sync_start_date_label: "Start syncing transactions from:"
|
||||
title: Set Up Your <%= class_name %> Accounts
|
||||
complete_account_setup:
|
||||
all_skipped: "All accounts were skipped. No accounts were created."
|
||||
creation_failed: "Failed to create accounts: %%{error}"
|
||||
no_accounts: "No accounts to set up."
|
||||
success: "Successfully created %%{count} account(s)."
|
||||
sync:
|
||||
success: Sync started
|
||||
update:
|
||||
success: <%= class_name %> connection updated
|
||||
Reference in New Issue
Block a user