class LunchMoney::Api

Constants

BASE_URL
LUNCHMONEY_TOKEN

Public Instance Methods

create_category(name:, description: nil, is_income: false, exclude_from_budget: false, exclude_from_totals: false) click to toggle source
# File lib/lunchmoney/api.rb, line 39
def create_category(name:, description: nil, is_income: false,
  exclude_from_budget: false, exclude_from_totals: false)
  params = {
    name: name,
    description: description,
    is_income: is_income,
    exclude_from_budget: exclude_from_budget,
    exclude_from_totals: exclude_from_totals,
  }

  response = post("categories", params)
  get_errors(response)

  response.body
end
create_transaction_group(date:, payee:, transactions:, category_id: nil, notes: nil, tags: nil) click to toggle source
# File lib/lunchmoney/api.rb, line 196
def create_transaction_group(date:, payee:, transactions:, category_id: nil, notes: nil, tags: nil)
  params = {
    date: date,
    payee: payee,
    transactions: transactions,
  }
  params[:category_id] = category_id if category_id
  params[:notes] = notes if notes
  params[:tags] = tags if tags

  response = post("transactions/group", params)
  get_errors(response)

  response.body
end
delete_transaction_group(transaction_id) click to toggle source
# File lib/lunchmoney/api.rb, line 213
def delete_transaction_group(transaction_id)
  response = delete("transactions/group/#{transaction_id}")
  get_errors(response)

  response.body
end
get_all_assets() click to toggle source
# File lib/lunchmoney/api.rb, line 280
def get_all_assets
  response = get("assets")

  get_errors(response)

  return response.body[:assets] unless use_structs?
  response.body[:assets].map { |asset| LunchMoney::Asset.new(asset) }
end
get_all_categories() click to toggle source
# File lib/lunchmoney/api.rb, line 26
def get_all_categories
  response = get("categories")

  get_errors(response)

  return response.body[:categories] unless use_structs?
  response.body[:categories].map { |category| LunchMoney::Category.new(category) }
end
get_all_crypto() click to toggle source
# File lib/lunchmoney/api.rb, line 331
def get_all_crypto
  response = get("crypto")

  get_errors(response)

  return response.body[:crypto] unless use_structs?
  response.body[:crypto].map { |crypto| LunchMoney::Crypto.new(crypto) }
end
get_all_plaid_accounts() click to toggle source
# File lib/lunchmoney/api.rb, line 321
def get_all_plaid_accounts
  response = get("plaid_accounts")

  get_errors(response)

  return response.body[:plaid_accounts] unless use_structs?
  response.body[:plaid_accounts].map { |plaid_account| LunchMoney::PlaidAccount.new(plaid_account) }
end
get_all_tags() click to toggle source
# File lib/lunchmoney/api.rb, line 56
def get_all_tags
  response = get("tags")

  get_errors(response)

  return response.body unless use_structs?
  response.body.map { |tag| LunchMoney::Tag.new(tag) }
end
get_budget_summary(start_date:, end_date:) click to toggle source
# File lib/lunchmoney/api.rb, line 243
def get_budget_summary(start_date:, end_date:)
  params = {
    start_date: start_date,
    end_date: end_date,
  }
  response = get("budgets", query_params: params)
  get_errors(response)

  response.body

  # TODO: below code is for use_structs path, however with changes to the
  # endpoint I do not have the documenation yet to finish that version
  response.body.map do |budget|
    budget[:data].each do |key, value|
      budget[:data][key] = LunchMoney::Data.new(value)
    end

    LunchMoney::Budget.new(budget)
  end
end
get_recurring_expenses(start_date: nil, debit_as_negative: nil) click to toggle source
# File lib/lunchmoney/api.rb, line 225
def get_recurring_expenses(start_date: nil, debit_as_negative: nil)
  params = {}
  params[:start_date] = start_date if start_date
  params[:debit_as_negative] = debit_as_negative if debit_as_negative

  response = if params.empty?
    get("recurring_expenses")
  else
    get("recurring_expenses", query_params: params)
  end

  get_errors(response)

  return response.body[:recurring_expenses] unless use_structs?
  response.body[:recurring_expenses].map { |recurring_expense| LunchMoney::RecurringExpense.new(recurring_expense) }
