2024-07-11 08:37:21 -04:00
|
|
|
class Demo::Generator
|
|
|
|
COLORS = %w[#e99537 #4da568 #6471eb #db5a54 #df4e92 #c44fe9 #eb5429 #61c9ea #805dee #6ad28a]
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
# Builds a semi-realistic mirror of what production data might look like
|
|
|
|
def reset_and_clear_data!(family_names)
|
|
|
|
puts "Clearing existing data..."
|
|
|
|
|
|
|
|
destroy_everything!
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
puts "Data cleared"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
family_names.each_with_index do |family_name, index|
|
|
|
|
create_family_and_user!(family_name, "user#{index == 0 ? "" : index + 1}@maybe.local")
|
|
|
|
end
|
|
|
|
|
|
|
|
puts "Users reset"
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def reset_data!(family_names)
|
|
|
|
puts "Clearing existing data..."
|
|
|
|
|
|
|
|
destroy_everything!
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
puts "Data cleared"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
family_names.each_with_index do |family_name, index|
|
2025-02-07 15:36:05 -05:00
|
|
|
create_family_and_user!(family_name, "user#{index == 0 ? "" : index + 1}@maybe.local")
|
2025-01-31 19:08:21 -05:00
|
|
|
end
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
puts "Users reset"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
load_securities!
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
puts "Securities loaded"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
family_names.each do |family_name|
|
|
|
|
family = Family.find_by(name: family_name)
|
2025-01-07 09:41:24 -05:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
ActiveRecord::Base.transaction do
|
|
|
|
create_tags!(family)
|
|
|
|
create_categories!(family)
|
|
|
|
create_merchants!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
puts "tags, categories, merchants created for #{family_name}"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
create_credit_card_account!(family)
|
|
|
|
create_checking_account!(family)
|
|
|
|
create_savings_account!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
create_investment_account!(family)
|
|
|
|
create_house_and_mortgage!(family)
|
|
|
|
create_car_and_loan!(family)
|
|
|
|
create_other_accounts!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
create_transfer_transactions!(family)
|
|
|
|
end
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
puts "accounts created for #{family_name}"
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
puts "Demo data loaded successfully!"
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
def destroy_everything!
|
|
|
|
Family.destroy_all
|
|
|
|
Setting.destroy_all
|
2024-09-13 17:24:19 -04:00
|
|
|
InviteCode.destroy_all
|
2024-07-11 08:37:21 -04:00
|
|
|
ExchangeRate.destroy_all
|
2024-07-16 09:26:49 -04:00
|
|
|
Security.destroy_all
|
|
|
|
Security::Price.destroy_all
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_family_and_user!(family_name, user_email, data_enrichment_enabled: false)
|
|
|
|
base_uuid = "d99e3c6e-d513-4452-8f24-dc263f8528c0"
|
|
|
|
id = Digest::UUID.uuid_v5(base_uuid, family_name)
|
|
|
|
|
|
|
|
family = Family.create!(
|
|
|
|
id: id,
|
|
|
|
name: family_name,
|
|
|
|
stripe_subscription_status: "active",
|
|
|
|
data_enrichment_enabled: data_enrichment_enabled,
|
|
|
|
locale: "en",
|
|
|
|
country: "US",
|
|
|
|
timezone: "America/New_York",
|
|
|
|
date_format: "%m-%d-%Y"
|
|
|
|
)
|
2024-09-13 17:24:19 -04:00
|
|
|
|
2024-07-11 08:37:21 -04:00
|
|
|
family.users.create! \
|
2025-01-31 19:08:21 -05:00
|
|
|
email: user_email,
|
2024-07-11 08:37:21 -04:00
|
|
|
first_name: "Demo",
|
|
|
|
last_name: "User",
|
2024-09-20 15:56:21 -04:00
|
|
|
role: "admin",
|
2024-10-24 11:02:27 -04:00
|
|
|
password: "password",
|
|
|
|
onboarded_at: Time.current
|
2025-01-31 19:08:21 -05:00
|
|
|
|
|
|
|
family.users.create! \
|
|
|
|
email: "member_#{user_email}",
|
|
|
|
first_name: "Demo (member user)",
|
|
|
|
last_name: "User",
|
|
|
|
role: "member",
|
|
|
|
password: "password",
|
|
|
|
onboarded_at: Time.current
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_tags!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
[ "Trips", "Emergency Fund", "Demo Tag" ].each do |tag|
|
|
|
|
family.tags.create!(name: tag)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_categories!(family)
|
2025-01-16 14:36:37 -05:00
|
|
|
family.categories.bootstrap_defaults
|
2024-12-20 11:37:26 -05:00
|
|
|
|
|
|
|
food = family.categories.find_by(name: "Food & Drink")
|
2025-01-16 14:36:37 -05:00
|
|
|
family.categories.create!(name: "Restaurants", parent: food, color: COLORS.sample, classification: "expense")
|
|
|
|
family.categories.create!(name: "Groceries", parent: food, color: COLORS.sample, classification: "expense")
|
|
|
|
family.categories.create!(name: "Alcohol & Bars", parent: food, color: COLORS.sample, classification: "expense")
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_merchants!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
merchants = [ "Amazon", "Starbucks", "McDonald's", "Target", "Costco",
|
|
|
|
"Home Depot", "Shell", "Whole Foods", "Walgreens", "Nike",
|
|
|
|
"Uber", "Netflix", "Spotify", "Delta Airlines", "Airbnb", "Sephora" ]
|
|
|
|
|
|
|
|
merchants.each do |merchant|
|
|
|
|
family.merchants.create!(name: merchant, color: COLORS.sample)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_credit_card_account!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
cc = family.accounts.create! \
|
|
|
|
accountable: CreditCard.new,
|
|
|
|
name: "Chase Credit Card",
|
|
|
|
balance: 2300,
|
2024-11-15 13:49:37 -05:00
|
|
|
currency: "USD"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
800.times do
|
|
|
|
merchant = random_family_record(Merchant, family)
|
2024-07-11 08:37:21 -04:00
|
|
|
create_transaction! \
|
|
|
|
account: cc,
|
|
|
|
name: merchant.name,
|
|
|
|
amount: Faker::Number.positive(to: 200),
|
2025-01-31 19:08:21 -05:00
|
|
|
tags: [ tag_for_merchant(merchant, family) ],
|
|
|
|
category: category_for_merchant(merchant, family),
|
2024-07-11 08:37:21 -04:00
|
|
|
merchant: merchant
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
24.times do
|
2024-07-11 08:37:21 -04:00
|
|
|
create_transaction! \
|
|
|
|
account: cc,
|
|
|
|
amount: Faker::Number.negative(from: -1000),
|
|
|
|
name: "CC Payment"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_checking_account!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
checking = family.accounts.create! \
|
|
|
|
accountable: Depository.new,
|
|
|
|
name: "Chase Checking",
|
|
|
|
balance: 15000,
|
2024-11-15 13:49:37 -05:00
|
|
|
currency: "USD"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
200.times do
|
2024-07-11 08:37:21 -04:00
|
|
|
create_transaction! \
|
|
|
|
account: checking,
|
|
|
|
name: "Expense",
|
|
|
|
amount: Faker::Number.positive(from: 100, to: 1000)
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
50.times do
|
2024-07-11 08:37:21 -04:00
|
|
|
create_transaction! \
|
|
|
|
account: checking,
|
|
|
|
amount: Faker::Number.negative(from: -2000),
|
|
|
|
name: "Income",
|
2025-01-31 19:08:21 -05:00
|
|
|
category: family.categories.find_by(name: "Income")
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_savings_account!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
savings = family.accounts.create! \
|
|
|
|
accountable: Depository.new,
|
|
|
|
name: "Demo Savings",
|
|
|
|
balance: 40000,
|
2024-07-17 14:18:12 -04:00
|
|
|
currency: "USD",
|
2024-11-15 13:49:37 -05:00
|
|
|
subtype: "savings"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
100.times do
|
2024-07-11 08:37:21 -04:00
|
|
|
create_transaction! \
|
|
|
|
account: savings,
|
|
|
|
amount: Faker::Number.negative(from: -2000),
|
2025-01-31 19:08:21 -05:00
|
|
|
tags: [ family.tags.find_by(name: "Emergency Fund") ],
|
|
|
|
category: family.categories.find_by(name: "Income"),
|
2024-07-11 08:37:21 -04:00
|
|
|
name: "Income"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_transfer_transactions!(family)
|
2025-01-07 09:41:24 -05:00
|
|
|
checking = family.accounts.find_by(name: "Chase Checking")
|
|
|
|
credit_card = family.accounts.find_by(name: "Chase Credit Card")
|
|
|
|
investment = family.accounts.find_by(name: "Robinhood")
|
|
|
|
|
|
|
|
create_transaction!(
|
|
|
|
account: checking,
|
|
|
|
date: 1.day.ago.to_date,
|
|
|
|
amount: 100,
|
|
|
|
name: "Credit Card Payment"
|
|
|
|
)
|
|
|
|
|
|
|
|
create_transaction!(
|
|
|
|
account: credit_card,
|
|
|
|
date: 1.day.ago.to_date,
|
|
|
|
amount: -100,
|
|
|
|
name: "Credit Card Payment"
|
|
|
|
)
|
|
|
|
|
|
|
|
create_transaction!(
|
|
|
|
account: checking,
|
|
|
|
date: 3.days.ago.to_date,
|
|
|
|
amount: 500,
|
|
|
|
name: "Transfer to investment"
|
|
|
|
)
|
|
|
|
|
|
|
|
create_transaction!(
|
|
|
|
account: investment,
|
|
|
|
date: 2.days.ago.to_date,
|
|
|
|
amount: -500,
|
|
|
|
name: "Transfer from checking"
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2024-07-16 09:26:49 -04:00
|
|
|
def load_securities!
|
2024-07-25 16:46:04 -04:00
|
|
|
# Create an unknown security to simulate edge cases
|
2025-02-11 10:40:30 -06:00
|
|
|
Security.create! ticker: "UNKNOWN", name: "Unknown Demo Stock"
|
2024-07-25 16:46:04 -04:00
|
|
|
|
2024-07-16 09:26:49 -04:00
|
|
|
securities = [
|
2025-02-11 10:40:30 -06:00
|
|
|
{ ticker: "AAPL", exchange_mic: "XNGS", exchange_operating_mic: "XNAS", name: "Apple Inc.", reference_price: 210 },
|
|
|
|
{ ticker: "TM", exchange_mic: "XNYS", exchange_operating_mic: "XNYS", name: "Toyota Motor Corporation", reference_price: 202 },
|
|
|
|
{ ticker: "MSFT", exchange_mic: "XNGS", exchange_operating_mic: "XNAS", name: "Microsoft Corporation", reference_price: 455 }
|
2024-07-16 09:26:49 -04:00
|
|
|
]
|
|
|
|
|
|
|
|
securities.each do |security_attributes|
|
|
|
|
security = Security.create! security_attributes.except(:reference_price)
|
|
|
|
|
|
|
|
# Load prices for last 2 years
|
|
|
|
(730.days.ago.to_date..Date.current).each do |date|
|
|
|
|
reference = security_attributes[:reference_price]
|
|
|
|
low_price = reference - 20
|
|
|
|
high_price = reference + 20
|
|
|
|
Security::Price.create! \
|
2024-10-29 15:37:59 -04:00
|
|
|
security: security,
|
2024-07-16 09:26:49 -04:00
|
|
|
date: date,
|
|
|
|
price: Faker::Number.positive(from: low_price, to: high_price)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_investment_account!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
account = family.accounts.create! \
|
|
|
|
accountable: Investment.new,
|
|
|
|
name: "Robinhood",
|
|
|
|
balance: 100000,
|
2024-11-15 13:49:37 -05:00
|
|
|
currency: "USD"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
2024-08-01 19:43:23 -04:00
|
|
|
aapl = Security.find_by(ticker: "AAPL")
|
|
|
|
tm = Security.find_by(ticker: "TM")
|
|
|
|
msft = Security.find_by(ticker: "MSFT")
|
|
|
|
unknown = Security.find_by(ticker: "UNKNOWN")
|
2024-07-25 16:46:04 -04:00
|
|
|
|
|
|
|
# Buy 20 shares of the unknown stock to simulate a stock where we can't fetch security prices
|
2024-08-09 11:22:57 -04:00
|
|
|
account.entries.create! date: 10.days.ago.to_date, amount: 100, currency: "USD", name: "Buy unknown stock", entryable: Account::Trade.new(qty: 20, price: 5, security: unknown, currency: "USD")
|
2024-07-17 08:57:28 -04:00
|
|
|
|
|
|
|
trades = [
|
|
|
|
{ security: aapl, qty: 20 }, { security: msft, qty: 10 }, { security: aapl, qty: -5 },
|
|
|
|
{ security: msft, qty: -5 }, { security: tm, qty: 10 }, { security: msft, qty: 5 },
|
|
|
|
{ security: tm, qty: 10 }, { security: aapl, qty: -5 }, { security: msft, qty: -5 },
|
|
|
|
{ security: tm, qty: 10 }, { security: msft, qty: 5 }, { security: aapl, qty: -10 }
|
|
|
|
]
|
|
|
|
|
|
|
|
trades.each do |trade|
|
2024-07-16 09:26:49 -04:00
|
|
|
date = Faker::Number.positive(to: 730).days.ago.to_date
|
2024-07-17 08:57:28 -04:00
|
|
|
security = trade[:security]
|
|
|
|
qty = trade[:qty]
|
2024-08-01 19:43:23 -04:00
|
|
|
price = Security::Price.find_by(ticker: security.ticker, date: date)&.price || 1
|
2024-07-16 09:26:49 -04:00
|
|
|
name_prefix = qty < 0 ? "Sell " : "Buy "
|
|
|
|
|
|
|
|
account.entries.create! \
|
|
|
|
date: date,
|
|
|
|
amount: qty * price,
|
|
|
|
currency: "USD",
|
2024-08-01 19:43:23 -04:00
|
|
|
name: name_prefix + "#{qty} shares of #{security.ticker}",
|
2024-08-09 11:22:57 -04:00
|
|
|
entryable: Account::Trade.new(qty: qty, price: price, currency: "USD", security: security)
|
2024-07-16 09:26:49 -04:00
|
|
|
end
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_house_and_mortgage!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
house = family.accounts.create! \
|
|
|
|
accountable: Property.new,
|
|
|
|
name: "123 Maybe Way",
|
2024-07-17 14:18:12 -04:00
|
|
|
balance: 560000,
|
|
|
|
currency: "USD"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
|
|
|
create_valuation!(house, 3.years.ago.to_date, 520000)
|
|
|
|
create_valuation!(house, 2.years.ago.to_date, 540000)
|
|
|
|
create_valuation!(house, 1.years.ago.to_date, 550000)
|
|
|
|
|
|
|
|
family.accounts.create! \
|
|
|
|
accountable: Loan.new,
|
|
|
|
name: "Mortgage",
|
2024-07-17 14:18:12 -04:00
|
|
|
balance: 495000,
|
|
|
|
currency: "USD"
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_car_and_loan!(family)
|
2024-07-11 08:37:21 -04:00
|
|
|
family.accounts.create! \
|
|
|
|
accountable: Vehicle.new,
|
|
|
|
name: "Honda Accord",
|
2024-07-17 14:18:12 -04:00
|
|
|
balance: 18000,
|
|
|
|
currency: "USD"
|
2024-07-11 08:37:21 -04:00
|
|
|
|
|
|
|
family.accounts.create! \
|
|
|
|
accountable: Loan.new,
|
|
|
|
name: "Car Loan",
|
2024-07-17 14:18:12 -04:00
|
|
|
balance: 8000,
|
|
|
|
currency: "USD"
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def create_other_accounts!(family)
|
2024-11-04 20:27:31 -05:00
|
|
|
family.accounts.create! \
|
|
|
|
accountable: OtherAsset.new,
|
|
|
|
name: "Other Asset",
|
|
|
|
balance: 10000,
|
|
|
|
currency: "USD"
|
|
|
|
|
|
|
|
family.accounts.create! \
|
|
|
|
accountable: OtherLiability.new,
|
|
|
|
name: "Other Liability",
|
|
|
|
balance: 5000,
|
|
|
|
currency: "USD"
|
|
|
|
end
|
|
|
|
|
2024-07-11 08:37:21 -04:00
|
|
|
def create_transaction!(attributes = {})
|
|
|
|
entry_attributes = attributes.except(:category, :tags, :merchant)
|
|
|
|
transaction_attributes = attributes.slice(:category, :tags, :merchant)
|
|
|
|
|
|
|
|
entry_defaults = {
|
2025-01-31 19:08:21 -05:00
|
|
|
date: Faker::Number.between(from: 0, to: 730).days.ago.to_date,
|
2024-07-11 08:37:21 -04:00
|
|
|
currency: "USD",
|
|
|
|
entryable: Account::Transaction.new(transaction_attributes)
|
|
|
|
}
|
|
|
|
|
|
|
|
Account::Entry.create! entry_defaults.merge(entry_attributes)
|
|
|
|
end
|
|
|
|
|
|
|
|
def create_valuation!(account, date, amount)
|
|
|
|
Account::Entry.create! \
|
|
|
|
account: account,
|
|
|
|
date: date,
|
|
|
|
amount: amount,
|
|
|
|
currency: "USD",
|
2024-12-19 10:16:09 -05:00
|
|
|
name: "Balance update",
|
2024-07-11 08:37:21 -04:00
|
|
|
entryable: Account::Valuation.new
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def random_family_record(model, family)
|
2024-07-11 08:37:21 -04:00
|
|
|
family_records = model.where(family_id: family.id)
|
|
|
|
model.offset(rand(family_records.count)).first
|
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def category_for_merchant(merchant, family)
|
2024-07-11 08:37:21 -04:00
|
|
|
mapping = {
|
|
|
|
"Amazon" => "Shopping",
|
|
|
|
"Starbucks" => "Food & Drink",
|
|
|
|
"McDonald's" => "Food & Drink",
|
|
|
|
"Target" => "Shopping",
|
|
|
|
"Costco" => "Food & Drink",
|
2025-01-16 14:36:37 -05:00
|
|
|
"Home Depot" => "Housing",
|
|
|
|
"Shell" => "Transportation",
|
2024-07-11 08:37:21 -04:00
|
|
|
"Whole Foods" => "Food & Drink",
|
2025-01-16 14:36:37 -05:00
|
|
|
"Walgreens" => "Healthcare",
|
2024-07-11 08:37:21 -04:00
|
|
|
"Nike" => "Shopping",
|
2025-01-16 14:36:37 -05:00
|
|
|
"Uber" => "Transportation",
|
|
|
|
"Netflix" => "Subscriptions",
|
|
|
|
"Spotify" => "Subscriptions",
|
|
|
|
"Delta Airlines" => "Transportation",
|
|
|
|
"Airbnb" => "Housing",
|
|
|
|
"Sephora" => "Shopping"
|
2024-07-11 08:37:21 -04:00
|
|
|
}
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
family.categories.find_by(name: mapping[merchant.name])
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
def tag_for_merchant(merchant, family)
|
2024-07-11 08:37:21 -04:00
|
|
|
mapping = {
|
|
|
|
"Delta Airlines" => "Trips",
|
|
|
|
"Airbnb" => "Trips"
|
|
|
|
}
|
|
|
|
|
2025-01-31 19:08:21 -05:00
|
|
|
tag_from_merchant = family.tags.find_by(name: mapping[merchant.name])
|
|
|
|
tag_from_merchant || family.tags.find_by(name: "Demo Tag")
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|
|
|
|
|
2024-07-16 09:26:49 -04:00
|
|
|
def securities
|
|
|
|
@securities ||= Security.all.to_a
|
|
|
|
end
|
2024-07-11 08:37:21 -04:00
|
|
|
end
|