async-firefly 1.0.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/lib/async/firefly/about.rb +79 -0
  3. data/lib/async/firefly/accounts.rb +129 -0
  4. data/lib/async/firefly/attachments.rb +53 -0
  5. data/lib/async/firefly/autocomplete.rb +435 -0
  6. data/lib/async/firefly/available_budgets.rb +59 -0
  7. data/lib/async/firefly/bills.rb +107 -0
  8. data/lib/async/firefly/budgets.rb +165 -0
  9. data/lib/async/firefly/categories.rb +63 -0
  10. data/lib/async/firefly/charts.rb +73 -0
  11. data/lib/async/firefly/client.rb +89 -0
  12. data/lib/async/firefly/configurations.rb +62 -0
  13. data/lib/async/firefly/currencies.rb +71 -0
  14. data/lib/async/firefly/data.rb +37 -0
  15. data/lib/async/firefly/error.rb +57 -0
  16. data/lib/async/firefly/escape.rb +9 -0
  17. data/lib/async/firefly/exchange_rates.rb +77 -0
  18. data/lib/async/firefly/insight.rb +185 -0
  19. data/lib/async/firefly/links.rb +69 -0
  20. data/lib/async/firefly/nested.rb +75 -0
  21. data/lib/async/firefly/object_groups.rb +33 -0
  22. data/lib/async/firefly/page.rb +139 -0
  23. data/lib/async/firefly/piggy_banks.rb +153 -0
  24. data/lib/async/firefly/preferences.rb +58 -0
  25. data/lib/async/firefly/recurrences.rb +169 -0
  26. data/lib/async/firefly/redacted.rb +32 -0
  27. data/lib/async/firefly/representation.rb +99 -0
  28. data/lib/async/firefly/rule_groups.rb +55 -0
  29. data/lib/async/firefly/rules.rb +105 -0
  30. data/lib/async/firefly/search.rb +40 -0
  31. data/lib/async/firefly/submit.rb +139 -0
  32. data/lib/async/firefly/summary.rb +45 -0
  33. data/lib/async/firefly/sums.rb +17 -0
  34. data/lib/async/firefly/tags.rb +57 -0
  35. data/lib/async/firefly/transactions.rb +231 -0
  36. data/lib/async/firefly/user_groups.rb +49 -0
  37. data/lib/async/firefly/users.rb +35 -0
  38. data/lib/async/firefly/version.rb +5 -0
  39. data/lib/async/firefly/webhooks.rb +101 -0
  40. data/lib/async/firefly/wrapper.rb +65 -0
  41. data/lib/async/firefly.rb +2 -0
  42. data/license.md +21 -0
  43. data/readme.md +498 -0
  44. metadata +110 -0