end
get_single_transaction(transaction_id:, debit_as_negative: nil) click to toggle source
# File lib/lunchmoney/api.rb, line 126
def get_single_transaction(transaction_id:, debit_as_negative: nil)
  params = {}
  params[:debit_as_negative] = debit_as_negative if debit_as_negative

  response = if params.empty?
    get("transactions/#{transaction_id}")
  else
    get("transactions/#{transaction_id}", query_params: params)
  end

  get_errors(response)

  return response.body unless use_structs?
  LunchMoney::Transaction.new(response.body)
end
get_transactions( tag_id: nil, recurring_id: nil, plaid_account_id: nil, category_id: nil, asset_id: nil, group_id: nil, is_group: nil, status: nil, offset: nil, limit: nil, start_date: nil, end_date: nil, debit_as_negative: nil ) click to toggle source
# File lib/lunchmoney/api.rb, line 82
def get_transactions(
  tag_id: nil,
  recurring_id: nil,
  plaid_account_id: nil,
  category_id: nil,
  asset_id: nil,
  group_id: nil,
  is_group: nil,
  status: nil,
  offset: nil,
  limit: nil,
  start_date: nil,
  end_date: nil,
  debit_as_negative: nil
)

  params = {}
  params[:tag_id] = tag_id if tag_id
  params[:recurring_id] = recurring_id if recurring_id
  params[:plaid_account_id] = plaid_account_id if plaid_account_id
  params[:category_id] = category_id if category_id
  params[:asset_id] = asset_id if asset_id
  params[:group_id] = group_id if group_id
  params[:is_group] = is_group if is_group
  params[:status] = status if status
  params[:offset] = offset if offset
  params[:limit] = limit if limit
  params[:start_date] = start_date if start_date
  params[:end_date] = end_date if end_date
  params[:debit_as_negative] = debit_as_negative if debit_as_negative

  response = if params.empty?
    get("transactions")
  else
    get("transactions", query_params: params)
  end

  get_errors(response)

  return response.body[:transactions] unless use_structs?
  response.body[:transactions].map { |transaction| LunchMoney::Transaction.new(transaction) }
end
insert_transactions(transactions, apply_rules: nil, skip_duplicates: nil, check_for_recurring: nil, debit_as_negative: nil, skip_balance_update: nil) click to toggle source
# File lib/lunchmoney/api.rb, line 150
def insert_transactions(transactions, apply_rules: nil, skip_duplicates: nil,
  check_for_recurring: nil, debit_as_negative: nil, skip_balance_update: nil)
  params = { transactions: transactions.map(&:serialize) }
  params[:apply_rules] = apply_rules if apply_rules
  params[:skip_duplicates] = skip_duplicates if skip_duplicates
  params[:check_for_recurring] = check_for_recurring if check_for_recurring
  params[:debit_as_negative] = debit_as_negative if debit_as_negative
  params[:skip_balance_update] = skip_balance_update if skip_balance_update

  response = post("transactions", params)
  get_errors(response)

  response.body
end
remove_budget() click to toggle source
# File lib/lunchmoney/api.rb, line 273
def remove_budget
  # TODO
  # response = delete("budgets")
  # response.body
end
update_asset(asset_id, type_name: nil, subtype_name: nil, name: nil, balance: nil, balance_as_of: nil, currency: nil, institution_name: nil) click to toggle source
# File lib/lunchmoney/api.rb, line 301
def update_asset(asset_id, type_name: nil, subtype_name: nil, name: nil, balance: nil,
  balance_as_of: nil, currency: nil, institution_name: nil)
  params = {}
  params[:type_name] = type_name if type_name
  params[:subtype_name] = subtype_name if subtype_name
  params[:name] = name if name
  params[:balance] = balance if balance
  params[:balance_as_of] = balance_as_of if balance_as_of
  params[:currency] = currency if currency
  params[:institution_name] = institution_name if institution_name

  response = put("assets/#{asset_id}", params)

  get_errors(response)

  return response.body unless use_structs?
  LunchMoney::Asset.new(response.body)
end
update_manual_crypto(crypto_asset_id, name: nil, display_name: nil, institution_name: nil, balance: nil, currency: nil) click to toggle source
# File lib/lunchmoney/api.rb, line 350
def update_manual_crypto(crypto_asset_id, name: nil, display_name: nil,
  institution_name: nil, balance: nil, currency: nil)
  params = {}
  params[:name] = name if name
  params[:display_name] = display_name if display_name
  params[:institution_name] = institution_name if institution_name
  params[:balance] = balance if balance
  params[:currency] = currency if currency

  response = put("crypto/manual/#{crypto_asset_id}", params)

  get_errors(response)

  return response.body unless use_structs?
  LunchMoney::Asset.new(response.body)
