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
@@ -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}) &rarr; #{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 << " =&nbsp;#{humanized_rate currency_rate.rate_value}&nbsp;#{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,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Gera
4
+ class ApplicationJob < ActiveJob::Base
5
+ end
6
+ 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