@@ -0,0 +1,153 @@
1
+ require_relative "page"
2
+
3
+ module Async
4
+ module Firefly
5
+ class PiggyBankAccount < Representation
6
+ def account_id = self.data[:account_id]
7
+
8
+ def name = self.data[:name]
9
+
10
+ def current_amount = self.data[:current_amount]
11
+
12
+ def pc_current_amount = self.data[:pc_current_amount]
13
+ end
14
+
15
+ class PiggyBank < Representation
16
+ def created_at = self.attributes[:created_at]
17
+
18
+ def updated_at = self.attributes[:updated_at]
19
+
20
+ def name = self.attributes[:name]
21
+
22
+ def percentage = self.attributes[:percentage]
23
+
24
+ def start_date = self.attributes[:start_date]
25
+
26
+ def target_date = self.attributes[:target_date]
27
+
28
+ def order = self.attributes[:order]
29
+
30
+ def active = self.attributes[:active]
31
+
32
+ def notes = self.attributes[:notes]
33
+
34
+ def object_group_id = self.attributes[:object_group_id]
35
+
36
+ def object_group_order = self.attributes[:object_group_order]
37
+
38
+ def object_group_title = self.attributes[:object_group_title]
39
+
40
+ def accounts = self.nested_list(PiggyBankAccount, self.attributes[:accounts])
41
+
42
+ def object_has_currency_setting = self.attributes[:object_has_currency_setting]
43
+
44
+ def currency_id = self.attributes[:currency_id]
45
+
46
+ def currency_name = self.attributes[:currency_name]
47
+
48
+ def currency_code = self.attributes[:currency_code]
49
+
50
+ def currency_symbol = self.attributes[:currency_symbol]
51
+
52
+ def currency_decimal_places = self.attributes[:currency_decimal_places]
53
+
54
+ def primary_currency_id = self.attributes[:primary_currency_id]
55
+
56
+ def primary_currency_name = self.attributes[:primary_currency_name]
57
+
58
+ def primary_currency_code = self.attributes[:primary_currency_code]
59
+
60
+ def primary_currency_symbol = self.attributes[:primary_currency_symbol]
61
+
62
+ def primary_currency_decimal_places = self.attributes[:primary_currency_decimal_places]
63
+
64
+ def target_amount = self.attributes[:target_amount]
65
+
66
+ def pc_target_amount = self.attributes[:pc_target_amount]
67
+
68
+ def current_amount = self.attributes[:current_amount]
69
+
70
+ def pc_current_amount = self.attributes[:pc_current_amount]
71
+
72
+ def left_to_save = self.attributes[:left_to_save]
73
+
74
+ def pc_left_to_save = self.attributes[:pc_left_to_save]
75
+
76
+ def save_per_month = self.attributes[:save_per_month]
77
+
78
+ def pc_save_per_month = self.attributes[:pc_save_per_month]
79
+
80
+ def active? = self.active == true
81
+
82
+ def events(**parameters) = Collection.for(@resource, "events", PiggyBankEventPage, **parameters)
83
+
84
+ def attachments(**parameters) = Collection.for(@resource, "attachments", NestedAttachmentPage, **parameters)
85
+
86
+ def linked_accounts(**parameters) = Collection.for(@resource, "accounts", PiggyBankLinkedAccountPage, **parameters)
87
+
88
+ def update(payload) = self.submit(PiggyBank, @resource, payload, method: :put)
89
+
90
+ def delete = self.discard(@resource)
91
+ end
92
+
93
+ class PiggyBankEvent < Representation
94
+ def created_at = self.attributes[:created_at]
95
+
96
+ def updated_at = self.attributes[:updated_at]
97
+
98
+ def amount = self.attributes[:amount]
99
+
100
+ def pc_amount = self.attributes[:pc_amount]
101
+
102
+ def object_has_currency_setting = self.attributes[:object_has_currency_setting]
103
+
104
+ def currency_id = self.attributes[:currency_id]
105
+
106
+ def currency_name = self.attributes[:currency_name]
107
+
108
+ def currency_code = self.attributes[:currency_code]
109
+
110
+ def currency_symbol = self.attributes[:currency_symbol]
111
+
112
+ def currency_decimal_places = self.attributes[:currency_decimal_places]
113
+
114
+ def primary_currency_id = self.attributes[:primary_currency_id]
115
+
116
+ def primary_currency_name = self.attributes[:primary_currency_name]
117
+
118
+ def primary_currency_code = self.attributes[:primary_currency_code]
119
+
120
+ def primary_currency_symbol = self.attributes[:primary_currency_symbol]
121
+
122
+ def primary_currency_decimal_places = self.attributes[:primary_currency_decimal_places]
123
+
124
+ def transaction_journal_id = self.attributes[:transaction_journal_id]
125
+
126
+ def transaction_group_id = self.attributes[:transaction_group_id]
127
+ end
128
+
129
+ class PiggyBankPage < Page
130
+ MEMBER = PiggyBank
131
+ end
132
+
133
+ class PiggyBankEventPage < Page
134
+ MEMBER = PiggyBankEvent
135
+
136
+ def member_resource(record) = @resource
137
+ end
138
+
139
+ class PiggyBankLinkedAccountPage < NestedPage
140
+ def member_class = Account
141
+
142
+ def collection = "accounts"
143
+ end
144
+
145
+ module PiggyBanks
146
+ def piggy_banks(**parameters) = Collection.for(self, "v1/piggy-banks", PiggyBankPage, **parameters)
147
+
148
+ def piggy_bank(id) = PiggyBank.new(self.with(path: "v1/piggy-banks/" + Firefly.escape(id)))
149
+
150
+ def create_piggy_bank(payload) = self.submit(PiggyBank, self.with(path: "v1/piggy-banks"), payload, identify: true)
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,58 @@
1
+ require_relative "page"
2
+
3
+ module Async
4
+ module Firefly
5
+ class Preference < Representation
6
+ def id
7
+ case self.value
8
+ in {data: {id: String | Integer => id}}
9
+ id
10
+ else
11
+ nil
12
+ end
13
+ end
14
+
15
+ def type
16
+ case self.value
17
+ in {data: {type: String => type}}
18
+ type
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ def attributes
25
+ case self.value
26
+ in {data: {attributes: Hash => attributes}}
27
+ attributes
28
+ else
29
+ {}
30
+ end
31
+ end
32
+
33
+ def created_at = self.attributes[:created_at]
34
+
35
+ def updated_at = self.attributes[:updated_at]
36
+
37
+ def name = self.attributes[:name]
38
+
39
+ def data = self.attributes[:data]
40
+
41
+ def update(payload) = self.submit(Preference, @resource, payload, method: :put)
42
+ end
43
+
44
+ class PreferencePage < Page
45
+ MEMBER = Preference
46
+
47
+ def member_path(record) = self.identifier(record, :attributes, :name)
48
+ end
49
+
50
+ module Preferences
51
+ def preferences(**parameters) = Collection.for(self, "v1/preferences", PreferencePage, **parameters)
52
+
53
+ def preference(name) = Preference.new(self.with(path: "v1/preferences/" + Firefly.escape(name)))
54
+
55
+ def create_preference(payload) = self.submit(Preference, self.with(path: "v1/preferences"), payload, identify: :name)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,169 @@
1
+ require_relative "page"
2
+
3
+ module Async
4
+ module Firefly
5
+ class RecurrenceRepetition < Representation
6
+ def id = self.value[:id]
7
+
8
+ def created_at = self.value[:created_at]
9
+
10
+ def updated_at = self.value[:updated_at]
11
+
12
+ def type = self.value[:type]
13
+
14
+ def moment = self.value[:moment]
15
+
16
+ def skip = self.value[:skip]
17
+
18
+ def weekend = self.value[:weekend]
19
+
20
+ def description = self.value[:description]
21
+
22
+ def occurrences = self.value[:occurrences]
23
+ end
24
+
25
+ class RecurrenceTransaction < Representation
26
+ def id = self.value[:id]
27
+
28
+ def description = self.value[:description]
29
+
30
+ def object_has_currency_setting = self.value[:object_has_currency_setting]
31
+
32
+ def currency_id = self.value[:currency_id]
33
+
34
+ def currency_name = self.value[:currency_name]
35
+
36
+ def currency_code = self.value[:currency_code]
37
+
38
+ def currency_symbol = self.value[:currency_symbol]
39
+
40
+ def currency_decimal_places = self.value[:currency_decimal_places]
41
+
42
+ def primary_currency_id = self.value[:primary_currency_id]
43
+
44
+ def primary_currency_name = self.value[:primary_currency_name]
45
+
46
+ def primary_currency_code = self.value[:primary_currency_code]
47
+
48
+ def primary_currency_symbol = self.value[:primary_currency_symbol]
49
+
50
+ def primary_currency_decimal_places = self.value[:primary_currency_decimal_places]
51
+
52
+ def amount = self.value[:amount]
53
+
54
+ def pc_amount = self.value[:pc_amount]
55
+
56
+ def foreign_amount = self.value[:foreign_amount]
57
+
58
+ def pc_foreign_amount = self.value[:pc_foreign_amount]
59
+
60
+ def foreign_currency_id = self.value[:foreign_currency_id]
61
+
62
+ def foreign_currency_name = self.value[:foreign_currency_name]
63
+
64
+ def foreign_currency_code = self.value[:foreign_currency_code]
65
+
66
+ def foreign_currency_symbol = self.value[:foreign_currency_symbol]
67
+
68
+ def foreign_currency_decimal_places = self.value[:foreign_currency_decimal_places]
69
+
70
+ def budget_id = self.value[:budget_id]
71
+
72
+ def budget_name = self.value[:budget_name]
73
+
74
+ def category_id = self.value[:category_id]
75
+
76
+ def category_name = self.value[:category_name]
77
+
78
+ def source_id = self.value[:source_id]
79
+
80
+ def source_name = self.value[:source_name]
81
+
82
+ def source_iban = self.value[:source_iban]
83
+
84
+ def source_type = self.value[:source_type]
85
+
86
+ def destination_id = self.value[:destination_id]
87
+
88
+ def destination_name = self.value[:destination_name]
89
+
90
+ def destination_iban = self.value[:destination_iban]
91
+
92
+ def destination_type = self.value[:destination_type]
93
+
94
+ def tags = self.value[:tags]
95
+
96
+ def piggy_bank_id = self.value[:piggy_bank_id]
97
+
98
+ def piggy_bank_name = self.value[:piggy_bank_name]
99
+
100
+ def subscription_id = self.value[:subscription_id]
101
+
102
+ def subscription_name = self.value[:subscription_name]
103
+ end
104
+
105
+ class Recurrence < Representation
106
+ def created_at = self.attributes[:created_at]
107
+
108
+ def updated_at = self.attributes[:updated_at]
109
+
110
+ def type = self.attributes[:type]
111
+
112
+ def title = self.attributes[:title]
113
+
114
+ def description = self.attributes[:description]
115
+
116
+ def first_date = self.attributes[:first_date]
117
+
118
+ def latest_date = self.attributes[:latest_date]
119
+
120
+ def repeat_until = self.attributes[:repeat_until]
121
+
122
+ def apply_rules = self.attributes[:apply_rules]
123
+
124
+ def active = self.attributes[:active]
125
+
126
+ def nr_of_repetitions = self.attributes[:nr_of_repetitions]
127
+
128
+ def notes = self.attributes[:notes]
129
+
130
+ def repetitions = self.nested_list(RecurrenceRepetition, self.attributes[:repetitions])
131
+
132
+ def transactions = self.nested_list(RecurrenceTransaction, self.attributes[:transactions])
133
+
134
+ def active? = self.active == true
135
+
136
+ def transaction_history(**parameters) = Collection.for(@resource, "transactions", RecurrenceTransactionPage, **parameters)
137
+
138
+ def fire(**parameters) = self.submit(RecurrenceTriggerPage, @resource.with(path: "trigger", parameters: parameters), identify: nil)
139
+
140
+ def update(payload) = self.submit(Recurrence, @resource, payload, method: :put)
141
+
142
+ def delete = self.discard(@resource)
143
+ end
144
+
145
+ class RecurrencePage < Page
146
+ MEMBER = Recurrence
147
+ end
148
+
149
+ class RecurrenceTransactionPage < Page
150
+ def member_class = Transaction
151
+
152
+ def member_path(record) = "../../../transactions/" + self.identifier(record, :id)
153
+ end
154
+
155
+ class RecurrenceTriggerPage < Page
156
+ def member_class = Transaction
157
+
158
+ def member_path(record) = "../../../transactions/" + self.identifier(record, :id)
159
+ end
160
+
161
+ module Recurrences
162
+ def recurrences(**parameters) = Collection.for(self, "v1/recurrences", RecurrencePage, **parameters)
163
+
164
+ def recurrence(id) = Recurrence.new(self.with(path: "v1/recurrences/" + Firefly.escape(id)))
165
+
166
+ def create_recurrence(payload) = self.submit(Recurrence, self.with(path: "v1/recurrences"), payload, identify: true)
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,32 @@
1
+ module Async
2
+ module Firefly
3
+ module Redacted
4
+ SECRET = [
5
+ :access_token,
6
+ :client_secret,
7
+ :code_verifier,
8
+ :password,
9
+ :refresh_token,
10
+ :secret,
11
+ :token,
12
+ ].freeze
13
+
14
+ REDACTED = "[redacted]"
15
+
16
+ def self.redact(value)
17
+ case value
18
+ when Hash
19
+ value.to_h{|key, nested| SECRET.include?(key) ? [key, REDACTED] : [key, self.redact(nested)]}
20
+ when Array
21
+ value.map{|each| self.redact(each)}
22
+ else
23
+ value
24
+ end
25
+ end
26
+
27
+ def inspect
28
+ "\#<" + self.class.to_s + " " + @resource.path.to_s.inspect + " value=" + Redacted.redact(@value).inspect + ">"
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,99 @@
1
+ require "async/rest/representation"
2
+
3
+ require_relative "escape"
4
+ require_relative "redacted"
5
+ require_relative "submit"
6
+ require_relative "wrapper"
7
+
8
+ module Async
9
+ module Firefly
10
+ class Representation < Async::REST::Representation[Wrapper]
11
+ include Redacted
12
+ include Submit
13
+
14
+ def self.schema = self.name.to_s.split("::").last
15
+
16
+ def data
17
+ case self.value
18
+ in {data: Hash => data}
19
+ data
20
+ in {data: Array}
21
+ {}
22
+ in Hash => value
23
+ value
24
+ else
25
+ {}
26
+ end
27
+ end
28
+
29
+ def attributes
30
+ case self.data
31
+ in {attributes: Hash => attributes}
32
+ attributes
33
+ else
34
+ {}
35
+ end
36
+ end
37
+
38
+ def id = self.data[:id]
39
+
40
+ def type = self.data[:type]
41
+
42
+ def deconstruct_keys(keys)
43
+ case self.value
44
+ in Hash => value
45
+ value
46
+ else
47
+ {}
48
+ end
49
+ end
50
+
51
+ def deconstruct
52
+ case self.value
53
+ in Array => value
54
+ value
55
+ else
56
+ []
57
+ end
58
+ end
59
+
60
+ def cacheable?
61
+ cache_control = self.metadata["cache-control"]
62
+
63
+ if cache_control
64
+ !cache_control.no_store?
65
+ else
66
+ true
67
+ end
68
+ end
69
+
70
+ def nested(klass, value)
71
+ if value
72
+ klass.new(@resource, value: value, metadata: self.metadata)
73
+ end
74
+ end
75
+
76
+ def nested_list(klass, values)
77
+ Array(values).map do |value|
78
+ self.nested(klass, value)
79
+ end
80
+ end
81
+ end
82
+
83
+ class Download < Representation
84
+ WRAPPER = Content.new
85
+
86
+ def bytes = self.value
87
+
88
+ def media_type = self.metadata["content-type"]&.split(";")&.first
89
+
90
+ def content_disposition = self.metadata["content-disposition"]
91
+
92
+ def size = self.value.to_s.bytesize
93
+ end
94
+
95
+ class Upload < Representation
96
+ WRAPPER = Binary.new
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,55 @@
1
+ require_relative "page"
2
+
3
+ module Async
4
+ module Firefly
5
+ class RuleGroup < Representation
6
+ def created_at = self.attributes[:created_at]
7
+
8
+ def updated_at = self.attributes[:updated_at]
9
+
10
+ def title = self.attributes[:title]
11
+
12
+ def description = self.attributes[:description]
13
+
14
+ def order = self.attributes[:order]
15
+
16
+ def active = self.attributes[:active]
17
+
18
+ def active? = self.active == true
19
+
20
+ def rules(**parameters) = Collection.for(@resource, "rules", RuleGroupRulePage, **parameters)
21
+
22
+ def test(**parameters) = Collection.for(@resource, "test", RuleGroupTestPage, **parameters)
23
+
24
+ def fire(**parameters) = self.discard(@resource.with(path: "trigger", parameters: parameters), method: :post)
25
+
26
+ def update(payload) = self.submit(RuleGroup, @resource, payload, method: :put)
27
+
28
+ def delete = self.discard(@resource)
29
+ end
30
+
31
+ class RuleGroupPage < Page
32
+ MEMBER = RuleGroup
33
+ end
34
+
35
+ class RuleGroupRulePage < Page
36
+ def member_class = Rule
37
+
38
+ def member_path(record) = "../../../rules/" + self.identifier(record, :id)
39
+ end
40
+
41
+ class RuleGroupTestPage < Page
42
+ def member_class = Transaction
43
+
44
+ def member_path(record) = "../../../transactions/" + self.identifier(record, :id)
45
+ end
46
+
47
+ module RuleGroups
48
+ def rule_groups(**parameters) = Collection.for(self, "v1/rule-groups", RuleGroupPage, **parameters)
49
+
50
+ def rule_group(id) = RuleGroup.new(self.with(path: "v1/rule-groups/" + Firefly.escape(id)))
51
+
52
+ def create_rule_group(payload) = self.submit(RuleGroup, self.with(path: "v1/rule-groups"), payload, identify: true)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,105 @@
1
+ require_relative "page"
2
+
3
+ module Async
4
+ module Firefly
5
+ class RuleAction < Representation
6
+ def id = self.value[:id]
7
+
8
+ def created_at = self.value[:created_at]
9
+
10
+ def updated_at = self.value[:updated_at]
11
+
12
+ def type = self.value[:type]
13
+
14
+ def value_attribute = self.value[:value]
15
+
16
+ def order = self.value[:order]
17
+
18
+ def active = self.value[:active]
19
+
20
+ def stop_processing = self.value[:stop_processing]
21
+ end
22
+
23
+ class RuleTrigger < Representation
24
+ def id = self.value[:id]
25
+
26
+ def created_at = self.value[:created_at]
27
+
28
+ def updated_at = self.value[:updated_at]
29
+
30
+ def type = self.value[:type]
31
+
32
+ def value_attribute = self.value[:value]
33
+
34
+ def prohibited = self.value[:prohibited]
35
+
36
+ def order = self.value[:order]
37
+
38
+ def active = self.value[:active]
39
+
40
+ def stop_processing = self.value[:stop_processing]
41
+ end
42
+
43
+ class Rule < Representation
44
+ def created_at = self.attributes[:created_at]
45
+
46
+ def updated_at = self.attributes[:updated_at]
47
+
48
+ def title = self.attributes[:title]
49
+
50
+ def description = self.attributes[:description]
51
+
52
+ def rule_group_id = self.attributes[:rule_group_id]
53
+
54
+ def rule_group_title = self.attributes[:rule_group_title]
55
+
56
+ def order = self.attributes[:order]
57
+
58
+ def trigger = self.attributes[:trigger]
59
+
60
+ def active = self.attributes[:active]
61
+
62
+ def strict = self.attributes[:strict]
63
+
64
+ def stop_processing = self.attributes[:stop_processing]
65
+
66
+ def triggers = self.nested_list(RuleTrigger, self.attributes[:triggers])
67
+
68
+ def actions = self.nested_list(RuleAction, self.attributes[:actions])
69
+
70
+ def active? = self.active == true
71
+
72
+ def test(**parameters) = RuleTestPage.new(@resource.with(path: "test", parameters: parameters))
73
+
74
+ def fire(**parameters) = self.discard(@resource.with(path: "trigger", parameters: parameters), method: :post)
75
+
76
+ def update(payload) = self.submit(Rule, @resource, payload, method: :put)
77
+
78
+ def delete = self.discard(@resource)
79
+ end
80
+
81
+ class RulePage < Page
82
+ MEMBER = Rule
83
+ end
84
+
85
+ class RuleTestPage < Page
86
+ def member_class = Transaction
87
+
88
+ def member_path(record) = "../../../transactions/" + self.identifier(record, :id)
89
+ end
90
+
91
+ class RuleExpressionValidity < Representation
92
+ def valid = self.value[:valid]
93
+ end
94
+
95
+ module Rules
96
+ def rules(**parameters) = Collection.for(self, "v1/rules", RulePage, **parameters)
97
+
98
+ def rule(id) = Rule.new(self.with(path: "v1/rules/" + Firefly.escape(id)))
99
+
100
+ def create_rule(payload) = self.submit(Rule, self.with(path: "v1/rules"), payload, identify: true)
101
+
102
+ def validate_rule_expression(expression) = RuleExpressionValidity.new(self.with(path: "v1/rules/validate-expression", parameters: {expression: expression}))
103
+ end
104
+ end
105
+ end