gera 0.3.4

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 (164) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +67 -0
  4. data/Rakefile +43 -0
  5. data/app/assets/config/gera_manifest.js +2 -0
  6. data/app/assets/javascripts/gera/application.js +14 -0
  7. data/app/assets/stylesheets/gera/application.css +15 -0
  8. data/app/authorizers/gera/application_authorizer.rb +6 -0
  9. data/app/authorizers/gera/currency_rate_authorizer.rb +9 -0
  10. data/app/authorizers/gera/currency_rate_mode_authorizer.rb +7 -0
  11. data/app/authorizers/gera/direction_rate_authorizer.rb +8 -0
  12. data/app/authorizers/gera/exchange_rate_authorizer.rb +8 -0
  13. data/app/authorizers/gera/payment_system_authorizer.rb +13 -0
  14. data/app/authorizers/gera/rate_source_authorizer.rb +7 -0
  15. data/app/controllers/gera/application_controller.rb +30 -0
  16. data/app/controllers/gera/currencies_controller.rb +8 -0
  17. data/app/controllers/gera/currency_rate_history_intervals_controller.rb +53 -0
  18. data/app/controllers/gera/currency_rate_mode_snapshots_controller.rb +83 -0
  19. data/app/controllers/gera/currency_rate_modes_controller.rb +60 -0
  20. data/app/controllers/gera/currency_rates_controller.rb +70 -0
  21. data/app/controllers/gera/direction_rate_history_intervals_controller.rb +62 -0
  22. data/app/controllers/gera/direction_rates_controller.rb +28 -0
  23. data/app/controllers/gera/exchange_rates_controller.rb +25 -0
  24. data/app/controllers/gera/external_rate_snapshots_controller.rb +35 -0
  25. data/app/controllers/gera/external_rates_controller.rb +28 -0
  26. data/app/controllers/gera/payment_systems_controller.rb +78 -0
  27. data/app/controllers/gera/rate_sources_controller.rb +8 -0
  28. data/app/decorators/gera/currency_rate_decorator.rb +148 -0
  29. data/app/decorators/gera/direction_rate_decorator.rb +47 -0
  30. data/app/decorators/gera/payment_system_decorator.rb +19 -0
  31. data/app/helpers/gera/application_helper.rb +110 -0
  32. data/app/helpers/gera/currency_rate_helper.rb +19 -0
  33. data/app/helpers/gera/currency_rate_modes_helper.rb +73 -0
  34. data/app/helpers/gera/direction_rate_helper.rb +36 -0
  35. data/app/helpers/gera/exchange_rates_helper.rb +21 -0
  36. data/app/jobs/gera/application_job.rb +6 -0
  37. data/app/models/concerns/gera/currency_pair_generator.rb +14 -0
  38. data/app/models/concerns/gera/currency_pair_support.rb +42 -0
  39. data/app/models/concerns/gera/currency_rate_mode_builder_support.rb +35 -0
  40. data/app/models/concerns/gera/direction_support.rb +14 -0
  41. data/app/models/concerns/gera/history_interval_concern.rb +46 -0
  42. data/app/models/gera/application_record.rb +8 -0
  43. data/app/models/gera/cbr_external_rate.rb +13 -0
  44. data/app/models/gera/cross_rate_mode.rb +13 -0
  45. data/app/models/gera/currency_rate.rb +78 -0
  46. data/app/models/gera/currency_rate_history_interval.rb +25 -0
  47. data/app/models/gera/currency_rate_history_interval_filter.rb +30 -0
  48. data/app/models/gera/currency_rate_mode.rb +20 -0
  49. data/app/models/gera/currency_rate_mode_snapshot.rb +26 -0
  50. data/app/models/gera/currency_rate_snapshot.rb +12 -0
  51. data/app/models/gera/direction.rb +44 -0
  52. data/app/models/gera/direction_rate.rb +136 -0
  53. data/app/models/gera/direction_rate_history_interval.rb +33 -0
  54. data/app/models/gera/direction_rate_history_interval_filter.rb +30 -0
  55. data/app/models/gera/direction_rate_snapshot.rb +7 -0
  56. data/app/models/gera/exchange_rate.rb +130 -0
  57. data/app/models/gera/external_rate.rb +38 -0
  58. data/app/models/gera/external_rate_snapshot.rb +20 -0
  59. data/app/models/gera/payment_system.rb +98 -0
  60. data/app/models/gera/rate_source.rb +77 -0
  61. data/app/models/gera/rate_source_auto.rb +25 -0
  62. data/app/models/gera/rate_source_bitfinex.rb +9 -0
  63. data/app/models/gera/rate_source_cbr.rb +13 -0
  64. data/app/models/gera/rate_source_cbr_avg.rb +6 -0
  65. data/app/models/gera/rate_source_exmo.rb +9 -0
  66. data/app/models/gera/rate_source_manual.rb +13 -0
  67. data/app/views/application/_exchange_rate_monitor.slim +1 -0
  68. data/app/views/gera/application/_attributes_table.slim +5 -0
  69. data/app/views/gera/application/_currencies_table.slim +18 -0
  70. data/app/views/gera/application/_currency_rate_mode_snapshots.slim +6 -0
  71. data/app/views/gera/application/_direction_rate.slim +6 -0
  72. data/app/views/gera/application/_directions_submenu.slim +11 -0
  73. data/app/views/gera/application/_directions_table.slim +15 -0
  74. data/app/views/gera/application/_exchange_rate.slim +6 -0
  75. data/app/views/gera/application/_external_rate.slim +6 -0
  76. data/app/views/gera/application/_header.slim +12 -0
  77. data/app/views/gera/application/_table.slim +28 -0
  78. data/app/views/gera/application/_topnav.slim +21 -0
  79. data/app/views/gera/application/direction_details.slim +75 -0
  80. data/app/views/gera/application/page.html.slim +1 -0
  81. data/app/views/gera/currencies/index.html.slim +20 -0
  82. data/app/views/gera/currency_rate_history_intervals/_filter.slim +11 -0
  83. data/app/views/gera/currency_rate_history_intervals/index.slim +39 -0
  84. data/app/views/gera/currency_rate_mode_snapshots/_snapshot.slim +20 -0
  85. data/app/views/gera/currency_rate_mode_snapshots/edit.html.slim +30 -0
  86. data/app/views/gera/currency_rate_modes/_cross_rate_mode_fields.slim +21 -0
  87. data/app/views/gera/currency_rate_modes/_currency_rate_mode.slim +7 -0
  88. data/app/views/gera/currency_rate_modes/_form.slim +29 -0
  89. data/app/views/gera/currency_rate_modes/edit.slim +11 -0
  90. data/app/views/gera/currency_rate_modes/index.html.slim +12 -0
  91. data/app/views/gera/currency_rates/_currency_rate.slim +22 -0
  92. data/app/views/gera/currency_rates/_currency_rate_humanized.slim +35 -0
  93. data/app/views/gera/currency_rates/diff.slim +12 -0
  94. data/app/views/gera/currency_rates/index.slim +27 -0
  95. data/app/views/gera/currency_rates/modes.slim +14 -0
  96. data/app/views/gera/currency_rates/show.slim +4 -0
  97. data/app/views/gera/direction_rate_history_intervals/_filter.slim +11 -0
  98. data/app/views/gera/direction_rate_history_intervals/index.slim +41 -0
  99. data/app/views/gera/direction_rates/_direction_rate_example_calculator.slim +28 -0
  100. data/app/views/gera/direction_rates/diff.slim +19 -0
  101. data/app/views/gera/direction_rates/index.slim +26 -0
  102. data/app/views/gera/direction_rates/legacy.html.slim +5 -0
  103. data/app/views/gera/direction_rates/minimals.slim +5 -0
  104. data/app/views/gera/direction_rates/show.slim +14 -0
  105. data/app/views/gera/external_rate_snapshots/index.slim +25 -0
  106. data/app/views/gera/external_rate_snapshots/show.slim +22 -0
  107. data/app/views/gera/external_rates/_flat_list.slim +22 -0
  108. data/app/views/gera/external_rates/index.html.slim +28 -0
  109. data/app/views/gera/external_rates/show.slim +1 -0
  110. data/app/views/gera/payment_systems/_fields.slim +4 -0
  111. data/app/views/gera/payment_systems/_fields_table.slim +18 -0
  112. data/app/views/gera/payment_systems/_form.slim +9 -0
  113. data/app/views/gera/payment_systems/edit.slim +7 -0
  114. data/app/views/gera/payment_systems/index.slim +3 -0
  115. data/app/views/gera/payment_systems/new.slim +9 -0
  116. data/app/views/gera/payment_systems/show.slim +1 -0
  117. data/app/views/gera/rate_sources/_list.slim +13 -0
  118. data/app/views/gera/rate_sources/_rate_source.slim +23 -0
  119. data/app/views/gera/rate_sources/index.html.slim +6 -0
  120. data/app/views/layouts/application.html.slim +15 -0
  121. data/app/views/layouts/gera/blank.html.slim +10 -0
  122. data/app/workers/concerns/gera/rates_worker.rb +87 -0
  123. data/app/workers/gera/bitfinex_rates_worker.rb +65 -0
  124. data/app/workers/gera/cbr_avg_rates_worker.rb +42 -0
  125. data/app/workers/gera/cbr_rates_worker.rb +192 -0
  126. data/app/workers/gera/create_history_intervals_worker.rb +38 -0
  127. data/app/workers/gera/currency_rates_worker.rb +64 -0
  128. data/app/workers/gera/directions_rates_worker.rb +51 -0
  129. data/app/workers/gera/exmo_rates_worker.rb +62 -0
  130. data/app/workers/gera/purge_currency_rates_worker.rb +21 -0
  131. data/app/workers/gera/purge_direction_rates_worker.rb +30 -0
  132. data/config/currencies.yml +559 -0
  133. data/config/routes.rb +30 -0
  134. data/db/migrate/20180912130000_setup.rb +228 -0
  135. data/db/migrate/20190314114844_add_is_available_to_payment_systems.rb +7 -0
  136. data/db/migrate/20190315113046_add_icon_url_to_payment_systems.rb +7 -0
  137. data/db/migrate/20190315132137_add_commission_to_payment_systems.rb +7 -0
  138. data/lib/banks/currency_exchange.rb +12 -0
  139. data/lib/builders/currency_rate_auto_builder.rb +38 -0
  140. data/lib/builders/currency_rate_builder.rb +60 -0
  141. data/lib/builders/currency_rate_cross_builder.rb +70 -0
  142. data/lib/builders/currency_rate_direct_builder.rb +26 -0
  143. data/lib/gera.rb +32 -0
  144. data/lib/gera/bitfinex_fetcher.rb +36 -0
  145. data/lib/gera/configuration.rb +47 -0
  146. data/lib/gera/currencies_purger.rb +28 -0
  147. data/lib/gera/currency_pair.rb +93 -0
  148. data/lib/gera/engine.rb +14 -0
  149. data/lib/gera/mathematic.rb +156 -0
  150. data/lib/gera/money_support.rb +89 -0
  151. data/lib/gera/numeric.rb +25 -0
  152. data/lib/gera/railtie.rb +8 -0
  153. data/lib/gera/rate.rb +22 -0
  154. data/lib/gera/rate_from_multiplicator.rb +54 -0
  155. data/lib/gera/repositories/currency_rate_modes_repository.rb +37 -0
  156. data/lib/gera/repositories/currency_rates_repository.rb +25 -0
  157. data/lib/gera/repositories/direction_rates_repository.rb +46 -0
  158. data/lib/gera/repositories/exchange_rates_repository.rb +23 -0
  159. data/lib/gera/repositories/payment_systems_repository.rb +21 -0
  160. data/lib/gera/repositories/universe.rb +47 -0
  161. data/lib/gera/version.rb +3 -0
  162. data/lib/tasks/auto_generate_diagram.rake +6 -0
  163. data/lib/tasks/gera_tasks.rake +4 -0
  164. metadata +765 -0
