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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +67 -0
- data/Rakefile +43 -0
- data/app/assets/config/gera_manifest.js +2 -0
- data/app/assets/javascripts/gera/application.js +14 -0
- data/app/assets/stylesheets/gera/application.css +15 -0
- data/app/authorizers/gera/application_authorizer.rb +6 -0
- data/app/authorizers/gera/currency_rate_authorizer.rb +9 -0
- data/app/authorizers/gera/currency_rate_mode_authorizer.rb +7 -0
- data/app/authorizers/gera/direction_rate_authorizer.rb +8 -0
- data/app/authorizers/gera/exchange_rate_authorizer.rb +8 -0
- data/app/authorizers/gera/payment_system_authorizer.rb +13 -0
- data/app/authorizers/gera/rate_source_authorizer.rb +7 -0
- data/app/controllers/gera/application_controller.rb +30 -0
- data/app/controllers/gera/currencies_controller.rb +8 -0
- data/app/controllers/gera/currency_rate_history_intervals_controller.rb +53 -0
- data/app/controllers/gera/currency_rate_mode_snapshots_controller.rb +83 -0
- data/app/controllers/gera/currency_rate_modes_controller.rb +60 -0
- data/app/controllers/gera/currency_rates_controller.rb +70 -0
- data/app/controllers/gera/direction_rate_history_intervals_controller.rb +62 -0
- data/app/controllers/gera/direction_rates_controller.rb +28 -0
- data/app/controllers/gera/exchange_rates_controller.rb +25 -0
- data/app/controllers/gera/external_rate_snapshots_controller.rb +35 -0
- data/app/controllers/gera/external_rates_controller.rb +28 -0
- data/app/controllers/gera/payment_systems_controller.rb +78 -0
- data/app/controllers/gera/rate_sources_controller.rb +8 -0
- data/app/decorators/gera/currency_rate_decorator.rb +148 -0
- data/app/decorators/gera/direction_rate_decorator.rb +47 -0
- data/app/decorators/gera/payment_system_decorator.rb +19 -0
- data/app/helpers/gera/application_helper.rb +110 -0
- data/app/helpers/gera/currency_rate_helper.rb +19 -0
- data/app/helpers/gera/currency_rate_modes_helper.rb +73 -0
- data/app/helpers/gera/direction_rate_helper.rb +36 -0
- data/app/helpers/gera/exchange_rates_helper.rb +21 -0
- data/app/jobs/gera/application_job.rb +6 -0
- data/app/models/concerns/gera/currency_pair_generator.rb +14 -0
- data/app/models/concerns/gera/currency_pair_support.rb +42 -0
- data/app/models/concerns/gera/currency_rate_mode_builder_support.rb +35 -0
- data/app/models/concerns/gera/direction_support.rb +14 -0
- data/app/models/concerns/gera/history_interval_concern.rb +46 -0
- data/app/models/gera/application_record.rb +8 -0
- data/app/models/gera/cbr_external_rate.rb +13 -0
- data/app/models/gera/cross_rate_mode.rb +13 -0
- data/app/models/gera/currency_rate.rb +78 -0
- data/app/models/gera/currency_rate_history_interval.rb +25 -0
- data/app/models/gera/currency_rate_history_interval_filter.rb +30 -0
- data/app/models/gera/currency_rate_mode.rb +20 -0
- data/app/models/gera/currency_rate_mode_snapshot.rb +26 -0
- data/app/models/gera/currency_rate_snapshot.rb +12 -0
- data/app/models/gera/direction.rb +44 -0
- data/app/models/gera/direction_rate.rb +136 -0
- data/app/models/gera/direction_rate_history_interval.rb +33 -0
- data/app/models/gera/direction_rate_history_interval_filter.rb +30 -0
- data/app/models/gera/direction_rate_snapshot.rb +7 -0
- data/app/models/gera/exchange_rate.rb +130 -0
- data/app/models/gera/external_rate.rb +38 -0
- data/app/models/gera/external_rate_snapshot.rb +20 -0
- data/app/models/gera/payment_system.rb +98 -0
- data/app/models/gera/rate_source.rb +77 -0
- data/app/models/gera/rate_source_auto.rb +25 -0
- data/app/models/gera/rate_source_bitfinex.rb +9 -0
- data/app/models/gera/rate_source_cbr.rb +13 -0
- data/app/models/gera/rate_source_cbr_avg.rb +6 -0
- data/app/models/gera/rate_source_exmo.rb +9 -0
- data/app/models/gera/rate_source_manual.rb +13 -0
- data/app/views/application/_exchange_rate_monitor.slim +1 -0
- data/app/views/gera/application/_attributes_table.slim +5 -0
- data/app/views/gera/application/_currencies_table.slim +18 -0
- data/app/views/gera/application/_currency_rate_mode_snapshots.slim +6 -0
- data/app/views/gera/application/_direction_rate.slim +6 -0
- data/app/views/gera/application/_directions_submenu.slim +11 -0
- data/app/views/gera/application/_directions_table.slim +15 -0
- data/app/views/gera/application/_exchange_rate.slim +6 -0
- data/app/views/gera/application/_external_rate.slim +6 -0
- data/app/views/gera/application/_header.slim +12 -0
- data/app/views/gera/application/_table.slim +28 -0
- data/app/views/gera/application/_topnav.slim +21 -0
- data/app/views/gera/application/direction_details.slim +75 -0
- data/app/views/gera/application/page.html.slim +1 -0
- data/app/views/gera/currencies/index.html.slim +20 -0
- data/app/views/gera/currency_rate_history_intervals/_filter.slim +11 -0
- data/app/views/gera/currency_rate_history_intervals/index.slim +39 -0
- data/app/views/gera/currency_rate_mode_snapshots/_snapshot.slim +20 -0
- data/app/views/gera/currency_rate_mode_snapshots/edit.html.slim +30 -0
- data/app/views/gera/currency_rate_modes/_cross_rate_mode_fields.slim +21 -0
- data/app/views/gera/currency_rate_modes/_currency_rate_mode.slim +7 -0
- data/app/views/gera/currency_rate_modes/_form.slim +29 -0
- data/app/views/gera/currency_rate_modes/edit.slim +11 -0
- data/app/views/gera/currency_rate_modes/index.html.slim +12 -0
- data/app/views/gera/currency_rates/_currency_rate.slim +22 -0
- data/app/views/gera/currency_rates/_currency_rate_humanized.slim +35 -0
- data/app/views/gera/currency_rates/diff.slim +12 -0
- data/app/views/gera/currency_rates/index.slim +27 -0
- data/app/views/gera/currency_rates/modes.slim +14 -0
- data/app/views/gera/currency_rates/show.slim +4 -0
- data/app/views/gera/direction_rate_history_intervals/_filter.slim +11 -0
- data/app/views/gera/direction_rate_history_intervals/index.slim +41 -0
- data/app/views/gera/direction_rates/_direction_rate_example_calculator.slim +28 -0
- data/app/views/gera/direction_rates/diff.slim +19 -0
- data/app/views/gera/direction_rates/index.slim +26 -0
- data/app/views/gera/direction_rates/legacy.html.slim +5 -0
- data/app/views/gera/direction_rates/minimals.slim +5 -0
- data/app/views/gera/direction_rates/show.slim +14 -0
- data/app/views/gera/external_rate_snapshots/index.slim +25 -0
- data/app/views/gera/external_rate_snapshots/show.slim +22 -0
- data/app/views/gera/external_rates/_flat_list.slim +22 -0
- data/app/views/gera/external_rates/index.html.slim +28 -0
- data/app/views/gera/external_rates/show.slim +1 -0
- data/app/views/gera/payment_systems/_fields.slim +4 -0
- data/app/views/gera/payment_systems/_fields_table.slim +18 -0
- data/app/views/gera/payment_systems/_form.slim +9 -0
- data/app/views/gera/payment_systems/edit.slim +7 -0
- data/app/views/gera/payment_systems/index.slim +3 -0
- data/app/views/gera/payment_systems/new.slim +9 -0
- data/app/views/gera/payment_systems/show.slim +1 -0
- data/app/views/gera/rate_sources/_list.slim +13 -0
- data/app/views/gera/rate_sources/_rate_source.slim +23 -0
- data/app/views/gera/rate_sources/index.html.slim +6 -0
- data/app/views/layouts/application.html.slim +15 -0
- data/app/views/layouts/gera/blank.html.slim +10 -0
- data/app/workers/concerns/gera/rates_worker.rb +87 -0
- data/app/workers/gera/bitfinex_rates_worker.rb +65 -0
- data/app/workers/gera/cbr_avg_rates_worker.rb +42 -0
- data/app/workers/gera/cbr_rates_worker.rb +192 -0
- data/app/workers/gera/create_history_intervals_worker.rb +38 -0
- data/app/workers/gera/currency_rates_worker.rb +64 -0
- data/app/workers/gera/directions_rates_worker.rb +51 -0
- data/app/workers/gera/exmo_rates_worker.rb +62 -0
- data/app/workers/gera/purge_currency_rates_worker.rb +21 -0
- data/app/workers/gera/purge_direction_rates_worker.rb +30 -0
- data/config/currencies.yml +559 -0
- data/config/routes.rb +30 -0
- data/db/migrate/20180912130000_setup.rb +228 -0
- data/db/migrate/20190314114844_add_is_available_to_payment_systems.rb +7 -0
- data/db/migrate/20190315113046_add_icon_url_to_payment_systems.rb +7 -0
- data/db/migrate/20190315132137_add_commission_to_payment_systems.rb +7 -0
- data/lib/banks/currency_exchange.rb +12 -0
- data/lib/builders/currency_rate_auto_builder.rb +38 -0
- data/lib/builders/currency_rate_builder.rb +60 -0
- data/lib/builders/currency_rate_cross_builder.rb +70 -0
- data/lib/builders/currency_rate_direct_builder.rb +26 -0
- data/lib/gera.rb +32 -0
- data/lib/gera/bitfinex_fetcher.rb +36 -0
- data/lib/gera/configuration.rb +47 -0
- data/lib/gera/currencies_purger.rb +28 -0
- data/lib/gera/currency_pair.rb +93 -0
- data/lib/gera/engine.rb +14 -0
- data/lib/gera/mathematic.rb +156 -0
- data/lib/gera/money_support.rb +89 -0
- data/lib/gera/numeric.rb +25 -0
- data/lib/gera/railtie.rb +8 -0
- data/lib/gera/rate.rb +22 -0
- data/lib/gera/rate_from_multiplicator.rb +54 -0
- data/lib/gera/repositories/currency_rate_modes_repository.rb +37 -0
- data/lib/gera/repositories/currency_rates_repository.rb +25 -0
- data/lib/gera/repositories/direction_rates_repository.rb +46 -0
- data/lib/gera/repositories/exchange_rates_repository.rb +23 -0
- data/lib/gera/repositories/payment_systems_repository.rb +21 -0
- data/lib/gera/repositories/universe.rb +47 -0
- data/lib/gera/version.rb +3 -0
- data/lib/tasks/auto_generate_diagram.rake +6 -0
- data/lib/tasks/gera_tasks.rake +4 -0
- metadata +765 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
class DirectionRateDecorator < ApplicationDecorator
|
|
5
|
+
include Mathematic
|
|
6
|
+
delegate :id
|
|
7
|
+
|
|
8
|
+
def inverse_direction
|
|
9
|
+
h.link_to h.direction_rate_path(object.inverse_direction_rate), class: 'text-muted' do
|
|
10
|
+
dd = DirectionRateDecorator.new(object.inverse_direction_rate)
|
|
11
|
+
buffer = dd.direction
|
|
12
|
+
buffer << ' '
|
|
13
|
+
buffer << dd.rate_value
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def direction
|
|
18
|
+
"#{h.ps_icon object.ps_from}(#{object.ps_from.currency}) → #{h.ps_icon object.ps_to}(#{object.ps_to.currency})".html_safe
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def title
|
|
22
|
+
[object.ps_from, object.ps_to].join('->')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def ps_comission
|
|
26
|
+
object.ps_comission.to_percent
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def created_at
|
|
30
|
+
h.link_to h.direction_rate_path(object) do
|
|
31
|
+
I18n.l object.created_at, format: :long
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def base_rate_value
|
|
36
|
+
h.currency_rate_mode_detailed object.currency_rate
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def rate_percent
|
|
40
|
+
object.rate_percent.to_percent
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def rate_value
|
|
44
|
+
h.rate_humanized_description(object.rate_value, object.ps_from.currency, object.ps_to.currency)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
class PaymentSystemDecorator < ApplicationDecorator
|
|
5
|
+
delegate_all
|
|
6
|
+
|
|
7
|
+
def icon
|
|
8
|
+
h.ps_icon object, size: 32
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def actions
|
|
12
|
+
h.link_to t('.edit'), h.edit_payment_system_path(object), class: 'btn btn-outline btn-default btn-sm' if object.updatable_by? current_user
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.decorated_class
|
|
16
|
+
PaymentSystem
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
module ApplicationHelper
|
|
5
|
+
MINIMAL_EPSILON = 0.001
|
|
6
|
+
|
|
7
|
+
def humanized_currency_rate(rate_value, pair, currency)
|
|
8
|
+
rate = if rate_value < 1
|
|
9
|
+
format('%.9f', rate_value.to_f)
|
|
10
|
+
else
|
|
11
|
+
format('%.3f', rate_value.to_f)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
if pair.first == currency
|
|
15
|
+
"#{rate} #{currency}" # покупка
|
|
16
|
+
elsif pair.second == currency
|
|
17
|
+
"#{rate} #{currency}" # продажа
|
|
18
|
+
else
|
|
19
|
+
raise
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def rate_source(currency_rate, level = 0)
|
|
24
|
+
if currency_rate.mode_cross?
|
|
25
|
+
buffer = currency_rate_mode_detailed currency_rate, level
|
|
26
|
+
"⟮ <span class='text-muted'>#{buffer}</span> ⟯".html_safe
|
|
27
|
+
else
|
|
28
|
+
buffer = currency_rate.rate_source.presence || currency_rate.mode
|
|
29
|
+
"(#{buffer})".html_safe
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def currency_rate_cell_data_attr(rate)
|
|
34
|
+
{
|
|
35
|
+
toggle: :popover,
|
|
36
|
+
container: :body,
|
|
37
|
+
content: "Calculation method: #{currency_rate_mode_detailed rate}",
|
|
38
|
+
trigger: :hover,
|
|
39
|
+
html: 'true',
|
|
40
|
+
placement: :bottom,
|
|
41
|
+
animation: false,
|
|
42
|
+
delay: 0,
|
|
43
|
+
href: currency_rate_path(rate)
|
|
44
|
+
}
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def rate_diff(rv1, rv2, _reverse = false)
|
|
48
|
+
return rate_diff(1.0 / rv1, 1.0 / rv2, true) if rv1 < 1
|
|
49
|
+
|
|
50
|
+
diff = rv2 - rv1
|
|
51
|
+
return 0 if diff.abs.round(3) == 0
|
|
52
|
+
|
|
53
|
+
p = 100 * diff / rv2
|
|
54
|
+
|
|
55
|
+
buffer = "#{format('%.2f', p.round(3))}%"
|
|
56
|
+
content_tag :span, buffer, data: { toggle: :tooltip, title: "#{rv2} - #{rv1}" }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def rate_with_currency(rate, currency)
|
|
60
|
+
rate = format('%.12f', rate) if rate.is_a?(Float) && rate < MINIMAL_EPSILON
|
|
61
|
+
"#{rate} <span class=text-muted>#{currency}</span>".html_safe
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def rate_cell_with_currency(rate, currency)
|
|
65
|
+
buffer = [rate_with_currency(rate, currency)]
|
|
66
|
+
buffer << rate_with_currency(rate_inversed(rate), currency) if rate < 1
|
|
67
|
+
[buffer].join('<br/>').html_safe
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# = '%.12f' % humanized_money rate.buy_money
|
|
71
|
+
def humanized_rate(rate, _currency = nil)
|
|
72
|
+
rate = rate.to_f if rate.is_a? Gera::Rate
|
|
73
|
+
if rate.is_a? Money
|
|
74
|
+
raise 'Dont use Money, it has bad round'
|
|
75
|
+
currency = rate.currency
|
|
76
|
+
rate = rate.to_f
|
|
77
|
+
end
|
|
78
|
+
if rate < 1
|
|
79
|
+
rate1 = format('%.3f', (1.0 / rate))
|
|
80
|
+
"<span class=text-muted>1/</span>#{rate1}".html_safe
|
|
81
|
+
else
|
|
82
|
+
format('%.3f', rate)
|
|
83
|
+
# = '%.12f' % humanized_money rate.buy_money
|
|
84
|
+
# humanized_money Money.from_amount(rate, currency)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def humanized_rate_text(rate, _currency = nil)
|
|
89
|
+
if rate < 1
|
|
90
|
+
rate1 = format('%.3f', (1.0 / rate))
|
|
91
|
+
"1/#{rate1}".html_safe
|
|
92
|
+
else
|
|
93
|
+
format('%.3f', rate)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def rate_inversed(rate)
|
|
98
|
+
"<span class='text-muted'>(1/#{1.0 / rate.to_f})</span>".html_safe
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def humanized_rate_detailed(rate, separator = ' ')
|
|
102
|
+
buffer = if rate < 1
|
|
103
|
+
"#{rate}#{separator}#{rate_inversed(rate)}".html_safe
|
|
104
|
+
else
|
|
105
|
+
rate
|
|
106
|
+
end
|
|
107
|
+
content_tag :span, buffer.to_s, class: 'text-nowrap'
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera::CurrencyRateHelper
|
|
4
|
+
def currency_rate_mode_autoshow_style(crm)
|
|
5
|
+
'display: none' unless crm.mode_cross?
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def currency_rate_columns(cer)
|
|
9
|
+
if cer.external_rate_id.present?
|
|
10
|
+
%i[id created_at rate_value mode external_rate tooltip metadata]
|
|
11
|
+
else
|
|
12
|
+
%i[id created_at rate_value mode tooltip metadata]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def currency_rate_class(cer)
|
|
17
|
+
"cer-mode-#{cer.mode}"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera::CurrencyRateModesHelper
|
|
4
|
+
ICON_CLASS = {
|
|
5
|
+
'draft' => 'battery-half',
|
|
6
|
+
'active' => 'battery-charging',
|
|
7
|
+
'deactive' => 'battery-empty'
|
|
8
|
+
}.freeze
|
|
9
|
+
|
|
10
|
+
STATUS_CLASS = {
|
|
11
|
+
'draft' => 'label-info',
|
|
12
|
+
'active' => 'label-success',
|
|
13
|
+
'deactive' => 'label-default'
|
|
14
|
+
}.freeze
|
|
15
|
+
|
|
16
|
+
def currency_rate_mode_detailed(currency_rate, level = 0)
|
|
17
|
+
buffer = []
|
|
18
|
+
if currency_rate.mode_cross?
|
|
19
|
+
currency_rate.external_rates.each do |er|
|
|
20
|
+
buffer << "#{er.currency_pair}(#{er.source})<sup>#{humanized_rate er.rate_value}</sup>"
|
|
21
|
+
end
|
|
22
|
+
elsif currency_rate.mode_same?
|
|
23
|
+
buffer << t('.same_currency')
|
|
24
|
+
else
|
|
25
|
+
buffer << "#{currency_rate.currency_pair}(#{currency_rate.rate_source})"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
buffer = buffer.join(' × ')
|
|
29
|
+
buffer << " = #{humanized_rate currency_rate.rate_value} #{currency_rate.currency_pair.last}" if level == 0
|
|
30
|
+
buffer.html_safe
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def currency_rate_mode_build_result_details(build_result)
|
|
34
|
+
return build_result.error.message if build_result.error?
|
|
35
|
+
|
|
36
|
+
raw t('.calculation_method', rate: currency_rate_mode_detailed(build_result.currency_rate))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def crms_cell_data_attr(crm)
|
|
40
|
+
url = crm.persisted? ? edit_currency_rate_mode_path(crm, back: request.url) :
|
|
41
|
+
new_currency_rate_mode_path(
|
|
42
|
+
currency_rate_mode: crm.attributes.slice('currency_rate_mode_snapshot_id', 'cur_from', 'cur_to'),
|
|
43
|
+
back: request.url
|
|
44
|
+
)
|
|
45
|
+
{
|
|
46
|
+
toggle: :popover,
|
|
47
|
+
container: :body,
|
|
48
|
+
content: currency_rate_mode_build_result_details(crm.build_result),
|
|
49
|
+
trigger: :hover,
|
|
50
|
+
html: 'true',
|
|
51
|
+
placement: :bottom,
|
|
52
|
+
animation: false,
|
|
53
|
+
delay: 0,
|
|
54
|
+
href: url
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def crms_status_label(status)
|
|
59
|
+
content_tag :span, status, class: "label #{STATUS_CLASS[status]}"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def currency_rate_mode_snapshot_icon(crms)
|
|
63
|
+
ion_icon ICON_CLASS[crms.status]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def currency_rate_modes_enum
|
|
67
|
+
Gera::CurrencyRateMode.modes.keys
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def currencies_enum
|
|
71
|
+
Money::Currency.all.map(&:to_s)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
module DirectionRateHelper
|
|
5
|
+
def exchange_rate_cell_data_attr(direction)
|
|
6
|
+
rate_cell_data_attr(direction).merge href: operator_exchange_rate_path(direction.exchange_rate)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def direction_rate_cell_data_attr(direction)
|
|
10
|
+
rate_cell_data_attr(direction).merge href: direction_rate_path(direction.direction_rate.try(:id) || 0)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def rate_cell_data_attr(direction)
|
|
14
|
+
return {} unless show_direction_popover?
|
|
15
|
+
|
|
16
|
+
{
|
|
17
|
+
toggle: 'ajax-popover',
|
|
18
|
+
container: :body,
|
|
19
|
+
popover_content_url: details_exchange_rate_path(direction.exchange_rate),
|
|
20
|
+
trigger: :hover,
|
|
21
|
+
html: 'true',
|
|
22
|
+
placement: :bottom,
|
|
23
|
+
animation: false,
|
|
24
|
+
delay: 0
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def rate_humanized_description(rate_value, cur_from, cur_to)
|
|
29
|
+
if rate_value < 1
|
|
30
|
+
t '.sell_for', cur_to: cur_to, value: (1.0 / rate_value).round(3), cur_from: cur_from
|
|
31
|
+
else
|
|
32
|
+
t '.buy_for', cur_to: cur_to, value: rate_value.round(3), cur_from: cur_from
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
module ExchangeRatesHelper
|
|
5
|
+
def exchange_rate_cell_class(er)
|
|
6
|
+
return unless er
|
|
7
|
+
|
|
8
|
+
classes = []
|
|
9
|
+
|
|
10
|
+
classes << 'rate-popover' if show_direction_popover?
|
|
11
|
+
|
|
12
|
+
classes << if er.comission_percents <= 0
|
|
13
|
+
'text-danger'
|
|
14
|
+
else
|
|
15
|
+
'text-success'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
classes.join ' '
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
module CurrencyPairGenerator
|
|
5
|
+
def generate_pairs_from_currencies(currencies)
|
|
6
|
+
currencies = currencies.map { |c| Money::Currency.find c }
|
|
7
|
+
|
|
8
|
+
currencies
|
|
9
|
+
.map { |c1| currencies.reject { |c2| c2 == c1 }.map { |c2| [c1, c2].join('/') } }
|
|
10
|
+
.flatten.compact
|
|
11
|
+
.map { |cp| Gera::CurrencyPair.new cp }.uniq
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
module CurrencyPairSupport
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
included do
|
|
8
|
+
if ancestors.include? ActiveRecord::Base
|
|
9
|
+
scope :by_currency_pair, ->(pair) { where cur_from: pair.cur_from.to_s, cur_to: pair.cur_to.to_s }
|
|
10
|
+
|
|
11
|
+
def self.find_by_currency_pair(pair)
|
|
12
|
+
by_currency_pair(pair).take
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.find_or_build_by_currency_pair(pair)
|
|
16
|
+
by_currency_pair(pair).take || new(currency_pair: pair)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def currency_pair=(value)
|
|
22
|
+
self.cur_from = value.cur_from
|
|
23
|
+
self.cur_to = value.cur_to
|
|
24
|
+
@currency_pair = nil
|
|
25
|
+
@currency_from = nil
|
|
26
|
+
@currency_to = nil
|
|
27
|
+
value
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def currency_pair
|
|
31
|
+
@currency_pair ||= Gera::CurrencyPair.new currency_from, currency_to
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def currency_from
|
|
35
|
+
@currency_from ||= cur_from.is_a?(Money::Currency) ? cur_from : Money::Currency.find!(cur_from)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def currency_to
|
|
39
|
+
@currency_to ||= cur_to.is_a?(Money::Currency) ? cur_to : Money::Currency.find!(cur_to)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
module CurrencyRateModeBuilderSupport
|
|
5
|
+
def build_currency_rate
|
|
6
|
+
@currency_rate ||= build_currency_rate!
|
|
7
|
+
rescue CurrencyRateBuilder::Error
|
|
8
|
+
nil
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def build_result
|
|
12
|
+
@result ||= builder.build_currency_rate
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def build_currency_rate!
|
|
16
|
+
raise build_result.error if build_result.error?
|
|
17
|
+
|
|
18
|
+
build_result.currency_rate
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def builder
|
|
22
|
+
case mode
|
|
23
|
+
when 'auto'
|
|
24
|
+
CurrencyRateAutoBuilder.new currency_pair: currency_pair
|
|
25
|
+
when 'cross'
|
|
26
|
+
CurrencyRateCrossBuilder.new currency_pair: currency_pair, cross_rate_modes: cross_rate_modes
|
|
27
|
+
else
|
|
28
|
+
source = RateSource.find_by_key(mode)
|
|
29
|
+
raise "not supported mode #{mode} for #{currency_pair}" unless source.present?
|
|
30
|
+
|
|
31
|
+
CurrencyRateDirectBuilder.new currency_pair: currency_pair, source: source
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gera
|
|
4
|
+
module DirectionSupport
|
|
5
|
+
def direction=(value)
|
|
6
|
+
self.payment_system_from = value.payment_system_from
|
|
7
|
+
self.payment_system_to = value.payment_system_to
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def direction
|
|
11
|
+
::Gera::Direction.new(ps_from: payment_system_from, ps_to: payment_system_to).freeze
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|