lunchmoney 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.github/dependabot.yml +18 -0
- data/.github/workflows/build_and_publish_yard_docs.yml +47 -0
- data/.github/workflows/ci.yml +58 -0
- data/.github/workflows/dependabot-rbi-updater.yml +43 -0
- data/.github/workflows/publish_gem.yml +31 -0
- data/.gitignore +62 -0
- data/.rubocop.yml +45 -0
- data/.ruby-version +1 -0
- data/.toys/.toys.rb +10 -0
- data/.toys/ci.rb +22 -0
- data/.toys/rbi.rb +60 -0
- data/.toys/rubocop.rb +10 -0
- data/.toys/spoom.rb +15 -0
- data/.toys/typecheck.rb +5 -0
- data/.yardopts +2 -0
- data/Appraisals +22 -0
- data/Gemfile +25 -0
- data/Gemfile.lock +174 -0
- data/LICENSE +21 -0
- data/README.md +57 -0
- data/bin/console +16 -0
- data/bin/rubocop +27 -0
- data/bin/setup +8 -0
- data/bin/spoom +27 -0
- data/bin/srb +27 -0
- data/bin/tapioca +27 -0
- data/bin/toys +27 -0
- data/bin/yard +27 -0
- data/lib/lunchmoney/api.rb +147 -0
- data/lib/lunchmoney/api_call.rb +109 -0
- data/lib/lunchmoney/assets/asset.rb +89 -0
- data/lib/lunchmoney/assets/asset_calls.rb +96 -0
- data/lib/lunchmoney/budget/budget.rb +74 -0
- data/lib/lunchmoney/budget/budget_calls.rb +82 -0
- data/lib/lunchmoney/budget/config.rb +38 -0
- data/lib/lunchmoney/budget/data.rb +42 -0
- data/lib/lunchmoney/categories/category/category.rb +52 -0
- data/lib/lunchmoney/categories/category/child_category.rb +42 -0
- data/lib/lunchmoney/categories/category_calls.rb +195 -0
- data/lib/lunchmoney/configuration.rb +26 -0
- data/lib/lunchmoney/crypto/crypto/crypto.rb +43 -0
- data/lib/lunchmoney/crypto/crypto/crypto_base.rb +65 -0
- data/lib/lunchmoney/crypto/crypto_calls.rb +49 -0
- data/lib/lunchmoney/data_object.rb +25 -0
- data/lib/lunchmoney/errors.rb +19 -0
- data/lib/lunchmoney/exceptions.rb +19 -0
- data/lib/lunchmoney/plaid_accounts/plaid_account.rb +73 -0
- data/lib/lunchmoney/plaid_accounts/plaid_account_calls.rb +38 -0
- data/lib/lunchmoney/recurring_expenses/recurring_expense/recurring_expense.rb +65 -0
- data/lib/lunchmoney/recurring_expenses/recurring_expense/recurring_expense_base.rb +29 -0
- data/lib/lunchmoney/recurring_expenses/recurring_expense_calls.rb +28 -0
- data/lib/lunchmoney/tags/tag/tag.rb +20 -0
- data/lib/lunchmoney/tags/tag/tag_base.rb +21 -0
- data/lib/lunchmoney/tags/tag_calls.rb +20 -0
- data/lib/lunchmoney/transactions/transaction/child_transaction.rb +31 -0
- data/lib/lunchmoney/transactions/transaction/split.rb +24 -0
- data/lib/lunchmoney/transactions/transaction/transaction.rb +156 -0
- data/lib/lunchmoney/transactions/transaction/transaction_base.rb +52 -0
- data/lib/lunchmoney/transactions/transaction/transaction_modification_base.rb +30 -0
- data/lib/lunchmoney/transactions/transaction/update_transaction.rb +43 -0
- data/lib/lunchmoney/transactions/transaction_calls.rb +218 -0
- data/lib/lunchmoney/user/user.rb +36 -0
- data/lib/lunchmoney/user/user_calls.rb +19 -0
- data/lib/lunchmoney/validators.rb +43 -0
- data/lib/lunchmoney/version.rb +7 -0
- data/lib/lunchmoney.rb +54 -0
- data/lunchmoney.gemspec +34 -0
- data/sorbet/config +5 -0
- data/sorbet/rbi/annotations/.gitattributes +1 -0
- data/sorbet/rbi/annotations/activesupport.rbi +410 -0
- data/sorbet/rbi/annotations/faraday.rbi +17 -0
- data/sorbet/rbi/annotations/mocha.rbi +34 -0
- data/sorbet/rbi/annotations/rainbow.rbi +269 -0
- data/sorbet/rbi/annotations/webmock.rbi +9 -0
- data/sorbet/rbi/dsl/.gitattributes +1 -0
- data/sorbet/rbi/dsl/active_support/callbacks.rbi +22 -0
- data/sorbet/rbi/gems/.gitattributes +1 -0
- data/sorbet/rbi/gems/activesupport@7.1.3.rbi +18004 -0
- data/sorbet/rbi/gems/addressable@2.8.6.rbi +1993 -0
- data/sorbet/rbi/gems/appraisal@2.5.0.rbi +621 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
- data/sorbet/rbi/gems/base64@0.2.0.rbi +508 -0
- data/sorbet/rbi/gems/bigdecimal@3.1.6.rbi +77 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +3426 -0
- data/sorbet/rbi/gems/concurrent-ruby@1.2.3.rbi +11590 -0
- data/sorbet/rbi/gems/connection_pool@2.4.1.rbi +8 -0
- data/sorbet/rbi/gems/crack@0.4.5.rbi +144 -0
- data/sorbet/rbi/gems/dotenv@2.8.1.rbi +234 -0
- data/sorbet/rbi/gems/drb@2.2.0.rbi +1346 -0
- data/sorbet/rbi/gems/erubi@1.12.0.rbi +145 -0
- data/sorbet/rbi/gems/faraday-net_http@3.1.0.rbi +146 -0
- data/sorbet/rbi/gems/faraday@2.9.0.rbi +2911 -0
- data/sorbet/rbi/gems/hashdiff@1.1.0.rbi +352 -0
- data/sorbet/rbi/gems/i18n@1.14.1.rbi +2325 -0
- data/sorbet/rbi/gems/json@2.7.1.rbi +1561 -0
- data/sorbet/rbi/gems/language_server-protocol@3.17.0.3.rbi +14237 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +272 -0
- data/sorbet/rbi/gems/minitest@5.21.2.rbi +2197 -0
- data/sorbet/rbi/gems/mocha@2.1.0.rbi +3934 -0
- data/sorbet/rbi/gems/mutex_m@0.2.0.rbi +93 -0
- data/sorbet/rbi/gems/net-http@0.4.1.rbi +4068 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +158 -0
- data/sorbet/rbi/gems/parallel@1.24.0.rbi +280 -0
- data/sorbet/rbi/gems/parser@3.3.0.5.rbi +5472 -0
- data/sorbet/rbi/gems/prettier_print@1.2.1.rbi +951 -0
- data/sorbet/rbi/gems/prism@0.19.0.rbi +29883 -0
- data/sorbet/rbi/gems/pry-sorbet@0.2.1.rbi +966 -0
- data/sorbet/rbi/gems/pry@0.14.2.rbi +10077 -0
- data/sorbet/rbi/gems/public_suffix@5.0.4.rbi +935 -0
- data/sorbet/rbi/gems/racc@1.7.3.rbi +161 -0
- data/sorbet/rbi/gems/rack@3.0.8.rbi +5183 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +402 -0
- data/sorbet/rbi/gems/rake@13.1.0.rbi +3027 -0
- data/sorbet/rbi/gems/rbi@0.1.6.rbi +2922 -0
- data/sorbet/rbi/gems/regexp_parser@2.9.0.rbi +3771 -0
- data/sorbet/rbi/gems/rexml@3.2.6.rbi +4781 -0
- data/sorbet/rbi/gems/rubocop-ast@1.30.0.rbi +7117 -0
- data/sorbet/rbi/gems/rubocop-minitest@0.34.5.rbi +2576 -0
- data/sorbet/rbi/gems/rubocop-rails@2.23.1.rbi +9175 -0
- data/sorbet/rbi/gems/rubocop-shopify@2.14.0.rbi +8 -0
- data/sorbet/rbi/gems/rubocop-sorbet@0.7.6.rbi +1510 -0
- data/sorbet/rbi/gems/rubocop@1.60.1.rbi +57356 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1317 -0
- data/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi +8 -0
- data/sorbet/rbi/gems/spoom@1.2.4.rbi +3777 -0
- data/sorbet/rbi/gems/syntax_tree@6.2.0.rbi +23136 -0
- data/sorbet/rbi/gems/tapioca@0.12.0.rbi +3506 -0
- data/sorbet/rbi/gems/thor@1.3.0.rbi +4312 -0
- data/sorbet/rbi/gems/toys-core@0.15.4.rbi +9462 -0
- data/sorbet/rbi/gems/toys@0.15.4.rbi +243 -0
- data/sorbet/rbi/gems/tzinfo@2.0.6.rbi +5917 -0
- data/sorbet/rbi/gems/unicode-display_width@2.5.0.rbi +65 -0
- data/sorbet/rbi/gems/uri@0.13.0.rbi +2327 -0
- data/sorbet/rbi/gems/vcr@6.2.0.rbi +3036 -0
- data/sorbet/rbi/gems/webmock@3.19.1.rbi +1768 -0
- data/sorbet/rbi/gems/yard-sorbet@0.8.1.rbi +428 -0
- data/sorbet/rbi/gems/yard@0.9.34.rbi +18084 -0
- data/sorbet/shims/module.rbi +6 -0
- data/sorbet/tapioca/require.rb +10 -0
- metadata +228 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# https://lunchmoney.dev/#crypto-object
|
6
|
+
class CryptoBase < LunchMoney::DataObject
|
7
|
+
include LunchMoney::Validators
|
8
|
+
|
9
|
+
sig { returns(T.nilable(Integer)) }
|
10
|
+
attr_accessor :id, :zabo_account_id
|
11
|
+
|
12
|
+
sig { returns(String) }
|
13
|
+
attr_reader :source, :created_at
|
14
|
+
|
15
|
+
sig { returns(String) }
|
16
|
+
attr_accessor :name, :balance
|
17
|
+
|
18
|
+
sig { returns(T.nilable(String)) }
|
19
|
+
attr_accessor :display_name, :institution_name
|
20
|
+
|
21
|
+
# Valid crypto source types
|
22
|
+
VALID_SOURCES = T.let(
|
23
|
+
[
|
24
|
+
"synced",
|
25
|
+
"manual",
|
26
|
+
],
|
27
|
+
T::Array[String],
|
28
|
+
)
|
29
|
+
|
30
|
+
sig do
|
31
|
+
params(
|
32
|
+
created_at: String,
|
33
|
+
source: String,
|
34
|
+
name: String,
|
35
|
+
balance: String,
|
36
|
+
institution_name: T.nilable(String),
|
37
|
+
id: T.nilable(Integer),
|
38
|
+
zabo_account_id: T.nilable(Integer),
|
39
|
+
display_name: T.nilable(String),
|
40
|
+
).void
|
41
|
+
end
|
42
|
+
def initialize(created_at:, source:, name:, balance:, institution_name: nil, id: nil, zabo_account_id: nil,
|
43
|
+
display_name: nil)
|
44
|
+
super()
|
45
|
+
@created_at = T.let(validate_iso8601!(created_at), String)
|
46
|
+
@source = T.let(validate_one_of!(source, VALID_SOURCES), String)
|
47
|
+
@name = name
|
48
|
+
@balance = balance
|
49
|
+
@institution_name = institution_name
|
50
|
+
@id = id
|
51
|
+
@zabo_account_id = zabo_account_id
|
52
|
+
@display_name = display_name
|
53
|
+
end
|
54
|
+
|
55
|
+
sig { params(name: String).void }
|
56
|
+
def source=(name)
|
57
|
+
@source = validate_one_of!(name, VALID_SOURCES)
|
58
|
+
end
|
59
|
+
|
60
|
+
sig { params(time: String).void }
|
61
|
+
def created_at=(time)
|
62
|
+
@created_at = validate_iso8601!(time)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "crypto/crypto_base"
|
5
|
+
require_relative "crypto/crypto"
|
6
|
+
|
7
|
+
module LunchMoney
|
8
|
+
# https://lunchmoney.dev/#crypto
|
9
|
+
class CryptoCalls < ApiCall
|
10
|
+
sig { returns(T.any(T::Array[LunchMoney::Crypto], LunchMoney::Errors)) }
|
11
|
+
def crypto
|
12
|
+
response = get("crypto")
|
13
|
+
|
14
|
+
api_errors = errors(response)
|
15
|
+
return api_errors if api_errors.present?
|
16
|
+
|
17
|
+
response.body[:crypto].map do |crypto|
|
18
|
+
LunchMoney::Crypto.new(**crypto)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
sig do
|
23
|
+
params(
|
24
|
+
crypto_id: Integer,
|
25
|
+
name: T.nilable(String),
|
26
|
+
display_name: T.nilable(String),
|
27
|
+
institution_name: T.nilable(String),
|
28
|
+
balance: T.nilable(String),
|
29
|
+
currency: T.nilable(String),
|
30
|
+
).returns(T.any(LunchMoney::CryptoBase, LunchMoney::Errors))
|
31
|
+
end
|
32
|
+
def update_crypto(crypto_id, name: nil, display_name: nil, institution_name: nil, balance: nil, currency: nil)
|
33
|
+
params = clean_params({
|
34
|
+
name:,
|
35
|
+
display_name:,
|
36
|
+
institution_name:,
|
37
|
+
balance:,
|
38
|
+
currency:,
|
39
|
+
})
|
40
|
+
|
41
|
+
response = put("crypto/manual/#{crypto_id}", params)
|
42
|
+
|
43
|
+
api_errors = errors(response)
|
44
|
+
return api_errors if api_errors.present?
|
45
|
+
|
46
|
+
LunchMoney::CryptoBase.new(**response.body)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# Base data object for the objects returned and used when calling the LunchMoney API
|
6
|
+
class DataObject
|
7
|
+
sig { params(symbolize_keys: T::Boolean).returns(T::Hash[String, T.untyped]) }
|
8
|
+
def serialize(symbolize_keys: false)
|
9
|
+
ivars = instance_variables
|
10
|
+
|
11
|
+
output = {}
|
12
|
+
|
13
|
+
ivars.each do |ivar|
|
14
|
+
key = ivar.to_s.gsub("@", "")
|
15
|
+
key = key.to_sym if symbolize_keys
|
16
|
+
|
17
|
+
value = instance_variable_get(ivar)
|
18
|
+
|
19
|
+
output[key] = value
|
20
|
+
end
|
21
|
+
|
22
|
+
output
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# This class is used to represent errors returned directly from the LunchMoney API
|
6
|
+
class Errors
|
7
|
+
sig { returns(T::Array[String]) }
|
8
|
+
attr_accessor :messages
|
9
|
+
|
10
|
+
sig { params(message: T.nilable(String)).void }
|
11
|
+
def initialize(message: nil)
|
12
|
+
@messages = T.let([], T::Array[String])
|
13
|
+
|
14
|
+
@messages << message unless message.nil?
|
15
|
+
end
|
16
|
+
|
17
|
+
delegate :[], :<<, :each, :to_a, :first, :last, :empty?, :present?, to: :@messages
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# Base exception class for exceptions raised by this gem
|
6
|
+
class Exception < StandardError; end
|
7
|
+
|
8
|
+
# Exception raised when an API Key appears to be invalid
|
9
|
+
class InvalidApiKey < Exception; end
|
10
|
+
|
11
|
+
# Exception raised when an object attribute is invalid
|
12
|
+
class InvalidObjectAttribute < Exception; end
|
13
|
+
|
14
|
+
# Exception raised when a query parameter is invalid
|
15
|
+
class InvalidQueryParameter < Exception; end
|
16
|
+
|
17
|
+
# Exception raised when an essential argument is missing
|
18
|
+
class MissingArgument < Exception; end
|
19
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# https://lunchmoney.dev/#plaid-accounts-object
|
6
|
+
class PlaidAccount < LunchMoney::DataObject
|
7
|
+
sig { returns(Integer) }
|
8
|
+
attr_accessor :id
|
9
|
+
|
10
|
+
sig { returns(String) }
|
11
|
+
attr_accessor :date_linked,
|
12
|
+
:name,
|
13
|
+
:type,
|
14
|
+
:mask,
|
15
|
+
:institution_name,
|
16
|
+
:status,
|
17
|
+
:balance,
|
18
|
+
:currency,
|
19
|
+
:balance_last_update,
|
20
|
+
:display_name,
|
21
|
+
:plaid_last_successful_update
|
22
|
+
|
23
|
+
sig { returns(T.nilable(String)) }
|
24
|
+
attr_accessor :subtype, :import_start_date, :last_fetch, :last_import
|
25
|
+
|
26
|
+
sig { returns(T.nilable(Integer)) }
|
27
|
+
attr_accessor :limit
|
28
|
+
|
29
|
+
sig do
|
30
|
+
params(
|
31
|
+
date_linked: String,
|
32
|
+
name: String,
|
33
|
+
type: String,
|
34
|
+
mask: String,
|
35
|
+
institution_name: String,
|
36
|
+
status: String,
|
37
|
+
balance: String,
|
38
|
+
currency: String,
|
39
|
+
balance_last_update: String,
|
40
|
+
display_name: String,
|
41
|
+
id: Integer,
|
42
|
+
plaid_last_successful_update: String,
|
43
|
+
last_import: T.nilable(String),
|
44
|
+
limit: T.nilable(Integer),
|
45
|
+
subtype: T.nilable(String),
|
46
|
+
import_start_date: T.nilable(String),
|
47
|
+
last_fetch: T.nilable(String),
|
48
|
+
).void
|
49
|
+
end
|
50
|
+
def initialize(date_linked:, name:, type:, mask:, institution_name:, status:, balance:, currency:,
|
51
|
+
balance_last_update:, display_name:, id:, plaid_last_successful_update:, last_import: nil, limit: nil,
|
52
|
+
subtype: nil, import_start_date: nil, last_fetch: nil)
|
53
|
+
super()
|
54
|
+
@id = id
|
55
|
+
@date_linked = date_linked
|
56
|
+
@name = name
|
57
|
+
@display_name = display_name
|
58
|
+
@type = type
|
59
|
+
@subtype = subtype
|
60
|
+
@mask = mask
|
61
|
+
@institution_name = institution_name
|
62
|
+
@status = status
|
63
|
+
@limit = limit
|
64
|
+
@balance = balance
|
65
|
+
@currency = currency
|
66
|
+
@balance_last_update = balance_last_update
|
67
|
+
@import_start_date = import_start_date
|
68
|
+
@last_import = last_import
|
69
|
+
@last_fetch = last_fetch
|
70
|
+
@plaid_last_successful_update = plaid_last_successful_update
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "plaid_account"
|
5
|
+
|
6
|
+
module LunchMoney
|
7
|
+
# https://lunchmoney.dev/#plaid-accounts
|
8
|
+
class PlaidAccountCalls < ApiCall
|
9
|
+
sig { returns(T.any(T::Array[LunchMoney::PlaidAccount], LunchMoney::Errors)) }
|
10
|
+
def plaid_accounts
|
11
|
+
response = get("plaid_accounts")
|
12
|
+
|
13
|
+
api_errors = errors(response)
|
14
|
+
return api_errors if api_errors.present?
|
15
|
+
|
16
|
+
response.body[:plaid_accounts].map do |plaid_account|
|
17
|
+
LunchMoney::PlaidAccount.new(**plaid_account)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
sig do
|
22
|
+
params(
|
23
|
+
start_date: T.nilable(String),
|
24
|
+
end_date: T.nilable(String),
|
25
|
+
plaid_account_id: T.nilable(Integer),
|
26
|
+
).returns(T.any(T::Boolean, LunchMoney::Errors))
|
27
|
+
end
|
28
|
+
def plaid_accounts_fetch(start_date: nil, end_date: nil, plaid_account_id: nil)
|
29
|
+
params = clean_params({ start_date:, end_date:, plaid_account_id: })
|
30
|
+
response = post("plaid_accounts/fetch", params)
|
31
|
+
|
32
|
+
api_errors = errors(response)
|
33
|
+
return api_errors if api_errors.present?
|
34
|
+
|
35
|
+
response.body
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# https://lunchmoney.dev/#recurring-expenses-object
|
6
|
+
class RecurringExpense < RecurringExpenseBase
|
7
|
+
sig { returns(Integer) }
|
8
|
+
attr_accessor :id
|
9
|
+
|
10
|
+
sig { returns(T.nilable(String)) }
|
11
|
+
attr_accessor :start_date, :end_date, :description, :original_name
|
12
|
+
|
13
|
+
sig { returns(String) }
|
14
|
+
attr_accessor :cadence, :billing_date, :type, :source, :created_at
|
15
|
+
|
16
|
+
sig { returns(T.nilable(Integer)) }
|
17
|
+
attr_accessor :plaid_account_id, :asset_id, :transaction_id, :category_id
|
18
|
+
|
19
|
+
sig do
|
20
|
+
params(
|
21
|
+
cadence: String,
|
22
|
+
payee: String,
|
23
|
+
amount: String,
|
24
|
+
currency: String,
|
25
|
+
billing_date: String,
|
26
|
+
type: String,
|
27
|
+
source: String,
|
28
|
+
id: Integer,
|
29
|
+
created_at: String,
|
30
|
+
category_id: T.nilable(Integer),
|
31
|
+
start_date: T.nilable(String),
|
32
|
+
end_date: T.nilable(String),
|
33
|
+
description: T.nilable(String),
|
34
|
+
original_name: T.nilable(String),
|
35
|
+
plaid_account_id: T.nilable(Integer),
|
36
|
+
asset_id: T.nilable(Integer),
|
37
|
+
transaction_id: T.nilable(Integer),
|
38
|
+
to_base: T.nilable(Number),
|
39
|
+
).void
|
40
|
+
end
|
41
|
+
def initialize(cadence:, payee:, amount:, currency:, billing_date:, type:, source:, id:, created_at:,
|
42
|
+
category_id: nil, start_date: nil, end_date: nil, description: nil, original_name: nil, plaid_account_id: nil,
|
43
|
+
asset_id: nil, transaction_id: nil, to_base: nil)
|
44
|
+
super(payee:, amount:, currency:, to_base:)
|
45
|
+
@cadence = cadence
|
46
|
+
@payee = payee
|
47
|
+
@amount = amount
|
48
|
+
@currency = currency
|
49
|
+
@billing_date = billing_date
|
50
|
+
@type = type
|
51
|
+
@source = source
|
52
|
+
@id = id
|
53
|
+
@category_id = category_id
|
54
|
+
@created_at = created_at
|
55
|
+
@start_date = start_date
|
56
|
+
@end_date = end_date
|
57
|
+
@description = description
|
58
|
+
@original_name = original_name
|
59
|
+
@plaid_account_id = plaid_account_id
|
60
|
+
@asset_id = asset_id
|
61
|
+
@transaction_id = transaction_id
|
62
|
+
@to_base = to_base
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# https://lunchmoney.dev/#recurring-expenses-object
|
6
|
+
class RecurringExpenseBase < LunchMoney::DataObject
|
7
|
+
sig { returns(String) }
|
8
|
+
attr_accessor :payee, :currency, :amount
|
9
|
+
|
10
|
+
sig { returns(T.nilable(Number)) }
|
11
|
+
attr_accessor :to_base
|
12
|
+
|
13
|
+
sig do
|
14
|
+
params(
|
15
|
+
payee: String,
|
16
|
+
amount: String,
|
17
|
+
currency: String,
|
18
|
+
to_base: T.nilable(Number),
|
19
|
+
).void
|
20
|
+
end
|
21
|
+
def initialize(payee:, amount:, currency:, to_base:)
|
22
|
+
super()
|
23
|
+
@payee = payee
|
24
|
+
@amount = amount
|
25
|
+
@currency = currency
|
26
|
+
@to_base = to_base
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "recurring_expense/recurring_expense_base"
|
5
|
+
require_relative "recurring_expense/recurring_expense"
|
6
|
+
|
7
|
+
module LunchMoney
|
8
|
+
# https://lunchmoney.dev/#recurring-expenses
|
9
|
+
class RecurringExpenseCalls < ApiCall
|
10
|
+
sig do
|
11
|
+
params(
|
12
|
+
start_date: T.nilable(String),
|
13
|
+
end_date: T.nilable(String),
|
14
|
+
).returns(T.any(T::Array[LunchMoney::RecurringExpense], LunchMoney::Errors))
|
15
|
+
end
|
16
|
+
def recurring_expenses(start_date: nil, end_date: nil)
|
17
|
+
params = clean_params({ start_date:, end_date: })
|
18
|
+
response = get("recurring_expenses", query_params: params)
|
19
|
+
|
20
|
+
api_errors = errors(response)
|
21
|
+
return api_errors if api_errors.present?
|
22
|
+
|
23
|
+
response.body[:recurring_expenses].map do |recurring_expense|
|
24
|
+
LunchMoney::RecurringExpense.new(**recurring_expense)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# https://lunchmoney.dev/#tags-object
|
6
|
+
class Tag < TagBase
|
7
|
+
sig { returns(T.nilable(String)) }
|
8
|
+
attr_accessor :description
|
9
|
+
|
10
|
+
sig { returns(T::Boolean) }
|
11
|
+
attr_accessor :archived
|
12
|
+
|
13
|
+
sig { params(id: Integer, name: String, archived: T::Boolean, description: T.nilable(String)).void }
|
14
|
+
def initialize(id:, name:, archived:, description: nil)
|
15
|
+
super(id:, name:)
|
16
|
+
@archived = archived
|
17
|
+
@description = description
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# https://lunchmoney.dev/#tags-object without some fields. This is used within field returns of other objects like
|
6
|
+
# field returns of other objects like transactions
|
7
|
+
class TagBase < LunchMoney::DataObject
|
8
|
+
sig { returns(Integer) }
|
9
|
+
attr_accessor :id
|
10
|
+
|
11
|
+
sig { returns(String) }
|
12
|
+
attr_accessor :name
|
13
|
+
|
14
|
+
sig { params(id: Integer, name: String).void }
|
15
|
+
def initialize(id:, name:)
|
16
|
+
super()
|
17
|
+
@id = id
|
18
|
+
@name = name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "tag/tag_base"
|
5
|
+
require_relative "tag/tag"
|
6
|
+
|
7
|
+
module LunchMoney
|
8
|
+
# https://lunchmoney.dev/#tags
|
9
|
+
class TagCalls < ApiCall
|
10
|
+
sig { returns(T.any(T::Array[LunchMoney::Tag], LunchMoney::Errors)) }
|
11
|
+
def tags
|
12
|
+
response = get("tags")
|
13
|
+
|
14
|
+
api_errors = errors(response)
|
15
|
+
return api_errors if api_errors.present?
|
16
|
+
|
17
|
+
response.body.map { |tag| LunchMoney::Tag.new(**tag) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# Slimmed down version of https://lunchmoney.dev/#transaction-object used in the
|
6
|
+
# `children` field of a transaction object with an additional `formatted_date`` field
|
7
|
+
class ChildTransaction < TransactionBase
|
8
|
+
sig { returns(String) }
|
9
|
+
attr_accessor :formatted_date
|
10
|
+
|
11
|
+
sig do
|
12
|
+
params(
|
13
|
+
id: Integer,
|
14
|
+
date: String,
|
15
|
+
amount: String,
|
16
|
+
currency: String,
|
17
|
+
to_base: Number,
|
18
|
+
payee: String,
|
19
|
+
formatted_date: String,
|
20
|
+
notes: T.nilable(String),
|
21
|
+
asset_id: T.nilable(Integer),
|
22
|
+
plaid_account_id: T.nilable(Integer),
|
23
|
+
).void
|
24
|
+
end
|
25
|
+
def initialize(id:, date:, amount:, currency:, to_base:, payee:, formatted_date:, notes: nil, asset_id: nil,
|
26
|
+
plaid_account_id: nil)
|
27
|
+
super(id:, date:, amount:, currency:, to_base:, payee:, notes:, asset_id:, plaid_account_id:)
|
28
|
+
@formatted_date = formatted_date
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# Object used to split a transaction when updating https://lunchmoney.dev/#update-transaction
|
6
|
+
class Split < TransactionModificationBase
|
7
|
+
sig { returns(T.any(Number, String)) }
|
8
|
+
attr_accessor :amount
|
9
|
+
|
10
|
+
sig do
|
11
|
+
params(
|
12
|
+
amount: T.any(Number, String),
|
13
|
+
payee: T.nilable(String),
|
14
|
+
date: T.nilable(String),
|
15
|
+
category_id: T.nilable(Integer),
|
16
|
+
notes: T.nilable(String),
|
17
|
+
).void
|
18
|
+
end
|
19
|
+
def initialize(amount:, payee: nil, date: nil, category_id: nil, notes: nil)
|
20
|
+
super(payee:, date:, category_id:, notes:)
|
21
|
+
@amount = amount
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module LunchMoney
|
5
|
+
# https://lunchmoney.dev/#transaction-object
|
6
|
+
class Transaction < TransactionBase
|
7
|
+
sig { returns(T.nilable(Integer)) }
|
8
|
+
attr_accessor :category_id,
|
9
|
+
:category_group_id,
|
10
|
+
:recurring_id,
|
11
|
+
:parent_id,
|
12
|
+
:group_id,
|
13
|
+
:external_id
|
14
|
+
|
15
|
+
sig { returns(String) }
|
16
|
+
attr_accessor :created_at,
|
17
|
+
:updated_at,
|
18
|
+
:status,
|
19
|
+
:source,
|
20
|
+
:display_name,
|
21
|
+
:account_display_name
|
22
|
+
|
23
|
+
sig { returns(T.nilable(String)) }
|
24
|
+
attr_accessor :category_name,
|
25
|
+
:category_group_name,
|
26
|
+
:original_name,
|
27
|
+
:recurring_payee,
|
28
|
+
:recurring_description,
|
29
|
+
:recurring_cadence,
|
30
|
+
:recurring_type,
|
31
|
+
:recurring_amount,
|
32
|
+
:recurring_currency,
|
33
|
+
:asset_institution_name,
|
34
|
+
:asset_name,
|
35
|
+
:asset_display_name,
|
36
|
+
:asset_status,
|
37
|
+
:plaid_account_name,
|
38
|
+
:plaid_account_mask,
|
39
|
+
:institution_name,
|
40
|
+
:plaid_account_display_name,
|
41
|
+
:plaid_metadata,
|
42
|
+
:display_notes
|
43
|
+
|
44
|
+
sig { returns(T::Boolean) }
|
45
|
+
attr_accessor :is_income, :exclude_from_budget, :exclude_from_totals, :is_pending, :has_children, :is_group
|
46
|
+
|
47
|
+
sig { returns(T::Array[LunchMoney::TagBase]) }
|
48
|
+
attr_accessor :tags
|
49
|
+
|
50
|
+
sig { returns(T.nilable(T::Array[LunchMoney::ChildTransaction])) }
|
51
|
+
attr_accessor :children
|
52
|
+
|
53
|
+
sig do
|
54
|
+
params(
|
55
|
+
id: Integer,
|
56
|
+
date: String,
|
57
|
+
amount: String,
|
58
|
+
currency: String,
|
59
|
+
to_base: Number,
|
60
|
+
payee: String,
|
61
|
+
is_income: T::Boolean,
|
62
|
+
exclude_from_budget: T::Boolean,
|
63
|
+
exclude_from_totals: T::Boolean,
|
64
|
+
created_at: String,
|
65
|
+
updated_at: String,
|
66
|
+
status: String,
|
67
|
+
is_pending: T::Boolean,
|
68
|
+
has_children: T::Boolean,
|
69
|
+
is_group: T::Boolean,
|
70
|
+
source: String,
|
71
|
+
display_name: String,
|
72
|
+
account_display_name: String,
|
73
|
+
tags: T::Array[LunchMoney::TagBase],
|
74
|
+
category_id: T.nilable(Integer),
|
75
|
+
category_name: T.nilable(String),
|
76
|
+
category_group_id: T.nilable(Integer),
|
77
|
+
category_group_name: T.nilable(String),
|
78
|
+
notes: T.nilable(String),
|
79
|
+
original_name: T.nilable(String),
|
80
|
+
recurring_id: T.nilable(Integer),
|
81
|
+
recurring_payee: T.nilable(String),
|
82
|
+
recurring_description: T.nilable(String),
|
83
|
+
recurring_cadence: T.nilable(String),
|
84
|
+
recurring_type: T.nilable(String),
|
85
|
+
recurring_amount: T.nilable(String),
|
86
|
+
recurring_currency: T.nilable(String),
|
87
|
+
parent_id: T.nilable(Integer),
|
88
|
+
group_id: T.nilable(Integer),
|
89
|
+
asset_id: T.nilable(Integer),
|
90
|
+
asset_institution_name: T.nilable(String),
|
91
|
+
asset_name: T.nilable(String),
|
92
|
+
asset_display_name: T.nilable(String),
|
93
|
+
asset_status: T.nilable(String),
|
94
|
+
plaid_account_id: T.nilable(Integer),
|
95
|
+
plaid_account_name: T.nilable(String),
|
96
|
+
plaid_account_mask: T.nilable(String),
|
97
|
+
institution_name: T.nilable(String),
|
98
|
+
plaid_account_display_name: T.nilable(String),
|
99
|
+
plaid_metadata: T.nilable(String),
|
100
|
+
display_notes: T.nilable(String),
|
101
|
+
external_id: T.nilable(Integer),
|
102
|
+
children: T.nilable(T::Array[LunchMoney::ChildTransaction]),
|
103
|
+
).void
|
104
|
+
end
|
105
|
+
def initialize(id:, date:, amount:, currency:, to_base:, payee:, is_income:, exclude_from_budget:,
|
106
|
+
exclude_from_totals:, created_at:, updated_at:, status:, is_pending:, has_children:, is_group:, source:,
|
107
|
+
display_name:, account_display_name:, tags:, category_id: nil, category_name: nil, category_group_id: nil,
|
108
|
+
category_group_name: nil, notes: nil, original_name: nil, recurring_id: nil, recurring_payee: nil,
|
109
|
+
recurring_description: nil, recurring_cadence: nil, recurring_type: nil, recurring_amount: nil,
|
110
|
+
recurring_currency: nil, parent_id: nil, group_id: nil, asset_id: nil, asset_institution_name: nil,
|
111
|
+
asset_name: nil, asset_display_name: nil, asset_status: nil, plaid_account_id: nil, plaid_account_name: nil,
|
112
|
+
plaid_account_mask: nil, institution_name: nil, plaid_account_display_name: nil, plaid_metadata: nil,
|
113
|
+
display_notes: nil, external_id: nil, children: nil)
|
114
|
+
super(id:, date:, amount:, currency:, to_base:, payee:, notes:, asset_id:, plaid_account_id:)
|
115
|
+
@is_income = is_income
|
116
|
+
@exclude_from_budget = exclude_from_budget
|
117
|
+
@exclude_from_totals = exclude_from_totals
|
118
|
+
@created_at = created_at
|
119
|
+
@updated_at = updated_at
|
120
|
+
@status = status
|
121
|
+
@is_pending = is_pending
|
122
|
+
@has_children = has_children
|
123
|
+
@is_group = is_group
|
124
|
+
@source = source
|
125
|
+
@display_name = display_name
|
126
|
+
@account_display_name = account_display_name
|
127
|
+
@tags = tags
|
128
|
+
@category_id = category_id
|
129
|
+
@category_name = category_name
|
130
|
+
@category_group_id = category_group_id
|
131
|
+
@category_group_name = category_group_name
|
132
|
+
@original_name = original_name
|
133
|
+
@recurring_id = recurring_id
|
134
|
+
@recurring_payee = recurring_payee
|
135
|
+
@recurring_description = recurring_description
|
136
|
+
@recurring_cadence = recurring_cadence
|
137
|
+
@recurring_type = recurring_type
|
138
|
+
@recurring_amount = recurring_amount
|
139
|
+
@recurring_currency = recurring_currency
|
140
|
+
@parent_id = parent_id
|
141
|
+
@group_id = group_id
|
142
|
+
@asset_institution_name = asset_institution_name
|
143
|
+
@asset_name = asset_name
|
144
|
+
@asset_display_name = asset_display_name
|
145
|
+
@asset_status = asset_status
|
146
|
+
@plaid_account_name = plaid_account_name
|
147
|
+
@plaid_account_mask = plaid_account_mask
|
148
|
+
@institution_name = institution_name
|
149
|
+
@plaid_account_display_name = plaid_account_display_name
|
150
|
+
@plaid_metadata = plaid_metadata
|
151
|
+
@display_notes = display_notes
|
152
|
+
@children = children
|
153
|
+
@external_id = external_id
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|