gera 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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