gera 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- 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,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
module HistoryIntervalConcern
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
INTERVAL = 5.minutes
|
7
|
+
|
8
|
+
included do
|
9
|
+
extend AutoLogger::Named.new(name: 'history_intervals')
|
10
|
+
before_save do
|
11
|
+
self.avg_rate = (max_rate + min_rate) / 2.0
|
12
|
+
end
|
13
|
+
|
14
|
+
before_save do
|
15
|
+
raise "Time must be even to #{INTERVAL}" unless interval_from.min % INTERVAL.parts[:minutes] == 0
|
16
|
+
raise "Time must be even to #{INTERVAL}" unless interval_to.min % INTERVAL.parts[:minutes] == 0
|
17
|
+
raise 'Time must have zero seconds' unless interval_from.sec == 0
|
18
|
+
raise 'Time must have zero seconds' unless interval_to.sec == 0
|
19
|
+
end
|
20
|
+
|
21
|
+
before_save do
|
22
|
+
raise "min_rate (#{min_rate}) must be less or equal to max_rate (#{max_rate})" if min_rate > max_rate
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class_methods do
|
27
|
+
def create_multiple_intervals_from!(interval_from, interval_to = nil)
|
28
|
+
interval_from -= interval_from.sec # Обнуляем секунды
|
29
|
+
interval_from -= interval_from.min % INTERVAL.parts[:minutes]
|
30
|
+
interval_to ||= Time.zone.now
|
31
|
+
((interval_to - interval_from) / 5.minutes).to_i.times do |i|
|
32
|
+
f = interval_from + i * INTERVAL
|
33
|
+
begin
|
34
|
+
logger.info "#{self}: Create HistoryInterval #{f} -> #{f + INTERVAL}"
|
35
|
+
transaction do
|
36
|
+
create_by_interval! f, f + INTERVAL
|
37
|
+
end
|
38
|
+
logger.info "#{self}: Create HistoryInterval #{f} -> #{f + INTERVAL} - done"
|
39
|
+
rescue ActiveRecord::RecordNotUnique => err
|
40
|
+
logger.error err
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class CrossRateMode < ApplicationRecord
|
5
|
+
include CurrencyPairSupport
|
6
|
+
belongs_to :currency_rate_mode
|
7
|
+
belongs_to :rate_source, optional: true
|
8
|
+
|
9
|
+
def title
|
10
|
+
"#{currency_pair}(#{rate_source || 'auto'})"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
# Базовый курс
|
5
|
+
# Basic currency rate
|
6
|
+
class CurrencyRate < ApplicationRecord
|
7
|
+
include CurrencyPairSupport
|
8
|
+
include Authority::Abilities
|
9
|
+
|
10
|
+
belongs_to :snapshot, class_name: 'Gera::CurrencyRateSnapshot'
|
11
|
+
belongs_to :external_rate, optional: true
|
12
|
+
belongs_to :rate_source, optional: true
|
13
|
+
|
14
|
+
belongs_to :external_rate1, class_name: 'Gera::ExternalRate', optional: true
|
15
|
+
belongs_to :external_rate2, class_name: 'Gera::ExternalRate', optional: true
|
16
|
+
belongs_to :external_rate3, class_name: 'Gera::ExternalRate', optional: true
|
17
|
+
|
18
|
+
has_many :direction_rates, class_name: 'Gera::DirectionRate'
|
19
|
+
|
20
|
+
scope :by_exchange_rate, ->(er) { by_currency_pair er.currency_pair }
|
21
|
+
|
22
|
+
enum mode: %i[direct inverse same cross], _prefix: true
|
23
|
+
|
24
|
+
before_save do
|
25
|
+
raise("У кросс-курса (#{currency_pair}) должно быть несколько external_rates (#{external_rates.count})") if mode_cross? && !external_rates.many?
|
26
|
+
|
27
|
+
self.metadata ||= {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def external_rates=(rates)
|
31
|
+
self.external_rate, self.external_rate1, self.external_rate2, self.external_rate3 = rates
|
32
|
+
end
|
33
|
+
|
34
|
+
def external_rates
|
35
|
+
[external_rate, external_rate1, external_rate2, external_rate3].compact
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
currency_pair.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
def inspect
|
43
|
+
"#{currency_pair}:#{humanized_rate}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def in_money
|
47
|
+
reverse_rate_money.to_d > 1 ? reverse_rate_money : 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def out_money
|
51
|
+
rate_money.to_d > 1 ? rate_money : 1
|
52
|
+
end
|
53
|
+
|
54
|
+
def rate_money
|
55
|
+
Money.from_amount(rate_value, cur_to)
|
56
|
+
end
|
57
|
+
|
58
|
+
def reverse_rate_money
|
59
|
+
Money.from_amount(1.0 / rate_value, cur_from)
|
60
|
+
end
|
61
|
+
|
62
|
+
def humanized_rate
|
63
|
+
if rate_value < 1
|
64
|
+
"#{rate_value} (1/#{1.0 / rate_value})"
|
65
|
+
else
|
66
|
+
rate_value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def dump
|
71
|
+
as_json(only: %i[created_at cur_from cur_to mode rate_value metadata rate_source_id]).merge external_rates: external_rates.map(&:dump)
|
72
|
+
end
|
73
|
+
|
74
|
+
def meta
|
75
|
+
@meta ||= OpenStruct.new metadata.deep_symbolize_keys
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class CurrencyRateHistoryInterval < ApplicationRecord
|
5
|
+
include HistoryIntervalConcern
|
6
|
+
def self.create_by_interval!(interval_from, interval_to = nil)
|
7
|
+
interval_to ||= interval_from + INTERVAL
|
8
|
+
CurrencyRate
|
9
|
+
.where('created_at >= ? and created_at < ?', interval_from, interval_to)
|
10
|
+
.group(:cur_from, :cur_to)
|
11
|
+
.pluck(:cur_from, :cur_to, 'min(rate_value)', 'max(rate_value)')
|
12
|
+
.each do |cur_from, cur_to, min_rate, max_rate|
|
13
|
+
|
14
|
+
next if cur_from == cur_to
|
15
|
+
|
16
|
+
create!(
|
17
|
+
cur_from_id: Money::Currency.find(cur_from).local_id,
|
18
|
+
cur_to_id: Money::Currency.find(cur_to).local_id,
|
19
|
+
min_rate: min_rate, max_rate: max_rate,
|
20
|
+
interval_from: interval_from, interval_to: interval_to
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class CurrencyRateHistoryIntervalFilter
|
5
|
+
include Virtus.model strict: true
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
8
|
+
include ActiveModel::Validations
|
9
|
+
|
10
|
+
attribute :cur_from, String, default: ->(_a, _b) { Money::Currency.first }
|
11
|
+
attribute :cur_to, String, default: ->(_a, _b) { Money::Currency.first }
|
12
|
+
attribute :value_type, String, default: 'rate'
|
13
|
+
|
14
|
+
def currency_from
|
15
|
+
Money::Currency.find cur_from
|
16
|
+
end
|
17
|
+
|
18
|
+
def currency_to
|
19
|
+
Money::Currency.find cur_to
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_param
|
23
|
+
to_hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def persisted?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class CurrencyRateMode < ApplicationRecord
|
5
|
+
include CurrencyPairSupport
|
6
|
+
include CurrencyRateModeBuilderSupport
|
7
|
+
include Authority::Abilities
|
8
|
+
|
9
|
+
belongs_to :snapshot, class_name: 'CurrencyRateModeSnapshot', foreign_key: :currency_rate_mode_snapshot_id
|
10
|
+
has_many :cross_rate_modes
|
11
|
+
|
12
|
+
# Тут режими из ключей rate_source
|
13
|
+
# TODO выделить привязку к rate_source в отедельную ассоциацию
|
14
|
+
enum mode: %i[auto cbr cbr_avg exmo cross bitfinex], _prefix: true
|
15
|
+
|
16
|
+
accepts_nested_attributes_for :cross_rate_modes, reject_if: :all_blank, allow_destroy: true
|
17
|
+
|
18
|
+
delegate :to_s, to: :mode
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class CurrencyRateModeSnapshot < ApplicationRecord
|
5
|
+
has_many :currency_rate_modes, dependent: :destroy
|
6
|
+
|
7
|
+
scope :ordered, -> { order('status desc').order('created_at desc') }
|
8
|
+
|
9
|
+
enum status: %i[draft active deactive], _prefix: true
|
10
|
+
|
11
|
+
accepts_nested_attributes_for :currency_rate_modes
|
12
|
+
|
13
|
+
before_validation do
|
14
|
+
self.title = Time.zone.now.to_s if title.blank?
|
15
|
+
end
|
16
|
+
|
17
|
+
validates :title, presence: true, uniqueness: true
|
18
|
+
|
19
|
+
def create_modes!
|
20
|
+
CurrencyPair.all.each do |pair|
|
21
|
+
currency_rate_modes.create! currency_pair: pair
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class CurrencyRateSnapshot < ApplicationRecord
|
5
|
+
has_many :rates, class_name: 'Gera::CurrencyRate', foreign_key: :snapshot_id
|
6
|
+
belongs_to :currency_rate_mode_snapshot
|
7
|
+
|
8
|
+
def currency_rates
|
9
|
+
rates
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
# Exchange Direction
|
5
|
+
#
|
6
|
+
class Direction
|
7
|
+
include Virtus.model
|
8
|
+
|
9
|
+
attribute :ps_from # , PaymentSystem
|
10
|
+
attribute :ps_to # , PaymentSystem
|
11
|
+
|
12
|
+
alias_attribute :payment_system_from, :ps_from
|
13
|
+
alias_attribute :payment_system_to, :ps_to
|
14
|
+
alias_attribute :income_payment_system, :ps_from
|
15
|
+
alias_attribute :outcome_payment_system, :ps_to
|
16
|
+
|
17
|
+
delegate :id, to: :ps_to, prefix: true
|
18
|
+
delegate :id, to: :ps_from, prefix: true
|
19
|
+
|
20
|
+
def currency_from
|
21
|
+
payment_system_from.currency
|
22
|
+
end
|
23
|
+
|
24
|
+
def currency_to
|
25
|
+
payment_system_to.currency
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
"direction:#{payment_system_from.try(:id) || '???'}-#{payment_system_to.try(:id) || '???'}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def exchange_rate
|
37
|
+
Universe.exchange_rates_repository.find_by_direction self
|
38
|
+
end
|
39
|
+
|
40
|
+
def direction_rate
|
41
|
+
Universe.direction_rates_repository.find_by_direction self
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
# Конечный курс
|
5
|
+
# Finite direction rate
|
6
|
+
class DirectionRate < ApplicationRecord
|
7
|
+
include Mathematic
|
8
|
+
include AutoLogger
|
9
|
+
include DirectionSupport
|
10
|
+
include Authority::Abilities
|
11
|
+
|
12
|
+
UnknownExchangeRate = Class.new StandardError
|
13
|
+
|
14
|
+
belongs_to :ps_from, class_name: 'Gera::PaymentSystem'
|
15
|
+
belongs_to :ps_to, class_name: 'Gera::PaymentSystem'
|
16
|
+
belongs_to :currency_rate, class_name: 'Gera::CurrencyRate'
|
17
|
+
belongs_to :exchange_rate
|
18
|
+
belongs_to :snapshot, class_name: 'Gera::DirectionRateSnapshot'
|
19
|
+
|
20
|
+
before_validation do
|
21
|
+
self.ps_from = exchange_rate.payment_system_from
|
22
|
+
self.ps_to = exchange_rate.payment_system_to
|
23
|
+
end
|
24
|
+
|
25
|
+
before_validation :calculate_rate, unless: :finite_rate
|
26
|
+
|
27
|
+
validates :base_rate_value, presence: true
|
28
|
+
validates :rate_percent, presence: true
|
29
|
+
validates :finite_rate, presence: true
|
30
|
+
|
31
|
+
alias_attribute :payment_system_from, :ps_from
|
32
|
+
alias_attribute :payment_system_to, :ps_to
|
33
|
+
alias_attribute :income_payment_system, :ps_from
|
34
|
+
alias_attribute :outcome_payment_system, :ps_to
|
35
|
+
alias_attribute :income_payment_system_id, :ps_from_id
|
36
|
+
alias_attribute :outcome_payment_system_id, :ps_to_id
|
37
|
+
|
38
|
+
alias_attribute :comission, :rate_percent
|
39
|
+
alias_attribute :finite_rate, :rate_value
|
40
|
+
|
41
|
+
def exchange(amount)
|
42
|
+
rate.exchange amount, outcome_currency
|
43
|
+
end
|
44
|
+
|
45
|
+
def reverse_exchange(amount)
|
46
|
+
rate.reverse_exchange amount, income_currency
|
47
|
+
end
|
48
|
+
|
49
|
+
def currency_pair
|
50
|
+
@currency_pair ||= CurrencyPair.new income_currency, outcome_currency
|
51
|
+
end
|
52
|
+
|
53
|
+
def income_currency
|
54
|
+
ps_from.currency
|
55
|
+
end
|
56
|
+
|
57
|
+
def outcome_currency
|
58
|
+
ps_to.currency
|
59
|
+
end
|
60
|
+
|
61
|
+
def ps_comission
|
62
|
+
ps_to.commission
|
63
|
+
end
|
64
|
+
|
65
|
+
def in_money
|
66
|
+
return 1 if rate_value < 1
|
67
|
+
|
68
|
+
rate_value
|
69
|
+
end
|
70
|
+
|
71
|
+
def out_money
|
72
|
+
return 1.0 / rate_value if rate_value < 1
|
73
|
+
|
74
|
+
1
|
75
|
+
end
|
76
|
+
|
77
|
+
def rate
|
78
|
+
RateFromMultiplicator.new(rate_value).freeze
|
79
|
+
end
|
80
|
+
|
81
|
+
def rate_money
|
82
|
+
Money.from_amount(rate_value, currency_rate.currency_to)
|
83
|
+
end
|
84
|
+
|
85
|
+
def base_rate
|
86
|
+
RateFromMultiplicator.new(base_rate_value).freeze
|
87
|
+
end
|
88
|
+
|
89
|
+
def inverse_direction_rate
|
90
|
+
Universe.direction_rates_repository.get_matrix[ps_to_id][ps_from_id]
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_profit_result(income_amount)
|
94
|
+
res = calculate_profits(
|
95
|
+
base_rate: base_rate_value,
|
96
|
+
comission: rate_percent,
|
97
|
+
ps_interest: ps_comission,
|
98
|
+
income_amount: income_amount
|
99
|
+
)
|
100
|
+
|
101
|
+
diff = res.finite_rate.to_f.as_percentage_of(rate_value.to_f) - 100
|
102
|
+
|
103
|
+
logger.warn "direction_rate_id=#{id} Calculates finite rate (#{res.finite_rate}) does not equal to current (#{rate_value}). Difference is #{diff}" if diff.abs > 0
|
104
|
+
|
105
|
+
res
|
106
|
+
end
|
107
|
+
|
108
|
+
def dump
|
109
|
+
as_json(only: %i[id ps_from_id ps_to_id currency_rate_id rate_value base_rate_value rate_percent created_at])
|
110
|
+
.merge currency_rate: currency_rate.dump, dump_version: 1
|
111
|
+
end
|
112
|
+
|
113
|
+
def exchange_notification
|
114
|
+
ExchangeNotification.find_by(
|
115
|
+
income_payment_system_id: income_payment_system_id,
|
116
|
+
outcome_payment_system_id: outcome_payment_system_id
|
117
|
+
) ||
|
118
|
+
ExchangeNotification.find_by(
|
119
|
+
income_payment_system_id: income_payment_system_id,
|
120
|
+
outcome_payment_system_id: nil
|
121
|
+
) ||
|
122
|
+
ExchangeNotification.find_by(
|
123
|
+
income_payment_system_id: nil,
|
124
|
+
outcome_payment_system_id: outcome_payment_system_id
|
125
|
+
)
|
126
|
+
end
|
127
|
+
|
128
|
+
def calculate_rate
|
129
|
+
self.base_rate_value = currency_rate.rate_value
|
130
|
+
raise UnknownExchangeRate, "No exchange_rate for #{ps_from}->#{ps_to}" unless exchange_rate
|
131
|
+
|
132
|
+
self.rate_percent = exchange_rate.comission_percents
|
133
|
+
self.rate_value = calculate_finite_rate base_rate_value, rate_percent unless rate_percent.nil?
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|