cashctrl 0.0.1 → 0.1.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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +21 -0
  3. data/README.md +549 -14
  4. data/lib/cashctrl/client.rb +216 -0
  5. data/lib/cashctrl/collection.rb +77 -0
  6. data/lib/cashctrl/configuration.rb +30 -0
  7. data/lib/cashctrl/error.rb +27 -0
  8. data/lib/cashctrl/localized_string.rb +115 -0
  9. data/lib/cashctrl/models/account.rb +35 -0
  10. data/lib/cashctrl/models/article.rb +40 -0
  11. data/lib/cashctrl/models/asset.rb +32 -0
  12. data/lib/cashctrl/models/bank.rb +16 -0
  13. data/lib/cashctrl/models/category.rb +13 -0
  14. data/lib/cashctrl/models/certificate_document.rb +14 -0
  15. data/lib/cashctrl/models/certificate_template.rb +13 -0
  16. data/lib/cashctrl/models/cost_center.rb +15 -0
  17. data/lib/cashctrl/models/currency.rb +18 -0
  18. data/lib/cashctrl/models/custom_field.rb +18 -0
  19. data/lib/cashctrl/models/custom_field_group.rb +12 -0
  20. data/lib/cashctrl/models/file.rb +19 -0
  21. data/lib/cashctrl/models/fiscal_period.rb +16 -0
  22. data/lib/cashctrl/models/fiscal_period_task.rb +14 -0
  23. data/lib/cashctrl/models/history.rb +19 -0
  24. data/lib/cashctrl/models/insurance_type.rb +13 -0
  25. data/lib/cashctrl/models/journal.rb +56 -0
  26. data/lib/cashctrl/models/journal_import.rb +18 -0
  27. data/lib/cashctrl/models/journal_import_entry.rb +20 -0
  28. data/lib/cashctrl/models/loader.rb +52 -0
  29. data/lib/cashctrl/models/location.rb +22 -0
  30. data/lib/cashctrl/models/order.rb +46 -0
  31. data/lib/cashctrl/models/order_book_entry.rb +17 -0
  32. data/lib/cashctrl/models/order_document.rb +15 -0
  33. data/lib/cashctrl/models/order_layout.rb +18 -0
  34. data/lib/cashctrl/models/order_payment.rb +16 -0
  35. data/lib/cashctrl/models/person.rb +72 -0
  36. data/lib/cashctrl/models/report.rb +15 -0
  37. data/lib/cashctrl/models/report_collection.rb +13 -0
  38. data/lib/cashctrl/models/report_element.rb +16 -0
  39. data/lib/cashctrl/models/rounding.rb +15 -0
  40. data/lib/cashctrl/models/salary_book_entry.rb +16 -0
  41. data/lib/cashctrl/models/salary_certificate.rb +15 -0
  42. data/lib/cashctrl/models/salary_document.rb +15 -0
  43. data/lib/cashctrl/models/salary_field.rb +16 -0
  44. data/lib/cashctrl/models/salary_layout.rb +13 -0
  45. data/lib/cashctrl/models/salary_payment.rb +16 -0
  46. data/lib/cashctrl/models/salary_setting.rb +12 -0
  47. data/lib/cashctrl/models/salary_statement.rb +17 -0
  48. data/lib/cashctrl/models/salary_status.rb +12 -0
  49. data/lib/cashctrl/models/salary_sum.rb +14 -0
  50. data/lib/cashctrl/models/salary_template.rb +12 -0
  51. data/lib/cashctrl/models/salary_type.rb +14 -0
  52. data/lib/cashctrl/models/sequence_number.rb +13 -0
  53. data/lib/cashctrl/models/setting.rb +33 -0
  54. data/lib/cashctrl/models/tax.rb +17 -0
  55. data/lib/cashctrl/models/text.rb +13 -0
  56. data/lib/cashctrl/models/title.rb +13 -0
  57. data/lib/cashctrl/models/unit.rb +11 -0
  58. data/lib/cashctrl/resource.rb +190 -0
  59. data/lib/cashctrl/resources/account/bank.rb +24 -0
  60. data/lib/cashctrl/resources/account/category.rb +22 -0
  61. data/lib/cashctrl/resources/account/cost_center/category.rb +24 -0
  62. data/lib/cashctrl/resources/account/cost_center.rb +48 -0
  63. data/lib/cashctrl/resources/account.rb +54 -0
  64. data/lib/cashctrl/resources/base.rb +161 -0
  65. data/lib/cashctrl/resources/currency.rb +26 -0
  66. data/lib/cashctrl/resources/custom_field/group.rb +24 -0
  67. data/lib/cashctrl/resources/custom_field.rb +30 -0
  68. data/lib/cashctrl/resources/file/category.rb +22 -0
  69. data/lib/cashctrl/resources/file.rb +66 -0
  70. data/lib/cashctrl/resources/fiscal_period/task.rb +30 -0
  71. data/lib/cashctrl/resources/fiscal_period.rb +96 -0
  72. data/lib/cashctrl/resources/history.rb +44 -0
  73. data/lib/cashctrl/resources/inventory/article/category.rb +24 -0
  74. data/lib/cashctrl/resources/inventory/article.rb +34 -0
  75. data/lib/cashctrl/resources/inventory/asset/category.rb +24 -0
  76. data/lib/cashctrl/resources/inventory/asset.rb +34 -0
  77. data/lib/cashctrl/resources/inventory/unit.rb +12 -0
  78. data/lib/cashctrl/resources/journal/import/entry.rb +54 -0
  79. data/lib/cashctrl/resources/journal/import.rb +22 -0
  80. data/lib/cashctrl/resources/journal.rb +94 -0
  81. data/lib/cashctrl/resources/location.rb +10 -0
  82. data/lib/cashctrl/resources/order/book_entry.rb +12 -0
  83. data/lib/cashctrl/resources/order/category.rb +32 -0
  84. data/lib/cashctrl/resources/order/document.rb +38 -0
  85. data/lib/cashctrl/resources/order/layout.rb +12 -0
  86. data/lib/cashctrl/resources/order/payment.rb +56 -0
  87. data/lib/cashctrl/resources/order.rb +94 -0
  88. data/lib/cashctrl/resources/person/category.rb +22 -0
  89. data/lib/cashctrl/resources/person/title.rb +12 -0
  90. data/lib/cashctrl/resources/person.rb +40 -0
  91. data/lib/cashctrl/resources/report/collection.rb +72 -0
  92. data/lib/cashctrl/resources/report/element.rb +80 -0
  93. data/lib/cashctrl/resources/report.rb +60 -0
  94. data/lib/cashctrl/resources/rounding.rb +10 -0
  95. data/lib/cashctrl/resources/salary/book_entry.rb +12 -0
  96. data/lib/cashctrl/resources/salary/category.rb +22 -0
  97. data/lib/cashctrl/resources/salary/certificate/document.rb +72 -0
  98. data/lib/cashctrl/resources/salary/certificate/template.rb +24 -0
  99. data/lib/cashctrl/resources/salary/certificate.rb +30 -0
  100. data/lib/cashctrl/resources/salary/document.rb +62 -0
  101. data/lib/cashctrl/resources/salary/field.rb +38 -0
  102. data/lib/cashctrl/resources/salary/insurance/type.rb +14 -0
  103. data/lib/cashctrl/resources/salary/layout.rb +12 -0
  104. data/lib/cashctrl/resources/salary/payment.rb +56 -0
  105. data/lib/cashctrl/resources/salary/setting.rb +12 -0
  106. data/lib/cashctrl/resources/salary/statement.rb +77 -0
  107. data/lib/cashctrl/resources/salary/status.rb +24 -0
  108. data/lib/cashctrl/resources/salary/sum.rb +12 -0
  109. data/lib/cashctrl/resources/salary/template.rb +22 -0
  110. data/lib/cashctrl/resources/salary/type.rb +24 -0
  111. data/lib/cashctrl/resources/sequence_number.rb +20 -0
  112. data/lib/cashctrl/resources/setting.rb +52 -0
  113. data/lib/cashctrl/resources/tax.rb +10 -0
  114. data/lib/cashctrl/resources/text.rb +10 -0
  115. data/lib/cashctrl/schema.yml +601 -0
  116. data/lib/cashctrl/version.rb +1 -1
  117. data/lib/cashctrl.rb +114 -2
  118. data/lib/generators/model_generator.rb +92 -0
  119. metadata +115 -1
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class SalaryStatus < Resource
8
+ attribute :name, type: :string
9
+ attribute :sequence, type: :integer
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class SalarySum < Resource
8
+ attribute :type_id, type: :integer
9
+ attribute :name, type: :string
10
+ attribute :description, type: :string
11
+ attribute :sequence, type: :integer
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class SalaryTemplate < Resource
8
+ attribute :name, type: :string
9
+ attribute :description, type: :string
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class SalaryType < Resource
8
+ attribute :name, type: :string
9
+ attribute :description, type: :string
10
+ attribute :account_id, type: :integer
11
+ attribute :account_name, type: :string, readonly: true
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class SequenceNumber < Resource
8
+ attribute :name, type: :string
9
+ attribute :pattern, type: :string
10
+ attribute :counter, type: :integer
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class Setting < Resource
8
+ attribute :fiscal_period_id, type: :integer
9
+ attribute :fiscal_period_name, type: :string, readonly: true
10
+ attribute :default_currency_id, type: :integer
11
+ attribute :default_currency_code, type: :string, readonly: true
12
+ attribute :default_location_id, type: :integer
13
+ attribute :default_location_name, type: :string, readonly: true
14
+ attribute :default_debit_id, type: :integer
15
+ attribute :default_debit_name, type: :string, readonly: true
16
+ attribute :default_credit_id, type: :integer
17
+ attribute :default_credit_name, type: :string, readonly: true
18
+ attribute :default_opening_id, type: :integer
19
+ attribute :default_opening_name, type: :string, readonly: true
20
+ attribute :default_tax_id, type: :integer
21
+ attribute :default_tax_name, type: :string, readonly: true
22
+ attribute :default_order_category_id, type: :integer
23
+ attribute :default_person_category_customer_id, type: :integer
24
+ attribute :default_person_category_vendor_id, type: :integer
25
+ attribute :logo_file_id, type: :integer
26
+ attribute :csv_delimiter, type: :string
27
+ attribute :journal_import_duplicate_check, type: :string
28
+ attribute :journal_import_force_duplicate_detection, type: :boolean
29
+ attribute :tax_accounting_method, type: :string
30
+ attribute :tax_type, type: :string
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class Tax < Resource
8
+ attribute :name, type: :string
9
+ attribute :percentage, type: :decimal
10
+ attribute :document_name, type: :string
11
+ attribute :calc_type, type: :string
12
+ attribute :account_id, type: :integer
13
+ attribute :account_name, type: :string, readonly: true
14
+ attribute :is_inactive, type: :boolean
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class Text < Resource
8
+ attribute :type, type: :string
9
+ attribute :name, type: :string
10
+ attribute :value, type: :string
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class Title < Resource
8
+ attribute :name, type: :string
9
+ attribute :sentence, type: :string
10
+ attribute :gender, type: :string
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is auto-generated from schema.yml. Do not edit manually.
4
+
5
+ module Cashctrl
6
+ module Models
7
+ class Unit < Resource
8
+ attribute :name, type: :string
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,190 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bigdecimal"
4
+ require "date"
5
+ require "json"
6
+
7
+ module Cashctrl
8
+ class Resource
9
+ class << self
10
+ def attribute(name, type: :string, readonly: false)
11
+ attributes[name.to_sym] = { type: type, readonly: readonly }
12
+
13
+ define_method(name) do
14
+ @attributes[name.to_sym]
15
+ end
16
+
17
+ return if readonly
18
+
19
+ define_method("#{name}=") do |value|
20
+ @attributes[name.to_sym] = value
21
+ end
22
+ end
23
+
24
+ def attributes
25
+ @attributes ||= {}
26
+ end
27
+
28
+ def inherited(subclass)
29
+ super
30
+
31
+ subclass.instance_variable_set(:@attributes, attributes.dup)
32
+ end
33
+
34
+ def from_response(response)
35
+ return nil if response.nil?
36
+
37
+ data = response.is_a?(Hash) && response.key?("data") ? response["data"] : response
38
+ new(data)
39
+ end
40
+ end
41
+
42
+ attribute :id, type: :integer, readonly: true
43
+ attribute :created, type: :datetime, readonly: true
44
+ attribute :created_by, type: :string, readonly: true
45
+ attribute :last_updated, type: :datetime, readonly: true
46
+ attribute :last_updated_by, type: :string, readonly: true
47
+
48
+ attr_reader :raw_data
49
+
50
+ def initialize(attributes = {})
51
+ @raw_data = attributes.dup.freeze
52
+ @attributes = {}
53
+ @original_attributes = attributes.transform_keys { |k| underscore(k.to_s).to_sym }
54
+
55
+ self.class.attributes.each do |name, meta|
56
+ camel_key = camelize(name.to_s)
57
+ snake_key = name.to_sym
58
+
59
+ value = attributes[camel_key] || attributes[camel_key.to_sym] || attributes[snake_key.to_s] || attributes[snake_key]
60
+
61
+ @attributes[snake_key] = coerce_value(value, meta[:type])
62
+ end
63
+
64
+ @extra_attributes = {}
65
+
66
+ attributes.each do |key, value|
67
+ snake_key = underscore(key.to_s).to_sym
68
+
69
+ @extra_attributes[snake_key] = value unless self.class.attributes.key?(snake_key)
70
+ end
71
+ end
72
+
73
+ def [](key)
74
+ snake_key = underscore(key.to_s).to_sym
75
+ @attributes[snake_key] || @extra_attributes[snake_key]
76
+ end
77
+
78
+ def []=(key, value)
79
+ snake_key = underscore(key.to_s).to_sym
80
+ if self.class.attributes.key?(snake_key)
81
+ @attributes[snake_key] = value
82
+ else
83
+ @extra_attributes[snake_key] = value
84
+ end
85
+ end
86
+
87
+ def to_h
88
+ result = {}
89
+
90
+ @attributes.each do |key, value|
91
+ result[camelize(key.to_s)] = value
92
+ end
93
+
94
+ @extra_attributes.each do |key, value|
95
+ result[camelize(key.to_s)] = value
96
+ end
97
+
98
+ result
99
+ end
100
+
101
+ def to_json(*)
102
+ to_h.to_json(*)
103
+ end
104
+
105
+ def inspect
106
+ attrs = @attributes.map { |key, value| "#{key}: #{value.inspect}" }.join(", ")
107
+
108
+ "#<#{self.class.name} #{attrs}>"
109
+ end
110
+
111
+ def persisted?
112
+ !id.nil?
113
+ end
114
+
115
+ def ==(other)
116
+ other.is_a?(self.class) && id == other.id
117
+ end
118
+
119
+ alias eql? ==
120
+
121
+ def hash
122
+ [self.class, id].hash
123
+ end
124
+
125
+ def method_missing(method_name, *args)
126
+ snake_key = method_name.to_s.delete_suffix("=").to_sym
127
+
128
+ if method_name.to_s.end_with?("=")
129
+ @extra_attributes[snake_key] = args.first
130
+ elsif @extra_attributes.key?(snake_key)
131
+ coerce_dynamic_value(@extra_attributes[snake_key])
132
+ elsif @original_attributes.key?(snake_key)
133
+ coerce_dynamic_value(@original_attributes[snake_key])
134
+ end
135
+ end
136
+
137
+ def respond_to_missing?(method_name, include_private = false)
138
+ snake_key = method_name.to_s.delete_suffix("=").to_sym
139
+ @extra_attributes.key?(snake_key) || @original_attributes.key?(snake_key) || super
140
+ end
141
+
142
+ private
143
+
144
+ def coerce_dynamic_value(value)
145
+ return value unless value.is_a?(String)
146
+
147
+ LocalizedString.localized?(value) ? LocalizedString.parse(value) : value
148
+ end
149
+
150
+ def coerce_value(value, type)
151
+ return nil if value.nil?
152
+
153
+ case type
154
+ when :integer
155
+ value.to_i
156
+ when :decimal, :float
157
+ value.is_a?(BigDecimal) ? value : BigDecimal(value.to_s)
158
+ when :boolean
159
+ [true, "true", 1].include?(value)
160
+ when :date
161
+ value.is_a?(Date) ? value : Date.parse(value.to_s)
162
+ when :datetime
163
+ case value
164
+ when DateTime then value
165
+ when Time then value.to_datetime
166
+ else DateTime.parse(value.to_s)
167
+ end
168
+ when :json
169
+ value.is_a?(String) ? JSON.parse(value) : value
170
+ when :localized
171
+ LocalizedString.parse(value)
172
+ when :string
173
+ # Auto-detect localized strings
174
+ LocalizedString.localized?(value) ? LocalizedString.parse(value) : value
175
+ else
176
+ value
177
+ end
178
+ rescue ArgumentError, JSON::ParserError
179
+ value
180
+ end
181
+
182
+ def underscore(string)
183
+ string.gsub(/([A-Z])/, '_\1').sub(/^_/, "").downcase
184
+ end
185
+
186
+ def camelize(string)
187
+ string.split("_").each_with_index.map { |part, index| index.zero? ? part : part.capitalize }.join
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cashctrl
4
+ module Resources
5
+ class Account
6
+ class Bank < Base
7
+ api_path "account/bank"
8
+ model_class Models::Bank
9
+
10
+ class << self
11
+ def update_attachments(id:, file_ids:)
12
+ file_ids_param = Array(file_ids).join(",")
13
+ client.post("#{api_path}/update_attachments.json", id: id, fileIds: file_ids_param)
14
+ end
15
+ end
16
+
17
+ def update_attachments(id:, file_ids:)
18
+ file_ids_param = Array(file_ids).join(",")
19
+ client.post("#{api_path}/update_attachments.json", id: id, fileIds: file_ids_param)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cashctrl
4
+ module Resources
5
+ class Account
6
+ class Category < Base
7
+ api_path "account/category"
8
+ model_class Models::Category
9
+
10
+ class << self
11
+ def tree
12
+ client.get("#{api_path}/tree.json")
13
+ end
14
+ end
15
+
16
+ def tree
17
+ client.get("#{api_path}/tree.json")
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cashctrl
4
+ module Resources
5
+ class Account
6
+ class CostCenter
7
+ class Category < Base
8
+ api_path "account/costcenter/category"
9
+ model_class Models::Category
10
+
11
+ class << self
12
+ def tree
13
+ client.get("#{api_path}/tree.json")
14
+ end
15
+ end
16
+
17
+ def tree
18
+ client.get("#{api_path}/tree.json")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cashctrl
4
+ module Resources
5
+ class Account
6
+ class CostCenter < Base
7
+ api_path "account/costcenter"
8
+ model_class Models::CostCenter
9
+
10
+ class << self
11
+ def balance(id:, date: nil)
12
+ params = { id: id }
13
+ params[:date] = date if date
14
+ result = client.get_raw("#{api_path}/balance", params)
15
+ BigDecimal(result.to_s)
16
+ end
17
+
18
+ def categorize(ids:, target:)
19
+ ids_param = Array(ids).join(",")
20
+ client.post("#{api_path}/categorize.json", ids: ids_param, target: target)
21
+ end
22
+
23
+ def update_attachments(id:, file_ids:)
24
+ file_ids_param = Array(file_ids).join(",")
25
+ client.post("#{api_path}/update_attachments.json", id: id, fileIds: file_ids_param)
26
+ end
27
+ end
28
+
29
+ def balance(id:, date: nil)
30
+ params = { id: id }
31
+ params[:date] = date if date
32
+ result = client.get_raw("#{api_path}/balance", params)
33
+ BigDecimal(result.to_s)
34
+ end
35
+
36
+ def categorize(ids:, target:)
37
+ ids_param = Array(ids).join(",")
38
+ client.post("#{api_path}/categorize.json", ids: ids_param, target: target)
39
+ end
40
+
41
+ def update_attachments(id:, file_ids:)
42
+ file_ids_param = Array(file_ids).join(",")
43
+ client.post("#{api_path}/update_attachments.json", id: id, fileIds: file_ids_param)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cashctrl
4
+ module Resources
5
+ class Account < Base
6
+ api_path "account"
7
+ model_class Models::Account
8
+
9
+ class << self
10
+ def find_by_number(number)
11
+ list.find { |account| account.number == number }
12
+ end
13
+
14
+ def balance(id:, date: nil)
15
+ params = { id: id }
16
+ params[:date] = date if date
17
+ result = client.get_raw("#{api_path}/balance", params)
18
+ BigDecimal(result.to_s)
19
+ end
20
+
21
+ def categorize(ids:, target:)
22
+ ids_param = Array(ids).join(",")
23
+ client.post("#{api_path}/categorize.json", ids: ids_param, target: target)
24
+ end
25
+
26
+ def update_attachments(id:, file_ids:)
27
+ file_ids_param = Array(file_ids).join(",")
28
+ client.post("#{api_path}/update_attachments.json", id: id, fileIds: file_ids_param)
29
+ end
30
+ end
31
+
32
+ def find_by_number(number)
33
+ list.find { |account| account.number == number }
34
+ end
35
+
36
+ def balance(id:, date: nil)
37
+ params = { id: id }
38
+ params[:date] = date if date
39
+ result = client.get_raw("#{api_path}/balance", params)
40
+ BigDecimal(result.to_s)
41
+ end
42
+
43
+ def categorize(ids:, target:)
44
+ ids_param = Array(ids).join(",")
45
+ client.post("#{api_path}/categorize.json", ids: ids_param, target: target)
46
+ end
47
+
48
+ def update_attachments(id:, file_ids:)
49
+ file_ids_param = Array(file_ids).join(",")
50
+ client.post("#{api_path}/update_attachments.json", id: id, fileIds: file_ids_param)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cashctrl
4
+ module Resources
5
+ class Base
6
+ class << self
7
+ def api_path(path = nil)
8
+ if path
9
+ @api_path = path
10
+ else
11
+ @api_path
12
+ end
13
+ end
14
+
15
+ def model_class(klass = nil)
16
+ if klass
17
+ @model_class = klass
18
+ else
19
+ @model_class || Resource
20
+ end
21
+ end
22
+
23
+ def client
24
+ Cashctrl.client
25
+ end
26
+
27
+ def list(**params)
28
+ response = client.get("#{api_path}/list.json", params)
29
+ Collection.from_response(response, resource_class: model_class)
30
+ end
31
+
32
+ def all(...)
33
+ list(...)
34
+ end
35
+
36
+ def read(id:)
37
+ response = client.get("#{api_path}/read.json", id: id)
38
+ model_class.from_response(response)
39
+ end
40
+
41
+ def find(id)
42
+ read(id: id)
43
+ end
44
+
45
+ def create(**params)
46
+ response = client.post("#{api_path}/create.json", params)
47
+ wrap_response(response)
48
+ end
49
+
50
+ def update(id:, **params)
51
+ response = client.post("#{api_path}/update.json", { id: id, **params })
52
+ wrap_response(response)
53
+ end
54
+
55
+ def delete(ids:)
56
+ ids_param = Array(ids).join(",")
57
+ client.post("#{api_path}/delete.json", ids: ids_param)
58
+ end
59
+
60
+ def first
61
+ list.first
62
+ end
63
+
64
+ def last
65
+ list.last
66
+ end
67
+
68
+ private
69
+
70
+ def wrap_response(response)
71
+ return response unless response.is_a?(Hash) && response["data"]
72
+
73
+ if response["data"].is_a?(Array)
74
+ Collection.from_response(response, resource_class: model_class)
75
+ else
76
+ model_class.from_response(response["data"])
77
+ end
78
+ end
79
+ end
80
+
81
+ attr_reader :client
82
+
83
+ def initialize(client)
84
+ @client = client
85
+ end
86
+
87
+ def api_path
88
+ self.class.api_path
89
+ end
90
+
91
+ def model_class
92
+ self.class.model_class
93
+ end
94
+
95
+ def list(**params)
96
+ response = client.get("#{api_path}/list.json", params)
97
+ Collection.from_response(response, resource_class: model_class)
98
+ end
99
+
100
+ def all(...)
101
+ list(...)
102
+ end
103
+
104
+ def read(id:)
105
+ response = client.get("#{api_path}/read.json", id: id)
106
+ model_class.from_response(response)
107
+ end
108
+
109
+ def find(id)
110
+ read(id: id)
111
+ end
112
+
113
+ def create(**params)
114
+ response = client.post("#{api_path}/create.json", params)
115
+ wrap_response(response)
116
+ end
117
+
118
+ def update(id:, **params)
119
+ response = client.post("#{api_path}/update.json", { id: id, **params })
120
+ wrap_response(response)
121
+ end
122
+
123
+ def delete(ids:)
124
+ ids_param = Array(ids).join(",")
125
+ client.post("#{api_path}/delete.json", ids: ids_param)
126
+ end
127
+
128
+ def first
129
+ list.first
130
+ end
131
+
132
+ def last
133
+ list.last
134
+ end
135
+
136
+ def list_csv(**params)
137
+ client.get_raw("#{api_path}/list.csv", params)
138
+ end
139
+
140
+ def list_xlsx(**params)
141
+ client.get_raw("#{api_path}/list.xlsx", params)
142
+ end
143
+
144
+ def list_pdf(**params)
145
+ client.get_raw("#{api_path}/list.pdf", params)
146
+ end
147
+
148
+ private
149
+
150
+ def wrap_response(response)
151
+ return response unless response.is_a?(Hash) && response["data"]
152
+
153
+ if response["data"].is_a?(Array)
154
+ Collection.from_response(response, resource_class: model_class)
155
+ else
156
+ model_class.from_response(response["data"])
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end