end
update_transaction(transaction_id, transaction:, split: nil, debit_as_negative: false, skip_balance_update: true) click to toggle source
# File lib/lunchmoney/api.rb, line 174
def update_transaction(transaction_id, transaction:, split: nil,
  debit_as_negative: false, skip_balance_update: true)
  body = transaction.wrap_and_serialize
  body.merge!(split) if split
  body["debit_as_negative"] = debit_as_negative if debit_as_negative
  body["skip_balance_update"] = skip_balance_update unless skip_balance_update

  response = put("transactions/#{transaction_id}", body)
  get_errors(response)
  response.body
end
upsert_budget(body) click to toggle source
# File lib/lunchmoney/api.rb, line 265
def upsert_budget(body)
  # TODO
  # response = put("budgets", body)
  # get_errors(response)
  # response.body
end

Private Instance Methods

delete(endpoint) click to toggle source
# File lib/lunchmoney/api.rb, line 409
def delete(endpoint)
  request = Faraday.new do |conn|
    conn.authorization(:Bearer, LUNCHMONEY_TOKEN)
    conn.response(:json, content_type: /json$/, parser_options: { symbolize_names: true })
  end

  request.delete(BASE_URL + endpoint)
end
get(endpoint, query_params: nil) click to toggle source
# File lib/lunchmoney/api.rb, line 370
def get(endpoint, query_params: nil)
  request = Faraday.new do |conn|
    conn.authorization(:Bearer, LUNCHMONEY_TOKEN)
    conn.options.params_encoder = Faraday::FlatParamsEncoder
    conn.response(:json, content_type: /json$/, parser_options: { symbolize_names: true })
  end

  if query_params
    request.get(BASE_URL + endpoint, query_params)
  else
    request.get(BASE_URL + endpoint)
  end
end
get_errors(response) click to toggle source
# File lib/lunchmoney/api.rb, line 419
def get_errors(response)
  body = response.body
  if body.is_a?(Hash)
    parse_and_raise_error(body) if body[:error]
    raise(LunchMoney::ValidateError, body[:message]) if body[:name]&.eql?("ValidateError")
  end
end
parse_and_raise_error(body) click to toggle source
# File lib/lunchmoney/api.rb, line 428
def parse_and_raise_error(body)
  error = body[:error]
  raise(LunchMoney::MultipleIssuesError, error) if error.is_a?(Array)

  case error
  when /Missing category name|Category \w+ must be less than /
    raise(LunchMoney::CategoryError, error)
  when /Operation error occurred/
    raise(LunchMoney::OperationError, error)
  when /Both start_date and end_date must be specified./
    raise(LunchMoney::MissingDateError, error)
  when /Transaction ID not found/
    raise(LunchMoney::UnknownTransactionError, error)
  when /Must be in format YYYY-MM-DD/
    raise(LunchMoney::InvalidDateError, error)
  when /Budget must be greater than or equal/
    raise(LunchMoney::BudgetAmountError, error)
  else
    raise(LunchMoney::GeneralError, error)
  end
end
post(endpoint, params) click to toggle source
# File lib/lunchmoney/api.rb, line 385
def post(endpoint, params)
  request = Faraday.new do |conn|
    conn.authorization(:Bearer, LUNCHMONEY_TOKEN)
    conn.request(:json)
    conn.response(:json, content_type: /json$/, parser_options: { symbolize_names: true })
  end

  request.post(BASE_URL + endpoint, params)
end
put(endpoint, body) click to toggle source
# File lib/lunchmoney/api.rb, line 396
def put(endpoint, body)
  request = Faraday.new do |conn|
    conn.authorization(:Bearer, LUNCHMONEY_TOKEN)
    conn.request(:json)
    conn.response(:json, content_type: /json$/, parser_options: { symbolize_names: true })
  end

  request.put(BASE_URL + endpoint) do |req|
    req.body = body
  end
end
use_structs?() click to toggle source
# File lib/lunchmoney/api.rb, line 451
def use_structs?
  LunchMoney.config.response_objects_as_structs
end