data/config/routes.rb ADDED
@@ -0,0 +1,30 @@
1
+ Gera::Engine.routes.draw do
2
+ root 'direction_rates#index'
3
+ resources :payment_systems
4
+
5
+ resources :currency_rate_history_intervals, only: [:index]
6
+ resources :direction_rate_history_intervals, only: [:index]
7
+
8
+ resources :currencies, only: [:index]
9
+ resources :direction_rates do
10
+ member do
11
+ get :last
12
+ end
13
+ end
14
+ resources :external_rates, only: [:index, :show]
15
+
16
+ resources :exchange_rates, only: [:show] do
17
+ member do
18
+ get :details
19
+ end
20
+ end
21
+ resources :external_rate_snapshots, only: [:index, :show]
22
+ resources :currency_rates
23
+ resources :currency_rate_modes, only: [:edit, :update, :new, :create]
24
+ resources :currency_rate_mode_snapshots, only: [:index, :edit, :update, :show, :create] do
25
+ member do
26
+ post :activate
27
+ end
28
+ end
29
+ resources :rate_sources
30
+ end
@@ -0,0 +1,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Setup < ActiveRecord::Migration[5.2]
4
+ MYSQL_OPTIONS = 'ENGINE=InnoDB DEFAULT CHARSET=utf8'
5
+
6
+ def change
7
+ if defined?(ActiveRecord::ConnectionAdapters::Mysql2Adapter) &&
8
+ connection.is_a?(ActiveRecord::ConnectionAdapters::Mysql2Adapter)
9
+ table_options = MYSQL_OPTIONS
10
+ execute "SET SQL_MODE='ALLOW_INVALID_DATES';"
11
+ end
12
+
13
+ create_table 'gera_external_rate_snapshots', options: table_options, force: :cascade do |t|
14
+ t.bigint 'rate_source_id', null: false
15
+ t.timestamp 'actual_for', default: -> { 'CURRENT_TIMESTAMP' }, null: false
16
+ t.datetime 'created_at', null: false
17
+ t.index %w[rate_source_id actual_for], name: 'index_external_rate_snapshots_on_rate_source_id_and_actual_for', unique: true
18
+ t.index ['rate_source_id'], name: 'index_external_rate_snapshots_on_rate_source_id'
19
+ end
20
+
21
+ create_table 'gera_external_rates', options: table_options, force: :cascade do |t|
22
+ t.bigint 'source_id', null: false
23
+ t.string 'cur_from', null: false
24
+ t.string 'cur_to', null: false
25
+ t.float 'rate_value', limit: 53
26
+ t.bigint 'snapshot_id', null: false
27
+ t.timestamp 'created_at'
28
+ t.index %w[snapshot_id cur_from cur_to], name: 'index_external_rates_on_snapshot_id_and_cur_from_and_cur_to', unique: true
29
+ t.index ['source_id'], name: 'index_external_rates_on_source_id'
30
+ end
31
+
32
+ create_table 'gera_rate_sources', options: table_options, force: :cascade do |t|
33
+ t.string 'title', null: false
34
+ t.string 'type', null: false
35
+ t.datetime 'created_at', null: false
36
+ t.datetime 'updated_at', null: false
37
+ t.string 'key', null: false
38
+ t.bigint 'actual_snapshot_id'
39
+ t.integer 'priority', default: 0, null: false
40
+ t.boolean 'is_enabled', default: true, null: false
41
+ t.index ['actual_snapshot_id'], name: 'fk_rails_0b6cf3ddaa'
42
+ t.index ['key'], name: 'index_rate_sources_on_key', unique: true
43
+ t.index ['title'], name: 'index_rate_sources_on_title', unique: true
44
+ end
45
+
46
+ create_table 'gera_cross_rate_modes', options: table_options, force: :cascade do |t|
47
+ t.bigint 'currency_rate_mode_id', null: false
48
+ t.string 'cur_from', null: false
49
+ t.string 'cur_to', null: false
50
+ t.bigint 'rate_source_id'
51
+ t.datetime 'created_at', null: false
52
+ t.datetime 'updated_at', null: false
53
+ t.index ['currency_rate_mode_id'], name: 'index_cross_rate_modes_on_currency_rate_mode_id'
54
+ t.index ['rate_source_id'], name: 'index_cross_rate_modes_on_rate_source_id'
55
+ end
56
+
57
+ create_table 'gera_direction_rate_history_intervals', options: table_options, force: :cascade do |t|
58
+ t.float 'min_rate', null: false
59
+ t.float 'max_rate', null: false
60
+ t.float 'min_comission', null: false
61
+ t.float 'max_comission', null: false
62
+ t.timestamp 'interval_from', default: -> { 'CURRENT_TIMESTAMP' }, null: false
63
+ t.timestamp 'interval_to', null: false
64
+ t.bigint 'payment_system_to_id', null: false
65
+ t.bigint 'payment_system_from_id', null: false
66
+ t.float 'avg_rate', null: false
67
+ t.index %w[interval_from payment_system_from_id payment_system_to_id], name: 'drhi_uniq', unique: true
68
+ t.index ['payment_system_from_id'], name: 'fk_rails_70f35124fc'
69
+ t.index ['payment_system_to_id'], name: 'fk_rails_5c92dd1b7f'
70
+ end
71
+
72
+ create_table 'gera_currency_rate_history_intervals', options: table_options, force: :cascade do |t|
73
+ t.integer 'cur_from_id', limit: 1, null: false
74
+ t.integer 'cur_to_id', limit: 1, null: false
75
+ t.float 'min_rate', null: false
76
+ t.float 'avg_rate', null: false
77
+ t.float 'max_rate', null: false
78
+ t.timestamp 'interval_from', default: -> { 'CURRENT_TIMESTAMP' }, null: false
79
+ t.timestamp 'interval_to', null: false
80
+ t.index %w[cur_from_id cur_to_id interval_from], name: 'crhi_unique_index', unique: true
81
+ t.index ['interval_from'], name: 'index_currency_rate_history_intervals_on_interval_from'
82
+ end
83
+
84
+ create_table 'gera_currency_rate_mode_snapshots', options: table_options, force: :cascade do |t|
85
+ t.datetime 'created_at', null: false
86
+ t.datetime 'updated_at', null: false
87
+ t.integer 'status', default: 0, null: false
88
+ t.string 'title'
89
+ t.text 'details'
90
+ t.index ['status'], name: 'index_currency_rate_mode_snapshots_on_status'
91
+ t.index ['title'], name: 'index_currency_rate_mode_snapshots_on_title', unique: true
92
+ end
93
+
94
+ create_table 'gera_currency_rate_modes', options: table_options, force: :cascade do |t|
95
+ t.string 'cur_from', null: false
96
+ t.string 'cur_to', null: false
97
+ t.integer 'mode', default: 0, null: false
98
+ t.datetime 'created_at', null: false
99
+ t.datetime 'updated_at', null: false
100
+ t.bigint 'currency_rate_mode_snapshot_id', null: false
101
+ t.string 'cross_currency1'
102
+ t.bigint 'cross_rate_source1_id'
103
+ t.string 'cross_currency2'
104
+ t.string 'cross_currency3'
105
+ t.bigint 'cross_rate_source2_id'
106
+ t.bigint 'cross_rate_source3_id'
107
+ t.index ['cross_rate_source1_id'], name: 'index_currency_rate_modes_on_cross_rate_source1_id'
108
+ t.index ['cross_rate_source2_id'], name: 'index_currency_rate_modes_on_cross_rate_source2_id'
109
+ t.index ['cross_rate_source3_id'], name: 'index_currency_rate_modes_on_cross_rate_source3_id'
110
+ t.index %w[currency_rate_mode_snapshot_id cur_from cur_to], name: 'crm_id_pair', unique: true
111
+ end
112
+
113
+ create_table 'gera_currency_rate_snapshots', options: table_options, force: :cascade do |t|
114
+ t.timestamp 'created_at', default: -> { 'CURRENT_TIMESTAMP' }, null: false
115
+ t.bigint 'currency_rate_mode_snapshot_id', null: false
116
+ t.index ['currency_rate_mode_snapshot_id'], name: 'fk_rails_456167e2a9'
117
+ end
118
+
119
+ create_table 'gera_currency_rates', options: table_options, force: :cascade do |t|
120
+ t.string 'cur_from', null: false
121
+ t.string 'cur_to', null: false
122
+ t.float 'rate_value', limit: 53, null: false
123
+ t.bigint 'snapshot_id', null: false
124
+ t.json 'metadata', null: false
125
+ t.timestamp 'created_at'
126
+ t.bigint 'external_rate_id'
127
+ t.integer 'mode', null: false
128
+ t.bigint 'rate_source_id'
129
+ t.bigint 'external_rate1_id'
130
+ t.bigint 'external_rate2_id'
131
+ t.bigint 'external_rate3_id'
132
+ t.index %w[created_at cur_from cur_to], name: 'currency_rates_created_at'
133
+ t.index ['external_rate1_id'], name: 'index_currency_rates_on_external_rate1_id'
134
+ t.index ['external_rate2_id'], name: 'index_currency_rates_on_external_rate2_id'
135
+ t.index ['external_rate3_id'], name: 'index_currency_rates_on_external_rate3_id'
136
+ t.index ['external_rate_id'], name: 'fk_rails_905ddd038e'
137
+ t.index ['rate_source_id'], name: 'fk_rails_2397c780d5'
138
+ t.index %w[snapshot_id cur_from cur_to], name: 'index_current_exchange_rates_uniq', unique: true
139
+ end
140
+
141
+ create_table 'gera_direction_rate_snapshots', options: table_options, force: :cascade do |t|
142
+ t.timestamp 'created_at', default: -> { 'CURRENT_TIMESTAMP' }, null: false
143
+ end
144
+
145
+ create_table 'gera_direction_rates', options: table_options, force: :cascade do |t|
146
+ t.bigint 'ps_from_id', null: false
147
+ t.bigint 'ps_to_id', null: false
148
+ t.bigint 'currency_rate_id', null: false
149
+ t.float 'rate_value', limit: 53, null: false
150
+ t.float 'base_rate_value', limit: 53, null: false
151
+ t.float 'rate_percent', null: false
152
+ t.timestamp 'created_at', default: -> { 'CURRENT_TIMESTAMP' }, null: false
153
+ t.bigint 'exchange_rate_id', null: false
154
+ t.boolean 'is_used', default: false, null: false
155
+ t.bigint 'snapshot_id'
156
+ t.index %w[created_at ps_from_id ps_to_id], name: 'direction_rates_created_at'
157
+ t.index ['currency_rate_id'], name: 'fk_rails_d6f1847478'
158
+ t.index %w[exchange_rate_id id], name: 'index_direction_rates_on_exchange_rate_id_and_id'
159
+ t.index %w[ps_from_id ps_to_id id], name: 'index_direction_rates_on_ps_from_id_and_ps_to_id_and_id'
160
+ t.index ['ps_to_id'], name: 'fk_rails_fbaf7f33e1'
161
+ t.index ['snapshot_id'], name: 'fk_rails_392aafe0ef'
162
+ end
163
+
164
+ create_table 'gera_cbr_external_rates', options: table_options, force: :cascade do |t|
165
+ t.date 'date', null: false
166
+ t.string 'cur_from', null: false
167
+ t.string 'cur_to', null: false
168
+ t.float 'rate', null: false
169
+ t.float 'original_rate', null: false
170
+ t.integer 'nominal', null: false
171
+ t.datetime 'created_at', null: false
172
+ t.datetime 'updated_at', null: false
173
+ t.index %w[cur_from cur_to date], name: 'index_cbr_external_rates_on_cur_from_and_cur_to_and_date', unique: true
174
+ end
175
+
176
+ create_table 'gera_exchange_rates', options: table_options, force: :cascade do |t|
177
+ t.bigint 'income_payment_system_id', null: false
178
+ t.string 'in_cur', limit: 4, null: false
179
+ t.string 'out_cur', limit: 4, null: false
180
+ t.bigint 'outcome_payment_system_id', null: false
181
+ t.float 'value', null: false
182
+ t.boolean 'is_enabled', default: false, null: false
183
+ t.timestamp 'updated_at', default: -> { 'CURRENT_TIMESTAMP' }, null: false
184
+ t.timestamp 'created_at', default: -> { 'CURRENT_TIMESTAMP' }, null: false
185
+ t.index %w[income_payment_system_id outcome_payment_system_id], name: 'exchange_rate_unique_index', unique: true
186
+ t.index ['outcome_payment_system_id'], name: 'fk_rails_ef77ea3609'
187
+ t.index ['is_enabled'], name: 'index_exchange_rates_on_is_enabled'
188
+ end
189
+
190
+ create_table 'gera_payment_systems', options: table_options, force: :cascade do |t|
191
+ t.string 'name', limit: 60
192
+ t.integer 'priority', limit: 1
193
+ t.string 'img'
194
+ t.integer 'type_cy', null: false
195
+ t.boolean 'income_enabled', default: false, null: false
196
+ t.boolean 'outcome_enabled', default: false, null: false
197
+ t.timestamp 'deleted_at'
198
+ t.timestamp 'updated_at', default: -> { 'CURRENT_TIMESTAMP' }, null: false
199
+ t.timestamp 'created_at', default: -> { 'CURRENT_TIMESTAMP' }, null: false
200
+ t.index ['income_enabled'], name: 'index_payment_systems_on_income_enabled'
201
+ t.index ['outcome_enabled'], name: 'index_payment_systems_on_outcome_enabled'
202
+ end
203
+
204
+ add_foreign_key 'gera_exchange_rates', 'gera_payment_systems', column: 'income_payment_system_id', on_delete: :cascade
205
+ add_foreign_key 'gera_exchange_rates', 'gera_payment_systems', column: 'outcome_payment_system_id', on_delete: :cascade
206
+ add_foreign_key 'gera_cross_rate_modes', 'gera_currency_rate_modes', column: :currency_rate_mode_id, on_delete: :cascade
207
+ add_foreign_key 'gera_cross_rate_modes', 'gera_rate_sources', column: :rate_source_id, on_delete: :cascade
208
+ add_foreign_key 'gera_currency_rate_modes', 'gera_currency_rate_mode_snapshots', column: :currency_rate_mode_snapshot_id, on_delete: :cascade
209
+ add_foreign_key 'gera_currency_rate_modes', 'gera_rate_sources', column: 'cross_rate_source1_id', on_delete: :cascade
210
+ add_foreign_key 'gera_currency_rate_modes', 'gera_rate_sources', column: 'cross_rate_source2_id', on_delete: :cascade
211
+ add_foreign_key 'gera_currency_rate_modes', 'gera_rate_sources', column: 'cross_rate_source3_id', on_delete: :cascade
212
+ add_foreign_key 'gera_currency_rate_snapshots', 'gera_currency_rate_mode_snapshots', column: :currency_rate_mode_snapshot_id, on_delete: :cascade
213
+ add_foreign_key 'gera_currency_rates', 'gera_currency_rate_snapshots', column: 'snapshot_id', on_delete: :cascade
214
+ add_foreign_key 'gera_currency_rates', 'gera_external_rates', column: 'external_rate1_id', on_delete: :cascade
215
+ add_foreign_key 'gera_currency_rates', 'gera_external_rates', column: 'external_rate2_id', on_delete: :cascade
216
+ add_foreign_key 'gera_currency_rates', 'gera_external_rates', column: 'external_rate3_id', on_delete: :cascade
217
+ add_foreign_key 'gera_currency_rates', 'gera_external_rates', column: :external_rate_id, on_delete: :nullify
218
+ add_foreign_key 'gera_currency_rates', 'gera_rate_sources', column: :rate_source_id, on_delete: :cascade
219
+ add_foreign_key 'gera_direction_rates', 'gera_exchange_rates', column: 'exchange_rate_id', on_delete: :cascade
220
+ add_foreign_key 'gera_direction_rates', 'gera_payment_systems', column: 'ps_from_id', on_delete: :cascade
221
+ add_foreign_key 'gera_direction_rates', 'gera_payment_systems', column: 'ps_to_id', on_delete: :cascade
222
+ add_foreign_key 'gera_direction_rates', 'gera_currency_rates', column: :currency_rate_id, on_delete: :cascade
223
+ add_foreign_key 'gera_external_rates', 'gera_external_rate_snapshots', column: 'snapshot_id', on_delete: :cascade
224
+ add_foreign_key 'gera_external_rates', 'gera_rate_sources', column: 'source_id', on_delete: :cascade
225
+ add_foreign_key 'gera_direction_rate_history_intervals', 'gera_payment_systems', column: 'payment_system_from_id', on_delete: :cascade
226
+ add_foreign_key 'gera_direction_rate_history_intervals', 'gera_payment_systems', column: 'payment_system_to_id', on_delete: :cascade
227
+ end
228
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddIsAvailableToPaymentSystems < ActiveRecord::Migration[5.2]
4
+ def change
5
+ add_column :gera_payment_systems, :is_available, :boolean, null: false, default: true
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddIconUrlToPaymentSystems < ActiveRecord::Migration[5.2]
4
+ def change
5
+ add_column :gera_payment_systems, :icon_url, :string
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddCommissionToPaymentSystems < ActiveRecord::Migration[5.2]
4
+ def change
5
+ add_column :gera_payment_systems, :commission, :float, null: false, default: 0
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ # Банк для Money
2
+ #
3
+
4
+ module Gera
5
+ class CurrencyExchange
6
+ def self.get_rate(cur_from, cur_to)
7
+ pair = CurrencyPair.new(cur_from, cur_to)
8
+ cr = Universe.currency_rates_repository.find_currency_rate_by_pair(pair) || raise("Отсутсвует текущий курс для #{pair}")
9
+ cr.rate_value
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'currency_rate_builder'
2
+
3
+ module Gera
4
+ class CurrencyRateAutoBuilder < CurrencyRateBuilder
5
+ private
6
+
7
+ def build
8
+ build_same ||
9
+ build_from_sources ||
10
+ build_cross ||
11
+ raise(Error, "Не найден автоматический способ расчета")
12
+ end
13
+
14
+ def build_from_sources
15
+ RateSource.enabled.ordered.each do |rate_source|
16
+ result = build_from_source rate_source
17
+ return result if result.present?
18
+ end
19
+
20
+ nil
21
+ end
22
+
23
+ def build_cross
24
+ result = CurrencyRateCrossBuilder.new(currency_pair: currency_pair).build_currency_rate
25
+ raise result.error if result.error?
26
+ result.currency_rate
27
+ end
28
+
29
+ def build_from_source source
30
+ CurrencyRateDirectBuilder.new(currency_pair: currency_pair, source: source).build_currency_rate.currency_rate
31
+ end
32
+
33
+ def build_same
34
+ return unless currency_pair.same?
35
+ CurrencyRate.new currency_pair: currency_pair, rate_value: 1, mode: :same
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,60 @@
1
+ module Gera
2
+ class CurrencyRateBuilder
3
+ Error = Class.new StandardError
4
+ Result = Class.new
5
+ class SuccessResult < Result
6
+ include Virtus.model
7
+ attribute :currency_rate #, CurrencyRate
8
+
9
+ def success?
10
+ true
11
+ end
12
+
13
+ def error?
14
+ false
15
+ end
16
+ end
17
+
18
+ class ErrorResult < Result
19
+ include Virtus.model
20
+ attribute :error, StandardError
21
+
22
+ def currency_rate
23
+ nil
24
+ end
25
+
26
+ def success?
27
+ false
28
+ end
29
+
30
+ def error?
31
+ true
32
+ end
33
+ end
34
+
35
+ include Virtus.model
36
+
37
+ attribute :currency_pair, CurrencyPair
38
+
39
+ def build_currency_rate
40
+ success build
41
+ rescue => err
42
+ Rails.logger.error err unless err.is_a? Error
43
+ failure err
44
+ end
45
+
46
+ private
47
+
48
+ def build
49
+ raise 'not implemented'
50
+ end
51
+
52
+ def success(currency_rate)
53
+ SuccessResult.new(currency_rate: currency_rate).freeze
54
+ end
55
+
56
+ def failure(error)
57
+ ErrorResult.new(error: error).freeze
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,70 @@
1
+ require_relative 'currency_rate_builder'
2
+
3
+ module Gera
4
+ class CurrencyRateCrossBuilder < CurrencyRateBuilder
5
+ attribute :cross_rate_modes
6
+
7
+ private
8
+
9
+ def build
10
+ @cached_pairs = Set.new
11
+
12
+ CurrencyRate.new(
13
+ currency_pair: currency_pair,
14
+ rate_value: external_rates.map(&:rate_value).inject(&:*),
15
+ mode: :cross,
16
+ external_rates: external_rates
17
+ )
18
+ end
19
+
20
+ def external_rates
21
+ @external_rates ||= build_external_rates(cross_rates)
22
+ end
23
+
24
+ def cross_rates
25
+ return cross_rate_modes if cross_rate_modes.present?
26
+ generate_cross_rates currency_pair
27
+ end
28
+
29
+ def build_external_rates(cross_rates)
30
+ cross_rates.map do |cr|
31
+ if cr.rate_source.present?
32
+ cr.rate_source.find_rate_by_currency_pair! cr.currency_pair
33
+ else
34
+ find_external_rate(cr.currency_pair) || raise(Error, "При расчете кросс-курса не найден источник для #{cr.currency_pair}")
35
+ end
36
+ end.flatten
37
+ end
38
+
39
+ def generate_cross_rates(pair)
40
+ if Gera.cross_pairs.has_key? pair.cur_from
41
+ cross_cur = Gera.cross_pairs[pair.cur_from]
42
+ elsif Gera.cross_pairs.has_key? pair.cur_to
43
+ cross_cur = Gera.cross_pairs[pair.cur_to]
44
+ else
45
+ cross_cur = Gera.default_cross_currency
46
+ end
47
+
48
+ [
49
+ Gera::CrossRateMode.new(currency_pair: pair.change_to(cross_cur)).freeze,
50
+ Gera::CrossRateMode.new(currency_pair: pair.change_from(cross_cur)).freeze
51
+ ]
52
+ end
53
+
54
+ def sources
55
+ @sources ||= Gera::RateSource.enabled_for_cross_rates.ordered
56
+ end
57
+
58
+ def find_external_rate pair
59
+ raise Error, "Поиск курса через самого себя #{pair}" if pair.same?
60
+ raise Error, "Циклический поиск (#{@cached_pairs.to_a.join(',')}) курса для #{pair}" if @cached_pairs.include? pair
61
+ @cached_pairs << pair
62
+ sources.each do |source|
63
+ external_rate = source.find_rate_by_currency_pair pair
64
+ return external_rate if external_rate.present?
65
+ end
66
+
67
+ build_external_rates generate_cross_rates pair
68
+ end
69
+ end
70
+ end